summaryrefslogtreecommitdiffstats
path: root/tdeio
diff options
context:
space:
mode:
Diffstat (limited to 'tdeio')
-rw-r--r--tdeio/CMakeLists.txt71
-rw-r--r--tdeio/DESIGN272
-rw-r--r--tdeio/DESIGN.krun35
-rw-r--r--tdeio/DESIGN.metadata147
-rw-r--r--tdeio/DESIGN.mimetypes34
-rw-r--r--tdeio/DESKTOP_ENTRY_STANDARD373
-rw-r--r--tdeio/Mainpage.dox120
-rw-r--r--tdeio/Makefile.am67
-rw-r--r--tdeio/application.desktop124
-rw-r--r--tdeio/bookmarks/CMakeLists.txt55
-rw-r--r--tdeio/bookmarks/Makefile.am40
-rw-r--r--tdeio/bookmarks/dptrtemplate.h57
-rw-r--r--tdeio/bookmarks/kbookmark.cc535
-rw-r--r--tdeio/bookmarks/kbookmark.h329
-rw-r--r--tdeio/bookmarks/kbookmarkbar.cc554
-rw-r--r--tdeio/bookmarks/kbookmarkbar.h131
-rw-r--r--tdeio/bookmarks/kbookmarkdombuilder.cc81
-rw-r--r--tdeio/bookmarks/kbookmarkdombuilder.h48
-rw-r--r--tdeio/bookmarks/kbookmarkdrag.cc169
-rw-r--r--tdeio/bookmarks/kbookmarkdrag.h57
-rw-r--r--tdeio/bookmarks/kbookmarkexporter.cc32
-rw-r--r--tdeio/bookmarks/kbookmarkexporter.h50
-rw-r--r--tdeio/bookmarks/kbookmarkimporter.cc101
-rw-r--r--tdeio/bookmarks/kbookmarkimporter.h106
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_crash.cc215
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_crash.h74
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_ie.cc185
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_ie.h90
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_kde1.cc156
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_kde1.h49
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_ns.cc243
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_ns.h132
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_opera.cc170
-rw-r--r--tdeio/bookmarks/kbookmarkimporter_opera.h86
-rw-r--r--tdeio/bookmarks/kbookmarkmanager.cc727
-rw-r--r--tdeio/bookmarks/kbookmarkmanager.h367
-rw-r--r--tdeio/bookmarks/kbookmarkmenu.cc1187
-rw-r--r--tdeio/bookmarks/kbookmarkmenu.h265
-rw-r--r--tdeio/bookmarks/kbookmarkmenu_p.h224
-rw-r--r--tdeio/bookmarks/kbookmarknotifier.h45
-rw-r--r--tdeio/data.protocol71
-rw-r--r--tdeio/httpfilter/CMakeLists.txt32
-rw-r--r--tdeio/httpfilter/Makefile.am8
-rw-r--r--tdeio/httpfilter/httpfilter.cc372
-rw-r--r--tdeio/httpfilter/httpfilter.h119
-rw-r--r--tdeio/kcomprfilter.desktop82
-rw-r--r--tdeio/kdatatool.desktop96
-rw-r--r--tdeio/kpasswdserver.desktop157
-rw-r--r--tdeio/kpasswdserver/CMakeLists.txt43
-rw-r--r--tdeio/kpasswdserver/DESIGN56
-rw-r--r--tdeio/kpasswdserver/Makefile.am15
-rw-r--r--tdeio/kpasswdserver/kpasswdserver.cpp715
-rw-r--r--tdeio/kpasswdserver/kpasswdserver.h118
-rw-r--r--tdeio/kscan.desktop19
-rw-r--r--tdeio/kssl/CMakeLists.txt57
-rw-r--r--tdeio/kssl/KPMG-CA-16389.0.DC80502.pdfbin0 -> 91118 bytes
-rw-r--r--tdeio/kssl/Makefile.am72
-rw-r--r--tdeio/kssl/README15
-rw-r--r--tdeio/kssl/SECURITY-HOLES17
-rw-r--r--tdeio/kssl/TODO25
-rw-r--r--tdeio/kssl/configure.in.in7
-rw-r--r--tdeio/kssl/keygenwizard.ui46
-rw-r--r--tdeio/kssl/keygenwizard2.ui78
-rw-r--r--tdeio/kssl/kopenssl.cc1601
-rw-r--r--tdeio/kssl/kopenssl.h920
-rw-r--r--tdeio/kssl/ksmimecrypto.cc424
-rw-r--r--tdeio/kssl/ksmimecrypto.h128
-rw-r--r--tdeio/kssl/kssl.cc688
-rw-r--r--tdeio/kssl/kssl.h301
-rw-r--r--tdeio/kssl/kssl/CMakeLists.txt14
-rw-r--r--tdeio/kssl/kssl/DigiCertAssuredIDRootCA.pem22
-rw-r--r--tdeio/kssl/kssl/DigiCertGlobalRootCA.pem22
-rw-r--r--tdeio/kssl/kssl/DigiCertHighAssuranceEVRootCA.pem23
-rw-r--r--tdeio/kssl/kssl/GeoTrust_Universal_CA.pem32
-rw-r--r--tdeio/kssl/kssl/GeoTrust_Universal_CA2.pem31
-rw-r--r--tdeio/kssl/kssl/HOWTO30
-rw-r--r--tdeio/kssl/kssl/Makefile.am6
-rw-r--r--tdeio/kssl/kssl/StartCom.pem148
-rw-r--r--tdeio/kssl/kssl/SwissSign-Gold-G2.pem33
-rw-r--r--tdeio/kssl/kssl/SwissSign-Platinum-G2.pem33
-rw-r--r--tdeio/kssl/kssl/SwissSign-Silver-G2.pem33
-rw-r--r--tdeio/kssl/kssl/WiseKey.pem24
-rw-r--r--tdeio/kssl/kssl/ac_offline_raiz_certicamara.pem37
-rw-r--r--tdeio/kssl/kssl/argedaten-root-ca-cert.pem23
-rw-r--r--tdeio/kssl/kssl/belgacom.pem16
-rw-r--r--tdeio/kssl/kssl/caroot/CMakeLists.txt12
-rw-r--r--tdeio/kssl/kssl/caroot/Makefile.am4
-rw-r--r--tdeio/kssl/kssl/caroot/ca-bundle.crt2973
-rwxr-xr-xtdeio/kssl/kssl/cert_bundle47
-rw-r--r--tdeio/kssl/kssl/cert_extract.c183
-rw-r--r--tdeio/kssl/kssl/certbundle_Makefile43
-rwxr-xr-xtdeio/kssl/kssl/certkde75
-rw-r--r--tdeio/kssl/kssl/certum.pem19
-rw-r--r--tdeio/kssl/kssl/certum1.pem16
-rw-r--r--tdeio/kssl/kssl/certum2.pem16
-rw-r--r--tdeio/kssl/kssl/certum3.pem16
-rw-r--r--tdeio/kssl/kssl/certum4.pem16
-rw-r--r--tdeio/kssl/kssl/comodo1.pem25
-rw-r--r--tdeio/kssl/kssl/comodo2.pem25
-rw-r--r--tdeio/kssl/kssl/comodo3.pem25
-rw-r--r--tdeio/kssl/kssl/comodo4.pem26
-rw-r--r--tdeio/kssl/kssl/comodo5.pem26
-rw-r--r--tdeio/kssl/kssl/comodo6.pem27
-rw-r--r--tdeio/kssl/kssl/comodo7.pem26
-rw-r--r--tdeio/kssl/kssl/dfn-root-ca-cert.pem39
-rw-r--r--tdeio/kssl/kssl/gd-class2-root.pem24
-rw-r--r--tdeio/kssl/kssl/geotrust-global-1.pem20
-rw-r--r--tdeio/kssl/kssl/geotrust-global-2.pem22
-rw-r--r--tdeio/kssl/kssl/globalsign-root-r1.pem21
-rw-r--r--tdeio/kssl/kssl/globalsign-root-r2.pem22
-rw-r--r--tdeio/kssl/kssl/icpbrasil.pem28
-rw-r--r--tdeio/kssl/kssl/ipsservidores.pem17
-rw-r--r--tdeio/kssl/kssl/ksslcalist787
-rw-r--r--tdeio/kssl/kssl/localcerts36
-rwxr-xr-xtdeio/kssl/kssl/mergelocal65
-rw-r--r--tdeio/kssl/kssl/netlock1.pem31
-rw-r--r--tdeio/kssl/kssl/netlock2.pem37
-rw-r--r--tdeio/kssl/kssl/netlock3.pem31
-rw-r--r--tdeio/kssl/kssl/netlock4.pem39
-rw-r--r--tdeio/kssl/kssl/oces.pem30
-rw-r--r--tdeio/kssl/kssl/quovadis.pem34
-rw-r--r--tdeio/kssl/kssl/qvrca2.pem33
-rw-r--r--tdeio/kssl/kssl/qvrca3.pem38
-rw-r--r--tdeio/kssl/kssl/sf-class2-root.pem24
-rw-r--r--tdeio/kssl/kssl/sonera1.pem19
-rw-r--r--tdeio/kssl/kssl/sonera2.pem19
-rw-r--r--tdeio/kssl/kssl/staatdernederlandenrotca.pem22
-rw-r--r--tdeio/kssl/kssl/startcom.pem30
-rw-r--r--tdeio/kssl/kssl/startssl.pem44
-rw-r--r--tdeio/kssl/kssl/tcclass2-2011.pem20
-rw-r--r--tdeio/kssl/kssl/tcclass3-2011.pem20
-rw-r--r--tdeio/kssl/kssl/utn-network.pem26
-rw-r--r--tdeio/kssl/kssl/utn-sgc.pem26
-rw-r--r--tdeio/kssl/kssl/xgca.pem25
-rw-r--r--tdeio/kssl/ksslall.h41
-rw-r--r--tdeio/kssl/ksslcallback.c89
-rw-r--r--tdeio/kssl/ksslcertchain.cc216
-rw-r--r--tdeio/kssl/ksslcertchain.h136
-rw-r--r--tdeio/kssl/ksslcertdlg.cc174
-rw-r--r--tdeio/kssl/ksslcertdlg.h138
-rw-r--r--tdeio/kssl/ksslcertificate.cc1157
-rw-r--r--tdeio/kssl/ksslcertificate.h376
-rw-r--r--tdeio/kssl/ksslcertificatecache.cc399
-rw-r--r--tdeio/kssl/ksslcertificatecache.h107
-rw-r--r--tdeio/kssl/ksslcertificatefactory.cc122
-rw-r--r--tdeio/kssl/ksslcertificatefactory.h50
-rw-r--r--tdeio/kssl/ksslcertificatehome.cc246
-rw-r--r--tdeio/kssl/ksslcertificatehome.h90
-rw-r--r--tdeio/kssl/ksslconfig.h.cmake26
-rw-r--r--tdeio/kssl/ksslconfig.h.in26
-rw-r--r--tdeio/kssl/ksslconfig_win.h26
-rw-r--r--tdeio/kssl/ksslconnectioninfo.cc66
-rw-r--r--tdeio/kssl/ksslconnectioninfo.h95
-rw-r--r--tdeio/kssl/ksslcsessioncache.cc120
-rw-r--r--tdeio/kssl/ksslcsessioncache.h47
-rw-r--r--tdeio/kssl/kssldefs.h37
-rw-r--r--tdeio/kssl/ksslinfodlg.cc463
-rw-r--r--tdeio/kssl/ksslinfodlg.h173
-rw-r--r--tdeio/kssl/ksslkeygen.cc223
-rw-r--r--tdeio/kssl/ksslkeygen.h95
-rw-r--r--tdeio/kssl/ksslpeerinfo.cc171
-rw-r--r--tdeio/kssl/ksslpeerinfo.h108
-rw-r--r--tdeio/kssl/ksslpemcallback.cc61
-rw-r--r--tdeio/kssl/ksslpemcallback.h29
-rw-r--r--tdeio/kssl/ksslpkcs12.cc295
-rw-r--r--tdeio/kssl/ksslpkcs12.h194
-rw-r--r--tdeio/kssl/ksslpkcs7.cc208
-rw-r--r--tdeio/kssl/ksslpkcs7.h156
-rw-r--r--tdeio/kssl/ksslsession.cc82
-rw-r--r--tdeio/kssl/ksslsession.h73
-rw-r--r--tdeio/kssl/ksslsettings.cc356
-rw-r--r--tdeio/kssl/ksslsettings.h224
-rw-r--r--tdeio/kssl/ksslsigners.cc251
-rw-r--r--tdeio/kssl/ksslsigners.h172
-rw-r--r--tdeio/kssl/ksslutils.cc94
-rw-r--r--tdeio/kssl/ksslutils.h77
-rw-r--r--tdeio/kssl/ksslx509map.cc103
-rw-r--r--tdeio/kssl/ksslx509map.h86
-rw-r--r--tdeio/kssl/ksslx509v3.cc143
-rw-r--r--tdeio/kssl/ksslx509v3.h122
-rw-r--r--tdeio/kurifilterplugin.desktop84
-rw-r--r--tdeio/magic1065
-rw-r--r--tdeio/misc/CMakeLists.txt100
-rw-r--r--tdeio/misc/Makefile.am60
-rwxr-xr-xtdeio/misc/fileshareset430
-rw-r--r--tdeio/misc/kpac/CMakeLists.txt66
-rw-r--r--tdeio/misc/kpac/Makefile.am30
-rw-r--r--tdeio/misc/kpac/README9
-rw-r--r--tdeio/misc/kpac/README.wpad73
-rw-r--r--tdeio/misc/kpac/TODO1
-rw-r--r--tdeio/misc/kpac/configure.in.in26
-rw-r--r--tdeio/misc/kpac/dhcp.h78
-rw-r--r--tdeio/misc/kpac/discovery.cpp147
-rw-r--r--tdeio/misc/kpac/discovery.h55
-rw-r--r--tdeio/misc/kpac/downloader.cpp89
-rw-r--r--tdeio/misc/kpac/downloader.h64
-rw-r--r--tdeio/misc/kpac/eventsrc530
-rw-r--r--tdeio/misc/kpac/kpac_dhcp_helper.c229
-rw-r--r--tdeio/misc/kpac/kpactest.pac169
-rw-r--r--tdeio/misc/kpac/proxyscout.cpp196
-rw-r--r--tdeio/misc/kpac/proxyscout.desktop131
-rw-r--r--tdeio/misc/kpac/proxyscout.h82
-rw-r--r--tdeio/misc/kpac/script.cpp465
-rw-r--r--tdeio/misc/kpac/script.h56
-rw-r--r--tdeio/misc/kssld/CMakeLists.txt47
-rw-r--r--tdeio/misc/kssld/Makefile.am33
-rw-r--r--tdeio/misc/kssld/kssld.cpp1027
-rw-r--r--tdeio/misc/kssld/kssld.desktop156
-rw-r--r--tdeio/misc/kssld/kssld.h154
-rw-r--r--tdeio/misc/mms.protocol73
-rw-r--r--tdeio/misc/mmst.protocol15
-rw-r--r--tdeio/misc/mmsu.protocol15
-rw-r--r--tdeio/misc/pnm.protocol15
-rw-r--r--tdeio/misc/rlogin.protocol13
-rw-r--r--tdeio/misc/rtsp.protocol15
-rw-r--r--tdeio/misc/rtspt.protocol15
-rw-r--r--tdeio/misc/rtspu.protocol15
-rw-r--r--tdeio/misc/ssh.protocol13
-rw-r--r--tdeio/misc/tdefile/CMakeLists.txt39
-rw-r--r--tdeio/misc/tdefile/Makefile.am10
-rw-r--r--tdeio/misc/tdefile/README4
-rw-r--r--tdeio/misc/tdefile/fileprops.cpp480
-rw-r--r--tdeio/misc/tdefile/fileprops.h74
-rw-r--r--tdeio/misc/tdeio_uiserver.desktop100
-rw-r--r--tdeio/misc/tdemailservice.cpp45
-rw-r--r--tdeio/misc/tdemailservice.protocol15
-rw-r--r--tdeio/misc/tdentlm/CMakeLists.txt43
-rw-r--r--tdeio/misc/tdentlm/Makefile.am12
-rw-r--r--tdeio/misc/tdentlm/des.cpp513
-rw-r--r--tdeio/misc/tdentlm/des.h19
-rw-r--r--tdeio/misc/tdentlm/kswap.h428
-rw-r--r--tdeio/misc/tdentlm/tdentlm.cpp389
-rw-r--r--tdeio/misc/tdentlm/tdentlm.h233
-rw-r--r--tdeio/misc/tdesasl/CMakeLists.txt42
-rw-r--r--tdeio/misc/tdesasl/Makefile.am12
-rw-r--r--tdeio/misc/tdesasl/tdesasl.cpp285
-rw-r--r--tdeio/misc/tdesasl/tdesasl.h169
-rw-r--r--tdeio/misc/tdesendbugmail/CMakeLists.txt37
-rw-r--r--tdeio/misc/tdesendbugmail/Makefile.am26
-rw-r--r--tdeio/misc/tdesendbugmail/main.cpp142
-rw-r--r--tdeio/misc/tdesendbugmail/main.h20
-rw-r--r--tdeio/misc/tdesendbugmail/smtp.cpp336
-rw-r--r--tdeio/misc/tdesendbugmail/smtp.h144
-rw-r--r--tdeio/misc/tdetelnetservice.cpp112
-rw-r--r--tdeio/misc/tdewalletd/CMakeLists.txt49
-rw-r--r--tdeio/misc/tdewalletd/Makefile.am35
-rw-r--r--tdeio/misc/tdewalletd/kbetterthankdialogbase.ui154
-rw-r--r--tdeio/misc/tdewalletd/kbetterthankdialogbase.ui.h50
-rw-r--r--tdeio/misc/tdewalletd/ktimeout.cpp84
-rw-r--r--tdeio/misc/tdewalletd/ktimeout.h52
-rw-r--r--tdeio/misc/tdewalletd/tdewalletd.cpp1514
-rw-r--r--tdeio/misc/tdewalletd/tdewalletd.desktop151
-rw-r--r--tdeio/misc/tdewalletd/tdewalletd.h199
-rw-r--r--tdeio/misc/tdewalletd/tdewalletwizard.ui545
-rw-r--r--tdeio/misc/tdewalletd/tdewalletwizard.ui.h74
-rw-r--r--tdeio/misc/telnet.protocol13
-rw-r--r--tdeio/misc/uiserver.cpp1413
-rw-r--r--tdeio/misc/uiserver.h430
-rw-r--r--tdeio/pics/CMakeLists.txt14
-rw-r--r--tdeio/pics/Makefile.am3
-rw-r--r--tdeio/pics/cr16-app-tdeio_uiserver.pngbin0 -> 838 bytes
-rwxr-xr-xtdeio/proxytype.pl11
-rw-r--r--tdeio/renamedlgplugin.desktop84
-rw-r--r--tdeio/tdecmodule.desktop109
-rw-r--r--tdeio/tdefile/CMakeLists.txt76
-rw-r--r--tdeio/tdefile/ChangeLog725
-rw-r--r--tdeio/tdefile/Makefile.am78
-rw-r--r--tdeio/tdefile/NOTES100
-rw-r--r--tdeio/tdefile/TODO17
-rw-r--r--tdeio/tdefile/config-tdefile.h32
-rw-r--r--tdeio/tdefile/images.h277
-rw-r--r--tdeio/tdefile/kacleditwidget.cpp1054
-rw-r--r--tdeio/tdefile/kacleditwidget.h65
-rw-r--r--tdeio/tdefile/kacleditwidget_p.h206
-rw-r--r--tdeio/tdefile/kcombiview.cpp371
-rw-r--r--tdeio/tdefile/kcombiview.h133
-rw-r--r--tdeio/tdefile/kcustommenueditor.cpp242
-rw-r--r--tdeio/tdefile/kcustommenueditor.h67
-rw-r--r--tdeio/tdefile/kdiroperator.cpp1740
-rw-r--r--tdeio/tdefile/kdiroperator.h950
-rw-r--r--tdeio/tdefile/kdirselectdialog.cpp481
-rw-r--r--tdeio/tdefile/kdirselectdialog.h131
-rw-r--r--tdeio/tdefile/kdirsize.cpp166
-rw-r--r--tdeio/tdefile/kdirsize.h106
-rw-r--r--tdeio/tdefile/kdiskfreesp.cpp169
-rw-r--r--tdeio/tdefile/kdiskfreesp.h89
-rw-r--r--tdeio/tdefile/kencodingfiledialog.cpp223
-rw-r--r--tdeio/tdefile/kencodingfiledialog.h313
-rw-r--r--tdeio/tdefile/kicondialog.cpp772
-rw-r--r--tdeio/tdefile/kicondialog.h350
-rw-r--r--tdeio/tdefile/kimagefilepreview.cpp187
-rw-r--r--tdeio/tdefile/kimagefilepreview.h77
-rw-r--r--tdeio/tdefile/kmetaprops.cpp268
-rw-r--r--tdeio/tdefile/kmetaprops.h69
-rw-r--r--tdeio/tdefile/knotifydialog.cpp1191
-rw-r--r--tdeio/tdefile/knotifydialog.h341
-rw-r--r--tdeio/tdefile/knotifywidgetbase.ui469
-rw-r--r--tdeio/tdefile/kopenwith.cpp851
-rw-r--r--tdeio/tdefile/kopenwith.h209
-rw-r--r--tdeio/tdefile/kopenwith_p.h101
-rw-r--r--tdeio/tdefile/kpreviewprops.cpp89
-rw-r--r--tdeio/tdefile/kpreviewprops.h57
-rw-r--r--tdeio/tdefile/kpreviewwidgetbase.cpp49
-rw-r--r--tdeio/tdefile/kpreviewwidgetbase.h92
-rw-r--r--tdeio/tdefile/kpropertiesdesktopadvbase.ui280
-rw-r--r--tdeio/tdefile/kpropertiesdesktopbase.ui316
-rw-r--r--tdeio/tdefile/kpropertiesdialog.cpp4170
-rw-r--r--tdeio/tdefile/kpropertiesdialog.h918
-rw-r--r--tdeio/tdefile/kpropertiesmimetypebase.ui70
-rw-r--r--tdeio/tdefile/kpropsdlg.h4
-rw-r--r--tdeio/tdefile/kpropsdlgplugin.desktop87
-rw-r--r--tdeio/tdefile/krecentdirs.cpp99
-rw-r--r--tdeio/tdefile/krecentdirs.h70
-rw-r--r--tdeio/tdefile/krecentdocument.cpp177
-rw-r--r--tdeio/tdefile/krecentdocument.h105
-rw-r--r--tdeio/tdefile/kurlbar.cpp1049
-rw-r--r--tdeio/tdefile/kurlbar.h660
-rw-r--r--tdeio/tdefile/kurlcombobox.cpp363
-rw-r--r--tdeio/tdefile/kurlcombobox.h229
-rw-r--r--tdeio/tdefile/kurlrequester.cpp430
-rw-r--r--tdeio/tdefile/kurlrequester.h301
-rw-r--r--tdeio/tdefile/kurlrequesterdlg.cpp135
-rw-r--r--tdeio/tdefile/kurlrequesterdlg.h114
-rw-r--r--tdeio/tdefile/tdefile.h129
-rw-r--r--tdeio/tdefile/tdefilebookmarkhandler.cpp81
-rw-r--r--tdeio/tdefile/tdefilebookmarkhandler.h63
-rw-r--r--tdeio/tdefile/tdefiledetailview.cpp686
-rw-r--r--tdeio/tdefile/tdefiledetailview.h219
-rw-r--r--tdeio/tdefile/tdefiledialog.cpp2380
-rw-r--r--tdeio/tdefile/tdefiledialog.h989
-rw-r--r--tdeio/tdefile/tdefilefiltercombo.cpp203
-rw-r--r--tdeio/tdefile/tdefilefiltercombo.h104
-rw-r--r--tdeio/tdefile/tdefileiconview.cpp943
-rw-r--r--tdeio/tdefile/tdefileiconview.h267
-rw-r--r--tdeio/tdefile/tdefilemetainfowidget.cpp375
-rw-r--r--tdeio/tdefile/tdefilemetainfowidget.h95
-rw-r--r--tdeio/tdefile/tdefilemetapreview.cpp196
-rw-r--r--tdeio/tdefile/tdefilemetapreview.h56
-rw-r--r--tdeio/tdefile/tdefilepreview.cpp279
-rw-r--r--tdeio/tdefile/tdefilepreview.h122
-rw-r--r--tdeio/tdefile/tdefilesharedlg.cpp325
-rw-r--r--tdeio/tdefile/tdefilesharedlg.h70
-rw-r--r--tdeio/tdefile/tdefilespeedbar.cpp147
-rw-r--r--tdeio/tdefile/tdefilespeedbar.h41
-rw-r--r--tdeio/tdefile/tdefiletreebranch.cpp528
-rw-r--r--tdeio/tdefile/tdefiletreebranch.h242
-rw-r--r--tdeio/tdefile/tdefiletreeview.cpp677
-rw-r--r--tdeio/tdefile/tdefiletreeview.h273
-rw-r--r--tdeio/tdefile/tdefiletreeviewitem.cpp83
-rw-r--r--tdeio/tdefile/tdefiletreeviewitem.h106
-rw-r--r--tdeio/tdefile/tdefileview.cpp429
-rw-r--r--tdeio/tdefile/tdefileview.h444
-rw-r--r--tdeio/tdefile/tests/Makefile.am41
-rw-r--r--tdeio/tdefile/tests/kcustommenueditortest.cpp19
-rw-r--r--tdeio/tdefile/tests/kdirselectdialogtest.cpp17
-rw-r--r--tdeio/tdefile/tests/kfdtest.cpp34
-rw-r--r--tdeio/tdefile/tests/kfdtest.h28
-rw-r--r--tdeio/tdefile/tests/kfstest.cpp183
-rw-r--r--tdeio/tdefile/tests/kicondialogtest.cpp19
-rw-r--r--tdeio/tdefile/tests/knotifytest.cpp10
-rw-r--r--tdeio/tdefile/tests/kopenwithtest.cpp67
-rw-r--r--tdeio/tdefile/tests/kurlrequestertest.cpp16
-rw-r--r--tdeio/tdefile/tests/tdefiletreeviewtest.cpp165
-rw-r--r--tdeio/tdefile/tests/tdefiletreeviewtest.h42
-rw-r--r--tdeio/tdefileplugin.desktop88
-rw-r--r--tdeio/tdeio/CMakeLists.txt138
-rw-r--r--tdeio/tdeio/KFILEMETAINFO_ISSUES4
-rw-r--r--tdeio/tdeio/Makefile.am129
-rw-r--r--tdeio/tdeio/authinfo.cpp332
-rw-r--r--tdeio/tdeio/authinfo.h320
-rw-r--r--tdeio/tdeio/chmodjob.cpp258
-rw-r--r--tdeio/tdeio/chmodjob.h109
-rw-r--r--tdeio/tdeio/configure.in.in167
-rw-r--r--tdeio/tdeio/connection.cpp273
-rw-r--r--tdeio/tdeio/connection.h158
-rw-r--r--tdeio/tdeio/dataprotocol.cpp339
-rw-r--r--tdeio/tdeio/dataprotocol.h71
-rw-r--r--tdeio/tdeio/dataslave.cpp213
-rw-r--r--tdeio/tdeio/dataslave.h126
-rw-r--r--tdeio/tdeio/davjob.cpp142
-rw-r--r--tdeio/tdeio/davjob.h127
-rw-r--r--tdeio/tdeio/defaultprogress.cpp507
-rw-r--r--tdeio/tdeio/defaultprogress.h164
-rw-r--r--tdeio/tdeio/forwardingslavebase.cpp475
-rw-r--r--tdeio/tdeio/forwardingslavebase.h204
-rw-r--r--tdeio/tdeio/global.cpp2009
-rw-r--r--tdeio/tdeio/global.h547
-rw-r--r--tdeio/tdeio/http_slave_defaults.h49
-rw-r--r--tdeio/tdeio/ioslave_defaults.h53
-rw-r--r--tdeio/tdeio/job.cpp4814
-rw-r--r--tdeio/tdeio/job.h532
-rw-r--r--tdeio/tdeio/jobclasses.h1909
-rw-r--r--tdeio/tdeio/kacl.cpp682
-rw-r--r--tdeio/tdeio/kacl.h207
-rw-r--r--tdeio/tdeio/kar.cpp170
-rw-r--r--tdeio/tdeio/kar.h103
-rw-r--r--tdeio/tdeio/karchive.cpp717
-rw-r--r--tdeio/tdeio/karchive.h639
-rw-r--r--tdeio/tdeio/kautomount.cpp117
-rw-r--r--tdeio/tdeio/kautomount.h122
-rw-r--r--tdeio/tdeio/kdatatool.cpp285
-rw-r--r--tdeio/tdeio/kdatatool.h303
-rw-r--r--tdeio/tdeio/kdcopservicestarter.cpp97
-rw-r--r--tdeio/tdeio/kdcopservicestarter.h103
-rw-r--r--tdeio/tdeio/kdirlister.cpp2538
-rw-r--r--tdeio/tdeio/kdirlister.h634
-rw-r--r--tdeio/tdeio/kdirlister_p.h358
-rw-r--r--tdeio/tdeio/kdirnotify.cpp40
-rw-r--r--tdeio/tdeio/kdirnotify.h84
-rw-r--r--tdeio/tdeio/kdirnotify_stub.cpp101
-rw-r--r--tdeio/tdeio/kdirnotify_stub.h32
-rw-r--r--tdeio/tdeio/kdirwatch.cpp1774
-rw-r--r--tdeio/tdeio/kdirwatch.h290
-rw-r--r--tdeio/tdeio/kdirwatch_p.h158
-rw-r--r--tdeio/tdeio/kemailsettings.cpp272
-rw-r--r--tdeio/tdeio/kemailsettings.h147
-rw-r--r--tdeio/tdeio/kfilterbase.cpp76
-rw-r--r--tdeio/tdeio/kfilterbase.h116
-rw-r--r--tdeio/tdeio/kfilterdev.cpp484
-rw-r--r--tdeio/tdeio/kfilterdev.h204
-rw-r--r--tdeio/tdeio/kimageio.cpp566
-rw-r--r--tdeio/tdeio/kimageio.h170
-rw-r--r--tdeio/tdeio/kimageiofactory.h142
-rw-r--r--tdeio/tdeio/klimitediodevice.h105
-rw-r--r--tdeio/tdeio/kmdbase.h6
-rw-r--r--tdeio/tdeio/kmessageboxwrapper.h56
-rw-r--r--tdeio/tdeio/kmimemagic.cpp2317
-rw-r--r--tdeio/tdeio/kmimemagic.h218
-rw-r--r--tdeio/tdeio/kmimetype.cpp1172
-rw-r--r--tdeio/tdeio/kmimetype.h641
-rw-r--r--tdeio/tdeio/kmimetypechooser.cpp298
-rw-r--r--tdeio/tdeio/kmimetypechooser.h180
-rw-r--r--tdeio/tdeio/kmimetyperesolver.h255
-rw-r--r--tdeio/tdeio/knfsshare.cpp219
-rw-r--r--tdeio/tdeio/knfsshare.h86
-rw-r--r--tdeio/tdeio/kprotocolinfo.cpp257
-rw-r--r--tdeio/tdeio/kprotocolinfo.h688
-rw-r--r--tdeio/tdeio/kprotocolmanager.cpp534
-rw-r--r--tdeio/tdeio/kprotocolmanager.h389
-rw-r--r--tdeio/tdeio/kremoteencoding.cpp95
-rw-r--r--tdeio/tdeio/kremoteencoding.h127
-rw-r--r--tdeio/tdeio/krun.cpp1574
-rw-r--r--tdeio/tdeio/krun.h512
-rw-r--r--tdeio/tdeio/ksambashare.cpp239
-rw-r--r--tdeio/tdeio/ksambashare.h85
-rw-r--r--tdeio/tdeio/kscan.cpp185
-rw-r--r--tdeio/tdeio/kscan.h370
-rw-r--r--tdeio/tdeio/kservice.cpp934
-rw-r--r--tdeio/tdeio/kservice.h562
-rw-r--r--tdeio/tdeio/kservice_p.h41
-rw-r--r--tdeio/tdeio/kservicefactory.cpp291
-rw-r--r--tdeio/tdeio/kservicefactory.h113
-rw-r--r--tdeio/tdeio/kservicegroup.cpp724
-rw-r--r--tdeio/tdeio/kservicegroup.h353
-rw-r--r--tdeio/tdeio/kservicegroupfactory.cpp148
-rw-r--r--tdeio/tdeio/kservicegroupfactory.h80
-rw-r--r--tdeio/tdeio/kservicetype.cpp366
-rw-r--r--tdeio/tdeio/kservicetype.h251
-rw-r--r--tdeio/tdeio/kservicetypefactory.cpp300
-rw-r--r--tdeio/tdeio/kservicetypefactory.h123
-rw-r--r--tdeio/tdeio/kshellcompletion.cpp311
-rw-r--r--tdeio/tdeio/kshellcompletion.h85
-rw-r--r--tdeio/tdeio/kshred.cpp276
-rw-r--r--tdeio/tdeio/kshred.h156
-rw-r--r--tdeio/tdeio/ktar.cpp980
-rw-r--r--tdeio/tdeio/ktar.h171
-rw-r--r--tdeio/tdeio/ktrader.cpp186
-rw-r--r--tdeio/tdeio/ktrader.h295
-rw-r--r--tdeio/tdeio/ktraderparse.cpp159
-rw-r--r--tdeio/tdeio/ktraderparse.h52
-rw-r--r--tdeio/tdeio/ktraderparsetree.cpp714
-rw-r--r--tdeio/tdeio/ktraderparsetree.h371
-rw-r--r--tdeio/tdeio/kurifilter.cpp451
-rw-r--r--tdeio/tdeio/kurifilter.h667
-rw-r--r--tdeio/tdeio/kurlcompletion.cpp1604
-rw-r--r--tdeio/tdeio/kurlcompletion.h236
-rw-r--r--tdeio/tdeio/kurlpixmapprovider.cpp33
-rw-r--r--tdeio/tdeio/kurlpixmapprovider.h59
-rw-r--r--tdeio/tdeio/kuserprofile.cpp355
-rw-r--r--tdeio/tdeio/kuserprofile.h282
-rw-r--r--tdeio/tdeio/kzip.cpp1460
-rw-r--r--tdeio/tdeio/kzip.h284
-rw-r--r--tdeio/tdeio/lex.c1759
-rw-r--r--tdeio/tdeio/lex.l126
-rw-r--r--tdeio/tdeio/metainfojob.cpp184
-rw-r--r--tdeio/tdeio/metainfojob.h119
-rw-r--r--tdeio/tdeio/netaccess.cpp536
-rw-r--r--tdeio/tdeio/netaccess.h540
-rw-r--r--tdeio/tdeio/observer.cpp417
-rw-r--r--tdeio/tdeio/observer.h213
-rw-r--r--tdeio/tdeio/passdlg.cpp367
-rw-r--r--tdeio/tdeio/passdlg.h175
-rw-r--r--tdeio/tdeio/paste.cpp308
-rw-r--r--tdeio/tdeio/paste.h125
-rw-r--r--tdeio/tdeio/pastedialog.cpp84
-rw-r--r--tdeio/tdeio/pastedialog.h64
-rw-r--r--tdeio/tdeio/posixacladdons.cpp236
-rw-r--r--tdeio/tdeio/posixacladdons.h47
-rw-r--r--tdeio/tdeio/previewjob.cpp597
-rw-r--r--tdeio/tdeio/previewjob.h182
-rw-r--r--tdeio/tdeio/progressbase.cpp180
-rw-r--r--tdeio/tdeio/progressbase.h271
-rw-r--r--tdeio/tdeio/renamedlg.cpp574
-rw-r--r--tdeio/tdeio/renamedlg.h153
-rw-r--r--tdeio/tdeio/renamedlgplugin.h59
-rw-r--r--tdeio/tdeio/scheduler.cpp922
-rw-r--r--tdeio/tdeio/scheduler.h364
-rw-r--r--tdeio/tdeio/sessiondata.cpp311
-rw-r--r--tdeio/tdeio/sessiondata.h67
-rw-r--r--tdeio/tdeio/skipdlg.cpp143
-rw-r--r--tdeio/tdeio/skipdlg.h61
-rw-r--r--tdeio/tdeio/slave.cpp519
-rw-r--r--tdeio/tdeio/slave.h270
-rw-r--r--tdeio/tdeio/slavebase.cpp1315
-rw-r--r--tdeio/tdeio/slavebase.h847
-rw-r--r--tdeio/tdeio/slaveconfig.cpp225
-rw-r--r--tdeio/tdeio/slaveconfig.h106
-rw-r--r--tdeio/tdeio/slaveinterface.cpp550
-rw-r--r--tdeio/tdeio/slaveinterface.h290
-rw-r--r--tdeio/tdeio/statusbarprogress.cpp166
-rw-r--r--tdeio/tdeio/statusbarprogress.h112
-rw-r--r--tdeio/tdeio/tcpslavebase.cpp1343
-rw-r--r--tdeio/tdeio/tcpslavebase.h389
-rw-r--r--tdeio/tdeio/tdefilefilter.cpp134
-rw-r--r--tdeio/tdeio/tdefilefilter.h170
-rw-r--r--tdeio/tdeio/tdefileitem.cpp1202
-rw-r--r--tdeio/tdeio/tdefileitem.h671
-rw-r--r--tdeio/tdeio/tdefilemetainfo.cpp1859
-rw-r--r--tdeio/tdeio/tdefilemetainfo.h1738
-rw-r--r--tdeio/tdeio/tdefileshare.cpp346
-rw-r--r--tdeio/tdeio/tdefileshare.h165
-rw-r--r--tdeio/tdeio/tdelficon.cpp89
-rw-r--r--tdeio/tdeio/tdelficon.h54
-rw-r--r--tdeio/tdeio/thumbcreator.h124
-rw-r--r--tdeio/tdeio/yacc.c1522
-rw-r--r--tdeio/tdeio/yacc.h93
-rw-r--r--tdeio/tdeio/yacc.y126
-rw-r--r--tdeio/tdeioexec/CMakeLists.txt42
-rw-r--r--tdeio/tdeioexec/Makefile.am19
-rw-r--r--tdeio/tdeioexec/README26
-rw-r--r--tdeio/tdeioexec/main.cpp294
-rw-r--r--tdeio/tdeioexec/main.h35
-rw-r--r--tdeio/tdeioslave.upd18
-rw-r--r--tdeio/tests/CMakeLists.txt36
-rw-r--r--tdeio/tests/Makefile.am91
-rw-r--r--tdeio/tests/dataprotocoltest.cpp287
-rw-r--r--tdeio/tests/dummymeta.cpp20
-rw-r--r--tdeio/tests/dummymeta.desktop54
-rw-r--r--tdeio/tests/dummymeta.h20
-rw-r--r--tdeio/tests/getalltest.cpp44
-rw-r--r--tdeio/tests/jobtest.cpp613
-rw-r--r--tdeio/tests/jobtest.h79
-rw-r--r--tdeio/tests/kacltest.cpp309
-rw-r--r--tdeio/tests/kacltest.h53
-rw-r--r--tdeio/tests/kdcopcheck.cpp132
-rw-r--r--tdeio/tests/kdcopcheck.h28
-rw-r--r--tdeio/tests/kdefaultprogresstest.cpp39
-rw-r--r--tdeio/tests/kdirlistertest.cpp162
-rw-r--r--tdeio/tests/kdirlistertest.h120
-rw-r--r--tdeio/tests/kdirwatchtest.cpp82
-rw-r--r--tdeio/tests/kdirwatchtest.h33
-rw-r--r--tdeio/tests/kdirwatchunittest.cpp180
-rw-r--r--tdeio/tests/kdirwatchunittest.h66
-rw-r--r--tdeio/tests/kfiltertest.cpp118
-rw-r--r--tdeio/tests/kionetrctest.cpp71
-rw-r--r--tdeio/tests/kiopassdlgtest.cpp32
-rw-r--r--tdeio/tests/kmfitest.cpp28
-rw-r--r--tdeio/tests/kmimefromext.cpp53
-rw-r--r--tdeio/tests/kmimemagictest.cpp54
-rw-r--r--tdeio/tests/kmimetypetest.cpp76
-rw-r--r--tdeio/tests/kpropsdlgtest.cpp35
-rw-r--r--tdeio/tests/kprotocolinfotest.cpp59
-rw-r--r--tdeio/tests/kruntest.cpp209
-rw-r--r--tdeio/tests/kruntest.h58
-rw-r--r--tdeio/tests/kscantest.cpp16
-rw-r--r--tdeio/tests/kshredtest.cpp74
-rw-r--r--tdeio/tests/ktartest.cpp178
-rw-r--r--tdeio/tests/kurifiltertest.cpp361
-rw-r--r--tdeio/tests/kurlcompletiontest.cpp189
-rw-r--r--tdeio/tests/kziptest.cpp435
-rw-r--r--tdeio/tests/metatest.cpp321
-rw-r--r--tdeio/tests/netaccesstest.cpp48
-rw-r--r--tdeio/tests/previewtest.cpp64
-rw-r--r--tdeio/tests/previewtest.h25
-rw-r--r--tdeio/tests/speed.cpp139
-rw-r--r--tdeio/tests/speed.h24
-rw-r--r--tdeio/tests/tdeioslavetest.cpp555
-rw-r--r--tdeio/tests/tdeioslavetest.h108
-rw-r--r--tdeio/tests/tdesycocatest.cpp360
-rw-r--r--tdeio/tests/tdesycocaupdatetest.cpp11
-rw-r--r--tdeio/tests/tdetradertest.cpp108
-rw-r--r--tdeio/tests/wronglocalsizes.zipbin0 -> 325 bytes
-rwxr-xr-xtdeio/useragent.pl13
593 files changed, 156273 insertions, 0 deletions
diff --git a/tdeio/CMakeLists.txt b/tdeio/CMakeLists.txt
new file mode 100644
index 000000000..826fbf743
--- /dev/null
+++ b/tdeio/CMakeLists.txt
@@ -0,0 +1,71 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_definitions(
+ -D_LARGEFILE64_SOURCE=1
+)
+
+add_subdirectory( kssl )
+add_subdirectory( tdeio )
+add_subdirectory( bookmarks )
+add_subdirectory( tdefile )
+add_subdirectory( pics )
+add_subdirectory( tdeioexec )
+add_subdirectory( httpfilter )
+add_subdirectory( misc )
+add_subdirectory( kpasswdserver )
+add_subdirectory( tests )
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+ ${LIBR_LIBDIR}
+)
+
+
+##### other data ################################
+
+install( FILES magic DESTINATION ${MIME_INSTALL_DIR} )
+
+install( FILES
+ application.desktop kurifilterplugin.desktop
+ kcomprfilter.desktop kscan.desktop kdatatool.desktop
+ tdefileplugin.desktop tdecmodule.desktop
+ DESTINATION ${SERVICETYPES_INSTALL_DIR} )
+
+install( FILES tdeioslave.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+install( PROGRAMS useragent.pl proxytype.pl DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+install( FILES renamedlgplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
+install( FILES kpasswdserver.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded )
+install( FILES data.protocol DESTINATION ${SERVICES_INSTALL_DIR} )
+
+
+if( HAVE_ELFICON )
+ set( ELFICON_STATIC_LIB tdelficon-static )
+endif( HAVE_ELFICON )
+
+
+##### libtdeio ####################################
+
+set( target tdeio )
+
+configure_file( ${CMAKE_SOURCE_DIR}/cmake/modules/template_dummy_cpp.cmake dummy.cpp COPYONLY )
+
+tde_add_library( ${target} SHARED
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
+ VERSION 4.2.0
+ EMBED kssl-static tdeiocore-static tdesycoca-static kbookmarks-static tdefile-static ${ELFICON_STATIC_LIB}
+ LINK ltdlc-static tdeui-shared tdesu-shared tdewalletclient-shared ${LIBR_LIBRARIES}
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tdeio/DESIGN b/tdeio/DESIGN
new file mode 100644
index 000000000..22307c5c0
--- /dev/null
+++ b/tdeio/DESIGN
@@ -0,0 +1,272 @@
+DESIGN:
+=======
+
+libtdeio uses tdeioslaves (separate processes) that handle a given protocol.
+Launching those slaves is taken care of by the tdeinit/tdelauncher tandem,
+which are notified by DCOP.
+
+Connection is the most low-level class, the one that encapsulates the pipe.
+
+SlaveInterface is the main class for transferring anything to the slave
+and Slave, which inherits SlaveInterface, is the sub class that Job should handle.
+
+A slave inherits SlaveBase, which is the other half of SlaveInterface.
+
+The scheduling is supposed to be on a two level basis. One is in the daemon
+and one is in the application. The daemon one (as opposite to the holy one? :)
+will determine how many slaves are ok for this app to be opened and it will
+also assign tasks to actually existing slaves.
+The application will still have some kind of a scheduler, but it should be
+a lot simpler as it doesn't have to decide anything besides which
+task goes to which pool of slaves (related to the protocol/host/user/port)
+and move tasks around.
+Currently a design study to name it cool is in scheduler.cpp but in the
+application side. This is just to test other things like recursive jobs
+and signals/slots within SlaveInterface. If someone feels brave, the scheduler
+is yours!
+On a second thought: at the daemon side there is no real scheduler, but a
+pool of slaves. So what we need is some kind of load calculation of the
+scheduler in the application and load balancing in the daemon.
+
+A third thought: Maybe the daemon can just take care of a number of 'unused'
+slaves. When an application needs a slave, it can request it from the daemon.
+The application will get one, either from the pool of unused slaves,
+or a new one will be created. This keeps things simple at the daemon level.
+It is up to the application to give the slaves back to the daemon.
+The scheduler in the application must take care not to request too many
+slaves and could implement priorities.
+
+Thought on usage:
+* Typically a single slave-type is used exclusively in one application. E.g.
+http slaves are used in a web-browser. POP3 slaves used in a mail program.
+
+* Sometimes a single program can have multiple roles. E.g. konqueror is
+both a web-browser and a file-manager. As a web-browser it primarily uses
+http-slaves as a file-manager file-slaves.
+
+* Selecting a link in konqueror: konqueror does a partial download of
+the file to check the mimetype (right??) then the application is
+started which downloads the complete file. In this case it should
+be able to pass the slave which does the partial download from konqueror
+to the application where it can do the complete download.
+
+Do we need to have a hard limit on the number of slaves/host?
+It seems so, because some protocols are about to fail if you
+have two slaves running in parralel (e.g. POP3)
+This has to be implemented in the daemon because only at daemon
+level all the slaves are known. As a consequence slaves must
+be returned to the daemon before connecting to another host.
+(Returning the slaves back to the daemon after every job is not
+strictly needed and only causes extra overhead)
+
+Instead of actually returning the slave to the daemon, it could
+be enough to ask 'recycling permission' from the daemon: the
+application asks the daemon whether it is ok to use a slave for
+another host. The daemon can then update its administration of
+which slave is connected to which host.
+
+The above does of course not apply to hostless protocols (like file).
+(They will never change host).
+
+Apart from a 'hard limit' on the number of slaves/host we can have
+a 'soft limit'. E.g. upon connection to a HTTP 1.1 server, the web-
+server tells the slave the number of parallel connections allowed.
+THe simplest solution seems to be to treat 'soft limits' the same
+as 'hard limits'. This means that the slave has to communicate the
+'soft limit' to the daemon.
+
+Jobs using multiple slaves.
+
+If a job needs multiple slaves in parallel (e.g. copying a file from
+a web-server to a ftp-server or browsing a tar-file on a ftp-site)
+we must make sure to request the daemon for all slaves together since
+otherwise there is a risk of deadlock.
+
+(If two applications both need a 'pop3' and a 'ftp' slave for a single
+job and only a single slave/host is allowed for pop3 and ftp, we must
+prevent giving the single pop3 slave to application #1 and the single
+ftp slave to application #2. Both applications will then wait till the
+end of times till they get the other slave so that they can start the
+job. (This is a quite unlikely situation, but nevertheless possible))
+
+
+File Operations:
+listRecursive is implemented as listDir and finding out if in the result
+ is a directory. If there is, another listDir job is issued. As listDir
+ is a readonly operation it fails when a directory isn't readable
+ .. but the main job goes on and discards the error, because
+bIgnoreSubJobsError is true, which is what we want (David)
+
+del is implemented as listRecursive, removing all files and removing all
+ empty directories. This basically means if one directory isn't readable
+ we don't remove it as listRecursive didn't find it. But the del will later
+ on try to remove it's parent directory and fail. But there are cases when
+ it would be possible to delete the dir in chmod the dir before. On the
+ other hand del("/") shouldn't list the whole file system and remove all
+ user owned files just to find out it can't remove everything else (this
+ basically means we have to take care of things we can remove before we try)
+
+ ... Well, rm -rf / refuses to do anything, so we should just do the same:
+ use a listRecursive with bIgnoreSubJobsError = false. If anything can't
+ be removed, we just abort. (David)
+
+ ... My concern was more that the fact we can list / doesn't mean we can
+ remove it. So we shouldn't remove everything we could list without checking
+ we can. But then the question arises how do we check whether we can remove it?
+ (Stephan)
+
+ ... I was wrong, rm -rf /, even as a user, lists everything and removes
+ everything it can (don't try this at home!). I don't think we can do
+ better, unless we add a protocol-dependent "canDelete(path)", which is
+ _really_ not easy to implement, whatever protocol. (David)
+
+
+Lib docu
+========
+
+mkdir: ...
+
+rmdir: ...
+
+chmod: ...
+
+special: ...
+
+stat: ...
+
+get is implemented as TransferJob. Clients get 'data' signals with the data.
+A data block of zero size indicates end of data (EOD)
+
+put is implemented as TransferJob. Clients have to connect to the
+'dataReq' signal. The slave will call you when it needs your data.
+
+mimetype: ...
+
+file_copy: copies a single file, either using CMD_COPY if the slave
+ supports that or get & put otherwise.
+
+file_move: moves a single file, either using CMD_RENAME if the slave
+ supports that, CMD_COPY + del otherwise, or eventually
+ get & put & del.
+
+file_delete: delete a single file.
+
+copy: copies a file or directory, recursively if the latter
+
+move: moves a file or directory, recursively if the latter
+
+del: deletes a file or directory, recursively if the latter
+
+PROGRESS DISPLAYING :
+=====================
+Taj brought up the idea of deligating all progress informations to an extern
+GUI daemon which could be provided in several implementations - examples
+are popup dialogs (most are annoyed by them, like me :) or a kicker applet
+or something completely different. This would also remove the dependency on
+libtdeui (I hope).
+Conclusion: tdeio_uiserver is this single GUI daemon, but the dependency on
+libtdeui couldn't be removed (for many reasons, including Job::showErrorDialog())
+
+A. progress handling
+---------------------
+There will be two ways how the application can display progress :
+
+1. regular apps will use NetAccess for all kio operations and will not care
+ about progress handling :
+ - NetAccess creates Job
+ - NetAccess creates JobObserver that will connect to the Job's signals and
+ pass them via dcop to the running GUI Progress Server
+
+2. apps that want to do some handling with progress dialogs like Caitoo or
+ KMail :
+ - app creates Job
+ - app creates a progress dialog : this should be a ProgressBase descendant
+ e.g. StatusProgress or custom progress dialog
+ - app calls progress->setJob( job ) in order to connect job's signals with
+ progress dialog slots
+
+B. customized progress dialogs
+-------------------------------
+ This will be similar to what we had before.
+
+ - ProgressBase class that all other dialogs will inherit.
+ will contain an initialization method setJob( TDEIO::Job*) for apps of the
+ second class (see A.2 above), that will connect job's signals to dialog's
+ slots
+
+ - DefaultProgress ( former KIOSimpleProgressDialog ) that will be used for
+ regular progress dialogs created by GUI Progress Server
+
+ - StatusProgress ( former KIOLittleProgressDialog ) that can be used for
+ embedding in status bar
+
+C. GUI Progress Server
+-----------------------
+ This is a special progress server.
+ - createProgress() will either create a DefaultProgress dialog or add new entry
+ in a ListProgress ( an all-jobs-in-one progress dialog )
+ - after receiving signals from the JobObserver via DCOP it will call
+ appropriate method of progress dialog ( either in DefaultProgress or ListProgress )
+ - ListProgres can be a Caitoo style dialog, kicker applet or both in one.
+
+D. Some notes
+--------------
+ 1. most of the apps will not care at all about the progress display
+ 2. user will be able to choose whether he wants to see separate progress
+ dialogs or all-in-one ListProgress dialog
+ 3. developers can create their custom progress dialogs that inherit
+ ProgressBase and do any manipulation with a dialog if they use a second
+ approach ( see A.2 above )
+
+
+Streaming
+---------
+
+ 1. We currently support a streaming "GET": e.g. file:/tmp/test.gz#gzip:/
+ works. The following should also work: file:/tmp/test.gz.gz#gzip:/#gzip:/
+ The current approach makes a TrasnferJob for gzip:/ and then adds a
+ subjob for "file:/tmp/test.gz.gz#gzip:/" which itself adds a subjob
+ for "file:/tmp/test.gz.gz".
+ 2. This doesn't extend very well to PUT, because there the order should
+ basically be the other way around, but the "input" to the job as a whole
+ should go to the "gzip:/" job, not to the "file:/tmp/test.gz.gz."
+ It would probably be easier to implement such a job in the way the
+ current "CopyJob" is done. Have a Job and make all sub-urls sub-jobs of
+ this Job.
+ 3. As a result of 1. COPY FROM an url like file:/tmp/test.gz#gzip:/ should
+ work. COPY TO does not, because that would require PUT.
+
+
+Resuming
+--------
+
+A rough note for now, just to have this somewhere :
+(PJ=put-job, GJ=get-job)
+
+PJ can't resume:
+PJ-->app: canResume(0) (emitted by dataReq)
+GJ-->app: data()
+PJ-->app: dataReq()
+app->PJ: data()
+
+PJ can resume but GJ can't resume:
+PJ-->app: canResume(xx)
+app->GJ: start job with "resume=xxx" metadata.
+GJ-->app: data()
+PJ-->app: dataReq()
+app->PJ: data()
+
+PJ can resume and GJ can resume:
+PJ-->app: canResume(xx)
+app->GJ: start job with "resume=xxx" metadata.
+GJ-->app: canResume(xx)
+GJ-->app: data()
+PJ-->app: dataReq()
+app->PJ: canResume(xx)
+app->PJ: data()
+
+So when the slave supports resume for "put" it has to check after the first
+dataRequest() whether it has got a canResume() back from the app. If it did
+it must resume. Otherwise it must start from 0.
+
+
diff --git a/tdeio/DESIGN.krun b/tdeio/DESIGN.krun
new file mode 100644
index 000000000..9ac31f433
--- /dev/null
+++ b/tdeio/DESIGN.krun
@@ -0,0 +1,35 @@
+
+konq_run / krun should determine the mimetype by actually
+getting the contents of the URL. It should then put the slave
+on hold and tell the job-scheduler which request the
+slave is currently handling. (Status: implemented in konq_run)
+
+Now krun/konq_run should determine which client should process the
+result of the request.
+
+* When the client belongs to the same process, no action needs to be
+taken. When a new job is created for the request which is on hold the
+existing slave will be re-used and the request resumed.
+(Status: implemented)
+
+* When the client is an external process, the on-hold-slave should be
+removed from the job-scheduler and should connect itself with
+tdelauncher. This is hard because it must ensure that the external
+program does not request the slave before it has been transfered to
+tdelauncher. (Status: to be done)
+
+* When a slave is on hold but not used for a certain period of time,
+or, when another slave is put on hold, the slave should be killed.
+(Status: almost done)
+
+=====
+
+The slave must emit "mimetype" during a GET before the first data is send.
+
+It may wait with sending "mimetype" until it has enough data to
+determine the mimetype, but it should not pass any data along before it has
+send the mimetype.
+
+Currently only http _always_ sends a mimetype.
+
+
diff --git a/tdeio/DESIGN.metadata b/tdeio/DESIGN.metadata
new file mode 100644
index 000000000..783d7f52a
--- /dev/null
+++ b/tdeio/DESIGN.metadata
@@ -0,0 +1,147 @@
+METADATA
+========
+
+Applications can provide "metadata" to the slaves. Metadata can influence
+the behavior of a slave and is usally protocol dependent. MetaData consists
+of two strings: a "key" and a "value".
+
+
+The following keys are currently in use:
+
+Key Value(s) Description
+---- -------- -----------
+
+referrer string The URL from which the request originates. (read by http)
+
+modified string The modification date of the document (set by http)
+
+accept string List of mimetypes to accept separated by a ", ". (read by http)
+
+SendUserAgent bool Whether to send a User-Agent (read by http)
+UserAgent string The user agent name to send to remote host (read by http)
+
+content-type string The content type of the data to be uploaded (read by http)
+media-* string Media-Parameter attributes (e.g. media-boundary)
+
+cache "cache" Use entry from cache if available.
+ "cacheonly" Do not do any remote lookups, fail if not in cache. (read by http)
+ "verify" Use entry from cache, verify with remote server if expired
+ "refresh" Use entry from cache after verifying with remote server
+ "reload" Do not do any cache lookups.
+
+no-cache bool Flag that indicates whether caching is enabled/disabled
+
+window-id number winId() of the window the request is associated with.
+
+resume number Try to get the file starting at the given offset (set by TransferJob)
+
+charset string Charset of the current content as returned by a HTTP Header Response.
+
+Charsets string Charset(s) send in the "Accept-Charset:" HTTP Request Header.
+
+Languages string Language(s) send in the "Accept-Language:" HTTP Request Header.
+
+content-
+disposition string Suggested name to Save a file as as returned by a HTTP Header Response.
+
+request-id number Sequence number to identify requests in a MultiGet command.
+
+expire-date number Date on which a cache entry needs validation.
+
+cache-creation-date number Date on which a cache entry has been created.
+
+http-refresh string Passes HTTP Refresh meta-data back to the application.
+
+cookies "auto" Use kcookiejar to lookup and collect cookies (default)
+ "manual" Cookies set in "setcookies" are send, received cookies are reported via "setcookies".
+ "none" No cookies are send, received cookies are discarded.
+
+setcookies string Used to send/receive HTTP cookies when "cookies" is set to "manual".
+
+errorPage bool Flag that indicates that an errorPage() is preferred over an error(). (default:true)
+
+no-auth bool Flag that indicates that no authentication attempts should be made.
+no-auth-prompt bool Flag that indicates that only cached authentication tokens should be used.
+
+ssl_activate_warnings bool Flag that disables SSL warning dialogs if set to false. (default: true)
+
+ssl_was_in_use bool Flag to tell TCPSlaveBase if SSL was in use in the previous transaction. (default: false)
+
+ssl_in_use bool Set in TCPSlaveBase to tell the caller if SSL is in use. (default: assume false)
+
+ssl_using_client_cert bool Set in TCPSlaveBase to tell the caller if the session is using a client certificate (default: assume false)
+
+ssl_no_client_cert bool Flag to tell TCPSlaveBase if it should, under no circumstances, use a client certificate. (default: false)
+
+ssl_force_cert_prompt bool Flag to tell TCPSlaveBase to force the client certificate dialog to appear on this connection. ssl_no_client_cert overrides this flag. This does not force the user to actually choose a certificate. (default: false)
+
+ssl_demand_certificate bool Flag to tell TCPSlaveBase to demand that a client certificate is used for this connection. (default: false)
+
+ssl_militant bool Flag to tell TCPSlaveBase "do it right, or don't do it at all". This means that if the certificate check or any other security test fails, just silently fail the connection. This is of particular use to favicon code. (default: false)
+
+ssl_cipher string Set in TCPSlaveBase to tell the caller which cipher is currently being used.
+
+ssl_cipher_desc string Set in TCPSlaveBase to describe the details of the current cipher being used.
+
+ssl_cipher_version string Set in TCPSlaveBase to describe the version of the cipher being used.
+
+ssl_cipher_used_bits integer Set in TCPSlaveBase to relay the number of bits of the key actually being used in this cipher and connection.
+
+ssl_cipher_bits integer Set in TCPSlaveBase to relay the number of bits the key is capable of in this cipher and connection.
+
+ssl_peer_ip string Set in TCPSlaveBase to tell the caller the IP address of the peer.
+
+ssl_cert_state integer Set in TCPSlaveBase to relay the state of the certificate check, without considering the cache settings. Can be checked with KSSLCertificate enumeration.
+
+ssl_peer_certificate string Set in TCPSlaveBase to relay the base64 encoding of the X.509 certificate presented by the peer.
+
+ssl_peer_chain string Set, if present, in TCPSlaveBase to relay the entire certificate chain presented by the peer. The is base64 encoded and \n delimited.
+
+ssl_action string Set in TCPSlaveBase to determine what the user wishes to do about the connection. Enumerated to {"accept", "reject"} currently.
+
+ssl_parent_ip string Set in TCPSlaveBase and in the caller. If this is the parent frame of a frame of the session (really only applies to https), this variable is set so that it can be passed back to the child frames. It is necessary to send it to child frames so that they can do a full certificate check.
+
+ssl_parent_cert string Set in TCPSlaveBase and in the caller. As above, this must be passed to child frames by the caller so that it can compare against the certificate presented in the child frames. It is a base64 encoding of the X.509 presented.
+
+ssl_session_id string Set in TCPSlaveBase to indicate the SSL session ID in base64 encoded ASN.1 encoded binary format. Also set in the caller to indicate to TCPSlaveBase to reuse a particular session ID.
+
+ssl_proxied bool Presently exists only if true. Set in TCPSlaveBase to indicate that a proxy is in use for this SSL connection.
+
+main_frame_request bool Actually for SSL, this is set in the caller to tell TCPSlaveBase if this is the request for the main frame of an html page. (dfault: true)
+
+HTTP-Version string The HTTP version in use for kio_http (set by http)
+
+PropagateHttpHeader bool Whether HTTP headers should be send back (read by http)
+
+HTTP-Headers string The HTTP headers, concatenated, \n delimited (set by http)
+ Requires PropagateHttpHeader to be set.
+
+PrivacyPolicy stringlist \n delimited URIs referring to P3P privacy
+ policies presented by the HTTP server
+
+PrivacyCompactPolicy stringlist \n delimited P3P compact tag policies
+ presented by the HTTP server
+
+textmode bool When true, switches FTP up/downloads to ascii transfer mode (read by ftp)
+
+DefaultRemoteProtocol string Protocol to redirect file://<hostname>/ URLs to, default is "smb" (read by file)
+
+** NOTE: Anything in quotes ("") under Value(s) indicates literal value.
+
+
+Examples:
+
+E.g. the following disables cookies:
+job = TDEIO::get( KURL("http://www.kde.org"), false, false);
+job->addMetaData("cookies", "none");
+
+If you want to handle cookies yourself, you can do:
+job = TDEIO::get( KURL("http://www.kde.org"), false, false);
+job->addMetaData("cookies", "manual");
+job->addMetaData("setcookies", "Cookie: foo=bar; gnat=gnork");
+
+The above sends two cookies along with the request, any cookies send back by
+the server can be retrieved with job->queryMetaData("cookies") after
+receiving the mimetype() signal or when the job is finished.
+
+The cookiejar is not used in this case.
diff --git a/tdeio/DESIGN.mimetypes b/tdeio/DESIGN.mimetypes
new file mode 100644
index 000000000..7f1d81b11
--- /dev/null
+++ b/tdeio/DESIGN.mimetypes
@@ -0,0 +1,34 @@
+TODO: servicetypes
+TODO: mimetypes
+
+Service type inheritance (X-TDE-Derived)
+========================================
+X-TDE-Derived is for service types. ST1 derives from ST2 means ST1 is more specific than ST2.
+If a service implements ST1, it also implements ST2, but not the other way round.
+
+For instance, KoDocument derives from KParts/ReadWritePart, which derives from KParts/ReadOnlyPart,
+so KWord's part (which implements KoDocument) can be used as a readonly viewer for KWord files
+in Konqueror (which looks for a KParts/ReadOnlyPart).
+
+Mimetype "inheritance"
+======================
+We need a mechanism to also say that "text/xml is a special case of text/plain",
+or "text/docbook is a kind of text/sgml", or "application/x-smb-workgroup is a kind
+of inode/directory", etc. See below.
+
+Why mimetype "inheritance" doesn't use X-TDE-Derived
+====================================================
+The confusing thing is that we said "a mimetype is a servicetype". But that's not exactly correct.
+As Waldo noted, "the ability to open a mimetype" is what's a servicetype.
+So if text/xml said X-TDE-Derived=text/plain (i.e. ST1=text/xml, ST2=text/plain),
+then an application opening text/xml (ST1) could also open text/plain (ST2) - which is not necessarily true.
+
+We want the other way round: to be able to open special kinds of text/plain in a plain text editor.
+This is what X-TDE-IsAlso was introduced for. X-TDE-IsAlso kind of "works the other way" than X-TDE-Derived.
+If M1 is a special kind of M2 (mimetypes), then "the ability to open M2" derives from "the ability to open M1"
+So we say in text/xml: X-TDE-IsAlso=text/plain, and applications that can open text/plain can also open text/xml.
+
+Pattern Accuracy
+======================
+In some cases of inheritance several mimetypes shares the same extension (with the primary case being Ogg Multimedia files).
+This has been solved sofar by matching the extension to most generic mimetype. To indicate that the mimetype can be refined further, the flag X-TDE-PatternsAccuracy can be set. The value to X-TDE-PatternsAccuracy is a number between 0-100, with 100 being the default if not set. Any values below 100 is interpreted as the possibility of further mimetype refinement.
diff --git a/tdeio/DESKTOP_ENTRY_STANDARD b/tdeio/DESKTOP_ENTRY_STANDARD
new file mode 100644
index 000000000..e19cc24c8
--- /dev/null
+++ b/tdeio/DESKTOP_ENTRY_STANDARD
@@ -0,0 +1,373 @@
+ ----------------------------------------------------------------------------------------------------------------------------
+
+ Desktop Entry Standard
+
+ Preston Brown
+
+ <pbrown@kde.org>
+
+ Jonathan Blandford
+
+ <jrb@redhat.com>
+
+ Owen Taylor
+
+ <otaylor@gtk.org>
+
+ Version 0.9.4
+
+ ----------------------------------------------------------------------------------------------------------------------------
+
+ Table of Contents
+
+ Introduction
+
+ Basic format of the file
+
+ Possible value types
+
+ Recognized desktop entry keys
+
+ Character set encoding of the file
+
+ List of valid Exec parameter variables
+
+ Detailed discussion of supporting MIME types
+
+ Extending the format
+
+ A. Example Desktop Entry File
+
+ B. Currently reserved for use within KDE
+
+ C. Deprecated Items
+
+ D. The Legacy-Mixed encoding (Deprecated)
+
+Introduction
+
+ Both the KDE and GNOME desktop environments have adopted a similar format for "desktop entries," or configuration files
+ describing how a particular program is to be launched, how it appears in menus, etc. It is to the larger community's benefit
+ that a unified standard be agreed upon by all parties such that interoperation between the two environments, and indeed any
+ additional environments that implement the specification, becomes simpler.
+
+Basic format of the file
+
+ These desktop entry files should have the extension ".desktop". Determining file type on basis of extension makes determining
+ the file type very easy and quick. When no file extension is present, the desktop system should fall back to recognition via
+ "magic detection." Desktop entries which describe how a directory is to be formatted/displayed should be simply called
+ ".directory".
+
+ The basic format of the desktop entry file requires that there be a "group" header named "[Desktop Entry]". This "group" entry
+ denotes that all {key,value} pairs following it belong in the Desktop Entry group. There may be other groups present in the file
+ (see MIME types discussion below), but this is the most important group which explicitly needs to be supported. This group
+ should also be used as the "magic key" for automatic mime type detection. There should be nothing proceeding this group in the
+ desktop entry file but possibly one or more comments (see below).
+
+ Group headers may not contain the characters '[' and ']' as those delimit the header.
+
+ Lines beginning with a "#" and blank lines are considered comments and will be ignored, however they should be preserved across
+ reads / writes of the desktop entry file.
+
+ Compliant implementations MUST not remove any fields from the file, even if they don't support them. Such fields must be
+ maintained in a list somewhere, and if the file is "rewritten," they will be included. This ensures that any desktop-specific
+ extensions will be preserved even if another system accesses and changes the file.
+
+ Entries in the file are {key,value} pairs in the format:
+
+ Name=Value
+
+ Space before and after the equals sign should be ignored; the "=" sign is the actual delimiter.
+
+ The escape sequences \s, \n, \t, \r, and \\ are supported, meaning ASCII space, newline, tab, carriage return, and backslash,
+ respectively.
+
+Possible value types
+
+ The value types recognized are string, localestring, regexp, boolean (encoded as the string true/false), and numeric.
+
+ The difference between string and localestring is that the value for a string key must contain only ASCII characters and while
+ the value of a localestring key may contain UTF-8 characters. (See section 5.)
+
+ Some keys can have multiple values; these should be separated by a semicolon. Those keys which have several values should have a
+ semicolon as the trailing character. For lists of strings, semicolons are simply not allowed in the strings, there is no escape
+ mechanism.
+
+Recognized desktop entry keys
+
+ Keys with type localestring may be postfixed by [LOCALE], where LOCALE is the locale type of the entry. LOCALE must be of the
+ form lang[_COUNTRY][ ENCODING][ MODIFIER], where _COUNTRY, .ENCODING, and @MODIFIER may be omitted. If a postfixed key occurs,
+ the same key must be also present without the postfix.
+
+ When reading in the desktop entry file, the value of the key is selected by matching the current POSIX locale for the
+ LC_MESSAGES category against the locale postfixes of all occurrences of the key, with the .ENCODING part stripped. The .ENCODING
+ field is used only when the Encoding key for the desktop entry file is Legacy-Mixed, (see Appendix D.)
+
+ The matching of is done as follows. If LC_MESSAGES is of the form LANG_COUNTRY.ENCODING@MODIFIER, then it will match a key of
+ the form LANG_COUNTRY@MODIFIER. If such a key does not exist, it will attempt to match LANG_COUNTRY followed by LANG@MODIFIER.
+ Then, a match against LANG by itself will be attempted. Finally, if no matching key is found the required key without a locale
+ specified is used. The encoding from the LC_MESSAGES value is ignored when matching.
+
+ If LC_MESSAGES does not have a MODIFIER field, then no key with a modifier will be matched. Similarly, if LC_MESSAGES does not
+ have a COUNTRY field, then no key with a country specified will be matched. If LC_MESSAGES just has a LANG field, then it will
+ do a straight match to a key with a similar value. The following table lists possible matches of various LC_MESSAGES in the
+ order in which they are matched. Note that the ENCODING field isn't shown.
+
+ Table 1. Locale Matching
+
+ +-------------------------------------------------------------------------------------------------+
+ | LC_MESSAGES Value | Possible Keys in Order of Matching |
+ |-----------------------+-------------------------------------------------------------------------|
+ | LANG_COUNTRY@MODIFIER | LANG_COUNTRY@MODIFIER, LANG_COUNTRY, LANG@MODIFIER, LANG, Default Value |
+ |-----------------------+-------------------------------------------------------------------------|
+ | LANG_COUNTRY | LANG_COUNTRY, LANG, Default Value |
+ |-----------------------+-------------------------------------------------------------------------|
+ | LANG@MODIFIER | LANG@MODIFIER, LANG, Default Value |
+ |-----------------------+-------------------------------------------------------------------------|
+ | LANG | LANG, Default Value |
+ +-------------------------------------------------------------------------------------------------+
+
+ For example, if the current value of the LC_MESSAGES category is sr_YU Latn and the desktop file includes:
+
+ Name=Foo
+ Name[sr_YU]=...
+ Name[sr Latn]=
+ Name[sr]=...
+
+ then the value of the Name keyed by "sr_YU" is used.
+
+ Case is significant. The keys "Name" and "NAME" are not equivalent. The same holds for group names. Key values are case
+ sensitive as well.
+
+ Keys are either OPTIONAL or REQUIRED. If a key is optional it may or may not be present in the file. However, if it isn't, the
+ implementation of the standard should not blow up, it must provide some sane defaults. Additionally, keys either MUST or MAY be
+ supported by a particular implementation.
+
+ Some keys only make sense in the context when another particular key is also present.
+
+ Some example keys: Name[C], Comment[it].
+
+ Table 2. Standard Keys
+
+ +------------------------------------------------------------------------------------------------------------------------------+
+ | Key | Description | Value Type | REQ? | MUST? | Type |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Type | There are 4 types of desktop entries: Application(1), Link(2), | string | YES | YES | |
+ | | FSDevice(3) and Directory(4). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | Version of Desktop Entry Specification (While the version | | | | |
+ | | field is not required to be present, it should be in all newer | | | | |
+ | Version | implementations of the Desktop Entry specification. If the | numeric | NO | YES | 1-4 |
+ | | version number is not present, a "pre-standard" desktop entry | | | | |
+ | | file is to be assumed). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Encoding | Encoding of the whole desktop entry file (UTF-8 or | string | YES | YES | 1-4 |
+ | | LegacyMixed). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Name | Specific name of the application, for example "Mozilla". | localestring | YES | YES | 1-4 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | GenericName | Generic name of the application, for example "Web Browser". | localestring | NO | YES | 1-4 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | NoDisplay means "this application exists, but don't display it | | | | |
+ | | in the menus". This can be useful to e.g. associate this | | | | |
+ | NoDisplay | application with mimetypes, so that it gets launched from a | boolean | NO | NO | 1-4 |
+ | | file manager (or other apps), without having a menu entry for | | | | |
+ | | it (there are tons of good reasons for this, including e.g. | | | | |
+ | | the netscape -remote, or kfmclient openURL kind of stuff). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Comment | Tooltip for the entry, for example "View sites on the | localestring | NO | YES | 1-4 |
+ | | Internet"; should not be redundant with Name or GenericName. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | Icon to display in file manager, menus, etc. If the name is an | | | | |
+ | | absolute path, the given file will be used. If the name is not | | | | |
+ | Icon | an absolute path, an implementation-dependent search algorithm | string | NO | YES | 1-4 |
+ | | will be used to locate the icon. Icons may be localized with | | | | |
+ | | the Icon[xx]= syntax. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | Hidden should have been called Deleted. It means the user | | | | |
+ | | deleted (at his level) something that was present (at an upper | | | | |
+ | | level, e.g. in the system dirs). It's strictly equivalent to | | | | |
+ | Hidden | the .desktop file not existing at all, as far as that user is | boolean | NO | NO | 1-4 |
+ | | concerned. This can also be used to "uninstall" existing files | | | | |
+ | | (e.g. due to a renaming) - by letting "make install" install a | | | | |
+ | | file with Hidden=true in it. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | A list of regular expressions to match against for a file | | | | |
+ | FilePattern | manager to determine if this entry's icon should be displayed. | regexp(s) | NO | NO | 1 |
+ | | Usually simply the name of the main executable and friends. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | Filename of a binary on disk used to determine if the program | | | | |
+ | TryExec | is actually installed. If not, entry may not show in menus, | string | NO | NO | 1 |
+ | | etc. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Exec | Program to execute, possibly with arguments. | string | NO | YES | 1 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Path | If entry is type Application, the working directory to run the | string | NO | YES | 1 |
+ | | program in. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Terminal | Whether the program runs in a terminal window | boolean | NO | YES | 1 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | SwallowTitle | If entry is swallowed onto the panel, this should be the title | localestring | NO | NO | 1 |
+ | | of window | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | SwallowExec | Program to exec if swallowed app is clicked. | string | NO | NO | 1 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Actions | Additional actions possible, see MIME type discussion in the | string(s) | NO | YES | 1 |
+ | | section called "Detailed discussion of supporting MIME types". | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | MimeType | The MIME type(s) supported by this entry. | regexp(s) | NO | NO | 1 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | SortOrder | This may specify the order in which to display files. | string(s) | NO | NO | 4 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Dev | The device to mount. | string | NO | NO | 3 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | FSType | The type of filesystem to try to mount. | string | NO | NO | 3 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | MountPoint | The mount point of the device in question. | string | NO | NO | 3 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | ReadOnly | Specifies whether or not the device is read-only. | boolean | NO | NO | 3 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | Icon to display when device is not mounted Mounted devices | | | | |
+ | UnmountIcon | display icon from Icon key. UnmountIcons may be localized with | string | NO | NO | 3 |
+ | | the UnmountIcon[xx]= syntax. | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | URL | If entry is Link type, the URL to access. | string | NO | YES | 2 |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | Categories | Categories in which the entry should be shown in a menu (for | string(s) | NO | NO | 1 |
+ | | possible values see the xdg-menu specification). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | A list of strings identifying the environments that should | | | | |
+ | OnlyShowIn / NotShowIn | display/not display a given .desktop item. Only one of these | string(s) | NO | NO | 1-4 |
+ | | keys, either OnlyShowIn or NotShowIn, may appear in a Group. | | | | |
+ | | (for possible values see the xdg-menu specification) | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | If true, it is KNOWN that the application will send a "remove" | | | | |
+ | StartupNotify | message when started with the DESKTOP_LAUNCH_ID environment | boolean | NO | NO | 1 |
+ | | variable set (see the startup notification spec for more | | | | |
+ | | details). | | | | |
+ |------------------------+----------------------------------------------------------------+--------------+------+-------+------|
+ | | If true, it is KNOWN that the application will map at least | | | | |
+ | StartupWMClass | one window with the given string as its WM class or WM name | string | NO | NO | 1 |
+ | | hint (see the startup notification spec for more details). | | | | |
+ +------------------------------------------------------------------------------------------------------------------------------+
+
+Character set encoding of the file
+
+ Desktop entry files are encoded as lines of 8-bit characters separated by LF characters.
+
+ o Key names must contain only the characters 'A-Za-z0-9-'
+
+ o Group names may contain all ASCII characters except for control characters and '[' and ']'.
+
+ o Values of type string may contain all ASCII characters except for control characters.
+
+ o Values of type boolean must either be the string 'true' or 'false'.
+
+ o Numeric values must be a valid floating point number as recognized by the %f specifier for scanf.
+
+ Comment lines are uninterpreted and may contain any character (except for LF). However, using UTF-8 for comment lines that
+ contain characters not in ASCII is encouraged.
+
+ The encoding for values of type localestring is determined by the Encoding field.
+
+List of valid Exec parameter variables
+
+ Each "Exec" field may take a number of arguments which will be expanded by the file manager or program launcher and passed to
+ the program if necessary.
+
+ Literal % characters must be escaped as %%, and adding new format characters is not allowed. It's a fatal error to have an Exec
+ field with a format character not given in the spec (exception to this are the deprecated format characters which can be
+ ignored, that is expanded to no parameters, by the implementation). Again for emphasis: nonstandard extensions are not allowed
+ here - you must add an X-Foo-Exec field if you have nonstandard Exec lines.
+
+ The escaping of the exec parameters is done in the way the mailcap specification describes. Take a look at RFC 1524 for more
+ information.
+
+ Recognized fields are as follows:
+
+ +------------------------------------------------------------------------------------------------------------------------------+
+ | | a single file name, even if multiple files are selected. The system reading the Desktop Entry should recognize that the |
+ | | program in question cannot handle multiple file arguments, and it should should probably spawn and execute multiple |
+ | %f | copies of a program for each selected file if the program is not able to handle additional file arguments. If files are |
+ | | not on the local file system (i.e. HTTP or FTP locations), the files will be copied to the local file system and %f |
+ | | will be expanded to point at the temporary file. Used for programs that do not understand URL syntax. |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %F | a list of files. Use for apps that can open several local files at once. |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %u | a single URL. |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %U | a list of URLs. |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %d | directory containing the file that would be passed in a %f field |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %D | list of directories containing the files that would be passed in to a %F field |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %n | a single filename (without path) |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %N | a list of filenames (without path) |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %i | the Icon field of the desktop entry expanded as two parameters, first "--icon" and then the contents of the Icon field |
+ | | (should not expand as any prameters if the Icon field is empty or missing) |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %c | the translated Name field associated with the desktop entry |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %k | the location of the desktop file as either a uri (if for example gotten from the vfolder system) or a local filename or |
+ | | empty if no location is known |
+ |----+-------------------------------------------------------------------------------------------------------------------------|
+ | %v | the name of the Device entry in the desktop file |
+ +------------------------------------------------------------------------------------------------------------------------------+
+
+Detailed discussion of supporting MIME types
+
+ It is in every desktop's best interest to have thorough support for mime types. The old /etc/mailcap and /etc/mime.types files
+ are rather limited in scope and frankly, are outdated. Various desktop systems have come up with different ways of extending
+ this original system, but none are compatible with each other. The Desktop Entry Standard hopes to be able to provide the
+ beginnings of a solution to this problem.
+
+ At a very basic level, the "Exec" key provides the default action to take when the program described by a desktop entry is used
+ to open a document or data file. Usually this consists of some action along the lines of "kedit %f" or "ee %f". This is a good
+ start, but it isn't as flexible as it can be.
+
+ Let us first establish that a program which supports a MIME type or multiple mime types may be able to support multiple actions
+ on those MIME types as well. The desktop entry may want to define additional actions in addition to the default. The toplevel
+ "Exec" key describes the default action; Let us define this action to also be known as the "Open" action. Additional actions
+ which might be possible include View, Edit, Play, etc. A further revision of this document will probably specify several
+ "standard" actions in addition to the default "Open" action, but in all cases, the number of actions is arbitrary.
+
+ Let us use a sound player as a simple example. Call it sp. The default Exec (Open) action for this program would likely look
+ something like:
+
+ Exec=sp %u
+
+ However, imagine the sound player also supports editing of sound files in a graphical manner. We might wish to define an
+ additional action which could accomodate this. Adding the action would be performed like this:
+
+ Actions=Edit;
+
+ [Desktop Action Edit]
+ Exec=sp -edit %u
+
+ As you can see, defining the action "edit" will enable an additional group of the name [Desktop Action actionname] to be read.
+ This group can contain an additional Exec line, as well as possibly other information like a new Name, Comment, Icon, and Path.
+ Thus right-clicking on a .wav file will show both the default "Open" action and this "Edit" action to both be displayed as
+ choices in the context-menu. A left click (double or single, whichever the file manager implements) would cause the default
+ action to take place. These are implementation-specific details which are up to the implementer, and are not enforced by this
+ standard.
+
+ If no DefaultApp is specified for a particular MIME type, any one of the programs registered which claim to be able to handle
+ the MIME type may become the default handler. This behaviour is undefined and implementation-specific. KDE doesn't use a
+ DefaultApp anymore, but assigns a Preference number to each program, so that the highest number is the one chosen for handling
+ the MIME type.
+
+Extending the format
+
+ If the standard is to be amended with a new {key,value} pair which should be applicable to all supporting parties, a group
+ discussion will take place. This is the preferred method for introducing changes. If one particular party wishes to add a field
+ for personal use, they should prefix the key with the string "X-PRODUCT", i.e. "X-NewDesktop-Foo", following the precedent set
+ by other IETF and RFC standards.
+
+ Alternatively, fields can be placed in their own group, where they may then have arbitrary key names. If this is the case, the
+ group should follow the scheme outlined above, i.e. [X-PRODUCT GROUPNAME] or something similar. These steps will avoid namespace
+ clashes between different yet similar environments.
+
+ ----------------------------------------------------------------------------------------------------------------------------
diff --git a/tdeio/Mainpage.dox b/tdeio/Mainpage.dox
new file mode 100644
index 000000000..7545c29ef
--- /dev/null
+++ b/tdeio/Mainpage.dox
@@ -0,0 +1,120 @@
+/**
+ * \mainpage A network-enabled file management system in a library
+ *
+ * This library implements almost all the file management functions you
+ * will ever need. In fact, the %Trinity file manager, Konqueror also uses
+ * this to provide its network-enabled file management.
+ *
+ * The easiest way to use this library from a %Trinity application is via the
+ * TDEIO::NetAccess class (for easy synchronous access) or via the
+ * TDEIO::Job class (for more complex asynchronous jobs).
+ *
+ * This library also implements the System Configuration Cache (KSycoca).
+ *
+ * KMimeType:
+ * The notion of a file type, already existing in Trinity-1.x
+ *
+ * KService:
+ * To a mimetype are bound one or more applications, now called services.
+ * Services can be applications, but also libraries, dynamically opened.
+ *
+ * KServiceType:
+ * A service type allows the same mechanism to be extended to components.
+ * For instance : the question "what are the koffice plugins" is solved by
+ * a service type called KOfficePlugin, and by every plugin providing
+ * a .desktop file stating that it is a service that implements the servicetype
+ * KOfficePlugin.
+ *
+ * KServiceTypeProfile:
+ * Stores the user's preferences for services bound to mimetypes/servicetypes.
+ *
+ * KTrader:
+ * Use it to query for which services implement a given mimetype/servicetype.
+ * Has its own language, in order to allow complex queries.
+ *
+ *
+ * \section Trinity Filedialog widget and associated classes.
+ *
+ * This library also provides the Trinity file selector widget,
+ * its building blocks and some other widgets, making use of the file dialog.
+ *
+ * The file dialog provides different views; there is a vertically scrolling
+ * view based on KListView, showing things like filename, file size,
+ * permissions etc. in separate columns. And there is a horizontally scrolling
+ * view based on KIconView. Additionally, there are some compound views,
+ * like a view using the icon-view for files on the right side and another
+ * view for directories on the left. A view, that shows a preview for the
+ * currently selected file (using TDEIO::PreviewJob to generate previews)
+ * and any other view to show the files is also available.
+ *
+ * All those views share a common baseclass, named KFileView, which
+ * defines the interface for inserting files into a view, removing them,
+ * selecting etc.
+ *
+ * The one class encapsulating all those views and adding browsing capabilities
+ * to them is KDirOperator. It allows the user to switch between different
+ * views.
+ *
+ * KFileTreeView is a KListView based widget that displays files and/or
+ * directories as a tree. It does not implement the KFileView interface,
+ * however, so it can't be used with KDirOperator.
+ *
+ * Besides the filebrowsing widgets, there is the KPropertiesDialog class,
+ * implementing a dialog showing the name, permissions, icons, meta
+ * information and all kinds of properties of a file, as well as providing a
+ * means to modify them.
+ *
+ * The KPropertiesDialog is extensible with plugin-pages via the
+ * KPropsDlgPlugin class.
+ *
+ * The KIconDialog class shows a list of icons installed on the system (as
+ * accessible via KIconLoader) and allows the user to select one.
+ *
+ * KOpenWithDlg implements a dialog to choose an application from, that is
+ * to be run, e.g. to let the user choose an application to open a file/url
+ * with.
+ *
+ *
+ * KFileDialog:
+ * The class providing the file selector dialog. It combines a KDirOperator,
+ * KURLBar and several other widgets.
+ *
+ * KDirOperator:
+ * The class encapsulating different KFileViews, offering file browsing and
+ * file selection. Asynchronous, network transparent reading of directories
+ * is performed via the KIO library.
+ *
+ * KURLRequester:
+ * A widget to be used for asking for a filename/path/URL. It consists of a
+ * KLineEdit (or KComboBox) and a button. Activating the button
+ * will open a KFileDialog. Typing in the lineedit is aided with
+ * filename completion.
+ *
+ * KURLRequesterDlg:
+ * A dialog to ask for a filename/path/URL, using KURLRequester.
+ *
+ * KFileView:
+ * The base class for all views to be used with KDirOperator.
+ *
+ * KFileIconView:
+ * The KFileView based on KIconView.
+ *
+ * KFileDetailView:
+ * The KFileView based on KListView.
+ *
+ * KFilePreview:
+ * The KFileView, combining a widget showing preview for a selected file
+ * and another KFileView for browsing.
+ *
+ * KURLBar:
+ * A widget offering a number of clickable entries which represent a URL,
+ * aligned horizontally or vertically. The entries are customizable by the
+ * user both on a per application basis or for all applications (URLs, their
+ * icon and the description can be added, removed or edited by the user).
+ * This is the widget used as "sidebar" in the KFileDialog.
+ *
+ * KFileMetaInfoWidget:
+ * A widget that allows viewing and editing of meta data of a file, utilizing
+ * KFileMetaInfo.
+ *
+ */
diff --git a/tdeio/Makefile.am b/tdeio/Makefile.am
new file mode 100644
index 000000000..aa23fcb5a
--- /dev/null
+++ b/tdeio/Makefile.am
@@ -0,0 +1,67 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Torben Weis (weis@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.
+
+AM_CPPFLAGS = -D_LARGEFILE64_SOURCE
+
+INCLUDES= -I$(srcdir)/.. $(all_includes) $(SSL_INCLUDES)
+
+SUBDIRS = kssl tdeio bookmarks tdefile . pics tests tdeioexec httpfilter misc kpasswdserver
+
+lib_LTLIBRARIES = libtdeio.la
+
+libtdeio_la_SOURCES = dummy.cpp
+
+libtdeio_la_LDFLAGS = -version-info 6:0:2 -no-undefined $(all_libraries) \
+ $(KDE_MT_LDFLAGS)
+libtdeio_la_LIBADD = kssl/libkssl.la tdeio/libtdeiocore.la \
+ tdeio/libtdesycoca.la bookmarks/libkbookmarks.la tdefile/libtdefile.la \
+ ../tdeui/libtdeui.la ../tdesu/libtdesu.la \
+ ../tdewallet/client/libtdewalletclient.la \
+ $(LIBZ) $(LIBFAM) $(LIBVOLMGT) $(ACL_LIBS) $(LIB_QT) $(LIB_TDECORE) $(top_builddir)/dcop/libDCOP.la $(LIB_X11)
+
+kde_mime_DATA = magic
+kde_servicetypes_DATA = application.desktop kurifilterplugin.desktop \
+ kcomprfilter.desktop kscan.desktop kdatatool.desktop \
+ tdefileplugin.desktop tdecmodule.desktop
+
+EXTRA_DIST = $(kde_mime_DATA)
+
+update_DATA = tdeioslave.upd
+update_SCRIPTS = useragent.pl proxytype.pl
+updatedir = $(kde_datadir)/tdeconf_update
+
+servicetype_DATA = renamedlgplugin.desktop
+servicetypedir = $(kde_servicetypesdir)
+
+kded_DATA = kpasswdserver.desktop
+kdeddir = $(kde_servicesdir)/kded
+
+dataprotocol_DATA = data.protocol
+dataprotocoldir = $(kde_servicesdir)
+
+dummy.cpp:
+ echo >dummy.cpp
+
+messages:
+ $(EXTRACTRC) `find . ../tdeioslave -name "*.rc" -o -name "*.ui"` > rc.cpp
+ $(XGETTEXT) `find . ../tdeioslave -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $(podir)/tdeio.pot
+ rm -f rc.cpp
+
+DOXYGEN_REFERENCES = tdecore tdefx kjs dcop tdeui tdeio/tdeio tdeio/tdefile
+DOXYGEN_EXCLUDE = kssl/kssl
+include ../admin/Doxyfile.am
diff --git a/tdeio/application.desktop b/tdeio/application.desktop
new file mode 100644
index 000000000..d9e9fc3c2
--- /dev/null
+++ b/tdeio/application.desktop
@@ -0,0 +1,124 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=Application
+Name=Application
+Name[af]=Program
+Name[ar]=تطبيق
+Name[az]=Proqram
+Name[be]=Праграма
+Name[bg]=Програма
+Name[bn]=অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨
+Name[br]=Arload
+Name[bs]=Program
+Name[ca]=Aplicació
+Name[cs]=Aplikace
+Name[csb]=Programa
+Name[cy]=Cymhwysiad
+Name[da]=Program
+Name[de]=Programm
+Name[el]=ΕφαÏμογή
+Name[eo]=Aplikaĵo
+Name[es]=Aplicación
+Name[et]=Rakendus
+Name[eu]=Aplikazioa
+Name[fa]=کاربرد
+Name[fi]=Sovellus
+Name[fy]=Applikaasje
+Name[ga]=Feidhmchlár
+Name[gl]=Aplicación
+Name[he]=יישו×
+Name[hi]=अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—
+Name[hr]=Aplikacija
+Name[hu]=alkalmazás
+Name[id]=Aplikasi
+Name[is]=Forrit
+Name[it]=Applicazione
+Name[ja]=アプリケーション
+Name[ka]=პრáƒáƒ’რáƒáƒ›áƒ
+Name[kk]=Қолданба
+Name[km]=កម្មវិធី
+Name[ko]=ì‘ìš© 프로그램
+Name[lb]=Programm
+Name[lt]=Programa
+Name[lv]=AplikÄcija
+Name[mi]=Utauta
+Name[mk]=Ðпликација
+Name[mn]=Программ
+Name[ms]=Aplikasi
+Name[mt]=Programm
+Name[nb]=Program
+Name[nds]=Programm
+Name[ne]=अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—
+Name[nl]=Toepassing
+Name[nn]=Program
+Name[nso]=Tshomiso
+Name[oc]=Aplicacions
+Name[pa]=ਕਾਰਜ
+Name[pl]=Program
+Name[pt]=Aplicação
+Name[pt_BR]=Aplicativo
+Name[ro]=Aplicaţie
+Name[ru]=Приложение
+Name[rw]=Porogaramu
+Name[se]=Prográmma
+Name[sk]=Aplikácia
+Name[sl]=Program
+Name[sq]=Aplikacion
+Name[sr]=Програм
+Name[sr@Latn]=Program
+Name[ss]=Sicelo
+Name[sv]=Program
+Name[ta]=பயனà¯à®ªà®¾à®Ÿà¯
+Name[te]=కారà±à°¯à°•à±à°°à°®à°‚
+Name[tg]=Гузориш
+Name[th]=à¹à¸­à¸žà¸žà¸¥à¸´à¹€à¸„ชัน
+Name[tr]=Uygulama
+Name[tt]=Yazılım
+Name[uk]=Програма
+Name[uz]=Dastur
+Name[uz@cyrillic]=ДаÑтур
+Name[ven]=Apulifikhesheni
+Name[vi]=Ứng dụng
+Name[wa]=Programe
+Name[xh]=Isicelo
+Name[zh_CN]=应用程åº
+Name[zh_HK]=應用程å¼
+Name[zh_TW]=應用程å¼
+Name[zu]=Umyaleli
+
+[PropertyDef::NoDisplay]
+Type=bool
+
+[PropertyDef::DocPath]
+Type=TQString
+
+[PropertyDef::X-TDE-SubstituteUID]
+Type=bool
+
+[PropertyDef::X-TDE-Username]
+Type=TQString
+
+[PropertyDef::StartupWMClass]
+Type=TQString
+
+[PropertyDef::StartupNotify]
+Type=bool
+
+[PropertyDef::X-TDE-WMClass]
+Type=TQString
+
+[PropertyDef::X-TDE-StartupNotify]
+Type=bool
+
+[PropertyDef::X-DCOP-ServiceName]
+Type=TQString
+
+[PropertyDef::X-TDE-ParentApp]
+Type=TQString
+
+[PropertyDef::X-TDE-HasTempFileOption]
+Type=bool
+
+[PropertyDef::X-TDE-Protocols]
+Type=TQStringList
+
diff --git a/tdeio/bookmarks/CMakeLists.txt b/tdeio/bookmarks/CMakeLists.txt
new file mode 100644
index 000000000..93121cbac
--- /dev/null
+++ b/tdeio/bookmarks/CMakeLists.txt
@@ -0,0 +1,55 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdefx
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdefile
+)
+
+
+##### headers ###################################
+
+install( FILES
+ kbookmark.h kbookmarkbar.h kbookmarkdrag.h kbookmarkexporter.h
+ kbookmarkimporter.h kbookmarkmanager.h kbookmarkmenu.h
+ kbookmarknotifier.h kbookmarkimporter_crash.h
+ kbookmarkimporter_opera.h kbookmarkimporter_ie.h
+ kbookmarkimporter_ns.h kbookmarkimporter_kde1.h
+ kbookmarkdombuilder.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} )
+
+
+##### kbookmarks ################################
+
+set( target kbookmarks )
+
+set( ${target}_SRCS
+ kbookmark.cc kbookmarkbar.cc kbookmarkdrag.cc kbookmarkexporter.cc
+ kbookmarkimporter.cc kbookmarkmanager.cc kbookmarkmenu.cc
+ kbookmarkimporter_crash.cc kbookmarkimporter_opera.cc
+ kbookmarkimporter_ie.cc kbookmarkimporter_ns.cc
+ kbookmarkimporter_kde1.cc kbookmarkdombuilder.cc
+ kbookmarkmanager.skel kbookmarknotifier.skel
+)
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+ DEPENDENCIES dcopidl
+)
diff --git a/tdeio/bookmarks/Makefile.am b/tdeio/bookmarks/Makefile.am
new file mode 100644
index 000000000..e1ec3a8df
--- /dev/null
+++ b/tdeio/bookmarks/Makefile.am
@@ -0,0 +1,40 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Stephan Kulow (coolo@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 General Public License
+# along with this library; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+
+INCLUDES= -I$(srcdir)/../libltdl/ -I$(top_srcdir) -I$(top_srcdir)/tdefx -I$(top_builddir)/tdeio/tdeio $(all_includes)
+
+noinst_LTLIBRARIES = libkbookmarks.la
+
+METASOURCES = AUTO
+
+# convenience lib - no _LDFLAGS or _LIBADD !
+
+include_HEADERS = \
+ kbookmark.h kbookmarkbar.h kbookmarkdrag.h kbookmarkexporter.h \
+ kbookmarkimporter.h kbookmarkmanager.h kbookmarkmenu.h kbookmarknotifier.h \
+ kbookmarkimporter_crash.h kbookmarkimporter_opera.h kbookmarkimporter_ie.h \
+ kbookmarkimporter_ns.h kbookmarkimporter_kde1.h kbookmarkdombuilder.h
+libkbookmarks_la_SOURCES = \
+ kbookmark.cc kbookmarkbar.cc kbookmarkdrag.cc kbookmarkexporter.cc \
+ kbookmarkimporter.cc kbookmarkmanager.cc kbookmarkmenu.cc \
+ kbookmarkimporter_crash.cc kbookmarkimporter_opera.cc kbookmarkimporter_ie.cc \
+ kbookmarkimporter_ns.cc kbookmarkimporter_kde1.cc kbookmarkdombuilder.cc \
+ kbookmarkmanager.skel kbookmarknotifier.skel
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/bookmarks/dptrtemplate.h b/tdeio/bookmarks/dptrtemplate.h
new file mode 100644
index 000000000..dbc059e7e
--- /dev/null
+++ b/tdeio/bookmarks/dptrtemplate.h
@@ -0,0 +1,57 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 __dptrtemplate_h__
+#define __dptrtemplate_h__
+
+#include <tqptrdict.h>
+
+template<class Instance, class PrivateData>
+class dPtrTemplate {
+public:
+ static PrivateData* d( const Instance* instance )
+ {
+ if ( !d_ptr ) {
+ cleanup_d_ptr();
+ d_ptr = new TQPtrDict<PrivateData>;
+ tqAddPostRoutine( cleanup_d_ptr );
+ }
+ PrivateData* ret = d_ptr->find( (void*) instance );
+ if ( ! ret ) {
+ ret = new PrivateData;
+ d_ptr->replace( (void*) instance, ret );
+ }
+ return ret;
+ }
+ static void delete_d( const Instance* instance )
+ {
+ if ( d_ptr )
+ d_ptr->remove( (void*) instance );
+ }
+private:
+ static void cleanup_d_ptr()
+ {
+ delete d_ptr;
+ }
+ static TQPtrDict<PrivateData>* d_ptr;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmark.cc b/tdeio/bookmarks/kbookmark.cc
new file mode 100644
index 000000000..ab1cc398a
--- /dev/null
+++ b/tdeio/bookmarks/kbookmark.cc
@@ -0,0 +1,535 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 "kbookmark.h"
+#include <tqvaluestack.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kstringhandler.h>
+#include <kinputdialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <assert.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kbookmarkmanager.h>
+
+KBookmarkGroup::KBookmarkGroup()
+ : KBookmark( TQDomElement() )
+{
+}
+
+KBookmarkGroup::KBookmarkGroup( TQDomElement elem )
+ : KBookmark(elem)
+{
+}
+
+TQString KBookmarkGroup::groupAddress() const
+{
+ if (m_address.isEmpty())
+ m_address = address();
+ return m_address;
+}
+
+bool KBookmarkGroup::isOpen() const
+{
+ return element.attribute("folded") == "no"; // default is: folded
+}
+
+// Returns first element node equal to or after node n
+static TQDomElement firstElement(TQDomNode n)
+{
+ while(!n.isNull() && !n.isElement())
+ n = n.nextSibling();
+ return n.toElement();
+}
+
+// Returns first element node equal to or before node n
+static TQDomElement lastElement(TQDomNode n)
+{
+ while(!n.isNull() && !n.isElement())
+ n = n.previousSibling();
+ return n.toElement();
+}
+
+KBookmark KBookmarkGroup::first() const
+{
+ return KBookmark( nextKnownTag( firstElement(element.firstChild()), true ) );
+}
+
+KBookmark KBookmarkGroup::previous( const KBookmark & current ) const
+{
+ return KBookmark( nextKnownTag( lastElement(current.element.previousSibling()), false ) );
+}
+
+KBookmark KBookmarkGroup::next( const KBookmark & current ) const
+{
+ return KBookmark( nextKnownTag( firstElement(current.element.nextSibling()), true ) );
+}
+
+// KDE4: Change TQDomElement to TQDomNode so that we can get rid of
+// firstElement() and lastElement()
+TQDomElement KBookmarkGroup::nextKnownTag( TQDomElement start, bool goNext ) const
+{
+ static const TQString & bookmark = TDEGlobal::staticQString("bookmark");
+ static const TQString & folder = TDEGlobal::staticQString("folder");
+ static const TQString & separator = TDEGlobal::staticQString("separator");
+
+ for( TQDomNode n = start; !n.isNull(); )
+ {
+ TQDomElement elem = n.toElement();
+ TQString tag = elem.tagName();
+ if (tag == folder || tag == bookmark || tag == separator)
+ return elem;
+ if (goNext)
+ n = n.nextSibling();
+ else
+ n = n.previousSibling();
+ }
+ return TQDomElement();
+}
+
+KBookmarkGroup KBookmarkGroup::createNewFolder( KBookmarkManager* mgr, const TQString & text, bool emitSignal )
+{
+ TQString txt( text );
+ if ( text.isEmpty() )
+ {
+ bool ok;
+ TQString caption = parentGroup().fullText().isEmpty() ?
+ i18n( "Create New Bookmark Folder" ) :
+ i18n( "Create New Bookmark Folder in %1" )
+ .arg( parentGroup().text() );
+ txt = KInputDialog::getText( caption, i18n( "New folder:" ),
+ TQString::null, &ok );
+ if ( !ok )
+ return KBookmarkGroup();
+ }
+
+ Q_ASSERT(!element.isNull());
+ TQDomDocument doc = element.ownerDocument();
+ TQDomElement groupElem = doc.createElement( "folder" );
+ element.appendChild( groupElem );
+ TQDomElement textElem = doc.createElement( "title" );
+ groupElem.appendChild( textElem );
+ textElem.appendChild( doc.createTextNode( txt ) );
+
+ KBookmarkGroup grp(groupElem);
+
+ if (emitSignal)
+ emit mgr->notifier().createdNewFolder(
+ mgr->path(), grp.fullText(),
+ grp.address() );
+
+ return grp;
+
+}
+
+KBookmark KBookmarkGroup::createNewSeparator()
+{
+ Q_ASSERT(!element.isNull());
+ TQDomDocument doc = element.ownerDocument();
+ Q_ASSERT(!doc.isNull());
+ TQDomElement sepElem = doc.createElement( "separator" );
+ element.appendChild( sepElem );
+ return KBookmark(sepElem);
+}
+
+bool KBookmarkGroup::moveItem( const KBookmark & item, const KBookmark & after )
+{
+ TQDomNode n;
+ if ( !after.isNull() )
+ n = element.insertAfter( item.element, after.element );
+ else // first child
+ {
+ if ( element.firstChild().isNull() ) // Empty element -> set as real first child
+ n = element.insertBefore( item.element, TQDomElement() );
+
+ // we have to skip everything up to the first valid child
+ TQDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true);
+ if ( !firstChild.isNull() )
+ n = element.insertBefore( item.element, firstChild );
+ else
+ {
+ // No real first child -> append after the <title> etc.
+ n = element.appendChild( item.element );
+ }
+ }
+ return (!n.isNull());
+}
+
+KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal )
+{
+ element.appendChild( bm.internalElement() );
+
+ if (emitSignal) {
+ if ( bm.hasMetaData() ) {
+ mgr->notifyCompleteChange( "" );
+ } else {
+ emit mgr->notifier().addedBookmark(
+ mgr->path(), bm.url().url(),
+ bm.fullText(), bm.address(), bm.icon() );
+ }
+ }
+
+ return bm;
+}
+
+KBookmark KBookmarkGroup::addBookmark( KBookmarkManager* mgr, const TQString & text, const KURL & url, const TQString & icon, bool emitSignal )
+{
+ //kdDebug(7043) << "KBookmarkGroup::addBookmark " << text << " into " << m_address << endl;
+ TQDomDocument doc = element.ownerDocument();
+ TQDomElement elem = doc.createElement( "bookmark" );
+ elem.setAttribute( "href", url.url( 0, 106 ) ); // write utf8 URL (106 is mib enum for utf8)
+ TQString _icon = icon;
+ if ( _icon.isEmpty() )
+ _icon = KMimeType::iconForURL( url );
+ elem.setAttribute( "icon", _icon );
+
+ TQDomElement textElem = doc.createElement( "title" );
+ elem.appendChild( textElem );
+ textElem.appendChild( doc.createTextNode( text ) );
+
+ return addBookmark( mgr, KBookmark( elem ), emitSignal );
+}
+
+void KBookmarkGroup::deleteBookmark( KBookmark bk )
+{
+ element.removeChild( bk.element );
+}
+
+bool KBookmarkGroup::isToolbarGroup() const
+{
+ return ( element.attribute("toolbar") == "yes" );
+}
+
+TQDomElement KBookmarkGroup::findToolbar() const
+{
+ if ( element.attribute("toolbar") == "yes" )
+ return element;
+ for (TQDomNode n = element.firstChild(); !n.isNull() ; n = n.nextSibling() )
+ {
+ TQDomElement e = n.toElement();
+ // Search among the "folder" children only
+ if ( e.tagName() == "folder" )
+ {
+ if ( e.attribute("toolbar") == "yes" )
+ return e;
+ else
+ {
+ TQDomElement result = KBookmarkGroup(e).findToolbar();
+ if (!result.isNull())
+ return result;
+ }
+ }
+ }
+ return TQDomElement();
+}
+
+TQValueList<KURL> KBookmarkGroup::groupUrlList() const
+{
+ TQValueList<KURL> urlList;
+ for ( KBookmark bm = first(); !bm.isNull(); bm = next(bm) )
+ {
+ if ( bm.isSeparator() || bm.isGroup() )
+ continue;
+ urlList << bm.url();
+ }
+ return urlList;
+}
+
+//////
+
+bool KBookmark::isGroup() const
+{
+ TQString tag = element.tagName();
+ return ( tag == "folder"
+ || tag == "xbel" ); // don't forget the toplevel group
+}
+
+bool KBookmark::isSeparator() const
+{
+ return (element.tagName() == "separator");
+}
+
+bool KBookmark::hasParent() const
+{
+ TQDomElement parent = element.parentNode().toElement();
+ return !parent.isNull();
+}
+
+TQString KBookmark::text() const
+{
+ return KStringHandler::csqueeze( fullText() );
+}
+
+TQString KBookmark::fullText() const
+{
+ if (isSeparator())
+ return i18n("--- separator ---");
+
+ return element.namedItem("title").toElement().text();
+}
+
+KURL KBookmark::url() const
+{
+ return KURL(element.attribute("href"), 106); // Decode it from utf8 (106 is mib enum for utf8)
+}
+
+TQString KBookmark::icon() const
+{
+ TQString icon = element.attribute("icon");
+ if ( icon.isEmpty() )
+ // Default icon depends on URL for bookmarks, and is default directory
+ // icon for groups.
+ if ( isGroup() )
+ icon = "bookmark_folder";
+ else
+ if ( isSeparator() )
+ icon = "eraser"; // whatever
+ else
+ icon = KMimeType::iconForURL( url() );
+ return icon;
+}
+
+KBookmarkGroup KBookmark::parentGroup() const
+{
+ return KBookmarkGroup( element.parentNode().toElement() );
+}
+
+KBookmarkGroup KBookmark::toGroup() const
+{
+ Q_ASSERT( isGroup() );
+ return KBookmarkGroup(element);
+}
+
+TQString KBookmark::address() const
+{
+ if ( element.tagName() == "xbel" )
+ return ""; // not TQString::null !
+ else
+ {
+ // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :)
+ if (!hasParent())
+ {
+ Q_ASSERT(hasParent());
+ return "ERROR"; // Avoid an infinite loop
+ }
+ KBookmarkGroup group = parentGroup();
+ TQString parentAddress = group.address();
+ uint counter = 0;
+ // Implementation note: we don't use QDomNode's childNode list because we
+ // would have to skip "TEXT", which KBookmarkGroup already does for us.
+ for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk), ++counter )
+ {
+ if ( bk.element == element )
+ return parentAddress + "/" + TQString::number(counter);
+ }
+ kdWarning() << "KBookmark::address : this can't happen! " << parentAddress << endl;
+ return "ERROR";
+ }
+}
+
+KBookmark KBookmark::standaloneBookmark( const TQString & text, const KURL & url, const TQString & icon )
+{
+ TQDomDocument doc("xbel");
+ TQDomElement elem = doc.createElement("xbel");
+ doc.appendChild( elem );
+ KBookmarkGroup grp( elem );
+ grp.addBookmark( 0L, text, url, icon, false );
+ return grp.first();
+}
+
+// For some strange reason TQString("").left(0) returns TQString::null;
+// That breaks commonParent()
+TQString KBookmark::left(const TQString & str, uint len)
+{
+ //kdDebug()<<"********"<<TQString("").left(0).isNull()<<endl;
+ if(len == 0)
+ return TQString("");
+ else
+ return str.left(len);
+}
+
+TQString KBookmark::commonParent(TQString A, TQString B)
+{
+ TQString error("ERROR");
+ if(A == error || B == error)
+ return error;
+
+ A += "/";
+ B += "/";
+
+ uint lastCommonSlash = 0;
+ uint lastPos = A.length() < B.length() ? A.length() : B.length();
+ for(uint i=0; i < lastPos; ++i)
+ {
+ if(A[i] != B[i])
+ return left(A, lastCommonSlash);
+ if(A[i] == '/')
+ lastCommonSlash = i;
+ }
+ return left(A, lastCommonSlash);
+}
+
+static TQDomNode cd_or_create(TQDomNode node, TQString name)
+{
+ TQDomNode subnode = node.namedItem(name);
+ if (subnode.isNull())
+ {
+ subnode = node.ownerDocument().createElement(name);
+ node.appendChild(subnode);
+ }
+ return subnode;
+}
+
+static TQDomText get_or_create_text(TQDomNode node)
+{
+ TQDomNode subnode = node.firstChild();
+ if (subnode.isNull())
+ {
+ subnode = node.ownerDocument().createTextNode("");
+ node.appendChild(subnode);
+ }
+ return subnode.toText();
+}
+
+// Look for a metadata with owner="http://www.kde.org" or without any owner (for compatibility)
+static TQDomNode findOrCreateMetadata( TQDomNode& parent )
+{
+ static const char kdeOwner[] = "http://www.kde.org";
+ TQDomElement metadataElement;
+ for ( TQDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) {
+ TQDomElement elem = _node.toElement();
+ if ( !elem.isNull() && elem.tagName() == "metadata" ) {
+ const TQString owner = elem.attribute( "owner" );
+ if ( owner == kdeOwner )
+ return elem;
+ if ( owner.isEmpty() )
+ metadataElement = elem;
+ }
+ }
+ if ( metadataElement.isNull() ) {
+ metadataElement = parent.ownerDocument().createElement( "metadata" );
+ parent.appendChild(metadataElement);
+ }
+ metadataElement.setAttribute( "owner", kdeOwner );
+ return metadataElement;
+}
+
+bool KBookmark::hasMetaData() const
+{
+ // ### NOTE: this code creates <info> and <metadata>, despite its name and the const.
+ // It doesn't matter much in practice since it's only called for newly-created bookmarks,
+ // which will get metadata soon after anyway.
+ TQDomNode n = cd_or_create( internalElement(), "info" );
+ return findOrCreateMetadata( n ).hasChildNodes();
+}
+
+void KBookmark::updateAccessMetadata()
+{
+ kdDebug(7043) << "KBookmark::updateAccessMetadata " << address() << " " << url().prettyURL() << endl;
+
+ const uint timet = TQDateTime::currentDateTime().toTime_t();
+ setMetaDataItem( "time_added", TQString::number( timet ), DontOverwriteMetaData );
+ setMetaDataItem( "time_visited", TQString::number( timet ) );
+
+ TQString countStr = metaDataItem( "visit_count" ); // TODO use spec'ed name
+ bool ok;
+ int currentCount = countStr.toInt(&ok);
+ if (!ok)
+ currentCount = 0;
+ currentCount++;
+ setMetaDataItem( "visit_count", TQString::number( currentCount ) );
+
+ // TODO - for 4.0 - time_modified
+}
+
+TQString KBookmark::metaDataItem( const TQString &key ) const
+{
+ TQDomNode infoNode = cd_or_create( internalElement(), "info" );
+ infoNode = findOrCreateMetadata( infoNode );
+ for ( TQDomNode n = infoNode.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( !n.isElement() ) {
+ continue;
+ }
+ const TQDomElement e = n.toElement();
+ if ( e.tagName() == key ) {
+ return e.text();
+ }
+ }
+ return TQString::null;
+}
+
+void KBookmark::setMetaDataItem( const TQString &key, const TQString &value, MetaDataOverwriteMode mode )
+{
+ TQDomNode infoNode = cd_or_create( internalElement(), "info" );
+ infoNode = findOrCreateMetadata( infoNode );
+
+ TQDomNode item = cd_or_create( infoNode, key );
+ TQDomText text = get_or_create_text( item );
+ if ( mode == DontOverwriteMetaData && !text.data().isEmpty() ) {
+ return;
+ }
+
+ text.setData( value );
+}
+
+void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root)
+{
+ // non-recursive bookmark iterator
+ TQValueStack<KBookmarkGroup> stack;
+ stack.push(root);
+ KBookmark bk = stack.top().first();
+ for (;;) {
+ if (bk.isNull())
+ {
+ if (stack.isEmpty())
+ return;
+ if (stack.count() > 1)
+ visitLeave(stack.top());
+ bk = stack.pop();
+ bk = stack.top().next(bk);
+ if (bk.isNull())
+ continue;
+ }
+
+ if (bk.isGroup())
+ {
+ KBookmarkGroup gp = bk.toGroup();
+ visitEnter(gp);
+ if (!gp.first().isNull())
+ {
+ stack.push(gp);
+ bk = gp.first();
+ continue;
+ }
+ // empty group
+ visitLeave(gp);
+ }
+ else
+ visit(bk);
+
+ bk = stack.top().next(bk);
+ }
+
+ // never reached
+}
+
diff --git a/tdeio/bookmarks/kbookmark.h b/tdeio/bookmarks/kbookmark.h
new file mode 100644
index 000000000..4e5dc9149
--- /dev/null
+++ b/tdeio/bookmarks/kbookmark.h
@@ -0,0 +1,329 @@
+// -*- c-basic-offset: 4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kbookmark_h
+#define __kbookmark_h
+
+#include <tqstring.h>
+#include <tqvaluelist.h>
+#include <tqdom.h>
+#include <kurl.h>
+
+class KBookmarkManager;
+class KBookmarkGroup;
+
+class TDEIO_EXPORT KBookmark
+{
+ friend class KBookmarkGroup;
+public:
+ enum MetaDataOverwriteMode {
+ OverwriteMetaData, DontOverwriteMetaData
+ };
+
+ KBookmark( ) {}
+ KBookmark( TQDomElement elem ) : element(elem) {}
+
+ static KBookmark standaloneBookmark( const TQString & text, const KURL & url, const TQString & icon = TQString::null );
+
+ /**
+ * Whether the bookmark is a group or a normal bookmark
+ */
+ bool isGroup() const;
+
+ /**
+ * Whether the bookmark is a separator
+ */
+ bool isSeparator() const;
+
+ /**
+ * @return true if this is a null bookmark. This will never
+ * be the case for a real bookmark (in a menu), but it's used
+ * for instance as the end condition for KBookmarkGroup::next()
+ */
+ bool isNull() const {return element.isNull();}
+
+ /**
+ * @return true if bookmark is contained by a TQDomDocument,
+ * if not it is most likely that it has become separated and
+ * is thus invalid and/or has been deleted from the bookmarks.
+ * @since 3.2
+ */
+ bool hasParent() const;
+
+ /**
+ * Text shown for the bookmark
+ * If bigger than 40, the text is shortened by
+ * replacing middle characters with "..." (see KStringHandler::csqueeze)
+ */
+ TQString text() const;
+ /**
+ * Text shown for the bookmark, not truncated.
+ * You should not use this - this is mainly for keditbookmarks.
+ */
+ TQString fullText() const;
+ /**
+ * URL contained by the bookmark
+ */
+ KURL url() const;
+ /**
+ * @return the pixmap file for this bookmark
+ * (i.e. the name of the icon)
+ */
+ TQString icon() const;
+
+ /**
+ * @return the group containing this bookmark
+ */
+ KBookmarkGroup parentGroup() const;
+
+ /**
+ * Convert this to a group - do this only if
+ * isGroup() returns true.
+ */
+ KBookmarkGroup toGroup() const;
+
+ /**
+ * Return the "address" of this bookmark in the whole tree.
+ * This is used when telling other processes about a change
+ * in a given bookmark. The encoding of the address is "/4/2", for
+ * instance, to design the 2nd child inside the 4th child of the root bk.
+ */
+ TQString address() const;
+
+ // Hard to decide. Good design would imply that each bookmark
+ // knows about its manager, so that there can be several managers.
+ // But if we say there is only one manager (i.e. set of bookmarks)
+ // per application, then KBookmarkManager::self() is much easier.
+ //KBookmarkManager * manager() const { return m_manager; }
+
+ /**
+ * @internal for KEditBookmarks
+ */
+ TQDomElement internalElement() const { return element; }
+
+ /**
+ * Updates the bookmarks access metadata
+ * Call when a user accesses the bookmark
+ * @since 3.2
+ */
+ void updateAccessMetadata();
+
+ // Utility functions (internal)
+
+ /**
+ * @return address of parent
+ */
+ static TQString parentAddress( const TQString & address )
+ { return address.left( address.findRev('/') ); }
+
+ /**
+ * @return position in parent (e.g. /4/5/2 -> 2)
+ */
+ static uint positionInParent( const TQString & address )
+ { return address.mid( address.findRev('/') + 1 ).toInt(); }
+
+ /**
+ * @return address of previous sibling (e.g. /4/5/2 -> /4/5/1)
+ * Returns TQString::null for a first child
+ */
+ static TQString previousAddress( const TQString & address )
+ {
+ uint pp = positionInParent(address);
+ return pp>0 ? parentAddress(address) + '/' + TQString::number(pp-1) : TQString::null;
+ }
+
+ /**
+ * @return address of next sibling (e.g. /4/5/2 -> /4/5/3)
+ * This doesn't check whether it actually exists
+ */
+ static TQString nextAddress( const TQString & address )
+ { return parentAddress(address) + '/' + TQString::number(positionInParent(address)+1); }
+
+ /**
+ * @return the common parent of both addresses which
+ * has the greatest depth
+ * @since 3.5
+ */
+ static TQString commonParent(TQString A, TQString B);
+
+ /**
+ * Get the value of a specific metadata item.
+ * @param key Name of the metadata item
+ * @return Value of the metadata item. TQString::null is returned in case
+ * the specified key does not exist.
+ * @since 3.4
+ */
+ TQString metaDataItem( const TQString &key ) const;
+
+ /**
+ * Change the value of a specific metadata item, or create the given item
+ * if it doesn't exist already.
+ * @param key Name of the metadata item to change
+ * @param value Value to use for the specified metadata item
+ * @param mode Whether to overwrite the item's value if it exists already or not.
+ * @since 3.4
+ */
+ void setMetaDataItem( const TQString &key, const TQString &value, MetaDataOverwriteMode mode = OverwriteMetaData );
+
+protected:
+ TQDomElement element;
+ // Note: you can't add new member variables here.
+ // The KBookmarks are created on the fly, as wrappers
+ // around internal QDomElements. Any additional information
+ // has to be implemented as an attribute of the TQDomElement.
+
+private:
+ bool hasMetaData() const;
+ static TQString left(const TQString & str, uint len);
+};
+
+/**
+ * A group of bookmarks
+ */
+class TDEIO_EXPORT KBookmarkGroup : public KBookmark
+{
+public:
+ /**
+ * Create an invalid group. This is mostly for use in TQValueList,
+ * and other places where we need a null group.
+ * Also used as a parent for a bookmark that doesn't have one
+ * (e.g. Netscape bookmarks)
+ */
+ KBookmarkGroup();
+
+ /**
+ * Create a bookmark group as specified by the given element
+ */
+ KBookmarkGroup( TQDomElement elem );
+
+ /**
+ * Much like KBookmark::address, but caches the
+ * address into m_address.
+ */
+ TQString groupAddress() const;
+
+ /**
+ * @return true if the bookmark folder is opened in the bookmark editor
+ */
+ bool isOpen() const;
+
+ /**
+ * Return the first child bookmark of this group
+ */
+ KBookmark first() const;
+ /**
+ * Return the prevous sibling of a child bookmark of this group
+ * @param current has to be one of our child bookmarks.
+ */
+ KBookmark previous( const KBookmark & current ) const;
+ /**
+ * Return the next sibling of a child bookmark of this group
+ * @param current has to be one of our child bookmarks.
+ */
+ KBookmark next( const KBookmark & current ) const;
+
+ /**
+ * Create a new bookmark folder, as the last child of this group
+ * @param mgr the manager of the bookmark
+ * @param text for the folder. If empty, the user will be queried for it.
+ * @param emitSignal if true emit KBookmarkNotifier signal
+ */
+ KBookmarkGroup createNewFolder( KBookmarkManager* mgr, const TQString & text = TQString::null, bool emitSignal = true );
+ /**
+ * Create a new bookmark separator
+ * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark );
+ */
+ KBookmark createNewSeparator();
+
+ /**
+ * Create a new bookmark, as the last child of this group
+ * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark );
+ * @param mgr the manager of the bookmark
+ * @param bm the bookmark to add
+ * @param emitSignal if true emit KBookmarkNotifier signal
+ * @since 3.4
+ */
+ KBookmark addBookmark( KBookmarkManager* mgr, const KBookmark &bm, bool emitSignal = true );
+
+ /**
+ * Create a new bookmark, as the last child of this group
+ * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark );
+ * @param mgr the manager of the bookmark
+ * @param text for the bookmark
+ * @param url the URL that the bookmark points to
+ * @param icon the name of the icon to associate with the bookmark. A suitable default
+ * will be determined from the URL if not specified.
+ * @param emitSignal if true emit KBookmarkNotifier signal
+ */
+ KBookmark addBookmark( KBookmarkManager* mgr, const TQString & text, const KURL & url, const TQString & icon = TQString::null, bool emitSignal = true );
+
+ /**
+ * Moves @p item after @p after (which should be a child of ours).
+ * If item is null, @p item is moved as the first child.
+ * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark );
+ */
+ bool moveItem( const KBookmark & item, const KBookmark & after );
+
+ /**
+ * Delete a bookmark - it has to be one of our children !
+ * Don't forget to use KBookmarkManager::self()->emitChanged( parentBookmark );
+ */
+ void deleteBookmark( KBookmark bk );
+
+ /**
+ * @return true if this is the toolbar group
+ */
+ bool isToolbarGroup() const;
+ /**
+ * @internal
+ */
+ TQDomElement findToolbar() const;
+
+ /**
+ * @return the list of urls of bookmarks at top level of the group
+ * @since 3.2
+ */
+ TQValueList<KURL> groupUrlList() const;
+
+protected:
+ TQDomElement nextKnownTag( TQDomElement start, bool goNext ) const;
+
+private:
+ mutable TQString m_address;
+ // Note: you can't add other member variables here, except for caching info.
+ // The KBookmarks are created on the fly, as wrappers
+ // around internal QDomElements. Any additional information
+ // has to be implemented as an attribute of the TQDomElement.
+};
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KBookmarkGroupTraverser {
+protected:
+ virtual ~KBookmarkGroupTraverser() { ; }
+ void traverse(const KBookmarkGroup &);
+ virtual void visit(const KBookmark &) { ; }
+ virtual void visitEnter(const KBookmarkGroup &) { ; }
+ virtual void visitLeave(const KBookmarkGroup &) { ; }
+private:
+ class KBookmarkGroupTraverserPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkbar.cc b/tdeio/bookmarks/kbookmarkbar.cc
new file mode 100644
index 000000000..e73801808
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkbar.cc
@@ -0,0 +1,554 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 1999 Kurt Granroth <granroth@kde.org>
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 <tqregexp.h>
+#include <tqfile.h>
+
+#include <kbookmarkbar.h>
+#include <kbookmarkdrag.h>
+
+#include <kbookmarkmenu.h>
+#include <kdebug.h>
+
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+
+#include <tdeconfig.h>
+#include <kpopupmenu.h>
+
+#include "kbookmarkdrag.h"
+#include "kbookmarkmenu_p.h"
+#include "kbookmarkdombuilder.h"
+
+#include "dptrtemplate.h"
+
+#include <tqapplication.h>
+
+class KBookmarkBarPrivate : public dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>
+{
+public:
+ TQPtrList<KAction> m_actions;
+ bool m_readOnly;
+ KBookmarkManager* m_filteredMgr;
+ KToolBar* m_sepToolBar;
+ int m_sepIndex;
+ bool m_atFirst;
+ TQString m_dropAddress;
+ TQString m_highlightedAddress;
+public:
+ KBookmarkBarPrivate() {
+ m_readOnly = false;
+ m_filteredMgr = 0;
+ m_sepToolBar = 0;
+ m_sepIndex = -1;
+ m_atFirst = false;
+ }
+};
+template<> TQPtrDict<KBookmarkBarPrivate>* dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>::d_ptr = 0;
+
+KBookmarkBarPrivate* KBookmarkBar::dptr() const
+{
+ return KBookmarkBarPrivate::d( this );
+}
+
+// usage of KXBELBookmarkImporterImpl is just plain evil, but it reduces code dup. so...
+class ToolbarFilter : public KXBELBookmarkImporterImpl
+{
+public:
+ ToolbarFilter() : m_visible(false) { ; }
+ void filter( const KBookmarkGroup &grp ) { traverse(grp); }
+private:
+ virtual void visit( const KBookmark & );
+ virtual void visitEnter( const KBookmarkGroup & );
+ virtual void visitLeave( const KBookmarkGroup & );
+private:
+ bool m_visible;
+ KBookmarkGroup m_visibleStart;
+};
+
+KBookmarkBar::KBookmarkBar( KBookmarkManager* mgr,
+ KBookmarkOwner *_owner, KToolBar *_toolBar,
+ KActionCollection *coll,
+ TQObject *parent, const char *name )
+ : TQObject( parent, name ), m_pOwner(_owner), m_toolBar(_toolBar),
+ m_actionCollection( coll ), m_pManager(mgr)
+{
+ m_lstSubMenus.setAutoDelete( true );
+
+ m_toolBar->setAcceptDrops( true );
+ m_toolBar->installEventFilter( this ); // for drops
+
+ dptr()->m_actions.setAutoDelete( true );
+
+ connect( mgr, TQT_SIGNAL( changed(const TQString &, const TQString &) ),
+ TQT_SLOT( slotBookmarksChanged(const TQString &) ) );
+
+ KBookmarkGroup toolbar = getToolbar();
+ fillBookmarkBar( toolbar );
+}
+
+TQString KBookmarkBar::parentAddress()
+{
+ return dptr()->m_filteredMgr ? TQString::null : m_pManager->toolbar().address();
+}
+
+#define CURRENT_TOOLBAR() ( \
+ dptr()->m_filteredMgr ? dptr()->m_filteredMgr->root() \
+ : m_pManager->toolbar() )
+
+#define CURRENT_MANAGER() ( \
+ dptr()->m_filteredMgr ? dptr()->m_filteredMgr \
+ : m_pManager )
+
+KBookmarkGroup KBookmarkBar::getToolbar()
+{
+ if ( KBookmarkSettings::self()->m_filteredtoolbar )
+ {
+ if ( !dptr()->m_filteredMgr ) {
+ dptr()->m_filteredMgr = KBookmarkManager::createTempManager();
+ } else {
+ KBookmarkGroup bkRoot = dptr()->m_filteredMgr->root();
+ TQValueList<KBookmark> bks;
+ for (KBookmark bm = bkRoot.first(); !bm.isNull(); bm = bkRoot.next(bm))
+ bks << bm;
+ for ( TQValueListConstIterator<KBookmark> it = bks.begin(); it != bks.end(); ++it )
+ bkRoot.deleteBookmark( (*it) );
+ }
+ ToolbarFilter filter;
+ KBookmarkDomBuilder builder( dptr()->m_filteredMgr->root(),
+ dptr()->m_filteredMgr );
+ builder.connectImporter( &filter );
+ filter.filter( m_pManager->root() );
+ }
+
+ return CURRENT_TOOLBAR();
+}
+
+KBookmarkBar::~KBookmarkBar()
+{
+ //clear();
+ KBookmarkBarPrivate::delete_d(this);
+}
+
+void KBookmarkBar::clear()
+{
+ TQPtrListIterator<KAction> it( dptr()->m_actions );
+ m_toolBar->clear();
+ for (; it.current(); ++it ) {
+ (*it)->unplugAll();
+ }
+ dptr()->m_actions.clear();
+ m_lstSubMenus.clear();
+}
+
+void KBookmarkBar::slotBookmarksChanged( const TQString & group )
+{
+ KBookmarkGroup tb = getToolbar(); // heavy for non cached toolbar version
+ kdDebug(7043) << "slotBookmarksChanged( " << group << " )" << endl;
+
+ if ( tb.isNull() )
+ return;
+
+ if ( KBookmark::commonParent(group, tb.address()) == group // Is group a parent of tb.address?
+ || KBookmarkSettings::self()->m_filteredtoolbar )
+ {
+ clear();
+ fillBookmarkBar( tb );
+ }
+ else
+ {
+ // Iterate recursively into child menus
+ TQPtrListIterator<KBookmarkMenu> it( m_lstSubMenus );
+ for (; it.current(); ++it )
+ {
+ it.current()->slotBookmarksChanged( group );
+ }
+ }
+}
+
+void KBookmarkBar::fillBookmarkBar(KBookmarkGroup & parent)
+{
+ if (parent.isNull())
+ return;
+
+ for (KBookmark bm = parent.first(); !bm.isNull(); bm = parent.next(bm))
+ {
+ TQString text = bm.text();
+ text.replace( '&', "&&" );
+ if (!bm.isGroup())
+ {
+ if ( bm.isSeparator() )
+ m_toolBar->insertLineSeparator();
+ else
+ {
+ KAction *action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 );
+ connect(action, TQT_SIGNAL( activated ( KAction::ActivationReason, TQt::ButtonState )),
+ this, TQT_SLOT( slotBookmarkSelected( KAction::ActivationReason, TQt::ButtonState ) ));
+
+ action->setProperty( "url", bm.url().url() );
+ action->setProperty( "address", bm.address() );
+
+ action->setToolTip( bm.url().pathOrURL() );
+
+ action->plug(m_toolBar);
+
+ dptr()->m_actions.append( action );
+ }
+ }
+ else
+ {
+ KActionMenu *action = new KBookmarkActionMenu( text, bm.icon(),
+ m_actionCollection,
+ "bookmarkbar-actionmenu");
+ action->setProperty( "address", bm.address() );
+ action->setProperty( "readOnly", dptr()->m_readOnly );
+ action->setDelayed( false );
+
+ // this flag doesn't have any UI yet
+ TDEGlobal::config()->setGroup( "Settings" );
+ bool addEntriesBookmarkBar = TDEGlobal::config()->readBoolEntry("AddEntriesBookmarkBar",true);
+
+ KBookmarkMenu *menu = new KBookmarkMenu(CURRENT_MANAGER(), m_pOwner, action->popupMenu(),
+ m_actionCollection, false, addEntriesBookmarkBar,
+ bm.address());
+ connect(menu, TQT_SIGNAL( aboutToShowContextMenu(const KBookmark &, TQPopupMenu * ) ),
+ this, TQT_SIGNAL( aboutToShowContextMenu(const KBookmark &, TQPopupMenu * ) ));
+ connect(menu, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState) ),
+ this, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState) ));
+ menu->fillBookmarkMenu();
+ action->plug(m_toolBar);
+ m_lstSubMenus.append( menu );
+
+ dptr()->m_actions.append( action );
+ }
+ }
+}
+
+void KBookmarkBar::setReadOnly(bool readOnly)
+{
+ dptr()->m_readOnly = readOnly;
+}
+
+bool KBookmarkBar::isReadOnly() const
+{
+ return dptr()->m_readOnly;
+}
+
+void KBookmarkBar::slotBookmarkSelected( KAction::ActivationReason /*reason*/, TQt::ButtonState state )
+{
+ if (!m_pOwner) return; // this view doesn't handle bookmarks...
+
+ const KAction* action = dynamic_cast<const KAction *>(sender());
+ if(action)
+ {
+ const TQString & url = sender()->property("url").toString();
+ m_pOwner->openBookmarkURL(url);
+ emit openBookmark( url, state );
+ }
+}
+
+void KBookmarkBar::slotBookmarkSelected()
+{
+ slotBookmarkSelected(KAction::ToolBarActivation, Qt::NoButton);
+}
+
+static const int const_sepId = -9999; // FIXME this is ugly,
+ // surely there is another
+ // way of doing this...
+
+static void removeTempSep(KBookmarkBarPrivate* p)
+{
+ if (p->m_sepToolBar) {
+ p->m_sepToolBar->removeItem(const_sepId);
+ p->m_sepToolBar = 0; // needed?
+ }
+}
+
+static KAction* findPluggedAction(TQPtrList<KAction> actions, KToolBar *tb, int id)
+{
+ TQPtrListIterator<KAction> it( actions );
+ for (; (*it); ++it )
+ if ((*it)->isPlugged(tb, id))
+ return (*it);
+ return 0;
+}
+
+/**
+ * Handle a TQDragMoveEvent event on a toolbar drop
+ * @return the address of the bookmark to be dropped after/before
+ * else a TQString::null if event should be ignored
+ * @param pos the current TQDragMoveEvent position
+ * @param the toolbar
+ * @param actions the list of actions plugged into the bar
+ * @param atFirst bool reference, when true the position before the
+ * returned action was dropped on
+ */
+static TQString handleToolbarDragMoveEvent(
+ KBookmarkBarPrivate *p, KToolBar *tb, TQPoint pos, TQPtrList<KAction> actions,
+ bool &atFirst, KBookmarkManager *mgr
+) {
+ Q_UNUSED( mgr );
+ Q_ASSERT( actions.isEmpty() || (tb == dynamic_cast<KToolBar*>(actions.first()->container(0))) );
+ p->m_sepToolBar = tb;
+ p->m_sepToolBar->removeItemDelayed(const_sepId);
+
+ int index = 0;
+ KToolBarButton* b;
+
+ b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
+ KAction *a = 0;
+ TQString address;
+ atFirst = false;
+
+ if (b)
+ {
+ index = tb->itemIndex(b->id());
+ TQRect r = b->geometry();
+ if (pos.x() < ((r.left() + r.right())/2))
+ {
+ // if in first half of button then
+ // we jump to previous index
+ if ( index == 0 )
+ atFirst = true;
+ else {
+ index--;
+ b = tb->getButton(tb->idAt(index));
+ }
+ }
+ }
+ else if (actions.isEmpty())
+ {
+ atFirst = true;
+ index = 0;
+ // we skip the action related stuff
+ // and do what it should have...
+ // FIXME - here we want to get the
+ // parent address of the bookmark
+ // bar itself and return that + "/0"
+ p->m_sepIndex = 0;
+ goto skipact;
+ }
+ else // (!b)
+ {
+ index = actions.count() - 1;
+ b = tb->getButton(tb->idAt(index));
+ // if !b and not past last button, we didn't find button
+ if (pos.x() <= b->geometry().left())
+ goto skipact; // TODO - rename
+ }
+
+ if ( !b )
+ return TQString::null; // TODO Make it works for that case
+
+ a = findPluggedAction(actions, tb, b->id());
+ Q_ASSERT(a);
+ address = a->property("address").toString();
+ p->m_sepIndex = index + (atFirst ? 0 : 1);
+
+#if 0
+ { // ugly workaround to fix the goto scoping problems...
+ KBookmark bk = mgr->findByAddress( address );
+ if (bk.isGroup()) // TODO - fix this ****!!!, manhatten distance should be used!!!
+ {
+ kdDebug() << "kbookmarkbar:: popping up " << bk.text() << endl;
+ KBookmarkActionMenu *menu = dynamic_cast<KBookmarkActionMenu*>(a);
+ Q_ASSERT(menu);
+ menu->popup(tb->mapToGlobal(b->geometry().center()));
+ }
+ }
+#endif
+
+skipact:
+ tb->insertLineSeparator(p->m_sepIndex, const_sepId);
+ return address;
+}
+
+// TODO - document!!!!
+static KAction* handleToolbarMouseButton(TQPoint pos, TQPtrList<KAction> actions,
+ KBookmarkManager * /*mgr*/, TQPoint & pt)
+{
+ KAction *act = actions.first();
+ if (!act) {
+ return 0;
+ }
+
+ KToolBar *tb = dynamic_cast<KToolBar*>(act->container(0));
+ Q_ASSERT(tb);
+
+ KToolBarButton *b;
+ b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
+ if (!b)
+ return 0;
+
+ KAction *a = 0;
+ a = findPluggedAction(actions, tb, b->id());
+ Q_ASSERT(a);
+ pt = tb->mapToGlobal(pos);
+
+ return a;
+}
+
+// TODO *** drop improvements ***
+// open submenus on drop interactions
+
+// TODO *** generic rmb improvements ***
+// don't *ever* show the rmb on press, always relase, possible???
+
+class KBookmarkBarRMBAssoc : public dPtrTemplate<KBookmarkBar, RMB> { };
+template<> TQPtrDict<RMB>* dPtrTemplate<KBookmarkBar, RMB>::d_ptr = 0;
+
+static RMB* rmbSelf(KBookmarkBar *m) { return KBookmarkBarRMBAssoc::d(m); }
+
+void RMB::begin_rmb_action(KBookmarkBar *self)
+{
+ RMB *s = rmbSelf(self);
+ s->recv = self;
+ s->m_parentAddress = self->parentAddress();
+ s->s_highlightedAddress = self->dptr()->m_highlightedAddress; // rename in RMB
+ s->m_pManager = self->m_pManager;
+ s->m_pOwner = self->m_pOwner;
+ s->m_parentMenu = 0;
+}
+
+void KBookmarkBar::slotRMBActionEditAt( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); }
+
+void KBookmarkBar::slotRMBActionProperties( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); }
+
+void KBookmarkBar::slotRMBActionInsert( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); }
+
+void KBookmarkBar::slotRMBActionRemove( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); }
+
+void KBookmarkBar::slotRMBActionCopyLocation( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); }
+
+bool KBookmarkBar::eventFilter( TQObject *o, TQEvent *e )
+{
+ if (dptr()->m_readOnly || dptr()->m_filteredMgr) // note, we assume m_pManager in various places,
+ // this shouldn't really be the case
+ return false; // todo: make this limit the actions
+
+ if ( (e->type() == TQEvent::MouseButtonRelease) || (e->type() == TQEvent::MouseButtonPress) ) // FIXME, which one?
+ {
+ TQMouseEvent *mev = (TQMouseEvent*)e;
+
+ TQPoint pt;
+ KAction *_a;
+
+ // FIXME, see how this holds up on an empty toolbar
+ _a = handleToolbarMouseButton( mev->pos(), dptr()->m_actions, m_pManager, pt );
+ if (_a && mev->button() == Qt::RightButton)
+ {
+ dptr()->m_highlightedAddress = _a->property("address").toString();
+ KBookmark bookmark = m_pManager->findByAddress( dptr()->m_highlightedAddress );
+ RMB::begin_rmb_action(this);
+ KPopupMenu *pm = new KPopupMenu;
+ rmbSelf(this)->fillContextMenu( pm, dptr()->m_highlightedAddress, 0 );
+ emit aboutToShowContextMenu( rmbSelf(this)->atAddress( dptr()->m_highlightedAddress ), pm );
+ rmbSelf(this)->fillContextMenu2( pm, dptr()->m_highlightedAddress, 0 );
+ pm->popup( pt );
+ mev->accept();
+ }
+
+ return !!_a; // ignore the event if we didn't find the button
+ }
+ else if ( e->type() == TQEvent::DragLeave )
+ {
+ removeTempSep(dptr());
+ dptr()->m_dropAddress = TQString::null;
+ }
+ else if ( e->type() == TQEvent::Drop )
+ {
+ removeTempSep(dptr());
+ TQDropEvent *dev = (TQDropEvent*)e;
+ if ( !KBookmarkDrag::canDecode( dev ) )
+ return false;
+ TQValueList<KBookmark> list = KBookmarkDrag::decode( dev );
+ if (list.count() > 1)
+ kdWarning(7043) << "Sorry, currently you can only drop one address "
+ "onto the bookmark bar!" << endl;
+ KBookmark toInsert = list.first();
+ KBookmark bookmark = m_pManager->findByAddress( dptr()->m_dropAddress );
+ Q_ASSERT(!bookmark.isNull());
+ kdDebug(7043) << "inserting "
+ << TQString(dptr()->m_atFirst ? "before" : "after")
+ << " dptr()->m_dropAddress == " << dptr()->m_dropAddress << endl;
+ KBookmarkGroup parentBookmark = bookmark.parentGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ KBookmark newBookmark = parentBookmark.addBookmark(
+ m_pManager, toInsert.fullText(),
+ toInsert.url() );
+ parentBookmark.moveItem( newBookmark, dptr()->m_atFirst ? KBookmark() : bookmark );
+ m_pManager->emitChanged( parentBookmark );
+ return true;
+ }
+ else if ( e->type() == TQEvent::DragMove )
+ {
+ TQDragMoveEvent *dme = (TQDragMoveEvent*)e;
+ if (!KBookmarkDrag::canDecode( dme ))
+ return false;
+ bool _atFirst;
+ TQString dropAddress;
+ KToolBar *tb = (KToolBar*)o;
+ dropAddress = handleToolbarDragMoveEvent(dptr(), tb, dme->pos(), dptr()->m_actions, _atFirst, m_pManager);
+ if (!dropAddress.isNull())
+ {
+ dptr()->m_dropAddress = dropAddress;
+ dptr()->m_atFirst = _atFirst;
+ dme->accept();
+ }
+ }
+ return false;
+}
+
+static bool showInToolbar( const KBookmark &bk ) {
+ return (bk.internalElement().attributes().namedItem("showintoolbar").toAttr().value() == "yes");
+}
+
+void ToolbarFilter::visit( const KBookmark &bk ) {
+ //kdDebug() << "visit(" << bk.text() << ")" << endl;
+ if ( m_visible || showInToolbar(bk) )
+ KXBELBookmarkImporterImpl::visit(bk);
+}
+
+void ToolbarFilter::visitEnter( const KBookmarkGroup &grp ) {
+ //kdDebug() << "visitEnter(" << grp.text() << ")" << endl;
+ if ( !m_visible && showInToolbar(grp) )
+ {
+ m_visibleStart = grp;
+ m_visible = true;
+ }
+ if ( m_visible )
+ KXBELBookmarkImporterImpl::visitEnter(grp);
+}
+
+void ToolbarFilter::visitLeave( const KBookmarkGroup &grp ) {
+ //kdDebug() << "visitLeave()" << endl;
+ if ( m_visible )
+ KXBELBookmarkImporterImpl::visitLeave(grp);
+ if ( m_visible && grp.address() == m_visibleStart.address() )
+ m_visible = false;
+}
+
+#include "kbookmarkbar.moc"
diff --git a/tdeio/bookmarks/kbookmarkbar.h b/tdeio/bookmarks/kbookmarkbar.h
new file mode 100644
index 000000000..1f100d183
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkbar.h
@@ -0,0 +1,131 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 1999 Kurt Granroth <granroth@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 KBOOKMARKBAR_H
+#define KBOOKMARKBAR_H
+
+#include <tqobject.h>
+#include <tqguardedptr.h>
+#include <tqptrlist.h>
+#include <kbookmark.h>
+#include <kaction.h>
+
+class KToolBar;
+class KBookmarkMenu;
+class KBookmarkOwner;
+class KActionCollection;
+class KAction;
+class TQPopupMenu;
+
+/**
+ * This class provides a bookmark toolbar. Using this class is nearly
+ * identical to using KBookmarkMenu so follow the directions
+ * there.
+ */
+class TDEIO_EXPORT KBookmarkBar : public TQObject
+{
+ Q_OBJECT
+
+ friend class RMB;
+public:
+ /**
+ * Fills a bookmark toolbar
+ *
+ * @param manager the bookmark manager
+ * @param owner implementation of the KBookmarkOwner interface (callbacks)
+ * @param toolBar toolbar to fill
+ *
+ * The KActionCollection pointer argument is now obsolete.
+ *
+ * @param parent the parent widget for the bookmark toolbar
+ * @param name the internal name for the bookmark toolbar
+ */
+ KBookmarkBar( KBookmarkManager* manager,
+ KBookmarkOwner *owner, KToolBar *toolBar,
+ KActionCollection *,
+ TQObject *parent = 0L, const char *name = 0L);
+
+ virtual ~KBookmarkBar();
+
+ /**
+ * @since 3.2
+ */
+ bool isReadOnly() const;
+
+ /**
+ * @since 3.2
+ */
+ void setReadOnly(bool);
+
+ /**
+ * @since 3.2
+ */
+ TQString parentAddress();
+
+signals:
+ /**
+ * @since 3.2
+ */
+ void aboutToShowContextMenu( const KBookmark &, TQPopupMenu * );
+ /**
+ * @since 3.4
+ */
+ void openBookmark( const TQString& url, TQt::ButtonState state );
+
+public slots:
+ void clear();
+
+ void slotBookmarksChanged( const TQString & );
+ void slotBookmarkSelected();
+
+ /**
+ * @since 3.4
+ */
+ void slotBookmarkSelected( KAction::ActivationReason reason, TQt::ButtonState state );
+
+ /// @since 3.2
+ void slotRMBActionRemove( int );
+ /// @since 3.2
+ void slotRMBActionInsert( int );
+ /// @since 3.2
+ void slotRMBActionCopyLocation( int );
+ /// @since 3.2
+ void slotRMBActionEditAt( int );
+ /// @since 3.2
+ void slotRMBActionProperties( int );
+
+protected:
+ void fillBookmarkBar( KBookmarkGroup & parent );
+ virtual bool eventFilter( TQObject *o, TQEvent *e );
+
+private:
+ KBookmarkGroup getToolbar();
+
+ KBookmarkOwner *m_pOwner;
+ TQGuardedPtr<KToolBar> m_toolBar;
+ KActionCollection *m_actionCollection;
+ KBookmarkManager *m_pManager;
+ TQPtrList<KBookmarkMenu> m_lstSubMenus;
+
+private:
+ class KBookmarkBarPrivate* dptr() const;
+};
+
+#endif // KBOOKMARKBAR_H
diff --git a/tdeio/bookmarks/kbookmarkdombuilder.cc b/tdeio/bookmarks/kbookmarkdombuilder.cc
new file mode 100644
index 000000000..5c0882d05
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkdombuilder.cc
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2002-2003 Alexander Kellett <lypanov@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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kbookmarkmanager.h>
+#include <kdebug.h>
+
+#include "kbookmarkdombuilder.h"
+
+KBookmarkDomBuilder::KBookmarkDomBuilder(
+ const KBookmarkGroup &bkGroup, KBookmarkManager *manager
+) {
+ m_manager = manager;
+ m_stack.push(bkGroup);
+}
+
+KBookmarkDomBuilder::~KBookmarkDomBuilder() {
+ m_list.clear();
+ m_stack.clear();
+}
+
+void KBookmarkDomBuilder::connectImporter(const TQObject *importer) {
+ connect(importer, TQT_SIGNAL( newBookmark(const TQString &, const TQCString &, const TQString &) ),
+ TQT_SLOT( newBookmark(const TQString &, const TQCString &, const TQString &) ));
+ connect(importer, TQT_SIGNAL( newFolder(const TQString &, bool, const TQString &) ),
+ TQT_SLOT( newFolder(const TQString &, bool, const TQString &) ));
+ connect(importer, TQT_SIGNAL( newSeparator() ),
+ TQT_SLOT( newSeparator() ) );
+ connect(importer, TQT_SIGNAL( endFolder() ),
+ TQT_SLOT( endFolder() ) );
+}
+
+void KBookmarkDomBuilder::newBookmark(
+ const TQString &text, const TQCString &url, const TQString &additionalInfo
+) {
+ KBookmark bk = m_stack.top().addBookmark(
+ m_manager, text,
+ KURL( TQString::fromUtf8(url), 106 /*utf8*/ ),
+ TQString::null, false);
+ // store additional info
+ bk.internalElement().setAttribute("netscapeinfo", additionalInfo);
+}
+
+void KBookmarkDomBuilder::newFolder(
+ const TQString & text, bool open, const TQString & additionalInfo
+) {
+ // we use a qvaluelist so that we keep pointers to valid objects in the stack
+ KBookmarkGroup gp = m_stack.top().createNewFolder(m_manager, text, false);
+ m_list.append(gp);
+ m_stack.push(m_list.last());
+ // store additional info
+ TQDomElement element = m_list.last().internalElement();
+ element.setAttribute("netscapeinfo", additionalInfo);
+ element.setAttribute("folded", (open?"no":"yes"));
+}
+
+void KBookmarkDomBuilder::newSeparator() {
+ m_stack.top().createNewSeparator();
+}
+
+void KBookmarkDomBuilder::endFolder() {
+ m_stack.pop();
+}
+
+#include "kbookmarkdombuilder.moc"
diff --git a/tdeio/bookmarks/kbookmarkdombuilder.h b/tdeio/bookmarks/kbookmarkdombuilder.h
new file mode 100644
index 000000000..44fe7b170
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkdombuilder.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kbookmarkdombuilder_h
+#define __kbookmarkdombuilder_h
+
+#include <tqvaluestack.h>
+#include <tqobject.h>
+#include <kbookmark.h>
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KBookmarkDomBuilder : public TQObject {
+ Q_OBJECT
+public:
+ KBookmarkDomBuilder(const KBookmarkGroup &group, KBookmarkManager *);
+ virtual ~KBookmarkDomBuilder();
+ void connectImporter(const TQObject *);
+protected slots:
+ void newBookmark(const TQString &text, const TQCString &url, const TQString &additionalInfo);
+ void newFolder(const TQString &text, bool open, const TQString &additionalInfo);
+ void newSeparator();
+ void endFolder();
+private:
+ TQValueStack<KBookmarkGroup> m_stack;
+ TQValueList<KBookmarkGroup> m_list;
+ KBookmarkManager *m_manager;
+ class KBookmarkDomBuilderPrivate *p;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkdrag.cc b/tdeio/bookmarks/kbookmarkdrag.cc
new file mode 100644
index 000000000..d13893eed
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkdrag.cc
@@ -0,0 +1,169 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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.
+*/
+
+#include "kbookmarkdrag.h"
+#include <kurldrag.h>
+#include <kdebug.h>
+
+KBookmarkDrag * KBookmarkDrag::newDrag( const TQValueList<KBookmark> & bookmarks, TQWidget * dragSource, const char * name )
+{
+ KURL::List urls;
+
+ for ( TQValueListConstIterator<KBookmark> it = bookmarks.begin(); it != bookmarks.end(); ++it ) {
+ urls.append( (*it).url() );
+ }
+
+ // See KURLDrag::newDrag
+ TQStrList uris;
+ KURL::List::ConstIterator uit = urls.begin();
+ KURL::List::ConstIterator uEnd = urls.end();
+ // Get each URL encoded in utf8 - and since we get it in escaped
+ // form on top of that, .latin1() is fine.
+ for ( ; uit != uEnd ; ++uit )
+ uris.append( KURLDrag::urlToString(*uit).latin1() );
+
+ return new KBookmarkDrag( bookmarks, uris, dragSource, name );
+}
+
+KBookmarkDrag * KBookmarkDrag::newDrag( const KBookmark & bookmark, TQWidget * dragSource, const char * name )
+{
+ TQValueList<KBookmark> bookmarks;
+ bookmarks.append( KBookmark(bookmark) );
+ return newDrag(bookmarks, dragSource, name);
+}
+
+KBookmarkDrag::KBookmarkDrag( const TQValueList<KBookmark> & bookmarks, const TQStrList & urls,
+ TQWidget * dragSource, const char * name )
+ : TQUriDrag( urls, dragSource, name ), m_bookmarks( bookmarks ), m_doc("xbel")
+{
+ // We need to create the XML for this drag right now and not
+ // in encodedData because when cutting a folder, the children
+ // wouldn't be part of the bookmarks anymore, when encodedData
+ // is requested.
+ TQDomElement elem = m_doc.createElement("xbel");
+ m_doc.appendChild( elem );
+ for ( TQValueListConstIterator<KBookmark> it = bookmarks.begin(); it != bookmarks.end(); ++it ) {
+ elem.appendChild( (*it).internalElement().cloneNode( true /* deep */ ) );
+ }
+ //kdDebug(7043) << "KBookmarkDrag::KBookmarkDrag " << m_doc.toString() << endl;
+}
+
+const char* KBookmarkDrag::format( int i ) const
+{
+ if ( i == 0 )
+ return "application/x-xbel";
+ else if ( i == 1 )
+ return "text/uri-list";
+ else if ( i == 2 )
+ return "text/plain";
+ else return 0;
+}
+
+TQByteArray KBookmarkDrag::encodedData( const char* mime ) const
+{
+ TQByteArray a;
+ TQCString mimetype( mime );
+ if ( mimetype == "text/uri-list" )
+ return TQUriDrag::encodedData( mime );
+ else if ( mimetype == "application/x-xbel" )
+ {
+ a = m_doc.toCString();
+ //kdDebug(7043) << "KBookmarkDrag::encodedData " << m_doc.toCString() << endl;
+ }
+ else if ( mimetype == "text/plain" )
+ {
+ KURL::List m_lstDragURLs;
+ if ( KURLDrag::decode( this, m_lstDragURLs ) )
+ {
+ TQStringList uris;
+ KURL::List::ConstIterator uit = m_lstDragURLs.begin();
+ KURL::List::ConstIterator uEnd = m_lstDragURLs.end();
+ for ( ; uit != uEnd ; ++uit )
+ uris.append( (*uit).prettyURL() );
+
+ TQCString s = uris.join( "\n" ).local8Bit();
+ a.resize( s.length() + 1 ); // trailing zero
+ memcpy( a.data(), s.data(), s.length() + 1 );
+ }
+ }
+ return a;
+}
+
+bool KBookmarkDrag::canDecode( const TQMimeSource * e )
+{
+ return e->provides("text/uri-list") || e->provides("application/x-xbel") ||
+ e->provides("text/plain");
+}
+
+TQValueList<KBookmark> KBookmarkDrag::decode( const TQMimeSource * e )
+{
+ TQValueList<KBookmark> bookmarks;
+ if ( e->provides("application/x-xbel") )
+ {
+ TQByteArray s( e->encodedData("application/x-xbel") );
+ //kdDebug(7043) << "KBookmarkDrag::decode s=" << TQCString(s) << endl;
+ TQDomDocument doc;
+ doc.setContent( s );
+ TQDomElement elem = doc.documentElement();
+ TQDomNodeList children = elem.childNodes();
+ for ( uint childno = 0; childno < children.count(); childno++)
+ {
+ bookmarks.append( KBookmark( children.item(childno).cloneNode(true).toElement() ));
+ }
+ return bookmarks;
+ }
+ if ( e->provides("text/uri-list") )
+ {
+ KURL::List m_lstDragURLs;
+ //kdDebug(7043) << "KBookmarkDrag::decode uri-list" << endl;
+ if ( KURLDrag::decode( e, m_lstDragURLs ) )
+ {
+ KURL::List::ConstIterator uit = m_lstDragURLs.begin();
+ KURL::List::ConstIterator uEnd = m_lstDragURLs.end();
+ for ( ; uit != uEnd ; ++uit )
+ {
+ //kdDebug(7043) << "KBookmarkDrag::decode url=" << (*uit).url() << endl;
+ bookmarks.append( KBookmark::standaloneBookmark(
+ (*uit).prettyURL(), (*uit) ));
+ }
+ return bookmarks;
+ }
+ }
+ if( e->provides("text/plain") )
+ {
+ //kdDebug(7043) << "KBookmarkDrag::decode text/plain" << endl;
+ TQString s;
+ if(TQTextDrag::decode( e, s ))
+ {
+
+ TQStringList listDragURLs = TQStringList::split(TQChar('\n'), s);
+ TQStringList::ConstIterator it = listDragURLs.begin();
+ TQStringList::ConstIterator end = listDragURLs.end();
+ for( ; it!=end; ++it)
+ {
+ //kdDebug(7043)<<"KBookmarkDrag::decode string"<<(*it)<<endl;
+ bookmarks.append( KBookmark::standaloneBookmark( KURL(*it).prettyURL(), KURL(*it)));
+ }
+ return bookmarks;
+ }
+ }
+ bookmarks.append( KBookmark() );
+ return bookmarks;
+}
diff --git a/tdeio/bookmarks/kbookmarkdrag.h b/tdeio/bookmarks/kbookmarkdrag.h
new file mode 100644
index 000000000..016bd6849
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkdrag.h
@@ -0,0 +1,57 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kebdrag_h
+#define __kebdrag_h
+
+#include <tqdragobject.h>
+#include <kbookmark.h>
+
+// Clipboard/dnd data : URLs + XML for bookmarks
+class TDEIO_EXPORT KBookmarkDrag : public TQUriDrag
+{
+public:
+ static KBookmarkDrag * newDrag( const TQValueList<KBookmark> & bookmarks,
+ TQWidget * dragSource = 0,
+ const char * name = 0 );
+ static KBookmarkDrag * newDrag( const KBookmark & bookmark,
+ TQWidget * dragSource = 0,
+ const char * name = 0 );
+protected:
+ KBookmarkDrag( const TQValueList<KBookmark> & bookmarks,
+ const TQStrList & urls,
+ TQWidget * dragSource,
+ const char * name );
+public:
+ virtual ~KBookmarkDrag() {}
+
+ virtual const char* format( int i ) const;
+ virtual TQByteArray encodedData( const char* mime ) const;
+
+ static bool canDecode( const TQMimeSource * e );
+ static TQValueList<KBookmark> decode( const TQMimeSource * e );
+
+protected:
+ TQValueList<KBookmark> m_bookmarks;
+ TQDomDocument m_doc;
+ class KBookmarkDragPrivate;
+ KBookmarkDragPrivate * d;
+};
+#endif
diff --git a/tdeio/bookmarks/kbookmarkexporter.cc b/tdeio/bookmarks/kbookmarkexporter.cc
new file mode 100644
index 000000000..30c52bdb8
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkexporter.cc
@@ -0,0 +1,32 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 <stdio.h>
+
+#include <tqfile.h>
+#include <tqtextcodec.h>
+#include <tqstylesheet.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kbookmarkmanager.h"
+#include "kbookmarkexporter.h"
+
+// todo - put stuff in here :)
diff --git a/tdeio/bookmarks/kbookmarkexporter.h b/tdeio/bookmarks/kbookmarkexporter.h
new file mode 100644
index 000000000..68e8f475a
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkexporter.h
@@ -0,0 +1,50 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 1996-1998 Martin R. Jones <mjones@kde.org>
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 __kbookmarkexporter_h
+#define __kbookmarkexporter_h
+
+#include <tqtextstream.h>
+#include <kbookmark.h>
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KBookmarkExporterBase
+{
+public:
+ KBookmarkExporterBase(KBookmarkManager* mgr, const TQString & fileName)
+ : m_fileName(fileName), m_pManager(mgr)
+ { ; }
+ virtual ~KBookmarkExporterBase() {}
+ virtual void write(KBookmarkGroup) = 0;
+protected:
+ TQString m_fileName;
+ KBookmarkManager* m_pManager;
+private:
+ class KBookmarkExporterBasePrivate *d;
+};
+
+// for SC
+#include "kbookmarkimporter_ns.h"
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter.cc b/tdeio/bookmarks/kbookmarkimporter.cc
new file mode 100644
index 000000000..366802905
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter.cc
@@ -0,0 +1,101 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcharsets.h>
+#include <tqtextcodec.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "kbookmarkmanager.h"
+
+#include "kbookmarkimporter_ns.h"
+#include "kbookmarkimporter_opera.h"
+#include "kbookmarkimporter_ie.h"
+
+#include "kbookmarkimporter.h"
+
+void KXBELBookmarkImporterImpl::parse()
+{
+ //kdDebug() << "KXBELBookmarkImporterImpl::parse()" << endl;
+ KBookmarkManager *manager = KBookmarkManager::managerForFile(m_fileName);
+ KBookmarkGroup root = manager->root();
+ traverse(root);
+ // FIXME delete it!
+ // delete manager;
+}
+
+void KXBELBookmarkImporterImpl::visit(const KBookmark &bk)
+{
+ //kdDebug() << "KXBELBookmarkImporterImpl::visit" << endl;
+ if (bk.isSeparator())
+ emit newSeparator();
+ else
+ emit newBookmark(bk.fullText(), bk.url().url().utf8(), "");
+}
+
+void KXBELBookmarkImporterImpl::visitEnter(const KBookmarkGroup &grp)
+{
+ //kdDebug() << "KXBELBookmarkImporterImpl::visitEnter" << endl;
+ emit newFolder(grp.fullText(), false, "");
+}
+
+void KXBELBookmarkImporterImpl::visitLeave(const KBookmarkGroup &)
+{
+ //kdDebug() << "KXBELBookmarkImporterImpl::visitLeave" << endl;
+ emit endFolder();
+}
+
+void KBookmarkImporterBase::setupSignalForwards(TQObject *src, TQObject *dst)
+{
+ connect(src, TQT_SIGNAL( newBookmark( const TQString &, const TQCString &, const TQString & ) ),
+ dst, TQT_SIGNAL( newBookmark( const TQString &, const TQCString &, const TQString & ) ));
+ connect(src, TQT_SIGNAL( newFolder( const TQString &, bool, const TQString & ) ),
+ dst, TQT_SIGNAL( newFolder( const TQString &, bool, const TQString & ) ));
+ connect(src, TQT_SIGNAL( newSeparator() ),
+ dst, TQT_SIGNAL( newSeparator() ) );
+ connect(src, TQT_SIGNAL( endFolder() ),
+ dst, TQT_SIGNAL( endFolder() ) );
+}
+
+KBookmarkImporterBase* KBookmarkImporterBase::factory( const TQString &type )
+{
+ if (type == "netscape")
+ return new KNSBookmarkImporterImpl;
+ else if (type == "mozilla")
+ return new KMozillaBookmarkImporterImpl;
+ else if (type == "xbel")
+ return new KXBELBookmarkImporterImpl;
+ else if (type == "ie")
+ return new KIEBookmarkImporterImpl;
+ else if (type == "opera")
+ return new KOperaBookmarkImporterImpl;
+ else
+ return 0;
+}
+
+#include <kbookmarkimporter.moc>
diff --git a/tdeio/bookmarks/kbookmarkimporter.h b/tdeio/bookmarks/kbookmarkimporter.h
new file mode 100644
index 000000000..cc87b2004
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter.h
@@ -0,0 +1,106 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kbookmarkimporter_h
+#define __kbookmarkimporter_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <ksimpleconfig.h>
+
+#include "kbookmark.h"
+
+/**
+ * A class for importing NS bookmarks
+ * KEditBookmarks uses it to insert bookmarks into its DOM tree,
+ * and KActionMenu uses it to create actions directly.
+ * @since 3.2
+ */
+class TDEIO_EXPORT KBookmarkImporterBase : public TQObject
+{
+ Q_OBJECT
+public:
+ KBookmarkImporterBase() {}
+ virtual ~KBookmarkImporterBase() {}
+
+ void setFilename(const TQString &filename) { m_fileName = filename; }
+
+ virtual void parse() = 0;
+ virtual TQString findDefaultLocation(bool forSaving = false) const = 0;
+
+ // TODO - make this static?
+ void setupSignalForwards(TQObject *src, TQObject *dst);
+ static KBookmarkImporterBase *factory(const TQString &type);
+
+signals:
+ /**
+ * Notify about a new bookmark
+ * Use "html" for the icon
+ */
+ void newBookmark(const TQString & text, const TQCString & url, const TQString & additionalInfo);
+
+ /**
+ * Notify about a new folder
+ * Use "bookmark_folder" for the icon
+ */
+ void newFolder(const TQString & text, bool open, const TQString & additionalInfo);
+
+ /**
+ * Notify about a new separator
+ */
+ void newSeparator();
+
+ /**
+ * Tell the outside world that we're going down
+ * one menu
+ */
+ void endFolder();
+
+protected:
+ TQString m_fileName;
+
+private:
+ class KBookmarkImporterBasePrivate *d;
+};
+
+/**
+ * A class for importing XBEL files
+ */
+class TDEIO_EXPORT KXBELBookmarkImporterImpl : public KBookmarkImporterBase, protected KBookmarkGroupTraverser
+{
+ Q_OBJECT
+public:
+ KXBELBookmarkImporterImpl() {}
+ virtual void parse();
+ virtual TQString findDefaultLocation(bool = false) const { return TQString::null; }
+protected:
+ virtual void visit(const KBookmark &);
+ virtual void visitEnter(const KBookmarkGroup &);
+ virtual void visitLeave(const KBookmarkGroup &);
+private:
+ class KXBELBookmarkImporterImplPrivate *d;
+};
+
+// for SC
+#include "kbookmarkimporter_ns.h"
+#include "kbookmarkimporter_kde1.h"
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter_crash.cc b/tdeio/bookmarks/kbookmarkimporter_crash.cc
new file mode 100644
index 000000000..b2871eecd
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_crash.cc
@@ -0,0 +1,215 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002-2003 Alexander Kellett <lypanov@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 "kbookmarkimporter_crash.h"
+
+#include <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tqstring.h>
+#include <tqtextcodec.h>
+#include <dcopclient.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+typedef TQMap<TQString, TQString> ViewMap;
+
+// KDE 4.0: remove this BC keeping stub
+void KCrashBookmarkImporter::parseCrashLog( TQString /*filename*/, bool /*del*/ )
+{
+ ;
+}
+
+ViewMap KCrashBookmarkImporterImpl::parseCrashLog_noemit( const TQString & filename, bool del )
+{
+ static const int g_lineLimit = 16*1024;
+
+ TQFile f( filename );
+ ViewMap views;
+
+ if ( !f.open( IO_ReadOnly ) )
+ return views;
+
+ TQCString s( g_lineLimit );
+
+ TQTextCodec * codec = TQTextCodec::codecForName( "UTF-8" );
+ Q_ASSERT( codec );
+ if ( !codec )
+ return views;
+
+ while ( f.readLine( s.data(), g_lineLimit ) >=0 )
+ {
+ if ( s[s.length()-1] != '\n' )
+ {
+ kdWarning() << "Crash bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl;
+ continue;
+ }
+ TQString t = codec->toUnicode( s.stripWhiteSpace() );
+ TQRegExp rx( "(.*)\\((.*)\\):(.*)$" );
+ rx.setMinimal( true );
+ if ( !rx.exactMatch( t ) )
+ continue;
+ if ( rx.cap(1) == "opened" )
+ views[rx.cap(2)] = rx.cap(3);
+ else if ( rx.cap(1) == "close" )
+ views.remove( rx.cap(2) );
+ }
+
+ f.close();
+
+ if ( del )
+ f.remove();
+
+ return views;
+}
+
+TQStringList KCrashBookmarkImporter::getCrashLogs()
+{
+ return KCrashBookmarkImporterImpl::getCrashLogs();
+}
+
+TQStringList KCrashBookmarkImporterImpl::getCrashLogs()
+{
+ TQMap<TQString, bool> activeLogs;
+
+ DCOPClient* dcop = kapp->dcopClient();
+
+ QCStringList apps = dcop->registeredApplications();
+ for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
+ {
+ TQCString &clientId = *it;
+
+ if ( tqstrncmp(clientId, "konqueror", 9) != 0 )
+ continue;
+
+ TQByteArray data, replyData;
+ TQCString replyType;
+ TQDataStream arg( data, IO_WriteOnly );
+
+ if ( !dcop->call( clientId.data(), "KonquerorIface",
+ "crashLogFile()", data, replyType, replyData) )
+ {
+ kdWarning() << "can't find dcop function KonquerorIface::crashLogFile()" << endl;
+ continue;
+ }
+
+ if ( replyType != "TQString" )
+ continue;
+
+ TQDataStream reply( replyData, IO_ReadOnly );
+ TQString ret;
+ reply >> ret;
+ activeLogs[ret] = true;
+ }
+
+ TQDir d( KCrashBookmarkImporterImpl().findDefaultLocation() );
+ d.setSorting( TQDir::Time );
+ d.setFilter( TQDir::Files );
+ d.setNameFilter( "konqueror-crash-*.log" );
+
+ const TQFileInfoList *list = d.entryInfoList();
+ TQFileInfoListIterator it( *list );
+
+ TQFileInfo *fi;
+ TQStringList crashFiles;
+
+ int count = 0;
+ for ( ; (( fi = it.current() ) != 0) && (count < 20); ++it, ++count )
+ {
+ bool stillAlive = activeLogs.contains( fi->absFilePath() );
+ if ( !stillAlive )
+ crashFiles << fi->absFilePath();
+ }
+ // Delete remaining ones
+ for ( ; ( fi = it.current() ) != 0; ++it )
+ {
+ TQFile::remove( fi->absFilePath() );
+ }
+
+ return crashFiles;
+}
+
+void KCrashBookmarkImporterImpl::parse()
+{
+ TQDict<bool> signatureMap;
+ TQStringList crashFiles = KCrashBookmarkImporterImpl::getCrashLogs();
+ int count = 1;
+ for ( TQStringList::Iterator it = crashFiles.begin(); it != crashFiles.end(); ++it )
+ {
+ ViewMap views;
+ views = parseCrashLog_noemit( *it, m_shouldDelete );
+ TQString signature;
+ for ( ViewMap::Iterator vit = views.begin(); vit != views.end(); ++vit )
+ signature += "|"+vit.data();
+ if (signatureMap[signature])
+ {
+ // Duplicate... throw away and skip
+ TQFile::remove(*it);
+ continue;
+ }
+
+ signatureMap.insert(signature, (bool *) true); // hack
+
+ int outerFolder = ( crashFiles.count() > 1 ) && (views.count() > 0);
+ if ( outerFolder )
+ emit newFolder( TQString("Konqueror Window %1").arg(count++), false, "" );
+ for ( ViewMap::Iterator vit = views.begin(); vit != views.end(); ++vit )
+ emit newBookmark( vit.data(), vit.data().latin1(), TQString("") );
+ if ( outerFolder )
+ emit endFolder();
+ }
+}
+
+TQString KCrashBookmarkImporter::crashBookmarksDir()
+{
+ static KCrashBookmarkImporterImpl *p = 0;
+ if (!p)
+ p = new KCrashBookmarkImporterImpl;
+ return p->findDefaultLocation();
+}
+
+void KCrashBookmarkImporterImpl::setShouldDelete( bool shouldDelete )
+{
+ m_shouldDelete = shouldDelete;
+}
+
+void KCrashBookmarkImporter::parseCrashBookmarks( bool del )
+{
+ KCrashBookmarkImporterImpl importer;
+ importer.setFilename( m_fileName );
+ importer.setShouldDelete( del );
+ importer.setupSignalForwards( &importer, this );
+ importer.parse();
+}
+
+TQString KCrashBookmarkImporterImpl::findDefaultLocation( bool ) const
+{
+ return locateLocal( "tmp", "" );
+}
+
+#include "kbookmarkimporter_crash.moc"
diff --git a/tdeio/bookmarks/kbookmarkimporter_crash.h b/tdeio/bookmarks/kbookmarkimporter_crash.h
new file mode 100644
index 000000000..f4fc9af32
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_crash.h
@@ -0,0 +1,74 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Alexander Kellett <lypanov@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 __kbookmarkimporter_crash_h
+#define __kbookmarkimporter_crash_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <tqmap.h>
+#include <ksimpleconfig.h>
+#include <kdemacros.h>
+
+#include "kbookmarkimporter.h"
+
+/**
+ * A class for importing all crash sessions as bookmarks
+ * @deprecated
+ */
+class TDEIO_EXPORT_DEPRECATED KCrashBookmarkImporter : public TQObject
+{
+ Q_OBJECT
+public:
+ KCrashBookmarkImporter( const TQString & fileName ) : m_fileName(fileName) {}
+ ~KCrashBookmarkImporter() {}
+ void parseCrashBookmarks( bool del = true );
+ static TQString crashBookmarksDir( );
+ static TQStringList getCrashLogs(); // EMPTY!
+signals:
+ void newBookmark( const TQString & text, const TQCString & url, const TQString & additionalInfo );
+ void newFolder( const TQString & text, bool open, const TQString & additionalInfo );
+ void newSeparator();
+ void endFolder();
+protected:
+ TQString m_fileName;
+ void parseCrashLog( TQString filename, bool del ); // EMPTY!
+};
+
+/**
+ * A class for importing all crash sessions as bookmarks
+ * @since 3.2
+ */
+class TDEIO_EXPORT KCrashBookmarkImporterImpl : public KBookmarkImporterBase
+{
+public:
+ KCrashBookmarkImporterImpl() : m_shouldDelete(false) { }
+ void setShouldDelete(bool);
+ virtual void parse();
+ virtual TQString findDefaultLocation(bool forSaving = false) const;
+ static TQStringList getCrashLogs();
+private:
+ bool m_shouldDelete;
+ TQMap<TQString, TQString> parseCrashLog_noemit( const TQString & filename, bool del );
+ class KCrashBookmarkImporterImplPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter_ie.cc b/tdeio/bookmarks/kbookmarkimporter_ie.cc
new file mode 100644
index 000000000..092ebe596
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_ie.cc
@@ -0,0 +1,185 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002-2003 Alexander Kellett <lypanov@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 <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <tqtextcodec.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "kbookmarkimporter.h"
+#include "kbookmarkimporter_ie.h"
+
+/* antlarr: KDE 4: Make them const TQString & */
+void KIEBookmarkImporter::parseIEBookmarks_url_file( TQString filename, TQString name ) {
+ static const int g_lineLimit = 16*1024;
+
+ TQFile f(filename);
+
+ if(f.open(IO_ReadOnly)) {
+
+ TQCString s(g_lineLimit);
+
+ while(f.readLine(s.data(), g_lineLimit)>=0) {
+ if ( s[s.length()-1] != '\n' ) // Gosh, this line is longer than g_lineLimit. Skipping.
+ {
+ kdWarning() << "IE bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl;
+ continue;
+ }
+ TQCString t = s.stripWhiteSpace();
+ TQRegExp rx( "URL=(.*)" );
+ if (rx.exactMatch(t)) {
+ emit newBookmark( name, TQString(rx.cap(1)).latin1(), TQString("") );
+ }
+ }
+
+ f.close();
+ }
+}
+
+/* antlarr: KDE 4: Make them const TQString & */
+void KIEBookmarkImporter::parseIEBookmarks_dir( TQString dirname, TQString foldername )
+{
+
+ TQDir dir(dirname);
+ dir.setFilter( TQDir::Files | TQDir::Dirs );
+ dir.setSorting( TQDir::Name | TQDir::DirsFirst );
+ dir.setNameFilter("*.url"); // AK - possibly add ";index.ini" ?
+ dir.setMatchAllDirs(true);
+
+ const TQFileInfoList *list = dir.entryInfoList();
+ if (!list) return;
+
+ if (dirname != m_fileName)
+ emit newFolder( foldername, false, "" );
+
+ TQFileInfoListIterator it( *list );
+ TQFileInfo *fi;
+
+ while ( (fi = it.current()) != 0 ) {
+ ++it;
+
+ if (fi->fileName() == "." || fi->fileName() == "..") continue;
+
+ if (fi->isDir()) {
+ parseIEBookmarks_dir(fi->absFilePath(), fi->fileName());
+
+ } else if (fi->isFile()) {
+ if (fi->fileName().endsWith(".url")) {
+ TQString name = fi->fileName();
+ name.truncate(name.length() - 4); // .url
+ parseIEBookmarks_url_file(fi->absFilePath(), name);
+ }
+ // AK - add index.ini
+ }
+ }
+
+ if (dirname != m_fileName)
+ emit endFolder();
+}
+
+
+void KIEBookmarkImporter::parseIEBookmarks( )
+{
+ parseIEBookmarks_dir( m_fileName );
+}
+
+TQString KIEBookmarkImporter::IEBookmarksDir()
+{
+ static KIEBookmarkImporterImpl* p = 0;
+ if (!p)
+ p = new KIEBookmarkImporterImpl;
+ return p->findDefaultLocation();
+}
+
+void KIEBookmarkImporterImpl::parse() {
+ KIEBookmarkImporter importer(m_fileName);
+ setupSignalForwards(&importer, this);
+ importer.parseIEBookmarks();
+}
+
+TQString KIEBookmarkImporterImpl::findDefaultLocation(bool) const
+{
+ // notify user that they must give a new dir such
+ // as "Favourites" as otherwise it'll just place
+ // lots of .url files in the given dir and gui
+ // stuff in the exporter is ugly so that exclues
+ // the possibility of just writing to Favourites
+ // and checking if overwriting...
+ return KFileDialog::getExistingDirectory();
+}
+
+/////////////////////////////////////////////////
+
+class IEExporter : private KBookmarkGroupTraverser {
+public:
+ IEExporter( const TQString & );
+ void write( const KBookmarkGroup &grp ) { traverse(grp); };
+private:
+ virtual void visit( const KBookmark & );
+ virtual void visitEnter( const KBookmarkGroup & );
+ virtual void visitLeave( const KBookmarkGroup & );
+private:
+ TQDir m_currentDir;
+};
+
+static TQString ieStyleQuote( const TQString &str ) {
+ TQString s(str);
+ s.replace(TQRegExp("[/\\:*?\"<>|]"), "_");
+ return s;
+}
+
+IEExporter::IEExporter( const TQString & dname ) {
+ m_currentDir.setPath( dname );
+}
+
+void IEExporter::visit( const KBookmark &bk ) {
+ TQString fname = m_currentDir.path() + "/" + ieStyleQuote( bk.fullText() ) + ".url";
+ // kdDebug() << "visit(" << bk.text() << "), fname == " << fname << endl;
+ TQFile file( fname );
+ file.open( IO_WriteOnly );
+ TQTextStream ts( &file );
+ ts << "[InternetShortcut]\r\n";
+ ts << "URL=" << bk.url().url().utf8() << "\r\n";
+}
+
+void IEExporter::visitEnter( const KBookmarkGroup &grp ) {
+ TQString dname = m_currentDir.path() + "/" + ieStyleQuote( grp.fullText() );
+ // kdDebug() << "visitEnter(" << grp.text() << "), dname == " << dname << endl;
+ m_currentDir.mkdir( dname );
+ m_currentDir.cd( dname );
+}
+
+void IEExporter::visitLeave( const KBookmarkGroup & ) {
+ // kdDebug() << "visitLeave()" << endl;
+ m_currentDir.cdUp();
+}
+
+void KIEBookmarkExporterImpl::write(KBookmarkGroup parent) {
+ IEExporter exporter( m_fileName );
+ exporter.write( parent );
+}
+
+#include "kbookmarkimporter_ie.moc"
diff --git a/tdeio/bookmarks/kbookmarkimporter_ie.h b/tdeio/bookmarks/kbookmarkimporter_ie.h
new file mode 100644
index 000000000..b1b7c651c
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_ie.h
@@ -0,0 +1,90 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Alexander Kellett <lypanov@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 __kbookmarkimporter_ie_h
+#define __kbookmarkimporter_ie_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <ksimpleconfig.h>
+#include <kdemacros.h>
+
+#include <kbookmarkimporter.h>
+
+/**
+ * A class for importing IE bookmarks
+ * @deprecated
+ */
+class TDEIO_EXPORT_DEPRECATED KIEBookmarkImporter : public TQObject
+{
+ Q_OBJECT
+public:
+ KIEBookmarkImporter( const TQString & fileName ) : m_fileName(fileName) {}
+ ~KIEBookmarkImporter() {}
+
+ void parseIEBookmarks();
+
+ // Usual place for IE bookmarks
+ static TQString IEBookmarksDir();
+
+signals:
+ void newBookmark( const TQString & text, const TQCString & url, const TQString & additionalInfo );
+ void newFolder( const TQString & text, bool open, const TQString & additionalInfo );
+ void newSeparator();
+ void endFolder();
+
+protected:
+ void parseIEBookmarks_dir( TQString dirname, TQString name = TQString::null );
+ void parseIEBookmarks_url_file( TQString filename, TQString name );
+
+ TQString m_fileName;
+};
+
+/**
+ * A class for importing IE bookmarks
+ * @since 3.2
+ */
+class TDEIO_EXPORT KIEBookmarkImporterImpl : public KBookmarkImporterBase
+{
+public:
+ KIEBookmarkImporterImpl() { }
+ virtual void parse();
+ virtual TQString findDefaultLocation(bool forSaving = false) const;
+private:
+ class KIEBookmarkImporterImplPrivate *d;
+};
+
+/*
+ * @since 3.2
+ */
+class TDEIO_EXPORT KIEBookmarkExporterImpl : public KBookmarkExporterBase
+{
+public:
+ KIEBookmarkExporterImpl(KBookmarkManager* mgr, const TQString & path)
+ : KBookmarkExporterBase(mgr, path)
+ { ; }
+ virtual ~KIEBookmarkExporterImpl() {}
+ virtual void write(KBookmarkGroup);
+private:
+ class KIEBookmarkExporterImplPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter_kde1.cc b/tdeio/bookmarks/kbookmarkimporter_kde1.cc
new file mode 100644
index 000000000..6aca22b84
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_kde1.cc
@@ -0,0 +1,156 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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.
+*/
+
+#include "kbookmarkimporter_kde1.h"
+#include <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcharsets.h>
+#include <tqtextcodec.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+////////////////////
+
+void KBookmarkImporter::import( const TQString & path )
+{
+ TQDomElement elem = m_pDoc->documentElement();
+ Q_ASSERT(!elem.isNull());
+ scanIntern( elem, path );
+}
+
+void KBookmarkImporter::scanIntern( TQDomElement & parentElem, const TQString & _path )
+{
+ kdDebug(7043) << "KBookmarkImporter::scanIntern " << _path << endl;
+ // Substitute all symbolic links in the path
+ TQDir dir( _path );
+ TQString canonical = dir.canonicalPath();
+
+ if ( m_lstParsedDirs.contains(canonical) )
+ {
+ kdWarning() << "Directory " << canonical << " already parsed" << endl;
+ return;
+ }
+
+ m_lstParsedDirs.append( canonical );
+
+ DIR *dp;
+ struct dirent *ep;
+ dp = opendir( TQFile::encodeName(_path) );
+ if ( dp == 0L )
+ return;
+
+ // Loop thru all directory entries
+ while ( ( ep = readdir( dp ) ) != 0L )
+ {
+ if ( strcmp( ep->d_name, "." ) != 0 && strcmp( ep->d_name, ".." ) != 0 )
+ {
+ KURL file;
+ file.setPath( TQString( _path ) + '/' + TQFile::decodeName(ep->d_name) );
+
+ KMimeType::Ptr res = KMimeType::findByURL( file, 0, true );
+ //kdDebug(7043) << " - " << file.url() << " -> " << res->name() << endl;
+
+ if ( res->name() == "inode/directory" )
+ {
+ // We could use KBookmarkGroup::createNewFolder, but then it
+ // would notify about the change, so we'd need a flag, etc.
+ TQDomElement groupElem = m_pDoc->createElement( "folder" );
+ parentElem.appendChild( groupElem );
+ TQDomElement textElem = m_pDoc->createElement( "title" );
+ groupElem.appendChild( textElem );
+ textElem.appendChild( m_pDoc->createTextNode( TDEIO::decodeFileName( ep->d_name ) ) );
+ if ( TDEIO::decodeFileName( ep->d_name ) == "Toolbar" )
+ groupElem.setAttribute("toolbar","yes");
+ scanIntern( groupElem, file.path() );
+ }
+ else if ( (res->name() == "application/x-desktop")
+ || (res->name() == "media/builtin-mydocuments")
+ || (res->name() == "media/builtin-mycomputer")
+ || (res->name() == "media/builtin-mynetworkplaces")
+ || (res->name() == "media/builtin-printers")
+ || (res->name() == "media/builtin-trash")
+ || (res->name() == "media/builtin-webbrowser") )
+ {
+ KSimpleConfig cfg( file.path(), true );
+ cfg.setDesktopGroup();
+ TQString type = cfg.readEntry( "Type" );
+ // Is it really a bookmark file ?
+ if ( type == "Link" )
+ parseBookmark( parentElem, ep->d_name, cfg, 0 /* desktop group */ );
+ else
+ kdWarning(7043) << " Not a link ? Type=" << type << endl;
+ }
+ else if ( res->name() == "text/plain")
+ {
+ // maybe its an IE Favourite..
+ KSimpleConfig cfg( file.path(), true );
+ TQStringList grp = cfg.groupList().grep( "internetshortcut", false );
+ if ( grp.count() == 0 )
+ continue;
+ cfg.setGroup( *grp.begin() );
+
+ TQString url = cfg.readPathEntry("URL");
+ if (!url.isEmpty() )
+ parseBookmark( parentElem, ep->d_name, cfg, *grp.begin() );
+ } else
+ kdWarning(7043) << "Invalid bookmark : found mimetype='" << res->name() << "' for file='" << file.path() << "'!" << endl;
+ }
+ }
+
+ closedir( dp );
+}
+
+void KBookmarkImporter::parseBookmark( TQDomElement & parentElem, TQCString _text,
+ KSimpleConfig& _cfg, const TQString &_group )
+{
+ if ( !_group.isEmpty() )
+ _cfg.setGroup( _group );
+ else
+ _cfg.setDesktopGroup();
+
+ TQString url = _cfg.readPathEntry( "URL" );
+ TQString icon = _cfg.readEntry( "Icon" );
+ if (icon.right( 4 ) == ".xpm" ) // prevent warnings
+ icon.truncate( icon.length() - 4 );
+
+ TQString text = TDEIO::decodeFileName( TQString::fromLocal8Bit(_text) );
+ if ( text.length() > 8 && text.right( 8 ) == ".desktop" )
+ text.truncate( text.length() - 8 );
+ if ( text.length() > 7 && text.right( 7 ) == ".kdelnk" )
+ text.truncate( text.length() - 7 );
+
+ TQDomElement elem = m_pDoc->createElement( "bookmark" );
+ parentElem.appendChild( elem );
+ elem.setAttribute( "href", url );
+ //if ( icon != "www" ) // No need to save the default
+ // Hmm, after all, it makes KBookmark::pixmapFile faster,
+ // and it shows a nice feature to those reading the file
+ elem.setAttribute( "icon", icon );
+ TQDomElement textElem = m_pDoc->createElement( "title" );
+ elem.appendChild( textElem );
+ textElem.appendChild( m_pDoc->createTextNode( text ) );
+ kdDebug(7043) << "KBookmarkImporter::parseBookmark text=" << text << endl;
+}
diff --git a/tdeio/bookmarks/kbookmarkimporter_kde1.h b/tdeio/bookmarks/kbookmarkimporter_kde1.h
new file mode 100644
index 000000000..5af4f04e9
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_kde1.h
@@ -0,0 +1,49 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kbookmarkimporter_kde1_h
+#define __kbookmarkimporter_kde1_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <ksimpleconfig.h>
+
+/**
+ * A class for importing the previous bookmarks (desktop files)
+ * Separated from KBookmarkManager to save memory (we throw this one
+ * out once the import is done)
+ */
+class TDEIO_EXPORT KBookmarkImporter
+{
+public:
+ KBookmarkImporter( TQDomDocument * doc ) : m_pDoc(doc) {}
+
+ void import( const TQString & path );
+
+private:
+ void scanIntern( TQDomElement & parentElem, const TQString & _path );
+ void parseBookmark( TQDomElement & parentElem, TQCString _text,
+ KSimpleConfig& _cfg, const TQString &_group );
+ TQDomDocument * m_pDoc;
+ TQStringList m_lstParsedDirs;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter_ns.cc b/tdeio/bookmarks/kbookmarkimporter_ns.cc
new file mode 100644
index 000000000..8ce06a79b
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_ns.cc
@@ -0,0 +1,243 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 1996-1998 Martin R. Jones <mjones@kde.org>
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 "kbookmarkimporter.h"
+#include "kbookmarkexporter.h"
+#include "kbookmarkmanager.h"
+#include <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcharsets.h>
+#include <tqtextcodec.h>
+#include <tqstylesheet.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+void KNSBookmarkImporterImpl::parse()
+{
+ TQFile f(m_fileName);
+ TQTextCodec * codec = m_utf8 ? TQTextCodec::codecForName("UTF-8") : TQTextCodec::codecForLocale();
+ Q_ASSERT(codec);
+ if (!codec)
+ return;
+
+ if(f.open(IO_ReadOnly)) {
+
+ static const int g_lineLimit = 16*1024;
+ TQCString s(g_lineLimit);
+ // skip header
+ while(f.readLine(s.data(), g_lineLimit) >= 0 && !s.contains("<DL>"));
+
+ while(f.readLine(s.data(), g_lineLimit)>=0) {
+ if ( s[s.length()-1] != '\n' ) // Gosh, this line is longer than g_lineLimit. Skipping.
+ {
+ kdWarning() << "Netscape bookmarks contain a line longer than " << g_lineLimit << ". Skipping." << endl;
+ continue;
+ }
+ TQCString t = s.stripWhiteSpace();
+ if(t.left(12).upper() == "<DT><A HREF=" ||
+ t.left(16).upper() == "<DT><H3><A HREF=") {
+ int firstQuotes = t.find('"')+1;
+ int secondQuotes = t.find('"', firstQuotes);
+ if (firstQuotes != -1 && secondQuotes != -1)
+ {
+ TQCString link = t.mid(firstQuotes, secondQuotes-firstQuotes);
+ int endTag = t.find('>', secondQuotes+1);
+ TQCString name = t.mid(endTag+1);
+ name = name.left(name.findRev('<'));
+ if ( name.right(4) == "</A>" )
+ name = name.left( name.length() - 4 );
+ TQString qname = KCharsets::resolveEntities( codec->toUnicode( name ) );
+ TQCString additionalInfo = t.mid( secondQuotes+1, endTag-secondQuotes-1 );
+
+ emit newBookmark( qname,
+ link, codec->toUnicode(additionalInfo) );
+ }
+ }
+ else if(t.left(7).upper() == "<DT><H3") {
+ int endTag = t.find('>', 7);
+ TQCString name = t.mid(endTag+1);
+ name = name.left(name.findRev('<'));
+ TQString qname = KCharsets::resolveEntities( codec->toUnicode( name ) );
+ TQCString additionalInfo = t.mid( 8, endTag-8 );
+ bool folded = (additionalInfo.left(6) == "FOLDED");
+ if (folded) additionalInfo.remove(0,7);
+
+ emit newFolder( qname,
+ !folded,
+ codec->toUnicode(additionalInfo) );
+ }
+ else if(t.left(4).upper() == "<HR>")
+ emit newSeparator();
+ else if(t.left(8).upper() == "</DL><P>")
+ emit endFolder();
+ }
+
+ f.close();
+ }
+}
+
+TQString KNSBookmarkImporterImpl::findDefaultLocation(bool forSaving) const
+{
+ if (m_utf8)
+ {
+ if ( forSaving )
+ return KFileDialog::getSaveFileName( TQDir::homeDirPath() + "/.mozilla",
+ i18n("*.html|HTML Files (*.html)") );
+ else
+ return KFileDialog::getOpenFileName( TQDir::homeDirPath() + "/.mozilla",
+ i18n("*.html|HTML Files (*.html)") );
+ }
+ else
+ {
+ return TQDir::homeDirPath() + "/.netscape/bookmarks.html";
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+
+void KNSBookmarkImporter::parseNSBookmarks( bool utf8 )
+{
+ KNSBookmarkImporterImpl importer;
+ importer.setFilename(m_fileName);
+ importer.setUtf8(utf8);
+ importer.setupSignalForwards(&importer, this);
+ importer.parse();
+}
+
+TQString KNSBookmarkImporter::netscapeBookmarksFile( bool forSaving )
+{
+ static KNSBookmarkImporterImpl *p = 0;
+ if (!p)
+ {
+ p = new KNSBookmarkImporterImpl;
+ p->setUtf8(false);
+ }
+ return p->findDefaultLocation(forSaving);
+}
+
+TQString KNSBookmarkImporter::mozillaBookmarksFile( bool forSaving )
+{
+ static KNSBookmarkImporterImpl *p = 0;
+ if (!p)
+ {
+ p = new KNSBookmarkImporterImpl;
+ p->setUtf8(true);
+ }
+ return p->findDefaultLocation(forSaving);
+}
+
+
+////////////////////////////////////////////////////////////////
+// compat only
+////////////////////////////////////////////////////////////////
+
+void KNSBookmarkExporter::write(bool utf8) {
+ KNSBookmarkExporterImpl exporter(m_pManager, m_fileName);
+ exporter.setUtf8(utf8);
+ exporter.write(m_pManager->root());
+}
+
+void KNSBookmarkExporter::writeFolder(TQTextStream &/*stream*/, KBookmarkGroup /*gp*/) {
+ // TODO - requires a d pointer workaround hack?
+}
+
+////////////////////////////////////////////////////////////////
+
+void KNSBookmarkExporterImpl::setUtf8(bool utf8) {
+ m_utf8 = utf8;
+}
+
+void KNSBookmarkExporterImpl::write(KBookmarkGroup parent) {
+ if (TQFile::exists(m_fileName)) {
+ ::rename(
+ TQFile::encodeName(m_fileName),
+ TQFile::encodeName(m_fileName + ".beforekde"));
+ }
+
+ TQFile file(m_fileName);
+
+ if (!file.open(IO_WriteOnly)) {
+ kdError(7043) << "Can't write to file " << m_fileName << endl;
+ return;
+ }
+
+ TQTextStream fstream(&file);
+ fstream.setEncoding(m_utf8 ? TQTextStream::UnicodeUTF8 : TQTextStream::Locale);
+
+ TQString charset
+ = m_utf8 ? "UTF-8" : TQString::fromLatin1(TQTextCodec::codecForLocale()->name()).upper();
+
+ fstream << "<!DOCTYPE NETSCAPE-Bookmark-file-1>" << endl
+ << i18n("<!-- This file was generated by Konqueror -->") << endl
+ << "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset="
+ << charset << "\">" << endl
+ << "<TITLE>" << i18n("Bookmarks") << "</TITLE>" << endl
+ << "<H1>" << i18n("Bookmarks") << "</H1>" << endl
+ << "<DL><p>" << endl
+ << folderAsString(parent)
+ << "</DL><P>" << endl;
+}
+
+TQString KNSBookmarkExporterImpl::folderAsString(KBookmarkGroup parent) const {
+ TQString str;
+ TQTextStream fstream(&str, IO_WriteOnly);
+
+ for (KBookmark bk = parent.first(); !bk.isNull(); bk = parent.next(bk)) {
+ if (bk.isSeparator()) {
+ fstream << "<HR>" << endl;
+ continue;
+ }
+
+ TQString text = TQStyleSheet::escape(bk.fullText());
+
+ if (bk.isGroup() ) {
+ fstream << "<DT><H3 "
+ << (!bk.toGroup().isOpen() ? "FOLDED " : "")
+ << bk.internalElement().attribute("netscapeinfo") << ">"
+ << text << "</H3>" << endl
+ << "<DL><P>" << endl
+ << folderAsString(bk.toGroup())
+ << "</DL><P>" << endl;
+ continue;
+
+ } else {
+ // note - netscape seems to use local8bit for url...
+ fstream << "<DT><A HREF=\"" << bk.url().url() << "\""
+ << bk.internalElement().attribute("netscapeinfo") << ">"
+ << text << "</A>" << endl;
+ continue;
+ }
+ }
+
+ return str;
+}
+
+////
+
+#include "kbookmarkimporter_ns.moc"
diff --git a/tdeio/bookmarks/kbookmarkimporter_ns.h b/tdeio/bookmarks/kbookmarkimporter_ns.h
new file mode 100644
index 000000000..10844fc63
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_ns.h
@@ -0,0 +1,132 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kbookmarkimporter_ns_h
+#define __kbookmarkimporter_ns_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <ksimpleconfig.h>
+#include <kdemacros.h>
+
+#include "kbookmarkimporter.h"
+#include "kbookmarkexporter.h"
+
+/**
+ * A class for importing NS bookmarks
+ * @deprecated
+ */
+class TDEIO_EXPORT_DEPRECATED KNSBookmarkImporter : public TQObject
+{
+ Q_OBJECT
+public:
+ KNSBookmarkImporter( const TQString & fileName ) : m_fileName(fileName) {}
+ ~KNSBookmarkImporter() {}
+
+ // for compat reasons only
+ void parseNSBookmarks() { parseNSBookmarks(false); }
+ // go for it. Set utf8 to true for Mozilla, false for Netscape.
+ void parseNSBookmarks( bool utf8 );
+
+ static TQString netscapeBookmarksFile( bool forSaving=false );
+ static TQString mozillaBookmarksFile( bool forSaving=false );
+
+signals:
+ void newBookmark( const TQString & text, const TQCString & url, const TQString & additionalInfo );
+ void newFolder( const TQString & text, bool open, const TQString & additionalInfo );
+ void newSeparator();
+ void endFolder();
+
+protected:
+ TQString m_fileName;
+};
+
+/**
+ * A class for importing NS bookmarks
+ * utf8 defaults to off
+ * @since 3.2
+ */
+class TDEIO_EXPORT KNSBookmarkImporterImpl : public KBookmarkImporterBase
+{
+public:
+ KNSBookmarkImporterImpl() : m_utf8(false) { }
+ void setUtf8(bool utf8) { m_utf8 = utf8; }
+ virtual void parse();
+ virtual TQString findDefaultLocation(bool forSaving = false) const;
+private:
+ bool m_utf8;
+ class KNSBookmarkImporterImplPrivate *d;
+};
+
+/**
+ * A class for importing Mozilla bookmarks
+ * utf8 defaults to on
+ * @since 3.2
+ */
+class TDEIO_EXPORT KMozillaBookmarkImporterImpl : public KNSBookmarkImporterImpl
+{
+public:
+ KMozillaBookmarkImporterImpl() { setUtf8(true); }
+private:
+ class KMozillaBookmarkImporterImplPrivate *d;
+};
+
+/**
+ * A class that exports all the current bookmarks to Netscape/Mozilla bookmarks
+ * Warning, it overwrites the existing bookmarks.html file !
+ * @deprecated
+ */
+class TDEIO_EXPORT_DEPRECATED KNSBookmarkExporter
+{
+public:
+ KNSBookmarkExporter(KBookmarkManager* mgr, const TQString & fileName)
+ : m_fileName(fileName), m_pManager(mgr) { }
+ ~KNSBookmarkExporter() {}
+
+ void write() { write(false); } // deprecated
+ void write( bool utf8 );
+
+protected:
+ void writeFolder(TQTextStream &stream, KBookmarkGroup parent);
+ TQString m_fileName;
+ KBookmarkManager* m_pManager;
+};
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KNSBookmarkExporterImpl : public KBookmarkExporterBase
+{
+public:
+ KNSBookmarkExporterImpl(KBookmarkManager* mgr, const TQString & fileName)
+ : KBookmarkExporterBase(mgr, fileName)
+ { ; }
+ virtual ~KNSBookmarkExporterImpl() {}
+ virtual void write(KBookmarkGroup);
+ void setUtf8(bool);
+protected:
+ TQString folderAsString(KBookmarkGroup) const;
+private:
+ bool m_utf8;
+ class KNSBookmarkExporterImplPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkimporter_opera.cc b/tdeio/bookmarks/kbookmarkimporter_opera.cc
new file mode 100644
index 000000000..57b5d6208
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_opera.cc
@@ -0,0 +1,170 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002-2003 Alexander Kellett <lypanov@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 <tdefiledialog.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <tqtextcodec.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "kbookmarkimporter.h"
+#include "kbookmarkimporter_opera.h"
+
+void KOperaBookmarkImporter::parseOperaBookmarks( )
+{
+ TQFile file(m_fileName);
+ if(!file.open(IO_ReadOnly)) {
+ return;
+ }
+
+ TQTextCodec * codec = TQTextCodec::codecForName("UTF-8");
+ Q_ASSERT(codec);
+ if (!codec)
+ return;
+
+ int lineno = 0;
+ TQString url, name, type;
+ static const int g_lineLimit = 16*1024;
+ TQCString line(g_lineLimit);
+
+ while ( file.readLine(line.data(), g_lineLimit) >=0 ) {
+ lineno++;
+
+ // skip lines that didn't fit in buffer and first two headers lines
+ if ( line[line.length()-1] != '\n' || lineno <= 2 )
+ continue;
+
+ TQString currentLine = codec->toUnicode(line).stripWhiteSpace();
+
+ if (currentLine.isEmpty()) {
+ // end of data block
+ if (type.isNull())
+ continue;
+ else if ( type == "URL")
+ emit newBookmark( name, url.latin1(), "" );
+ else if (type == "FOLDER" )
+ emit newFolder( name, false, "" );
+
+ type = TQString::null;
+ name = TQString::null;
+ url = TQString::null;
+
+ } else if (currentLine == "-") {
+ // end of folder
+ emit endFolder();
+
+ } else {
+ // data block line
+ TQString tag;
+ if ( tag = "#", currentLine.startsWith( tag ) )
+ type = currentLine.remove( 0, tag.length() );
+ else if ( tag = "NAME=", currentLine.startsWith( tag ) )
+ name = currentLine.remove(0, tag.length());
+ else if ( tag = "URL=", currentLine.startsWith( tag ) )
+ url = currentLine.remove(0, tag.length());
+ }
+ }
+
+}
+
+TQString KOperaBookmarkImporter::operaBookmarksFile()
+{
+ static KOperaBookmarkImporterImpl *p = 0;
+ if (!p)
+ p = new KOperaBookmarkImporterImpl;
+ return p->findDefaultLocation();
+}
+
+void KOperaBookmarkImporterImpl::parse() {
+ KOperaBookmarkImporter importer(m_fileName);
+ setupSignalForwards(&importer, this);
+ importer.parseOperaBookmarks();
+}
+
+TQString KOperaBookmarkImporterImpl::findDefaultLocation(bool saving) const
+{
+ return saving ? KFileDialog::getSaveFileName(
+ TQDir::homeDirPath() + "/.opera",
+ i18n("*.adr|Opera Bookmark Files (*.adr)") )
+ : KFileDialog::getOpenFileName(
+ TQDir::homeDirPath() + "/.opera",
+ i18n("*.adr|Opera Bookmark Files (*.adr)") );
+}
+
+/////////////////////////////////////////////////
+
+class OperaExporter : private KBookmarkGroupTraverser {
+public:
+ OperaExporter();
+ TQString generate( const KBookmarkGroup &grp ) { traverse(grp); return m_string; };
+private:
+ virtual void visit( const KBookmark & );
+ virtual void visitEnter( const KBookmarkGroup & );
+ virtual void visitLeave( const KBookmarkGroup & );
+private:
+ TQString m_string;
+ TQTextStream m_out;
+};
+
+OperaExporter::OperaExporter() : m_out(&m_string, IO_WriteOnly) {
+ m_out << "Opera Hotlist version 2.0" << endl;
+ m_out << "Options: encoding = utf8, version=3" << endl;
+}
+
+void OperaExporter::visit( const KBookmark &bk ) {
+ // kdDebug() << "visit(" << bk.text() << ")" << endl;
+ m_out << "#URL" << endl;
+ m_out << "\tNAME=" << bk.fullText() << endl;
+ m_out << "\tURL=" << bk.url().url().utf8() << endl;
+ m_out << endl;
+}
+
+void OperaExporter::visitEnter( const KBookmarkGroup &grp ) {
+ // kdDebug() << "visitEnter(" << grp.text() << ")" << endl;
+ m_out << "#FOLDER" << endl;
+ m_out << "\tNAME="<< grp.fullText() << endl;
+ m_out << endl;
+}
+
+void OperaExporter::visitLeave( const KBookmarkGroup & ) {
+ // kdDebug() << "visitLeave()" << endl;
+ m_out << "-" << endl;
+ m_out << endl;
+}
+
+void KOperaBookmarkExporterImpl::write(KBookmarkGroup parent) {
+ OperaExporter exporter;
+ TQString content = exporter.generate( parent );
+ TQFile file(m_fileName);
+ if (!file.open(IO_WriteOnly)) {
+ kdError(7043) << "Can't write to file " << m_fileName << endl;
+ return;
+ }
+ TQTextStream fstream(&file);
+ fstream.setEncoding(TQTextStream::UnicodeUTF8);
+ fstream << content;
+}
+
+#include "kbookmarkimporter_opera.moc"
diff --git a/tdeio/bookmarks/kbookmarkimporter_opera.h b/tdeio/bookmarks/kbookmarkimporter_opera.h
new file mode 100644
index 000000000..f6f1028b1
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkimporter_opera.h
@@ -0,0 +1,86 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Alexander Kellett <lypanov@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 __kbookmarkimporter_opera_h
+#define __kbookmarkimporter_opera_h
+
+#include <tqdom.h>
+#include <tqcstring.h>
+#include <tqstringlist.h>
+#include <ksimpleconfig.h>
+
+#include <kbookmarkimporter.h>
+
+/**
+ * A class for importing Opera bookmarks
+ * @deprecated
+ */
+class TDEIO_EXPORT_DEPRECATED KOperaBookmarkImporter : public TQObject
+{
+ Q_OBJECT
+public:
+ KOperaBookmarkImporter( const TQString & fileName ) : m_fileName(fileName) {}
+ ~KOperaBookmarkImporter() {}
+
+ void parseOperaBookmarks();
+
+ // Usual place for Opera bookmarks
+ static TQString operaBookmarksFile();
+
+signals:
+ void newBookmark( const TQString & text, const TQCString & url, const TQString & additionalInfo );
+ void newFolder( const TQString & text, bool open, const TQString & additionalInfo );
+ void newSeparator();
+ void endFolder();
+
+protected:
+ TQString m_fileName;
+};
+
+/**
+ * A class for importing Opera bookmarks
+ * @since 3.2
+ */
+class TDEIO_EXPORT KOperaBookmarkImporterImpl : public KBookmarkImporterBase
+{
+public:
+ KOperaBookmarkImporterImpl() { }
+ virtual void parse();
+ virtual TQString findDefaultLocation(bool forSaving = false) const;
+private:
+ class KOperaBookmarkImporterImplPrivate *d;
+};
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KOperaBookmarkExporterImpl : public KBookmarkExporterBase
+{
+public:
+ KOperaBookmarkExporterImpl(KBookmarkManager* mgr, const TQString & filename)
+ : KBookmarkExporterBase(mgr, filename)
+ { ; }
+ virtual ~KOperaBookmarkExporterImpl() {}
+ virtual void write(KBookmarkGroup);
+private:
+ class KOperaBookmarkExporterImplPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkmanager.cc b/tdeio/bookmarks/kbookmarkmanager.cc
new file mode 100644
index 000000000..a87e0f20e
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkmanager.cc
@@ -0,0 +1,727 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 "kbookmarkmanager.h"
+#include "kbookmarkmenu.h"
+#include "kbookmarkmenu_p.h"
+#include "kbookmarkimporter.h"
+#include <kdebug.h>
+#include <krun.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+#include <dcopref.h>
+#include <tqregexp.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqtextstream.h>
+#include <kstaticdeleter.h>
+#include <tqptrstack.h>
+
+#include "dptrtemplate.h"
+
+class KBookmarkManagerPrivate : public dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate> {
+public:
+ KBookmarkManagerPrivate()
+ { m_browserEditor = true; }
+ TQString m_editorCaption;
+ bool m_browserEditor;
+};
+template<> TQPtrDict<KBookmarkManagerPrivate>* dPtrTemplate<KBookmarkManager, KBookmarkManagerPrivate>::d_ptr = 0;
+
+KBookmarkManagerPrivate* KBookmarkManager::dptr() const {
+ return KBookmarkManagerPrivate::d( this );
+}
+
+// TODO - clean this stuff up by just using the above dptrtemplate?
+TQPtrList<KBookmarkManager>* KBookmarkManager::s_pSelf;
+static KStaticDeleter<TQPtrList<KBookmarkManager> > sdbm;
+
+class KBookmarkMap : private KBookmarkGroupTraverser {
+public:
+ KBookmarkMap( KBookmarkManager * );
+ void update();
+ TQValueList<KBookmark> find( const TQString &url ) const
+ { return m_bk_map[url]; }
+private:
+ virtual void visit(const KBookmark &);
+ virtual void visitEnter(const KBookmarkGroup &) { ; }
+ virtual void visitLeave(const KBookmarkGroup &) { ; }
+private:
+ typedef TQValueList<KBookmark> KBookmarkList;
+ TQMap<TQString, KBookmarkList> m_bk_map;
+ KBookmarkManager *m_manager;
+};
+
+static KBookmarkMap *s_bk_map = 0;
+
+KBookmarkMap::KBookmarkMap( KBookmarkManager *manager ) {
+ m_manager = manager;
+}
+
+void KBookmarkMap::update()
+{
+ m_bk_map.clear();
+ KBookmarkGroup root = m_manager->root();
+ traverse(root);
+}
+
+void KBookmarkMap::visit(const KBookmark &bk)
+{
+ if (!bk.isSeparator()) {
+ // add bookmark to url map
+ m_bk_map[bk.internalElement().attribute("href")].append(bk);
+ }
+}
+
+
+KBookmarkManager* KBookmarkManager::managerForFile( const TQString& bookmarksFile, bool bImportDesktopFiles )
+{
+ if ( !s_pSelf ) {
+ sdbm.setObject( s_pSelf, new TQPtrList<KBookmarkManager> );
+ s_pSelf->setAutoDelete( true );
+ }
+ TQPtrListIterator<KBookmarkManager> it ( *s_pSelf );
+ for ( ; it.current() ; ++it )
+ if ( it.current()->path() == bookmarksFile )
+ return it.current();
+
+ KBookmarkManager* mgr = new KBookmarkManager( bookmarksFile, bImportDesktopFiles );
+ s_pSelf->append( mgr );
+ return mgr;
+}
+
+// principally used for filtered toolbars
+KBookmarkManager* KBookmarkManager::createTempManager()
+{
+ if ( !s_pSelf ) {
+ sdbm.setObject( s_pSelf, new TQPtrList<KBookmarkManager> );
+ s_pSelf->setAutoDelete( true );
+ }
+ KBookmarkManager* mgr = new KBookmarkManager();
+ s_pSelf->append( mgr );
+ return mgr;
+}
+
+#define PI_DATA "version=\"1.0\" encoding=\"UTF-8\""
+
+KBookmarkManager::KBookmarkManager( const TQString & bookmarksFile, bool bImportDesktopFiles )
+ : DCOPObject(TQCString("KBookmarkManager-")+bookmarksFile.utf8()), m_doc("xbel"), m_docIsLoaded(false)
+{
+ m_toolbarDoc.clear();
+
+ m_update = true;
+ m_showNSBookmarks = true;
+
+ Q_ASSERT( !bookmarksFile.isEmpty() );
+ m_bookmarksFile = bookmarksFile;
+
+ if ( !TQFile::exists(m_bookmarksFile) )
+ {
+ TQDomElement topLevel = m_doc.createElement("xbel");
+ m_doc.appendChild( topLevel );
+ m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel );
+ if ( bImportDesktopFiles )
+ importDesktopFiles();
+ m_docIsLoaded = true;
+ }
+
+ connectDCOPSignal(0, objId(), "bookmarksChanged(TQString)", "notifyChanged(TQString)", false);
+ connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false);
+}
+
+KBookmarkManager::KBookmarkManager( )
+ : DCOPObject(TQCString("KBookmarkManager-generated")), m_doc("xbel"), m_docIsLoaded(true)
+{
+ m_toolbarDoc.clear(); // strange ;-)
+
+ m_update = false; // TODO - make it read/write
+ m_showNSBookmarks = true;
+
+ m_bookmarksFile = TQString::null; // AK - check all codepaths for this one
+
+ TQDomElement topLevel = m_doc.createElement("xbel");
+ m_doc.appendChild( topLevel );
+ m_doc.insertBefore( m_doc.createProcessingInstruction( "xml", PI_DATA), topLevel );
+
+ // TODO - enable this via some sort of api and fix the above DCOPObject script somehow
+#if 0
+ connectDCOPSignal(0, objId(), "bookmarksChanged(TQString)", "notifyChanged(TQString)", false);
+ connectDCOPSignal(0, objId(), "bookmarkConfigChanged()", "notifyConfigChanged()", false);
+#endif
+}
+
+KBookmarkManager::~KBookmarkManager()
+{
+ if ( s_pSelf )
+ s_pSelf->removeRef( this );
+}
+
+void KBookmarkManager::setUpdate( bool update )
+{
+ m_update = update;
+}
+
+const TQDomDocument &KBookmarkManager::internalDocument() const
+{
+ if(!m_docIsLoaded)
+ {
+ parse();
+ m_toolbarDoc.clear();
+ }
+ return m_doc;
+}
+
+
+void KBookmarkManager::parse() const
+{
+ m_docIsLoaded = true;
+ //kdDebug(7043) << "KBookmarkManager::parse " << m_bookmarksFile << endl;
+ TQFile file( m_bookmarksFile );
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ kdWarning() << "Can't open " << m_bookmarksFile << endl;
+ return;
+ }
+ m_doc = TQDomDocument("xbel");
+ m_doc.setContent( &file );
+
+ TQDomElement docElem = m_doc.documentElement();
+ if ( docElem.isNull() )
+ kdWarning() << "KBookmarkManager::parse : can't parse " << m_bookmarksFile << endl;
+ else
+ {
+ TQString mainTag = docElem.tagName();
+ if ( mainTag == "BOOKMARKS" )
+ {
+ kdWarning() << "Old style bookmarks found. Calling convertToXBEL." << endl;
+ docElem.setTagName("xbel");
+ if ( docElem.hasAttribute( "HIDE_NSBK" ) && m_showNSBookmarks ) // non standard either, but we need it
+ {
+ docElem.setAttribute( "hide_nsbk", docElem.attribute( "HIDE_NSBK" ) == "1" ? "yes" : "no" );
+ docElem.removeAttribute( "HIDE_NSBK" );
+ }
+
+ convertToXBEL( docElem );
+ save();
+ }
+ else if ( mainTag != "xbel" )
+ kdWarning() << "KBookmarkManager::parse : unknown main tag " << mainTag << endl;
+
+ TQDomNode n = m_doc.documentElement().previousSibling();
+ if ( n.isProcessingInstruction() )
+ {
+ TQDomProcessingInstruction pi = n.toProcessingInstruction();
+ pi.parentNode().removeChild(pi);
+ }
+
+ TQDomProcessingInstruction pi;
+ pi = m_doc.createProcessingInstruction( "xml", PI_DATA );
+ m_doc.insertBefore( pi, docElem );
+ }
+
+ file.close();
+ if ( !s_bk_map )
+ s_bk_map = new KBookmarkMap( const_cast<KBookmarkManager*>( this ) );
+ s_bk_map->update();
+}
+
+void KBookmarkManager::convertToXBEL( TQDomElement & group )
+{
+ TQDomNode n = group.firstChild();
+ while( !n.isNull() )
+ {
+ TQDomElement e = n.toElement();
+ if ( !e.isNull() )
+ if ( e.tagName() == "TEXT" )
+ {
+ e.setTagName("title");
+ }
+ else if ( e.tagName() == "SEPARATOR" )
+ {
+ e.setTagName("separator"); // so close...
+ }
+ else if ( e.tagName() == "GROUP" )
+ {
+ e.setTagName("folder");
+ convertAttribute(e, "ICON","icon"); // non standard, but we need it
+ if ( e.hasAttribute( "TOOLBAR" ) ) // non standard either, but we need it
+ {
+ e.setAttribute( "toolbar", e.attribute( "TOOLBAR" ) == "1" ? "yes" : "no" );
+ e.removeAttribute( "TOOLBAR" );
+ }
+
+ convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem
+ bool open = (e.attribute("OPEN") == "1");
+ e.removeAttribute("OPEN");
+ e.setAttribute("folded", open ? "no" : "yes");
+ convertToXBEL( e );
+ }
+ else
+ if ( e.tagName() == "BOOKMARK" )
+ {
+ e.setTagName("bookmark"); // so much difference :-)
+ convertAttribute(e, "ICON","icon"); // non standard, but we need it
+ convertAttribute(e, "NETSCAPEINFO","netscapeinfo"); // idem
+ convertAttribute(e, "URL","href");
+ TQString text = e.text();
+ while ( !e.firstChild().isNull() ) // clean up the old contained text
+ e.removeChild(e.firstChild());
+ TQDomElement titleElem = e.ownerDocument().createElement("title");
+ e.appendChild( titleElem ); // should be the only child anyway
+ titleElem.appendChild( e.ownerDocument().createTextNode( text ) );
+ }
+ else
+ kdWarning(7043) << "Unknown tag " << e.tagName() << endl;
+ n = n.nextSibling();
+ }
+}
+
+void KBookmarkManager::convertAttribute( TQDomElement elem, const TQString & oldName, const TQString & newName )
+{
+ if ( elem.hasAttribute( oldName ) )
+ {
+ elem.setAttribute( newName, elem.attribute( oldName ) );
+ elem.removeAttribute( oldName );
+ }
+}
+
+void KBookmarkManager::importDesktopFiles()
+{
+ KBookmarkImporter importer( const_cast<TQDomDocument *>(&internalDocument()) );
+ TQString path(TDEGlobal::dirs()->saveLocation("data", "kfm/bookmarks", true));
+ importer.import( path );
+ //kdDebug(7043) << internalDocument().toCString() << endl;
+
+ save();
+}
+
+bool KBookmarkManager::save( bool toolbarCache ) const
+{
+ return saveAs( m_bookmarksFile, toolbarCache );
+}
+
+bool KBookmarkManager::saveAs( const TQString & filename, bool toolbarCache ) const
+{
+ kdDebug(7043) << "KBookmarkManager::save " << filename << endl;
+
+ // Save the bookmark toolbar folder for quick loading
+ // but only when it will actually make things quicker
+ const TQString cacheFilename = filename + TQString::fromLatin1(".tbcache");
+ if(toolbarCache && !root().isToolbarGroup())
+ {
+ KSaveFile cacheFile( cacheFilename );
+ if ( cacheFile.status() == 0 )
+ {
+ TQString str;
+ TQTextStream stream(&str, IO_WriteOnly);
+ stream << root().findToolbar();
+ TQCString cstr = str.utf8();
+ cacheFile.file()->writeBlock( cstr.data(), cstr.length() );
+ cacheFile.close();
+ }
+ }
+ else // remove any (now) stale cache
+ {
+ TQFile::remove( cacheFilename );
+ }
+
+ KSaveFile file( filename );
+ if ( file.status() == 0 )
+ {
+ file.backupFile( file.name(), TQString::null, ".bak" );
+ TQCString cstr;
+ cstr = internalDocument().toCString(); // is in UTF8
+ file.file()->writeBlock( cstr.data(), cstr.length() );
+ if ( file.close() )
+ return true;
+ }
+
+ static int hadSaveError = false;
+ file.abort();
+ if ( !hadSaveError ) {
+ TQString error = i18n("Unable to save bookmarks in %1. Reported error was: %2. "
+ "This error message will only be shown once. The cause "
+ "of the error needs to be fixed as quickly as possible, "
+ "which is most likely a full hard drive.")
+ .arg(filename).arg(TQString::fromLocal8Bit(strerror(file.status())));
+ if (tqApp->type() != TQApplication::Tty)
+ KMessageBox::error( 0L, error );
+ else
+ kdError() << error << endl;
+ }
+ hadSaveError = true;
+ return false;
+}
+
+KBookmarkGroup KBookmarkManager::root() const
+{
+ return KBookmarkGroup(internalDocument().documentElement());
+}
+
+KBookmarkGroup KBookmarkManager::toolbar()
+{
+ kdDebug(7043) << "KBookmarkManager::toolbar begin" << endl;
+ // Only try to read from a toolbar cache if the full document isn't loaded
+ if(!m_docIsLoaded)
+ {
+ kdDebug(7043) << "KBookmarkManager::toolbar trying cache" << endl;
+ const TQString cacheFilename = m_bookmarksFile + TQString::fromLatin1(".tbcache");
+ TQFileInfo bmInfo(m_bookmarksFile);
+ TQFileInfo cacheInfo(cacheFilename);
+ if (m_toolbarDoc.isNull() &&
+ TQFile::exists(cacheFilename) &&
+ bmInfo.lastModified() < cacheInfo.lastModified())
+ {
+ kdDebug(7043) << "KBookmarkManager::toolbar reading file" << endl;
+ TQFile file( cacheFilename );
+
+ if ( file.open( IO_ReadOnly ) )
+ {
+ m_toolbarDoc = TQDomDocument("cache");
+ m_toolbarDoc.setContent( &file );
+ kdDebug(7043) << "KBookmarkManager::toolbar opened" << endl;
+ }
+ }
+ if (!m_toolbarDoc.isNull())
+ {
+ kdDebug(7043) << "KBookmarkManager::toolbar returning element" << endl;
+ TQDomElement elem = m_toolbarDoc.firstChild().toElement();
+ return KBookmarkGroup(elem);
+ }
+ }
+
+ // Fallback to the normal way if there is no cache or if the bookmark file
+ // is already loaded
+ TQDomElement elem = root().findToolbar();
+ if (elem.isNull())
+ return root(); // Root is the bookmark toolbar if none has been set.
+ else
+ return KBookmarkGroup(root().findToolbar());
+}
+
+KBookmark KBookmarkManager::findByAddress( const TQString & address, bool tolerant )
+{
+ //kdDebug(7043) << "KBookmarkManager::findByAddress " << address << endl;
+ KBookmark result = root();
+ // The address is something like /5/10/2+
+ TQStringList addresses = TQStringList::split(TQRegExp("[/+]"),address);
+ // kdWarning() << addresses.join(",") << endl;
+ for ( TQStringList::Iterator it = addresses.begin() ; it != addresses.end() ; )
+ {
+ bool append = ((*it) == "+");
+ uint number = (*it).toUInt();
+ Q_ASSERT(result.isGroup());
+ KBookmarkGroup group = result.toGroup();
+ KBookmark bk = group.first(), lbk = bk; // last non-null bookmark
+ for ( uint i = 0 ; ( (i<number) || append ) && !bk.isNull() ; ++i ) {
+ lbk = bk;
+ bk = group.next(bk);
+ //kdWarning() << i << endl;
+ }
+ it++;
+ int shouldBeGroup = !bk.isGroup() && (it != addresses.end());
+ if ( tolerant && ( bk.isNull() || shouldBeGroup ) ) {
+ if (!lbk.isNull()) result = lbk;
+ //kdWarning() << "break" << endl;
+ break;
+ }
+ //kdWarning() << "found section" << endl;
+ result = bk;
+ }
+ if (result.isNull()) {
+ kdWarning() << "KBookmarkManager::findByAddress: couldn't find item " << address << endl;
+ Q_ASSERT(!tolerant);
+ }
+ //kdWarning() << "found " << result.address() << endl;
+ return result;
+ }
+
+static TQString pickUnusedTitle( KBookmarkGroup parentBookmark,
+ const TQString &title, const TQString &url
+) {
+ // If this title is already used, we'll try to find something unused.
+ KBookmark ch = parentBookmark.first();
+ int count = 1;
+ TQString uniqueTitle = title;
+ do
+ {
+ while ( !ch.isNull() )
+ {
+ if ( uniqueTitle == ch.text() )
+ {
+ // Title already used !
+ if ( url != ch.url().url() )
+ {
+ uniqueTitle = title + TQString(" (%1)").arg(++count);
+ // New title -> restart search from the beginning
+ ch = parentBookmark.first();
+ break;
+ }
+ else
+ {
+ // this exact URL already exists
+ return TQString::null;
+ }
+ }
+ ch = parentBookmark.next( ch );
+ }
+ } while ( !ch.isNull() );
+
+ return uniqueTitle;
+}
+
+KBookmarkGroup KBookmarkManager::addBookmarkDialog(
+ const TQString & _url, const TQString & _title,
+ const TQString & _parentBookmarkAddress
+) {
+ TQString url = _url;
+ TQString title = _title;
+ TQString parentBookmarkAddress = _parentBookmarkAddress;
+
+ if ( url.isEmpty() )
+ {
+ KMessageBox::error( 0L, i18n("Cannot add bookmark with empty URL."));
+ return KBookmarkGroup();
+ }
+
+ if ( title.isEmpty() )
+ title = url;
+
+ if ( KBookmarkSettings::self()->m_advancedaddbookmark)
+ {
+ KBookmarkEditDialog dlg( title, url, this, KBookmarkEditDialog::InsertionMode, parentBookmarkAddress );
+ if ( dlg.exec() != KDialogBase::Accepted )
+ return KBookmarkGroup();
+ title = dlg.finalTitle();
+ url = dlg.finalUrl();
+ parentBookmarkAddress = dlg.finalAddress();
+ }
+
+ KBookmarkGroup parentBookmark;
+ parentBookmark = findByAddress( parentBookmarkAddress ).toGroup();
+ Q_ASSERT( !parentBookmark.isNull() );
+
+ TQString uniqueTitle = pickUnusedTitle( parentBookmark, title, url );
+ if ( !uniqueTitle.isNull() )
+ parentBookmark.addBookmark( this, uniqueTitle, KURL( url ));
+
+ return parentBookmark;
+}
+
+
+void KBookmarkManager::emitChanged( /*KDE4 const*/ KBookmarkGroup & group )
+{
+ save();
+
+ // Tell the other processes too
+ // kdDebug(7043) << "KBookmarkManager::emitChanged : broadcasting change " << group.address() << endl;
+
+ TQByteArray data;
+ TQDataStream ds( data, IO_WriteOnly );
+ ds << group.address();
+
+ emitDCOPSignal("bookmarksChanged(TQString)", data);
+
+ // We do get our own broadcast, so no need for this anymore
+ //emit changed( group );
+}
+
+void KBookmarkManager::emitConfigChanged()
+{
+ emitDCOPSignal("bookmarkConfigChanged()", TQByteArray());
+}
+
+void KBookmarkManager::notifyCompleteChange( TQString caller ) // DCOP call
+{
+ if (!m_update) return;
+
+ //kdDebug(7043) << "KBookmarkManager::notifyCompleteChange" << endl;
+ // The bk editor tells us we should reload everything
+ // Reparse
+ parse();
+ // Tell our GUI
+ // (emit where group is "" to directly mark the root menu as dirty)
+ emit changed( "", caller );
+}
+
+void KBookmarkManager::notifyConfigChanged() // DCOP call
+{
+ kdDebug() << "reloaded bookmark config!" << endl;
+ KBookmarkSettings::self()->readSettings();
+ parse(); // reload, and thusly recreate the menus
+}
+
+void KBookmarkManager::notifyChanged( TQString groupAddress ) // DCOP call
+{
+ if (!m_update) return;
+
+ // Reparse (the whole file, no other choice)
+ // if someone else notified us
+ if (callingDcopClient()->senderId() != DCOPClient::mainClient()->appId())
+ parse();
+
+ //kdDebug(7043) << "KBookmarkManager::notifyChanged " << groupAddress << endl;
+ //KBookmarkGroup group = findByAddress( groupAddress ).toGroup();
+ //Q_ASSERT(!group.isNull());
+ emit changed( groupAddress, TQString::null );
+}
+
+bool KBookmarkManager::showNSBookmarks() const
+{
+ return KBookmarkMenu::showDynamicBookmarks("netscape").show;
+}
+
+void KBookmarkManager::setShowNSBookmarks( bool show )
+{
+ m_showNSBookmarks = show;
+ if (this->path() != userBookmarksFile())
+ return;
+ KBookmarkMenu::DynMenuInfo info
+ = KBookmarkMenu::showDynamicBookmarks("netscape");
+ info.show = show;
+ KBookmarkMenu::setDynamicBookmarks("netscape", info);
+}
+
+void KBookmarkManager::setEditorOptions( const TQString& caption, bool browser )
+{
+ dptr()->m_editorCaption = caption;
+ dptr()->m_browserEditor = browser;
+}
+
+void KBookmarkManager::slotEditBookmarks()
+{
+ TDEProcess proc;
+ proc << TQString::fromLatin1("keditbookmarks");
+ if (!dptr()->m_editorCaption.isNull())
+ proc << TQString::fromLatin1("--customcaption") << dptr()->m_editorCaption;
+ if (!dptr()->m_browserEditor)
+ proc << TQString::fromLatin1("--nobrowser");
+ proc << m_bookmarksFile;
+ proc.start(TDEProcess::DontCare);
+}
+
+void KBookmarkManager::slotEditBookmarksAtAddress( const TQString& address )
+{
+ TDEProcess proc;
+ proc << TQString::fromLatin1("keditbookmarks")
+ << TQString::fromLatin1("--address") << address
+ << m_bookmarksFile;
+ proc.start(TDEProcess::DontCare);
+}
+
+///////
+
+void KBookmarkOwner::openBookmarkURL( const TQString& url )
+{
+ (void) new KRun(KURL( url ));
+}
+
+void KBookmarkOwner::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+bool KBookmarkManager::updateAccessMetadata( const TQString & url, bool emitSignal )
+{
+ if (!s_bk_map) {
+ s_bk_map = new KBookmarkMap(this);
+ s_bk_map->update();
+ }
+
+ TQValueList<KBookmark> list = s_bk_map->find(url);
+ if ( list.count() == 0 )
+ return false;
+
+ for ( TQValueList<KBookmark>::iterator it = list.begin();
+ it != list.end(); ++it )
+ (*it).updateAccessMetadata();
+
+ if (emitSignal)
+ emit notifier().updatedAccessMetadata( path(), url );
+
+ return true;
+}
+
+void KBookmarkManager::updateFavicon( const TQString &url, const TQString &faviconurl, bool emitSignal )
+{
+ Q_UNUSED(faviconurl);
+
+ if (!s_bk_map) {
+ s_bk_map = new KBookmarkMap(this);
+ s_bk_map->update();
+ }
+
+ TQValueList<KBookmark> list = s_bk_map->find(url);
+ for ( TQValueList<KBookmark>::iterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ // TODO - update favicon data based on faviconurl
+ // but only when the previously used icon
+ // isn't a manually set one.
+ }
+
+ if (emitSignal)
+ {
+ // TODO
+ // emit notifier().updatedFavicon( path(), url, faviconurl );
+ }
+}
+
+TQString KBookmarkManager::userBookmarksFile()
+{
+ return locateLocal("data", TQString::fromLatin1("konqueror/bookmarks.xml"));
+}
+
+KBookmarkManager* KBookmarkManager::userBookmarksManager()
+{
+ return KBookmarkManager::managerForFile( userBookmarksFile() );
+}
+
+KBookmarkSettings* KBookmarkSettings::s_self = 0;
+
+void KBookmarkSettings::readSettings()
+{
+ TDEConfig config("kbookmarkrc", false, false);
+ config.setGroup("Bookmarks");
+
+ // add bookmark dialog usage - no reparse
+ s_self->m_advancedaddbookmark = config.readBoolEntry("AdvancedAddBookmarkDialog", false);
+
+ // these three alter the menu, therefore all need a reparse
+ s_self->m_contextmenu = config.readBoolEntry("ContextMenuActions", true);
+ s_self->m_quickactions = config.readBoolEntry("QuickActionSubmenu", false);
+ s_self->m_filteredtoolbar = config.readBoolEntry("FilteredToolbar", false);
+}
+
+KBookmarkSettings *KBookmarkSettings::self()
+{
+ if (!s_self)
+ {
+ s_self = new KBookmarkSettings;
+ readSettings();
+ }
+ return s_self;
+}
+
+#include "kbookmarkmanager.moc"
diff --git a/tdeio/bookmarks/kbookmarkmanager.h b/tdeio/bookmarks/kbookmarkmanager.h
new file mode 100644
index 000000000..4a129704a
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkmanager.h
@@ -0,0 +1,367 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* 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 __kbookmarkmanager_h
+#define __kbookmarkmanager_h
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqobject.h>
+#include <tqdom.h>
+#include <dcopobject.h>
+#include "kbookmark.h"
+#include "kbookmarknotifier.h"
+
+/**
+ * This class implements the reading/writing of bookmarks in XML.
+ * The bookmarks file is read and written using the XBEL standard
+ * (http://pyxml.sourceforge.net/topics/xbel/)
+ *
+ * A sample file looks like this :
+ * \code
+ * <xbel>
+ * <bookmark href="http://developer.kde.org"><title>Developer Web Site</title></bookmark>
+ * <folder folded="no">
+ * <title>Title of this folder</title>
+ * <bookmark icon="kde" href="http://www.kde.org"><title>KDE Web Site</title></bookmark>
+ * <folder toolbar="yes">
+ * <title>My own bookmarks</title>
+ * <bookmark href="http://www.koffice.org"><title>KOffice Web Site</title></bookmark>
+ * <separator/>
+ * <bookmark href="http://www.tdevelop.org"><title>KDevelop Web Site</title></bookmark>
+ * </folder>
+ * </folder>
+ * </xbel>
+ * \endcode
+ */
+class TDEIO_EXPORT KBookmarkManager : public TQObject, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+protected:
+ /**
+ * Creates a bookmark manager with a path to the bookmarks. By
+ * default, it will use the KDE standard dirs to find and create the
+ * correct location. If you are using your own app-specific
+ * bookmarks directory, you must instantiate this class with your
+ * own path <em>before</em> KBookmarkManager::managerForFile() is ever
+ * called.
+ *
+ * @param bookmarksFile full path to the bookmarks file,
+ * Use ~/.trinity/share/apps/konqueror/bookmarks.xml for the konqueror bookmarks
+ *
+ * @param bImportDesktopFiles if true, and if the bookmarksFile
+ * doesn't already exist, import bookmarks from desktop files
+ */
+ KBookmarkManager( const TQString & bookmarksFile, bool bImportDesktopFiles = true );
+
+ /**
+ * @since 3.2
+ */
+ KBookmarkManager();
+
+public:
+ /**
+ * Destructor
+ */
+ ~KBookmarkManager();
+
+ /**
+ * Set the update flag. Defaults to true. TODO - check
+ * @param update if true then KBookmarkManager will listen to DCOP update requests.
+ */
+ void setUpdate( bool update );
+
+ /**
+ * Save the bookmarks to the default konqueror XML file on disk.
+ * You should use emitChanged() instead of this function, it saves
+ * and notifies everyone that the file has changed.
+ * @param toolbarCache iff true save a cache of the toolbar folder, too
+ * @return true if saving was successful
+ */
+ bool save( bool toolbarCache = true ) const;
+
+ /**
+ * Save the bookmarks to the given XML file on disk.
+ * @param filename full path to the desired bookmarks file location
+ * @param toolbarCache iff true save a cache of the toolbar folder, too
+ * @return true if saving was successful
+ */
+ bool saveAs( const TQString & filename, bool toolbarCache = true ) const;
+
+ /**
+ * Update access time stamps for a given url.
+ * @param url the viewed url
+ * @param emitSignal iff true emit KBookmarkNotifier signal
+ * @since 3.2
+ * @return true if any metadata was modified (bookmarks file is not saved automatically)
+ */
+ bool updateAccessMetadata( const TQString &url, bool emitSignal = true );
+
+ /*
+ * NB. currently *unimplemented*
+ *
+ * Update favicon url for a given url.
+ * @param url the viewed url
+ * @param faviconurl the favicion url
+ * @emitSignal iff true emit KBookmarkNotifier signal
+ * @since 3.3
+ */
+ void updateFavicon( const TQString &url, const TQString &faviconurl, bool emitSignal = true );
+
+ /**
+ * This will return the path that this manager is using to read
+ * the bookmarks.
+ * @internal
+ * @return the path containing the bookmarks
+ */
+ TQString path() { return m_bookmarksFile; }
+
+ /**
+ * This will return the root bookmark. It is used to iterate
+ * through the bookmarks manually. It is mostly used internally.
+ *
+ * @return the root (top-level) bookmark
+ */
+ KBookmarkGroup root() const;
+
+ /**
+ * This returns the root of the toolbar menu.
+ * In the XML, this is the group with the attribute TOOLBAR=1
+ *
+ * @return the toolbar group
+ */
+ KBookmarkGroup toolbar();
+
+ /**
+ * @return the bookmark designated by @p address
+ * @param address the address belonging to the bookmark you're looking for
+ * @param tolerate when true tries to find the most tolerable bookmark position
+ * @see KBookmark::address
+ */
+ KBookmark findByAddress( const TQString & address, bool tolerate = false );
+
+ /**
+ * Saves the bookmark file and notifies everyone.
+ * @param group the parent of all changed bookmarks
+ */
+ void emitChanged( KBookmarkGroup & group );
+
+ void emitConfigChanged();
+
+ /**
+ * @return true if the NS bookmarks should be dynamically shown
+ * in the toplevel kactionmenu
+ * @deprecated
+ */
+ bool showNSBookmarks() const;
+
+ /**
+ * Shows an extra menu for NS bookmarks. Set this to false, if you don't
+ * want this.
+ */
+ void setShowNSBookmarks( bool show );
+
+ /**
+ * Set options with which slotEditBookmarks called keditbookmarks
+ * this can be used to change the appearance of the keditbookmarks
+ * in order to provide a slightly differing outer shell depending
+ * on the bookmarks file / app which calls it.
+ * @param caption the --caption string, for instance "Konsole"
+ * @param browser iff false display no browser specific
+ * menu items in keditbookmarks :: --nobrowser
+ * @since 3.2
+ */
+ void setEditorOptions( const TQString& caption, bool browser );
+
+ /**
+ * This static function will return an instance of the
+ * KBookmarkManager, responsible for the given @p bookmarksFile.
+ * If you do not instantiate this class either
+ * natively or in a derived class, then it will return an object
+ * with the default behaviors. If you wish to use different
+ * behaviors, you <em>must</em> derive your own class and
+ * instantiate it before this method is ever called.
+ *
+ * @param bookmarksFile full path to the bookmarks file,
+ * Use ~/.trinity/share/apps/konqueror/bookmarks.xml for the konqueror bookmarks
+ *
+ * @param bImportDesktopFiles if true, and if the bookmarksFile
+ * doesn't already exist, import bookmarks from desktop files
+ * @return a pointer to an instance of the KBookmarkManager.
+ */
+ static KBookmarkManager* managerForFile( const TQString& bookmarksFile,
+ bool bImportDesktopFiles = true );
+
+
+ static KBookmarkManager* createTempManager();
+
+ /**
+ * Returns a pointer to the users main bookmark collection.
+ * @since 3.2
+ */
+ static KBookmarkManager* userBookmarksManager();
+
+ /**
+ * Returns the path to the user's main bookmark collection file.
+ * @since 3.5.5
+ */
+ static TQString userBookmarksFile();
+
+ /**
+ * @internal
+ */
+ const TQDomDocument & internalDocument() const;
+
+ /**
+ * Access to bookmark notifier, for emitting signals.
+ * We need this object to exist in one instance only, so we could
+ * connectDCOP to it by name.
+ */
+ KBookmarkNotifier& notifier() { return m_notifier; }
+
+ /**
+ * @since 3.2
+ */
+ KBookmarkGroup addBookmarkDialog( const TQString & _url, const TQString & _title,
+ const TQString & _parentBookmarkAddress = TQString::null );
+
+public slots:
+ void slotEditBookmarks();
+ void slotEditBookmarksAtAddress( const TQString& address );
+
+public:
+k_dcop:
+ /**
+ * Reparse the whole bookmarks file and notify about the change
+ * (Called by the bookmark editor)
+ */
+ ASYNC notifyCompleteChange( TQString caller );
+
+ /**
+ * Emit the changed signal for the group whose address is given
+ * @see KBookmark::address()
+ * Called by the instance of konqueror that saved the file after
+ * a small change (new bookmark or new folder).
+ */
+ ASYNC notifyChanged( TQString groupAddress );
+
+ ASYNC notifyConfigChanged();
+
+signals:
+ /**
+ * Signals that the group (or any of its children) with the address
+ * @p groupAddress (e.g. "/4/5")
+ * has been modified by the caller @p caller.
+ */
+ void changed( const TQString & groupAddress, const TQString & caller );
+
+protected:
+ // consts added to avoid a copy-and-paste of internalDocument
+ void parse() const;
+ void importDesktopFiles();
+ static void convertToXBEL( TQDomElement & group );
+ static void convertAttribute( TQDomElement elem, const TQString & oldName, const TQString & newName );
+
+private:
+ KBookmarkNotifier m_notifier;
+ TQString m_bookmarksFile;
+ mutable TQDomDocument m_doc;
+ mutable TQDomDocument m_toolbarDoc;
+ mutable bool m_docIsLoaded;
+ bool m_update;
+ static TQPtrList<KBookmarkManager>* s_pSelf;
+ bool m_showNSBookmarks;
+
+private:
+ class KBookmarkManagerPrivate* dptr() const;
+};
+
+/**
+ * The KBookmarkMenu and KBookmarkBar classes gives the user
+ * the ability to either edit bookmarks or add their own. In the
+ * first case, the app may want to open the bookmark in a special way.
+ * In the second case, the app <em>must</em> supply the name and the
+ * URL for the bookmark.
+ *
+ * This class gives the app this callback-like ability.
+ *
+ * If your app does not give the user the ability to add bookmarks and
+ * you don't mind using the default bookmark editor to edit your
+ * bookmarks, then you don't need to overload this class at all.
+ * Rather, just use something like:
+ *
+ * <CODE>
+ * bookmarks = new KBookmarkMenu(new KBookmarkOwner(), ...)
+ * </CODE>
+ *
+ * If you wish to use your own editor or allow the user to add
+ * bookmarks, you must overload this class.
+ */
+class TDEIO_EXPORT KBookmarkOwner
+{
+public:
+ /**
+ * This function is called if the user selects a bookmark. It will
+ * open up the bookmark in a default fashion unless you override it.
+ */
+ virtual void openBookmarkURL(const TQString& _url);
+
+ /**
+ * This function is called whenever the user wants to add the
+ * current page to the bookmarks list. The title will become the
+ * "name" of the bookmark. You must overload this function if you
+ * wish to give your users the ability to add bookmarks.
+ *
+ * @return the title of the current page.
+ */
+ virtual TQString currentTitle() const { return TQString::null; }
+
+ /**
+ * This function is called whenever the user wants to add the
+ * current page to the bookmarks list. The URL will become the URL
+ * of the bookmark. You must overload this function if you wish to
+ * give your users the ability to add bookmarks.
+ *
+ * @return the URL of the current page.
+ */
+ virtual TQString currentURL() const { return TQString::null; }
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * @since 3.2
+ */
+class TDEIO_EXPORT KExtendedBookmarkOwner : public TQObject, virtual public KBookmarkOwner
+{
+ Q_OBJECT
+public:
+ typedef TQValueList<QPair<TQString,TQString> > QStringPairList;
+public slots:
+ void fillBookmarksList( KExtendedBookmarkOwner::QStringPairList & list ) { emit signalFillBookmarksList( list ); };
+signals:
+ void signalFillBookmarksList( KExtendedBookmarkOwner::QStringPairList & list );
+private:
+ class KExtendedBookmarkOwnerPrivate;
+ KExtendedBookmarkOwnerPrivate *d;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkmenu.cc b/tdeio/bookmarks/kbookmarkmenu.cc
new file mode 100644
index 000000000..a4d88ae57
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkmenu.cc
@@ -0,0 +1,1187 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 "kbookmarkmenu.h"
+#include "kbookmarkmenu_p.h"
+#include "kbookmarkimporter.h"
+#include "kbookmarkimporter_opera.h"
+#include "kbookmarkimporter_ie.h"
+#include "kbookmarkdrag.h"
+
+#include <kapplication.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kstringhandler.h>
+
+#include <tqclipboard.h>
+#include <tqfile.h>
+#include <tqheader.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <tqlistview.h>
+#include <tqpushbutton.h>
+
+#include <dptrtemplate.h>
+
+template class TQPtrList<KBookmarkMenu>;
+
+static TQString makeTextNodeMod(KBookmark bk, const TQString &m_nodename, const TQString &m_newText) {
+ TQDomNode subnode = bk.internalElement().namedItem(m_nodename);
+ if (subnode.isNull()) {
+ subnode = bk.internalElement().ownerDocument().createElement(m_nodename);
+ bk.internalElement().appendChild(subnode);
+ }
+
+ if (subnode.firstChild().isNull()) {
+ TQDomText domtext = subnode.ownerDocument().createTextNode("");
+ subnode.appendChild(domtext);
+ }
+
+ TQDomText domtext = subnode.firstChild().toText();
+
+ TQString m_oldText = domtext.data();
+ domtext.setData(m_newText);
+
+ return m_oldText;
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+KBookmarkMenu::KBookmarkMenu( KBookmarkManager* mgr,
+ KBookmarkOwner * _owner, KPopupMenu * _parentMenu,
+ KActionCollection *collec, bool _isRoot, bool _add,
+ const TQString & parentAddress )
+ : TQObject(),
+ m_bIsRoot(_isRoot), m_bAddBookmark(_add),
+ m_bAddShortcuts(true),
+ m_pManager(mgr), m_pOwner(_owner),
+ m_parentMenu( _parentMenu ),
+ m_actionCollection( collec ),
+ m_parentAddress( parentAddress )
+{
+ m_parentMenu->setKeyboardShortcutsEnabled( true );
+
+ m_lstSubMenus.setAutoDelete( true );
+ m_actions.setAutoDelete( true );
+
+ if (m_actionCollection)
+ {
+ m_actionCollection->setHighlightingEnabled(true);
+ disconnect( m_actionCollection, TQT_SIGNAL( actionHighlighted( KAction * ) ), 0, 0 );
+ connect( m_actionCollection, TQT_SIGNAL( actionHighlighted( KAction * ) ),
+ this, TQT_SLOT( slotActionHighlighted( KAction * ) ) );
+ }
+
+ m_bNSBookmark = m_parentAddress.isNull();
+ if ( !m_bNSBookmark ) // not for the netscape bookmark
+ {
+ //kdDebug(7043) << "KBookmarkMenu::KBookmarkMenu " << this << " address : " << m_parentAddress << endl;
+
+ connect( _parentMenu, TQT_SIGNAL( aboutToShow() ),
+ TQT_SLOT( slotAboutToShow() ) );
+
+ if ( KBookmarkSettings::self()->m_contextmenu )
+ {
+ (void) _parentMenu->contextMenu();
+ connect( _parentMenu, TQT_SIGNAL( aboutToShowContextMenu(KPopupMenu*, int, TQPopupMenu*) ),
+ this, TQT_SLOT( slotAboutToShowContextMenu(KPopupMenu*, int, TQPopupMenu*) ));
+ }
+
+ if ( m_bIsRoot )
+ {
+ connect( m_pManager, TQT_SIGNAL( changed(const TQString &, const TQString &) ),
+ TQT_SLOT( slotBookmarksChanged(const TQString &) ) );
+ }
+ }
+
+ // add entries that possibly have a shortcut, so they are available _before_ first popup
+ if ( m_bIsRoot )
+ {
+ if ( m_bAddBookmark )
+ {
+ addAddBookmark();
+ if ( extOwner() )
+ addAddBookmarksList(); // FIXME
+ }
+
+ addEditBookmarks();
+ }
+
+ m_bDirty = true;
+}
+
+KBookmarkMenu::~KBookmarkMenu()
+{
+ //kdDebug(7043) << "KBookmarkMenu::~KBookmarkMenu() " << this << endl;
+ TQPtrListIterator<KAction> it( m_actions );
+ for (; it.current(); ++it )
+ it.current()->unplugAll();
+
+ m_lstSubMenus.clear();
+ m_actions.clear();
+}
+
+void KBookmarkMenu::ensureUpToDate()
+{
+ slotAboutToShow();
+}
+
+void KBookmarkMenu::slotAboutToShow()
+{
+ // Did the bookmarks change since the last time we showed them ?
+ if ( m_bDirty )
+ {
+ m_bDirty = false;
+ refill();
+ }
+}
+
+TQString KBookmarkMenu::s_highlightedAddress;
+TQString KBookmarkMenu::s_highlightedImportType;
+TQString KBookmarkMenu::s_highlightedImportLocation;
+
+void KBookmarkMenu::slotActionHighlighted( KAction* action )
+{
+ if (action->isA("KBookmarkActionMenu") || action->isA("KBookmarkAction"))
+ {
+ s_highlightedAddress = action->property("address").toString();
+ //kdDebug() << "KBookmarkMenu::slotActionHighlighted" << s_highlightedAddress << endl;
+ }
+ else if (action->isA("KImportedBookmarksActionMenu"))
+ {
+ s_highlightedImportType = action->property("type").toString();
+ s_highlightedImportLocation = action->property("location").toString();
+ }
+ else
+ {
+ s_highlightedAddress = TQString::null;
+ s_highlightedImportType = TQString::null;
+ s_highlightedImportLocation = TQString::null;
+ }
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+class KBookmarkMenuRMBAssoc : public dPtrTemplate<KBookmarkMenu, RMB> { };
+template<> TQPtrDict<RMB>* dPtrTemplate<KBookmarkMenu, RMB>::d_ptr = 0;
+
+static RMB* rmbSelf(KBookmarkMenu *m) { return KBookmarkMenuRMBAssoc::d(m); }
+
+// TODO check via dcop before making any changes to the bookmarks file???
+
+void RMB::begin_rmb_action(KBookmarkMenu *self)
+{
+ RMB *s = rmbSelf(self);
+ s->recv = self;
+ s->m_parentAddress = self->m_parentAddress;
+ s->s_highlightedAddress = KBookmarkMenu::s_highlightedAddress;
+ s->m_pManager = self->m_pManager;
+ s->m_pOwner = self->m_pOwner;
+ s->m_parentMenu = self->m_parentMenu;
+}
+
+bool RMB::invalid( int val )
+{
+ bool valid = true;
+
+ if (val == 1)
+ s_highlightedAddress = m_parentAddress;
+
+ if (s_highlightedAddress.isNull())
+ valid = false;
+
+ return !valid;
+}
+
+KBookmark RMB::atAddress(const TQString & address)
+{
+ KBookmark bookmark = m_pManager->findByAddress( address );
+ Q_ASSERT(!bookmark.isNull());
+ return bookmark;
+}
+
+void KBookmarkMenu::slotAboutToShowContextMenu( KPopupMenu*, int, TQPopupMenu* contextMenu )
+{
+ //kdDebug(7043) << "KBookmarkMenu::slotAboutToShowContextMenu" << s_highlightedAddress << endl;
+ if (s_highlightedAddress.isNull())
+ {
+ KPopupMenu::contextMenuFocus()->hideContextMenu();
+ return;
+ }
+ contextMenu->clear();
+ fillContextMenu( contextMenu, s_highlightedAddress, 0 );
+}
+
+void RMB::fillContextMenu( TQPopupMenu* contextMenu, const TQString & address, int val )
+{
+ KBookmark bookmark = atAddress(address);
+
+ int id;
+
+ // binner:
+ // "Add Bookmark Here" when pointing at a bookmark looks strange and if you
+ // call it you have to close and reopen the menu to see an entry was added?
+ //
+ // TODO rename these, but, message freeze... umm...
+
+// if (bookmark.isGroup()) {
+ id = contextMenu->insertItem( SmallIcon("bookmark_add"), i18n( "Add Bookmark Here" ), recv, TQT_SLOT(slotRMBActionInsert(int)) );
+ contextMenu->setItemParameter( id, val );
+/* }
+ else
+ {
+ id = contextMenu->insertItem( SmallIcon("bookmark_add"), i18n( "Add Bookmark Here" ), recv, TQT_SLOT(slotRMBActionInsert(int)) );
+ contextMenu->setItemParameter( id, val );
+ }*/
+}
+
+void RMB::fillContextMenu2( TQPopupMenu* contextMenu, const TQString & address, int val )
+{
+ KBookmark bookmark = atAddress(address);
+
+ int id;
+
+ if (bookmark.isGroup()) {
+ id = contextMenu->insertItem( i18n( "Open Folder in Bookmark Editor" ), recv, TQT_SLOT(slotRMBActionEditAt(int)) );
+ contextMenu->setItemParameter( id, val );
+ contextMenu->insertSeparator();
+ id = contextMenu->insertItem( SmallIcon("editdelete"), i18n( "Delete Folder" ), recv, TQT_SLOT(slotRMBActionRemove(int)) );
+ contextMenu->setItemParameter( id, val );
+ contextMenu->insertSeparator();
+ id = contextMenu->insertItem( i18n( "Properties" ), recv, TQT_SLOT(slotRMBActionProperties(int)) );
+ contextMenu->setItemParameter( id, val );
+ }
+ else
+ {
+ id = contextMenu->insertItem( i18n( "Copy Link Address" ), recv, TQT_SLOT(slotRMBActionCopyLocation(int)) );
+ contextMenu->setItemParameter( id, val );
+ contextMenu->insertSeparator();
+ id = contextMenu->insertItem( SmallIcon("editdelete"), i18n( "Delete Bookmark" ), recv, TQT_SLOT(slotRMBActionRemove(int)) );
+ contextMenu->setItemParameter( id, val );
+ contextMenu->insertSeparator();
+ id = contextMenu->insertItem( i18n( "Properties" ), recv, TQT_SLOT(slotRMBActionProperties(int)) );
+ contextMenu->setItemParameter( id, val );
+ }
+}
+
+void RMB::slotRMBActionEditAt( int val )
+{
+ kdDebug(7043) << "KBookmarkMenu::slotRMBActionEditAt" << s_highlightedAddress << endl;
+ if (invalid(val)) { hidePopup(); return; }
+
+ KBookmark bookmark = atAddress(s_highlightedAddress);
+
+ m_pManager->slotEditBookmarksAtAddress( s_highlightedAddress );
+}
+
+void RMB::slotRMBActionProperties( int val )
+{
+ kdDebug(7043) << "KBookmarkMenu::slotRMBActionProperties" << s_highlightedAddress << endl;
+ if (invalid(val)) { hidePopup(); return; }
+
+ KBookmark bookmark = atAddress(s_highlightedAddress);
+
+ TQString folder = bookmark.isGroup() ? TQString::null : bookmark.url().pathOrURL();
+ KBookmarkEditDialog dlg( bookmark.fullText(), folder,
+ m_pManager, KBookmarkEditDialog::ModifyMode, 0,
+ 0, 0, i18n("Bookmark Properties") );
+ if ( dlg.exec() != KDialogBase::Accepted )
+ return;
+
+ makeTextNodeMod(bookmark, "title", dlg.finalTitle());
+ if ( !dlg.finalUrl().isNull() )
+ {
+ KURL u = KURL::fromPathOrURL(dlg.finalUrl());
+ bookmark.internalElement().setAttribute("href", u.url(0, 106));
+ }
+
+ kdDebug(7043) << "Requested move to " << dlg.finalAddress() << "!" << endl;
+
+ KBookmarkGroup parentBookmark = atAddress(m_parentAddress).toGroup();
+ m_pManager->emitChanged( parentBookmark );
+}
+
+void RMB::slotRMBActionInsert( int val )
+{
+ kdDebug(7043) << "KBookmarkMenu::slotRMBActionInsert" << s_highlightedAddress << endl;
+ if (invalid(val)) { hidePopup(); return; }
+
+ TQString url = m_pOwner->currentURL();
+ if (url.isEmpty())
+ {
+ KMessageBox::error( 0L, i18n("Cannot add bookmark with empty URL."));
+ return;
+ }
+ TQString title = m_pOwner->currentTitle();
+ if (title.isEmpty())
+ title = url;
+
+ KBookmark bookmark = atAddress( s_highlightedAddress );
+
+ // TODO use unique title
+
+ if (bookmark.isGroup())
+ {
+ KBookmarkGroup parentBookmark = bookmark.toGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ parentBookmark.addBookmark( m_pManager, title, KURL( url ) );
+ m_pManager->emitChanged( parentBookmark );
+ }
+ else
+ {
+ KBookmarkGroup parentBookmark = bookmark.parentGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ KBookmark newBookmark = parentBookmark.addBookmark( m_pManager, title, KURL( url ) );
+ parentBookmark.moveItem( newBookmark, parentBookmark.previous(bookmark) );
+ m_pManager->emitChanged( parentBookmark );
+ }
+}
+
+void RMB::slotRMBActionRemove( int val )
+{
+ //kdDebug(7043) << "KBookmarkMenu::slotRMBActionRemove" << s_highlightedAddress << endl;
+ if (invalid(val)) { hidePopup(); return; }
+
+ KBookmark bookmark = atAddress( s_highlightedAddress );
+ bool folder = bookmark.isGroup();
+
+ if (KMessageBox::warningContinueCancel(
+ m_parentMenu,
+ folder ? i18n("Are you sure you wish to remove the bookmark folder\n\"%1\"?").arg(bookmark.text())
+ : i18n("Are you sure you wish to remove the bookmark\n\"%1\"?").arg(bookmark.text()),
+ folder ? i18n("Bookmark Folder Deletion")
+ : i18n("Bookmark Deletion"),
+ KStdGuiItem::del())
+ != KMessageBox::Continue
+ )
+ return;
+
+ KBookmarkGroup parentBookmark = atAddress( m_parentAddress ).toGroup();
+ parentBookmark.deleteBookmark( bookmark );
+ m_pManager->emitChanged( parentBookmark );
+ if (m_parentMenu)
+ m_parentMenu->hide();
+}
+
+void RMB::slotRMBActionCopyLocation( int val )
+{
+ //kdDebug(7043) << "KBookmarkMenu::slotRMBActionCopyLocation" << s_highlightedAddress << endl;
+ if (invalid(val)) { hidePopup(); return; }
+
+ KBookmark bookmark = atAddress( s_highlightedAddress );
+
+ if ( !bookmark.isGroup() )
+ {
+ kapp->clipboard()->setData( KBookmarkDrag::newDrag(bookmark, 0),
+ TQClipboard::Selection );
+ kapp->clipboard()->setData( KBookmarkDrag::newDrag(bookmark, 0),
+ TQClipboard::Clipboard );
+ }
+}
+
+void RMB::hidePopup() {
+ KPopupMenu::contextMenuFocus()->hideContextMenu();
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+void KBookmarkMenu::fillContextMenu( TQPopupMenu* contextMenu, const TQString & address, int val )
+{
+ RMB::begin_rmb_action(this);
+ rmbSelf(this)->fillContextMenu(contextMenu, address, val);
+ emit aboutToShowContextMenu( rmbSelf(this)->atAddress(address), contextMenu);
+ rmbSelf(this)->fillContextMenu2(contextMenu, address, val);
+}
+
+void KBookmarkMenu::slotRMBActionEditAt( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); }
+
+void KBookmarkMenu::slotRMBActionProperties( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); }
+
+void KBookmarkMenu::slotRMBActionInsert( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); }
+
+void KBookmarkMenu::slotRMBActionRemove( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); }
+
+void KBookmarkMenu::slotRMBActionCopyLocation( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); }
+
+void KBookmarkMenu::slotBookmarksChanged( const TQString & groupAddress )
+{
+ if (m_bNSBookmark)
+ return;
+
+ if ( groupAddress == m_parentAddress )
+ {
+ //kdDebug(7043) << "KBookmarkMenu::slotBookmarksChanged -> setting m_bDirty on " << groupAddress << endl;
+ m_bDirty = true;
+ }
+ else
+ {
+ // Iterate recursively into child menus
+ TQPtrListIterator<KBookmarkMenu> it( m_lstSubMenus );
+ for (; it.current(); ++it )
+ {
+ it.current()->slotBookmarksChanged( groupAddress );
+ }
+ }
+}
+
+void KBookmarkMenu::refill()
+{
+ //kdDebug(7043) << "KBookmarkMenu::refill()" << endl;
+ m_lstSubMenus.clear();
+
+ TQPtrListIterator<KAction> it( m_actions );
+ for (; it.current(); ++it )
+ it.current()->unplug( m_parentMenu );
+
+ m_parentMenu->clear();
+ m_actions.clear();
+
+ fillBookmarkMenu();
+ m_parentMenu->adjustSize();
+}
+
+void KBookmarkMenu::addAddBookmarksList()
+{
+ if (!kapp->authorizeKAction("bookmarks"))
+ return;
+
+ TQString title = i18n( "Bookmark Tabs as Folder..." );
+
+ KAction * paAddBookmarksList = new KAction( title,
+ "bookmarks_list_add",
+ 0,
+ this,
+ TQT_SLOT( slotAddBookmarksList() ),
+ m_actionCollection, m_bIsRoot ? "add_bookmarks_list" : 0 );
+
+ paAddBookmarksList->setToolTip( i18n( "Add a folder of bookmarks for all open tabs." ) );
+
+ paAddBookmarksList->plug( m_parentMenu );
+ m_actions.append( paAddBookmarksList );
+}
+
+void KBookmarkMenu::addAddBookmark()
+{
+ if (!kapp->authorizeKAction("bookmarks"))
+ return;
+
+ TQString title = i18n( "Add Bookmark" );
+
+ KAction * paAddBookmarks = new KAction( title,
+ "bookmark_add",
+ m_bIsRoot && m_bAddShortcuts ? KStdAccel::addBookmark() : KShortcut(),
+ this,
+ TQT_SLOT( slotAddBookmark() ),
+ m_actionCollection, m_bIsRoot ? "add_bookmark" : 0 );
+
+ paAddBookmarks->setToolTip( i18n( "Add a bookmark for the current document" ) );
+
+ paAddBookmarks->plug( m_parentMenu );
+ m_actions.append( paAddBookmarks );
+}
+
+void KBookmarkMenu::addEditBookmarks()
+{
+ if (!kapp->authorizeKAction("bookmarks"))
+ return;
+
+ KAction * m_paEditBookmarks = KStdAction::editBookmarks( m_pManager, TQT_SLOT( slotEditBookmarks() ),
+ m_actionCollection, "edit_bookmarks" );
+ m_paEditBookmarks->plug( m_parentMenu );
+ m_paEditBookmarks->setToolTip( i18n( "Edit your bookmark collection in a separate window" ) );
+ m_actions.append( m_paEditBookmarks );
+}
+
+void KBookmarkMenu::addNewFolder()
+{
+ if (!kapp->authorizeKAction("bookmarks"))
+ return;
+
+ TQString title = i18n( "&New Bookmark Folder..." );
+ int p;
+ while ( ( p = title.find( '&' ) ) >= 0 )
+ title.remove( p, 1 );
+
+ KAction * paNewFolder = new KAction( title,
+ "folder_new", //"folder",
+ 0,
+ this,
+ TQT_SLOT( slotNewFolder() ),
+ m_actionCollection );
+
+ paNewFolder->setToolTip( i18n( "Create a new bookmark folder in this menu" ) );
+
+ paNewFolder->plug( m_parentMenu );
+ m_actions.append( paNewFolder );
+}
+
+void KBookmarkMenu::fillBookmarkMenu()
+{
+ if (!kapp->authorizeKAction("bookmarks"))
+ return;
+
+ if ( m_bIsRoot )
+ {
+ if ( m_bAddBookmark )
+ {
+ addAddBookmark();
+ if ( extOwner() )
+ addAddBookmarksList(); // FIXME
+ }
+
+ addEditBookmarks();
+
+ if ( m_bAddBookmark && !KBookmarkSettings::self()->m_advancedaddbookmark )
+ addNewFolder();
+ }
+
+ if ( m_bIsRoot
+ && KBookmarkManager::userBookmarksFile() == m_pManager->path() )
+ {
+ bool haveSep = false;
+
+ TQValueList<TQString> keys = KBookmarkMenu::dynamicBookmarksList();
+ TQValueList<TQString>::const_iterator it;
+ for ( it = keys.begin(); it != keys.end(); ++it )
+ {
+ DynMenuInfo info;
+ info = showDynamicBookmarks((*it));
+
+ if ( !info.show || !TQFile::exists( info.location ) )
+ continue;
+
+ if (!haveSep)
+ {
+ m_parentMenu->insertSeparator();
+ haveSep = true;
+ }
+
+ KActionMenu * actionMenu;
+ actionMenu = new KImportedBookmarksActionMenu(
+ info.name, info.type,
+ m_actionCollection, "kbookmarkmenu" );
+
+ actionMenu->setProperty( "type", info.type );
+ actionMenu->setProperty( "location", info.location );
+
+ actionMenu->plug( m_parentMenu );
+ m_actions.append( actionMenu );
+
+ KBookmarkMenu *subMenu =
+ new KBookmarkMenu( m_pManager, m_pOwner, actionMenu->popupMenu(),
+ m_actionCollection, false,
+ m_bAddBookmark, TQString::null );
+ connect( subMenu, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ),
+ this, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ));
+ m_lstSubMenus.append(subMenu);
+
+ connect(actionMenu->popupMenu(), TQT_SIGNAL(aboutToShow()), subMenu, TQT_SLOT(slotNSLoad()));
+ }
+ }
+
+ KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ bool separatorInserted = false;
+ for ( KBookmark bm = parentBookmark.first(); !bm.isNull(); bm = parentBookmark.next(bm) )
+ {
+ TQString text = KStringHandler::csqueeze(bm.fullText(), 60);
+ text.replace( '&', "&&" );
+ if ( !separatorInserted && m_bIsRoot) {
+ // inserted before the first konq bookmark, to avoid the separator if no konq bookmark
+ m_parentMenu->insertSeparator();
+ separatorInserted = true;
+ }
+ if ( !bm.isGroup() )
+ {
+ if ( bm.isSeparator() )
+ {
+ m_parentMenu->insertSeparator();
+ }
+ else
+ {
+ //kdDebug(7043) << "Creating URL bookmark menu item for " << bm.text() << endl;
+ KAction * action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 );
+ connect(action, TQT_SIGNAL( activated ( KAction::ActivationReason, TQt::ButtonState )),
+ this, TQT_SLOT( slotBookmarkSelected( KAction::ActivationReason, TQt::ButtonState ) ));
+
+ action->setProperty( "url", bm.url().url() );
+ action->setProperty( "address", bm.address() );
+
+ action->setToolTip( bm.url().pathOrURL() );
+
+ action->plug( m_parentMenu );
+ m_actions.append( action );
+ }
+ }
+ else
+ {
+ //kdDebug(7043) << "Creating bookmark submenu named " << bm.text() << endl;
+ KActionMenu * actionMenu = new KBookmarkActionMenu( text, bm.icon(),
+ m_actionCollection,
+ "kbookmarkmenu" );
+ actionMenu->setProperty( "address", bm.address() );
+ actionMenu->plug( m_parentMenu );
+ m_actions.append( actionMenu );
+
+ KBookmarkMenu *subMenu = new KBookmarkMenu( m_pManager, m_pOwner, actionMenu->popupMenu(),
+ m_actionCollection, false,
+ m_bAddBookmark,
+ bm.address() );
+
+ connect(subMenu, TQT_SIGNAL( aboutToShowContextMenu( const KBookmark &, TQPopupMenu * ) ),
+ this, TQT_SIGNAL( aboutToShowContextMenu( const KBookmark &, TQPopupMenu * ) ));
+ connect(subMenu, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ),
+ this, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ));
+ m_lstSubMenus.append( subMenu );
+ }
+ }
+
+ if ( !m_bIsRoot && m_bAddBookmark )
+ {
+ if ( m_parentMenu->count() > 0 )
+ m_parentMenu->insertSeparator();
+
+ if ( KBookmarkSettings::self()->m_quickactions )
+ {
+ KActionMenu * actionMenu = new KActionMenu( i18n("Quick Actions"), m_actionCollection, 0L );
+ fillContextMenu( actionMenu->popupMenu(), m_parentAddress, 1 );
+ actionMenu->plug( m_parentMenu );
+ m_actions.append( actionMenu );
+ }
+ else
+ {
+ addAddBookmark();
+ if ( extOwner() )
+ addAddBookmarksList(); // FIXME
+ addNewFolder();
+ }
+ }
+}
+
+void KBookmarkMenu::slotAddBookmarksList()
+{
+ KExtendedBookmarkOwner *extOwner = dynamic_cast<KExtendedBookmarkOwner*>(m_pOwner);
+ if (!extOwner)
+ {
+ kdWarning() << "erm, sorry ;-)" << endl;
+ return;
+ }
+
+ KExtendedBookmarkOwner::QStringPairList list;
+ extOwner->fillBookmarksList( list );
+
+ KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ KBookmarkGroup group = parentBookmark.createNewFolder( m_pManager );
+ if ( group.isNull() )
+ return; // user canceled i guess
+
+ KExtendedBookmarkOwner::QStringPairList::const_iterator it;
+ for ( it = list.begin(); it != list.end(); ++it )
+ group.addBookmark( m_pManager, (*it).first, KURL((*it).second) );
+
+ m_pManager->emitChanged( parentBookmark );
+}
+
+
+void KBookmarkMenu::slotAddBookmark()
+{
+ KBookmarkGroup parentBookmark;
+ parentBookmark = m_pManager->addBookmarkDialog(m_pOwner->currentURL(), m_pOwner->currentTitle(), m_parentAddress);
+ if (!parentBookmark.isNull())
+ m_pManager->emitChanged( parentBookmark );
+}
+
+void KBookmarkMenu::slotNewFolder()
+{
+ if ( !m_pOwner ) return; // this view doesn't handle bookmarks...
+ KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ KBookmarkGroup group = parentBookmark.createNewFolder( m_pManager );
+ if ( !group.isNull() )
+ {
+ KBookmarkGroup parentGroup = group.parentGroup();
+ m_pManager->emitChanged( parentGroup );
+ }
+}
+
+void KBookmarkMenu::slotBookmarkSelected( KAction::ActivationReason /*reason*/, TQt::ButtonState state )
+{
+ kdDebug(7043) << "KBookmarkMenu::slotBookmarkSelected()" << endl;
+ if ( !m_pOwner ) return; // this view doesn't handle bookmarks...
+ const KAction* action = dynamic_cast<const KAction *>(sender());
+ if(action)
+ {
+ const TQString& url = sender()->property("url").toString();
+ m_pOwner->openBookmarkURL( url );
+ emit openBookmark( url, state );
+ }
+}
+
+void KBookmarkMenu::slotBookmarkSelected()
+{
+ slotBookmarkSelected(KAction::PopupMenuActivation, Qt::NoButton);
+}
+
+KExtendedBookmarkOwner* KBookmarkMenu::extOwner()
+{
+ return dynamic_cast<KExtendedBookmarkOwner*>(m_pOwner);
+}
+
+void KBookmarkMenu::slotNSLoad()
+{
+ // only fill menu once
+ m_parentMenu->disconnect(TQT_SIGNAL(aboutToShow()));
+
+ // not NSImporter, but kept old name for BC reasons
+ KBookmarkMenuNSImporter importer( m_pManager, this, m_actionCollection );
+ importer.openBookmarks(s_highlightedImportLocation, s_highlightedImportType);
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+KBookmarkEditFields::KBookmarkEditFields(TQWidget *main, TQBoxLayout *vbox, FieldsSet fieldsSet)
+{
+ bool isF = (fieldsSet != FolderFieldsSet);
+
+ TQGridLayout *grid = new TQGridLayout( vbox, 2, isF ? 2 : 1 );
+
+ m_title = new KLineEdit( main );
+ grid->addWidget( m_title, 0, 1 );
+ grid->addWidget( new TQLabel( m_title, i18n( "Name:" ), main ), 0, 0 );
+ m_title->setFocus();
+ if (isF)
+ {
+ m_url = new KLineEdit( main );
+ grid->addWidget( m_url, 1, 1 );
+ grid->addWidget( new TQLabel( m_url, i18n( "Location:" ), main ), 1, 0 );
+ }
+ else
+ {
+ m_url = 0;
+ }
+
+ main->setMinimumSize( 300, 0 );
+}
+
+void KBookmarkEditFields::setName(const TQString &str)
+{
+ m_title->setText(str);
+}
+
+void KBookmarkEditFields::setLocation(const TQString &str)
+{
+ m_url->setText(str);
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+// TODO - make the dialog use Properties as a title when in Modify mode... (dirk noticed the bug...)
+KBookmarkEditDialog::KBookmarkEditDialog(const TQString& title, const TQString& url, KBookmarkManager * mgr, BookmarkEditType editType, const TQString& address,
+ TQWidget * parent, const char * name, const TQString& caption )
+ : KDialogBase(parent, name, true, caption,
+ (editType == InsertionMode) ? (User1|Ok|Cancel) : (Ok|Cancel),
+ Ok, false, KGuiItem()),
+ m_folderTree(0), m_mgr(mgr), m_editType(editType), m_address(address)
+{
+ setButtonOK( (editType == InsertionMode) ? KGuiItem( i18n( "&Add" ), "bookmark_add") : i18n( "&Update" ) );
+ if (editType == InsertionMode) {
+ setButtonGuiItem( User1, KGuiItem( i18n( "&New Folder..." ), "folder_new") );
+ }
+
+ bool folder = url.isNull();
+
+ m_main = new TQWidget( this );
+ setMainWidget( m_main );
+
+ TQBoxLayout *vbox = new TQVBoxLayout( m_main, 0, spacingHint() );
+ KBookmarkEditFields::FieldsSet fs =
+ folder ? KBookmarkEditFields::FolderFieldsSet
+ : KBookmarkEditFields::BookmarkFieldsSet;
+ m_fields = new KBookmarkEditFields(m_main, vbox, fs);
+ m_fields->setName(title);
+ if ( !folder )
+ m_fields->setLocation(url);
+
+ if ( editType == InsertionMode )
+ {
+ m_folderTree = KBookmarkFolderTree::createTree( m_mgr, m_main, name, m_address );
+ connect( m_folderTree, TQT_SIGNAL( doubleClicked(TQListViewItem*) ),
+ this, TQT_SLOT( slotDoubleClicked(TQListViewItem*) ) );
+ vbox->addWidget( m_folderTree );
+ connect( this, TQT_SIGNAL( user1Clicked() ), TQT_SLOT( slotUser1() ) );
+ }
+}
+
+void KBookmarkEditDialog::slotDoubleClicked( TQListViewItem* item )
+{
+ Q_ASSERT( m_folderTree );
+ m_folderTree->setCurrentItem( item );
+ accept();
+}
+
+void KBookmarkEditDialog::slotOk()
+{
+ accept();
+}
+
+void KBookmarkEditDialog::slotCancel()
+{
+ reject();
+}
+
+TQString KBookmarkEditDialog::finalAddress() const
+{
+ Q_ASSERT( m_folderTree );
+ return KBookmarkFolderTree::selectedAddress( m_folderTree );
+}
+
+TQString KBookmarkEditDialog::finalUrl() const
+{
+ return m_fields->m_url ? m_fields->m_url->text() : TQString::null;
+}
+
+TQString KBookmarkEditDialog::finalTitle() const
+{
+ return m_fields->m_title ? m_fields->m_title->text() : TQString::null;
+}
+
+void KBookmarkEditDialog::slotUser1()
+{
+ // kdDebug(7043) << "KBookmarkEditDialog::slotUser1" << endl;
+ Q_ASSERT( m_folderTree );
+
+ TQString address = KBookmarkFolderTree::selectedAddress( m_folderTree );
+ if ( address.isNull() ) return;
+ KBookmarkGroup bm = m_mgr->findByAddress( address ).toGroup();
+ Q_ASSERT(!bm.isNull());
+ Q_ASSERT(m_editType == InsertionMode);
+
+ KBookmarkGroup group = bm.createNewFolder( m_mgr );
+ if ( !group.isNull() )
+ {
+ KBookmarkGroup parentGroup = group.parentGroup();
+ m_mgr->emitChanged( parentGroup );
+ }
+ KBookmarkFolderTree::fillTree( m_folderTree, m_mgr );
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+static void fillGroup( TQListView* listview, KBookmarkFolderTreeItem * parentItem, KBookmarkGroup group, bool expandOpenGroups = true, const TQString& address = TQString::null )
+{
+ bool noSubGroups = true;
+ KBookmarkFolderTreeItem * lastItem = 0L;
+ KBookmarkFolderTreeItem * item = 0L;
+ for ( KBookmark bk = group.first() ; !bk.isNull() ; bk = group.next(bk) )
+ {
+ if ( bk.isGroup() )
+ {
+ KBookmarkGroup grp = bk.toGroup();
+ item = new KBookmarkFolderTreeItem( parentItem, lastItem, grp );
+ fillGroup( listview, item, grp, expandOpenGroups, address );
+ if ( expandOpenGroups && grp.isOpen() )
+ item->setOpen( true );
+ lastItem = item;
+ noSubGroups = false;
+ }
+ if (bk.address() == address) {
+ listview->setCurrentItem( lastItem );
+ listview->ensureItemVisible( item );
+ }
+ }
+ if ( noSubGroups ) {
+ parentItem->setOpen( true );
+ }
+}
+
+TQListView* KBookmarkFolderTree::createTree( KBookmarkManager* mgr, TQWidget* parent, const char* name, const TQString& address )
+{
+ TQListView *listview = new TQListView( parent, name );
+
+ listview->setRootIsDecorated( false );
+ listview->header()->hide();
+ listview->addColumn( i18n("Bookmark"), 200 );
+ listview->setSorting( -1, false );
+ listview->setSelectionMode( TQListView::Single );
+ listview->setAllColumnsShowFocus( true );
+ listview->setResizeMode( TQListView::AllColumns );
+ listview->setMinimumSize( 60, 100 );
+
+ fillTree( listview, mgr, address );
+
+ return listview;
+}
+
+void KBookmarkFolderTree::fillTree( TQListView *listview, KBookmarkManager* mgr, const TQString& address )
+{
+ listview->clear();
+
+ KBookmarkGroup root = mgr->root();
+ KBookmarkFolderTreeItem * rootItem = new KBookmarkFolderTreeItem( listview, root );
+ listview->setCurrentItem( rootItem );
+ rootItem->setSelected( true );
+ fillGroup( listview, rootItem, root, (address == root.groupAddress() || address.isNull()) ? true : false, address );
+ rootItem->setOpen( true );
+}
+
+static KBookmarkFolderTreeItem* ft_cast( TQListViewItem *i )
+{
+ return static_cast<KBookmarkFolderTreeItem*>( i );
+}
+
+TQString KBookmarkFolderTree::selectedAddress( TQListView *listview )
+{
+ if ( !listview)
+ return TQString::null;
+ KBookmarkFolderTreeItem *item = ft_cast( listview->currentItem() );
+ return item ? item->m_bookmark.address() : TQString::null;
+}
+
+void KBookmarkFolderTree::setAddress( TQListView *listview, const TQString & address )
+{
+ KBookmarkFolderTreeItem* it = ft_cast( listview->firstChild() );
+ while ( true ) {
+ kdDebug(7043) << it->m_bookmark.address() << endl;
+ it = ft_cast( it->itemBelow() );
+ if ( !it )
+ return;
+ if ( it->m_bookmark.address() == address )
+ break;
+ }
+ it->setSelected( true );
+ listview->setCurrentItem( it );
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+// toplevel item
+KBookmarkFolderTreeItem::KBookmarkFolderTreeItem( TQListView *parent, const KBookmark & gp )
+ : TQListViewItem(parent, i18n("Bookmarks")), m_bookmark(gp)
+{
+ setPixmap(0, SmallIcon("bookmark"));
+ setExpandable(true);
+}
+
+// group
+KBookmarkFolderTreeItem::KBookmarkFolderTreeItem( KBookmarkFolderTreeItem *parent, TQListViewItem *after, const KBookmarkGroup & gp )
+ : TQListViewItem(parent, after, gp.fullText()), m_bookmark(gp)
+{
+ setPixmap(0, SmallIcon( gp.icon() ) );
+ setExpandable(true);
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+// NOTE - KBookmarkMenuNSImporter is really === KBookmarkMenuImporter
+// i.e, it is _not_ ns specific. and in KDE4 it should be renamed.
+
+void KBookmarkMenuNSImporter::openNSBookmarks()
+{
+ openBookmarks( KNSBookmarkImporter::netscapeBookmarksFile(), "netscape" );
+}
+
+void KBookmarkMenuNSImporter::openBookmarks( const TQString &location, const TQString &type )
+{
+ mstack.push(m_menu);
+
+ KBookmarkImporterBase *importer = KBookmarkImporterBase::factory(type);
+ if (!importer)
+ return;
+ importer->setFilename(location);
+ connectToImporter(*importer);
+ importer->parse();
+
+ delete importer;
+}
+
+void KBookmarkMenuNSImporter::connectToImporter(const TQObject &importer)
+{
+ connect( &importer, TQT_SIGNAL( newBookmark( const TQString &, const TQCString &, const TQString & ) ),
+ TQT_SLOT( newBookmark( const TQString &, const TQCString &, const TQString & ) ) );
+ connect( &importer, TQT_SIGNAL( newFolder( const TQString &, bool, const TQString & ) ),
+ TQT_SLOT( newFolder( const TQString &, bool, const TQString & ) ) );
+ connect( &importer, TQT_SIGNAL( newSeparator() ), TQT_SLOT( newSeparator() ) );
+ connect( &importer, TQT_SIGNAL( endFolder() ), TQT_SLOT( endFolder() ) );
+}
+
+void KBookmarkMenuNSImporter::newBookmark( const TQString & text, const TQCString & url, const TQString & )
+{
+ TQString _text = KStringHandler::csqueeze(text);
+ _text.replace( '&', "&&" );
+ KAction * action = new KBookmarkAction(_text, "html", 0, 0, "", m_actionCollection, 0);
+ connect(action, TQT_SIGNAL( activated ( KAction::ActivationReason, TQt::ButtonState )),
+ m_menu, TQT_SLOT( slotBookmarkSelected( KAction::ActivationReason, TQt::ButtonState ) ));
+ action->setProperty( "url", url );
+ action->setToolTip( url );
+ action->plug( mstack.top()->m_parentMenu );
+ mstack.top()->m_actions.append( action );
+}
+
+void KBookmarkMenuNSImporter::newFolder( const TQString & text, bool, const TQString & )
+{
+ TQString _text = KStringHandler::csqueeze(text);
+ _text.replace( '&', "&&" );
+ KActionMenu * actionMenu = new KActionMenu( _text, "folder", m_actionCollection, 0L );
+ actionMenu->plug( mstack.top()->m_parentMenu );
+ mstack.top()->m_actions.append( actionMenu );
+ KBookmarkMenu *subMenu = new KBookmarkMenu( m_pManager, m_menu->m_pOwner, actionMenu->popupMenu(),
+ m_actionCollection, false,
+ m_menu->m_bAddBookmark, TQString::null );
+ connect( subMenu, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ),
+ m_menu, TQT_SIGNAL( openBookmark( const TQString &, TQt::ButtonState ) ));
+ mstack.top()->m_lstSubMenus.append( subMenu );
+
+ mstack.push(subMenu);
+}
+
+void KBookmarkMenuNSImporter::newSeparator()
+{
+ mstack.top()->m_parentMenu->insertSeparator();
+}
+
+void KBookmarkMenuNSImporter::endFolder()
+{
+ mstack.pop();
+}
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+KBookmarkMenu::DynMenuInfo KBookmarkMenu::showDynamicBookmarks( const TQString &id )
+{
+ TDEConfig config("kbookmarkrc", false, false);
+ config.setGroup("Bookmarks");
+
+ DynMenuInfo info;
+ info.show = false;
+
+ if (!config.hasKey("DynamicMenus")) {
+ // upgrade path
+ if (id == "netscape") {
+ KBookmarkManager *manager = KBookmarkManager::userBookmarksManager();
+ info.show = manager->root().internalElement().attribute("hide_nsbk") != "yes";
+ info.location = KNSBookmarkImporter::netscapeBookmarksFile();
+ info.type = "netscape";
+ info.name = i18n("Netscape Bookmarks");
+ } // else, no show
+
+ } else {
+ // have new version config
+ if (config.hasGroup("DynamicMenu-" + id)) {
+ config.setGroup("DynamicMenu-" + id);
+ info.show = config.readBoolEntry("Show");
+ info.location = config.readPathEntry("Location");
+ info.type = config.readEntry("Type");
+ info.name = config.readEntry("Name");
+ } // else, no show
+ }
+
+ return info;
+}
+
+TQStringList KBookmarkMenu::dynamicBookmarksList()
+{
+ TDEConfig config("kbookmarkrc", false, false);
+ config.setGroup("Bookmarks");
+
+ TQStringList mlist;
+ if (config.hasKey("DynamicMenus"))
+ mlist = config.readListEntry("DynamicMenus");
+ else
+ mlist << "netscape";
+
+ return mlist;
+}
+
+void KBookmarkMenu::setDynamicBookmarks(const TQString &id, const DynMenuInfo &newMenu)
+{
+ TDEConfig config("kbookmarkrc", false, false);
+
+ // add group unconditionally
+ config.setGroup("DynamicMenu-" + id);
+ config.writeEntry("Show", newMenu.show);
+ config.writePathEntry("Location", newMenu.location);
+ config.writeEntry("Type", newMenu.type);
+ config.writeEntry("Name", newMenu.name);
+
+ TQStringList elist;
+
+ config.setGroup("Bookmarks");
+ if (!config.hasKey("DynamicMenus")) {
+ if (newMenu.type != "netscape") {
+ // update from old xbel method to new rc method
+ // though only if not writing the netscape setting
+ config.setGroup("DynamicMenu-" "netscape");
+ DynMenuInfo xbelSetting;
+ xbelSetting = showDynamicBookmarks("netscape");
+ config.writeEntry("Show", xbelSetting.show);
+ config.writePathEntry("Location", xbelSetting.location);
+ config.writeEntry("Type", xbelSetting.type);
+ config.writeEntry("Name", xbelSetting.name);
+ }
+ } else {
+ elist = config.readListEntry("DynamicMenus");
+ }
+
+ // make sure list includes type
+ config.setGroup("Bookmarks");
+ if (elist.contains(id) < 1) {
+ elist << id;
+ config.writeEntry("DynamicMenus", elist);
+ }
+
+ config.sync();
+}
+
+#include "kbookmarkmenu.moc"
+#include "kbookmarkmenu_p.moc"
diff --git a/tdeio/bookmarks/kbookmarkmenu.h b/tdeio/bookmarks/kbookmarkmenu.h
new file mode 100644
index 000000000..35e6191e3
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkmenu.h
@@ -0,0 +1,265 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __kbookmarkmenu_h__
+#define __kbookmarkmenu_h__
+
+#include <sys/types.h>
+
+#include <tqptrlist.h>
+#include <tqptrstack.h>
+#include <tqobject.h>
+#include <tqlistview.h>
+
+#include <kdialogbase.h>
+#include <klocale.h>
+#include <kaction.h>
+
+#include "kbookmark.h"
+#include "kbookmarkmanager.h"
+
+class TQString;
+class TQPopupMenu;
+class TQPushButton;
+class TQListView;
+class KLineEdit;
+class KBookmark;
+class KBookmarkGroup;
+class KAction;
+class KActionMenu;
+class KActionCollection;
+class KBookmarkOwner;
+class KBookmarkMenu;
+class KPopupMenu;
+
+namespace TDEIO { class Job; }
+
+/**
+ * This class provides a bookmark menu. It is typically used in
+ * cooperation with KActionMenu but doesn't have to be.
+ *
+ * If you use this class by itself, then it will use KDE defaults for
+ * everything -- the bookmark path, bookmark editor, bookmark launcher..
+ * everything. These defaults reside in the classes
+ * KBookmarkOwner (editing bookmarks) and KBookmarkManager
+ * (almost everything else). If you wish to change the defaults in
+ * any way, you must reimplement and instantiate those classes
+ * <em>before</em> this class is ever called.
+ *
+ * Using this class is very simple:
+ *
+ * 1) Create a popup menu (either KActionMenu or KPopupMenu will do)
+ * 2) Instantiate a new KBookmarkMenu object using the above popup
+ * menu as a parameter
+ * 3) Insert your (now full) popup menu wherever you wish
+ *
+ * Again, if you wish to modify any defaults, the procedure is:
+ *
+ * 1a) Reimplement your own KBookmarkOwner
+ * 1b) Reimplement and instantiate your own KBookmarkManager
+ */
+class TDEIO_EXPORT KBookmarkMenu : public TQObject
+{
+ Q_OBJECT
+ friend class KBookmarkMenuNSImporter;
+ friend class RMB;
+public:
+ /**
+ * Fills a bookmark menu
+ * (one instance of KBookmarkMenu is created for the toplevel menu,
+ * but also one per submenu).
+ *
+ * @param mgr The bookmark manager to use (i.e. for reading and writing)
+ * @param owner implementation of the KBookmarkOwner callback interface.
+ * @param parentMenu menu to be filled
+ * @param collec parent collection for the KActions.
+ * Only used for other menus than the toplevel one.
+ * @param root true for the toplevel menu
+ * @param add true to show the "Add Bookmark" and "New Folder" entries
+ * @param parentAddress the address of the group containing the items
+ * that we want to show.
+ * @see KBookmark::address.
+ * Be careful :
+ * A _null_ parentAddress denotes a NS-bookmark menu.
+ * An _empty_ parentAddress denotes the toplevel bookmark menu
+ */
+ KBookmarkMenu( KBookmarkManager* mgr,
+ KBookmarkOwner * owner, KPopupMenu * parentMenu,
+ KActionCollection * collec, bool root, bool add = true,
+ const TQString & parentAddress = "" );
+
+ ~KBookmarkMenu();
+
+ /**
+ * Even if you think you need to use this, you are probably wrong.
+ * It fills a bookmark menu starting a given KBookmark.
+ * This is public for KBookmarkBar.
+ */
+ void fillBookmarkMenu();
+
+ /**
+ * Call ensureUpToDate() if you need KBookmarkMenu to adjust to its
+ * final size before it is executed.
+ **/
+ void ensureUpToDate();
+
+ /**
+ * Structure used for storing information about
+ * the dynamic menu setting
+ * @since 3.2
+ */
+ // TODO - transform into class
+ struct DynMenuInfo {
+ bool show;
+ TQString location;
+ TQString type;
+ TQString name;
+ class DynMenuInfoPrivate *d;
+ };
+
+ /**
+ * @return dynmenu info block for the given dynmenu name
+ * @since 3.2
+ */
+ static DynMenuInfo showDynamicBookmarks( const TQString &id );
+
+ /**
+ * Shows an extra menu for the given bookmarks file and type.
+ * Upgrades from option inside XBEL to option in rc file
+ * on first call of this function.
+ * @param id the unique identification for the dynamic menu
+ * @param info a DynMenuInfo struct containing the to be added/modified data
+ * @since 3.2
+ */
+ static void setDynamicBookmarks( const TQString &id, const DynMenuInfo &info );
+
+ /**
+ * @return list of dynamic menu ids
+ * @since 3.2
+ */
+ static TQStringList dynamicBookmarksList();
+
+signals:
+ void aboutToShowContextMenu( const KBookmark &, TQPopupMenu * );
+ /**
+ * @since 3.4
+ */
+ void openBookmark( const TQString& url, TQt::ButtonState state );
+
+public slots: // public for bookmark bar
+ void slotBookmarksChanged( const TQString & );
+
+protected slots:
+ void slotAboutToShow();
+ void slotAboutToShowContextMenu( KPopupMenu *, int, TQPopupMenu * );
+ void slotActionHighlighted( KAction * );
+
+ void slotRMBActionRemove( int );
+ void slotRMBActionInsert( int );
+ void slotRMBActionCopyLocation( int );
+ void slotRMBActionEditAt( int );
+ void slotRMBActionProperties( int );
+
+ void slotBookmarkSelected();
+ /**
+ * @ since 3.4
+ */
+ void slotBookmarkSelected( KAction::ActivationReason reason, TQt::ButtonState state );
+ void slotAddBookmarksList();
+ void slotAddBookmark();
+ void slotNewFolder();
+
+ /**
+ * load Netscape's bookmarks
+ */
+ void slotNSLoad();
+
+protected:
+ KExtendedBookmarkOwner* extOwner();
+ void refill();
+ void addAddBookmark();
+ void addAddBookmarksList();
+ void addEditBookmarks();
+ void addNewFolder();
+
+ void fillContextMenu( TQPopupMenu *, const TQString &, int );
+
+ bool m_bIsRoot:1;
+ bool m_bAddBookmark:1;
+ bool m_bDirty:1;
+ bool m_bNSBookmark:1;
+ bool m_bAddShortcuts:1;
+
+ KBookmarkManager * m_pManager;
+ KBookmarkOwner *m_pOwner;
+ /**
+ * The menu in which we plug our actions.
+ * Supplied in the constructor.
+ */
+ KPopupMenu * m_parentMenu;
+ /**
+ * List of our sub menus
+ */
+ TQPtrList<KBookmarkMenu> m_lstSubMenus;
+ KActionCollection * m_actionCollection;
+ /**
+ * List of our actions.
+ */
+ TQPtrList<KAction> m_actions;
+ /**
+ * Parent bookmark for this menu.
+ */
+ TQString m_parentAddress;
+
+ // TODO make non static!
+ static TQString s_highlightedAddress;
+ static TQString s_highlightedImportLocation;
+ static TQString s_highlightedImportType;
+};
+
+/**
+ * A class connected to KNSBookmarkImporter, to fill KActionMenus.
+ */
+class TDEIO_EXPORT KBookmarkMenuNSImporter : public TQObject
+{
+ Q_OBJECT
+public:
+ KBookmarkMenuNSImporter( KBookmarkManager* mgr, KBookmarkMenu * menu, KActionCollection * act ) :
+ m_menu(menu), m_actionCollection(act), m_pManager(mgr) {}
+
+ void openNSBookmarks();
+ void openBookmarks( const TQString &location, const TQString &type );
+ void connectToImporter( const TQObject &importer );
+
+protected slots:
+ void newBookmark( const TQString & text, const TQCString & url, const TQString & );
+ void newFolder( const TQString & text, bool, const TQString & );
+ void newSeparator();
+ void endFolder();
+
+protected:
+ TQPtrStack<KBookmarkMenu> mstack;
+ KBookmarkMenu * m_menu;
+ KActionCollection * m_actionCollection;
+ KBookmarkManager* m_pManager;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarkmenu_p.h b/tdeio/bookmarks/kbookmarkmenu_p.h
new file mode 100644
index 000000000..cb88607fe
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarkmenu_p.h
@@ -0,0 +1,224 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 2003 Alexander Kellett <lypanov@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 __kbookmarkmenu_p_h__
+#define __kbookmarkmenu_p_h__
+
+#include <sys/types.h>
+
+#include <tqptrlist.h>
+#include <tqptrstack.h>
+#include <tqobject.h>
+#include <tqlistview.h>
+
+#include <kdialogbase.h>
+#include <klocale.h>
+#include <kaction.h>
+
+#include "kbookmark.h"
+#include "kbookmarkimporter.h"
+#include "kbookmarkmanager.h"
+
+class TQString;
+class TQPopupMenu;
+class TQPushButton;
+class TQListView;
+class KLineEdit;
+class KBookmark;
+class KBookmarkGroup;
+class KAction;
+class KActionMenu;
+class KActionCollection;
+class KBookmarkOwner;
+class KBookmarkMenu;
+class KBookmarkBar;
+class KPopupMenu;
+
+class KImportedBookmarksActionMenu : public KActionMenu {
+ Q_OBJECT
+ TQ_PROPERTY( TQString type READ type WRITE setType )
+ TQ_PROPERTY( TQString location READ location WRITE setLocation )
+public:
+ const TQString type() const { return m_type; }
+ void setType(const TQString &type) { m_type = type; }
+ const TQString location() const { return m_location; }
+ void setLocation(const TQString &location) { m_location = location; }
+private:
+ TQString m_type;
+ TQString m_location;
+public:
+ KImportedBookmarksActionMenu(
+ const TQString &text, const TQString& sIconName,
+ KActionCollection* parent, const char* name)
+ : KActionMenu(text, sIconName, parent, name) {
+ ;
+ }
+};
+
+class KBookmarkActionMenu : public KActionMenu {
+ Q_OBJECT
+ TQ_PROPERTY( TQString url READ url WRITE setUrl )
+ TQ_PROPERTY( TQString address READ address WRITE setAddress )
+ TQ_PROPERTY( bool readOnly READ readOnly WRITE setReadOnly )
+public:
+ const TQString url() const { return m_url; }
+ void setUrl(const TQString &url) { m_url = url; }
+ const TQString address() const { return m_address; }
+ void setAddress(const TQString &address) { m_address = address; }
+ bool readOnly() const { return m_readOnly; }
+ void setReadOnly(bool readOnly) { m_readOnly = readOnly; }
+private:
+ TQString m_url;
+ TQString m_address;
+ bool m_readOnly;
+public:
+ KBookmarkActionMenu(
+ const TQString &text, const TQString& sIconName,
+ KActionCollection* parent, const char* name)
+ : KActionMenu(text, sIconName, parent, name) {
+ ;
+ }
+};
+
+class KBookmarkAction : public KAction {
+ Q_OBJECT
+ TQ_PROPERTY( TQString url READ url WRITE setUrl )
+ TQ_PROPERTY( TQString address READ address WRITE setAddress )
+public:
+ const TQString url() const { return m_url; }
+ void setUrl(const TQString &url) { m_url = url; }
+ const TQString address() const { return m_address; }
+ void setAddress(const TQString &address) { m_address = address; }
+private:
+ TQString m_url;
+ TQString m_address;
+public:
+ // KDE4: remove
+ KBookmarkAction(
+ const TQString& text, const TQString& sIconName, const KShortcut& cut,
+ const TQObject* receiver, const char* slot,
+ KActionCollection* parent, const char* name)
+ : KAction(text, sIconName, cut, receiver, slot, parent, name) {
+ }
+ KBookmarkAction(
+ const TQString& text, const TQString& sIconName, const KShortcut& cut,
+ KActionCollection* parent, const char* name)
+ : KAction(text, sIconName, cut, parent, name) {
+ }
+};
+
+class KBookmarkEditFields {
+public:
+ typedef enum { FolderFieldsSet, BookmarkFieldsSet } FieldsSet;
+ KLineEdit * m_url;
+ KLineEdit * m_title;
+ KBookmarkEditFields(TQWidget *main, TQBoxLayout *vbox, FieldsSet isFolder);
+ void setName(const TQString &str);
+ void setLocation(const TQString &str);
+};
+
+class KBookmarkEditDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ typedef enum { ModifyMode, InsertionMode } BookmarkEditType;
+
+ KBookmarkEditDialog( const TQString& title, const TQString& url, KBookmarkManager *, BookmarkEditType editType, const TQString& address = TQString::null,
+ TQWidget * = 0, const char * = 0, const TQString& caption = i18n( "Add Bookmark" ) );
+
+ TQString finalUrl() const;
+ TQString finalTitle() const;
+ TQString finalAddress() const;
+
+protected slots:
+ void slotOk();
+ void slotCancel();
+ void slotUser1();
+ void slotDoubleClicked(TQListViewItem* item);
+
+private:
+ TQWidget * m_main;
+ KBookmarkEditFields * m_fields;
+ TQListView * m_folderTree;
+ TQPushButton * m_button;
+ KBookmarkManager * m_mgr;
+ BookmarkEditType m_editType;
+ TQString m_address;
+};
+
+class KBookmarkFolderTreeItem : public TQListViewItem
+{
+ // make this an accessor
+ friend class KBookmarkFolderTree;
+public:
+ KBookmarkFolderTreeItem( TQListView *, const KBookmark & );
+ KBookmarkFolderTreeItem( KBookmarkFolderTreeItem *, TQListViewItem *, const KBookmarkGroup & );
+private:
+ KBookmark m_bookmark;
+};
+
+class KBookmarkFolderTree
+{
+public:
+ static TQListView* createTree( KBookmarkManager *, TQWidget * = 0, const char * = 0, const TQString& = TQString::null );
+ static void fillTree( TQListView*, KBookmarkManager *, const TQString& = TQString::null );
+ static TQString selectedAddress( TQListView* );
+ static void setAddress( TQListView *, const TQString & );
+};
+
+class KBookmarkSettings
+{
+public:
+ bool m_advancedaddbookmark;
+ bool m_contextmenu;
+ bool m_quickactions;
+ bool m_filteredtoolbar;
+ static KBookmarkSettings *s_self;
+ static void readSettings();
+ static KBookmarkSettings *self();
+};
+
+class RMB
+{
+public:
+ static void begin_rmb_action(KBookmarkMenu *);
+ static void begin_rmb_action(KBookmarkBar *);
+ bool invalid( int val );
+ KBookmark atAddress(const TQString & address);
+ void fillContextMenu( TQPopupMenu* contextMenu, const TQString & address, int val );
+ void fillContextMenu2( TQPopupMenu* contextMenu, const TQString & address, int val );
+ void slotRMBActionEditAt( int val );
+ void slotRMBActionProperties( int val );
+ void slotRMBActionInsert( int val );
+ void slotRMBActionRemove( int val );
+ void slotRMBActionCopyLocation( int val );
+ void hidePopup();
+public:
+ TQObject *recv;
+ KBookmarkManager *m_pManager;
+ TQString s_highlightedAddress;
+ TQString m_parentAddress;
+ KBookmarkOwner *m_pOwner;
+ TQWidget *m_parentMenu;
+};
+
+#endif
diff --git a/tdeio/bookmarks/kbookmarknotifier.h b/tdeio/bookmarks/kbookmarknotifier.h
new file mode 100644
index 000000000..f99e570bc
--- /dev/null
+++ b/tdeio/bookmarks/kbookmarknotifier.h
@@ -0,0 +1,45 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE libraries
+ Copyright (C) 2001, 2003 Alexander Kellett <lypanov@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 __kbookmarknotifier_h__
+#define __kbookmarknotifier_h__
+
+#include <dcopobject.h>
+
+/**
+ * DCOP interface for a bookmark notifier (an object which emits signals
+ * upon changes to the bookmarks)
+ */
+class TDEIO_EXPORT KBookmarkNotifier : virtual public DCOPObject
+{
+ K_DCOP
+
+public:
+ KBookmarkNotifier(TQCString objId = "KBookmarkNotifier") : DCOPObject(objId) {}
+
+k_dcop_signals:
+ void addedBookmark( TQString filename, TQString url, TQString text, TQString address, TQString icon );
+ void createdNewFolder( TQString filename, TQString text, TQString address );
+ void updatedAccessMetadata( TQString filename, TQString url );
+};
+
+#endif
+
diff --git a/tdeio/data.protocol b/tdeio/data.protocol
new file mode 100644
index 000000000..1982efe80
--- /dev/null
+++ b/tdeio/data.protocol
@@ -0,0 +1,71 @@
+[Protocol]
+protocol=data
+input=stream
+output=none
+reading=true
+Icon=www
+Class=:internet
+Description=A tdeioslave for data URIs (rfc2397)
+Description[af]= ´n tdeioslave vir data URIs (rfc2397)
+Description[be]=Модуль tdeioslave Ð´Ð»Ñ URI з даннÑмі (rfc2397)
+Description[br]=Ur tdeioslave evit an URIoù roadoù (rfc2397)
+Description[bs]=Kioslave za data URIs (rfc2397)
+Description[ca]=Un tdeioslave per a URIs de dades (rfc2397)
+Description[cs]=Kioslave pro datová URI (rfc2397)
+Description[csb]=Plugins protokółu pòdôwków URI (rfc2397)
+Description[da]=En tdeioslave for data-URI'er (rfc2397)
+Description[de]=Ein-/Ausgabemodul für Daten-URIs (rfc2397)
+Description[el]=Ένα tdeioslave για URI δεδομένων (rfc2397)
+Description[es]=Un tdeioslave para datos URIs (rfc2397)
+Description[et]=Andme-URI-de I/O-moodul (rfc2397)
+Description[eu]=Datuen URLen (rfc2397) tdeioslave-a
+Description[fa]=یک tdeioslave برای URIهای داده )rfc2397(
+Description[fi]=tdeioslave data URI:lle (rfc2397)
+Description[fr]=Un module d'entrée / sortie pour les URI de données (rfc2397)
+Description[fy]=In tdeioslave foar data-URI-adresse (rfc2397)
+Description[gl]=Un tdeioslave para URIs de dados (rfc2397)
+Description[hi]=डाटा यूआरआई (आरà¤à¤«à¤¸à¥€2397) के लिठà¤à¤• के-आई-ओ-सà¥à¤²à¥‡à¤µ
+Description[hr]=tdeioslave za podatkovne URI-ije (rfc2397)
+Description[hu]=KDE-protokoll adat-URI-k használataához (RFC 2397)
+Description[id]=Kioslave for URI data (rfc2397)
+Description[is]=tdeioslave fyrir gagnaslóðir (rfc2397)
+Description[it]=Un tdeioslave per il protocollo di URI di dati (rfc2397)
+Description[ja]=データ URIs (rfc2397) 㮠tdeioslave
+Description[ka]=URI მáƒáƒœáƒáƒªáƒ”მთრ(rfc2397) დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბელი
+Description[kk]=URI деректерді өңдеу tdeioslave модулі (rfc2397)
+Description[km]=tdeioslave មួយ​សម្រាប់​ទិន្ននáŸáž™ URIs (rfc2397)
+Description[lb]=E tdeioslave fir Donnéen-URIs (rfc2397)
+Description[lt]=Antrinė KDE programa duomenų URI (rfc2397)
+Description[mk]=kio-Ñлужител за податочни URI (rfc2397)
+Description[ms]=Kioslave untuk URI data (rfc2397)
+Description[nb]=tdeioslave for data URI-er (rfc2397)
+Description[nds]=In-/Utgaavmoduul för Daten-URIs (rfc2397)
+Description[ne]=डेटा URIs का लागि किओसà¥à¤²à¥‡à¤­ (rfc2397)
+Description[nl]=Een tdeioslave voor data-URI-adressen (rfc2397)
+Description[nn]=A tdeioslave for data URI-ar (rfc2397)
+Description[pa]= ਡਾਟਾ URI ਲਈ tdeioslave(rfc2397)
+Description[pl]=Wtyczka protokołu URI danych (rfc2397)
+Description[pt]=Um 'tdeioslave' para URIs data (rfc2397)
+Description[pt_BR]=Uma implementação para o protocolo de URIs de dados (rfc2397)
+Description[ro]=Un dispozitiv de I/E pentru URI-urile de date (rfc2397)
+Description[ru]=Обработчик URI данных (rfc2397)
+Description[rw]=Kioslave y'ibyatanzwe URI (rfc2397)
+Description[se]=kiošláva dáhta-URI:aid várás (rfc2397)
+Description[sk]=IO klient pre dátové URI (rfc2397)
+Description[sl]=tdeioslave za podatkovne URI-je (rfc2397)
+Description[sr]=tdeioslave за URI-ије података (rfc2397)
+Description[sr@Latn]=tdeioslave za URI-ije podataka (rfc2397)
+Description[sv]=En I/O-slav för datawebbadresser (RFC 2397)
+Description[ta]=தரவ௠வலைமனைகளà¯à®•à¯à®•à®¾à®© ஒர௠tdeioslave (rfc2397)
+Description[te]=దతà±à°¤à°¾à°‚శం à°¯à±à°†à°°à±ˆà°² కొరకౠకెà°à°“బానిస (rfc2397)
+Description[tg]=tdeioslave барои URIs (rfc2397)
+Description[th]=tdeioslave สำหรับข้อมูล URIs (rfc2397)
+Description[tr]= Veri adresleri için bir tdeioslave (rfc2397)
+Description[tt]=Biremle URI öçen tdeioslave (rfc2397)
+Description[uk]=Підлеглий Ð’/Ð’ Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑ (URI) даних (rfc2397)
+Description[vi]=Một tdeioslave cho các địa điểm URI kiểu dữ liệu (rfc2397).
+Description[zh_CN]=data URI(rfc2397) çš„ tdeioslave
+DocPath=tdeioslave/data.html
+URIMode=rawuri
+defaultMimetype=application/octet-stream
+determineMimetypeFromExtension=false
diff --git a/tdeio/httpfilter/CMakeLists.txt b/tdeio/httpfilter/CMakeLists.txt
new file mode 100644
index 000000000..b40f10fdc
--- /dev/null
+++ b/tdeio/httpfilter/CMakeLists.txt
@@ -0,0 +1,32 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeio
+)
+
+
+##### httpfilter ################################
+
+set( target httpfilter )
+
+set( ${target}_SRCS
+ httpfilter.cc
+)
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+)
diff --git a/tdeio/httpfilter/Makefile.am b/tdeio/httpfilter/Makefile.am
new file mode 100644
index 000000000..2da25d1b6
--- /dev/null
+++ b/tdeio/httpfilter/Makefile.am
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = $(all_includes)
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libhttpfilter.la
+libhttpfilter_la_SOURCES = httpfilter.cc
+libhttpfilter_la_LIBADD = $(LIBZ)
+libhttpfilter_la_LDFLAGS = $(all_libraries)
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/httpfilter/httpfilter.cc b/tdeio/httpfilter/httpfilter.cc
new file mode 100644
index 000000000..21086d613
--- /dev/null
+++ b/tdeio/httpfilter/httpfilter.cc
@@ -0,0 +1,372 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2002 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 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 <tdeio/global.h>
+
+#include <klocale.h>
+
+#include "httpfilter.h"
+
+HTTPFilterBase::HTTPFilterBase()
+ : last(0)
+{
+}
+
+HTTPFilterBase::~HTTPFilterBase()
+{
+ delete last;
+}
+
+void
+HTTPFilterBase::chain(HTTPFilterBase *previous)
+{
+ last = previous;
+ connect(last, TQT_SIGNAL(output(const TQByteArray &)),
+ this, TQT_SLOT(slotInput(const TQByteArray &)));
+}
+
+HTTPFilterChain::HTTPFilterChain()
+ : first(0)
+{
+}
+
+void
+HTTPFilterChain::addFilter(HTTPFilterBase *filter)
+{
+ if (!last)
+ {
+ first = filter;
+ }
+ else
+ {
+ disconnect(last, TQT_SIGNAL(output(const TQByteArray &)), 0, 0);
+ filter->chain(last);
+ }
+ last = filter;
+ connect(filter, TQT_SIGNAL(output(const TQByteArray &)),
+ this, TQT_SIGNAL(output(const TQByteArray &)));
+ connect(filter, TQT_SIGNAL(error(int, const TQString &)),
+ this, TQT_SIGNAL(error(int, const TQString &)));
+}
+
+void
+HTTPFilterChain::slotInput(const TQByteArray &d)
+{
+ if (first)
+ first->slotInput(d);
+ else
+ emit output(d);
+}
+
+HTTPFilterMD5::HTTPFilterMD5()
+{
+}
+
+TQString
+HTTPFilterMD5::md5()
+{
+ return TQString::fromLatin1(context.base64Digest());
+}
+
+void
+HTTPFilterMD5::slotInput(const TQByteArray &d)
+{
+ context.update(d);
+ emit output(d);
+}
+
+
+HTTPFilterGZip::HTTPFilterGZip()
+{
+#ifdef DO_GZIP
+ bHasHeader = false;
+ bHasFinished = false;
+ bPlainText = false;
+ bEatTrailer = false;
+ bEof = false;
+ zstr.next_in = (Bytef *) Z_NULL;
+ zstr.avail_in = 0;
+ zstr.zalloc = Z_NULL;
+ zstr.zfree = Z_NULL;
+ zstr.opaque = Z_NULL;
+
+ inflateInit2(&zstr, -MAX_WBITS);
+
+ iTrailer = 8;
+#endif
+}
+
+HTTPFilterGZip::~HTTPFilterGZip()
+{
+#ifdef DO_GZIP
+ inflateEnd(&zstr);
+#endif
+
+}
+
+/* The get_byte() and checkHeader() functions are modified version from */
+/* the correpsonding functions that can be found in zlib, the following */
+/* copyright notice applies to these functions: */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.3, July 9th, 1998
+
+ Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+int
+HTTPFilterGZip::get_byte()
+{
+#ifdef DO_GZIP
+ if (bEof) return EOF;
+ if (zstr.avail_in == 0)
+ {
+ bEof = true;
+ return EOF;
+ }
+ zstr.avail_in--;
+ zstr.total_in++;
+ return *(zstr.next_in)++;
+#else
+ return 0;
+#endif
+}
+
+#ifdef DO_GZIP
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* 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 */
+#endif
+
+// 0 : ok
+// 1 : not gzip
+// 2 : no header
+int
+HTTPFilterGZip::checkHeader()
+{
+#ifdef DO_GZIP
+ uInt len;
+ int c;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte();
+ if (c != gz_magic[len]) {
+ if (len != 0)
+ {
+ zstr.avail_in++;
+ zstr.next_in--;
+ }
+ if (c != EOF) {
+ zstr.avail_in++;
+ zstr.next_in--;
+ return 1;
+ }
+ return 2;
+ }
+ }
+
+ int method = get_byte(); /* method byte */
+ int flags = get_byte(); /* flags byte */
+
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ return bEof ? 2 : 1;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte();
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte();
+ len += ((uInt)get_byte())<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte() != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte()) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte()) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte();
+ }
+
+ return bEof ? 2 : 0;
+#else
+ return 0;
+#endif
+}
+
+void
+HTTPFilterGZip::slotInput(const TQByteArray &d)
+{
+#ifdef DO_GZIP
+ if (bPlainText)
+ {
+ emit output(d);
+ return;
+ }
+ if (d.size() == 0)
+ {
+ if (bEatTrailer)
+ bHasFinished = true;
+ if (!bHasFinished)
+ {
+ // Make sure we get the last bytes still in the pipe.
+ // Needed with "deflate".
+ TQByteArray flush(4);
+ flush.fill(0);
+ slotInput(flush);
+ if (!bHasFinished && !bHasHeader)
+ {
+ // Send as-is
+ emit output(headerData);
+ bHasFinished = true;
+ // End of data
+ emit output(TQByteArray());
+ }
+ }
+ if (!bHasFinished)
+ emit error( TDEIO::ERR_SLAVE_DEFINED, i18n("Unexpected end of data, some information may be lost."));
+ return;
+ }
+ if (bHasFinished)
+ return;
+
+ if (bEatTrailer)
+ {
+ iTrailer -= d.size();
+ if (iTrailer <= 0)
+ {
+ bHasFinished = true;
+ // End of data
+ emit output(TQByteArray());
+ }
+ return;
+ }
+
+ if (!bHasHeader)
+ {
+ bEof = false;
+
+ // Add data to header.
+ int orig_size = headerData.size();
+ headerData.resize(orig_size+d.size());
+ memcpy(headerData.data()+orig_size, d.data(), d.size());
+
+ zstr.avail_in = headerData.size();
+ zstr.next_in = (Bytef *) headerData.data();
+
+ int result = checkHeader();
+ if (result == 1)
+ {
+ bPlainText = true;
+ output(headerData);
+ return;
+ }
+
+ if (result != 0)
+ return; // next time better
+
+ bHasHeader = true;
+ }
+ else
+ {
+ zstr.avail_in = d.size();
+ zstr.next_in = (Bytef *) d.data();
+ }
+
+ while( zstr.avail_in )
+ {
+ char buf[8192];
+ zstr.next_out = (Bytef *) buf;
+ zstr.avail_out = 8192;
+ int result = inflate( &zstr, Z_NO_FLUSH );
+ if ((result != Z_OK) && (result != Z_STREAM_END))
+ {
+ emit error( TDEIO::ERR_SLAVE_DEFINED, i18n("Receiving corrupt data."));
+ break;
+ }
+ int bytesOut = 8192 - zstr.avail_out;
+ if (bytesOut)
+ {
+ TQByteArray d;
+ d.setRawData( buf, bytesOut );
+ emit output(d);
+ d.resetRawData( buf, bytesOut );
+ }
+ if (result == Z_STREAM_END)
+ {
+ if (iTrailer)
+ {
+ bEatTrailer = true;
+ }
+ else
+ {
+ bHasFinished = true;
+ // End of data
+ emit output(TQByteArray());
+ }
+ return;
+ }
+ }
+#endif
+}
+
+HTTPFilterDeflate::HTTPFilterDeflate()
+{
+#ifdef DO_GZIP
+ bHasHeader = true;
+ iTrailer = 0;
+#endif
+}
+
+#include "httpfilter.moc"
diff --git a/tdeio/httpfilter/httpfilter.h b/tdeio/httpfilter/httpfilter.h
new file mode 100644
index 000000000..520a1c627
--- /dev/null
+++ b/tdeio/httpfilter/httpfilter.h
@@ -0,0 +1,119 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2002 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 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 _HTTPFILTER_H_
+#define _HTTPFILTER_H_
+
+#include <config.h>
+
+#ifdef HAVE_LIBZ
+#define DO_GZIP
+#endif
+
+#ifdef DO_GZIP
+#include <zlib.h>
+#endif
+
+#include <tqobject.h>
+#include <kmdcodec.h>
+
+class HTTPFilterBase : public TQObject
+{
+ Q_OBJECT
+public:
+ HTTPFilterBase();
+ ~HTTPFilterBase();
+
+ void chain(HTTPFilterBase *previous);
+
+public slots:
+ virtual void slotInput(const TQByteArray &d) = 0;
+
+signals:
+ void output(const TQByteArray &d);
+ void error(int, const TQString &);
+
+protected:
+ HTTPFilterBase *last;
+};
+
+class HTTPFilterChain : public HTTPFilterBase
+{
+ Q_OBJECT
+public:
+ HTTPFilterChain();
+
+ void addFilter(HTTPFilterBase *filter);
+
+public slots:
+ void slotInput(const TQByteArray &d);
+
+private:
+ HTTPFilterBase *first;
+};
+
+class HTTPFilterMD5 : public HTTPFilterBase
+{
+ Q_OBJECT
+public:
+ HTTPFilterMD5();
+
+ TQString md5();
+
+public slots:
+ void slotInput(const TQByteArray &d);
+
+private:
+ KMD5 context;
+};
+
+
+class HTTPFilterGZip : public HTTPFilterBase
+{
+ Q_OBJECT
+public:
+ HTTPFilterGZip();
+ ~HTTPFilterGZip();
+
+public slots:
+ void slotInput(const TQByteArray &d);
+
+protected:
+ int get_byte();
+ int checkHeader();
+#ifdef DO_GZIP
+ z_stream zstr;
+ bool bEof : 1;
+ bool bHasHeader : 1;
+ bool bHasFinished : 1;
+ bool bPlainText : 1;
+ bool bEatTrailer : 1;
+ TQByteArray headerData;
+ int iTrailer;
+#endif
+};
+
+class HTTPFilterDeflate : public HTTPFilterGZip
+{
+ Q_OBJECT
+public:
+ HTTPFilterDeflate();
+};
+
+#endif
diff --git a/tdeio/kcomprfilter.desktop b/tdeio/kcomprfilter.desktop
new file mode 100644
index 000000000..017bf987d
--- /dev/null
+++ b/tdeio/kcomprfilter.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=TDECompressionFilter
+Name=TDE Compression Filter
+Name[af]=TDE Kompakteer Filter
+Name[az]=TDE Sıxışdırma Filtri
+Name[bg]=КомпреÑиращ филтър
+Name[bn]=কে.ডি.ই. সংকোচন ফিলà§à¦Ÿà¦¾à¦°
+Name[bs]=TDE filter za kompresovanje
+Name[ca]=Filtre de compressió per al TDE
+Name[cs]=Kompresní filtr TDE
+Name[csb]=Filter kòmpresëji TDE
+Name[cy]=Hidl Cywasgiad TDE
+Name[da]=TDE Komprimeringsfilter
+Name[de]=TDE-Komprimierungsfilter
+Name[el]=ΦίλτÏο συμπίεσης του TDE
+Name[eo]=TDE-kunpremo-filtrilo
+Name[es]=Filtro de compresión de TDE
+Name[et]=TDE pakkimise filter
+Name[eu]=TDEren konpresio-iragazkia
+Name[fa]=پالایۀ Ùشرده‌سازی TDE
+Name[fi]=TDE:n pakkaussuodin
+Name[fr]=Filtre de compression de TDE
+Name[fy]=TDE kompresjefilter
+Name[ga]=Scagaire Comhbhrúite TDE
+Name[gl]=Filtro de Compresón de TDE
+Name[he]=מסנן הדחיסה של TDE
+Name[hi]=केडीई कंपà¥à¤°à¥‡à¤¶à¤¨ फ़िलà¥à¤Ÿà¤°
+Name[hr]=TDE filtr kompresije
+Name[hu]=TDE tömörítésszűrő
+Name[id]=Filter Kompresi TDE
+Name[is]=TDE þjöppunarsía
+Name[it]=Filtro di compressione TDE
+Name[ja]=TDE 圧縮フィルタ
+Name[ka]=TDE-ს შეკუმშვის ფილტრი
+Name[kk]=TDE Ñығу ÑүзгіÑÑ–
+Name[km]=ážáž˜áŸ’រង​បង្ហាប់ TDE
+Name[ko]=TDE 압축 거르개
+Name[lb]=TDE-Kompressiounsfilter
+Name[lt]=TDE suspaudimo filtras
+Name[lv]=TDE Kompresijas FIltrs
+Name[mk]=TDE филтер за компреÑија
+Name[mn]=TDE-шахагчийн шүүлтүүр
+Name[ms]=Penapis Pemadatan TDE
+Name[mt]=Filtru tal-kompressjoni TDE
+Name[nb]=Komprimeringsfilter for TDE
+Name[nds]=TDE-Komprimerenfilter
+Name[ne]=TDE सङà¥à¤–à¥à¤šà¤¨ फिलà¥à¤Ÿà¤°
+Name[nl]=TDE Compressiefilter
+Name[nn]=TDE Kompresjonsfilter
+Name[nso]=Sesekodi sa Pitleletso ya TDE
+Name[pa]=TDE ਨਪੀੜਨ ਫਿਲਟਰ
+Name[pl]=Filtr kompresji TDE
+Name[pt]=Filtro de Compressão do TDE
+Name[pt_BR]=Filtro de compressão do TDE
+Name[ro]=Filtru de compresie TDE
+Name[ru]=Фильтр ÑÐ¶Ð°Ñ‚Ð¸Ñ TDE
+Name[rw]=Muyunguruzi y'Iyegeranya TDE
+Name[se]=TDE Äoahkkáibáhkkenfilter
+Name[sk]=TDE filter pre kompresiu
+Name[sl]=Filter za stiskanje s TDE
+Name[sq]=Filter për Ngjeshje - TDE
+Name[sr]=TDE-ов компреÑиони филтер
+Name[sr@Latn]=TDE-ov kompresioni filter
+Name[ss]=Sisefo seminyenalisa se TDE
+Name[sv]=TDE-kompressionsfilter
+Name[ta]=கேடிஇ à®…à®´à¯à®¤à¯à®¤ வடிகடà¯à®Ÿà®¿
+Name[te]=కెడిఈ సంకà±à°·à°¿à°ªà±à°¤à°ªà°°à°¿à°šà±† గలని
+Name[tg]=TDE Газполои Фушурдашуда
+Name[th]=ตัวà¸à¸£à¸­à¸‡à¸à¸²à¸£à¸šà¸µà¸šà¸­à¸±à¸”ของ TDE
+Name[tr]=TDE Sıkıştırma Filtresi
+Name[tt]=TDE'nıñ Qısu Sözgeçe
+Name[uk]=Фільтр ÑтиÑÐºÐ°Ð½Ð½Ñ TDE
+Name[uz]=TDE qisish filteri
+Name[uz@cyrillic]=TDE қиÑиш филтери
+Name[ven]=Filithara yau tsikeledza ya TDE
+Name[vi]=Bá»™ lá»c nén TDE
+Name[xh]=Isihluzi Sodibaniso se TDE
+Name[zh_CN]=TDE 压缩过滤程åº
+Name[zh_HK]=TDE 壓縮éŽæ¿¾å™¨
+Name[zh_TW]=TDE 壓縮éŽæ¿¾å™¨
+Name[zu]=Ihluzo Lokunciphisa le-TDE
diff --git a/tdeio/kdatatool.desktop b/tdeio/kdatatool.desktop
new file mode 100644
index 000000000..a58357d41
--- /dev/null
+++ b/tdeio/kdatatool.desktop
@@ -0,0 +1,96 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=KDataTool
+Comment=TDE Data Tool
+Comment[af]=TDE Data Program
+Comment[ar]=أداة كيدي للبيانات
+Comment[az]=TDE Verilənlər Vasitəsi
+Comment[be]=ІнÑтрумент працы з даннÑмі TDE
+Comment[bn]=কে.ডি.ই তথà§à¦¯ টà§à¦²
+Comment[br]=Ostilh roadoù evit TDE
+Comment[bs]=TDE alat za podatke
+Comment[ca]=Eina per a la gestió de dades per al TDE
+Comment[cs]=Datový nástroj TDE
+Comment[csb]=Nôrzãdze pòdôwków TDE
+Comment[cy]=Erfyn Data TDE
+Comment[da]=TDE-dataværktøj
+Comment[de]=TDE-Datenprogramm
+Comment[el]=ΕÏγαλείο δεδομένων του TDE
+Comment[eo]=Datumilo
+Comment[es]=Herramienta TDE de datos
+Comment[et]=TDE andmete rakendus
+Comment[eu]=TDEren datuen tresna
+Comment[fa]=ابزار دادۀ TDE
+Comment[fi]=TDE:n datatyökalu
+Comment[fr]=Outil de données TDE
+Comment[fy]=TDE data-helpprogramma
+Comment[ga]=Uirlis Sonraí TDE
+Comment[gl]=Ferramenta de Dados de TDE
+Comment[he]=כלי × ×ª×•× ×™× ×©×œ TDE
+Comment[hi]=केडीई डाटा टूल
+Comment[hr]=TDE alat za podatke
+Comment[hu]=TDE adatkezelő segédprogram
+Comment[id]=Tool Data TDE
+Comment[is]=TDE gagnatól
+Comment[it]=Strumenti dati di TDE
+Comment[ja]=TDE データツール
+Comment[ka]=TDE-ს მáƒáƒœáƒáƒªáƒ”მების დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბელი
+Comment[kk]=TDE дерек өңдеу құралы
+Comment[km]=ឧបករណáŸâ€‹áž‘ិន្ននáŸáž™ TDE
+Comment[ko]=TDE ìžë£Œ 연장
+Comment[lb]=TDE-Donnéen-Hëllefsprogramm
+Comment[lt]=TDE duomenų priemonė
+Comment[lv]=TDE Datu RÄ«ks
+Comment[mk]=TDE податочна алатка
+Comment[mn]=TDE-Өгөгдөл боловÑруулах программ
+Comment[ms]=Alatan Data TDE
+Comment[mt]=Għodda għal data TDE
+Comment[nb]=TDE Dataverktøy
+Comment[nds]=TDE-Datenwarktüüch
+Comment[ne]=TDE डेटा उपकरण
+Comment[nl]=TDE Data-hulpprogramma
+Comment[nn]=TDE Dataverktøy
+Comment[nso]=Sebereka sa Data ya TDE
+Comment[pa]=TDE ਡਾਟਾ ਸੰਦ
+Comment[pl]=Narzędzie danych TDE
+Comment[pt]=Ferramenta de Dados do TDE
+Comment[pt_BR]=Ferramenta de Dados do TDE
+Comment[ro]=Utilitar de date TDE
+Comment[ru]=Утилита обработки информации TDE
+Comment[rw]=Igikoresho cy'Ibyatanzwe TDE
+Comment[se]=TDE dáhtareaidu
+Comment[sk]=Dátový nástroj TDE
+Comment[sl]=Podatkovno orodje za TDE
+Comment[sq]=Vegla për të Dhëna - TDE
+Comment[sr]=TDE-ов алат за податке
+Comment[sr@Latn]=TDE-ov alat za podatke
+Comment[ss]=Lithulusi lemniningwane lengakahlutwa ye TDE
+Comment[sv]=TDE-dataverktyg
+Comment[ta]=கேடிஇ தகவல௠கரà¯à®µà®¿
+Comment[te]=కెడిఈ దతà±à°¤à°¾à°‚శం పనిమà±à°Ÿà±à°Ÿà±
+Comment[tg]=TDE ÐÑбоби Сана
+Comment[th]=เครื่องมือข้อมูลของ TDE
+Comment[tr]=TDE Veri Aracı
+Comment[tt]=TDE'nıñ Eşkärtü Qoralı
+Comment[uk]=ЗаÑіб роботи з даними TDE
+Comment[uz]=TDE maʼlumot vositasi
+Comment[uz@cyrillic]=TDE маълумот воÑитаÑи
+Comment[ven]=Tshishumiswa tsha data tsha TDE
+Comment[vi]=Công cụ dữ liệu TDE.
+Comment[xh]=Isihluzi se Data ye TDE
+Comment[zh_CN]=TDE æ•°æ®å·¥å…·
+Comment[zh_HK]=TDE 資料工具
+Comment[zh_TW]=TDE 資料工具
+Comment[zu]=Ithuluzi Ledata le-TDE
+
+[PropertyDef::Commands]
+Type=TQStringList
+
+[PropertyDef::DataType]
+Type=TQString
+
+[PropertyDef::DataMimeTypes]
+Type=TQStringList
+
+[PropertyDef::ExcludeFrom]
+Type=TQStringList
diff --git a/tdeio/kpasswdserver.desktop b/tdeio/kpasswdserver.desktop
new file mode 100644
index 000000000..db43d621c
--- /dev/null
+++ b/tdeio/kpasswdserver.desktop
@@ -0,0 +1,157 @@
+[Desktop Entry]
+Type=Service
+Name=KDED Password Module
+Name[af]=KDED Wagwoord Module
+Name[ar]=وحدة كلمة سر KDED
+Name[az]=KDED ÅžifrÉ™ Modulu
+Name[be]=Модуль Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑÑž KDED
+Name[bg]=Модул за пароли KDED
+Name[bn]=KDED পাসওয়ারà§à¦¡ মডিউল
+Name[br]=Mollad tremenger KDED
+Name[bs]=KDED Å¡ifra modul
+Name[ca]=Mòdul de contrasenya KDED
+Name[cs]=KDED modul pro hesla
+Name[csb]=Parole
+Name[cy]=Modiwl Cyfrinair KDED
+Name[da]=KDED-kodeordsmodul
+Name[de]=Passwort-Zwischenspeicherung
+Name[el]=ΆÏθÏωμα ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης του KDED
+Name[eo]=KDED-pasvortmodulo
+Name[es]=Módulo de contraseña de KDED
+Name[et]=KDED parooli moodul
+Name[eu]=KDEDren pasahitz-modulua
+Name[fa]=پیمانۀ اسم رمز KDED
+Name[fi]=KDED-salasanamoduuli
+Name[fr]=Module de mot de passe KDED
+Name[fy]=KDED-wachtwurdmodule
+Name[ga]=Modúl Fhocail Fhaire KDED
+Name[gl]=Módulo de Contrasinais de KDED
+Name[he]=מודול סיסמה של KDED
+Name[hi]=KDED पासवरà¥à¤¡ घटक (मॉडà¥à¤¯à¥‚ल)
+Name[hr]=KDED modul za lozinke
+Name[hu]=KDED jelszómodul
+Name[id]=Modul Password KDED
+Name[is]=KDED Lykilorðaeining
+Name[it]=Modulo password di KDED
+Name[ja]=KDED パスワードモジュール
+Name[ka]=KDED პáƒáƒ áƒáƒšáƒ”ბის მáƒáƒ“ული
+Name[kk]=KDED пароль модулі
+Name[km]=ម៉ូឌុល​ពាក្យ​សម្ងាážáŸ‹ KDED
+Name[ko]=KDED 열쇠글 모듈
+Name[lb]=KDED-Passwuertmodul
+Name[lt]=KDED slaptažodžių modulis
+Name[lv]=KDED paroļu modulis
+Name[mk]=KDED модул за лозинка
+Name[mn]=KDED-ТеÑÑ‚ модул
+Name[ms]=Modul Kata laluan KDED
+Name[mt]=Modulu tal-passwords KDED
+Name[nb]=KDED Passordmodul
+Name[nds]=KDED-Passwoortmoduul
+Name[ne]=KDED पासवरà¥à¤¡ मोडà¥à¤¯à¥à¤²
+Name[nl]=KDED-wachtwoordmodule
+Name[nn]=KDED-passordmodul
+Name[nso]=Seripa sa Lentsuphetiso la KDED
+Name[pa]=KDED ਗà©à¨ªà¨¤-ਕੋਡ ਮੈਡੀਊਲ
+Name[pl]=Hasła
+Name[pt]=Módulo de Senhas do KDED
+Name[pt_BR]=Módulo de Senha do KDED
+Name[ro]=Modul parolă KDED
+Name[ru]=Служба паролей
+Name[rw]=Igice cy'Ijambobanga KDED
+Name[se]=KDED beassansátni-moduvla
+Name[sk]=Modul hesla KDED
+Name[sl]=Geselni modul KDED
+Name[sq]=Modula për Parullë(Password) - KDED
+Name[sr]=KDED модул за лозинке
+Name[sr@Latn]=KDED modul za lozinke
+Name[sv]=KDED-lösenordsmodul
+Name[ta]=KDED கடவà¯à®šà¯à®šà¯Šà®²à¯ பகà¯à®¤à®¿
+Name[te]=కెడిఈ పాసౠవరà±à°¡à± మాడà±à°¯à±‚à°²à±
+Name[tg]=KDED Модули номи шаб
+Name[th]=โมดูลรหัสผ่าน KDED
+Name[tr]=KDED Parola Modülü
+Name[tt]=KDED'nıñ Sersüz Modulı
+Name[uk]=Модуль паролів KDED
+Name[uz]=KDED maxfiy soʻz moduli
+Name[uz@cyrillic]=KDED махфий Ñўз модули
+Name[ven]=Modulu wa phasewede ya KDED
+Name[vi]=Mô-đun mật khẩu KDED
+Name[wa]=Module di screts po KDED
+Name[xh]=Igama lokugqitha le Sicatshulwa se KDED
+Name[zh_CN]=KDED 密ç æ¨¡å—
+Name[zh_HK]=KDED 密碼模組
+Name[zh_TW]=KDED 密碼模組
+Name[zu]=Ingxenye Yegama lokudlula le-KDED
+Comment=Password caching support
+Comment[af]=Wagwoord kasberging ondersteuning
+Comment[be]=Падтрымка Ð·Ð°Ñ…Ð¾ÑžÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑÑž
+Comment[bg]=Кеширане на пароли
+Comment[bn]=পাসওয়ারà§à¦¡ কà§à¦¯à¦¾à¦¶-ঠরাখা সমরà§à¦¥à¦¨ করে
+Comment[bs]=Podrška za keširanje šifre
+Comment[ca]=Permet l'ús de memòria cau de contrasenyes
+Comment[cs]=Podpora pro kešování hesel
+Comment[csb]=Spamiãtôwanié môlowëch parolów
+Comment[da]=Understøttelse for caching af kodeord
+Comment[de]=Verwaltet zwischengespeicherte Passwörter in KDED
+Comment[el]=ΥποστήÏιξη Ï€ÏοσωÏινής αποθήκευσης ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης
+Comment[eo]=Subteno por kaÅmemorigo de pasvortoj
+Comment[es]=Soporte de caché de contraseñas
+Comment[et]=Parooli meelespidamise toetus
+Comment[eu]=Pasahitzen cachearen euskarria
+Comment[fa]=پشتیبانی از مخÙÛŒ کردن اسم رمز
+Comment[fi]=Salasanojen välimuistituki
+Comment[fr]=Gestion du cache des mots de passe
+Comment[fy]=Wachtwurd caching stype
+Comment[gl]=Soporte de cacheado de contrasinais
+Comment[he]=תמיכה בשמירת ססמ×ות במטמון
+Comment[hi]=पासवरà¥à¤¡ कैचिंग समरà¥à¤¥à¤¨
+Comment[hr]=Podrška međuspremanja lozinki
+Comment[hu]=Jelszóelmentési támogatás
+Comment[id]=Dukungan penyimpanan password
+Comment[is]=Skyndiminni fyrir lykilorð
+Comment[it]=Supporto per la memorizzazione temporanea delle password
+Comment[ja]=パスワードキャッシュサãƒãƒ¼ãƒˆ
+Comment[ka]=პáƒáƒ áƒáƒšáƒ˜áƒ¡ ბუფერირებáƒ
+Comment[kk]=KDED парольдерді баÑқару
+Comment[km]=ទ្រទ្រង់​ការ​រក្សាទុក​ពាក្យសម្ងាážáŸ‹â€‹áž“ៅ​ក្នុង​ឃ្លាំង​សម្ងាážáŸ‹
+Comment[lb]=Ënnerstëtzung fir d'Zwëschespäichere vu Passwierder
+Comment[lt]=Slaptažodžių krepšio palaikymas
+Comment[mk]=Поддршка за кеширање на лозинки
+Comment[ms]=Sokongan Penyimpan Kata Laluan
+Comment[nb]=Støtte for passordlagring
+Comment[nds]=Ünnerstütten för't Twischenspiekern vun Passwöör
+Comment[ne]=पासवरà¥à¤¡ कà¥à¤¯à¤¾à¤¸à¤¿à¤™ समरà¥à¤¥à¤¨
+Comment[nl]=Ondersteuning voor het tussentijds bewaren van wachtwoorden
+Comment[nn]=Støtte for passordlagring
+Comment[pa]=ਗà©à¨ªà¨¤-ਕੋਡ ਕੈਚੇਇੰਗ ਸਹਾਇਤਾ
+Comment[pl]=Zapamiętywanie haseł lokalnych
+Comment[pt]=Suporte a 'cache' de senhas
+Comment[pt_BR]=Suporte de cache das senhas
+Comment[ro]=Suport pentru memorarea parolelor
+Comment[ru]=Управление паролÑми KDED
+Comment[rw]=Ifasha ry'uguhisha ijambobanga
+Comment[se]=Beassansáni gaskarádjama doarjja
+Comment[sk]=Podpora ukladania hesiel
+Comment[sl]=Podpora prepomnjenju gesel
+Comment[sr]=Подршка за кеширање лозинки
+Comment[sr@Latn]=Podrška za keširanje lozinki
+Comment[sv]=Stöd för lösenordscache
+Comment[ta]=கடவà¯à®šà¯à®šà¯Šà®²à¯ சேமிகà¯à®• ஆதரவà¯
+Comment[te]=పాసౠవరà±à°¡à±à°²à°¨à± దాయà±à°Ÿà°•à± సహకరించà±à°¨à±
+Comment[tg]=ДаÑтгирии Ҳофизаи Гузарвожа
+Comment[th]=สนับสนุนà¸à¸²à¸£à¸ˆà¸”จำรหัสผ่าน
+Comment[tr]=Parola önbellekleme desteği
+Comment[tt]=Sersüz alxäterläw totu
+Comment[uk]=Підтримка ÐºÐµÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²
+Comment[uz]=Maxfiy soʻzlarni keshda saqlash
+Comment[uz@cyrillic]=Махфий Ñўзларни кÑшда Ñақлаш
+Comment[vi]=Cách hỗ trợ khả năng lưu tạm mật khẩu.
+Comment[zh_CN]=密ç ç¼“存支æŒ
+Comment[zh_HK]=密碼暫存支æ´
+Comment[zh_TW]=密碼暫存(cache)支æ´
+ServiceTypes=KDEDModule
+X-TDE-ModuleType=Library
+X-TDE-Library=kpasswdserver
+X-TDE-FactoryName=kpasswdserver
+X-TDE-Kded-autoload=false
+X-TDE-Kded-load-on-demand=true
diff --git a/tdeio/kpasswdserver/CMakeLists.txt b/tdeio/kpasswdserver/CMakeLists.txt
new file mode 100644
index 000000000..1d54ddc95
--- /dev/null
+++ b/tdeio/kpasswdserver/CMakeLists.txt
@@ -0,0 +1,43 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdewallet/client
+ ${CMAKE_SOURCE_DIR}/tdeio
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+#### kded_kpasswdserver ##############################
+
+set( target kded_kpasswdserver )
+
+set( ${target}_SRCS
+ kpasswdserver.cpp kpasswdserver.skel
+)
+
+tde_add_kpart( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeinit_kded-shared
+ DEPENDENCIES dcopidl
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/tdeio/kpasswdserver/DESIGN b/tdeio/kpasswdserver/DESIGN
new file mode 100644
index 000000000..6a128f9df
--- /dev/null
+++ b/tdeio/kpasswdserver/DESIGN
@@ -0,0 +1,56 @@
+Sequence numbers
+================
+The idea is that whenever the user is queried for a password this
+login/pw combination gets a seq-nr. When a slave needs a login/pw
+it asks kpasswdserver and sends along the last seqnr it received. If
+this seqnr is older (lower) than the seq nr of the login/pw
+combination stored in kpasswdserver then appearantly the user has
+already been prompted for a new login/pw combination since the last
+time this slave asked for a login/pw and therefor it is not necessary
+to prompt the user again but kpassword will send the io-slave this
+new login/pw combination. If this new combination fails as well the
+user is being prompted for a new login/pw combo since the one stored
+in kpasswdserver doesn't work.
+
+Let me try to draw the situation I had in mind when writing this:
+
+Slave1 Slave2 kpasswdserver
+Asks for auth
+ asks user for login/pw (1)
+sends login/pw (1) to ftp site
+ Asks for auth
+ sends back login/pw (1)
+ sends login/pw (1) to ftp site
+gets login error,
+asks for new auth
+sends along seq.nr 1
+ seq.nr 1 == (1) -->
+ asks user for new login/pw (2)
+sends login/pw (2) to ftp site
+ gets login error,
+ asks for new auth
+ sends along seq.nr 1
+ seq.nr 1 < (2) -->
+ don't ask user for new login/pw
+ but send back login/pw (2) without asking
+ sends login/pw (2) to ftp site
+
+
+Actually, I had mostly http in mind, and not so much ftp. In http you
+typically try without password first, and only when you get an
+authentication error you ask for a password. The above scenario is
+then suddenly a lot more common than with ftp because it can happen
+that you have 4 requests /io-slaves who alll discover at about the
+same time that they need to have authentication credentials. The
+above scenario (and the seq. nrs) is to prevent that you get 4 login
+dialogs in such case.
+
+Now the assumption in this all, looking back on it, seems to be that
+when you ask for the same auth credentials twice in a row, it must be
+that the credentials issued the first time where wrong, and you will
+be prompted again. But if the user goes to ftp-site1, then
+ftp-site2 and then back to ftp-site1 again, the credentials for ftp-site1
+are still valid. This is why we reset the seq.nr stored in the io-slave
+to 0 whenever the io-slave switches hosts (or logins).
+
+Waldo Bastian <bastian@kde.org>
diff --git a/tdeio/kpasswdserver/Makefile.am b/tdeio/kpasswdserver/Makefile.am
new file mode 100644
index 000000000..d1a58059b
--- /dev/null
+++ b/tdeio/kpasswdserver/Makefile.am
@@ -0,0 +1,15 @@
+# $Id$
+# Makefile.am of tdebase/tdeioslave/http
+
+INCLUDES= -I$(top_srcdir)/tdewallet/client $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = kded_kpasswdserver.la
+
+kded_kpasswdserver_la_SOURCES = kpasswdserver.cpp kpasswdserver.skel
+kded_kpasswdserver_la_METASOURCES = AUTO
+kded_kpasswdserver_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_kpasswdserver_la_LIBADD = $(top_builddir)/tdewallet/client/libtdewalletclient.la $(LIB_KIO) $(LIB_KDED) $(LIB_QT) $(LIB_TDEUI) $(LIB_TDECORE) $(top_builddir)/dcop/libDCOP.la $(LIB_X11)
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/kpasswdserver/kpasswdserver.cpp b/tdeio/kpasswdserver/kpasswdserver.cpp
new file mode 100644
index 000000000..ff7295181
--- /dev/null
+++ b/tdeio/kpasswdserver/kpasswdserver.cpp
@@ -0,0 +1,715 @@
+/*
+ This file is part of the KDE Password Server
+
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 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 General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//----------------------------------------------------------------------------
+//
+// KDE Password Server
+// $Id$
+
+#include "kpasswdserver.h"
+
+#include <time.h>
+
+#include <tqtimer.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <tdeio/passdlg.h>
+#include <tdewallet.h>
+
+#include "config.h"
+#ifdef Q_WS_X11
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#endif
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_kpasswdserver(const TQCString &name)
+ {
+ return new KPasswdServer(name);
+ }
+}
+
+int
+KPasswdServer::AuthInfoList::compareItems(TQPtrCollection::Item n1, TQPtrCollection::Item n2)
+{
+ if (!n1 || !n2)
+ return 0;
+
+ AuthInfo *i1 = (AuthInfo *) n1;
+ AuthInfo *i2 = (AuthInfo *) n2;
+
+ int l1 = i1->directory.length();
+ int l2 = i2->directory.length();
+
+ if (l1 > l2)
+ return -1;
+ if (l1 < l2)
+ return 1;
+ return 0;
+}
+
+
+KPasswdServer::KPasswdServer(const TQCString &name)
+ : KDEDModule(name)
+{
+ m_authDict.setAutoDelete(true);
+ m_authPending.setAutoDelete(true);
+ m_seqNr = 0;
+ m_wallet = 0;
+ connect(this, TQT_SIGNAL(windowUnregistered(long)),
+ this, TQT_SLOT(removeAuthForWindowId(long)));
+}
+
+KPasswdServer::~KPasswdServer()
+{
+ delete m_wallet;
+}
+
+// Helper - returns the wallet key to use for read/store/checking for existence.
+static TQString makeWalletKey( const TQString& key, const TQString& realm )
+{
+ return realm.isEmpty() ? key : key + '-' + realm;
+}
+
+// Helper for storeInWallet/readFromWallet
+static TQString makeMapKey( const char* key, int entryNumber )
+{
+ TQString str = TQString::fromLatin1( key );
+ if ( entryNumber > 1 )
+ str += "-" + TQString::number( entryNumber );
+ return str;
+}
+
+static bool storeInWallet( KWallet::Wallet* wallet, const TQString& key, const TDEIO::AuthInfo &info )
+{
+ if ( !wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
+ if ( !wallet->createFolder( KWallet::Wallet::PasswordFolder() ) )
+ return false;
+ wallet->setFolder( KWallet::Wallet::PasswordFolder() );
+ // Before saving, check if there's already an entry with this login.
+ // If so, replace it (with the new password). Otherwise, add a new entry.
+ typedef TQMap<TQString,TQString> Map;
+ int entryNumber = 1;
+ Map map;
+ TQString walletKey = makeWalletKey( key, info.realmValue );
+ kdDebug(130) << "storeInWallet: walletKey=" << walletKey << " reading existing map" << endl;
+ if ( wallet->readMap( walletKey, map ) == 0 ) {
+ Map::ConstIterator end = map.end();
+ Map::ConstIterator it = map.find( "login" );
+ while ( it != end ) {
+ if ( it.data() == info.username ) {
+ break; // OK, overwrite this entry
+ }
+ it = map.find( TQString( "login-" ) + TQString::number( ++entryNumber ) );
+ }
+ // If no entry was found, create a new entry - entryNumber is set already.
+ }
+ const TQString loginKey = makeMapKey( "login", entryNumber );
+ const TQString passwordKey = makeMapKey( "password", entryNumber );
+ kdDebug(130) << "storeInWallet: writing to " << loginKey << "," << passwordKey << endl;
+ // note the overwrite=true by default
+ map.insert( loginKey, info.username );
+ map.insert( passwordKey, info.password );
+ wallet->writeMap( walletKey, map );
+ return true;
+}
+
+
+static bool readFromWallet( KWallet::Wallet* wallet, const TQString& key, const TQString& realm, TQString& username, TQString& password, bool userReadOnly, TQMap<TQString,TQString>& knownLogins )
+{
+ //kdDebug(130) << "readFromWallet: key=" << key << " username=" << username << " password=" /*<< password*/ << " userReadOnly=" << userReadOnly << " realm=" << realm << endl;
+ if ( wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
+ {
+ wallet->setFolder( KWallet::Wallet::PasswordFolder() );
+
+ TQMap<TQString,TQString> map;
+ if ( wallet->readMap( makeWalletKey( key, realm ), map ) == 0 )
+ {
+ typedef TQMap<TQString,TQString> Map;
+ int entryNumber = 1;
+ Map::ConstIterator end = map.end();
+ Map::ConstIterator it = map.find( "login" );
+ while ( it != end ) {
+ //kdDebug(130) << "readFromWallet: found " << it.key() << "=" << it.data() << endl;
+ Map::ConstIterator pwdIter = map.find( makeMapKey( "password", entryNumber ) );
+ if ( pwdIter != end ) {
+ if ( it.data() == username )
+ password = pwdIter.data();
+ knownLogins.insert( it.data(), pwdIter.data() );
+ }
+
+ it = map.find( TQString( "login-" ) + TQString::number( ++entryNumber ) );
+ }
+ //kdDebug(130) << knownLogins.count() << " known logins" << endl;
+
+ if ( !userReadOnly && !knownLogins.isEmpty() && username.isEmpty() ) {
+ // Pick one, any one...
+ username = knownLogins.begin().key();
+ password = knownLogins.begin().data();
+ //kdDebug(130) << "readFromWallet: picked the first one : " << username << endl;
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+TDEIO::AuthInfo
+KPasswdServer::checkAuthInfo(TDEIO::AuthInfo info, long windowId)
+{
+ return checkAuthInfo(info, windowId, 0);
+}
+
+TDEIO::AuthInfo
+KPasswdServer::checkAuthInfo(TDEIO::AuthInfo info, long windowId, unsigned long usertime)
+{
+ kdDebug(130) << "KPasswdServer::checkAuthInfo: User= " << info.username
+ << ", WindowId = " << windowId << endl;
+ if( usertime != 0 )
+ kapp->updateUserTimestamp( usertime );
+
+ TQString key = createCacheKey(info);
+
+ Request *request = m_authPending.first();
+ TQString path2 = info.url.directory(false, false);
+ for(; request; request = m_authPending.next())
+ {
+ if (request->key != key)
+ continue;
+
+ if (info.verifyPath)
+ {
+ TQString path1 = request->info.url.directory(false, false);
+ if (!path2.startsWith(path1))
+ continue;
+ }
+
+ request = new Request;
+ request->client = callingDcopClient();
+ request->transaction = request->client->beginTransaction();
+ request->key = key;
+ request->info = info;
+ m_authWait.append(request);
+ return info;
+ }
+
+ const AuthInfo *result = findAuthInfoItem(key, info);
+ if (!result || result->isCanceled)
+ {
+ if (!result &&
+ (info.username.isEmpty() || info.password.isEmpty()) &&
+ !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
+ KWallet::Wallet::PasswordFolder(), makeWalletKey(key, info.realmValue)))
+ {
+ TQMap<TQString, TQString> knownLogins;
+ if (openWallet(windowId)) {
+ if (readFromWallet(m_wallet, key, info.realmValue, info.username, info.password,
+ info.readOnly, knownLogins))
+ {
+ info.setModified(true);
+ return info;
+ }
+ }
+ }
+
+ info.setModified(false);
+ return info;
+ }
+
+ updateAuthExpire(key, result, windowId, false);
+
+ return copyAuthInfo(result);
+}
+
+TDEIO::AuthInfo
+KPasswdServer::queryAuthInfo(TDEIO::AuthInfo info, TQString errorMsg, long windowId, long seqNr)
+{
+ return queryAuthInfo(info, errorMsg, windowId, seqNr, 0 );
+}
+
+TDEIO::AuthInfo
+KPasswdServer::queryAuthInfo(TDEIO::AuthInfo info, TQString errorMsg, long windowId, long seqNr, unsigned long usertime)
+{
+ kdDebug(130) << "KPasswdServer::queryAuthInfo: User= " << info.username
+ << ", Message= " << info.prompt << ", WindowId = " << windowId << endl;
+ if ( !info.password.isEmpty() ) // should we really allow the caller to pre-fill the password?
+ kdDebug(130) << "password was set by caller" << endl;
+ if( usertime != 0 )
+ kapp->updateUserTimestamp( usertime );
+
+ TQString key = createCacheKey(info);
+ Request *request = new Request;
+ request->client = callingDcopClient();
+ request->transaction = request->client->beginTransaction();
+ request->key = key;
+ request->info = info;
+ request->windowId = windowId;
+ request->seqNr = seqNr;
+ if (errorMsg == "<NoAuthPrompt>")
+ {
+ request->errorMsg = TQString::null;
+ request->prompt = false;
+ }
+ else
+ {
+ request->errorMsg = errorMsg;
+ request->prompt = true;
+ }
+ m_authPending.append(request);
+
+ if (m_authPending.count() == 1)
+ TQTimer::singleShot(0, this, TQT_SLOT(processRequest()));
+
+ return info;
+}
+
+void
+KPasswdServer::addAuthInfo(TDEIO::AuthInfo info, long windowId)
+{
+ kdDebug(130) << "KPasswdServer::addAuthInfo: User= " << info.username
+ << ", RealmValue= " << info.realmValue << ", WindowId = " << windowId << endl;
+ TQString key = createCacheKey(info);
+
+ m_seqNr++;
+
+ addAuthInfoItem(key, info, windowId, m_seqNr, false);
+}
+
+bool
+KPasswdServer::openWallet( WId windowId )
+{
+ if ( m_wallet && !m_wallet->isOpen() ) { // forced closed
+ delete m_wallet;
+ m_wallet = 0;
+ }
+ if ( !m_wallet )
+ m_wallet = KWallet::Wallet::openWallet(
+ KWallet::Wallet::NetworkWallet(), windowId );
+ return m_wallet != 0;
+}
+
+void
+KPasswdServer::processRequest()
+{
+ Request *request = m_authPending.first();
+ if (!request)
+ return;
+
+ TDEIO::AuthInfo &info = request->info;
+
+ kdDebug(130) << "KPasswdServer::processRequest: User= " << info.username
+ << ", Message= " << info.prompt << endl;
+ const AuthInfo *result = findAuthInfoItem(request->key, request->info);
+
+ if (result && (request->seqNr < result->seqNr))
+ {
+ kdDebug(130) << "KPasswdServer::processRequest: auto retry!" << endl;
+ if (result->isCanceled)
+ {
+ info.setModified(false);
+ }
+ else
+ {
+ updateAuthExpire(request->key, result, request->windowId, false);
+ info = copyAuthInfo(result);
+ }
+ }
+ else
+ {
+ m_seqNr++;
+ bool askPw = request->prompt;
+ if (result && !info.username.isEmpty() &&
+ !request->errorMsg.isEmpty())
+ {
+ TQString prompt = request->errorMsg;
+ prompt += i18n(" Do you want to retry?");
+ int dlgResult = KMessageBox::warningContinueCancelWId(request->windowId, prompt,
+ i18n("Authentication"), i18n("Retry"));
+ if (dlgResult != KMessageBox::Continue)
+ askPw = false;
+ }
+
+ int dlgResult = TQDialog::Rejected;
+ if (askPw)
+ {
+ TQString username = info.username;
+ TQString password = info.password;
+ bool hasWalletData = false;
+ TQMap<TQString, TQString> knownLogins;
+
+ if ( ( username.isEmpty() || password.isEmpty() )
+ && !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), makeWalletKey( request->key, info.realmValue )) )
+ {
+ // no login+pass provided, check if tdewallet has one
+ if ( openWallet( request->windowId ) )
+ hasWalletData = readFromWallet( m_wallet, request->key, info.realmValue, username, password, info.readOnly, knownLogins );
+ }
+
+ TDEIO::PasswordDialog dlg( info.prompt, username, info.keepPassword );
+ if (info.caption.isEmpty())
+ dlg.setPlainCaption( i18n("Authorization Dialog") );
+ else
+ dlg.setPlainCaption( info.caption );
+
+ if ( !info.comment.isEmpty() )
+ dlg.addCommentLine( info.commentLabel, info.comment );
+
+ if ( !password.isEmpty() )
+ dlg.setPassword( password );
+
+ if (info.readOnly)
+ dlg.setUserReadOnly( true );
+ else
+ dlg.setKnownLogins( knownLogins );
+
+ if (hasWalletData)
+ dlg.setKeepPassword( true );
+
+#ifdef Q_WS_X11
+ XSetTransientForHint( tqt_xdisplay(), dlg.winId(), request->windowId);
+#endif
+
+ dlgResult = dlg.exec();
+
+ if (dlgResult == TQDialog::Accepted)
+ {
+ info.username = dlg.username();
+ info.password = dlg.password();
+ info.keepPassword = dlg.keepPassword();
+
+ // When the user checks "keep password", that means:
+ // * if the wallet is enabled, store it there for long-term, and in kpasswdserver
+ // only for the duration of the window (#92928)
+ // * otherwise store in kpasswdserver for the duration of the KDE session.
+ if ( info.keepPassword ) {
+ if ( openWallet( request->windowId ) ) {
+ if ( storeInWallet( m_wallet, request->key, info ) )
+ // password is in wallet, don't keep it in memory after window is closed
+ info.keepPassword = false;
+ }
+ }
+ }
+ }
+ if ( dlgResult != TQDialog::Accepted )
+ {
+ addAuthInfoItem(request->key, info, 0, m_seqNr, true);
+ info.setModified( false );
+ }
+ else
+ {
+ addAuthInfoItem(request->key, info, request->windowId, m_seqNr, false);
+ info.setModified( true );
+ }
+ }
+
+ TQCString replyType;
+ TQByteArray replyData;
+
+ TQDataStream stream2(replyData, IO_WriteOnly);
+ stream2 << info << m_seqNr;
+ replyType = "TDEIO::AuthInfo";
+ request->client->endTransaction( request->transaction,
+ replyType, replyData);
+
+ m_authPending.remove((unsigned int) 0);
+
+ // Check all requests in the wait queue.
+ for(Request *waitRequest = m_authWait.first();
+ waitRequest; )
+ {
+ bool keepQueued = false;
+ TQString key = waitRequest->key;
+
+ request = m_authPending.first();
+ TQString path2 = waitRequest->info.url.directory(false, false);
+ for(; request; request = m_authPending.next())
+ {
+ if (request->key != key)
+ continue;
+
+ if (info.verifyPath)
+ {
+ TQString path1 = request->info.url.directory(false, false);
+ if (!path2.startsWith(path1))
+ continue;
+ }
+
+ keepQueued = true;
+ break;
+ }
+ if (keepQueued)
+ {
+ waitRequest = m_authWait.next();
+ }
+ else
+ {
+ const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
+
+ TQCString replyType;
+ TQByteArray replyData;
+
+ TQDataStream stream2(replyData, IO_WriteOnly);
+
+ if (!result || result->isCanceled)
+ {
+ waitRequest->info.setModified(false);
+ stream2 << waitRequest->info;
+ }
+ else
+ {
+ updateAuthExpire(waitRequest->key, result, waitRequest->windowId, false);
+ TDEIO::AuthInfo info = copyAuthInfo(result);
+ stream2 << info;
+ }
+
+ replyType = "TDEIO::AuthInfo";
+ waitRequest->client->endTransaction( waitRequest->transaction,
+ replyType, replyData);
+
+ m_authWait.remove();
+ waitRequest = m_authWait.current();
+ }
+ }
+
+ if (m_authPending.count())
+ TQTimer::singleShot(0, this, TQT_SLOT(processRequest()));
+
+}
+
+TQString KPasswdServer::createCacheKey( const TDEIO::AuthInfo &info )
+{
+ if( !info.url.isValid() ) {
+ // Note that a null key will break findAuthInfoItem later on...
+ kdWarning(130) << "createCacheKey: invalid URL " << info.url << endl;
+ return TQString::null;
+ }
+
+ // Generate the basic key sequence.
+ TQString key = info.url.protocol();
+ key += '-';
+ if (!info.url.user().isEmpty())
+ {
+ key += info.url.user();
+ key += "@";
+ }
+ key += info.url.host();
+ int port = info.url.port();
+ if( port )
+ {
+ key += ':';
+ key += TQString::number(port);
+ }
+
+ return key;
+}
+
+TDEIO::AuthInfo
+KPasswdServer::copyAuthInfo(const AuthInfo *i)
+{
+ TDEIO::AuthInfo result;
+ result.url = i->url;
+ result.username = i->username;
+ result.password = i->password;
+ result.realmValue = i->realmValue;
+ result.digestInfo = i->digestInfo;
+ result.setModified(true);
+
+ return result;
+}
+
+const KPasswdServer::AuthInfo *
+KPasswdServer::findAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info)
+{
+ AuthInfoList *authList = m_authDict.find(key);
+ if (!authList)
+ return 0;
+
+ TQString path2 = info.url.directory(false, false);
+ for(AuthInfo *current = authList->first();
+ current; )
+ {
+ if ((current->expire == AuthInfo::expTime) &&
+ (difftime(time(0), current->expireTime) > 0))
+ {
+ authList->remove();
+ current = authList->current();
+ continue;
+ }
+
+ if (info.verifyPath)
+ {
+ TQString path1 = current->directory;
+ if (path2.startsWith(path1) &&
+ (info.username.isEmpty() || info.username == current->username))
+ return current;
+ }
+ else
+ {
+ if (current->realmValue == info.realmValue &&
+ (info.username.isEmpty() || info.username == current->username))
+ return current; // TODO: Update directory info,
+ }
+
+ current = authList->next();
+ }
+ return 0;
+}
+
+void
+KPasswdServer::removeAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info)
+{
+ AuthInfoList *authList = m_authDict.find(key);
+ if (!authList)
+ return;
+
+ for(AuthInfo *current = authList->first();
+ current; )
+ {
+ if (current->realmValue == info.realmValue)
+ {
+ authList->remove();
+ current = authList->current();
+ }
+ else
+ {
+ current = authList->next();
+ }
+ }
+ if (authList->isEmpty())
+ {
+ m_authDict.remove(key);
+ }
+}
+
+
+void
+KPasswdServer::addAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
+{
+ AuthInfoList *authList = m_authDict.find(key);
+ if (!authList)
+ {
+ authList = new AuthInfoList;
+ m_authDict.insert(key, authList);
+ }
+ AuthInfo *current = authList->first();
+ for(; current; current = authList->next())
+ {
+ if (current->realmValue == info.realmValue)
+ {
+ authList->take();
+ break;
+ }
+ }
+
+ if (!current)
+ {
+ current = new AuthInfo;
+ current->expire = AuthInfo::expTime;
+ kdDebug(130) << "Creating AuthInfo" << endl;
+ }
+ else
+ {
+ kdDebug(130) << "Updating AuthInfo" << endl;
+ }
+
+ current->url = info.url;
+ current->directory = info.url.directory(false, false);
+ current->username = info.username;
+ current->password = info.password;
+ current->realmValue = info.realmValue;
+ current->digestInfo = info.digestInfo;
+ current->seqNr = seqNr;
+ current->isCanceled = canceled;
+
+ updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
+
+ // Insert into list, keep the list sorted "longest path" first.
+ authList->inSort(current);
+}
+
+void
+KPasswdServer::updateAuthExpire(const TQString &key, const AuthInfo *auth, long windowId, bool keep)
+{
+ AuthInfo *current = const_cast<AuthInfo *>(auth);
+ if (keep)
+ {
+ current->expire = AuthInfo::expNever;
+ }
+ else if (windowId && (current->expire != AuthInfo::expNever))
+ {
+ current->expire = AuthInfo::expWindowClose;
+ if (!current->windowList.contains(windowId))
+ current->windowList.append(windowId);
+ }
+ else if (current->expire == AuthInfo::expTime)
+ {
+ current->expireTime = time(0)+10;
+ }
+
+ // Update mWindowIdList
+ if (windowId)
+ {
+ TQStringList *keysChanged = mWindowIdList.find(windowId);
+ if (!keysChanged)
+ {
+ keysChanged = new TQStringList;
+ mWindowIdList.insert(windowId, keysChanged);
+ }
+ if (!keysChanged->contains(key))
+ keysChanged->append(key);
+ }
+}
+
+void
+KPasswdServer::removeAuthForWindowId(long windowId)
+{
+ TQStringList *keysChanged = mWindowIdList.find(windowId);
+ if (!keysChanged) return;
+
+ for(TQStringList::ConstIterator it = keysChanged->begin();
+ it != keysChanged->end(); ++it)
+ {
+ TQString key = *it;
+ AuthInfoList *authList = m_authDict.find(key);
+ if (!authList)
+ continue;
+
+ AuthInfo *current = authList->first();
+ for(; current; )
+ {
+ if (current->expire == AuthInfo::expWindowClose)
+ {
+ if (current->windowList.remove(windowId) && current->windowList.isEmpty())
+ {
+ authList->remove();
+ current = authList->current();
+ continue;
+ }
+ }
+ current = authList->next();
+ }
+ }
+}
+
+#include "kpasswdserver.moc"
diff --git a/tdeio/kpasswdserver/kpasswdserver.h b/tdeio/kpasswdserver/kpasswdserver.h
new file mode 100644
index 000000000..ce6d0386e
--- /dev/null
+++ b/tdeio/kpasswdserver/kpasswdserver.h
@@ -0,0 +1,118 @@
+/*
+ This file is part of the KDE Password Server
+
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+//----------------------------------------------------------------------------
+//
+// KDE Password Server
+// $Id$
+
+#ifndef KPASSWDSERVER_H
+#define KPASSWDSERVER_H
+
+#include <tqdict.h>
+#include <tqintdict.h>
+
+#include <dcopclient.h>
+#include <tdeio/authinfo.h>
+#include <kded/kdedmodule.h>
+
+namespace KWallet {
+ class Wallet;
+}
+
+class KPasswdServer : public KDEDModule
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ KPasswdServer(const TQCString &);
+ ~KPasswdServer();
+
+k_dcop:
+ // KDE4 merge
+ TDEIO::AuthInfo checkAuthInfo(TDEIO::AuthInfo, long, unsigned long);
+ TDEIO::AuthInfo checkAuthInfo(TDEIO::AuthInfo, long);
+ TDEIO::AuthInfo queryAuthInfo(TDEIO::AuthInfo, TQString, long, long, unsigned long);
+ TDEIO::AuthInfo queryAuthInfo(TDEIO::AuthInfo, TQString, long, long);
+ void addAuthInfo(TDEIO::AuthInfo, long);
+
+public slots:
+ void processRequest();
+ // Remove all authentication info associated with windowId
+ void removeAuthForWindowId(long windowId);
+
+protected:
+ struct AuthInfo;
+
+ TQString createCacheKey( const TDEIO::AuthInfo &info );
+ const AuthInfo *findAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info);
+ void removeAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info);
+ void addAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info, long windowId, long seqNr, bool canceled);
+ TDEIO::AuthInfo copyAuthInfo(const AuthInfo *);
+ void updateAuthExpire(const TQString &key, const AuthInfo *, long windowId, bool keep);
+ int findWalletEntry( const TQMap<TQString,TQString>& map, const TQString& username );
+ bool openWallet( WId windowId );
+
+ struct AuthInfo {
+ AuthInfo() { expire = expNever; isCanceled = false; seqNr = 0; }
+
+ KURL url;
+ TQString directory;
+ TQString username;
+ TQString password;
+ TQString realmValue;
+ TQString digestInfo;
+
+ enum { expNever, expWindowClose, expTime } expire;
+ TQValueList<long> windowList;
+ unsigned long expireTime;
+ long seqNr;
+
+ bool isCanceled;
+ };
+
+ class AuthInfoList : public TQPtrList<AuthInfo>
+ {
+ public:
+ AuthInfoList() { setAutoDelete(true); }
+ int compareItems(TQPtrCollection::Item n1, TQPtrCollection::Item n2);
+ };
+
+ TQDict< AuthInfoList > m_authDict;
+
+ struct Request {
+ DCOPClient *client;
+ DCOPClientTransaction *transaction;
+ TQString key;
+ TDEIO::AuthInfo info;
+ TQString errorMsg;
+ long windowId;
+ long seqNr;
+ bool prompt;
+ };
+
+ TQPtrList< Request > m_authPending;
+ TQPtrList< Request > m_authWait;
+ TQIntDict<TQStringList> mWindowIdList;
+ DCOPClient *m_dcopClient;
+ KWallet::Wallet* m_wallet;
+ long m_seqNr;
+};
+
+#endif
diff --git a/tdeio/kscan.desktop b/tdeio/kscan.desktop
new file mode 100644
index 000000000..8d3a026fb
--- /dev/null
+++ b/tdeio/kscan.desktop
@@ -0,0 +1,19 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=KScan/KScanDialog
+Name=KScan
+Name[bn]=কে-সà§à¦•à§à¦¯à¦¾à¦¨
+Name[cy]=KSgan
+Name[eo]=Bildciferecigo
+Name[is]=KScan myndlesari
+Name[ka]=სკáƒáƒœáƒ”რი
+Name[ko]=K스캔
+Name[nso]=KTebelelo
+Name[pl]=Skan
+Name[ru]=Сканер
+Name[rw]=KGusikana
+Name[sv]=Kscan
+Name[ta]=Kவரà¯à®Ÿà®²à¯
+Name[te]=కేసà±à°•à±‡à°¨à±
+Name[th]=สà¹à¸à¸™à¸ à¸²à¸ž - K
+Name[ven]=U nanga ha K
diff --git a/tdeio/kssl/CMakeLists.txt b/tdeio/kssl/CMakeLists.txt
new file mode 100644
index 000000000..a2c9f00d6
--- /dev/null
+++ b/tdeio/kssl/CMakeLists.txt
@@ -0,0 +1,57 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( kssl )
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore/network
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdewallet/client
+)
+
+
+##### headers ###################################
+
+install( FILES
+ kssl.h ksslcertificatehome.h ksslsettings.h ksslcertificate.h
+ ksslconnectioninfo.h ksslcertificatefactory.h ksslcertificatecache.h
+ ksslpeerinfo.h ksslinfodlg.h ksslcertdlg.h ksslutils.h kopenssl.h
+ ksslall.h ksslpkcs12.h ksslcertchain.h ksslkeygen.h ksslx509v3.h
+ ksslsigners.h ksslpkcs7.h ksslpemcallback.h ksslsession.h
+ ${CMAKE_CURRENT_BINARY_DIR}/ksslconfig.h ksslx509map.h ksmimecrypto.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} )
+
+
+##### kssl ######################################
+
+set( target kssl )
+
+set( ${target}_SRCS
+ kssl.cc ksslcertificatehome.cc ksslsettings.cc
+ ksslcertificate.cc ksslconnectioninfo.cc ksslcertificatefactory.cc
+ ksslcertificatecache.cc ksslpeerinfo.cc ksslinfodlg.cc
+ ksslcertdlg.cc ksslutils.cc kopenssl.cc ksslpkcs12.cc
+ ksslcertchain.cc ksslkeygen.cc ksslx509v3.cc
+ ksslsigners.cc ksslpkcs7.cc ksslpemcallback.cc
+ ksslx509map.cc ksslsession.cc keygenwizard.ui
+ keygenwizard2.ui ksmimecrypto.cc ksslcsessioncache.cc
+)
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+)
diff --git a/tdeio/kssl/KPMG-CA-16389.0.DC80502.pdf b/tdeio/kssl/KPMG-CA-16389.0.DC80502.pdf
new file mode 100644
index 000000000..63a7633ee
--- /dev/null
+++ b/tdeio/kssl/KPMG-CA-16389.0.DC80502.pdf
Binary files differ
diff --git a/tdeio/kssl/Makefile.am b/tdeio/kssl/Makefile.am
new file mode 100644
index 000000000..5d57ab7ab
--- /dev/null
+++ b/tdeio/kssl/Makefile.am
@@ -0,0 +1,72 @@
+# don't change the order of this one. it breaks when openssl is in /usr/include
+# and the distro's KDE is there too, but the current "devel" KDE prefix is
+# somewhere else. Another option for the future (needs testing) would be to
+# change SSL_INCLUDES to .../include/openssl and make the source use #include <foo.h>
+# instead of #include <openssl/foo.h>
+INCLUDES=-I$(top_srcdir)/tdecore/network -I$(top_srcdir)/tdewallet/client $(all_includes) $(SSL_INCLUDES)
+
+noinst_LTLIBRARIES = libkssl.la
+KSSLVERSION= 3.0.0
+KSSLPATCH= 0
+METASOURCES= AUTO
+
+include_HEADERS = \
+ kssl.h \
+ ksslcertificatehome.h \
+ ksslsettings.h \
+ ksslcertificate.h \
+ ksslconnectioninfo.h \
+ ksslcertificatefactory.h \
+ ksslcertificatecache.h \
+ ksslpeerinfo.h \
+ ksslinfodlg.h \
+ ksslcertdlg.h \
+ ksslutils.h \
+ kopenssl.h \
+ ksslall.h \
+ ksslpkcs12.h \
+ ksslcertchain.h \
+ ksslkeygen.h \
+ ksslx509v3.h \
+ ksslsigners.h \
+ ksslpkcs7.h \
+ ksslpemcallback.h \
+ ksslconfig.h \
+ ksslsession.h \
+ ksslx509map.h \
+ ksmimecrypto.h
+
+noinst_HEADERS = ksslcsessioncache.h
+
+
+libkssl_la_SOURCES = \
+ kssl.cc \
+ ksslcertificatehome.cc \
+ ksslsettings.cc \
+ ksslcertificate.cc \
+ ksslconnectioninfo.cc \
+ ksslcertificatefactory.cc \
+ ksslcertificatecache.cc \
+ ksslpeerinfo.cc \
+ ksslinfodlg.cc \
+ ksslcertdlg.cc \
+ ksslutils.cc \
+ kopenssl.cc \
+ ksslpkcs12.cc \
+ ksslcertchain.cc \
+ ksslkeygen.cc \
+ ksslx509v3.cc \
+ ksslsigners.cc \
+ ksslpkcs7.cc \
+ ksslpemcallback.cc \
+ ksslx509map.cc \
+ ksslsession.cc \
+ keygenwizard.ui \
+ keygenwizard2.ui \
+ ksmimecrypto.cc \
+ ksslcsessioncache.cc
+
+
+SUBDIRS = kssl
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/kssl/README b/tdeio/kssl/README
new file mode 100644
index 000000000..b5f404fc7
--- /dev/null
+++ b/tdeio/kssl/README
@@ -0,0 +1,15 @@
+
+This library includes cryptographic software written by Eric Young
+(eay@cryptsoft.com).
+
+This set of classes is designed to make SSL easier to integrate in KDE
+applications. It currently uses OpenSSL and if it is not successfully
+compiled with OpenSSL, then it will do virtually nothing. The SSL settings
+for a user are shared across applications and managed with the kcontrol
+module "crypto". If this file is not updated by release, you can contact
+the author for development information.
+
+
+George Staikos <staikos@kde.org>
+
+
diff --git a/tdeio/kssl/SECURITY-HOLES b/tdeio/kssl/SECURITY-HOLES
new file mode 100644
index 000000000..62b8e9ca7
--- /dev/null
+++ b/tdeio/kssl/SECURITY-HOLES
@@ -0,0 +1,17 @@
+List of known security holes in KDE's SSL implementation and HTTPS support in
+Konqueror.
+-----------------------------------------------------------------------------
+
+
+1) Caching should be done on a per-host basis, not per-certificate.
+
+2) Autocompletion in form fields in HTTPS mode will result in various fields
+such as pin numbers and possibly credit cards or other sensitive information
+being silently written to disk in some cases.
+
+
+3) Certificate revocation lists (CRLs) are not implemented. This should be
+done after 2.2.
+
+
+
diff --git a/tdeio/kssl/TODO b/tdeio/kssl/TODO
new file mode 100644
index 000000000..7e2270575
--- /dev/null
+++ b/tdeio/kssl/TODO
@@ -0,0 +1,25 @@
+- KSSLServer class needs to be written (in a separate lib!!) so that an app
+ can act as an SSL server.
+
+- The certificate factory is not done. This is needed to generate personal
+ certificates (self signed) for users.
+ This should be a separate app I guess, and can include a CA signer even.
+
+- KDE4 - fix constness and reference arguments
+
+- CRL support (not much left to do?)
+
+- Code checking for OCX.
+
+- KSSLD should emit dcop signals to tell people when things change
+
+- <keygen> is not working.
+
+- Namespace it all to TDEIO::SSL:: in KDE4
+
+- Remove SSLv2
+
+- Fix ksslcalist and any code that uses subject/issuer name as provided by
+ openssl since this is broken by design. Use MD5 sum for indexing the database
+ instead
+
diff --git a/tdeio/kssl/configure.in.in b/tdeio/kssl/configure.in.in
new file mode 100644
index 000000000..7e3848d78
--- /dev/null
+++ b/tdeio/kssl/configure.in.in
@@ -0,0 +1,7 @@
+KDE_CHECK_SSL
+
+if test "$have_ssl" = yes; then
+ AC_DEFINE(KSSL_HAVE_SSL, 1, [Define if we shall use KSSL])
+fi
+
+AM_CONFIG_HEADER([tdeio/kssl/ksslconfig.h])
diff --git a/tdeio/kssl/keygenwizard.ui b/tdeio/kssl/keygenwizard.ui
new file mode 100644
index 000000000..4cb5fe1df
--- /dev/null
+++ b/tdeio/kssl/keygenwizard.ui
@@ -0,0 +1,46 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KGWizardPage1</class>
+<author>George Staikos &lt;staikos@kde.org&gt;</author>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KGWizardPage1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>345</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>You have indicated that you wish to obtain or purchase a secure certificate. This wizard is intended to guide you through the procedure. You may cancel at any time, and this will abort the transaction.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ </grid>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/tdeio/kssl/keygenwizard2.ui b/tdeio/kssl/keygenwizard2.ui
new file mode 100644
index 000000000..90fef8fef
--- /dev/null
+++ b/tdeio/kssl/keygenwizard2.ui
@@ -0,0 +1,78 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KGWizardPage2</class>
+<author>George Staikos &lt;staikos@kde.org&gt;</author>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KGWizardPage2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>343</width>
+ <height>155</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>You must now provide a password for the certificate request. Please choose a very secure password as this will be used to encrypt your private key.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Repeat password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_password2</cstring>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Choose password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_password1</cstring>
+ </property>
+ </widget>
+ <widget class="TQLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>_password1</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ <widget class="TQLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>_password2</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/tdeio/kssl/kopenssl.cc b/tdeio/kssl/kopenssl.cc
new file mode 100644
index 000000000..986609570
--- /dev/null
+++ b/tdeio/kssl/kopenssl.cc
@@ -0,0 +1,1601 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001-2003 George Staikos <staikos@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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef KSSL_HAVE_SSL
+#include <openssl/opensslv.h>
+#endif
+
+#include <kdebug.h>
+#include <tdeconfig.h>
+#include <kstaticdeleter.h>
+#include <tqregexp.h>
+#include <tqdir.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include "kopenssl.h"
+
+extern "C" {
+#ifdef KSSL_HAVE_SSL
+static int (*K_SSL_connect) (SSL *) = 0L;
+static int (*K_SSL_accept) (SSL *) = 0L;
+static int (*K_SSL_read) (SSL *, void *, int) = 0L;
+static int (*K_SSL_write) (SSL *, const void *, int) = 0L;
+static SSL *(*K_SSL_new) (SSL_CTX *) = 0L;
+static void (*K_SSL_free) (SSL *) = 0L;
+static int (*K_SSL_shutdown) (SSL *) = 0L;
+static SSL_CTX *(*K_SSL_CTX_new)(SSL_METHOD *) = 0L;
+static void (*K_SSL_CTX_free) (SSL_CTX *) = 0L;
+static int (*K_SSL_set_fd) (SSL *, int) = 0L;
+static int (*K_SSL_pending) (SSL *) = 0L;
+static int (*K_SSL_peek) (SSL *, void *, int) = 0L;
+static int (*K_SSL_CTX_set_cipher_list)(SSL_CTX *, const char *) = 0L;
+static void (*K_SSL_CTX_set_verify)(SSL_CTX *, int,
+ int (*)(int, X509_STORE_CTX *)) = 0L;
+static int (*K_SSL_use_certificate)(SSL *, X509 *) = 0L;
+static SSL_CIPHER *(*K_SSL_get_current_cipher)(SSL *) = 0L;
+static long (*K_SSL_ctrl) (SSL *,int, long, char *) = 0L;
+static int (*K_RAND_egd) (const char *) = 0L;
+static const char* (*K_RAND_file_name) (char *, size_t) = 0L;
+static int (*K_RAND_load_file) (const char *, long) = 0L;
+static int (*K_RAND_write_file) (const char *) = 0L;
+static SSL_METHOD * (*K_TLSv1_client_method) () = 0L;
+static SSL_METHOD * (*K_SSLv2_client_method) () = 0L;
+static SSL_METHOD * (*K_SSLv3_client_method) () = 0L;
+static SSL_METHOD * (*K_SSLv23_client_method) () = 0L;
+static X509 * (*K_SSL_get_peer_certificate) (SSL *) = 0L;
+static int (*K_SSL_CIPHER_get_bits) (SSL_CIPHER *,int *) = 0L;
+static char * (*K_SSL_CIPHER_get_version) (SSL_CIPHER *) = 0L;
+static const char * (*K_SSL_CIPHER_get_name) (SSL_CIPHER *) = 0L;
+static char * (*K_SSL_CIPHER_description) (SSL_CIPHER *, char *, int) = 0L;
+static X509 * (*K_d2i_X509) (X509 **,unsigned char **,long) = 0L;
+static int (*K_i2d_X509) (X509 *,unsigned char **) = 0L;
+static int (*K_X509_cmp) (X509 *, X509 *) = 0L;
+static void (*K_X509_STORE_CTX_free) (X509_STORE_CTX *) = 0L;
+static int (*K_X509_verify_cert) (X509_STORE_CTX *) = 0L;
+static X509_STORE_CTX *(*K_X509_STORE_CTX_new) (void) = 0L;
+static void (*K_X509_STORE_free) (X509_STORE *) = 0L;
+static X509_STORE *(*K_X509_STORE_new) (void) = 0L;
+static void (*K_X509_free) (X509 *) = 0L;
+static char *(*K_X509_NAME_oneline) (X509_NAME *,char *,int) = 0L;
+static X509_NAME *(*K_X509_get_subject_name) (X509 *) = 0L;
+static X509_NAME *(*K_X509_get_issuer_name) (X509 *) = 0L;
+static X509_LOOKUP *(*K_X509_STORE_add_lookup) (X509_STORE *, X509_LOOKUP_METHOD *) = 0L;
+static X509_LOOKUP_METHOD *(*K_X509_LOOKUP_file)(void) = 0L;
+static void (*K_X509_LOOKUP_free)(X509_LOOKUP *) = 0L;
+static int (*K_X509_LOOKUP_ctrl)(X509_LOOKUP *, int, const char *, long, char **) = 0L;
+static void (*K_X509_STORE_CTX_init)(X509_STORE_CTX *, X509_STORE *, X509 *, STACK_OF(X509) *) = 0L;
+static void (*K_CRYPTO_free) (void *) = 0L;
+static X509* (*K_X509_dup) (X509 *) = 0L;
+static BIO_METHOD *(*K_BIO_s_mem) (void) = 0L;
+static BIO* (*K_BIO_new) (BIO_METHOD *) = 0L;
+static BIO* (*K_BIO_new_fp) (FILE *, int) = 0L;
+static BIO* (*K_BIO_new_mem_buf) (void *, int) = 0L;
+static int (*K_BIO_free) (BIO *) = 0L;
+static long (*K_BIO_ctrl) (BIO *,int,long,void *) = 0L;
+static int (*K_BIO_write) (BIO *b, const void *data, int len) = 0L;
+static int (*K_PEM_ASN1_write_bio) (int (*)(),const char *,BIO *,char *,
+ const EVP_CIPHER *,unsigned char *,int ,
+ pem_password_cb *, void *) = 0L;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static int (*K_ASN1_item_i2d_fp)(ASN1_ITEM *,FILE *,unsigned char *) = 0L;
+static ASN1_ITEM *K_NETSCAPE_X509_it = 0L;
+#else
+static ASN1_METHOD* (*K_X509_asn1_meth) (void) = 0L;
+static int (*K_ASN1_i2d_fp)(int (*)(),FILE *,unsigned char *) = 0L;
+static int (*K_i2d_ASN1_HEADER)(ASN1_HEADER *, unsigned char **) = 0L;
+#endif
+static int (*K_X509_print_fp) (FILE *, X509*) = 0L;
+static int (*K_i2d_PKCS12) (PKCS12*, unsigned char**) = 0L;
+static int (*K_i2d_PKCS12_fp) (FILE *, PKCS12*) = 0L;
+static int (*K_PKCS12_newpass) (PKCS12*, char*, char*) = 0L;
+static PKCS12* (*K_d2i_PKCS12_fp) (FILE*, PKCS12**) = 0L;
+static PKCS12* (*K_PKCS12_new) (void) = 0L;
+static void (*K_PKCS12_free) (PKCS12 *) = 0L;
+static int (*K_PKCS12_parse) (PKCS12*, const char *, EVP_PKEY**,
+ X509**, STACK_OF(X509)**) = 0L;
+static void (*K_EVP_PKEY_free) (EVP_PKEY *) = 0L;
+static EVP_PKEY* (*K_EVP_PKEY_new) () = 0L;
+static void (*K_X509_REQ_free) (X509_REQ *) = 0L;
+static X509_REQ* (*K_X509_REQ_new) () = 0L;
+static int (*K_SSL_CTX_use_PrivateKey) (SSL_CTX*, EVP_PKEY*) = 0L;
+static int (*K_SSL_CTX_use_certificate) (SSL_CTX*, X509*) = 0L;
+static int (*K_SSL_get_error) (SSL*, int) = 0L;
+static STACK_OF(X509)* (*K_SSL_get_peer_cert_chain) (SSL*) = 0L;
+static void (*K_X509_STORE_CTX_set_chain) (X509_STORE_CTX *, STACK_OF(X509)*) = 0L;
+static void (*K_X509_STORE_CTX_set_purpose) (X509_STORE_CTX *, int) = 0L;
+static void (*K_sk_free) (STACK*) = 0L;
+static int (*K_sk_num) (STACK*) = 0L;
+static char* (*K_sk_pop) (STACK*) = 0L;
+static char* (*K_sk_value) (STACK*, int) = 0L;
+static STACK* (*K_sk_new) (int (*)()) = 0L;
+static int (*K_sk_push) (STACK*, char*) = 0L;
+static STACK* (*K_sk_dup) (STACK *) = 0L;
+static char * (*K_i2s_ASN1_INTEGER) (X509V3_EXT_METHOD *, ASN1_INTEGER *) =0L;
+static ASN1_INTEGER * (*K_X509_get_serialNumber) (X509 *) = 0L;
+static EVP_PKEY *(*K_X509_get_pubkey)(X509 *) = 0L;
+static int (*K_i2d_PublicKey)(EVP_PKEY *, unsigned char **) = 0L;
+static int (*K_X509_check_private_key)(X509 *, EVP_PKEY *) = 0L;
+static char * (*K_BN_bn2hex)(const BIGNUM *) = 0L;
+static int (*K_X509_digest)(const X509 *,const EVP_MD *, unsigned char *, unsigned int *) = 0L;
+static EVP_MD* (*K_EVP_md5)() = 0L;
+static void (*K_ASN1_INTEGER_free)(ASN1_INTEGER *) = 0L;
+static int (*K_OBJ_obj2nid)(ASN1_OBJECT *) = 0L;
+static const char * (*K_OBJ_nid2ln)(int) = 0L;
+static int (*K_X509_get_ext_count)(X509*) = 0L;
+static int (*K_X509_get_ext_by_NID)(X509*, int, int) = 0L;
+static int (*K_X509_get_ext_by_OBJ)(X509*,ASN1_OBJECT*,int) = 0L;
+static X509_EXTENSION *(*K_X509_get_ext)(X509*, int loc) = 0L;
+static X509_EXTENSION *(*K_X509_delete_ext)(X509*, int) = 0L;
+static int (*K_X509_add_ext)(X509*, X509_EXTENSION*, int) = 0L;
+static void *(*K_X509_get_ext_d2i)(X509*, int, int*, int*) = 0L;
+static char *(*K_i2s_ASN1_OCTET_STRING)(X509V3_EXT_METHOD*, ASN1_OCTET_STRING*) = 0L;
+static int (*K_ASN1_BIT_STRING_get_bit)(ASN1_BIT_STRING*, int) = 0L;
+static PKCS7 *(*K_PKCS7_new)() = 0L;
+static void (*K_PKCS7_free)(PKCS7*) = 0L;
+static void (*K_PKCS7_content_free)(PKCS7*) = 0L;
+static int (*K_i2d_PKCS7)(PKCS7*, unsigned char**) = 0L;
+static PKCS7 *(*K_d2i_PKCS7)(PKCS7**, unsigned char**,long) = 0L;
+static int (*K_i2d_PKCS7_fp)(FILE*,PKCS7*) = 0L;
+static PKCS7* (*K_d2i_PKCS7_fp)(FILE*,PKCS7**) = 0L;
+static int (*K_i2d_PKCS7_bio)(BIO *bp,PKCS7 *p7) = 0L;
+static PKCS7 *(*K_d2i_PKCS7_bio)(BIO *bp,PKCS7 **p7) = 0L;
+static PKCS7* (*K_PKCS7_dup)(PKCS7*) = 0L;
+static STACK_OF(X509_NAME) *(*K_SSL_load_client_CA_file)(const char*) = 0L;
+static STACK_OF(X509_INFO) *(*K_PEM_X509_INFO_read)(FILE*, STACK_OF(X509_INFO)*, pem_password_cb*, void*) = 0L;
+static char *(*K_ASN1_d2i_fp)(char *(*)(),char *(*)(),FILE*,unsigned char**) = 0L;
+static X509 *(*K_X509_new)() = 0L;
+static int (*K_X509_PURPOSE_get_count)() = 0L;
+static int (*K_X509_PURPOSE_get_id)(X509_PURPOSE *) = 0L;
+static int (*K_X509_check_purpose)(X509*,int,int) = 0L;
+static X509_PURPOSE* (*K_X509_PURPOSE_get0)(int) = 0L;
+static int (*K_EVP_PKEY_assign)(EVP_PKEY*, int, char*) = 0L;
+static int (*K_X509_REQ_set_pubkey)(X509_REQ*, EVP_PKEY*) = 0L;
+static RSA *(*K_RSA_generate_key)(int, unsigned long, void (*)(int,int,void *), void *) = 0L;
+static int (*K_i2d_X509_REQ_fp)(FILE*, X509_REQ*) = 0L;
+static void (*K_ERR_clear_error)() = 0L;
+static unsigned long (*K_ERR_get_error)() = 0L;
+static void (*K_ERR_print_errors_fp)(FILE*) = 0L;
+static PKCS7 *(*K_PKCS7_sign)(X509*, EVP_PKEY*, STACK_OF(X509)*, BIO*, int) = 0L;
+static int (*K_PKCS7_verify)(PKCS7*,STACK_OF(X509)*,X509_STORE*,BIO*,BIO*,int) = 0L;
+static STACK_OF(X509) *(*K_PKCS7_get0_signers)(PKCS7 *, STACK_OF(X509) *, int) = 0L;
+static PKCS7 *(*K_PKCS7_encrypt)(STACK_OF(X509) *, BIO *, EVP_CIPHER *, int) = 0L;
+static int (*K_PKCS7_decrypt)(PKCS7 *, EVP_PKEY *, X509 *, BIO *, int) = 0L;
+static SSL_SESSION* (*K_SSL_get1_session)(SSL*) = 0L;
+static void (*K_SSL_SESSION_free)(SSL_SESSION*) = 0L;
+static int (*K_SSL_set_session)(SSL*,SSL_SESSION*) = 0L;
+static SSL_SESSION* (*K_d2i_SSL_SESSION)(SSL_SESSION**,unsigned char**, long) = 0L;
+static int (*K_i2d_SSL_SESSION)(SSL_SESSION*,unsigned char**) = 0L;
+static STACK *(*K_X509_get1_email)(X509 *x) = 0L;
+static void (*K_X509_email_free)(STACK *sk) = 0L;
+static EVP_CIPHER *(*K_EVP_des_ede3_cbc)() = 0L;
+static EVP_CIPHER *(*K_EVP_des_cbc)() = 0L;
+static EVP_CIPHER *(*K_EVP_rc2_cbc)() = 0L;
+static EVP_CIPHER *(*K_EVP_rc2_64_cbc)() = 0L;
+static EVP_CIPHER *(*K_EVP_rc2_40_cbc)() = 0L;
+static int (*K_i2d_PrivateKey_fp)(FILE*,EVP_PKEY*) = 0L;
+static int (*K_i2d_PKCS8PrivateKey_fp)(FILE*, EVP_PKEY*, const EVP_CIPHER*, char*, int, pem_password_cb*, void*) = 0L;
+static void (*K_RSA_free)(RSA*) = 0L;
+static EVP_CIPHER *(*K_EVP_bf_cbc)() = 0L;
+static int (*K_X509_REQ_sign)(X509_REQ*, EVP_PKEY*, const EVP_MD*) = 0L;
+static int (*K_X509_NAME_add_entry_by_txt)(X509_NAME*, char*, int, unsigned char*, int, int, int) = 0L;
+static X509_NAME *(*K_X509_NAME_new)() = 0L;
+static int (*K_X509_REQ_set_subject_name)(X509_REQ*,X509_NAME*) = 0L;
+static unsigned char *(*K_ASN1_STRING_data)(ASN1_STRING*) = 0L;
+static int (*K_ASN1_STRING_length)(ASN1_STRING*) = 0L;
+static STACK_OF(SSL_CIPHER) *(*K_SSL_get_ciphers)(const SSL *ssl) = 0L;
+
+#endif
+}
+
+
+bool KOpenSSLProxy::hasLibSSL() const {
+ return _sslLib != 0L;
+}
+
+
+bool KOpenSSLProxy::hasLibCrypto() const {
+ return _cryptoLib != 0L;
+}
+
+
+void KOpenSSLProxy::destroy() {
+ delete this;
+ _me = 0L;
+}
+
+#ifdef __OpenBSD__
+#include <tqdir.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+static TQString findMostRecentLib(TQString dir, TQString name)
+{
+ // Grab all shared libraries in the directory
+ TQString filter = "lib"+name+".so.*";
+ TQDir d(dir, filter);
+ if (!d.exists())
+ return 0L;
+ TQStringList l = d.entryList();
+
+ // Find the best one
+ int bestmaj = -1;
+ int bestmin = -1;
+ TQString best = 0L;
+ // where do we start
+ uint s = filter.length()-1;
+ for (TQStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ TQString numberpart = (*it).mid(s);
+ uint endmaj = numberpart.find('.');
+ if (endmaj == -1)
+ continue;
+ bool ok;
+ int maj = numberpart.left(endmaj).toInt(&ok);
+ if (!ok)
+ continue;
+ int min = numberpart.mid(endmaj+1).toInt(&ok);
+ if (!ok)
+ continue;
+ if (maj > bestmaj || (maj == bestmaj && min > bestmin)) {
+ bestmaj = maj;
+ bestmin = min;
+ best = (*it);
+ }
+ }
+ if (best.isNull())
+ return 0L;
+ else
+ return dir+"/"+best;
+}
+#endif
+
+
+KOpenSSLProxy::KOpenSSLProxy() {
+KLibLoader *ll = KLibLoader::self();
+_ok = false;
+TQStringList libpaths, libnamesc, libnamess;
+TDEConfig *cfg;
+
+ _cryptoLib = 0L;
+ _sslLib = 0L;
+
+ cfg = new TDEConfig("cryptodefaults", false, false);
+ cfg->setGroup("OpenSSL");
+ TQString upath = cfg->readPathEntry("Path");
+ if (!upath.isEmpty())
+ libpaths << upath;
+
+ delete cfg;
+
+#ifdef __OpenBSD__
+ {
+ TQString libname = findMostRecentLib("/usr/lib" KDELIBSUFF, "crypto");
+ if (!libname.isNull())
+ _cryptoLib = ll->globalLibrary(libname.latin1());
+ }
+#elif defined(__CYGWIN__)
+ libpaths << "/usr/bin/"
+ << "/usr/local/bin"
+ << "/usr/local/openssl/bin"
+ << "/opt/openssl/bin"
+ << "/opt/trinity/bin"
+ << "";
+
+ libnamess << "cygssl-0.9.7.dll"
+ << "cygssl.dll"
+ << "libssl.dll"
+ << "";
+
+ libnamesc << "cygcrypto.dll"
+ << "libcrypto.dll"
+ << "";
+#else
+ libpaths
+ #ifdef _AIX
+ << "/opt/freeware/lib/"
+ #endif
+ << "/usr/lib" KDELIBSUFF "/"
+ << "/usr/ssl/lib" KDELIBSUFF "/"
+ << "/usr/local/lib" KDELIBSUFF "/"
+ << "/usr/local/openssl/lib" KDELIBSUFF "/"
+ << "/usr/local/ssl/lib" KDELIBSUFF "/"
+ << "/opt/openssl/lib" KDELIBSUFF "/"
+ << "/lib" KDELIBSUFF "/"
+ << "";
+
+// FIXME: #define here for the various OS types to optimize
+ libnamess
+ #ifdef hpux
+ << "libssl.sl"
+ #elif defined(_AIX)
+ << "libssl.a(libssl.so.0)"
+ #elif defined(__APPLE__)
+ << "libssl.dylib"
+ << "libssl.0.9.dylib"
+ #else
+ #ifdef SHLIB_VERSION_NUMBER
+ << "libssl.so." SHLIB_VERSION_NUMBER
+ #endif
+ << "libssl.so"
+ << "libssl.so.0"
+ #endif
+ ;
+
+ libnamesc
+ #ifdef hpux
+ << "libcrypto.sl"
+ #elif defined(_AIX)
+ << "libcrypto.a(libcrypto.so.0)"
+ #elif defined(__APPLE__)
+ << "libcrypto.dylib"
+ << "libcrypto.0.9.dylib"
+ #else
+ #ifdef SHLIB_VERSION_NUMBER
+ << "libcrypto.so." SHLIB_VERSION_NUMBER
+ #endif
+ << "libcrypto.so"
+ << "libcrypto.so.0"
+ #endif
+ ;
+#endif
+
+ for (TQStringList::Iterator it = libpaths.begin();
+ it != libpaths.end();
+ ++it) {
+ for (TQStringList::Iterator shit = libnamesc.begin();
+ shit != libnamesc.end();
+ ++shit) {
+ TQString alib = *it;
+ if (!alib.isEmpty() && !alib.endsWith("/"))
+ alib += "/";
+ alib += *shit;
+ TQString tmpStr(alib.latin1());
+ tmpStr.replace(TQRegExp("\\(.*\\)"), "");
+ if (!access(tmpStr.latin1(), R_OK))
+ _cryptoLib = ll->globalLibrary(alib.latin1());
+ if (!_cryptoLib) {
+ // Multiarch triplet search
+ TQDir madir (*it);
+ TQStringList multiarchdirs = madir.entryList("*-*-*", TQDir::Dirs);
+ for (TQStringList::Iterator mait = multiarchdirs.begin(); mait != multiarchdirs.end(); ++mait ) {
+ TQString malib = *it + *mait + "/" + *shit;
+ TQString tmpStr(malib.latin1());
+ tmpStr.replace(TQRegExp("\\(.*\\)"), "");
+ if (!access(tmpStr.latin1(), R_OK))
+ _cryptoLib = ll->globalLibrary(malib.latin1());
+ }
+ }
+ if (_cryptoLib) break;
+ }
+ if (_cryptoLib) break;
+ }
+
+ if (_cryptoLib) {
+#ifdef KSSL_HAVE_SSL
+ K_X509_free = (void (*) (X509 *)) _cryptoLib->symbol("X509_free");
+ K_RAND_egd = (int (*)(const char *)) _cryptoLib->symbol("RAND_egd");
+ K_RAND_load_file = (int (*)(const char *, long)) _cryptoLib->symbol("RAND_load_file");
+ K_RAND_file_name = (const char* (*)(char *, size_t)) _cryptoLib->symbol("RAND_file_name");
+ K_RAND_write_file = (int (*)(const char *)) _cryptoLib->symbol("RAND_write_file");
+ K_CRYPTO_free = (void (*) (void *)) _cryptoLib->symbol("CRYPTO_free");
+ K_d2i_X509 = (X509 * (*)(X509 **,unsigned char **,long)) _cryptoLib->symbol("d2i_X509");
+ K_i2d_X509 = (int (*)(X509 *,unsigned char **)) _cryptoLib->symbol("i2d_X509");
+ K_X509_cmp = (int (*)(X509 *, X509 *)) _cryptoLib->symbol("X509_cmp");
+ K_X509_STORE_CTX_new = (X509_STORE_CTX * (*) (void)) _cryptoLib->symbol("X509_STORE_CTX_new");
+ K_X509_STORE_CTX_free = (void (*) (X509_STORE_CTX *)) _cryptoLib->symbol("X509_STORE_CTX_free");
+ K_X509_verify_cert = (int (*) (X509_STORE_CTX *)) _cryptoLib->symbol("X509_verify_cert");
+ K_X509_STORE_new = (X509_STORE * (*) (void)) _cryptoLib->symbol("X509_STORE_new");
+ K_X509_STORE_free = (void (*) (X509_STORE *)) _cryptoLib->symbol("X509_STORE_free");
+ K_X509_NAME_oneline = (char * (*) (X509_NAME *,char *,int)) _cryptoLib->symbol("X509_NAME_oneline");
+ K_X509_get_subject_name = (X509_NAME * (*) (X509 *)) _cryptoLib->symbol("X509_get_subject_name");
+ K_X509_get_issuer_name = (X509_NAME * (*) (X509 *)) _cryptoLib->symbol("X509_get_issuer_name");
+ K_X509_STORE_add_lookup = (X509_LOOKUP *(*) (X509_STORE *, X509_LOOKUP_METHOD *)) _cryptoLib->symbol("X509_STORE_add_lookup");
+ K_X509_LOOKUP_file = (X509_LOOKUP_METHOD *(*)(void)) _cryptoLib->symbol("X509_LOOKUP_file");
+ K_X509_LOOKUP_free = (void (*)(X509_LOOKUP *)) _cryptoLib->symbol("X509_LOOKUP_free");
+ K_X509_LOOKUP_ctrl = (int (*)(X509_LOOKUP *, int, const char *, long, char **)) _cryptoLib->symbol("X509_LOOKUP_ctrl");
+ K_X509_STORE_CTX_init = (void (*)(X509_STORE_CTX *, X509_STORE *, X509 *, STACK_OF(X509) *)) _cryptoLib->symbol("X509_STORE_CTX_init");
+ K_X509_dup = (X509* (*)(X509*)) _cryptoLib->symbol("X509_dup");
+ K_BIO_s_mem = (BIO_METHOD *(*) (void)) _cryptoLib->symbol("BIO_s_mem");
+ K_BIO_new = (BIO* (*)(BIO_METHOD *)) _cryptoLib->symbol("BIO_new");
+ K_BIO_new_fp = (BIO* (*)(FILE*, int)) _cryptoLib->symbol("BIO_new_fp");
+ K_BIO_new_mem_buf = (BIO* (*)(void *, int)) _cryptoLib->symbol("BIO_new_mem_buf");
+ K_BIO_free = (int (*)(BIO*)) _cryptoLib->symbol("BIO_free");
+ K_BIO_ctrl = (long (*) (BIO *,int,long,void *)) _cryptoLib->symbol("BIO_ctrl");
+ K_BIO_write = (int (*) (BIO *b, const void *data, int len)) _cryptoLib->symbol("BIO_write");
+ K_PEM_ASN1_write_bio = (int (*)(int (*)(), const char *,BIO*, char*, const EVP_CIPHER *, unsigned char *, int, pem_password_cb *, void *)) _cryptoLib->symbol("PEM_ASN1_write_bio");
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ K_ASN1_item_i2d_fp = (int (*)(ASN1_ITEM *, FILE*, unsigned char *)) _cryptoLib->symbol("ASN1_item_i2d_fp");
+ K_NETSCAPE_X509_it = (ASN1_ITEM *) _cryptoLib->symbol("NETSCAPE_X509_it");
+#else
+ K_X509_asn1_meth = (ASN1_METHOD* (*)(void)) _cryptoLib->symbol("X509_asn1_meth");
+ K_ASN1_i2d_fp = (int (*)(int (*)(), FILE*, unsigned char *)) _cryptoLib->symbol("ASN1_i2d_fp");
+ K_i2d_ASN1_HEADER = (int (*)(ASN1_HEADER *, unsigned char **)) _cryptoLib->symbol("i2d_ASN1_HEADER");
+#endif
+ K_X509_print_fp = (int (*)(FILE*, X509*)) _cryptoLib->symbol("X509_print_fp");
+ K_i2d_PKCS12 = (int (*)(PKCS12*, unsigned char**)) _cryptoLib->symbol("i2d_PKCS12");
+ K_i2d_PKCS12_fp = (int (*)(FILE *, PKCS12*)) _cryptoLib->symbol("i2d_PKCS12_fp");
+ K_PKCS12_newpass = (int (*)(PKCS12*, char*, char*)) _cryptoLib->symbol("PKCS12_newpass");
+ K_d2i_PKCS12_fp = (PKCS12* (*)(FILE*, PKCS12**)) _cryptoLib->symbol("d2i_PKCS12_fp");
+ K_PKCS12_new = (PKCS12* (*)()) _cryptoLib->symbol("PKCS12_new");
+ K_PKCS12_free = (void (*)(PKCS12 *)) _cryptoLib->symbol("PKCS12_free");
+ K_PKCS12_parse = (int (*)(PKCS12*, const char *, EVP_PKEY**,
+ X509**, STACK_OF(X509)**)) _cryptoLib->symbol("PKCS12_parse");
+ K_EVP_PKEY_free = (void (*) (EVP_PKEY *)) _cryptoLib->symbol("EVP_PKEY_free");
+ K_EVP_PKEY_new = (EVP_PKEY* (*)()) _cryptoLib->symbol("EVP_PKEY_new");
+ K_X509_REQ_free = (void (*)(X509_REQ*)) _cryptoLib->symbol("X509_REQ_free");
+ K_X509_REQ_new = (X509_REQ* (*)()) _cryptoLib->symbol("X509_REQ_new");
+ K_X509_STORE_CTX_set_chain = (void (*)(X509_STORE_CTX *, STACK_OF(X509)*)) _cryptoLib->symbol("X509_STORE_CTX_set_chain");
+ K_X509_STORE_CTX_set_purpose = (void (*)(X509_STORE_CTX *, int)) _cryptoLib->symbol("X509_STORE_CTX_set_purpose");
+ K_sk_free = (void (*) (STACK *)) _cryptoLib->symbol("sk_free");
+ K_sk_num = (int (*) (STACK *)) _cryptoLib->symbol("sk_num");
+ K_sk_pop = (char* (*) (STACK *)) _cryptoLib->symbol("sk_pop");
+ K_sk_value = (char* (*) (STACK *, int)) _cryptoLib->symbol("sk_value");
+ K_sk_new = (STACK* (*) (int (*)())) _cryptoLib->symbol("sk_new");
+ K_sk_push = (int (*) (STACK*, char*)) _cryptoLib->symbol("sk_push");
+ K_sk_dup = (STACK* (*) (STACK *)) _cryptoLib->symbol("sk_dup");
+ K_i2s_ASN1_INTEGER = (char *(*) (X509V3_EXT_METHOD *, ASN1_INTEGER *)) _cryptoLib->symbol("i2s_ASN1_INTEGER");
+ K_X509_get_serialNumber = (ASN1_INTEGER * (*) (X509 *)) _cryptoLib->symbol("X509_get_serialNumber");
+ K_X509_get_pubkey = (EVP_PKEY *(*)(X509 *)) _cryptoLib->symbol("X509_get_pubkey");
+ K_i2d_PublicKey = (int (*)(EVP_PKEY *, unsigned char **)) _cryptoLib->symbol("i2d_PublicKey");
+ K_X509_check_private_key = (int (*)(X509 *, EVP_PKEY *)) _cryptoLib->symbol("X509_check_private_key");
+ K_BN_bn2hex = (char *(*)(const BIGNUM *)) _cryptoLib->symbol("BN_bn2hex");
+ K_X509_digest = (int (*)(const X509 *,const EVP_MD *, unsigned char *, unsigned int *)) _cryptoLib->symbol("X509_digest");
+ K_EVP_md5 = (EVP_MD *(*)()) _cryptoLib->symbol("EVP_md5");
+ K_ASN1_INTEGER_free = (void (*)(ASN1_INTEGER *)) _cryptoLib->symbol("ASN1_INTEGER_free");
+ K_OBJ_obj2nid = (int (*)(ASN1_OBJECT *)) _cryptoLib->symbol("OBJ_obj2nid");
+ K_OBJ_nid2ln = (const char *(*)(int)) _cryptoLib->symbol("OBJ_nid2ln");
+ K_X509_get_ext_count = (int (*)(X509*)) _cryptoLib->symbol("X509_get_ext_count");
+ K_X509_get_ext_by_NID = (int (*)(X509*,int,int)) _cryptoLib->symbol("X509_get_ext_by_NID");
+ K_X509_get_ext_by_OBJ = (int (*)(X509*,ASN1_OBJECT*,int)) _cryptoLib->symbol("X509_get_ext_by_OBJ");
+ K_X509_get_ext = (X509_EXTENSION* (*)(X509*,int)) _cryptoLib->symbol("X509_get_ext");
+ K_X509_delete_ext = (X509_EXTENSION* (*)(X509*,int)) _cryptoLib->symbol("X509_delete_ext");
+ K_X509_add_ext = (int (*)(X509*,X509_EXTENSION*,int)) _cryptoLib->symbol("X509_add_ext");
+ K_X509_get_ext_d2i = (void* (*)(X509*,int,int*,int*)) _cryptoLib->symbol("X509_get_ext_d2i");
+ K_i2s_ASN1_OCTET_STRING = (char *(*)(X509V3_EXT_METHOD*,ASN1_OCTET_STRING*)) _cryptoLib->symbol("i2s_ASN1_OCTET_STRING");
+ K_ASN1_BIT_STRING_get_bit = (int (*)(ASN1_BIT_STRING*,int)) _cryptoLib->symbol("ASN1_BIT_STRING_get_bit");
+ K_PKCS7_new = (PKCS7 *(*)()) _cryptoLib->symbol("PKCS7_new");
+ K_PKCS7_free = (void (*)(PKCS7*)) _cryptoLib->symbol("PKCS7_free");
+ K_PKCS7_content_free = (void (*)(PKCS7*)) _cryptoLib->symbol("PKCS7_content_free");
+ K_i2d_PKCS7 = (int (*)(PKCS7*, unsigned char**)) _cryptoLib->symbol("i2d_PKCS7");
+ K_i2d_PKCS7_fp = (int (*)(FILE*,PKCS7*)) _cryptoLib->symbol("i2d_PKCS7_fp");
+ K_i2d_PKCS7_bio = (int (*)(BIO *bp,PKCS7 *p7)) _cryptoLib->symbol("i2d_PKCS7_bio");
+ K_d2i_PKCS7 = (PKCS7* (*)(PKCS7**,unsigned char**,long)) _cryptoLib->symbol("d2i_PKCS7");
+ K_d2i_PKCS7_fp = (PKCS7 *(*)(FILE *,PKCS7**)) _cryptoLib->symbol("d2i_PKCS7_fp");
+ K_d2i_PKCS7_bio = (PKCS7 *(*)(BIO *bp,PKCS7 **p7)) _cryptoLib->symbol("d2i_PKCS7_bio");
+ K_PKCS7_dup = (PKCS7* (*)(PKCS7*)) _cryptoLib->symbol("PKCS7_dup");
+ K_PKCS7_sign = (PKCS7 *(*)(X509*, EVP_PKEY*, STACK_OF(X509)*, BIO*, int)) _cryptoLib->symbol("PKCS7_sign");
+ K_PKCS7_verify = (int (*)(PKCS7*,STACK_OF(X509)*,X509_STORE*,BIO*,BIO*,int)) _cryptoLib->symbol("PKCS7_verify");
+ K_PKCS7_get0_signers = (STACK_OF(X509) *(*)(PKCS7 *, STACK_OF(X509) *, int)) _cryptoLib->symbol("PKCS7_get0_signers");
+ K_PKCS7_encrypt = (PKCS7* (*)(STACK_OF(X509) *, BIO *, EVP_CIPHER *, int)) _cryptoLib->symbol("PKCS7_encrypt");
+ K_PKCS7_decrypt = (int (*)(PKCS7 *, EVP_PKEY *, X509 *, BIO *, int)) _cryptoLib->symbol("PKCS7_decrypt");
+ K_PEM_X509_INFO_read = (STACK_OF(X509_INFO) *(*)(FILE*, STACK_OF(X509_INFO)*, pem_password_cb*, void *)) _cryptoLib->symbol("PEM_X509_INFO_read");
+ K_ASN1_d2i_fp = (char *(*)(char *(*)(),char *(*)(),FILE*,unsigned char**)) _cryptoLib->symbol("ASN1_d2i_fp");
+ K_X509_new = (X509 *(*)()) _cryptoLib->symbol("X509_new");
+ K_X509_PURPOSE_get_count = (int (*)()) _cryptoLib->symbol("X509_PURPOSE_get_count");
+ K_X509_PURPOSE_get_id = (int (*)(X509_PURPOSE *)) _cryptoLib->symbol("X509_PURPOSE_get_id");
+ K_X509_check_purpose = (int (*)(X509*,int,int)) _cryptoLib->symbol("X509_check_purpose");
+ K_X509_PURPOSE_get0 = (X509_PURPOSE *(*)(int)) _cryptoLib->symbol("X509_PURPOSE_get0");
+ K_EVP_PKEY_assign = (int (*)(EVP_PKEY*, int, char*)) _cryptoLib->symbol("EVP_PKEY_assign");
+ K_X509_REQ_set_pubkey = (int (*)(X509_REQ*, EVP_PKEY*)) _cryptoLib->symbol("X509_REQ_set_pubkey");
+ K_RSA_generate_key = (RSA* (*)(int, unsigned long, void (*)(int,int,void *), void *)) _cryptoLib->symbol("RSA_generate_key");
+ K_i2d_X509_REQ_fp = (int (*)(FILE *, X509_REQ *)) _cryptoLib->symbol("i2d_X509_REQ_fp");
+ K_ERR_clear_error = (void (*)()) _cryptoLib->symbol("ERR_clear_error");
+ K_ERR_get_error = (unsigned long (*)()) _cryptoLib->symbol("ERR_get_error");
+ K_ERR_print_errors_fp = (void (*)(FILE*)) _cryptoLib->symbol("ERR_print_errors_fp");
+ K_X509_get1_email = (STACK *(*)(X509 *x)) _cryptoLib->symbol("X509_get1_email");
+ K_X509_email_free = (void (*)(STACK *sk)) _cryptoLib->symbol("X509_email_free");
+ K_EVP_des_ede3_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_des_ede3_cbc");
+ K_EVP_des_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_des_cbc");
+ K_EVP_rc2_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_rc2_cbc");
+ K_EVP_rc2_64_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_rc2_64_cbc");
+ K_EVP_rc2_40_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_rc2_40_cbc");
+ K_i2d_PrivateKey_fp = (int (*)(FILE*,EVP_PKEY*)) _cryptoLib->symbol("i2d_PrivateKey_fp");
+ K_i2d_PKCS8PrivateKey_fp = (int (*)(FILE*, EVP_PKEY*, const EVP_CIPHER*, char*, int, pem_password_cb*, void*)) _cryptoLib->symbol("i2d_PKCS8PrivateKey_fp");
+ K_RSA_free = (void (*)(RSA*)) _cryptoLib->symbol("RSA_free");
+ K_EVP_bf_cbc = (EVP_CIPHER *(*)()) _cryptoLib->symbol("EVP_bf_cbc");
+ K_X509_REQ_sign = (int (*)(X509_REQ*, EVP_PKEY*, const EVP_MD*)) _cryptoLib->symbol("X509_REQ_sign");
+ K_X509_NAME_add_entry_by_txt = (int (*)(X509_NAME*, char*, int, unsigned char*, int, int, int)) _cryptoLib->symbol("X509_NAME_add_entry_by_txt");
+ K_X509_NAME_new = (X509_NAME *(*)()) _cryptoLib->symbol("X509_NAME_new");
+ K_X509_REQ_set_subject_name = (int (*)(X509_REQ*,X509_NAME*)) _cryptoLib->symbol("X509_REQ_set_subject_name");
+ K_ASN1_STRING_data = (unsigned char *(*)(ASN1_STRING*)) _cryptoLib->symbol("ASN1_STRING_data");
+ K_ASN1_STRING_length = (int (*)(ASN1_STRING*)) _cryptoLib->symbol("ASN1_STRING_length");
+#endif
+ }
+
+#ifdef __OpenBSD__
+ {
+ TQString libname = findMostRecentLib("/usr/lib", "ssl");
+ if (!libname.isNull())
+ _sslLib = ll->globalLibrary(libname.latin1());
+ }
+#else
+ for (TQStringList::Iterator it = libpaths.begin();
+ it != libpaths.end();
+ ++it) {
+ for (TQStringList::Iterator shit = libnamess.begin();
+ shit != libnamess.end();
+ ++shit) {
+ TQString alib = *it;
+ if (!alib.isEmpty() && !alib.endsWith("/"))
+ alib += "/";
+ alib += *shit;
+ TQString tmpStr(alib.latin1());
+ tmpStr.replace(TQRegExp("\\(.*\\)"), "");
+ if (!access(tmpStr.latin1(), R_OK))
+ _sslLib = ll->globalLibrary(alib.latin1());
+ if (!_sslLib) {
+ // Multiarch triplet search
+ TQDir madir (*it);
+ TQStringList multiarchdirs = madir.entryList("*-*-*", TQDir::Dirs);
+ for (TQStringList::Iterator mait = multiarchdirs.begin(); mait != multiarchdirs.end(); ++mait ) {
+ TQString malib = *it + *mait + "/" + *shit;
+ TQString tmpStr(malib.latin1());
+ tmpStr.replace(TQRegExp("\\(.*\\)"), "");
+ if (!access(tmpStr.latin1(), R_OK))
+ _sslLib = ll->globalLibrary(malib.latin1());
+ }
+ }
+ if (_sslLib) break;
+ }
+ if (_sslLib) break;
+ }
+#endif
+
+ if (_sslLib) {
+#ifdef KSSL_HAVE_SSL
+ // stand back from your monitor and look at this. it's fun! :)
+ K_SSL_connect = (int (*)(SSL *)) _sslLib->symbol("SSL_connect");
+ K_SSL_accept = (int (*)(SSL *)) _sslLib->symbol("SSL_accept");
+ K_SSL_read = (int (*)(SSL *, void *, int)) _sslLib->symbol("SSL_read");
+ K_SSL_write = (int (*)(SSL *, const void *, int))
+ _sslLib->symbol("SSL_write");
+ K_SSL_new = (SSL* (*)(SSL_CTX *)) _sslLib->symbol("SSL_new");
+ K_SSL_free = (void (*)(SSL *)) _sslLib->symbol("SSL_free");
+ K_SSL_shutdown = (int (*)(SSL *)) _sslLib->symbol("SSL_shutdown");
+ K_SSL_CTX_new = (SSL_CTX* (*)(SSL_METHOD*)) _sslLib->symbol("SSL_CTX_new");
+ K_SSL_CTX_free = (void (*)(SSL_CTX*)) _sslLib->symbol("SSL_CTX_free");
+ K_SSL_set_fd = (int (*)(SSL *, int)) _sslLib->symbol("SSL_set_fd");
+ K_SSL_pending = (int (*)(SSL *)) _sslLib->symbol("SSL_pending");
+ K_SSL_CTX_set_cipher_list = (int (*)(SSL_CTX *, const char *))
+ _sslLib->symbol("SSL_CTX_set_cipher_list");
+ K_SSL_CTX_set_verify = (void (*)(SSL_CTX*, int, int (*)(int, X509_STORE_CTX*))) _sslLib->symbol("SSL_CTX_set_verify");
+ K_SSL_use_certificate = (int (*)(SSL*, X509*))
+ _sslLib->symbol("SSL_CTX_use_certificate");
+ K_SSL_get_current_cipher = (SSL_CIPHER *(*)(SSL *))
+ _sslLib->symbol("SSL_get_current_cipher");
+ K_SSL_ctrl = (long (*)(SSL * ,int, long, char *))
+ _sslLib->symbol("SSL_ctrl");
+ K_TLSv1_client_method = (SSL_METHOD *(*)()) _sslLib->symbol("TLSv1_client_method");
+ K_SSLv2_client_method = (SSL_METHOD *(*)()) _sslLib->symbol("SSLv2_client_method");
+ K_SSLv3_client_method = (SSL_METHOD *(*)()) _sslLib->symbol("SSLv3_client_method");
+ K_SSLv23_client_method = (SSL_METHOD *(*)()) _sslLib->symbol("SSLv23_client_method");
+ K_SSL_get_peer_certificate = (X509 *(*)(SSL *)) _sslLib->symbol("SSL_get_peer_certificate");
+ K_SSL_CIPHER_get_bits = (int (*)(SSL_CIPHER *,int *)) _sslLib->symbol("SSL_CIPHER_get_bits");
+ K_SSL_CIPHER_get_version = (char * (*)(SSL_CIPHER *)) _sslLib->symbol("SSL_CIPHER_get_version");
+ K_SSL_CIPHER_get_name = (const char * (*)(SSL_CIPHER *)) _sslLib->symbol("SSL_CIPHER_get_name");
+ K_SSL_CIPHER_description = (char * (*)(SSL_CIPHER *, char *, int)) _sslLib->symbol("SSL_CIPHER_description");
+ K_SSL_CTX_use_PrivateKey = (int (*)(SSL_CTX*, EVP_PKEY*)) _sslLib->symbol("SSL_CTX_use_PrivateKey");
+ K_SSL_CTX_use_certificate = (int (*)(SSL_CTX*, X509*)) _sslLib->symbol("SSL_CTX_use_certificate");
+ K_SSL_get_error = (int (*)(SSL*, int)) _sslLib->symbol("SSL_get_error");
+ K_SSL_get_peer_cert_chain = (STACK_OF(X509)* (*)(SSL*)) _sslLib->symbol("SSL_get_peer_cert_chain");
+ K_SSL_load_client_CA_file = (STACK_OF(X509_NAME)* (*)(const char *)) _sslLib->symbol("SSL_load_client_CA_file");
+ K_SSL_peek = (int (*)(SSL*,void*,int)) _sslLib->symbol("SSL_peek");
+ K_SSL_get1_session = (SSL_SESSION* (*)(SSL*)) _sslLib->symbol("SSL_get1_session");
+ K_SSL_SESSION_free = (void (*)(SSL_SESSION*)) _sslLib->symbol("SSL_SESSION_free");
+ K_SSL_set_session = (int (*)(SSL*,SSL_SESSION*)) _sslLib->symbol("SSL_set_session");
+ K_d2i_SSL_SESSION = (SSL_SESSION* (*)(SSL_SESSION**,unsigned char**, long)) _sslLib->symbol("d2i_SSL_SESSION");
+ K_i2d_SSL_SESSION = (int (*)(SSL_SESSION*,unsigned char**)) _sslLib->symbol("i2d_SSL_SESSION");
+ K_SSL_get_ciphers = (STACK_OF(SSL_CIPHER) *(*)(const SSL*)) _sslLib->symbol("SSL_get_ciphers");
+#endif
+
+
+ // Initialize the library (once only!)
+ void *x;
+ x = _sslLib->symbol("SSL_library_init");
+ if (_cryptoLib) {
+ if (x) ((int (*)())x)();
+ x = _cryptoLib->symbol("OpenSSL_add_all_algorithms");
+ if (!x)
+ x = _cryptoLib->symbol("OPENSSL_add_all_algorithms");
+ if (x) {
+ ((void (*)())x)();
+ } else {
+ x = _cryptoLib->symbol("OpenSSL_add_all_algorithms_conf");
+ if (!x)
+ x = _cryptoLib->symbol("OPENSSL_add_all_algorithms_conf");
+ if (x) {
+ ((void (*)())x)();
+ } else {
+ x = _cryptoLib->symbol("OpenSSL_add_all_algorithms_noconf");
+ if (!x)
+ x = _cryptoLib->symbol("OPENSSL_add_all_algorithms_noconf");
+ if (x)
+ ((void (*)())x)();
+ }
+ }
+ x = _cryptoLib->symbol("OpenSSL_add_all_ciphers");
+ if (!x)
+ x = _cryptoLib->symbol("OPENSSL_add_all_ciphers");
+ if (x) ((void (*)())x)();
+ x = _cryptoLib->symbol("OpenSSL_add_all_digests");
+ if (!x)
+ x = _cryptoLib->symbol("OPENSSL_add_all_digests");
+ if (x) ((void (*)())x)();
+ }
+ }
+
+}
+
+
+KOpenSSLProxy* KOpenSSLProxy::_me = 0L;
+static KStaticDeleter<KOpenSSLProxy> medProxy;
+
+
+
+KOpenSSLProxy::~KOpenSSLProxy() {
+ if (_sslLib) {
+ _sslLib->unload();
+ }
+ if (_cryptoLib) {
+ _cryptoLib->unload();
+ }
+ medProxy.setObject(0);
+}
+
+
+// FIXME: we should check "ok" and allow this to init the lib if !ok.
+
+KOpenSSLProxy *KOpenSSLProxy::self() {
+#ifdef KSSL_HAVE_SSL
+ if (!_me) {
+ _me = medProxy.setObject(_me, new KOpenSSLProxy);
+ }
+#endif
+ return _me;
+}
+
+
+
+
+
+
+
+#ifdef KSSL_HAVE_SSL
+
+
+
+int KOpenSSLProxy::SSL_connect(SSL *ssl) {
+ if (K_SSL_connect) return (K_SSL_connect)(ssl);
+ return -1;
+}
+
+
+int KOpenSSLProxy::SSL_accept(SSL *ssl) {
+ if (K_SSL_accept) return (K_SSL_accept)(ssl);
+ return -1;
+}
+
+
+int KOpenSSLProxy::SSL_read(SSL *ssl, void *buf, int num) {
+ if (K_SSL_read) return (K_SSL_read)(ssl, buf, num);
+ return -1;
+}
+
+
+int KOpenSSLProxy::SSL_write(SSL *ssl, const void *buf, int num) {
+ if (K_SSL_write) return (K_SSL_write)(ssl, buf, num);
+ return -1;
+}
+
+
+SSL *KOpenSSLProxy::SSL_new(SSL_CTX *ctx) {
+ if (K_SSL_new) return (K_SSL_new)(ctx);
+ return 0L;
+}
+
+
+void KOpenSSLProxy::SSL_free(SSL *ssl) {
+ if (K_SSL_free) (K_SSL_free)(ssl);
+}
+
+
+int KOpenSSLProxy::SSL_shutdown(SSL *ssl) {
+ if (K_SSL_shutdown) return (K_SSL_shutdown)(ssl);
+ return -1;
+}
+
+
+SSL_CTX *KOpenSSLProxy::SSL_CTX_new(SSL_METHOD *method) {
+ if (K_SSL_CTX_new) return (K_SSL_CTX_new)(method);
+ return 0L;
+}
+
+
+void KOpenSSLProxy::SSL_CTX_free(SSL_CTX *ctx) {
+ if (K_SSL_CTX_free) (K_SSL_CTX_free)(ctx);
+}
+
+
+int KOpenSSLProxy::SSL_set_fd(SSL *ssl, int fd) {
+ if (K_SSL_set_fd) return (K_SSL_set_fd)(ssl, fd);
+ return -1;
+}
+
+
+int KOpenSSLProxy::SSL_pending(SSL *ssl) {
+ if (K_SSL_pending) return (K_SSL_pending)(ssl);
+ return -1;
+}
+
+
+int KOpenSSLProxy::SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
+ if (K_SSL_CTX_set_cipher_list) return (K_SSL_CTX_set_cipher_list)(ctx, str);
+ return -1;
+}
+
+
+void KOpenSSLProxy::SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+ int (*verify_callback)(int, X509_STORE_CTX *)) {
+ if (K_SSL_CTX_set_verify) (K_SSL_CTX_set_verify)(ctx, mode, verify_callback);
+}
+
+
+int KOpenSSLProxy::SSL_use_certificate(SSL *ssl, X509 *x) {
+ if (K_SSL_use_certificate) return (K_SSL_use_certificate)(ssl, x);
+ return -1;
+}
+
+
+SSL_CIPHER *KOpenSSLProxy::SSL_get_current_cipher(SSL *ssl) {
+ if (K_SSL_get_current_cipher) return (K_SSL_get_current_cipher)(ssl);
+ return 0L;
+}
+
+
+long KOpenSSLProxy::SSL_ctrl(SSL *ssl,int cmd, long larg, char *parg) {
+ if (K_SSL_ctrl) return (K_SSL_ctrl)(ssl, cmd, larg, parg);
+ return -1;
+}
+
+
+int KOpenSSLProxy::RAND_egd(const char *path) {
+ if (K_RAND_egd) return (K_RAND_egd)(path);
+ return -1;
+}
+
+
+SSL_METHOD *KOpenSSLProxy::TLSv1_client_method() {
+ if (K_TLSv1_client_method) return (K_TLSv1_client_method)();
+ return 0L;
+}
+
+
+SSL_METHOD *KOpenSSLProxy::SSLv2_client_method() {
+ if (K_SSLv2_client_method) return (K_SSLv2_client_method)();
+ return 0L;
+}
+
+
+SSL_METHOD *KOpenSSLProxy::SSLv3_client_method() {
+ if (K_SSLv3_client_method) return (K_SSLv3_client_method)();
+ return 0L;
+}
+
+
+SSL_METHOD *KOpenSSLProxy::SSLv23_client_method() {
+ if (K_SSLv23_client_method) return (K_SSLv23_client_method)();
+ return 0L;
+}
+
+
+X509 *KOpenSSLProxy::SSL_get_peer_certificate(SSL *s) {
+ if (K_SSL_get_peer_certificate) return (K_SSL_get_peer_certificate)(s);
+ return 0L;
+}
+
+
+int KOpenSSLProxy::SSL_CIPHER_get_bits(SSL_CIPHER *c,int *alg_bits) {
+ if (K_SSL_CIPHER_get_bits) return (K_SSL_CIPHER_get_bits)(c, alg_bits);
+ return -1;
+}
+
+
+char * KOpenSSLProxy::SSL_CIPHER_get_version(SSL_CIPHER *c) {
+ if (K_SSL_CIPHER_get_version) return (K_SSL_CIPHER_get_version)(c);
+ return 0L;
+}
+
+
+const char * KOpenSSLProxy::SSL_CIPHER_get_name(SSL_CIPHER *c) {
+ if (K_SSL_CIPHER_get_name) return (K_SSL_CIPHER_get_name)(c);
+ return 0L;
+}
+
+
+char * KOpenSSLProxy::SSL_CIPHER_description(SSL_CIPHER *c,char *buf,int size) {
+ if (K_SSL_CIPHER_description) return (K_SSL_CIPHER_description)(c,buf,size);
+ return 0L;
+}
+
+
+X509 * KOpenSSLProxy::d2i_X509(X509 **a,unsigned char **pp,long length) {
+ if (K_d2i_X509) return (K_d2i_X509)(a,pp,length);
+ return 0L;
+}
+
+
+int KOpenSSLProxy::i2d_X509(X509 *a,unsigned char **pp) {
+ if (K_i2d_X509) return (K_i2d_X509)(a,pp);
+ return -1;
+}
+
+
+int KOpenSSLProxy::X509_cmp(X509 *a, X509 *b) {
+ if (K_X509_cmp) return (K_X509_cmp)(a,b);
+ return 0;
+}
+
+
+X509_STORE *KOpenSSLProxy::X509_STORE_new(void) {
+ if (K_X509_STORE_new) return (K_X509_STORE_new)();
+ return 0L;
+}
+
+
+void KOpenSSLProxy::X509_STORE_free(X509_STORE *v) {
+ if (K_X509_STORE_free) (K_X509_STORE_free)(v);
+}
+
+
+X509_STORE_CTX *KOpenSSLProxy::X509_STORE_CTX_new(void) {
+ if (K_X509_STORE_CTX_new) return (K_X509_STORE_CTX_new)();
+ return 0L;
+}
+
+
+void KOpenSSLProxy::X509_STORE_CTX_free(X509_STORE_CTX *ctx) {
+ if (K_X509_STORE_CTX_free) (K_X509_STORE_CTX_free)(ctx);
+}
+
+
+int KOpenSSLProxy::X509_verify_cert(X509_STORE_CTX *ctx) {
+ if (K_X509_verify_cert) return (K_X509_verify_cert)(ctx);
+ return -1;
+}
+
+
+void KOpenSSLProxy::X509_free(X509 *a) {
+ if (K_X509_free) (K_X509_free)(a);
+}
+
+
+char *KOpenSSLProxy::X509_NAME_oneline(X509_NAME *a,char *buf,int size) {
+ if (K_X509_NAME_oneline) return (K_X509_NAME_oneline)(a,buf,size);
+ return 0L;
+}
+
+
+X509_NAME *KOpenSSLProxy::X509_get_subject_name(X509 *a) {
+ if (K_X509_get_subject_name) return (K_X509_get_subject_name)(a);
+ return 0L;
+}
+
+
+X509_NAME *KOpenSSLProxy::X509_get_issuer_name(X509 *a) {
+ if (K_X509_get_issuer_name) return (K_X509_get_issuer_name)(a);
+ return 0L;
+}
+
+
+X509_LOOKUP *KOpenSSLProxy::X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m) {
+ if (K_X509_STORE_add_lookup) return (K_X509_STORE_add_lookup)(v,m);
+ return 0L;
+}
+
+
+X509_LOOKUP_METHOD *KOpenSSLProxy::X509_LOOKUP_file(void) {
+ if (K_X509_LOOKUP_file) return (K_X509_LOOKUP_file)();
+ return 0L;
+}
+
+
+void KOpenSSLProxy::X509_LOOKUP_free(X509_LOOKUP *x) {
+ if (K_X509_LOOKUP_free) (K_X509_LOOKUP_free)(x);
+}
+
+
+int KOpenSSLProxy::X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, char **ret) {
+ if (K_X509_LOOKUP_ctrl) return (K_X509_LOOKUP_ctrl)(ctx,cmd,argc,argl,ret);
+ return -1;
+}
+
+
+void KOpenSSLProxy::X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, STACK_OF(X509) *chain) {
+ if (K_X509_STORE_CTX_init) (K_X509_STORE_CTX_init)(ctx,store,x509,chain);
+}
+
+
+void KOpenSSLProxy::CRYPTO_free(void *x) {
+ if (K_CRYPTO_free) (K_CRYPTO_free)(x);
+}
+
+
+X509 *KOpenSSLProxy::X509_dup(X509 *x509) {
+ if (K_X509_dup) return (K_X509_dup)(x509);
+ return 0L;
+}
+
+
+BIO *KOpenSSLProxy::BIO_new(BIO_METHOD *type) {
+ if (K_BIO_new) return (K_BIO_new)(type);
+ else return 0L;
+}
+
+
+BIO_METHOD *KOpenSSLProxy::BIO_s_mem(void) {
+ if (K_BIO_s_mem) return (K_BIO_s_mem)();
+ else return 0L;
+}
+
+
+BIO *KOpenSSLProxy::BIO_new_fp(FILE *stream, int close_flag) {
+ if (K_BIO_new_fp) return (K_BIO_new_fp)(stream, close_flag);
+ return 0L;
+}
+
+
+BIO *KOpenSSLProxy::BIO_new_mem_buf(void *buf, int len) {
+ if (K_BIO_new_mem_buf) return (K_BIO_new_mem_buf)(buf,len);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::BIO_free(BIO *a) {
+ if (K_BIO_free) return (K_BIO_free)(a);
+ return -1;
+}
+
+
+long KOpenSSLProxy::BIO_ctrl(BIO *bp,int cmd,long larg,void *parg) {
+ if (K_BIO_ctrl) return (K_BIO_ctrl)(bp,cmd,larg,parg);
+ else return 0; // failure return for BIO_ctrl is quite individual, maybe we should abort() instead
+}
+
+
+int KOpenSSLProxy::BIO_write(BIO *b, const void *data, int len) {
+ if (K_BIO_write) return (K_BIO_write)(b, data, len);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::PEM_write_bio_X509(BIO *bp, X509 *x) {
+ if (K_PEM_ASN1_write_bio) return (K_PEM_ASN1_write_bio) ((int (*)())K_i2d_X509, PEM_STRING_X509, bp, (char *)x, 0L, 0L, 0, 0L, 0L);
+ else return -1;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+int KOpenSSLProxy::ASN1_i2d_fp(FILE *out,unsigned char *x) {
+ if (K_ASN1_item_i2d_fp && K_NETSCAPE_X509_it)
+ return (K_ASN1_item_i2d_fp)(K_NETSCAPE_X509_it, out, x);
+ else return -1;
+}
+#else
+ASN1_METHOD *KOpenSSLProxy::X509_asn1_meth(void) {
+ if (K_X509_asn1_meth) return (K_X509_asn1_meth)();
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::ASN1_i2d_fp(FILE *out,unsigned char *x) {
+ if (K_ASN1_i2d_fp && K_i2d_ASN1_HEADER)
+ return (K_ASN1_i2d_fp)((int (*)())K_i2d_ASN1_HEADER, out, x);
+ else return -1;
+}
+#endif
+
+int KOpenSSLProxy::X509_print(FILE *fp, X509 *x) {
+ if (K_X509_print_fp) return (K_X509_print_fp)(fp, x);
+ return -1;
+}
+
+
+PKCS12 *KOpenSSLProxy::d2i_PKCS12_fp(FILE *fp, PKCS12 **p12) {
+ if (K_d2i_PKCS12_fp) return (K_d2i_PKCS12_fp)(fp, p12);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass) {
+ if (K_PKCS12_newpass) return (K_PKCS12_newpass)(p12, oldpass, newpass);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::i2d_PKCS12(PKCS12 *p12, unsigned char **p) {
+ if (K_i2d_PKCS12) return (K_i2d_PKCS12)(p12, p);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::i2d_PKCS12_fp(FILE *fp, PKCS12 *p12) {
+ if (K_i2d_PKCS12_fp) return (K_i2d_PKCS12_fp)(fp, p12);
+ else return -1;
+}
+
+
+PKCS12 *KOpenSSLProxy::PKCS12_new(void) {
+ if (K_PKCS12_new) return (K_PKCS12_new)();
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::PKCS12_free(PKCS12 *a) {
+ if (K_PKCS12_free) (K_PKCS12_free)(a);
+}
+
+
+int KOpenSSLProxy::PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey,
+ X509 **cert, STACK_OF(X509) **ca) {
+ if (K_PKCS12_parse) return (K_PKCS12_parse) (p12, pass, pkey, cert, ca);
+ else return -1;
+}
+
+
+void KOpenSSLProxy::EVP_PKEY_free(EVP_PKEY *x) {
+ if (K_EVP_PKEY_free) (K_EVP_PKEY_free)(x);
+}
+
+
+EVP_PKEY* KOpenSSLProxy::EVP_PKEY_new() {
+ if (K_EVP_PKEY_new) return (K_EVP_PKEY_new)();
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::X509_REQ_free(X509_REQ *x) {
+ if (K_X509_REQ_free) (K_X509_REQ_free)(x);
+}
+
+
+X509_REQ* KOpenSSLProxy::X509_REQ_new() {
+ if (K_X509_REQ_new) return (K_X509_REQ_new)();
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) {
+ if (K_SSL_CTX_use_PrivateKey) return (K_SSL_CTX_use_PrivateKey)(ctx,pkey);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) {
+ if (K_SSL_CTX_use_certificate) return (K_SSL_CTX_use_certificate)(ctx,x);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::SSL_get_error(SSL *ssl, int rc) {
+ if (K_SSL_get_error) return (K_SSL_get_error)(ssl,rc);
+ else return -1;
+}
+
+
+STACK_OF(X509) *KOpenSSLProxy::SSL_get_peer_cert_chain(SSL *s) {
+ if (K_SSL_get_peer_cert_chain) return (K_SSL_get_peer_cert_chain)(s);
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::sk_free(STACK *s) {
+ if (K_sk_free) (K_sk_free)(s);
+}
+
+
+int KOpenSSLProxy::sk_num(STACK *s) {
+ if (K_sk_num) return (K_sk_num)(s);
+ else return -1;
+}
+
+
+char *KOpenSSLProxy::sk_pop(STACK *s) {
+ if (K_sk_pop) return (K_sk_pop)(s);
+ else return 0L;
+}
+
+
+char *KOpenSSLProxy::sk_value(STACK *s, int n) {
+ if (K_sk_value) return (K_sk_value)(s, n);
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::X509_STORE_CTX_set_chain(X509_STORE_CTX *v, STACK_OF(X509)* x) {
+ if (K_X509_STORE_CTX_set_chain) (K_X509_STORE_CTX_set_chain)(v,x);
+}
+
+void KOpenSSLProxy::X509_STORE_CTX_set_purpose(X509_STORE_CTX *v, int purpose) {
+ if (K_X509_STORE_CTX_set_purpose) (K_X509_STORE_CTX_set_purpose)(v,purpose);
+}
+
+
+STACK* KOpenSSLProxy::sk_dup(STACK *s) {
+ if (K_sk_dup) return (K_sk_dup)(s);
+ else return 0L;
+}
+
+
+STACK* KOpenSSLProxy::sk_new(int (*cmp)()) {
+ if (K_sk_new) return (K_sk_new)(cmp);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::sk_push(STACK* s, char* d) {
+ if (K_sk_push) return (K_sk_push)(s,d);
+ else return -1;
+}
+
+
+char *KOpenSSLProxy::i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint) {
+ if (K_i2s_ASN1_INTEGER) return (K_i2s_ASN1_INTEGER)(meth, aint);
+ else return 0L;
+}
+
+
+ASN1_INTEGER *KOpenSSLProxy::X509_get_serialNumber(X509 *x) {
+ if (K_X509_get_serialNumber) return (K_X509_get_serialNumber)(x);
+ else return 0L;
+}
+
+
+EVP_PKEY *KOpenSSLProxy::X509_get_pubkey(X509 *x) {
+ if (K_X509_get_pubkey) return (K_X509_get_pubkey)(x);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::i2d_PublicKey(EVP_PKEY *a, unsigned char **pp) {
+ if (K_i2d_PublicKey) return (K_i2d_PublicKey)(a,pp);
+ else return 0;
+}
+
+
+int KOpenSSLProxy::X509_check_private_key(X509 *x, EVP_PKEY *p) {
+ if (K_X509_check_private_key) return (K_X509_check_private_key)(x,p);
+ return -1;
+}
+
+
+char *KOpenSSLProxy::BN_bn2hex(const BIGNUM *a) {
+ if (K_BN_bn2hex) return (K_BN_bn2hex)(a);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::X509_digest(const X509 *x,const EVP_MD *t, unsigned char *md, unsigned int *len) {
+ if (K_X509_digest) return (K_X509_digest)(x, t, md, len);
+ else return -1;
+}
+
+
+EVP_MD *KOpenSSLProxy::EVP_md5() {
+ if (K_EVP_md5) return (K_EVP_md5)();
+ return 0L;
+}
+
+
+void KOpenSSLProxy::ASN1_INTEGER_free(ASN1_INTEGER *a) {
+ if (K_ASN1_INTEGER_free) (K_ASN1_INTEGER_free)(a);
+}
+
+
+int KOpenSSLProxy::OBJ_obj2nid(ASN1_OBJECT *o) {
+ if (K_OBJ_obj2nid) return (K_OBJ_obj2nid)(o);
+ else return -1;
+}
+
+
+const char * KOpenSSLProxy::OBJ_nid2ln(int n) {
+ if (K_OBJ_nid2ln) return (K_OBJ_nid2ln)(n);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::X509_get_ext_count(X509 *x) {
+ if (K_X509_get_ext_count) return (K_X509_get_ext_count)(x);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_get_ext_by_NID(X509 *x, int nid, int lastpos) {
+ if (K_X509_get_ext_by_NID) return (K_X509_get_ext_by_NID)(x,nid,lastpos);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos) {
+ if (K_X509_get_ext_by_OBJ) return (K_X509_get_ext_by_OBJ)(x,obj,lastpos);
+ else return -1;
+}
+
+
+X509_EXTENSION *KOpenSSLProxy::X509_get_ext(X509 *x, int loc) {
+ if (K_X509_get_ext) return (K_X509_get_ext)(x,loc);
+ else return 0L;
+}
+
+
+X509_EXTENSION *KOpenSSLProxy::X509_delete_ext(X509 *x, int loc) {
+ if (K_X509_delete_ext) return (K_X509_delete_ext)(x,loc);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc) {
+ if (K_X509_add_ext) return (K_X509_add_ext)(x,ex,loc);
+ else return -1;
+}
+
+
+void *KOpenSSLProxy::X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx) {
+ if (K_X509_get_ext_d2i) return (K_X509_get_ext_d2i)(x,nid,crit,idx);
+ else return 0L;
+}
+
+
+char *KOpenSSLProxy::i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5) {
+ if (K_i2s_ASN1_OCTET_STRING) return (K_i2s_ASN1_OCTET_STRING)(method,ia5);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n) {
+ if (K_ASN1_BIT_STRING_get_bit) return (K_ASN1_BIT_STRING_get_bit)(a,n);
+ else return -1;
+}
+
+
+PKCS7 *KOpenSSLProxy::PKCS7_new(void) {
+ if (K_PKCS7_new) return (K_PKCS7_new)();
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::PKCS7_free(PKCS7 *a) {
+ if (K_PKCS7_free) (K_PKCS7_free)(a);
+}
+
+
+void KOpenSSLProxy::PKCS7_content_free(PKCS7 *a) {
+ if (K_PKCS7_content_free) (K_PKCS7_content_free)(a);
+}
+
+
+int KOpenSSLProxy::i2d_PKCS7(PKCS7 *a, unsigned char **pp) {
+ if (K_i2d_PKCS7) return (K_i2d_PKCS7)(a,pp);
+ else return -1;
+}
+
+
+PKCS7 *KOpenSSLProxy::d2i_PKCS7(PKCS7 **a, unsigned char **pp,long length) {
+ if (K_d2i_PKCS7) return (K_d2i_PKCS7)(a,pp,length);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::i2d_PKCS7_fp(FILE *fp,PKCS7 *p7) {
+ if (K_i2d_PKCS7_fp) return (K_i2d_PKCS7_fp)(fp,p7);
+ else return -1;
+}
+
+
+PKCS7 *KOpenSSLProxy::d2i_PKCS7_fp(FILE *fp,PKCS7 **p7) {
+ if (K_d2i_PKCS7_fp) return (K_d2i_PKCS7_fp)(fp,p7);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::i2d_PKCS7_bio(BIO *bp,PKCS7 *p7) {
+ if (K_i2d_PKCS7_bio) return (K_i2d_PKCS7_bio)(bp, p7);
+ else return -1;
+}
+
+
+PKCS7 *KOpenSSLProxy::d2i_PKCS7_bio(BIO *bp,PKCS7 **p7) {
+ if (K_d2i_PKCS7_bio) return (K_d2i_PKCS7_bio)(bp, p7);
+ else return 0L;
+}
+
+
+PKCS7 *KOpenSSLProxy::PKCS7_dup(PKCS7 *p7) {
+ if (K_PKCS7_dup) return (K_PKCS7_dup)(p7);
+ else return 0L;
+}
+
+
+PKCS7 *KOpenSSLProxy::PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+ BIO *data, int flags) {
+ if (K_PKCS7_sign) return (K_PKCS7_sign)(signcert,pkey,certs,data,flags);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::PKCS7_verify(PKCS7* p, STACK_OF(X509)* st, X509_STORE* s, BIO* in, BIO *out, int flags) {
+ if (K_PKCS7_verify) return (K_PKCS7_verify)(p,st,s,in,out,flags);
+ else return 0;
+}
+
+
+STACK_OF(X509) *KOpenSSLProxy::PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) {
+ if (K_PKCS7_get0_signers) return (K_PKCS7_get0_signers)(p7,certs,flags);
+ else return 0L;
+}
+
+
+PKCS7 *KOpenSSLProxy::PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, EVP_CIPHER *cipher,
+ int flags) {
+ if (K_PKCS7_encrypt) return (K_PKCS7_encrypt)(certs,in,cipher,flags);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) {
+ if (K_PKCS7_decrypt) return (K_PKCS7_decrypt)(p7,pkey,cert,data,flags);
+ else return 0;
+}
+
+
+STACK_OF(X509_NAME) *KOpenSSLProxy::SSL_load_client_CA_file(const char *file) {
+ if (K_SSL_load_client_CA_file) return (K_SSL_load_client_CA_file)(file);
+ else return 0L;
+}
+
+
+STACK_OF(X509_INFO) *KOpenSSLProxy::PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) {
+ if (K_PEM_X509_INFO_read) return (K_PEM_X509_INFO_read)(fp,sk,cb,u);
+ else return 0L;
+}
+
+
+X509 *KOpenSSLProxy::X509_d2i_fp(FILE *out, X509** buf) {
+ if (K_ASN1_d2i_fp) return reinterpret_cast<X509 *>((K_ASN1_d2i_fp)(reinterpret_cast<char *(*)()>(K_X509_new), reinterpret_cast<char *(*)()>(K_d2i_X509), out, reinterpret_cast<unsigned char **>(buf)));
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::SSL_peek(SSL *ssl,void *buf,int num) {
+ if (K_SSL_peek) return (K_SSL_peek)(ssl,buf,num);
+ else return -1;
+}
+
+
+const char *KOpenSSLProxy::RAND_file_name(char *buf, size_t num) {
+ if (K_RAND_file_name) return (K_RAND_file_name)(buf, num);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::RAND_load_file(const char *filename, long max_bytes) {
+ if (K_RAND_load_file) return (K_RAND_load_file)(filename, max_bytes);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::RAND_write_file(const char *filename) {
+ if (K_RAND_write_file) return (K_RAND_write_file)(filename);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_PURPOSE_get_count() {
+ if (K_X509_PURPOSE_get_count) return (K_X509_PURPOSE_get_count)();
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_PURPOSE_get_id(X509_PURPOSE *p) {
+ if (K_X509_PURPOSE_get_id) return (K_X509_PURPOSE_get_id)(p);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_check_purpose(X509 *x, int id, int ca) {
+ if (K_X509_check_purpose) return (K_X509_check_purpose)(x, id, ca);
+ else return -1;
+}
+
+
+X509_PURPOSE *KOpenSSLProxy::X509_PURPOSE_get0(int idx) {
+ if (K_X509_PURPOSE_get0) return (K_X509_PURPOSE_get0)(idx);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::EVP_PKEY_assign(EVP_PKEY *pkey, int type, char *key) {
+ if (K_EVP_PKEY_assign) return (K_EVP_PKEY_assign)(pkey, type, key);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey) {
+ if (K_X509_REQ_set_pubkey) return (K_X509_REQ_set_pubkey)(x, pkey);
+ else return -1;
+}
+
+
+RSA* KOpenSSLProxy::RSA_generate_key(int bits, unsigned long e, void
+ (*callback)(int,int,void *), void *cb_arg) {
+ if (K_RSA_generate_key) return (K_RSA_generate_key)(bits, e, callback, cb_arg);
+ else return 0L;
+}
+
+STACK *KOpenSSLProxy::X509_get1_email(X509 *x) {
+ if (K_X509_get1_email) return (K_X509_get1_email)(x);
+ else return 0L;
+}
+
+void KOpenSSLProxy::X509_email_free(STACK *sk) {
+ if (K_X509_email_free) (K_X509_email_free)(sk);
+}
+
+EVP_CIPHER *KOpenSSLProxy::EVP_des_ede3_cbc() {
+ if (K_EVP_des_ede3_cbc) return (K_EVP_des_ede3_cbc)();
+ else return 0L;
+}
+
+EVP_CIPHER *KOpenSSLProxy::EVP_des_cbc() {
+ if (K_EVP_des_cbc) return (K_EVP_des_cbc)();
+ else return 0L;
+}
+
+EVP_CIPHER *KOpenSSLProxy::EVP_rc2_cbc() {
+ if (K_EVP_rc2_cbc) return (K_EVP_rc2_cbc)();
+ else return 0L;
+}
+
+EVP_CIPHER *KOpenSSLProxy::EVP_rc2_64_cbc() {
+ if (K_EVP_rc2_64_cbc) return (K_EVP_rc2_64_cbc)();
+ else return 0L;
+}
+
+EVP_CIPHER *KOpenSSLProxy::EVP_rc2_40_cbc() {
+ if (K_EVP_rc2_40_cbc) return (K_EVP_rc2_40_cbc)();
+ else return 0L;
+}
+
+int KOpenSSLProxy::i2d_X509_REQ_fp(FILE *fp, X509_REQ *x) {
+ if (K_i2d_X509_REQ_fp) return (K_i2d_X509_REQ_fp)(fp,x);
+ else return -1;
+}
+
+
+void KOpenSSLProxy::ERR_clear_error() {
+ if (K_ERR_clear_error) (K_ERR_clear_error)();
+}
+
+
+unsigned long KOpenSSLProxy::ERR_get_error() {
+ if (K_ERR_get_error) return (K_ERR_get_error)();
+ else return 0xffffffff;
+}
+
+
+void KOpenSSLProxy::ERR_print_errors_fp(FILE* fp) {
+ if (K_ERR_print_errors_fp) (K_ERR_print_errors_fp)(fp);
+}
+
+
+SSL_SESSION *KOpenSSLProxy::SSL_get1_session(SSL *ssl) {
+ if (K_SSL_get1_session) return (K_SSL_get1_session)(ssl);
+ else return 0L;
+}
+
+
+void KOpenSSLProxy::SSL_SESSION_free(SSL_SESSION *session) {
+ if (K_SSL_SESSION_free) (K_SSL_SESSION_free)(session);
+}
+
+
+int KOpenSSLProxy::SSL_set_session(SSL *ssl, SSL_SESSION *session) {
+ if (K_SSL_set_session) return (K_SSL_set_session)(ssl, session);
+ else return -1;
+}
+
+
+SSL_SESSION *KOpenSSLProxy::d2i_SSL_SESSION(SSL_SESSION **a, unsigned char **pp, long length) {
+ if (K_d2i_SSL_SESSION) return (K_d2i_SSL_SESSION)(a, pp, length);
+ else return 0L;
+}
+
+
+int KOpenSSLProxy::i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) {
+ if (K_i2d_SSL_SESSION) return (K_i2d_SSL_SESSION)(in, pp);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *p) {
+ if (K_i2d_PrivateKey_fp) return (K_i2d_PrivateKey_fp)(fp, p);
+ else return -1;
+}
+
+
+int KOpenSSLProxy::i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *p, const EVP_CIPHER *c, char *k, int klen, pem_password_cb *cb, void *u) {
+ if (K_i2d_PKCS8PrivateKey_fp) return (K_i2d_PKCS8PrivateKey_fp)(fp, p, c, k, klen, cb, u);
+ else return -1;
+}
+
+
+void KOpenSSLProxy::RSA_free(RSA *rsa) {
+ if (K_RSA_free) (K_RSA_free)(rsa);
+}
+
+
+EVP_CIPHER *KOpenSSLProxy::EVP_bf_cbc() {
+ if (K_EVP_bf_cbc) return (K_EVP_bf_cbc)();
+ return 0L;
+}
+
+
+int KOpenSSLProxy::X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md) {
+ if (K_X509_REQ_sign) return (K_X509_REQ_sign)(x, pkey, md);
+ return -1;
+}
+
+
+int KOpenSSLProxy::X509_NAME_add_entry_by_txt(X509_NAME *name, char *field,
+ int type, unsigned char *bytes, int len, int loc, int set) {
+ if (K_X509_NAME_add_entry_by_txt) return (K_X509_NAME_add_entry_by_txt)(name, field, type, bytes, len, loc, set);
+ return -1;
+}
+
+
+X509_NAME *KOpenSSLProxy::X509_NAME_new() {
+ if (K_X509_NAME_new) return (K_X509_NAME_new)();
+ return 0L;
+}
+
+
+int KOpenSSLProxy::X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name) {
+ if (K_X509_REQ_set_subject_name) return (K_X509_REQ_set_subject_name)(req, name);
+ return -1;
+}
+
+
+unsigned char *KOpenSSLProxy::ASN1_STRING_data(ASN1_STRING *x) {
+ if (K_ASN1_STRING_data) return (K_ASN1_STRING_data)(x);
+ return 0L;
+}
+
+int KOpenSSLProxy::ASN1_STRING_length(ASN1_STRING *x) {
+ if (K_ASN1_STRING_length) return (K_ASN1_STRING_length)(x);
+ return 0L;
+}
+
+STACK_OF(SSL_CIPHER) *KOpenSSLProxy::SSL_get_ciphers(const SSL* ssl) {
+ if (K_SSL_get_ciphers) return (K_SSL_get_ciphers)(ssl);
+ return 0L;
+}
+
+#endif
+
diff --git a/tdeio/kssl/kopenssl.h b/tdeio/kssl/kopenssl.h
new file mode 100644
index 000000000..59cf7b560
--- /dev/null
+++ b/tdeio/kssl/kopenssl.h
@@ -0,0 +1,920 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001-2003 George Staikos <staikos@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.
+*/
+
+
+// IF YOU ARE USING THIS CLASS, YOU ARE MAKING A MISTAKE.
+
+#ifndef __KOPENSSLPROXY_H
+#define __KOPENSSLPROXY_H
+
+#define KOSSL KOpenSSLProxy
+class KOpenSSLProxyPrivate;
+
+#include <klibloader.h>
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/bio.h>
+#include <openssl/rand.h>
+#include <openssl/asn1.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/evp.h>
+#include <openssl/stack.h>
+#include <openssl/bn.h>
+#undef crypt
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define STACK _STACK
+#endif
+#endif
+
+#include <kstaticdeleter.h>
+
+/**
+ * Dynamically load and wrap OpenSSL.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE OpenSSL Wrapper
+ * @internal
+ */
+class TDEIO_EXPORT KOpenSSLProxy {
+friend class KStaticDeleter<KOpenSSLProxy>;
+public:
+
+ /**
+ * Return an instance of class KOpenSSLProxy *
+ * You cannot delete this object. It is a singleton class.
+ */
+ static KOpenSSLProxy *self();
+
+ /**
+ * Return true of libcrypto was found and loaded
+ */
+ bool hasLibCrypto() const;
+
+ /**
+ * Return true of libssl was found and loaded
+ */
+ bool hasLibSSL() const;
+
+ /**
+ * Destroy the class and start over - don't use this unless you know
+ * what you are doing.
+ */
+ void destroy();
+
+ // Here are the symbols that we need.
+#ifdef KSSL_HAVE_SSL
+
+ /*
+ * SSL_connect - initiate the TLS/SSL handshake with an TLS/SSL server
+ */
+ int SSL_connect(SSL *ssl);
+
+ /*
+ * SSL_accept - initiate the TLS/SSL handshake with an TLS/SSL server
+ */
+ int SSL_accept(SSL *ssl);
+
+ /*
+ * SSL_get_error - get the error code
+ */
+ int SSL_get_error(SSL *ssl, int rc);
+
+ /*
+ * SSL_read - read bytes from a TLS/SSL connection.
+ */
+ int SSL_read(SSL *ssl, void *buf, int num);
+
+ /*
+ * SSL_write - write bytes to a TLS/SSL connection.
+ */
+ int SSL_write(SSL *ssl, const void *buf, int num);
+
+ /*
+ * SSL_new - create a new SSL structure for a connection
+ */
+ SSL *SSL_new(SSL_CTX *ctx);
+
+ /*
+ * SSL_free - free an allocated SSL structure
+ */
+ void SSL_free(SSL *ssl);
+
+ /*
+ * SSL_shutdown - shutdown an allocated SSL connection
+ */
+ int SSL_shutdown(SSL *ssl);
+
+ /*
+ * SSL_CTX_new - create a new SSL_CTX object as framework for TLS/SSL enabled functions
+ */
+ SSL_CTX *SSL_CTX_new(SSL_METHOD *method);
+
+ /*
+ * SSL_CTX_free - free an allocated SSL_CTX object
+ */
+ void SSL_CTX_free(SSL_CTX *ctx);
+
+ /*
+ * SSL_set_fd - connect the SSL object with a file descriptor
+ */
+ int SSL_set_fd(SSL *ssl, int fd);
+
+ /*
+ * SSL_pending - obtain number of readable bytes buffered in an SSL object
+ */
+ int SSL_pending(SSL *ssl);
+
+ /*
+ * SSL_peek - obtain bytes buffered in an SSL object
+ */
+ int SSL_peek(SSL *ssl, void *buf, int num);
+
+ /*
+ * SSL_CTX_set_cipher_list - choose list of available SSL_CIPHERs
+ */
+ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
+
+ /*
+ * SSL_CTX_set_verify - set peer certificate verification parameters
+ */
+ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+ int (*verify_callback)(int, X509_STORE_CTX *));
+
+ /*
+ * SSL_use_certificate - load certificate
+ */
+ int SSL_use_certificate(SSL *ssl, X509 *x);
+
+ /*
+ * SSL_get_current_cipher - get SSL_CIPHER of a connection
+ */
+ SSL_CIPHER *SSL_get_current_cipher(SSL *ssl);
+
+ /*
+ * SSL_set_options - manipulate SSL engine options
+ * Note: These are all mapped to SSL_ctrl so call them as the comment
+ * specifies but know that they use SSL_ctrl. They are #define
+ * so they will map to the one in this class if called as a
+ * member function of this class.
+ */
+ /* long SSL_set_options(SSL *ssl, long options); */
+ /* Returns 0 if not reused, 1 if session id is reused */
+ /* int SSL_session_reused(SSL *ssl); */
+ long SSL_ctrl(SSL *ssl,int cmd, long larg, char *parg);
+
+ /*
+ * RAND_egd - set the path to the EGD
+ */
+ int RAND_egd(const char *path);
+
+
+ /*
+ * RAND_file_name
+ */
+ const char *RAND_file_name(char *buf, size_t num);
+
+
+ /*
+ * RAND_load_file
+ */
+ int RAND_load_file(const char *filename, long max_bytes);
+
+
+ /*
+ * RAND_write_file
+ */
+ int RAND_write_file(const char *filename);
+
+
+ /*
+ * TLSv1_client_method - return a TLSv1 client method object
+ */
+ SSL_METHOD *TLSv1_client_method();
+
+
+ /*
+ * SSLv2_client_method - return a SSLv2 client method object
+ */
+ SSL_METHOD *SSLv2_client_method();
+
+
+ /*
+ * SSLv3_client_method - return a SSLv3 client method object
+ */
+ SSL_METHOD *SSLv3_client_method();
+
+
+ /*
+ * SSLv23_client_method - return a SSLv23 client method object
+ */
+ SSL_METHOD *SSLv23_client_method();
+
+
+ /*
+ * SSL_get_peer_certificate - return the peer's certificate
+ */
+ X509 *SSL_get_peer_certificate(SSL *s);
+
+
+ /*
+ * SSL_get_peer_cert_chain - get the peer's certificate chain
+ */
+ STACK_OF(X509) *SSL_get_peer_cert_chain(SSL *s);
+
+ /*
+ * SSL_CIPHER_get_bits - get the number of bits in this cipher
+ */
+ int SSL_CIPHER_get_bits(SSL_CIPHER *c,int *alg_bits);
+
+
+ /*
+ * SSL_CIPHER_get_version - get the version of this cipher
+ */
+ char *SSL_CIPHER_get_version(SSL_CIPHER *c);
+
+
+ /*
+ * SSL_CIPHER_get_name - get the name of this cipher
+ */
+ const char *SSL_CIPHER_get_name(SSL_CIPHER *c);
+
+
+ /*
+ * SSL_CIPHER_description - get the description of this cipher
+ */
+ char *SSL_CIPHER_description(SSL_CIPHER *,char *buf,int size);
+
+
+ /*
+ * SSL_CTX_use_PrivateKey - set the private key for the session.
+ * - for use with client certificates
+ */
+ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
+
+
+ /*
+ * SSL_CTX_use_certificate - set the client certificate for the session.
+ */
+ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
+
+
+ /*
+ * d2i_X509 - Covert a text representation of X509 to an X509 object
+ */
+ X509 * d2i_X509(X509 **a,unsigned char **pp,long length);
+
+
+ /*
+ * i2d_X509 - Covert an X509 object into a text representation
+ */
+ int i2d_X509(X509 *a,unsigned char **pp);
+
+
+ /*
+ * X509_cmp - compare two X509 objects
+ */
+ int X509_cmp(X509 *a, X509 *b);
+
+
+ /*
+ * X509_dup - duplicate an X509 object
+ */
+ X509 *X509_dup(X509 *x509);
+
+
+ /*
+ * X509_STORE_CTX_new - create an X509 store context
+ */
+ X509_STORE_CTX *X509_STORE_CTX_new(void);
+
+
+ /*
+ * X509_STORE_CTX_free - free up an X509 store context
+ */
+ void X509_STORE_CTX_free(X509_STORE_CTX *v);
+
+
+ /*
+ * X509_STORE_CTX_set_chain - set the certificate chain
+ */
+ void X509_STORE_CTX_set_chain(X509_STORE_CTX *v, STACK_OF(X509)* x);
+
+ /*
+ * X509_STORE_CTX_set_purpose - set the purpose of the certificate
+ */
+ void X509_STORE_CTX_set_purpose(X509_STORE_CTX *v, int purpose);
+
+ /*
+ * X509_verify_cert - verify the certificate
+ */
+ int X509_verify_cert(X509_STORE_CTX *v);
+
+
+ /*
+ * X509_STORE_new - create an X509 store
+ */
+ X509_STORE *X509_STORE_new(void);
+
+
+ /*
+ * X509_STORE_free - free up an X509 store
+ */
+ void X509_STORE_free(X509_STORE *v);
+
+
+ /*
+ * X509_free - free up an X509
+ */
+ void X509_free(X509 *v);
+
+
+ /*
+ * X509_NAME_oneline - return the X509 data in a string
+ */
+ char *X509_NAME_oneline(X509_NAME *a, char *buf, int size);
+
+
+ /*
+ * X509_get_subject_name - return the X509_NAME for the subject field
+ */
+ X509_NAME *X509_get_subject_name(X509 *a);
+
+
+ /*
+ * X509_get_issuer_name - return the X509_NAME for the issuer field
+ */
+ X509_NAME *X509_get_issuer_name(X509 *a);
+
+
+ /*
+ * X509_STORE_add_lookup - add a lookup file/method to an X509 store
+ */
+ X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
+
+
+ /*
+ * X509_LOOKUP_file - Definition of the LOOKUP_file method
+ */
+ X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
+
+
+ /*
+ * X509_LOOKUP_free - Free an X509_LOOKUP
+ */
+ void X509_LOOKUP_free(X509_LOOKUP *x);
+
+
+ /*
+ * X509_LOOKUP_ctrl - This is not normally called directly (use macros)
+ */
+ int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, char **ret);
+
+
+ /*
+ * X509_STORE_CTX_init - initialize an X509 STORE context
+ */
+ void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, STACK_OF(X509) *chain);
+
+
+ /*
+ * CRYPTO_free - free up an internally allocated object
+ */
+ void CRYPTO_free(void *x);
+
+ /*
+ * BIO_new - create new BIO
+ */
+ BIO *BIO_new(BIO_METHOD *type);
+
+ /*
+ * BIO methods - only one defined here yet
+ */
+ BIO_METHOD *BIO_s_mem(void);
+
+ /*
+ * BIO_new_fp - nastiness called BIO - used to create BIO* from FILE*
+ */
+ BIO *BIO_new_fp(FILE *stream, int close_flag);
+
+ /*
+ * BIO_new_mem_buf - read only BIO from memory region
+ */
+ BIO *BIO_new_mem_buf(void *buf, int len);
+
+ /*
+ * BIO_free - nastiness called BIO - used to destroy BIO*
+ */
+ int BIO_free(BIO *a);
+
+ /*
+ * BIO_ctrl - BIO control method
+ */
+ long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg);
+
+ /*
+ * BIO_write - equivalent to ::write for BIO
+ */
+ int BIO_write(BIO *b, const void *data, int len);
+
+ /*
+ * PEM_write_bio_X509 - write a PEM encoded cert to a BIO*
+ */
+ int PEM_write_bio_X509(BIO *bp, X509 *x);
+
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ /*
+ * X509_asn1_meth - used for netscape output
+ */
+ ASN1_METHOD *X509_asn1_meth();
+#endif
+
+ /*
+ * ASN1_i2d_fp - used for netscape output
+ */
+ int ASN1_i2d_fp(FILE *out, unsigned char *x);
+
+
+ /*
+ * ASN1_d2i_fp - read an X509 from a DER encoded file (buf can be NULL)
+ */
+ X509 *X509_d2i_fp(FILE *out, X509** buf);
+
+
+ /*
+ * X509_print - print the text form of an X509
+ */
+ int X509_print(FILE *fp, X509 *x);
+
+
+ /*
+ * Read a PKCS#12 cert from fp
+ */
+ PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12);
+
+
+ /*
+ * Change the password on a PKCS#12 cert
+ */
+ int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass);
+
+
+ /*
+ * Write a PKCS#12 to mem
+ */
+ int i2d_PKCS12(PKCS12 *p12, unsigned char **p);
+
+
+ /*
+ * Write a PKCS#12 to FILE*
+ */
+ int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12);
+
+
+ /*
+ * Create a new PKCS#12 object
+ */
+ PKCS12 *PKCS12_new(void);
+
+
+ /*
+ * Destroy that PKCS#12 that you created!
+ */
+ void PKCS12_free(PKCS12 *a);
+
+
+ /*
+ * Parse the PKCS#12
+ */
+ int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey,
+ X509 **cert, STACK_OF(X509) **ca);
+
+
+ /*
+ * Free the Private Key
+ */
+ void EVP_PKEY_free(EVP_PKEY *x);
+
+
+ /*
+ * Pop off the stack
+ */
+ char *sk_pop(STACK *s);
+
+
+ /*
+ * Free the stack
+ */
+ void sk_free(STACK *s);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ void sk_free(void *s) { return sk_free(reinterpret_cast<STACK*>(s)); }
+#endif
+
+ /*
+ * Number of elements in the stack
+ */
+ int sk_num(STACK *s);
+
+
+ /*
+ * Value of element n in the stack
+ */
+ char *sk_value(STACK *s, int n);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ char *sk_value(void *s, int n) { return sk_value(reinterpret_cast<STACK*>(s), n); }
+#endif
+
+ /*
+ * Create a new stack
+ */
+ STACK *sk_new(int (*cmp)());
+
+
+ /*
+ * Add an element to the stack
+ */
+ int sk_push(STACK *s, char *d);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ int sk_push(void *s, void *d) { return sk_push(reinterpret_cast<STACK*>(s), reinterpret_cast<char*>(d)); }
+#endif
+
+ /*
+ * Duplicate the stack
+ */
+ STACK *sk_dup(STACK *s);
+
+
+ /*
+ * Convert an ASN1_INTEGER to it's text form
+ */
+ char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint);
+
+
+ /*
+ * Get the certificate's serial number
+ */
+ ASN1_INTEGER *X509_get_serialNumber(X509 *x);
+
+
+ /*
+ * Get the certificate's public key
+ */
+ EVP_PKEY *X509_get_pubkey(X509 *x);
+
+
+ /*
+ * Convert the public key to a decimal form
+ */
+ int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp);
+
+
+ /*
+ * Check the private key of a PKCS bundle against the X509
+ */
+ int X509_check_private_key(X509 *x, EVP_PKEY *p);
+
+
+ /*
+ * Convert a BIGNUM to a hex string
+ */
+ char *BN_bn2hex(const BIGNUM *a);
+
+
+ /*
+ * Compute the digest of an X.509
+ */
+ int X509_digest(const X509 *x,const EVP_MD *t, unsigned char *md, unsigned int *len);
+
+
+ /*
+ * EVP_md5
+ */
+ EVP_MD *EVP_md5();
+
+
+ /*
+ * ASN1_INTEGER free
+ */
+ void ASN1_INTEGER_free(ASN1_INTEGER *x);
+
+
+ /*
+ * ASN1_STRING_data
+ */
+ unsigned char *ASN1_STRING_data(ASN1_STRING *x);
+
+ /*
+ * ASN1_STRING_length
+ */
+ int ASN1_STRING_length(ASN1_STRING *x);
+
+ /*
+ *
+ */
+ int OBJ_obj2nid(ASN1_OBJECT *o);
+
+ /*
+ *
+ */
+ const char * OBJ_nid2ln(int n);
+
+ /*
+ * get the number of extensions
+ */
+ int X509_get_ext_count(X509 *x);
+
+ /*
+ *
+ */
+ int X509_get_ext_by_NID(X509 *x, int nid, int lastpos);
+
+ /*
+ *
+ */
+ int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos);
+
+ /*
+ *
+ */
+ X509_EXTENSION *X509_get_ext(X509 *x, int loc);
+
+ /*
+ *
+ */
+ X509_EXTENSION *X509_delete_ext(X509 *x, int loc);
+
+ /*
+ *
+ */
+ int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
+
+ /*
+ *
+ */
+ void *X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
+
+ /*
+ *
+ */
+ char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5);
+
+ /*
+ *
+ */
+ int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n);
+
+ /*
+ *
+ */
+ PKCS7 *PKCS7_new(void);
+
+ /*
+ *
+ */
+ void PKCS7_free(PKCS7 *a);
+
+ /*
+ *
+ */
+ void PKCS7_content_free(PKCS7 *a);
+
+ /*
+ *
+ */
+ int i2d_PKCS7(PKCS7 *a, unsigned char **pp);
+
+ /*
+ *
+ */
+ PKCS7 *d2i_PKCS7(PKCS7 **a, unsigned char **pp,long length);
+
+ /*
+ *
+ */
+ int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7);
+
+ /*
+ *
+ */
+ PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7);
+
+ /*
+ *
+ */
+ int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7);
+
+ /*
+ *
+ */
+ PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7);
+
+ /*
+ *
+ */
+ PKCS7 *PKCS7_dup(PKCS7 *p7);
+
+ /*
+ * Create a PKCS7 signature / signed message
+ */
+ PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+ BIO *data, int flags);
+
+ /*
+ * Verify a PKCS7 signature.
+ */
+ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
+ BIO *indata, BIO *out, int flags);
+
+ /*
+ * Get signers of a verified PKCS7 signature
+ */
+ STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
+
+ /*
+ * PKCS7 encrypt message
+ */
+ PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, EVP_CIPHER *cipher,
+ int flags);
+
+ /*
+ * decrypt PKCS7 message
+ */
+ int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags);
+
+
+ /*
+ * Load a CA list file.
+ */
+ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
+
+ /*
+ * Load a file of PEM encoded objects.
+ */
+ STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
+ pem_password_cb *cb, void *u);
+
+ /*
+ * Get the number of purposes available
+ */
+ int X509_PURPOSE_get_count();
+
+
+ /*
+ * Get the ID of a purpose
+ */
+ int X509_PURPOSE_get_id(X509_PURPOSE *);
+
+
+ /*
+ * Check the existence of purpose id "id" in x. for CA, set ca = 1, else 0
+ */
+ int X509_check_purpose(X509 *x, int id, int ca);
+
+
+ /*
+ * Get the purpose with index #idx
+ */
+ X509_PURPOSE * X509_PURPOSE_get0(int idx);
+
+
+ /*
+ * Create a new Private KEY
+ */
+ EVP_PKEY* EVP_PKEY_new();
+
+
+ /*
+ * Assign a private key
+ */
+ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, char *key);
+
+
+ /*
+ * Generate a RSA key
+ */
+ RSA *RSA_generate_key(int bits, unsigned long e, void
+ (*callback)(int,int,void *), void *cb_arg);
+
+
+ /*
+ * Create/destroy a certificate request
+ */
+ X509_REQ *X509_REQ_new();
+ void X509_REQ_free(X509_REQ *a);
+
+
+ /*
+ * Set the public key in the REQ object
+ */
+ int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
+
+ /* for testing */
+ int i2d_X509_REQ_fp(FILE *fp, X509_REQ *x);
+
+ /* SMime support */
+ STACK *X509_get1_email(X509 *x);
+ void X509_email_free(STACK *sk);
+
+ /* Ciphers needed for SMime */
+ EVP_CIPHER *EVP_des_ede3_cbc();
+ EVP_CIPHER *EVP_des_cbc();
+ EVP_CIPHER *EVP_rc2_cbc();
+ EVP_CIPHER *EVP_rc2_64_cbc();
+ EVP_CIPHER *EVP_rc2_40_cbc();
+
+ /* clear the current error - use this often*/
+ void ERR_clear_error();
+
+ /* retrieve the latest error */
+ unsigned long ERR_get_error();
+
+ /* Print the errors to this stream */
+ void ERR_print_errors_fp(FILE *fp);
+
+ /* Get a pointer to the SSL session id (reference counted) */
+ SSL_SESSION *SSL_get1_session(SSL *ssl);
+
+ /* Frees a pointer to the SSL session id (reference decremented if needed) */
+ void SSL_SESSION_free(SSL_SESSION *session);
+
+ /* Set the SSL session to reuse. */
+ int SSL_set_session(SSL *ssl, SSL_SESSION *session);
+
+ /* Decode ASN.1 to SSL_SESSION */
+ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, unsigned char **pp, long length);
+ /* Encode SSL_SESSION to ASN.1 */
+ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
+
+ /* Write privatekey to FILE stream */
+ int i2d_PrivateKey_fp(FILE*, EVP_PKEY*);
+
+ /* Write PKCS#8privatekey to FILE stream */
+ int i2d_PKCS8PrivateKey_fp(FILE*, EVP_PKEY*, const EVP_CIPHER*, char*, int, pem_password_cb*, void*);
+
+ /* Free RSA structure */
+ void RSA_free(RSA*);
+
+ /* Get a blowfish CBC pointer */
+ EVP_CIPHER *EVP_bf_cbc();
+
+ /* Sign a CSR */
+ int X509_REQ_sign(X509_REQ*, EVP_PKEY*, const EVP_MD*);
+
+ /* add a name entry */
+ int X509_NAME_add_entry_by_txt(X509_NAME*, char*, int, unsigned char*, int, int, int);
+
+ /* Create a name */
+ X509_NAME *X509_NAME_new();
+
+ /* Set the subject */
+ int X509_REQ_set_subject_name(X509_REQ*,X509_NAME*);
+
+ /* get list of available SSL_CIPHER's sorted by preference */
+ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL* ssl);
+
+#endif
+
+private:
+ KOpenSSLProxy();
+ ~KOpenSSLProxy();
+ KOpenSSLProxyPrivate *d;
+
+ KLibrary *_sslLib;
+ KLibrary *_cryptoLib;
+ static KOpenSSLProxy *_me;
+
+ bool _ok;
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksmimecrypto.cc b/tdeio/kssl/ksmimecrypto.cc
new file mode 100644
index 000000000..1a9e37e60
--- /dev/null
+++ b/tdeio/kssl/ksmimecrypto.cc
@@ -0,0 +1,424 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
+ *
+ * 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 <tqptrlist.h>
+#include <tqcstring.h>
+#include <tqstring.h>
+#include <kdebug.h>
+
+#include "kopenssl.h"
+#include "ksslcertificate.h"
+#include "ksslpkcs12.h"
+#include "ksmimecrypto.h"
+
+// this hack provided by Malte Starostik to avoid glibc/openssl bug
+// on some systems
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/err.h>
+#undef crypt
+#endif
+
+
+// forward included macros to KOpenSSLProxy
+#define sk_new kossl->sk_new
+#define sk_free kossl->sk_free
+#define sk_push kossl->sk_push
+#define sk_value kossl->sk_value
+#define sk_num kossl->sk_num
+#define BIO_ctrl kossl->BIO_ctrl
+
+
+#ifdef KSSL_HAVE_SSL
+static const char eot = 0;
+
+class KSMIMECryptoPrivate {
+ KOpenSSLProxy *kossl;
+
+public:
+ KSMIMECryptoPrivate(KOpenSSLProxy *kossl);
+
+
+ STACK_OF(X509) *certsToX509(TQPtrList<KSSLCertificate> &certs);
+
+ KSMIMECrypto::rc signMessage(BIO *clearText,
+ BIO *cipherText,
+ KSSLPKCS12 &privKey, TQPtrList<KSSLCertificate> &certs,
+ bool detached);
+
+ KSMIMECrypto::rc encryptMessage(BIO *clearText,
+ BIO *cipherText, KSMIMECrypto::algo algorithm,
+ TQPtrList<KSSLCertificate> &recip);
+
+ KSMIMECrypto::rc checkSignature(BIO *clearText,
+ BIO *signature, bool detached,
+ TQPtrList<KSSLCertificate> &recip);
+
+ KSMIMECrypto::rc decryptMessage(BIO *cipherText,
+ BIO *clearText,
+ KSSLPKCS12 &privKey);
+
+ void MemBIOToQByteArray(BIO *src, TQByteArray &dest);
+
+ KSMIMECrypto::rc sslErrToRc(void);
+};
+
+
+KSMIMECryptoPrivate::KSMIMECryptoPrivate(KOpenSSLProxy *kossl): kossl(kossl) {
+}
+
+
+STACK_OF(X509) *KSMIMECryptoPrivate::certsToX509(TQPtrList<KSSLCertificate> &certs) {
+ STACK_OF(X509) *x509 = reinterpret_cast<STACK_OF(X509)*>(sk_new(NULL));
+ KSSLCertificate *cert = certs.first();
+ while(cert) {
+ sk_X509_push(x509, cert->getCert());
+ cert = certs.next();
+ }
+ return x509;
+}
+
+
+KSMIMECrypto::rc KSMIMECryptoPrivate::signMessage(BIO *clearText,
+ BIO *cipherText,
+ KSSLPKCS12 &privKey, TQPtrList<KSSLCertificate> &certs,
+ bool detached) {
+
+ STACK_OF(X509) *other = NULL;
+ KSMIMECrypto::rc rc;
+ int flags = detached?PKCS7_DETACHED:0;
+
+ if (certs.count()) other = certsToX509(certs);
+
+ PKCS7 *p7 = kossl->PKCS7_sign(privKey.getCertificate()->getCert(), privKey.getPrivateKey(),
+ other, clearText, flags);
+
+ if (other) sk_X509_free(other);
+
+ if (!p7) return sslErrToRc();
+
+ if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
+ rc = KSMIMECrypto::KSC_R_OK;
+ } else {
+ rc = sslErrToRc();
+ }
+
+ kossl->PKCS7_free(p7);
+
+ return rc;
+}
+
+KSMIMECrypto::rc KSMIMECryptoPrivate::encryptMessage(BIO *clearText,
+ BIO *cipherText, KSMIMECrypto::algo algorithm,
+ TQPtrList<KSSLCertificate> &recip) {
+ EVP_CIPHER *cipher = NULL;
+ KSMIMECrypto::rc rc;
+ switch(algorithm) {
+ case KSMIMECrypto::KSC_C_DES3_CBC:
+ cipher = kossl->EVP_des_ede3_cbc();
+ break;
+ case KSMIMECrypto::KSC_C_RC2_CBC_128:
+ cipher = kossl->EVP_rc2_cbc();
+ break;
+ case KSMIMECrypto::KSC_C_RC2_CBC_64:
+ cipher = kossl->EVP_rc2_64_cbc();
+ break;
+ case KSMIMECrypto::KSC_C_DES_CBC:
+ cipher = kossl->EVP_des_cbc();
+ break;
+ case KSMIMECrypto::KSC_C_RC2_CBC_40:
+ cipher = kossl->EVP_rc2_40_cbc();
+ break;
+ }
+ if (!cipher) return KSMIMECrypto::KSC_R_NOCIPHER;
+
+ STACK_OF(X509) *certs = certsToX509(recip);
+
+ PKCS7 *p7 = kossl->PKCS7_encrypt(certs, clearText, cipher, 0);
+
+ sk_X509_free(certs);
+
+ if (!p7) return sslErrToRc();
+
+ if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
+ rc = KSMIMECrypto::KSC_R_OK;
+ } else {
+ rc = sslErrToRc();
+ }
+
+ kossl->PKCS7_free(p7);
+
+ return rc;
+}
+
+
+KSMIMECrypto::rc KSMIMECryptoPrivate::checkSignature(BIO *clearText,
+ BIO *signature, bool detached,
+ TQPtrList<KSSLCertificate> &recip) {
+
+ PKCS7 *p7 = kossl->d2i_PKCS7_bio(signature, NULL);
+ KSMIMECrypto::rc rc = KSMIMECrypto::KSC_R_OTHER;
+
+ if (!p7) return sslErrToRc();
+
+ BIO *in;
+ BIO *out;
+ if (detached) {
+ in = clearText;
+ out = NULL;
+ } else {
+ in = NULL;
+ out = clearText;
+ }
+
+ X509_STORE *dummystore = kossl->X509_STORE_new();
+ if (kossl->PKCS7_verify(p7, NULL, dummystore, in, out, PKCS7_NOVERIFY)) {
+ STACK_OF(X509) *signers = kossl->PKCS7_get0_signers(p7, 0, PKCS7_NOVERIFY);
+ int num = sk_X509_num(signers);
+
+ for(int n=0; n<num; n++) {
+ KSSLCertificate *signer = KSSLCertificate::fromX509(sk_X509_value(signers, n));
+ recip.append(signer);
+ }
+
+ sk_X509_free(signers);
+ rc = KSMIMECrypto::KSC_R_OK;
+ } else {
+ rc = sslErrToRc();
+ }
+
+ kossl->X509_STORE_free(dummystore);
+ kossl->PKCS7_free(p7);
+
+ return rc;
+}
+
+
+KSMIMECrypto::rc KSMIMECryptoPrivate::decryptMessage(BIO *cipherText,
+ BIO *clearText,
+ KSSLPKCS12 &privKey) {
+
+ PKCS7 *p7 = kossl->d2i_PKCS7_bio(cipherText, NULL);
+ KSMIMECrypto::rc rc;
+
+ if (!p7) return sslErrToRc();
+
+ if (kossl->PKCS7_decrypt(p7, privKey.getPrivateKey(), privKey.getCertificate()->getCert(),
+ clearText, 0)) {
+ rc = KSMIMECrypto::KSC_R_OK;
+ } else {
+ rc = sslErrToRc();
+ }
+
+ kossl->PKCS7_free(p7);
+
+ return rc;
+}
+
+
+void KSMIMECryptoPrivate::MemBIOToQByteArray(BIO *src, TQByteArray &dest) {
+ char *buf;
+ long len = BIO_get_mem_data(src, &buf);
+ dest.assign(buf, len);
+ /* Now this goes quite a bit into openssl internals.
+ We assume that openssl uses malloc() (it does in
+ default config) and rip out the buffer.
+ */
+ reinterpret_cast<BUF_MEM *>(src->ptr)->data = NULL;
+}
+
+
+KSMIMECrypto::rc KSMIMECryptoPrivate::sslErrToRc(void) {
+ unsigned long cerr = kossl->ERR_get_error();
+
+ // To be completed and possibly fixed
+
+ switch(ERR_GET_REASON(cerr)) {
+ case ERR_R_MALLOC_FAILURE:
+ return KSMIMECrypto::KSC_R_NOMEM;
+ }
+
+ switch(ERR_GET_LIB(cerr)) {
+ case ERR_LIB_PKCS7:
+ switch(ERR_GET_REASON(cerr)) {
+ case PKCS7_R_WRONG_CONTENT_TYPE:
+ case PKCS7_R_NO_CONTENT:
+ case PKCS7_R_NO_SIGNATURES_ON_DATA:
+ return KSMIMECrypto::KSC_R_FORMAT;
+ break;
+ case PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE:
+ case PKCS7_R_DECRYPT_ERROR: // Hmm?
+ return KSMIMECrypto::KSC_R_WRONGKEY;
+ break;
+ case PKCS7_R_DIGEST_FAILURE:
+ return KSMIMECrypto::KSC_R_VERIFY;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ kdDebug(7029) <<"KSMIMECrypto: uncaught error " <<ERR_GET_LIB(cerr)
+ <<" " <<ERR_GET_REASON(cerr) <<endl;
+ return KSMIMECrypto::KSC_R_OTHER;
+}
+#endif
+
+
+KSMIMECrypto::KSMIMECrypto() {
+#ifdef KSSL_HAVE_SSL
+ kossl = KOpenSSLProxy::self();
+ priv = new KSMIMECryptoPrivate(kossl);
+ if (!kossl->hasLibCrypto()) kossl = 0L;
+#else
+ kossl = 0L;
+#endif
+}
+
+
+KSMIMECrypto::~KSMIMECrypto() {
+#ifdef KSSL_HAVE_SSL
+ delete priv;
+#endif
+}
+
+
+KSMIMECrypto::rc KSMIMECrypto::signMessage(const TQCString &clearText,
+ TQByteArray &cipherText,
+ const KSSLPKCS12 &privKey,
+ const TQPtrList<KSSLCertificate> &certs,
+ bool detached) {
+#ifdef KSSL_HAVE_SSL
+ if (!kossl) return KSC_R_NO_SSL;
+ BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
+ BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
+
+ rc rc = priv->signMessage(in, out,
+ const_cast<KSSLPKCS12 &>(privKey),
+ const_cast<TQPtrList<KSSLCertificate> &>(certs),
+ detached);
+
+ if (!rc) priv->MemBIOToQByteArray(out, cipherText);
+
+ kossl->BIO_free(out);
+ kossl->BIO_free(in);
+
+ return rc;
+#else
+ return KSC_R_NO_SSL;
+#endif
+}
+
+
+KSMIMECrypto::rc KSMIMECrypto::checkDetachedSignature(const TQCString &clearText,
+ const TQByteArray &signature,
+ TQPtrList<KSSLCertificate> &foundCerts) {
+#ifdef KSSL_HAVE_SSL
+ if (!kossl) return KSC_R_NO_SSL;
+ BIO *txt = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.length());
+ BIO *sig = kossl->BIO_new_mem_buf((char *)signature.data(), signature.size());
+
+ rc rc = priv->checkSignature(txt, sig, true, foundCerts);
+
+ kossl->BIO_free(sig);
+ kossl->BIO_free(txt);
+
+ return rc;
+#else
+ return KSC_R_NO_SSL;
+#endif
+}
+
+
+KSMIMECrypto::rc KSMIMECrypto::checkOpaqueSignature(const TQByteArray &signedText,
+ TQCString &clearText,
+ TQPtrList<KSSLCertificate> &foundCerts) {
+#ifdef KSSL_HAVE_SSL
+ if (!kossl) return KSC_R_NO_SSL;
+
+ BIO *in = kossl->BIO_new_mem_buf((char *)signedText.data(), signedText.size());
+ BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
+
+ rc rc = priv->checkSignature(out, in, false, foundCerts);
+
+ kossl->BIO_write(out, &eot, 1);
+ priv->MemBIOToQByteArray(out, clearText);
+
+ kossl->BIO_free(out);
+ kossl->BIO_free(in);
+
+ return rc;
+#else
+ return KSC_R_NO_SSL;
+#endif
+}
+
+
+KSMIMECrypto::rc KSMIMECrypto::encryptMessage(const TQCString &clearText,
+ TQByteArray &cipherText,
+ algo algorithm,
+ const TQPtrList<KSSLCertificate> &recip) {
+#ifdef KSSL_HAVE_SSL
+ if (!kossl) return KSC_R_NO_SSL;
+
+ BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
+ BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
+
+ rc rc = priv->encryptMessage(in,out,algorithm,
+ const_cast< TQPtrList<KSSLCertificate> &>(recip));
+
+ if (!rc) priv->MemBIOToQByteArray(out, cipherText);
+
+ kossl->BIO_free(out);
+ kossl->BIO_free(in);
+
+ return rc;
+#else
+ return KSC_R_NO_SSL;
+#endif
+}
+
+
+KSMIMECrypto::rc KSMIMECrypto::decryptMessage(const TQByteArray &cipherText,
+ TQCString &clearText,
+ const KSSLPKCS12 &privKey) {
+#ifdef KSSL_HAVE_SSL
+ if (!kossl) return KSC_R_NO_SSL;
+
+ BIO *in = kossl->BIO_new_mem_buf((char *)cipherText.data(), cipherText.size());
+ BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
+
+ rc rc = priv->decryptMessage(in,out,
+ const_cast<KSSLPKCS12 &>(privKey));
+
+ kossl->BIO_write(out, &eot, 1);
+ priv->MemBIOToQByteArray(out, clearText);
+
+ kossl->BIO_free(out);
+ kossl->BIO_free(in);
+
+ return rc;
+#else
+ return KSC_R_NO_SSL;
+#endif
+}
diff --git a/tdeio/kssl/ksmimecrypto.h b/tdeio/kssl/ksmimecrypto.h
new file mode 100644
index 000000000..5f8e1da73
--- /dev/null
+++ b/tdeio/kssl/ksmimecrypto.h
@@ -0,0 +1,128 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
+ *
+ * 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 __KSMIMECRYPTO_H
+#define __KSMIMECRYPTO_H
+
+
+#include <tqcstring.h>
+#include <tqptrlist.h>
+#include "ksslpkcs12.h"
+#include "ksslcertificate.h"
+
+class KOpenSSLProxy;
+class KSMIMECryptoPrivate;
+
+class TDEIO_EXPORT KSMIMECrypto {
+ public:
+ KSMIMECrypto();
+ ~KSMIMECrypto();
+
+ enum algo { KSC_C_DES3_CBC = 1,
+ KSC_C_RC2_CBC_128,
+ KSC_C_RC2_CBC_64,
+ KSC_C_DES_CBC,
+ KSC_C_RC2_CBC_40 };
+
+ enum rc { KSC_R_OK, /* everything ok */
+ KSC_R_OTHER, /* unspecified error */
+ KSC_R_NO_SSL, /* No crypto lib / compiled without SSL */
+ KSC_R_NOCIPHER, /* encryption cipher n/a */
+ KSC_R_NOMEM, /* out of memory */
+ KSC_R_FORMAT, /* wrong input data format */
+ KSC_R_WRONGKEY, /* wrong decryption/signature key */
+ KSC_R_VERIFY /* data does not match signature */
+ };
+
+ /**
+ * Sign a message
+ * @param clearText MIME representation of the message (part) to sign
+ * @param cipherText signature to append or signature block
+ * @param privKey private key/certificate to sign with
+ * @param certs additional certificates (may be empty)
+ * @param detached create detached or opaque signature
+ * @return 0 on success
+ */
+ rc signMessage(const TQCString &clearText,
+ TQByteArray &cipherText,
+ const KSSLPKCS12 &privKey,
+ const TQPtrList<KSSLCertificate> &certs,
+ bool detached);
+
+ /**
+ * Check a detached message signature
+ * Will check if messages matches signature and extract certificates
+ * Does not check certificates for validity!
+ * @param clearText MIME representation of signed message (without SIG)
+ * @param signature signature
+ * @param foundCerts certificates found in this message
+ * @return 0 on success
+ */
+ rc checkDetachedSignature(const TQCString &clearText,
+ const TQByteArray &signature,
+ TQPtrList<KSSLCertificate> &foundCerts);
+
+ /**
+ * Check an opaque signed message
+ * Will check if signature matches and extract message
+ * Does not check certificates for validity!
+ * @param signedText signed message block
+ * @param clearText cleartext of signed message
+ * @param foundCerts certificates found in this mesasge
+ * @return 0 on success
+ */
+ rc checkOpaqueSignature(const TQByteArray &signedText,
+ TQCString &clearText,
+ TQPtrList<KSSLCertificate> &foundCerts);
+
+ /**
+ * Encrypt a message
+ * encrypts a message for the given list of recipients and the
+ * selected algorithm. Note that any algorithm <128 bytes is
+ * insecure and should never be used, even if SMIME-2 requires
+ * only RC2-40
+ * @param clearText MIME representation of message to encrypt
+ * @param cipherText returned encrypted message
+ * @param algorithm encryption algorithm
+ * @param recip recipient certificates
+ * @return 0 on success
+ */
+ rc encryptMessage(const TQCString &clearText,
+ TQByteArray &cipherText,
+ algo algorithm,
+ const TQPtrList<KSSLCertificate> &recip);
+
+ /**
+ * Decrypt a message
+ * @param cipherText encrypted message block
+ * @param clearText returns decrypted message
+ * @param privKey private key to use
+ * @return 0 on success
+ */
+ rc decryptMessage(const TQByteArray &cipherText,
+ TQCString &clearText,
+ const KSSLPKCS12 &privKey);
+
+ private:
+ KSMIMECryptoPrivate *priv;
+ KOpenSSLProxy *kossl;
+};
+
+#endif
diff --git a/tdeio/kssl/kssl.cc b/tdeio/kssl/kssl.cc
new file mode 100644
index 000000000..66cc503d5
--- /dev/null
+++ b/tdeio/kssl/kssl.cc
@@ -0,0 +1,688 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// this hack provided by Malte Starostik to avoid glibc/openssl bug
+// on some systems
+#ifdef KSSL_HAVE_SSL
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#define crypt _openssl_crypt
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#undef crypt
+#endif
+
+#include "kssl.h"
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <ksock.h>
+#include <ksockaddr.h>
+
+#include <kopenssl.h>
+#include <ksslx509v3.h>
+#include <ksslpkcs12.h>
+#include <ksslsession.h>
+#include <klocale.h>
+#include <ksocks.h>
+
+#define sk_dup d->kossl->sk_dup
+
+class KSSLPrivate {
+public:
+ KSSLPrivate() {
+ lastInitTLS = false;
+ kossl = KOpenSSLProxy::self();
+ session = 0L;
+ }
+
+ ~KSSLPrivate() {
+ delete session;
+ session = 0L;
+ }
+
+ bool lastInitTLS;
+ KSSLCertificate::KSSLValidation m_cert_vfy_res;
+ TQString proxyPeer;
+
+#ifdef KSSL_HAVE_SSL
+ SSL *m_ssl;
+ SSL_CTX *m_ctx;
+ SSL_METHOD *m_meth;
+#endif
+ KSSLSession *session;
+ KOSSL *kossl;
+};
+
+
+KSSL::KSSL(bool init) {
+ d = new KSSLPrivate;
+ m_bInit = false;
+ m_bAutoReconfig = true;
+ m_cfg = new KSSLSettings();
+#ifdef KSSL_HAVE_SSL
+ d->m_ssl = 0L;
+#endif
+
+ if (init)
+ initialize();
+}
+
+
+KSSL::~KSSL() {
+ close();
+ delete m_cfg;
+ delete d;
+}
+
+
+int KSSL::seedWithEGD() {
+int rc = 0;
+#ifdef KSSL_HAVE_SSL
+ if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
+ rc = d->kossl->RAND_egd(m_cfg->getEGDPath().latin1());
+ if (rc < 0)
+ kdDebug(7029) << "KSSL: Error seeding PRNG with the EGD." << endl;
+ else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
+ << " bytes from the EGD." << endl;
+ } else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
+ rc = d->kossl->RAND_load_file(m_cfg->getEGDPath().latin1(), -1);
+ if (rc < 0)
+ kdDebug(7029) << "KSSL: Error seeding PRNG with the entropy file." << endl;
+ else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc
+ << " bytes from the entropy file." << endl;
+ }
+#endif
+return rc;
+}
+
+
+bool KSSL::TLSInit() {
+#ifdef KSSL_HAVE_SSL
+// kdDebug(7029) << "KSSL TLS initialize" << endl;
+ if (m_bInit)
+ return false;
+
+ if (m_bAutoReconfig)
+ m_cfg->load();
+
+ if (!m_cfg->tlsv1())
+ return false;
+
+ seedWithEGD();
+ d->m_meth = d->kossl->TLSv1_client_method();
+ d->lastInitTLS = true;
+
+ m_pi.reset();
+
+ d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
+ if (d->m_ctx == 0L) {
+ return false;
+ }
+
+ // set cipher list
+ TQString clist = m_cfg->getCipherList();
+ //kdDebug(7029) << "Cipher list: " << clist << endl;
+ if (!clist.isEmpty())
+ d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
+
+ m_bInit = true;
+return true;
+#else
+return false;
+#endif
+}
+
+
+bool KSSL::initialize() {
+#ifdef KSSL_HAVE_SSL
+ kdDebug(7029) << "KSSL initialize" << endl;
+ if (m_bInit)
+ return false;
+
+ if (m_bAutoReconfig)
+ m_cfg->load();
+
+ seedWithEGD();
+ // FIXME: we should be able to force SSL off entirely.
+ d->lastInitTLS = false;
+
+ m_pi.reset();
+
+ if (!m_cfg->tlsv1() && !m_cfg->sslv3() && m_cfg->sslv2())
+ d->m_meth = d->kossl->SSLv2_client_method();
+ else if (m_cfg->tlsv1() && !m_cfg->sslv3() && !m_cfg->sslv2())
+ d->m_meth = d->kossl->TLSv1_client_method();
+ else if (!m_cfg->tlsv1() && m_cfg->sslv3() && !m_cfg->sslv2())
+ d->m_meth = d->kossl->SSLv3_client_method();
+ else d->m_meth = d->kossl->SSLv23_client_method();
+
+/*
+if (m_cfg->sslv2() && m_cfg->sslv3()) kdDebug(7029) << "Double method" << endl;
+else if (m_cfg->sslv2()) kdDebug(7029) << "SSL2 method" << endl;
+else if (m_cfg->sslv3()) kdDebug(7029) << "SSL3 method" << endl;
+*/
+
+ d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
+ if (d->m_ctx == 0L) {
+ return false;
+ }
+
+ // set cipher list
+ TQString clist = m_cfg->getCipherList();
+ kdDebug(7029) << "Cipher list: " << clist << endl;
+ if (!clist.isEmpty())
+ d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
+
+ m_bInit = true;
+return true;
+#else
+return false;
+#endif
+}
+
+
+bool KSSL::setSession(const KSSLSession *session) {
+#ifdef KSSL_HAVE_SSL
+ if (!session) {
+ delete d->session;
+ d->session = 0L;
+ return true;
+ }
+
+ // Obtain a reference by incrementing the reference count. Yuck.
+ static_cast<SSL_SESSION*>(session->_session)->references++;
+
+ d->session = new KSSLSession;
+ d->session->_session = session->_session;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+void KSSL::close() {
+#ifdef KSSL_HAVE_SSL
+//kdDebug(7029) << "KSSL close" << endl;
+ if (!m_bInit)
+ return;
+
+ delete d->session;
+ d->session = 0L;
+
+ if (d->m_ssl) {
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0L;
+ }
+
+ d->kossl->SSL_CTX_free(d->m_ctx);
+ if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
+ d->kossl->RAND_write_file(m_cfg->getEGDPath().latin1());
+ }
+
+ m_bInit = false;
+#endif
+}
+
+
+bool KSSL::reInitialize() {
+ close();
+return initialize();
+}
+
+// get the callback file - it's hidden away in here
+//#include "ksslcallback.c"
+
+
+bool KSSL::setVerificationLogic() {
+#if 0
+#ifdef KSSL_HAVE_SSL
+ // SSL_set_verify_result(d->m_ssl, X509_V_OK);
+ // SSL_CTX_set_verify(d->m_ctx, SSL_VERIFY_PEER, X509Callback);
+#endif
+#endif
+return true;
+}
+
+
+int KSSL::accept(int sock) {
+#ifdef KSSL_HAVE_SSL
+// kdDebug(7029) << "KSSL accept" << endl;
+int rc;
+ if (!m_bInit)
+ return -1;
+ d->m_ssl = d->kossl->SSL_new(d->m_ctx);
+ if (!d->m_ssl)
+ return -1;
+
+ if (d->session) {
+ if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
+ {
+ kdDebug(7029) << "Can't reuse session, no certificate." << endl;
+ delete d->session;
+ d->session = 0;
+ } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
+ static_cast<SSL_SESSION*>(d->session->_session))) {
+ kdDebug(7029) << "Session ID is being reused." << endl;
+ } else {
+ kdDebug(7029) << "Error attempting to reuse session." << endl;
+ delete d->session;
+ d->session = 0;
+ }
+ }
+
+/*
+ if (!setVerificationLogic()) {
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return -1;
+ }
+*/
+
+ int off = SSL_OP_ALL;
+ if (!d->lastInitTLS && !m_cfg->tlsv1())
+ off |= SSL_OP_NO_TLSv1;
+ if (!m_cfg->sslv3())
+ off |= SSL_OP_NO_SSLv3;
+ if (!m_cfg->sslv2())
+ off |= SSL_OP_NO_SSLv2;
+
+ d->kossl->SSL_set_options(d->m_ssl, off);
+
+ rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
+ if (rc == 0) {
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return rc;
+ }
+
+ rc = d->kossl->SSL_accept(d->m_ssl);
+ if (rc == 1) {
+ setConnectionInfo();
+ setPeerInfo();
+ kdDebug(7029) << "KSSL connected OK" << endl;
+ } else {
+ kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
+ kdDebug(7029) << " ERROR = "
+ << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return -1;
+ }
+
+ if (!d->kossl->SSL_session_reused(d->m_ssl)) {
+ if (d->session) {
+ kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
+ delete d->session;
+ d->session = 0L;
+ }
+ }
+
+ if (!d->session) {
+ SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
+ if (sess) {
+ d->session = new KSSLSession;
+ d->session->_session = sess;
+ }
+ }
+
+return rc;
+#else
+return -1;
+#endif
+}
+
+
+int KSSL::connect(int sock) {
+#ifdef KSSL_HAVE_SSL
+// kdDebug(7029) << "KSSL connect" << endl;
+int rc;
+ if (!m_bInit)
+ return -1;
+ d->m_ssl = d->kossl->SSL_new(d->m_ctx);
+ if (!d->m_ssl)
+ return -1;
+
+ if (d->session) {
+ if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
+ {
+ kdDebug(7029) << "Can't reuse session, no certificate." << endl;
+ delete d->session;
+ d->session = 0;
+ } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
+ static_cast<SSL_SESSION*>(d->session->_session))) {
+ kdDebug(7029) << "Session ID is being reused." << endl;
+ } else {
+ kdDebug(7029) << "Error attempting to reuse session." << endl;
+ delete d->session;
+ d->session = 0;
+ }
+ }
+
+/*
+ if (!setVerificationLogic()) {
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return -1;
+ }
+*/
+
+ int off = SSL_OP_ALL;
+ if (!d->lastInitTLS && !m_cfg->tlsv1())
+ off |= SSL_OP_NO_TLSv1;
+ if (!m_cfg->sslv3())
+ off |= SSL_OP_NO_SSLv3;
+ if (!m_cfg->sslv2())
+ off |= SSL_OP_NO_SSLv2;
+
+ d->kossl->SSL_set_options(d->m_ssl, off);
+
+ rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
+ if (rc == 0) {
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return rc;
+ }
+
+connect_again:
+ rc = d->kossl->SSL_connect(d->m_ssl);
+ if (rc == 1) {
+ setConnectionInfo();
+ setPeerInfo();
+ kdDebug(7029) << "KSSL connected OK" << endl;
+ } else {
+ int err = d->kossl->SSL_get_error(d->m_ssl, rc);
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+ // nonblocking - but we block anyways in connect() :)
+ goto connect_again;
+ } else {
+ kdDebug(7029) << "KSSL connect failed - rc = "
+ << rc << endl;
+ kdDebug(7029) << " ERROR = "
+ << err << endl;
+ d->kossl->ERR_print_errors_fp(stderr);
+ d->kossl->SSL_shutdown(d->m_ssl);
+ d->kossl->SSL_free(d->m_ssl);
+ d->m_ssl = 0;
+ return -1;
+ }
+ }
+
+ if (!d->kossl->SSL_session_reused(d->m_ssl)) {
+ if (d->session) {
+ kdDebug(7029) << "Session reuse failed. New session used instead." << endl;
+ delete d->session;
+ d->session = 0L;
+ }
+ }
+
+ if (!d->session) {
+ SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
+ if (sess) {
+ d->session = new KSSLSession;
+ d->session->_session = sess;
+ }
+ }
+
+return rc;
+#else
+return -1;
+#endif
+}
+
+
+int KSSL::pending() {
+#ifdef KSSL_HAVE_SSL
+ if (!m_bInit)
+ return -1;
+return d->kossl->SSL_pending(d->m_ssl);
+#else
+return -1;
+#endif
+}
+
+
+int KSSL::peek(void *buf, int len) {
+#ifdef KSSL_HAVE_SSL
+ if (!m_bInit)
+ return -1;
+ // FIXME: enhance to work the way read() does below, handling errors
+return d->kossl->SSL_peek(d->m_ssl, buf, len);
+#else
+return -1;
+#endif
+}
+
+
+int KSSL::read(void *buf, int len) {
+#ifdef KSSL_HAVE_SSL
+ int rc = 0;
+ int maxIters = 10;
+
+ if (!m_bInit)
+ return -1;
+
+read_again:
+ rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
+ if (rc <= 0) {
+ int err = d->kossl->SSL_get_error(d->m_ssl, rc);
+
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+ kdDebug(7029) << "SSL read() returning 0: " << err << endl;
+ if (maxIters-- > 0) {
+ ::usleep(20000); // 20ms sleep
+ goto read_again;
+ }
+ return 0;
+ }
+
+ kdDebug(7029) << "SSL READ ERROR: " << err << endl;
+ if (err != SSL_ERROR_NONE &&
+ err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL) {
+ rc = -1; // OpenSSL returns 0 on error too
+ d->kossl->ERR_print_errors_fp(stderr);
+ }
+
+// else if (err == SSL_ERROR_ZERO_RETURN)
+// rc = 0;
+ }
+return rc;
+#else
+return -1;
+#endif
+}
+
+
+int KSSL::write(const void *buf, int len) {
+#ifdef KSSL_HAVE_SSL
+ if (!m_bInit)
+ return -1;
+
+write_again:
+ int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
+ if (rc <= 0) { // OpenSSL returns 0 on error too
+ int err = d->kossl->SSL_get_error(d->m_ssl, rc);
+
+ if (err == SSL_ERROR_WANT_WRITE) {
+ ::usleep(20000); // 20ms sleep
+ goto write_again;
+ }
+
+ kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
+ if (err != SSL_ERROR_NONE &&
+ err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
+ rc = -1;
+ }
+
+return rc;
+#else
+return -1;
+#endif
+}
+
+
+bool KSSL::reconfig() {
+ return reInitialize();
+}
+
+
+void KSSL::setAutoReconfig(bool ar) {
+ m_bAutoReconfig = ar;
+}
+
+
+bool KSSL::setSettings(KSSLSettings *settings) {
+ delete m_cfg;
+ m_cfg = settings;
+ return reconfig();
+}
+
+
+#ifdef KSSL_HAVE_SSL
+bool KSSL::m_bSSLWorks = true;
+#else
+bool KSSL::m_bSSLWorks = false;
+#endif
+
+bool KSSL::doesSSLWork() {
+ return m_bSSLWorks;
+}
+
+
+void KSSL::setConnectionInfo() {
+#ifdef KSSL_HAVE_SSL
+SSL_CIPHER *sc;
+char buf[1024];
+
+ buf[0] = 0; // for safety.
+ sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
+ if (!sc) {
+ kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
+ return;
+ }
+
+ // set the number of bits, bits used
+ m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
+ // set the cipher version
+ m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
+ // set the cipher name
+ m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
+ // set the cipher description
+ m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
+
+#endif
+}
+
+
+void KSSL::setPeerInfo() {
+#ifdef KSSL_HAVE_SSL
+ m_pi.setPeerHost(d->proxyPeer);
+ m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
+ STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
+ if (xs)
+ xs = sk_X509_dup(xs); // Leak?
+ m_pi.m_cert.setChain((void *)xs);
+#endif
+}
+
+
+KSSLConnectionInfo& KSSL::connectionInfo() {
+ return m_ci;
+}
+
+
+// KDE 4: Make it const TQString &
+void KSSL::setPeerHost(TQString realHost) {
+ d->proxyPeer = realHost;
+}
+
+// deprecated
+void KSSL::setProxyUse(bool, TQString, int, TQString) {
+}
+
+
+KSSLPeerInfo& KSSL::peerInfo() {
+ return m_pi;
+}
+
+
+bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
+#ifdef KSSL_HAVE_SSL
+ if (!pkcs || !pkcs->getCertificate())
+ return false;
+
+int rc;
+X509 *x = pkcs->getCertificate()->getCert();
+EVP_PKEY *k = pkcs->getPrivateKey();
+
+ if (!x || !k) return false;
+
+ if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
+ return false;
+
+ rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
+ if (rc <= 0) {
+ kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed. rc = " << rc << endl;
+ return false;
+ }
+
+ rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
+ if (rc <= 0) {
+ kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed. rc = " << rc << endl;
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+#undef sk_dup
+
+const KSSLSession* KSSL::session() const {
+ return d->session;
+}
+
+bool KSSL::reusingSession() const {
+#ifdef KSSL_HAVE_SSL
+ return (d->m_ssl && d->kossl->SSL_session_reused(d->m_ssl));
+#else
+ return false;
+#endif
+}
+
+
diff --git a/tdeio/kssl/kssl.h b/tdeio/kssl/kssl.h
new file mode 100644
index 000000000..e10b10eaf
--- /dev/null
+++ b/tdeio/kssl/kssl.h
@@ -0,0 +1,301 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSL_H
+#define _KSSL_H
+
+#include <ksslsettings.h>
+#include <ksslpeerinfo.h>
+#include <ksslconnectioninfo.h>
+
+class KSSLPrivate;
+class KSSLCertificate;
+class KSSLPKCS12;
+class KSSLSession;
+
+/**
+ * KDE SSL Wrapper Class
+ *
+ * This class implements KDE's SSL support by wrapping OpenSSL.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KExtendedSocket, TCPSlaveBase
+ * @short KDE SSL Class
+ */
+class TDEIO_EXPORT KSSL {
+public:
+ /**
+ * Construct a KSSL object
+ *
+ * @param init Set this to false if you do not want this class to
+ * immediately initialize OpenSSL.
+ */
+ KSSL(bool init = true);
+
+ /**
+ * Destroy this KSSL object
+ *
+ * Does not close any socket.
+ */
+ ~KSSL();
+
+ /**
+ * Determine if SSL is available and works.
+ *
+ * @return true is SSL is available and usable
+ */
+ static bool doesSSLWork();
+
+ /**
+ * Initialize OpenSSL.
+ *
+ * @return true on success
+ *
+ * This will do nothing if it is already initialized.
+ * @see reInitialize
+ */
+ bool initialize();
+
+ /**
+ * This is used for applicationss which do STARTTLS or something
+ * similar. It creates a TLS method regardless of the user's settings.
+ *
+ * @return true if TLS is successfully initialized
+ */
+ bool TLSInit();
+
+ /**
+ * Set an SSL session to use. This deep copies the session so it
+ * doesn't have to remain valid. You need to call it after calling
+ * initialize or reInitialize. The ID is cleared in close().
+ *
+ * @param session A valid session to reuse. If 0L, it will clear the
+ * session ID in memory.
+ *
+ * @return true on success
+ */
+ bool setSession(const KSSLSession *session);
+
+ /**
+ * Close the SSL session.
+ */
+ void close();
+
+ /**
+ * Reinitialize OpenSSL.
+ *
+ * @return true on success
+ *
+ * This is not generally needed unless you are reusing the KSSL object
+ * for a new session.
+ * @see initialize
+ */
+ bool reInitialize();
+
+ /**
+ * Trigger a reread of KSSL configuration and reInitialize() KSSL.
+ *
+ * @return true on successful reinitalizations
+ *
+ * If you setAutoReconfig() to false, then this will simply
+ * reInitialize() and not read in the new configuration.
+ * @see setAutoReconfig
+ */
+ bool reconfig();
+
+ /**
+ * Enable or disable automatic reconfiguration on initialize().
+ *
+ * @param ar Set to false in order to disable auto-reloading of the
+ * KSSL configuration during initialize().
+ *
+ * By default, KSSL will read its configuration on initialize(). You
+ * might want to disable this for performance reasons.
+ */
+ void setAutoReconfig(bool ar);
+
+ /**
+ * This will reseed the pseudo-random number generator with the EGD
+ * (entropy gathering daemon) if the EGD is configured and enabled.
+ * You don't need to call this yourself normally.
+ *
+ * @return 0 on success
+ */
+ int seedWithEGD();
+
+ /**
+ * Set a new KSSLSettings instance as the settings. This deletes the
+ * current instance of KSSLSettings.
+ *
+ * @param settings A new, valid settings object.
+ *
+ * @return true on success
+ */
+ bool setSettings(KSSLSettings *settings);
+
+ /**
+ * One is built by the constructor, so this will only return a NULL
+ * pointer if you set one with setSettings().
+ *
+ * @return the current settings instance
+ */
+ KSSLSettings * settings() { return m_cfg; }
+
+ /**
+ * Use this to set the certificate to send to the server.
+ * Do NOT delete the KSSLPKCS12 object until you are done with the
+ * session. It is not defined when KSSL will be done with this.
+ *
+ * @param pkcs the valid PKCS#12 object to send.
+ *
+ * @return true if the certificate was properly set to the session.
+ */
+ bool setClientCertificate(KSSLPKCS12 *pkcs);
+
+ /**
+ * Set the status of the connection with respect to proxies.
+ *
+ * @param active is not used
+ * @param realIP is the IP address of the host you're connecting to
+ * @param realPort is the port of the host you're connecting to
+ * @param proxy is the IP or hostname of the proxy server
+ * @deprecated
+ */
+ void setProxyUse(bool active, TQString realIP = TQString::null, int realPort = 0, TQString proxy = TQString::null) KDE_DEPRECATED;
+
+ /**
+ * Set the peer hostname to be used for certificate verification.
+ *
+ * @param realHost the remote hostname as the user believes to be
+ * connecting to
+ */
+ void setPeerHost(TQString realHost = TQString::null);
+
+ /**
+ * Connect the SSL session to the remote host using the provided
+ * socket descriptor.
+ *
+ * @param sock the socket descriptor to connect with. This must be
+ * an already connected socket.
+ * @return 1 on success, 0 on error setting the file descriptor,
+ * -1 on other error.
+ */
+ int connect(int sock);
+
+ /**
+ * Connect the SSL session to the remote host using the provided
+ * socket descriptor. This is for use with an SSL server application.
+ *
+ * @param sock the socket descriptor to connect with. This must be
+ * an already connected socket.
+ * @return 1 on success, 0 on error setting the file descriptor,
+ * -1 on other error.
+ */
+ int accept(int sock);
+
+ /**
+ * Read data from the remote host via SSL.
+ *
+ * @param buf the buffer to read the data into.
+ * @param len the maximum length of data to read.
+ * @return the number of bytes read, 0 on an exception, or -1 on error.
+ */
+ int read(void *buf, int len);
+
+ /**
+ * Peek at available data from the remote host via SSL.
+ *
+ * @param buf the buffer to read the data into.
+ * @param len the maximum length of data to read.
+ * @return the number of bytes read, 0 on an exception, or -1 on error.
+ */
+ int peek(void *buf, int len);
+
+ /**
+ * Write data to the remote host via SSL.
+ *
+ * @param buf the buffer to read the data from.
+ * @param len the length of data to send from the buffer.
+ * @return the number of bytes written, 0 on an exception,
+ * or -1 on error.
+ */
+ int write(const void *buf, int len);
+
+ /**
+ * Determine if data is waiting to be read.
+ *
+ * @return -1 on error, 0 if no data is waiting, > 0 if data is waiting.
+ */
+ int pending();
+
+ /**
+ * Obtain a reference to the connection information.
+ *
+ * @return a reference to the connection information,
+ * valid after connected
+ * @see KSSLConnectionInfo
+ */
+ KSSLConnectionInfo& connectionInfo();
+
+ /**
+ * Obtain a reference to the information about the peer.
+ *
+ * @return a reference to the peer information,
+ * valid after connected
+ * @see KSSLPeerInfo
+ */
+ KSSLPeerInfo& peerInfo();
+
+ /**
+ * Obtain a pointer to the session information.
+ *
+ * @return a pointer to the session information.
+ * This is valid after connected, while connected.
+ * It is deleted by the KSSL object which returns it.
+ * May return 0L if no valid session exists.
+ * @see KSSLSession
+ */
+ const KSSLSession* session() const;
+
+ /**
+ * Determine if we are currently reusing an SSL session ID.
+ *
+ * @return true if we are reusing a session ID.
+ */
+ bool reusingSession() const;
+
+private:
+ static bool m_bSSLWorks;
+ bool m_bInit;
+ bool m_bAutoReconfig;
+ KSSLSettings *m_cfg;
+ KSSLConnectionInfo m_ci;
+ KSSLPeerInfo m_pi;
+
+ KSSLPrivate *d;
+
+ void setConnectionInfo();
+ void setPeerInfo();
+ bool setVerificationLogic();
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/kssl/CMakeLists.txt b/tdeio/kssl/kssl/CMakeLists.txt
new file mode 100644
index 000000000..eeed10125
--- /dev/null
+++ b/tdeio/kssl/kssl/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( caroot )
+
+install( FILES ksslcalist DESTINATION ${CONFIG_INSTALL_DIR} )
diff --git a/tdeio/kssl/kssl/DigiCertAssuredIDRootCA.pem b/tdeio/kssl/kssl/DigiCertAssuredIDRootCA.pem
new file mode 100644
index 000000000..2731638b6
--- /dev/null
+++ b/tdeio/kssl/kssl/DigiCertAssuredIDRootCA.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/DigiCertGlobalRootCA.pem b/tdeio/kssl/kssl/DigiCertGlobalRootCA.pem
new file mode 100644
index 000000000..fd4341df2
--- /dev/null
+++ b/tdeio/kssl/kssl/DigiCertGlobalRootCA.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/DigiCertHighAssuranceEVRootCA.pem b/tdeio/kssl/kssl/DigiCertHighAssuranceEVRootCA.pem
new file mode 100644
index 000000000..9e6810ab7
--- /dev/null
+++ b/tdeio/kssl/kssl/DigiCertHighAssuranceEVRootCA.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/GeoTrust_Universal_CA.pem b/tdeio/kssl/kssl/GeoTrust_Universal_CA.pem
new file mode 100644
index 000000000..31d9e7aa7
--- /dev/null
+++ b/tdeio/kssl/kssl/GeoTrust_Universal_CA.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
diff --git a/tdeio/kssl/kssl/GeoTrust_Universal_CA2.pem b/tdeio/kssl/kssl/GeoTrust_Universal_CA2.pem
new file mode 100644
index 000000000..b61946475
--- /dev/null
+++ b/tdeio/kssl/kssl/GeoTrust_Universal_CA2.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/tdeio/kssl/kssl/HOWTO b/tdeio/kssl/kssl/HOWTO
new file mode 100644
index 000000000..762535b14
--- /dev/null
+++ b/tdeio/kssl/kssl/HOWTO
@@ -0,0 +1,30 @@
+
+NOTE: If you want to add a root file, please contact kde-core-devel and the
+maintainer (currently bradh@kde.org) with full details.
+
+
+1) Build cert_extract
+2) Make a directory 'certtmp'
+3) cd 'certtmp'
+4) Run ../cert_extract /path/to/netscape/cert7.db
+ This will create many files and an index
+5) Remove the TrustCenter level 0 certificate.
+6) Merge these files into a bundle with:
+ ../cert_bundle /path/to/netscape/cert7.db cert.index ../caroot/ca-bundle.crt
+7) Merge these files into a KDE config file with:
+ ../certkde
+8) mv ksslcalist ../
+9) Merge in the local certs that we added ourselves with:
+ cd ..
+ ./mergelocal
+10) *Do your diffs*! Make *sure* you commit what you think you are committing.
+11) svn commit
+
+
+
+
+To add local files:
+1) Create the .pem file and check it into cvs in tdelibs/tdeio/kssl/kssl.
+2) List the pem file name as a single line in 'localcerts'.
+
+
diff --git a/tdeio/kssl/kssl/Makefile.am b/tdeio/kssl/kssl/Makefile.am
new file mode 100644
index 000000000..a7ad33e95
--- /dev/null
+++ b/tdeio/kssl/kssl/Makefile.am
@@ -0,0 +1,6 @@
+
+SUBDIRS = caroot
+
+confdir = $(kde_confdir)
+conf_DATA = ksslcalist
+
diff --git a/tdeio/kssl/kssl/StartCom.pem b/tdeio/kssl/kssl/StartCom.pem
new file mode 100644
index 000000000..a7c9b39a0
--- /dev/null
+++ b/tdeio/kssl/kssl/StartCom.pem
@@ -0,0 +1,148 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority
+ Validity
+ Not Before: Sep 17 19:46:36 2006 GMT
+ Not After : Sep 17 19:46:36 2036 GMT
+ Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (4096 bit)
+ Modulus (4096 bit):
+ 00:c1:88:db:09:bc:6c:46:7c:78:9f:95:7b:b5:33:
+ 90:f2:72:62:d6:c1:36:20:22:24:5e:ce:e9:77:f2:
+ 43:0a:a2:06:64:a4:cc:8e:36:f8:38:e6:23:f0:6e:
+ 6d:b1:3c:dd:72:a3:85:1c:a1:d3:3d:b4:33:2b:d3:
+ 2f:af:fe:ea:b0:41:59:67:b6:c4:06:7d:0a:9e:74:
+ 85:d6:79:4c:80:37:7a:df:39:05:52:59:f7:f4:1b:
+ 46:43:a4:d2:85:85:d2:c3:71:f3:75:62:34:ba:2c:
+ 8a:7f:1e:8f:ee:ed:34:d0:11:c7:96:cd:52:3d:ba:
+ 33:d6:dd:4d:de:0b:3b:4a:4b:9f:c2:26:2f:fa:b5:
+ 16:1c:72:35:77:ca:3c:5d:e6:ca:e1:26:8b:1a:36:
+ 76:5c:01:db:74:14:25:fe:ed:b5:a0:88:0f:dd:78:
+ ca:2d:1f:07:97:30:01:2d:72:79:fa:46:d6:13:2a:
+ a8:b9:a6:ab:83:49:1d:e5:f2:ef:dd:e4:01:8e:18:
+ 0a:8f:63:53:16:85:62:a9:0e:19:3a:cc:b5:66:a6:
+ c2:6b:74:07:e4:2b:e1:76:3e:b4:6d:d8:f6:44:e1:
+ 73:62:1f:3b:c4:be:a0:53:56:25:6c:51:09:f7:aa:
+ ab:ca:bf:76:fd:6d:9b:f3:9d:db:bf:3d:66:bc:0c:
+ 56:aa:af:98:48:95:3a:4b:df:a7:58:50:d9:38:75:
+ a9:5b:ea:43:0c:02:ff:99:eb:e8:6c:4d:70:5b:29:
+ 65:9c:dd:aa:5d:cc:af:01:31:ec:0c:eb:d2:8d:e8:
+ ea:9c:7b:e6:6e:f7:27:66:0c:1a:48:d7:6e:42:e3:
+ 3f:de:21:3e:7b:e1:0d:70:fb:63:aa:a8:6c:1a:54:
+ b4:5c:25:7a:c9:a2:c9:8b:16:a6:bb:2c:7e:17:5e:
+ 05:4d:58:6e:12:1d:01:ee:12:10:0d:c6:32:7f:18:
+ ff:fc:f4:fa:cd:6e:91:e8:36:49:be:1a:48:69:8b:
+ c2:96:4d:1a:12:b2:69:17:c1:0a:90:d6:fa:79:22:
+ 48:bf:ba:7b:69:f8:70:c7:fa:7a:37:d8:d8:0d:d2:
+ 76:4f:57:ff:90:b7:e3:91:d2:dd:ef:c2:60:b7:67:
+ 3a:dd:fe:aa:9c:f0:d4:8b:7f:72:22:ce:c6:9f:97:
+ b6:f8:af:8a:a0:10:a8:d9:fb:18:c6:b6:b5:5c:52:
+ 3c:89:b6:19:2a:73:01:0a:0f:03:b3:12:60:f2:7a:
+ 2f:81:db:a3:6e:ff:26:30:97:f5:8b:dd:89:57:b6:
+ ad:3d:b3:af:2b:c5:b7:76:02:f0:a5:d6:2b:9a:86:
+ 14:2a:72:f6:e3:33:8c:5d:09:4b:13:df:bb:8c:74:
+ 13:52:4b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:TRUE
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment, Key Agreement, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2
+ X509v3 CRL Distribution Points:
+ URI:http://cert.startcom.org/sfsca-crl.crl
+ URI:http://crl.startcom.org/sfsca-crl.crl
+
+ X509v3 Certificate Policies:
+ Policy: ca_policy_id
+ CPS: http://cert.startcom.org/policy.pdf
+ CPS: http://cert.startcom.org/intermediate.pdf
+ User Notice:
+ Organization: Start Commercial (StartCom) Ltd.
+ Number: 1
+ Explicit Text: Limited Liability, read the section *Legal Limitations* of the StartCom Certification Authority Policy available at http://cert.startcom.org/policy.pdf
+
+ Netscape Cert Type:
+ SSL CA, S/MIME CA, Object Signing CA
+ Netscape Comment:
+ StartCom Free SSL Certification Authority
+ Signature Algorithm: sha1WithRSAEncryption
+ 16:6c:99:f4:66:0c:34:f5:d0:85:5e:7d:0a:ec:da:10:4e:38:
+ 1c:5e:df:a6:25:05:4b:91:32:c1:e8:3b:f1:3d:dd:44:09:5b:
+ 07:49:8a:29:cb:66:02:b7:b1:9a:f7:25:98:09:3c:8e:1b:e1:
+ dd:36:87:2b:4b:bb:68:d3:39:66:3d:a0:26:c7:f2:39:91:1d:
+ 51:ab:82:7b:7e:d5:ce:5a:e4:e2:03:57:70:69:97:08:f9:5e:
+ 58:a6:0a:df:8c:06:9a:45:16:16:38:0a:5e:57:f6:62:c7:7a:
+ 02:05:e6:bc:1e:b5:f2:9e:f4:a9:29:83:f8:b2:14:e3:6e:28:
+ 87:44:c3:90:1a:de:38:a9:3c:ac:43:4d:64:45:ce:dd:28:a9:
+ 5c:f2:73:7b:04:f8:17:e8:ab:b1:f3:2e:5c:64:6e:73:31:3a:
+ 12:b8:bc:b3:11:e4:7d:8f:81:51:9a:3b:8d:89:f4:4d:93:66:
+ 7b:3c:03:ed:d3:9a:1d:9a:f3:65:50:f5:a0:d0:75:9f:2f:af:
+ f0:ea:82:43:98:f8:69:9c:89:79:c4:43:8e:46:72:e3:64:36:
+ 12:af:f7:25:1e:38:89:90:77:7e:c3:6b:6a:b9:c3:cb:44:4b:
+ ac:78:90:8b:e7:c7:2c:1e:4b:11:44:c8:34:52:27:cd:0a:5d:
+ 9f:85:c1:89:d5:1a:78:f2:95:10:53:32:dd:80:84:66:75:d9:
+ b5:68:28:fb:61:2e:be:84:a8:38:c0:99:12:86:a5:1e:67:64:
+ ad:06:2e:2f:a9:70:85:c7:96:0f:7c:89:65:f5:8e:43:54:0e:
+ ab:dd:a5:80:39:94:60:c0:34:c9:96:70:2c:a3:12:f5:1f:48:
+ 7b:bd:1c:7e:6b:b7:9d:90:f4:22:3b:ae:f8:fc:2a:ca:fa:82:
+ 52:a0:ef:af:4b:55:93:eb:c1:b5:f0:22:8b:ac:34:4e:26:22:
+ 04:a1:87:2c:75:4a:b7:e5:7d:13:d7:b8:0c:64:c0:36:d2:c9:
+ 2f:86:12:8c:23:09:c1:1b:82:3b:73:49:a3:6a:57:87:94:e5:
+ d6:78:c5:99:43:63:e3:4d:e0:77:2d:e1:65:99:72:69:04:1a:
+ 47:09:e6:0f:01:56:24:fb:1f:bf:0e:79:a9:58:2e:b9:c4:09:
+ 01:7e:95:ba:6d:00:06:3e:b2:ea:4a:10:39:d8:d0:2b:f5:bf:
+ ec:75:bf:97:02:c5:09:1b:08:dc:55:37:e2:81:fb:37:84:43:
+ 62:20:ca:e7:56:4b:65:ea:fe:6c:c1:24:93:24:a1:34:eb:05:
+ ff:9a:22:ae:9b:7d:3f:f1:65:51:0a:a6:30:6a:b3:f4:88:1c:
+ 80:0d:fc:72:8a:e8:83:5e
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/SwissSign-Gold-G2.pem b/tdeio/kssl/kssl/SwissSign-Gold-G2.pem
new file mode 100644
index 000000000..d72118781
--- /dev/null
+++ b/tdeio/kssl/kssl/SwissSign-Gold-G2.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/SwissSign-Platinum-G2.pem b/tdeio/kssl/kssl/SwissSign-Platinum-G2.pem
new file mode 100644
index 000000000..0aa3e3577
--- /dev/null
+++ b/tdeio/kssl/kssl/SwissSign-Platinum-G2.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu
+IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw
+WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD
+ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y
+IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn
+IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+
+6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob
+jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw
+izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl
++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY
+zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP
+pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF
+KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW
+ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB
+AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0
+ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA
+A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0
+uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+
+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7
+jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/
+u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D
+YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1
+puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa
+icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG
+DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
+kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
+Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/SwissSign-Silver-G2.pem b/tdeio/kssl/kssl/SwissSign-Silver-G2.pem
new file mode 100644
index 000000000..67a172cb6
--- /dev/null
+++ b/tdeio/kssl/kssl/SwissSign-Silver-G2.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/WiseKey.pem b/tdeio/kssl/kssl/WiseKey.pem
new file mode 100644
index 000000000..a695c21bb
--- /dev/null
+++ b/tdeio/kssl/kssl/WiseKey.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
+ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
+aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w
+NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G
+A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX
+SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR
+VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2
+w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF
+mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg
+4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9
+4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw
+EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx
+SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2
+ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8
+vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
+Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
+/L7fCg0=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/ac_offline_raiz_certicamara.pem b/tdeio/kssl/kssl/ac_offline_raiz_certicamara.pem
new file mode 100644
index 000000000..c60cce890
--- /dev/null
+++ b/tdeio/kssl/kssl/ac_offline_raiz_certicamara.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx
+CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp
+ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa
+QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw
+NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft
+ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu
+QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG
+qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL
+fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ
+Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4
+Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ
+54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b
+MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j
+ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej
+YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt
+A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF
+rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ
+pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB
+lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy
+YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50
+7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs
+YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6
+xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc
+unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/
+Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp
+ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42
+gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0
+jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+
+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD
+W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/
+RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r
+MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk
+BYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/argedaten-root-ca-cert.pem b/tdeio/kssl/kssl/argedaten-root-ca-cert.pem
new file mode 100644
index 000000000..621e30e20
--- /dev/null
+++ b/tdeio/kssl/kssl/argedaten-root-ca-cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAyygAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmDELMAkGA1UEBhMCQVQx
+EDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAGA1UEChM5QXJn
+ZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBmdWVyIERhdGVu
+c2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVuLmF0MB4XDTAx
+MDIxMjExMzAzMFoXDTA5MDIxMjExMzAzMFowgZgxCzAJBgNVBAYTAkFUMRAwDgYD
+VQQIEwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExQjBABgNVBAoTOUFyZ2UgRGF0
+ZW4gT2VzdGVycmVpY2hpc2NoZSBHZXNlbGxzY2hhZnQgZnVlciBEYXRlbnNjaHV0
+ejEiMCAGCSqGSIb3DQEJARYTYS1jZXJ0QGFyZ2VkYXRlbi5hdDCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEAwgsHqoNtmmrJ86+e1I4hOVBaL4kokqKN2IPOIL+1
+XwY8vfOOUfPEdhWpaC0ldt7VYrksgDiUccgH0FROANWK2GkfKMDzjjXHysR04uEb
+Om7Kqjqn0nproOGkFG+QvBZgs+Ws+HXNFJA6V76fU4+JXq4452LSK4Lr5YcBquu3
+NJECAwEAAaOCARkwggEVMB0GA1UdDgQWBBQ0j59zH/G31zRjgK1y2P//tSAWZjCB
+xQYDVR0jBIG9MIG6gBQ0j59zH/G31zRjgK1y2P//tSAWZqGBnqSBmzCBmDELMAkG
+A1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAG
+A1UEChM5QXJnZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBm
+dWVyIERhdGVuc2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVu
+LmF0ggEAMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQE
+AwICBDANBgkqhkiG9w0BAQQFAAOBgQBFuJYncqMYB6gXQS3eDOI90BEHfFTKy/dV
+AV+K7QdAYikWmqgBheRdPKddJdccPy/Zl/p3ZT7GhDyC5f3wZjcuu8AJ27BNwbCA
+x54dgxgCNcyPm79nY8MRtEdEpoRGdSsFKJemz6hpXM++MWFciyrRWIIA44XB0Gv3
+US0spjsDPQ==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/belgacom.pem b/tdeio/kssl/kssl/belgacom.pem
new file mode 100644
index 000000000..0b581a774
--- /dev/null
+++ b/tdeio/kssl/kssl/belgacom.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICiTCCAfKgAwIBAgIEN4dnrDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJi
+ZTERMA8GA1UEChMIQmVsZ2Fjb20xDDAKBgNVBAsTA01UTTEkMCIGA1UEAxMbQmVs
+Z2Fjb20gRS1UcnVzdCBQcmltYXJ5IENBMR8wHQYKCZImiZPyLGQBAxQPaW5mb0Bl
+LXRydXN0LmJlMB4XDTk4MTEwNDEzMDQzOVoXDTEwMDEyMTEzMDQzOVowdTELMAkG
+A1UEBhMCYmUxETAPBgNVBAoTCEJlbGdhY29tMQwwCgYDVQQLEwNNVE0xJDAiBgNV
+BAMTG0JlbGdhY29tIEUtVHJ1c3QgUHJpbWFyeSBDQTEfMB0GCgmSJomT8ixkAQMU
+D2luZm9AZS10cnVzdC5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqtm5
+s9VPak3FQdB7BGFqi3GBB9pk41huJ1XCrc4XsPz6ko0I8Bxy/7LDMf7gaoeXTMxD
+V6coeTq1g12kHWrxasU+FCIdWQZv8KYxd9ywSTjmywwP/qpyNIjaKDohWu50Kxuk
+21sTFrVzX8OujNLAPj2wy/Dsi4YLwsFEGFpjqNUCAwEAAaMmMCQwDwYDVR0TBAgw
+BgEB/wIBATARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEFBQADgYEAerKx
+pbF9M+nC4RvO05OMfwH9Gx1amq6rB1Ev7Ymr3VBCux//SrWknLFhKQpM6oNZSY2v
+hmnXgaxHqqRxblnvynxqblSK2qiSyfVms3lf1IsBniFjRjWTpcJfImIDcB1jI+hr
+SB0jECfY9t9HorrsgFBKbMRwpnrkdCJ/9oRiMn8=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/caroot/CMakeLists.txt b/tdeio/kssl/kssl/caroot/CMakeLists.txt
new file mode 100644
index 000000000..05e2381a9
--- /dev/null
+++ b/tdeio/kssl/kssl/caroot/CMakeLists.txt
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+install( FILES ca-bundle.crt DESTINATION ${DATA_INSTALL_DIR}/kssl )
diff --git a/tdeio/kssl/kssl/caroot/Makefile.am b/tdeio/kssl/kssl/caroot/Makefile.am
new file mode 100644
index 000000000..cd049a036
--- /dev/null
+++ b/tdeio/kssl/kssl/caroot/Makefile.am
@@ -0,0 +1,4 @@
+
+kssldatadir = $(kde_datadir)/kssl
+kssldata_DATA = ca-bundle.crt
+
diff --git a/tdeio/kssl/kssl/caroot/ca-bundle.crt b/tdeio/kssl/kssl/caroot/ca-bundle.crt
new file mode 100644
index 000000000..31409b62f
--- /dev/null
+++ b/tdeio/kssl/kssl/caroot/ca-bundle.crt
@@ -0,0 +1,2973 @@
+##
+## ca-bundle.crt -- Bundle of CA Certificates
+## Last Modified: Tue Jun 30 02:55:18 UTC 2009
+##
+## This is a bundle of X.509 certificates of public
+## Certificate Authorities (CA).
+##
+
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw
+gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv
+bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv
+b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05
+OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG
+A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N
+LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB
+FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM
+0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG
+PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU
+LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs
+iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU
++/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB
+Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k
+qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir
+vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ
+w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8
+eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/
+O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfkCAgCNMA0GCSqGSIb3DQEBBAUAMIGPMQswCQYDVQQGEwJVUzEnMCUG
+A1UEChMeQW1lcmljYW4gRXhwcmVzcyBDb21wYW55LCBJbmMuMSYwJAYDVQQLEx1B
+bWVyaWNhbiBFeHByZXNzIFRlY2hub2xvZ2llczEvMC0GA1UEAxMmQW1lcmljYW4g
+RXhwcmVzcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgwODE0MjIwMTAwWhcN
+MDYwODE0MjM1OTAwWjCBjzELMAkGA1UEBhMCVVMxJzAlBgNVBAoTHkFtZXJpY2Fu
+IEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1lcmljYW4gRXhwcmVz
+cyBUZWNobm9sb2dpZXMxLzAtBgNVBAMTJkFtZXJpY2FuIEV4cHJlc3MgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ8kmS
+hcr9FSm1BrZE7PyIo/KGzv8UTyQckvnCI8HOQ99dNMi4FOzVKnCRSZXXVs2U8amT
+0Ggi3E19oApyKkfqJfCFAF82VGHPC/k3Wmed6R/pZD9wlWGn0DAC3iYopGYDBOkw
++48zB/lvYYeictvzaHhjZlmpybdm4RWySDYs+QIDAQABMA0GCSqGSIb3DQEBBAUA
+A4GBAGgXYrhzi0xs60qlPqvlnS7SzYoHV/PGWZd2Fxf4Uo4nk9hY2Chs9KIEeorC
+diSxArTfKPL386infiNIYYj0EWiuJl32oUtTJWrYKhQCDuCHIG6eGVxzkAsj4jGX
+Iz/VIqLTBnvaN/XXtUFEF3pFAtmFRWbWjsfwegyZYiJpW+3S
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVT
+MScwJQYDVQQKEx5BbWVyaWNhbiBFeHByZXNzIENvbXBhbnksIEluYy4xJjAkBgNV
+BAsTHUFtZXJpY2FuIEV4cHJlc3MgVGVjaG5vbG9naWVzMTYwNAYDVQQDEy1BbWVy
+aWNhbiBFeHByZXNzIEdsb2JhbCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgw
+ODE0MTkwNjAwWhcNMTMwODE0MjM1OTAwWjCBljELMAkGA1UEBhMCVVMxJzAlBgNV
+BAoTHkFtZXJpY2FuIEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1l
+cmljYW4gRXhwcmVzcyBUZWNobm9sb2dpZXMxNjA0BgNVBAMTLUFtZXJpY2FuIEV4
+cHJlc3MgR2xvYmFsIENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAPAkJmYu++tKc3FTiUfLJjxTkpRMysKFtQ34w1e9
+Lyofahi3V68MABb6oLaQpvcaoS5mJsdoo4qTaWa1RlYtHYLqkAwKIsKJUI0F89Sr
+c0HwzxKsKLRvFJSWWUuekHWG3+JH6+HpT0N+h8onGGaetcFAZX38YW+tm3LPqV7Y
+8/nabpEQ+ky16n4g3qk5L/WI5IpvNcYgnCuGRjMK/DFVpWusFkDpzTVZbzIEw3u1
+D3t3cPNIuypSgs6vKW3xEW9t5gcAAe+a8yYNpnkTZ6/4qxx1rJG1a75AsN6cDLFp
+hRlxkRNFyt/R/eayypaDedvFuKpbepALeFY+xteflEgR9a0CAwEAAaNaMFgwEgYD
+VR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0gBBAwDjAMBgoq
+hkiG+Q8KAQUBMBkGA1UdDgQSBBBXRzV7NicRqAj8L0Yl6yRpMA0GCSqGSIb3DQEB
+BQUAA4IBAQDHYUWoinG5vjTpIXshzVYTmNUwY+kYqkuSFb8LHbvskmnFLsNhi+gw
+RcsQRsFzOFyLGdIr80DrfHKzLh4n43WVihybLsSVBYZy0FX0oZJSeVzb9Pjc5dcS
+sUDHPIbkMWVKyjfG3nZXGWlMRmn8Kq0WN3qTrPchSy3766lQy8HRQAjaA2mHpzde
+VcHF7cTjjgwml5tcV0ty4/IDBdACOyYDQJCevgtbSQx48dVMVSng9v1MA6lUAjLR
+V1qFrEPtWzsWX6C/NdtLnnvo/+cNPDuom0lBRvVzTv+SZSGDE1Vx60k8f4gawhIo
+JaFGS0E3l3/sjvHUoZbCILZerakcHhGg
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSkwJwYD
+VQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAeFw0wMDA1MTIx
+ODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlC
+YWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAnBgNVBAMTIEJhbHRpbW9y
+ZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+ghY8vu9ThHB3yJB8osC+5pKVvoiIg
+ZP6ERzx+K2xparjUwJaOjFINzW9B1L8ErqeBLy2YSNLBlKO1GV1dUWT0jkGwm8At
+IqBexthaEmO8EUpeJhId4iYF5g9fIh96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAd
+BgNVHQ4EFgQUyeKPwAImWrbAB+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3j
+CzNx764zFE37+v0at1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddk
+j5TfR/6ghWk2qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avi
+eK318FL9m+pCDOjYVL5TZvU=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9CYW5rRW5n
+aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz
+aW9uMRMwEQYDVQQDEwpiYW5rZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBiYW5r
+ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw
+CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV
+BAoTD0JhbmtFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmJhbmtlbmdpbmUxIDAeBgkqhkiG9w0B
+CQEWEWNhQGJhbmtlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA14LoTUAl1/hEy+Kh1kLHiBdW2zD3V4IhM7xxTVKsYsIH56nr69ATTIxU
+P36eRzeZ137qt1AxHFjDCidk3m1Ul6l59ProPexdslLLM2npM3f2cteg+toyiYiS
+EJKjyzIu1xF1j9qzGkymSY/4DsXLZNk9FaczxMk/Ooc6Os1M3AverL4VG4rYIb6f
+eR32cIKJ9Q1fGuyKk7ipq1XQfPW8a8TgZdbHbe7U9Gk3iasGMHHvpR9Ep3mGbgdT
+uQ98SBEuIwe1BUCGg/MXpVy48MNXfAMotBgGw4pl9yqSjMni2FB+E9Q9DHFs2RgX
+MqzKuo8zcPxKx2kZ6Arj8+27dw2clQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQBauupHX9EhpC/r57d6b5kkeWvognxIP9//TO4iw3qb
+zIXEkPXmJmwVzlzoKJWqiya+aw19SP0+G6CzsFOBo/9ehmz+hZ8bhYX4MjlWzX5u
+Tnkhz172j9fOBUmrTVPkcRIs6zjCD5PQAGoBPP1/Zdy2N36lZ0U7lg07Opirj/yJ
+PSJeM2j0fwIFAroiVckvdT0BVwB6S/cPaAQGPghbbr1YGSmYrMriSv825ILJUfxz
+rJYunGR9FiY9Ob7+jwJwiZMS4CxSPktutxr/3hOvr1+ALS7IcVakhhA3PuZAJbdH
+FRclR9qMM8aBnBZmf+Uv3K3uhT+UBzzY654U9Yi1JYnA
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC8zCCAlygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBszELMAkGA1UEBhMCQkUx
+ETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTQwMgYDVQQL
+EytCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSEw
+HwYDVQQDExhCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ0ExIzAhBgkqhkiG9w0BCQEW
+FHdlYm1hc3RlckBiZWxzaWduLmJlMB4XDTk3MDcxNjIyMDA1NFoXDTA3MDcxNjIy
+MDA1NFowgbMxCzAJBgNVBAYTAkJFMREwDwYDVQQHEwhCcnVzc2VsczETMBEGA1UE
+ChMKQmVsU2lnbiBOVjE0MDIGA1UECxMrQmVsU2lnbiBTZWN1cmUgU2VydmVyIENl
+cnRpZmljYXRlIEF1dGhvcml0eTEhMB8GA1UEAxMYQmVsU2lnbiBTZWN1cmUgU2Vy
+dmVyIENBMSMwIQYJKoZIhvcNAQkBFhR3ZWJtYXN0ZXJAYmVsc2lnbi5iZTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1gESeJL4BEJ/yccig/x8R3AwK0kLPjZA
+kCjaIXODU/LE0RZAwFP/rqbGJLMnbaWzPTl3XagG9ubpvGMRTgZlcAqdk/miQIt/
+SoQOjRax1swIZBIM4ChLyKWEkBf7EUYu1qeFGMsYrmOasFgG9ADP+MQJGjUMofnu
+Sv1t3v4mpTsCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgCgMA0GCSqGSIb3DQEB
+BAUAA4GBAGw9mcMF4h3K5S2qaIWLQDEgZhNo5lg6idCNdbLFYth9go/32TKBd/Y1
+W4UpzmeyubwrGXjP84f9RvGVdbIJVwMwwXrNckdxgMp9ncllPEcRIn36BwsoeKGT
+6AVFSOIyMko96FMcELfHc4wHUOH5yStTQfWDjeUJOUqOA2KqQGOL
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9DZXJ0RW5n
+aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz
+aW9uMRMwEQYDVQQDEwpjZXJ0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBjZXJ0
+ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw
+CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV
+BAoTD0NlcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmNlcnRlbmdpbmUxIDAeBgkqhkiG9w0B
+CQEWEWNhQGNlcnRlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA7aTXURShaeVt9u/dP3Q2dVib3jTCZvEyc6yfpGgaYWewXWuP4HOSfI4h
+GZblbpl+dzJc6RjhR+pguIRtbT5FJB8SJGjRqoujBEOQOxtVtc2fjM9Dqh0iOvMW
+WS6buxHG55GVrHAQaO5HXEScKQBa9ZyNmpSXPTEBrDMej1OAGOkc524/TZrgFPF4
+AiJLLkxCcP8NuzUKlW3WzNMSSoCtjkUKy4wjSLlAWCFM0T9Df6/+Z8ZUQTzHoKCD
+ncH5Qnynd7DlOwKQ2JwwxRhYGiGVTUN0GUq7qA11kW3+vnbFesKQXoF6o2PVx9s2
+YXviI2NXXUjZ0pVnsnFCc45Pm8XojwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQBP/aHOKJ00Akzc9HWM1X30hlWZFBaQi4pqD4Uhk8+p
+KzzwFP5DRLBOz8TYBbtdXrS6hxVMr2sqWmhVkuyepWhHZazKGyHY/y0FbOXsewAV
+1QxxSyx7ve89pCKv4/w0rQcP916iHc8Y/TCpmz7eITa3GId+8H/XTaBi8GBp9X9O
+w8m25FmEB1NT+eJwefvfdKowjy4tSorKdW/eJspxNuTSRGmUy8G71W5dYvgpAlx6
+mdnHyzxEGvRYNNI2bS0ifXgbEFNWqSas9q34ea5KOpkJu8T/KyXfSb6rPOsBSb0t
+wMowwGtCVH2C4Lw/8zo0EjhMpTOsPaub408PrZ+NQ2bl
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjjCCAfegAwIBAgIBBjANBgkqhkiG9w0BAQQFADBtMQswCQYDVQQGEwJERTEc
+MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEdMBsGA1UECxMUVGVsZVNlYyBU
+cnVzdCBDZW50ZXIxITAfBgNVBAMTGERldXRzY2hlIFRlbGVrb20gUm9vdCBDQTAe
+Fw05ODEyMDkwOTExMDBaFw0wNDEyMDkyMzU5MDBaMG0xCzAJBgNVBAYTAkRFMRww
+GgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR0wGwYDVQQLExRUZWxlU2VjIFRy
+dXN0IENlbnRlcjEhMB8GA1UEAxMYRGV1dHNjaGUgVGVsZWtvbSBSb290IENBMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBSz5BbO5EtdpcffqVjAIVxRDe7sa
+nG0vV2HX4vVEa+42QZb2ZM7hwbK5pBQEmFDocPiONZp9ScFhHVmu2gYYlX2tzuyp
+vtEYD0CRdiqj5f3+iRX0V/fgVdp1rQD0LME1zLRDJlViRC4BJZyKW/DB0AA1eP41
+3pRAZHiDocw5iQIDAQABoz4wPDAPBgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQE
+AwIBBjAZBgNVHQ4EEgQQLIdZH4sTgLL5hp0+En5YljANBgkqhkiG9w0BAQQFAAOB
+gQAP/nO1B4hvoAuJ6spQH5TelCsLJ15P9RyVJtqMllStGZE3Q12ryYuzzW+YOT3t
+3TXjcbftE5OD6IblKTMTE7w1e/0oL3BZ1dO0jSgTWTvI1XT5RcIHYKq4GFT5pWj/
+1wXVj7YFMS5BSvQQH2BHGguLGU2SVyDS71AZ6M3QcLy8Ng==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg
+bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ
+j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV
+Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw
+MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5
+fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i
++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
+QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+
+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx
+ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf
+WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK
+xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE
+zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F
+5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv
+OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz
+ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME
+lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG
+Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q
+gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k
+Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/
+k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso
+LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o
+TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3
+MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C
+TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5
+WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
+xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL
+B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy
+MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV
+p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw
+BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl
+5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi
+3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+
+QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ
+2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN
+I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL
+553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q
+10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN
+uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u
+ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh
+Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU
+MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D
+bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq
+RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G
+CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo
+6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux
+5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm
+AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC
+ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
+cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m
+by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp
+IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg
+Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg
+KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV
+HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E
+BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE
+FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7
+pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz
+wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a
+EkP/TOYGJqibGapEPHayXOw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIzCCAoygAwIBAgIENeHvHjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEuMCwGA1UECxMlRXF1aWZheCBQcmVtaXVtIENl
+cnRpZmljYXRlIEF1dGhvcml0eTAeFw05ODA4MjQyMjU0MjNaFw0xODA4MjQyMjU0
+MjNaME8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVF
+cXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQDOoQaOBswIC8GGqN4g1Q0O0Q3En+pq2bPCMkdAb4qI
+pAm9OCwd5svmpPM269rrvPxkswf2Lbyqzp8ZSGhK/PWiRX4JEPWPs0lcIwY56hOL
+uAvNkR12X9k3oUT7X5DyZ7PNGJlDH3YSawLylYM4Q8L2YjTKyXhdX9LYupr/vhBg
+WwIDAQABo4IBCjCCAQYwcQYDVR0fBGowaDBmoGSgYqRgMF4xCzAJBgNVBAYTAlVT
+MRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIw
+MTgwODI0MjI1NDIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUFe6yKFmrbuX4
+z4uB9CThrj91G5gwHQYDVR0OBBYEFBXusihZq27l+M+LgfQk4a4/dRuYMAwGA1Ud
+EwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEB
+BQUAA4GBAL0LnCepA9so3JipS9DRjqeoGlqR4Jzx9xh8LiKeNh/JqLXNRkpu+jUH
+G4YI65/iqPmdQS06rlxctl80BOv8KmCw+3TkhellOJbuFcfGd2MSvYpoH6tsfdrK
+XBPO6snrCVzFc+cSAdXZUwee4A+W8Iu0u0VIn4bFGVWgy5bFA/xI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8WgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9Gb3J0RW5n
+aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz
+aW9uMRMwEQYDVQQDEwpmb3J0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBmb3J0
+ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw
+CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV
+BAoTD0ZvcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmZvcnRlbmdpbmUxIDAeBgkqhkiG9w0B
+CQEWEWNhQGZvcnRlbmdpbmUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAyr7GbpwDxx1v3EYbo0gcO+ligEhlDqG2e7u/AbWGoVAqc8+q6auUJUtz
+4i7oh0yNadu1o9kpXW+znkgO0zlrgjGskqqMO1ooppzTJdFy/P8gR6x1Iuv3kWtX
+OuzwPPEjv09LWlhyJsN+oU4ztTVf07I0Q9zYupcoDQ58XKRheI9KdDB2DYSmxywA
+WSLQwIeG0Qa7gvokeQlpkgkEC7viEecJ3752KXBJHnh7As51mxnlpmG6sDy67Eli
+HDw5tHETRqbtnscGBjskGQBqR5xt7+QnnthZrN8HJHDoa9zgGephwizhkL44lXLF
+YK9W5XhFbblw2c+mAcHkokRiwD7CPeIoyD2a/Jcw3n5hegKTlNhd4BFGVF6JR7gF
+OFk2QfHXit5uthsij9Xhl7WAgQUqLgggD9MphqPf4nY66OZUJV9ZsmB+Qfp8UizB
+0WAOegactKVyRqHtRa+KIEXQXNtZgjcmMk9CYkP0nIbKtgKXaH6+9VMHNOryCnFE
+7pSsuPUkypncFWCHGSeiFO3w4w4J4csltxBADQzxfRu5KZnlToQN7bVpI/Q31tVX
+E5bjrJcq6Oj/OTqZ3ID+OqbkUdAg0ggjRKcTgxnLHd/AbMzJ6PsclDDf7cLs0WSl
+xMxQR/z5bNST1rNtT9rsiv2TOhfvCBxO9AOjBioO8PLO032HTNECAwEAAaMQMA4w
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAVyBpPWfT2VOyvVpslGKx
+8h0+CWP8cilygGRtZJ5dAJzc//1REAHdvK+TgZ4Foz3dqHhXI+RNN0FpzuWaYMjW
+ZTS0kAmcOQuGY1Oo4PGlPHI21pNz29oFDTJr0ZmLBJ4JKVsE2soJg55jdk9MZHA7
+K//7HH9RsmrWZOE5DZDlrxp6+naixhMwnlPKKisIy9GNZUPqGdUWABMdB/BUVVNl
+NU5TtWpIXUClMd8a+eoKcItBeYXowkHOBpinPkDX3clFDIUfWiw0Ro08s8SrrFqR
+8Szwbrj52Xv1RM56oGqCjnkvJctxihODV7NcpxoAFjIZokDom0q6zPrrTUsLFQov
+Plovc3w5hmALiDMshaTvE1nm3Psn4yQ+FlRE8epTZrQiIGypZkZC6lcz0mYawueW
+cThYWGFhVG4ktQzOjjNRsNxopW+W7cF1zQTxiWUDnxIKSj7gtdQ2jiubxEEhfVag
+r8DMtAccNVTZVURpGi56TptOOuotrTqqC+2GviW4hlxvdvmuQN0OlXlUwzz2Trxc
+FamNnuA54lZw/8arLtxsFmHrcnPw53+1spumLD0S5UkxHNu40h6LIVpZz3H+0rLz
+uFofTfiyMjcfK2AyHQTgUCbsrvgNuLDQUbyFGVchdFUkhztX3DhEVnxnnrpY4BVj
+QdTqWIvw7lGlSuDCjxEQAOc=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICETCCAXoCAU4wDQYJKoZIhvcNAQEEBQAwUTELMAkGA1UEBhMCSlAxHzAdBgNV
+BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xITAfBgNVBAMTGEN5YmVyVHJ1c3Qg
+SkFQQU4gUm9vdCBDQTAeFw05ODA4MDQwNzU3MDBaFw0wMzA4MDQyMzU5MDBaMFEx
+CzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFuLCBJbmMuMSEw
+HwYDVQQDExhDeWJlclRydXN0IEpBUEFOIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEB
+BQADgY0AMIGJAoGBALet/MpHEHaJ/Wes5HMGfIFLHda1fA5Hr+ymVHWoxP1lr+fI
+sbFsNDWN97lkVygLIVredP7ceC6GRhJMfxEf3JO9X75mmIa4t+xtSdOQ2eF5AFZo
+uq1sHyw7H8ksjEOwBELqgXOmzjN1RQ2KRXIvqldV5AfDQ+J1Og+8PNCEzrrvAgMB
+AAEwDQYJKoZIhvcNAQEEBQADgYEAt6ZkowyAPBzE2O5BO+WGpJ5gXdYBMqhqZC0g
+cEC6ck5m+gdlTgOOC/1W4K07IKcy+rISHoDfHuN6GMxX2+bJNGDvdesQFtCkLnDY
+JCO4pXdzQvkHOt0BbAiTBzUmECVgKf8J5WSfabkWSfNc3SRjRpMNsFM2dbxIILsZ
+to/QIv0=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICIzCCAYwCAU8wDQYJKoZIhvcNAQEEBQAwWjELMAkGA1UEBhMCSlAxHzAdBgNV
+BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xKjAoBgNVBAMTIUN5YmVyVHJ1c3Qg
+SkFQQU4gU2VjdXJlIFNlcnZlciBDQTAeFw05ODA4MDQwODA2MzJaFw0wMzA4MDQy
+MzU5MDBaMFoxCzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFu
+LCBJbmMuMSowKAYDVQQDEyFDeWJlclRydXN0IEpBUEFOIFNlY3VyZSBTZXJ2ZXIg
+Q0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKwmo6G4b2rALBL52zEFkuf9
++tSBtLjVKtWQ+vBDZfwSFcrs27lh3jNjN0+vADx/kjcbGHPlnzyI8RoTRP558sMm
+lQ8L8J4UByFsV8Jdw+JRsM2LX81fhjj4eZc57Oi/Ui6xXqqprozt7tfIty4xi7Q5
+kjt8gScHGgFEL0lzILbJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAaB17Eu5aeSkx
+ygGsi1CpJ5ksAPw4Ghz/wtXwE/4bpzn1gBTrUfrAjXuEG1musTVRbqE+1xvsoJ7f
+4KWCluOxP9io8ct5gI738ESZfhT1I6MR42hLBTZuiOOrhqo4UwNCO9O5+eC/BenT
+X8NKp7b9t12QSfiasq1mpoIAk65g/yA=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgICAbYwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVVMx
+GDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1
+c3QgU29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290
+IDUwHhcNOTgwODE0MTQ1MDAwWhcNMTMwODE0MjM1OTAwWjBwMQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xHjAcBgNVBAMTFUdURSBDeWJlclRydXN0IFJv
+b3QgNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwSbj+KfHqXAewe
+uzlaAvR4RKJIG457SVJ6uHtHs6+Um2+7lvoramVcuByUc76/iQoigO5X/IwFu3Cf
+lzkE2qOHXKjlyq/AM5rVN1xLrOSA0KYjYPv9ci6UncfOwgQy73hgXe2thw9FZR48
+mgqavl0dmezn8tHGehfZrZtUln/EfGC/haoVNR1A2hG87FQhKC0joajwzy3N3fx+
+D17hZQdWywe00lboXjHMGGPEhtIthc+Tkqtt/mg5+95zvYb45EZ66p8My/QZ/mO8
+0Sx7iDM29uThnAxTgWAc2i6rlqkWiBNQmbK9Vd8VMH7o5Zj7cH5stQf8/Ea30O03
+ln4y/iECAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMC
+AQYwFwYDVR0gBBAwDjAMBgoqhkiG+GMBAgEDMBkGA1UdDgQSBBB2CkkhOEyf3vjE
+ScdxcZGdMA0GCSqGSIb3DQEBBQUAA4IBAQBBOtQYW9q43iEc4Y4J5fFoNP/elvQH
+9ac886xKsZv6kvqb7eYyIapKdsXcTzjl39WG5NXIdn2Y17HNj021kSNsi4rr6nzv
+FJTExvAfSi0ycWMrY5EmAgm2gB3t4sy4f9uHY8jh0GwmsTUdQGYQG82VVBgzYewT
+T9oT95mvPtDPjqZyorPDBZrJJ32SzH5SjbOrcG2eiZ9N6xp1wpiq1QIW1wyKvyXk
+6y28mOlYOBl8uTf+2+KZCHMGx5eDan0QAS8yuRcFSmXmL86+XlOmgumaUwqEdC2D
+ysiUFnZflGEo8IWnObvXi9moshMdVAk0JH0ggX1mfqKQdFwQxr3sqxvC
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv
+b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU
+cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv
+RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M
+ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5
+1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz
+dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl
+IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy
+bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgILAgAAAAAA1ni50a8wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xv
+YmFsU2lnbiBQYXJ0bmVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBANIs+DKsShJ6N8gpkaWujG4eDsA0M4jlM3EWHHiEaMMYNFAuFj6xlIJPsZqf
+APjGETXGaXuYAq0ABohs50wzKACIJ0Yfh7NxdWO8MruI3mYYDlAGk7T2vBQ3MD0i
+3z3/dX7ZChrFn7P80KyzCHqJ0wHoAFznSgs9TXsmordiBovaRt2TFz8/WwJLC7aI
+IBGSAK27xy7U40Wu9YlafI2krYVkMsAnjMbyioCShiRWWY10aKKDQrOePVBBhm8g
+bvb9ztMZ4zLMj+2aXm0fKPVSrG4YXvg90ZLlumwBiEsK8i3eZTMFQqBMqjF2vv2/
+gXj5cRxGXi0VlS0wWY5MQdFiqz0CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgAGMB0G
+A1UdDgQWBBRDJI1wFQhiVZxPDEAXXYZeD6JM+zAfBgNVHSMEGDAWgBRge2YaRQ2X
+yolQL30EzTSo//z9SzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IB
+AQBm7bSIaRGZgiGDrKFti5uErQ8tyB6Mynt+rarUjt4H1p5Fx6W4nAc5YCVVGsBP
+GeXPFylJiRg1ZuXrKEBOV8mvs+S4IAWjO5VQkUmUKX0s5YhBpUWIXp2CJ/fS71u1
+T5++/jVlLFVkn+FR2iJhd7pYTo/GeVlZbjCAok+QbiELrdBoOZAQm+0iZW8eETjm
+f4zS8zltR9Uh6Op1OkHRrfYWnV0LIb3zH2MGJR3BHzVxLOsgGdXBsOw95W/tAgc/
+E3tmktZEwZj3X1CLelvCb22w0fjldKBAN6MlD+Q9ymQxk5BcMHu5OTGaXkzNuUFP
+UOQ9OK7IZtnHO11RR6ybq/Kt
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4N88wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MTUxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDEgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAxIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAvSA1R9Eo1gijEjkjRw29cCFSDlcxlaY0V2vsfkN5
+wwZSSM28taGZvdgfMrzP125ybS53IpCCTkuPmgwBQprZcFm2nR/mY9EMrR1O+IWB
++a7vn6ZSYUR5GnVF4GFWRW1CjD1yy6akErea9dZg0GBQs46mpuy09BLNf6jO77Ph
+hTD+csTm53eznlhB1lGDiAfGtmlPNt7RC0g/vdafIXRkbycGPkv9Dqabv6RIV4yQ
+7okYCwKBGL5n/lNgiCe6o3M0S1pWtN5zBe2Yll3sSudA/EsJYuvQ4zFPhdF6q1ln
+K/uID+uqg701/WEn7GYOQlf3acIM7/xqwm5J2o9BOK5IqQIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFPzgZvZaNZnrQB7SuB5DvJiOH4rDMB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAJujCETO8pCdcfMyswVqterPKZjeVT6gFn0GekTWr9L6
+E1iM+BzHqx20G+9paJhcCDmP4Pf7SMwh57gz2wWqNCRsSuXpe2Deg7MfCr5BdfzM
+MEi3wSYdBDOqtnjtKsu6VpcybvcxlS5G8hTuJ8f3Yom5XFrTOIpk9Te08bM0ctXV
+IT1L13iT1zFmNR6j2EdJbxyt4YB/+JgkbHOsDsIadwKjJge3x2tdvILVKkgdY89Q
+Mqb7HBhHFQpbDFw4JJoEmKgISF98NIdjqy2NTAB3lBt2uvUWGKMVry+U9ikAdsEV
+F9PpN0121MtLKVkkrNpKoOpj3l9Usfrz0UXLxWS0cyE=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4jY0wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDIgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAyIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAkoz+7/RFjhdBbvzYvyFvqwadUsEsAJ0/joW4f0qP
+vaBjKspJJ65agvR04lWS/8LRqnmitvrVnYIET8ayxl5jpzq62O7rim+ftrsoQcAi
++05IGgaS17/Xz7nZvThPOw1EblVB/vwJ29i/844h8egStfYTpdPGTJMisAL/7h0M
+xKhrT3VoVujcKBJQ96gknS4kOfsJBd7lo2RJIdBofnEwkbFg4Dn0UPh6TZgAa3x5
+uk7OSuK6Nh23xTYVlZxkQupfxLr1QAW+4TpZvYSnGbjeTVNQzgfR0lHT7w2BbObn
+bctdfD98zOxPgycl/3BQ9oNZdYQGZlgs3omNAKZJ+aVDdwIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFHznsrEs3rGna+l2DOGj/U5sx7n2MB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAGPdWc6KeaqYnU7FiWQ3foqTZy8Q6m8nw413bfJcVpQZ
+GmlgMEZdj/JtRTyONZd8L7hR4uiJvYjPJxwINFyIwWgk25GF5M/7+0ON6CUBG8QO
+9wBCSIYfJAhYWoyN8mtHLGiRsWlC/Q2NySbmkoamZG6Sxc4+PH1x4yOkq8fVqKnf
+gqc76IbVw08Y40TQ4NzzxWgu/qUvBYTIfkdCU2uHSv4y/14+cIy3qBXMF8L/RuzQ
+7C20bhIoqflA6evUZpdTqWlVwKmqsi7N0Wn0vvi7fGnuVKbbnvtapj7+mu+UUUt1
+7tjU4ZrxAlYTiQ6nQouWi4UMG4W+Jq6rppm8IvFz30I=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni41sMwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDMgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAzIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAkV5WZdbAwAScv0fEXHt6MQH5WJaZ4xyEL9xWj631
+WYHVQ2ZdWpOMdcqp5xHBURAUYMks1HuvxneGq3onrm+VuQvKtkb7fhr0DRRt0slO
+sq7wVPZcQEw2SHToVIxlZhCnvSu3II0FSa14fdIkI1Dj8LR5mwE5/6870y3u4UmN
+jS88akFFL5vjPeES5JF1ns+gPjySgW+KLhjc4PKMjP2H2Qf0QJTJTk9D32dWb70D
+UHyZZ6S5PJFsAm6E1vxG98xvGD4X8O8LZBZX5qyG8UiqQ8HJJ3hzREXihX26/7Ph
++xsFpEs7mRIlAVAUaq9d6sgM7uTa7EuLXGgTldzDtTA61wIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFMw2zBe0RZEv7c87MEh3+7UUmb7jMB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAFeyVMy9lRdkYIm2U5EMRZLDPahsw8yyGPV4QXTYfaMn
+r3cNWT6UHWn6idMMvRoB9D/o4Hcagiha5mLXt+M2yQ6feuPC08xZiQzvFovwNnci
+yqS2t8FCZwFAY8znOGSHWxSWZnstFO69SW3/d9DiTlvTgMJND8q4nYGXpzRux+Oc
+SOW0qkX19mVMSPISwtKTjMIVJPMrUv/jCK64btYsEs85yxIq56l7X5g9o+HMpmOJ
+XH0xdfnV1l3y0NQ9355xqA7c5CCXeOZ/U6QNUU+OOwOuow1aTcN55zVYcELJXqFe
+tNkio0RTNaTQz3OAxc+fVph2+RRMd4eCydx+XTTVNnU=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9NYWlsRW5n
+aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz
+aW9uMRMwEQYDVQQDEwptYWlsZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBtYWls
+ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw
+CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV
+BAoTD01haWxFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCm1haWxlbmdpbmUxIDAeBgkqhkiG9w0B
+CQEWEWNhQG1haWxlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAqXmfsU+lx+NFmn6tN17RTOyaddHqLnr/3rzEDIyT9TN+tF9TG7jmK7lJ
+Jrj5arQ3nTFaLF8JuND2U1z/cLPw6/TX+1tE3v3CNUDSjaisyUDiUyp3TE8hMMMz
+zfZQn0JsGgNhhWxqyzjhRQGtKL4+xtn8VsF/8zGgZYke7nlmVKz/FslDFTnNoodL
+BAEGiu9JQS9qqpbSs20NdZ6LXPL2A4iTjnsNFBW3jIMVIn/JVVyaycU7ue2oFviD
+vLNpkVZcR7A+jjIdIumOc5VSF0y7y74cQC5YwkR2mLK7UBYDK6NCY3ta/C4M8NsM
+0FpmvRl0+A1ivZtVwqI98dxDtp7HeQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQAjfNn5BCzxylBDakFQGWKE/P43PRibMOEzfd7+DzbY
+WIekoz3i00DwoH3b6j4gwlDJRAOq4dF6/Pt/uBOHDo/op+ef+9ErmKPd+ehXN9h3
+7QbccTgz7DtVwA4iRlDRLru+JuXzT+OsCHuFZMOLJ+KD2JAGh3W68JjdcLkrlcpt
+AU0wc5aOHPPfEBdIah8y8QtNzXRVzoBt8zzvgCARkXxTS2u/9QaXR1hML0JtDgQS
+SdZ6Kd8SN6yzqxD+buYD5sOfJmjBF/n3lqFHNMHnnGXy2TAXZtIAWzffU3A0cGPB
+N6FZ026a86HbF1X4k+xszhbJu/ikczyuWnCJIg3fTYSD
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
+IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
+DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
+EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
+ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
+dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
+QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
+dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
+wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
+G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
+AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
+9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
+YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
+Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
+MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
+cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
+d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
+DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
+rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
+uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
+/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
+gQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
+dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
+bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
+BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
+IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
+bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
+Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
+Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
+ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
+KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIRIjCCCQoCAQAwDQYJKoZIhvcNAQEFBQAwVzEPMA0GA1UEChMGVGhhd3RlMSEw
+HwYDVQQLExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QxITAfBgNVBAMTGFRoYXd0
+ZSBVbml2ZXJzYWwgQ0EgUm9vdDAeFw05OTEyMDUxMzU2MDVaFw0zNzA0MDMxMzU2
+MDVaMFcxDzANBgNVBAoTBlRoYXd0ZTEhMB8GA1UECxMYVGhhd3RlIFVuaXZlcnNh
+bCBDQSBSb290MSEwHwYDVQQDExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3Qwgggi
+MA0GCSqGSIb3DQEBAQUAA4IIDwAwgggKAoIIAQDiiQVtw3+tpok6/7vHzZ03seHS
+IR6bYSoV53tXT1U80Lv52T0+przstK1TmhYC6wty/Yryj0QFxevT5b22RDnm+0e/
+ap4KlRjiaOLWltYhrYj99Rf109pCpZDtKZWWdTrah6HU9dOH3gVipuNmdJLPpby7
+32j/cXVWQVk16zNaZlHy0qMKwYzOc1wRby2MlYyRsf3P5a1WlcyFkoOQVUHJwnft
++aN0QgpoCPPQ0WX9Zyw0/yR/53nIBzslV92kDJg9vuDMGWXb8lSir0LUneKuhCMl
+CTMStWoedsSL2UkAbF66H/Ib2mfKJ6qjRCMbg4LO8qsz7VSk3MmrWWXROA7BPhtn
+j9Z1AeBVIt12d+yO3fTPeSJtuVcD9ZkIpzw+NPvEF64jWM0k8yPKagIolAGBNLRs
+a66LGsOj0gk8FlT1Nl8k459KoeJkxhbDpoF6JDZHjsFeDvv5FXgE1g5Z2Z1YZmLS
+lCkyMsh4uWb2tVbhbMYUS5ZSWZECJGpVR9c/tiMaYHeXLuJAr54EV56tEcXJQ3Dv
+SLRerBxpLi6C1VuLvoK+GRRe5w0ix1Eb/x6b8TCPcTEGszQnj196ZoJPii0Tq0LP
+IVael45mNg+Wm+Ur9AKpKmqMLMTDuHAsLSkeP1B3Hm0qVORVCpE4ocW1ZqJ2Wu4P
+v7Rn4ShuD+E2oYLRv9R34cRnMpN4yOdUU/4jeeZozCaQ9hBjXSpvkS2kczJRIfK7
+Fd+qJAhIBt6hnia/uoO/fKTIoIy90v+8hGknEyQYxEUYIyZeGBTKLoiHYqNT5iG3
+uIV7moW7FSZy+Ln3anQPST+SvqkFt5knv78JF0uZTK0REHzfdDH2jyZfqoiuOFfI
+VS3T+9gbUZm+JRs6usB9G+3O0km5z/PFfYmQgdhpSCAQo/jvklEYMosRGMA/G4VW
+zlfJ8oJkxt8CCS5KES+xJ203UvDwFmHxZ43fh3Kvh9rP+1CUbtSUheuKLOoh9ZZK
+RNXgzmp0RE3QBdOHFe020KSLZlVwk+5HBsF+LqUYeWfzKIXxcPcOg6R+VJ5adjLL
+ZRu4zfvIKAPSVJHRp8WFQwgXdqXmL2cI2KGigi0M+MGvY9RQd21rRkpBhdWQX3kt
+xOzXEYdAiuFo4mT4VTL7b5Ms2nfZIcEX5TYsTn6Qf6yUKzJnvjhQdriuQbnXIcUJ
+TGDIo1HENJtXN9/LyTNXi+v7dp8ZTcVqHypFrivtL42npQDLBPolYi50SBvKKoy6
+27Z+9rsCfKnD21h4ob/w/hoQVRHO6GlOlmXGFwPWB2iMVIKuHCJVP/H0CZcowEb3
+TgslHfcH1wkdOhhXODvoMwbnj3hGHlv1BrbsuKYN8boTS9YYIN1pM0ozFa64yJiK
+JyyTvC377jO/ZuZNurabBlVgl0u8RM1+9KHYqi/AAighFmJ42whU8vz0NOPGjxxD
+V86QGkvcLjsokYk/eto1HY4s7kns9DOtyVOojJ8EUz4kHFLJEvliV6O87izrQHwg
+I3ArlflzF4rRwRxpprc4mmf3cB16WgxAz2IPhTzCAk5+tfbFKimEsx83KuGqckLE
+7Wsaj5IcXb7R8lvyq6qp0vW4pEErK5FuEkjKmNg3jcjtADC1tgROfpzahOzA+nvl
+HYikU0awlORcG6ElLA9IUneXCWzsWxgzgwLlgn7NhSEwEf0nT8/kHuw/pVds6Sow
+GSqI5cNpOKtvOXF/hOFBw+HMKokgUi6DD2w5P0stFqwt8CSsAHP0m7MGPwW4FIUf
+q55cPJ5inQ5tO4AJ/ALqopd0ysf541bhw8qlpprAkOAkElPSwovavu0CQ15n4YmY
+ee7LqsrDG9znpUalfGsWh7ZaKNfbJzxepb22Ud0fQ887Jsg6jSVhwUn0PBvJROqv
+HMIrlAEqDjDRW4srR+XD0QQDmw45LNYn1OZwWtl1zyrYyQAF5BOI7MM5+4dhMDZD
+A8ienKIGwi/F/PCAY7FUBKBMqS7G9XZ62NDk1JQR5RW1eAbcuICPmakgMz0QhUxl
+Cco+WF5gk5qqYl3AUQYcXWCgDZxLQ/anFiGkh6rywS7ukjC4nt/fEAGLhglw2Gyo
+t1AeFpa092f9NTohkCoyxwB7TQcQCbkvc9gYfmeZBE8G/FDHhZudQJ2zljf6pdyy
+ck7vTgks/ZH9Tfe7pqE+q3uiA0CmqVUn4vr5Gc6HdarxdTbz87iR+JHDi3UTjkxl
+mhY5auU06HqWWX81sAD9W2n8Qyb69Shu/ofZfiT7tKCCblSi/66/YrT0cgHCy5hH
+mOFMtReAgM6PpijuHkVq+9/xHfxaO9bq9GwdYklXO4qPhurwUwTOnBZo/7q5/IgP
+R/cCRHJAuMo7LVOd3DxWjFl7aBosjXG7bADHGs5vQJKxoy8P2UTyo3Aunu4OrjLQ
+Oz6LB+rmebNcKeJ9a6he+Vox6AiWoowDmEbxuH2QVCbtdmL+numabl7JScdcNFMp
+VNns5EbhgDt12d/7edWH8bqe6xnOTFJz5luHriVPOXnMxrj5EHvs8JtxpAWg0ynT
+Tn8f9C0oeMxVlXsekS/MVhhzi7LbvGkH5tDYT+2i/1iFo23gSlO3Z32NDFxbe3co
+AjVEegTTKEPIazAXXTK4KTW6dto7FEp2GFik+JI8nk0zb0ZrCNkxSGjd9PskVjSy
+z2lmvkjSimYizfJpzcJTE0UpQSLWXZgftqSyo8LuAi9RG9yDpOxwJajUCGEyb+Sh
+gS58Y3L6KWW8cETPXQIDAQABMA0GCSqGSIb3DQEBBQUAA4IIAQBVmjRqIgZpCUUz
+x66pXMcJTpuGvEGQ1JRS9s0jKZRLIs3ovf6dzVLyve2rh8mrq0YEtL2iPyIwR1DA
+S4x2DwP1ktKxLcR6NZzJc4frpp/eD3ON03+Z2LqPb8Tzvhqui6KUNpDi5euNBfT8
+Zd+V8cSUTRdW1588j1A853e/lYYmZPtq/8ba6YyuQrtp5TPG2OkNxlUhScEMtKP5
+m0tc3oNPQQPOKnloOH3wVEkg9bYQ/wjcM2aWm/8G3gCe185WQ5pR/HDN9vBRo7fN
+tFyFYs1xt8YrIyvdw25AQvo3/zcc9npXlIeFI9fUycdfwU0vyQ3XXOycJe6eMIKR
+lnK4dR34CWhXl7ItS+4l7HokKe5y1JwT26vcAwrYShTJCFdEXaG1U4A08hSXz1Le
+og6KEOkU79BgvmGh8SVd1RhzP5MQypbus0DS26NVz1dapQ5PdUff6veQmm31cC4d
+FBw3ZARZULDccoZvnDc9XSivc1Xv0u4kdHQT79zbMUn7P2P10wg+M6XnnQreUyxR
+jmfbm0FlQVC91KSWbIe8EuCUx9PA5MtzWACD4awnhdadU51cvQo+A0OcDJH1bXv4
+QHJ1qxF2kSvhxqofcGl2cBUJ/pPQ1i23FWqbZ1y0aZ8lpn2K+30iqXHyzk6MuCEt
+3v5BcQ3/nexzprsHT4gOWEcufqnCx3jdunqeTuAwTmNvhdQgQen6/kNF5/uverLO
+pAUdIppYht/kzkyp/tgWpW/72M5We/XWIO/kR81jJP+5vvFIo8EBcua9wK3tJg3K
+NJ/8Ai0gTwUgriE9DMIgPD/wBITcz4n9uSWRjtBD5rMgq1wt1UCeoEvY9LLMffFY
+Co6H7YisNpbkVqARivKa0LNXozS7Gas44XRrIsQxzgHVGzbjHjhMM5PfQONZV06s
+bnseWj3FHVusyBCCNQIisvx16BCRjcR9eJNHnhydrGtiAliM1hwj1q94woCcpKok
+VBS1FJjG+CsaJMtxMgrimw5pa91+jGTRLmPvDn+xPohMnVXlyW4XBLdB/72KQcsl
+MW9Edz9HsfyBiAeOBUkgtxHZaQMqA525M4Sa399640Zzo9iijFMZiFVMdLj2RIQr
+0RQtTjkukmj/afyFYhvrVU/vJYRiRZnW2E5vP1MIfR0GlYGAf09OdDaYteKHcJjc
+1/XcUhXmxtZ5ljl/j5XPq4BTrRsLRUAO1Bi9LN6Kd3b98kRHxiHQ5HTw2BgFyHww
+csff8bv8AjCp9EImWQ2TBYKhc+005ThdzVCQ/pT8E7y9/KiiiKdzxLKo0V2IxAKi
+evEEyf6MdMnvHWRBn6welmdkrKsoQced98CYG24HwmR9WoNmVig2nOf7HHcOKKDE
+92t5OQQghMdXk7wboOq860LlqBH+/KxlzP34KIj0pZrlc1HgqJsNA3dO5eCYs4ja
+febGnnwUZsEuU0qSBzegfuk9CeQVfM/9uEGl755mncReBx2H+EGt6ucv0kFjGDf5
+FONN0OX3Q/0V4/k2cwYm3wFPqcNO3iBGd5i0eiQrO3UrTliNm12kxxagvDKIP6GD
+8wDI+NhY6WNdTCu18HJB2Kt3N9ZydK62NpzIpoNJS+DJVgspvgAwy93WyEKKANns
+FdE0cfJbZIf2J9K364awkL8p2yGeNozjIC+VI1FsG8Kk1ebYAkNnoP6bUANEf7vk
+ctXR5NqPkhRk+10UEBJKlQbJZQgpyiGjJjgRySffcGcE/cpIMn9jskV0MVBPh9kg
+cNIhcLHWEJ0zXXiDkW1Vguza5GJjx4FG1xllcipDGZC41yNNTBzgRKlmZ6zucXkn
+Jnhtcg71XUsjtXx8ZekXxjoLDd1eHlHDhrjsf8cnSqVG6GotGcGHo8uZk4dkolUU
+TLdDpZPX59JOeUDKZZlGPT96gHqIaswe5WszRvRQwNUfCbjNii6hJ+tdc6foawrl
+V4IqsPziVFJW8KupEsYjlgcknOC8RqW0IATaCZNj5dQuwn7FMe21FXSGF7mz8yaK
+HQJq2ho/6LrxBG2UUVTiWrRZgx1g0C1zzAe1Joz518aIke+Az10PoWDLRdRCItGx
+cB390LcwkDrGSG1n5TLaj9vjqOMdICWiHOFMuaT2xj9cWA27xrJ3ARaRnxcGDbdA
+PsyPjpxL4J1+mx4Fq4gi+tMoG1cUZEo+JCw4TSFpAHMu0FUtdPIV6JRDPkAqxsa5
+alveoswYUFRdTiqFbPaSiykZfufqSuAiKyW892bPd5pBdPI8FA10afVQg83NLyHb
+IkaK0PdRGpVX8gWLGhntO0XoNsJufvtXIgAfBlOprpPGj3EqMUWS545t5pkiwIP8
+79xXZndPojYx+6ETjeXKo5V9AQxkcDtTQmiAx7udqAA1aZgMqGfYQ+Wqz5XgUZWk
+Fz9CnbgEztN5ecjTihYykuDXou7XN0wvrLh7vkX28RgznHs3piTZvECrAOnDN4ur
+2LbzXoFOsBRrBz4f7ML2RCKVu7Pmb9b5cGW6CoNlqg4TL4MTI1OLQBb6zi/8TQT4
+69isxTbCFVdIOOxVs7Qeuq3SQgYXDXPIV6a+lk2p8sD7eiEc9clwqYKQtfEM1HkQ
+voGm6VxhnHd5mqTDNyZXN8lSLPoI/9BfxmHA9Ha+/N5Oz6tRmXHH33701s8GVhkT
+UwttdFlIGZtTBS2dMlTT5SxTi2Q+1GR744AJFMz+FkZja3Fp+PnLJ/aIVLxFs84C
+yJTuQFv5QgLC/7DYLOsof17JJgGZpw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID6TCCAtGgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRowGAYDVQQKExFUcmFkZXJF
+bmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2
+aXNpb24xFTATBgNVBAMTDHRyYWRlcmVuZ2luZTEiMCAGCSqGSIb3DQEJARYTY2FA
+dHJhZGVyZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBa
+MIGuMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8x
+GjAYBgNVBAoTEVRyYWRlckVuZ2luZSBJbmMuMSkwJwYDVQQLEyBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBEaXZpc2lvbjEVMBMGA1UEAxMMdHJhZGVyZW5naW5lMSIw
+IAYJKoZIhvcNAQkBFhNjYUB0cmFkZXJlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAzyX5QE+5SN+zgNn1v3zp9HmP4hQOWW8WuEVItZVP
+9bt/xj5NeJd1kyPL/SqnF2qHcL3o/74r0Ga55aKHniwKYgQTlp5ELGfQ568QQeN9
+xNIHtUXeStI9zCNZyZC+4YqObdMR/ivKA/WsLfUVMl2lV5JzJJz1BOE0gKEYiEyz
+gIq5oLzkP/mOXoHRvWSZD2D0eHYIO7ovV2epVFK7g7p+dC4QoeIUEli+GF/Myg88
+dV/qmi+Sybck2RLPXa8Nh27/ETVQ7kE1Eafmx7EyCqIhG+5lwJAy3HwHUBwAYuzj
+iuZz5lD8aQmr8SKuvy3eOH9SVN5wh3YBlrNGwTStkESVLwIDAQABoxAwDjAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAWOPAUhZd3x9EQiFJcuxFTMd9q
+axgcriCzJsM6D96sYGko9xTeLhX/lr1bliVYI5AlupoLXAdMzGHJkOgaTirKjQXr
+F9nymDdUWKe3TmwGob5016nQlH7qRKvGO3hka0rOGRK2U/2JT/4Qp8iH/DFi6cyM
+uP0q8n64SAkxZXLzUuFQXqf7U/SNjzb9XJQEIAdjp7eYd3Qb4jDsDcX0FrKMF1aV
+r0dCDnS7am7WTXPYCDGdSkPgEHEtLYIYH3lZp5sKdVZ9wl4F0WNFkRWRUr7AXPjw
+50uLmUNmKCd8JZLMGA1TRNSTi7U9EcrWt0OkMWm74T2WVnAgNsDv2WrWsGfj
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEeDCCA+GgAwIBAgICJ0swDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMx
+JTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsT
+EHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4
+MTYyMTA2MzlaFw0yMDA4MTUxMzA2MjVaMG4xCzAJBgNVBAYTAlVTMSUwIwYDVQQK
+ExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNw
+cy5jb20vQ1BTMR0wGwYDVQQDExRVU1BTIFByb2R1Y3Rpb24gQ0EgMTCBnzANBgkq
+hkiG9w0BAQEFAAOBjQAwgYkCgYEAxta577JTOMrSdwxsNigwwtAoAnhxTg2JQsdZ
+J7OQCCfUl1oetnhEQGt0xo2rUYvopu1RptZ1F+x6VF5Wg+fwbcRJ9Be9BgsSxlXv
+6ajhKC+gQ4919P/Z3H3+qtR485yTxZnaYkab9XYkVAkKKesURUIL/w12Ax+nZYii
+pH9v0E8CAwEAAaOCAiswggInMIHPBgNVHSAEgccwgcQwgcEGB2CGSIb5bWUwgbUw
+IwYIKwYBBQUHAgETF2h0dHA6Ly93d3cudXNwcy5jb20vQ1BTMIGNBggrBgEFBQcC
+AjCBgBp+U2VlIFVTUFMgQ1BTIGF0IGh0dHA6Ly93d3cudXNwcy5jb20vQ1BTLiBU
+aGlzIGNlcnRpZmljYXRlIGlzIHRvIGJlIHVzZWQgb25seSBpbiBhY2NvcmRhbmNl
+IHdpdGggVVNQUyByZWd1bGF0aW9ucyBhbmQgcG9saWNpZXMuMCQGCWCGSIb5bWQC
+BgQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwJAYJYIZIhvltZAIIBBcwFaADAgEB
+oQMCAQKiAwIBAaMEAgInFTAkBglghkiG+W1kAgcEFzAVoAMCAQGhAwIBAqIDAgEB
+owQCAidLMBAGCWCGSIb5bWQCAQQDCgECMBAGCWCGSIb5bWQCAwQDCgEHMBkGCWCG
+SIb5bWQCBAQMMAqgCBoGTm9Sb2xlMB0GA1UdDgQWBBQl5aDvLXJPbZUfNx8g1sMB
+RAPH0DAfBgNVHSMEGDAWgBTTzoJ08y9LiWBypF4Rv191A6ICqzAdBgNVHRIEFjAU
+gRJyb290MTAwMDFAdXNwcy5jb20wIQYDVR0RBBowGIEWY2FhZG1pbkBlbWFpbC51
+c3BzLmNvbTAPBgNVHQ8BAf8EBQMDB8YAMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQEFBQADgYEAcAmQhgkD1rSyWiOrPGVEr/WndJfcCC4EyFOXrWGpwjCKu2jT
+wWbAzS70nbA+qWPj718XgmaQb3C+LUJkQWJ/IiXBtc9WOTF3bqCT+Rqpw9wKcHbF
+tS2bl4N2zgJeyG3dgrDqW1kNCYdAh3G+xaiXBbxD++6tJgq8e0VfjlmoK4o=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAtegAwIBAgICJxEwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMx
+JTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsT
+EHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4
+MTUxOTM1NThaFw0yMDA4MTUxOTM1NThaMGYxCzAJBgNVBAYTAlVTMSUwIwYDVQQK
+ExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNw
+cy5jb20vQ1BTMRUwEwYDVQQDEwxVU1BTIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEB
+BQADgY0AMIGJAoGBALepJaxj2rCSz5Q2sAT/Fm52BFv1xjyfxrlCJlX7k3GFEWXJ
+YSeIxF6b/ip4SlJqRZ+o+5G04yZd9UMUJrnePG0sZvVTfd7kVleyonn14bTaavck
+5bMo/p53luIOxwUDzOlR9pb8EcCWLXM1/1hzX/JINeVES9B+1QAehG3YJdjRAgMB
+AAGjggEpMIIBJTAkBglghkiG+W1kAgYEFzAVoAMCAQGhAwIBAqIDAgEBowQCAicR
+MCQGCWCGSIb5bWQCBwQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwEAYJYIZIhvlt
+ZAIBBAMKAQEwEAYJYIZIhvltZAIDBAMKAQYwUwYJYIZIhvltZAIEBEYwRKA0GjJD
+QSBNQVNURVIgUlNBIDEwMjQgQmVyIChTRUxGIFNJR04pIChDaHJ5c0FsaXMgQ1NQ
+KaEMMAqhAwoBAKIDAwEAMB0GA1UdDgQWBBTTzoJ08y9LiWBypF4Rv191A6ICqzAd
+BgNVHREEFjAUgRJyb290MTAwMDFAdXNwcy5jb20wDwYDVR0PAQH/BAUDAwfGADAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAI7SbReJ5I5NalEKF2AR
+ay289lC8DMpJqaw7qotxs9HL9hx+IkIh6av2EiAybbIYKhFpcdjKWUqYrTKYo5hj
+UW0jIfJRrqB3giO7nciBgas7CFr6y02kLHfLYKik//iMkFQtsLSDSguwPOvsY5vl
+lP4Fo94aBCf2/0+o6iQIKyWa
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICMTCCAZoCBQKmAAABMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBa
+Fw05OTEyMzEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2ln
+biwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LJ1
+9njQrlpQ9OlQqZ+M1++RlHDo0iSQdomF1t+s5gEXMoDwnZNHvJplnR+Xrr/phnVj
+IIm9gFidBAydqMEk6QvlMXi9/C0MN2qeeIDpRnX57aP7E3vIwUzSo+/1PLBij0pd
+O92VZ48TucE81qcmm+zDO3rZTbxtm+gVAePwR6kCAwEAATANBgkqhkiG9w0BAQIF
+AAOBgQBT3dPwnCR+QKri/AAa19oM/DJhuBUNlvP6Vxt/M3yv6ZiaYch6s7f/sdyZ
+g9ysEvxwyR84Qu1E9oAuW2szaayc01znX1oYx7EteQSWQZGZQbE8DbqEOcY7l/Am
+yY7uvcxClf8exwI/VAx49byqYHwCaejcrOICdmHEPgPq0ook0Q==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
+NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
+VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
+bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
+H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
+4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
+BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
+EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
+FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
+lA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
+VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
+Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
+h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
+uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
+DzFc6PLZ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
+nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
+8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
+ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
+PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
+6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
+n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
+qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
+wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
+pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
+E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
+YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
+FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
+J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
+r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
+YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
+Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
+IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
+KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
+HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
+DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
+nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
+rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
+jBJ7xUS0rg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
+Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
+BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
+Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
+Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
+J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
+JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
+wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
+koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
+qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
+Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
+xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
+7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
+sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
+cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
+HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
+qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
+cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
+cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
+T8qAkbYp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICIzCCAZACBQJBAAAWMA0GCSqGSIb3DQEBAgUAMFwxCzAJBgNVBAYTAlVTMSAw
+HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVy
+Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NDExMDQxODU4MzRaFw05
+OTExMDMxODU4MzRaMFwxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBT
+ZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVyY2lhbCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTCBmzANBgkqhkiG9w0BAQEFAAOBiQAwgYUCfgCk+4Fie84QJ93o
+975sbsZwmdu41QUDaSiCnHJ/lj+O7Kwpkj+KFPhCdr69XQO5kNTQvAayUTNfxMK/
+touPmbZiImDd298ggrTKoi8tUO2UMt7gVY3UaOLgTNLNBRYulWZcYVI4HlGogqHE
+7yXpCuaLK44xZtn42f29O2nZ6wIDAQABMA0GCSqGSIb3DQEBAgUAA34AdrW2EP4j
+9/dZYkuwX5zBaLxJu7NJbyFHXSudVMQAKD+YufKKg5tgf+tQx6sFEC097TgCwaVI
+0v5loMC86qYjFmZsGySp8+x5NRhPJsjjr1BKx6cxa9B8GJ1Qv6km+iYrRpwUqbtb
+MJhCKLVLU7tDCZJAuqiqWqTGtotXTcU=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDWDCCAkCgAwIBAgICAx0wDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMB4XDTAwMDgxNjIxNTIwMFoXDTIwMDgxNTIzNTkwMFow
+TTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50
+ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAxR1Nc0GV4SC0bGzOZ+p1BqzEBMJgLwiSzyDtbqnJcSZW
+ov3auwz4lQnJ+fIdz0SV7TFK2m3gvfx1FpbC7wp6DMe4tJBGLqkXCuBHRIR8HD0g
+RgZDQ4Vy613hA7wymsvuCcZXFbMu2jJgpxKYkpvTyiNCsCP3UGlOjJtooTcwkskh
+L2iKoNaEqVhNDOtVPboKRkj6wr65B8DsvZM0eTk9t5o0oAw9o/+ahOb64D+qVIQB
+M0qFxqgUXhXB12DV8Gl4aWR41xTuE9ij8v91YThs1Cay12iIGWcO6+G/vI6a6siU
+6bbM+BWFk21mdyuxFwuIJmxGot/OQ6Vu9/0bR25Y9wIDAQABo0IwQDAOBgNVHQ8B
+Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUy8PGY8recX/bp9f/
+QnT2y8y2UDIwDQYJKoZIhvcNAQEFBQADggEBALYYhKS+5n/N+0aRFH0AQHd3hrmN
+cR2c/vHY5QE/2aJgG826czQs7l4EksQiRFbs6vv3yQEW/ego7fje/Tw+LpiMjeN4
+4s+Oi+CvwY1gFIKCVrGHLvDpEhUdPmkKrY6mWPSZ/BFG7vfJ7cavLLmGJdKX/k+d
+2DLhwmZRc4YN3XXjivr0ijVm3YhnrXmo/Gn12/qvlbSckB9fwRbJyAiAGtcD8l5x
+o1ZjHkU2fXG+MWd0hi/Z7IjCIL2ZTT1VBdCiWkxVIpjQ8XX0F/rY4/7iFOAPZfqy
+1mksM1DJJ6CskDFLFOXrY2TgPeP8EkrFloIt2iU5/tR/LkHHYkjXcUU7eJI=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1
+MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX
+ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i
+/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU
+58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g
+halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E
+1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/
+ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb
+mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ
+kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN
+dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ
+ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn
+B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgICAx8wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDMwHhcNMDAwODE2MjMz
+NDAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALrsQ7g06qNn33cJHxoQoh6pTpVMdOcM3GzGmNCr+hckmmejSRRkiY+T
+Ei/vj9jOEASLhcDcL7wpmK+cQsXL0pbP9KXFLW5NjDiOsmoImdWRG6jtM5NJXcvn
+FUNtUvHI6NfaMOCYKqlbo8PRAQOBXX62CZXo2zJu/TrDtZ6b/VkZILMjwOJq7kSW
+gO9oCUCUwrczSYPlya4tIDeQGD0gNtp5Oa+4V59672AqIYT4/6A5IdPYbVTHw2o8
+yFwfLkdyFGxVSwkGzY7FawvnB0c6fZJffQ+wXDNXg4M/HoSoeZCfl04i3HUiyG4v
+1tDLduEMV5fhJo8phFPy5Y6TykuKTDUCAwEAAaNCMEAwHQYDVR0OBBYEFKJcbg1l
+CMH3TlvJbfDQVhs5gkO7MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQADjVYIs6Gt/XNC2WcsbprPvx7ITfJN0tk3yThE
+ja6JDO+MmStKk/VtrGZKP1dqEKWiGhOmLOpi54D5vf3k/9oRnzlYbfVD8vT9pr+d
+sauaRgff4fBbP/5dWUAGrBgIR0w8TEhGzojhqLaedaag934btsSN7fAqUxVK2ylP
+OVPnUlijvtzkkC21yc6Y/yyGoQigyM73gjkJDMHC1KmkKg4zgcc8cMswbaRWt5tc
+fAIivuUHfW0k0Sex1h0eXEc8vy5u+ByESOz14aCVEc3nMOtc8Cl7dYICBrLzkznS
+DqzfXyQTFTBD9VDUx4OgQzlPZTS9punO4XS+IN/SchZLiUZ2
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICezCCAeSgAwIBAgICAyAwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDQwHhcNMDAwODE3MDAx
+OTAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEAuOvwj6Dm8eMAP15ynq4ED/RPzsraYjPq7lrCwfYuOIm0Dc+hrrkxs/2mx7bE
+bIMMgGE4Ogq+HAGgGRvn+3JtkmObpq8z9LRbGugo3kznN/EU8eAX4BRI7EQdeaVO
+quGkhHe9y0226nB+X6oXLEtbsOqF1GmoEekrNx27pgTum0ECAwEAAaNCMEAwHQYD
+VR0OBBYEFEPGSEDAD8YYWklJ5YGABk1f3dSFMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAKQZPXPOh9GfVhJcyDjl7vkS
+yNkB6p2DNMaia4t3epJ+h8dVIxSNwmhNGfJptOpHFJE7UYcY+nab4nscE9PmZh4K
+ErldkMY7ExQizTWMLUVgAATI71gCxV2ZtJBt3lTXI+I5hCXDaKNio3nYmKFa0lyJ
+/eUWDPSrF0h+reuAwFWB
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICezCCAeSgAwIBAgICAyEwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDUwHhcNMDAwODE3MDAy
+ODAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgNTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEArQBu8qB8MREcQbA3j4OiQ8uXXwIgiQ1uvCqx8aVk79iOStZynZ5uH5qo+YUD
+rMEnaoTlZkhxml5CD4rin/aADyOsU8PBnwLE+FhG6vSpgq9tB0aG8S38BrgeVdU5
+YZKEi/HYijNOPBO11nH8az60HHoLh9U1ZjTDczJjWN8SayMCAwEAAaNCMEAwHQYD
+VR0OBBYEFCNO8wIEBNfSpwBWwc5JLIwVljMvMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBADyUAYfyyM/hj665C+IcffEZ
+rdHt9gFbNlMKgD6uNFZncG5DVE55zYvVUBky2Ek4NP22c0nrDkl6vxr36gcoJbsV
+SRxRSlWaOC8tD1j5edECZROMWZ8Qf10XPHTytep3gTaGbzJbBbQNoyZn8OQ1Dke9
+a8GRnQv0P5oRfJQWZ7aY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID+DCCAuCgAwIBAgIRANAeQJAAACdLAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw
+gYwxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMRcwFQYDVQQHEw5TYWx0IExh
+a2UgQ2l0eTEYMBYGA1UEChMPWGNlcnQgRVogYnkgRFNUMRgwFgYDVQQDEw9YY2Vy
+dCBFWiBieSBEU1QxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAe
+Fw05OTA3MTQxNjE0MThaFw0wOTA3MTExNjE0MThaMIGMMQswCQYDVQQGEwJVUzEN
+MAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxGDAWBgNVBAoT
+D1hjZXJ0IEVaIGJ5IERTVDEYMBYGA1UEAxMPWGNlcnQgRVogYnkgRFNUMSEwHwYJ
+KoZIhvcNAQkBFhJjYUBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCtVBjetL/3reh0qu2LfI/C1HUa1YS5tmL8ie/kl2GS+x24
+4VpHNJ6eBiL70+o4y7iLB/caoBd3B1owHNQpOCDXJ0DYUJNDv9IYoil2BXKqa7Zp
+mKt5Hhxl9WqL/MUWqqJy2mDtTm4ZJXoKHTDjUJtCPETrobAgHtsCfv49H7/QAIrb
+QHamGKUVp1e2UsIBF5h3j4qBxhq0airmr6nWAKzP2BVJfNsbof6B+of505DBAsD5
+0ELpkWglX8a/hznplQBgKL+DLMDnXrbXNhbnYId26OcnsiUNi3rlqh3lWc3OCw5v
+xsic4xDZhTnTt5v6xrp8dNJddVardKSiUb9SfO5xAgMBAAGjUzBRMA8GA1UdEwEB
+/wQFMAMBAf8wHwYDVR0jBBgwFoAUCCBsZuuBCmxc1bWmPEHdHJaRJ3cwHQYDVR0O
+BBYEFAggbGbrgQpsXNW1pjxB3RyWkSd3MA0GCSqGSIb3DQEBBQUAA4IBAQBah1iP
+Lat2IWtUDNnxQfZOzSue4x+boy1/2St9WMhnpCn16ezVvZY/o3P4xFs2fNBjLDQ5
+m0i4PW/2FMWeY+anNG7T6DOzxzwYbiOuQ5KZP5jFaTDxNjutuTCC1rZZFpYCCykS
+YbQRifcML5SQhZgonFNsfmPdc/QZ/0qB0bJSI/08SjTOWhvgUIrtT4GV2GDn5MQN
+u1g+WPdOaG8+Z8nLepcWJ+xCYRR2uwDF6wg9FX9LtiJdhzuQ9PPA/jez6dliDMDD
+Wa9gvR8N26E0HzDEPYutsB0Ek+1f1eS/IDAE9EjpMwHRLpAnUrOb3jocq6mXf5vr
+wo3CbezcE9NGxXl8
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDYzCCAkugAwIBAgIQCgEBAQAAAnwAAAACAAAAAjANBgkqhkiG9w0BAQUFADA7
+MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhj
+ZXJ0IFJvb3QgQ0EwHhcNMDAwODE4MTgxODE3WhcNMjUwODE1MTkwMzE3WjA7MSEw
+HwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhjZXJ0
+IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCotGGLHRw+
+kHtwMkBtjRbKNWFhteL7Fcn0IV6BG88inKyru2DQoDPeEVMaCQ87GhOp1IfMWPct
+Uqmiwqk67c80naEC77jyuCtXiBCTtak1Y7sFQkMif79wXtMopVUoIEuTSY+nvz1A
+KA0Rr3ImCQU0CcWrAZNXoaxmVJginCPrugxknLY9++LGlsLPC0/qyDD6iivKHBGW
+GikAjOty1FFFqZ13INUSu7XyfwY4gk19kh7o1frIKUdpGhURjK+mLMEo9GlbaZ7k
+PBPuwKFg6kG/wmJLbaI3hDo+87AyroprbBPzOiEKe5ZYMylebqjKaaK+jgZFXfFm
+OVVKHFoksUvRAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB8GA1UdIwQYMBaAFESoSTh1MWyrKOdx8tjUyK9BD0eRMB0GA1UdDgQWBBRE
+qEk4dTFsqyjncfLY1MivQQ9HkTANBgkqhkiG9w0BAQUFAAOCAQEAPXNepQq7tRHD
+8WfREhqiRykRTE5ZNyCGCUDyRfFJeTkaPSXXLynQCAUVFPvkRGw/fl61UtiRWDyW
++9RK7/EuwVYeTGkM2WAdSkcntQMz2xi721OeoXtRapDTpRXIggvAtzcydYVUXlUQ
+fJE7qStgxjF2rMQwSQPEtlZApfBjr2lKiK/XqwvuOtu9E4OoO6LpuUX1UU2U8Fmp
+26E3Z9IUnqd71xmqFSNraXXREz5Y9PMB6IjElFbJwP7fT0dVH2uBTlTtE19y/CaG
+BDaPTxJNnFDiTlpWrLn9LB9YewUSB2M47xnj9DyRWqIlYle8xpSgd5zPNGLgv/t1
+POkbJhucZA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICaDCCAdGgAwIBAgIQCgEBAQAAAnwAAAADAAAAAjANBgkqhkiG9w0BAQUFADBA
+MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xGzAZBgNVBAsTElhj
+ZXJ0IFJvb3QgQ0EgMTAyNDAeFw0wMDA4MTgxODMxMzJaFw0yNTA4MTUxOTAwNTZa
+MEAxITAfBgNVBAoTGFhjZXJ0IEludGVybmF0aW9uYWwgSW5jLjEbMBkGA1UECxMS
+WGNlcnQgUm9vdCBDQSAxMDI0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW
+vjeJEami90csKs9qACZlKESkiuTeoENVmURrvG64x87GY7bT6G/FmCskkbieorpx
+SN40ICF61tLFiTKlicbchYRU8p5I7cxEtgb/jsTOWa2fbOkiWME/FApDgIcZUlDj
+KAfIrBjisRqqo+Jgt3ZRByk5XkjpZnCBLjiavRl96wIDAQABo2MwYTAPBgNVHRMB
+Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBSEecdPB1mxa8E6
+Nbq49NWZJ8i6DjAdBgNVHQ4EFgQUhHnHTwdZsWvBOjW6uPTVmSfIug4wDQYJKoZI
+hvcNAQEFBQADgYEAc7DhAO2uaNJgA0br+RzxpaZ8XDJ87AJh0xwdczEsuo69SU3I
+3dl3dUHnkiGabCnbp2xwhqBcw+TzMswBhFnXiDk486ji4hqwl80rF9xkBA+qanOU
+1usIxoBpTd561cU38ZIXPG3TiiHMZBCq3mKHH4+4+Kp1SvQILPXcZs/DOH4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAecCEAoBAQEAAAJ8AAAABAAAAAIwDQYJKoZIhvcNAQEFBQAwPjEhMB8G
+A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBS
+b290IENBIHYxMB4XDTAwMDgxODE4NDA1MFoXDTI1MDgxNTE5MDAzOFowPjEhMB8G
+A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBS
+b290IENBIHYxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwZKr8rY1
+NgJID4X0Ti+CZc1IvrG3PbN7rroyNIY8mL/4sL37wsz2CZc4XI2lI07hyITmkGd0
+O6P2bpkrj8MH0pdRB08Ey56y+Dz3OOaWSjrrFW/nYuZDMweyDVrPlSk5Z4gTI9SM
+bV+OIeAx87XcmcXE7YUQfpLUoh08HwuzI+bAyySbbBCmzRTWo51Tj/ceQZq2Gx0I
+XPc5QcMe3kwmo2B8LhOHkWzXwiMv530ZH81b6pjFuUZ9NUbke4tK2ZPgBqvAzEr9
+29oLMD+4XOAHE6jFMPy8hvaqvw5jL49JchDRnoX5Qe1IPHgM/aAqBhuv091nL+xI
+L1FJNiK3SM1J7wIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCo3LMgLv1XSBAP5o1g
+Uht2HZxmoG/6aAbYp5zLoQyOJeiux986cK2p+CokvLzHqscJt7sQ6R9a1aIBRosF
+xKN1SQtAx7Frn9tYFmMyhFoQjWKWq5hmm7r6VggbumLz7zlr/GSxya7vXpThooD5
+CIMWEjaW2QmQ2Zg6rz2F2JEqkhxcuczVXHM4jntzUgy6n/KOv8h8ChO6cpGgOyDv
+iSrDDIBpVnMQ9GAZ4B4WSmSr/EY60AvTl7Fc2ZysGDogB3oi+bcQZbrs5lPUquTD
+Qbyb38LdmgFG1I5F7cnKFjSEjTJUPFRikI0aZlLN+hzMDPyx45PIp9nraGOP0H4u
+Ld0p
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICBDCCAW0CEAoBAQEAAAJ8AAAABQAAAAIwDQYJKoZIhvcNAQEFBQAwQzEhMB8G
+A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMR4wHAYDVQQLExVYY2VydCBS
+b290IENBIHYxIDEwMjQwHhcNMDAwODE4MTg1MDU2WhcNMjUwODE1MTkwMTA4WjBD
+MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xHjAcBgNVBAsTFVhj
+ZXJ0IFJvb3QgQ0EgdjEgMTAyNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+pwnD0qmmGXDsKelFezbg6j7JmXBA0bZg9N0jx1l5nR6lvjVjAObALmxAU+bRdkbx
+oMuDRVSYGc97mjj4dDMzP6klICgmXShxRoYgPTArq+ZN+j/qREBM+3PU3JZ09E7k
+ah0bl6B8MOHAc7YNond68Rj4SnFxnviodf5i+Ko9z30CAwEAATANBgkqhkiG9w0B
+AQUFAAOBgQB709VMf0yifnzXVmHZlZiFitdJ3IxHqgfsuNt5JJ7npZJXZgmPFLD+
+BPK9URC4OMOhEtuQg361Y1irM62XHkZQQhCsyKstHTVsxuZDUCgDoaz7EZX/6dVK
+D5HlA+SIMDwcdtGX8ArUh6AMmo9hztp+crM7UMCAhA8hIJRoKtqMvg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX
+VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD
+QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX
+DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl
+ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU
+ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT
+CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P
+6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM
+jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX
+2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N
+R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j
+rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV
+HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa
+gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1
+bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
+ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy
+YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl
+ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl
+cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0
+L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx
+CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV
+HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ
+KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo
+Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2
+jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe
+1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5
+mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc
+tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjTCCAXWgAwIBAgIDAQAhMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMxNTNaFw0xMjA3MTIxNjMxNTNaMEMxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xFzAVBgNVBAMTDkNlcnR1bSBM
+ZXZlbCBJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl73pZ9DFcn7Qy0qBZ
+K+So18cav7drUrJ8SiYOlDDVskt81+eIcL/4FelTSGjuAOvYdmm+HGYG998RPB0i
+Z+Ak67vXFJ537vRWOcu6aMjNuAwu8BOdc5eSgB0Y8X4+3LOYfugtaZa8mrEQ8Hit
+0yLE9UBcU9J+4PmkVGecmZ8jZQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQAlDS4aTmgK0YgmUvt/3zN7G2/ZrtBBCtONlUvC69c7
+TmLJWJ842y2AH7ryNXXkcsn6p0ZBTrTJ2tA2y/j2PXJeXrCkK/qAJIpM0l4u0MT7
+enY5akasduHp2NXMP9vDlgMy7elU2s3nkOT79gfh5XttC+5D/x4JDNi1DMAA9hk1
+6DK4zWmDVfjkiP/G3fEndtJgNDQsyqnaQ3E3bljv3f1KJTjZUvtA2Ml6MP2hFRhg
+ZPsxuhW8QXidQYNiua1h7XUUiPiERLDLWZmfY6dxGrHXjSTx3shHNaQM0qkDs9gS
+6UK8uWJN2bf2YBnvGmzy0IQvx5wDCH7h8AdaBD6DgIG1
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAiMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMDNaFw0xMjA3MTIxNjMyMDNaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyMQSaN5fA94hNE46
+bMKpGUb5yIPEowReGZzGttYBQnC6oUOy+iM3md8WerzXeBKf7iIZEDW2HAp7BKhS
+4rMB6taxT07vDtkNfEKwOk6X7dODw6KY4mxnzjmjh5pf2feKKJ3MoZxi2HAz2a6J
+vHKFMq8dAlGL2GBtLvzlFp2jwkMCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAWo3wgy+/0B7UiTCu4Wn1rvGRXIUtbPNp4Bc4PP/i
+1q6pPheIe0ooCopuqnDX9maTHhZeNpnApgCUSbyw71EaOremD7HjWXASRUTylhwL
+5FdSx+D6MgF2uW9uwZ+NErkeRJYT2aRXe5FBOVIseC4g93Ay0D8Hg50MkAC5pQqW
++8GSszT94NzT7ppIaMtq53PZpUtLGiL3UBZ5vUJ5pE4lLKD7Ce+pXzZevy/MnkMG
+D1L7LgjRWL17OcMlASFETyUTajNjvxMy+oM4C22rwHRh2WQrvgw5MO+Q3UyYA1r5
+VrSaqgQ1g06ZcQt+mhzoc2swlOSwm8iis8H6orR8xmCWrA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjzCCAXegAwIBAgIDAQAjMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMTdaFw0xMjA3MTIxNjMyMTdaMEUxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGTAXBgNVBAMTEENlcnR1bSBM
+ZXZlbCBJSUkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZjBbfGFmlsLjPe
+pWaDwG0LqhF11lWKabaHi1sQhK3qomHY7Em7qpL11dUQ1vsMcnnpzz/J0AEH6KDh
++yAyXV1SE/tVToLYYByZK+JGacLYIYF9aCwV8AhqyzOGurO5QX6vLboXB2WNnwmX
+hyNVKUgnUVy4ktAR2qZJIw5Bjsn/AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAIsLt3vKCZqd/gui45ovm3FSO6FLjzzq4pagPvbN
+nZ39HrhRaCpqkHDAj71L5L27U3eW2D4ILL0iUmZadbC4i3at/PUL9mjhGlajcCN8
+EF6IXGT87Tbcii735jRaaXSbEY4YhNOg9DPBoD4uJMkA8Z0Y/6lYmk4S6KUMCzzt
+t5zZBiWjdd08yFi5VGMvpE74KVOMdMa3JNVaR0XvT0Q8yXo1XKCrY9OFIxnhVgDb
+hzr9fwjKWDwu8kxhT9khAETm0BU2Buu+CTasaJdT/bBR2YEx9qcN7XyXTeDtkOO5
+QeGSqFgzquwjWEbKhf7l/e+efdRCg+ikH3O5snHB6iS+dgg=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAkMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMzVaFw0xMjA3MTIxNjMyMzVaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJVjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmyb1lKqCAKE4juAy
+6lpVNUl6aJ2DuWPSiJ3BBk3/6ty6I4Lr2Dpy1b1vjVelhaFsVKEDgK2JyQlk9XMq
+LPZI2Ql166mJiPKFg77aY/W78EcQfGyjnRvVcs0tG40mAs/p84OEpFcVe/RSqDrD
+/D7R01u+Wj5xLl0PUsFplIGDbikCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAPS99JujKGVRfa50TKfieq+uK1SxjidErYaZTb3cJ
+NNfQDYn6nk4lnrnab5EUVhO/NegP2yIu3YOnZGfxFDhvVozMTKKAB5r5XKOvzsP9
+9C9578PVMLozucfUMCSwau7Z4l5uuQOHuzjzlVLCibbbf4RwfvZ7hh5sB5c0pNbw
+RQq64RXQUUEvul/W9gUeT9ISHOsASGTq+HJ5i7vNARjukEAXW/maqs9vyTWWbGVI
+1FSOnVyteymq4Xk+9YlIyNPNyacgnsMnU72XKBLDS0KJdhIWALFAZI4dSh5WZNuW
+ZguUnEmeH81lLbR+p/N3iuN8+oSo8UXik92jxeUY2tQJUA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy
+MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG
+A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt
+YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD
+VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA
+isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj
+Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50
+QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt
+bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR
+yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID
+AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0
+cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f
+BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj
+cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1
+U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl
+YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos
+SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/
+t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u
+mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb
+K+9A46sd33oqK8n8
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y
+AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw
+TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8
+/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/
+jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms
+Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF
+Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw
+Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW
+w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE
+Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD
+2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIG2jCCBcKgAwIBAgIDFc/9MA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJE
+RTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1E
+Rk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9w
+bGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNl
+cnRpZnlAcGNhLmRmbi5kZTAeFw0wMTEyMDExMjExMTZaFw0xMDAxMzExMjExMTZa
+MIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3Nu
+ZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0w
+KwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAf
+BgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMF5rhMt6zmhxK5oWPwT2FG7Up7T5DovHSD/YKPIRxsv
+DWmC4dTzByIBLnOmEflk+5KAqAYao6eY1qF0hR4WiS4DjCsn7l3zNo/4i2eF4EmG
+EksBygb4tRlTThcO7heFX+Du5qFoks+ONqa70RlwOr2l53KVwjMXBCtCLFSKRLVu
+xeh5+Smkm+FuOmwEugndM2n74Djjyf9DCOaHGZrHwVDh+Vpy5Ny4bKCSboujRxd5
+NxsStUshDVbTeS3B8TuzAJbywYWEE7erox+7WTfQr8ivSCBhrNJ36VRjAb8hiV9I
+uy2TmJYo2oPyC8a3eM3xj9Ku2IW3tS2zpfiIzt9xvFMCAwEAAaOCAwEwggL9MA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAYL+rX4SHijILELPs+g0MTRf33QMIHb
+BgNVHSMEgdMwgdCAFAYL+rX4SHijILELPs+g0MTRf33QoYGypIGvMIGsMQswCQYD
+VQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYD
+VQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRE
+Rk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0B
+CQEWEmNlcnRpZnlAcGNhLmRmbi5kZYIDFc/9MAsGA1UdDwQEAwIBBjARBglghkgB
+hvhCAQEEBAMCAAcwgaUGA1UdHwSBnTCBmjBLoEmgR4ZFaHR0cDovL3d3dy5kZm4t
+cGNhLmRlL2NlcnRpZmljYXRpb24veDUwOS9nMS9kYXRhL2NybHMvcm9vdC1jYS1j
+cmwuY3J4MEugSaBHhkVodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi94NTA5L2cxL2RhdGEvY3Jscy9yb290LWNhLWNybC5jcmwwOAYJYIZIAYb4QgED
+BCsWKWh0dHBzOi8vd3d3LmRmbi1wY2EuZGUvY2dpL2NoZWNrLXJldi5jZ2k/MEsG
+CWCGSAGG+EIBCAQ+FjxodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi9wb2xpY2llcy94NTA5cG9saWN5Lmh0bWwwOAYJYIZIAYb4QgENBCsWKVRoZSBE
+Rk4gVG9wLUxldmVsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MGQGA1UdIARdMFsw
+WQYLKwYBBAHZGoIsAQEwSjBIBggrBgEFBQcCARY8aHR0cDovL3d3dy5kZm4tcGNh
+LmRlL2NlcnRpZmljYXRpb24vcG9saWNpZXMveDUwOXBvbGljeS5odG1sMA0GCSqG
+SIb3DQEBBQUAA4IBAQAmbai6JMt7nkuavyvxKzLGn04Gyt0zKrp8zmERp4inktvY
+7p+vkaomYu2QYC7cHq0tlrPXQQhhetjiXGb+36aJtHDkEA0NwrJzYnHgPsvx7z0w
+ysENP4wxf97KsSWm07RY+f6/gIQF7Je7CW30Rzq7N6R0NMBs32mJgdn3ntqlFNw3
+Nbs050FEjPNq54RdawlJo85x+w+QJd7uQM4yZjHpRhvwgte9Ge1UqCUdpMsLHzeM
+KJ0B9GhwIIqOJCMiPgKjcUBrn6ehSX70POvXvjjE2+FzhPGTyTkS474d2UCAnL9q
+hPrdWXzBjOumOjhJutT1aecm9eljlshmh1cNen00
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAyygAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmDELMAkGA1UEBhMCQVQx
+EDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAGA1UEChM5QXJn
+ZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBmdWVyIERhdGVu
+c2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVuLmF0MB4XDTAx
+MDIxMjExMzAzMFoXDTA5MDIxMjExMzAzMFowgZgxCzAJBgNVBAYTAkFUMRAwDgYD
+VQQIEwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExQjBABgNVBAoTOUFyZ2UgRGF0
+ZW4gT2VzdGVycmVpY2hpc2NoZSBHZXNlbGxzY2hhZnQgZnVlciBEYXRlbnNjaHV0
+ejEiMCAGCSqGSIb3DQEJARYTYS1jZXJ0QGFyZ2VkYXRlbi5hdDCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEAwgsHqoNtmmrJ86+e1I4hOVBaL4kokqKN2IPOIL+1
+XwY8vfOOUfPEdhWpaC0ldt7VYrksgDiUccgH0FROANWK2GkfKMDzjjXHysR04uEb
+Om7Kqjqn0nproOGkFG+QvBZgs+Ws+HXNFJA6V76fU4+JXq4452LSK4Lr5YcBquu3
+NJECAwEAAaOCARkwggEVMB0GA1UdDgQWBBQ0j59zH/G31zRjgK1y2P//tSAWZjCB
+xQYDVR0jBIG9MIG6gBQ0j59zH/G31zRjgK1y2P//tSAWZqGBnqSBmzCBmDELMAkG
+A1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAG
+A1UEChM5QXJnZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBm
+dWVyIERhdGVuc2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVu
+LmF0ggEAMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQE
+AwICBDANBgkqhkiG9w0BAQQFAAOBgQBFuJYncqMYB6gXQS3eDOI90BEHfFTKy/dV
+AV+K7QdAYikWmqgBheRdPKddJdccPy/Zl/p3ZT7GhDyC5f3wZjcuu8AJ27BNwbCA
+x54dgxgCNcyPm79nY8MRtEdEpoRGdSsFKJemz6hpXM++MWFciyrRWIIA44XB0Gv3
+US0spjsDPQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD
+VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT
+IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD
+Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz
+MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE
+ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw
+FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu
+aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY
+XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1
+gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4
+Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY
+JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU
+dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14
+cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx
+MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG
+29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk
+oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk
+3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL
+qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN
+nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX
+ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H
+DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO
+TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
+kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w
+zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
+rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
+Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
+Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
+BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
+dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
+AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
+YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
+hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
+L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
+SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
+1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
+6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
+Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
+aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
+7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
+xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
+rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
+eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
+USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
+lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
+T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
+BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
+dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
+HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
+KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
+5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
+kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
+AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
+HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
+AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
+mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
+4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
+81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
+Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICiTCCAfKgAwIBAgIEN4dnrDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJi
+ZTERMA8GA1UEChMIQmVsZ2Fjb20xDDAKBgNVBAsTA01UTTEkMCIGA1UEAxMbQmVs
+Z2Fjb20gRS1UcnVzdCBQcmltYXJ5IENBMR8wHQYKCZImiZPyLGQBAxQPaW5mb0Bl
+LXRydXN0LmJlMB4XDTk4MTEwNDEzMDQzOVoXDTEwMDEyMTEzMDQzOVowdTELMAkG
+A1UEBhMCYmUxETAPBgNVBAoTCEJlbGdhY29tMQwwCgYDVQQLEwNNVE0xJDAiBgNV
+BAMTG0JlbGdhY29tIEUtVHJ1c3QgUHJpbWFyeSBDQTEfMB0GCgmSJomT8ixkAQMU
+D2luZm9AZS10cnVzdC5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqtm5
+s9VPak3FQdB7BGFqi3GBB9pk41huJ1XCrc4XsPz6ko0I8Bxy/7LDMf7gaoeXTMxD
+V6coeTq1g12kHWrxasU+FCIdWQZv8KYxd9ywSTjmywwP/qpyNIjaKDohWu50Kxuk
+21sTFrVzX8OujNLAPj2wy/Dsi4YLwsFEGFpjqNUCAwEAAaMmMCQwDwYDVR0TBAgw
+BgEB/wIBATARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEFBQADgYEAerKx
+pbF9M+nC4RvO05OMfwH9Gx1amq6rB1Ev7Ymr3VBCux//SrWknLFhKQpM6oNZSY2v
+hmnXgaxHqqRxblnvynxqblSK2qiSyfVms3lf1IsBniFjRjWTpcJfImIDcB1jI+hr
+SB0jECfY9t9HorrsgFBKbMRwpnrkdCJ/9oRiMn8=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw
+ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU
+REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr
+2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s
+2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU
+GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj
+dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r
+TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB
+AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv
+c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl
+ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu
+MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
+T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud
+HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD
+VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny
+bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ
+J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG
+SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom
+JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO
+inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y
+caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB
+mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ
+YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9
+BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD
+EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz
+aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w
+MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l
+dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh
+bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq
+eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe
+r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5
+3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd
+vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
+mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC
+wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg
+hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0
+TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg
+ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg
+dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6
+b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl
+c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0
+ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3
+dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu
+ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo
+ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3
+Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
+ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA
+A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ
+MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+
+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR
+VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY
+83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3
+macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx
+CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp
+ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa
+QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw
+NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft
+ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu
+QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG
+qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL
+fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ
+Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4
+Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ
+54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b
+MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j
+ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej
+YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt
+A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF
+rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ
+pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB
+lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy
+YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50
+7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs
+YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6
+xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc
+unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/
+Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp
+ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42
+gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0
+jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+
+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD
+W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/
+RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r
+MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk
+BYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
+ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
+aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w
+NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G
+A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX
+SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR
+VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2
+w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF
+mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg
+4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9
+4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw
+EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx
+SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2
+ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8
+vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
+Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
+/L7fCg0=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu
+IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw
+WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD
+ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y
+IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn
+IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+
+6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob
+jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw
+izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl
++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY
+zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP
+pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF
+KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW
+ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB
+AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0
+ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA
+A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0
+uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+
+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7
+jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/
+u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D
+YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1
+puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa
+icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG
+DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
+kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
+Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/cert_bundle b/tdeio/kssl/kssl/cert_bundle
new file mode 100755
index 000000000..331a64286
--- /dev/null
+++ b/tdeio/kssl/kssl/cert_bundle
@@ -0,0 +1,47 @@
+:
+eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+##
+## cert_bundle -- Bundle CA Certificates into one file
+## Copyright (c) 1998 Ralf S. Engelschall, All Rights Reserved.
+##
+
+($certdb, $indexfile, $bundlefile) = @ARGV;
+
+%CERT = ();
+open(IDX, "<$indexfile") || die;
+while (<IDX>) {
+ if (m|^(\S+):\s+(.+)\s*$|) {
+ $CERT{$2} = $1;
+ }
+}
+close(IDX);
+
+$date = `date`;
+$date =~ s|\n$||;
+open(BDL, ">$bundlefile") || die;
+print BDL "##\n";
+print BDL "## $bundlefile -- Bundle of CA Certificates\n";
+print BDL "## Last Modified: $date\n";
+print BDL "##\n";
+print BDL "## This is a bundle of X.509 certificates of public\n";
+print BDL "## Certificate Authorities (CA). These were automatically\n";
+print BDL "## extracted from Netscape Communicator's certificate database\n";
+print BDL "## (the file `$certdb').\n";
+print BDL "##\n";
+foreach $cert (sort(keys(%CERT))) {
+ $file = $CERT{$cert};
+ print STDERR "Bundling: $cert ($file)\n";
+ $pem = `openssl x509 -in $file -inform DER -outform PEM`;
+ $pem =~ s|\n$||;
+ $purpose = `openssl x509 -in $file -inform DER -noout -purpose`;
+ #
+ $_ = $purpose;
+ if ( /server CA : Yes\n/ || /client CA : Yes\n/ || (/Any Purpose CA : Yes\n/ && (/client : Yes\n/ || /server : Yes\n/ ))) {
+ print BDL "\n";
+ print BDL "$pem\n";
+ }
+}
+close(BDL);
+
diff --git a/tdeio/kssl/kssl/cert_extract.c b/tdeio/kssl/kssl/cert_extract.c
new file mode 100644
index 000000000..095f810f4
--- /dev/null
+++ b/tdeio/kssl/kssl/cert_extract.c
@@ -0,0 +1,183 @@
+//krazy:excludeall=license (program, not a library)
+/*
+** cert_extract.c -- Extract CA Certs out of Netscape certN.db files
+**
+** Copyright Ariel Glenn <ariel@columbia.edu>
+** Copyright 1998 Ralf S. Engelschall <rse@engelschall.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+**
+**
+** Originally written and released under the GPL by
+** Ariel Glenn from the AcIS R&D group at Columbia
+** as the two sources findoffset.c and dblist.c. See under
+** http://www.columbia.edu/~ariel/good-certs/ for more details.
+**
+** Merged into one single program in August 1998
+** by Ralf S. Engelschall for use in the mod_ssl project.
+** See under http://www.engelschall.com/sw/mod_ssl/ for more details.
+**
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <db1/db.h>
+
+#include "openssl/asn1.h"
+#include "openssl/x509.h"
+
+int findoffset(char *dbname);
+
+int findoffset(char *dbname)
+{
+ DB *db;
+ DBT dkey, dvalue;
+ int result;
+ int offset = 0;
+ char *p;
+ int ptag = 0, pclass, plen;
+ X509 *mycert;
+
+ if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) {
+ fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno));
+ exit(1);
+ }
+ while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) {
+ if ((dvalue.size) > 520) {
+ while (offset < dvalue.size) {
+ p = (char *)dvalue.data + offset - 1;
+ ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size);
+ if (ptag == V_ASN1_SEQUENCE) { /* ok, it might be a cert then. */
+ /* include length of object header junk */
+ plen += p - ((char *) dvalue.data + offset - 1);
+ mycert = NULL;
+ p = (char *) dvalue.data + offset - 1;
+ d2i_X509(&mycert, (unsigned char **) &p, plen);
+ if (mycert == NULL) { /* must be garbage after all */
+ offset++;
+ continue;
+ }
+ break;
+ }
+ else
+ offset++;
+ }
+ if (offset > 0)
+ break; /* found it, let's quit */
+ }
+ }
+ db->close(db);
+ return (offset);
+}
+
+int main(int argc, char **argv)
+{
+ char *dbname;
+ DB *db;
+ int j;
+ int offset;
+ DBT dkey, dvalue;
+ int result;
+ char oname[40];
+ int fout;
+ int find;
+ char *p;
+ int ptag = 0, pclass, plen;
+ X509 *mycert;
+ char *shortname;
+ char byte1, byte2;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s /path/to/netscape/cert.db\n", argv[0]);
+ exit(1);
+ }
+
+ dbname = argv[1];
+ offset = findoffset(dbname);
+ if (offset == 0) {
+ fprintf(stderr, "Could not determine cert offset in DB file '%s'\n", dbname);
+ exit(1);
+ }
+ else {
+ fprintf(stderr, "Ok: certificates are at offset %d\n", offset);
+ }
+
+ if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) {
+ fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno));
+ exit(1);
+ }
+ if ((find = open("cert.index", O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) {
+ fprintf(stderr, "Failed to open Index file '%s': %s\n", "cert-index", strerror(errno));
+ exit(1);
+ }
+ j = 0;
+ byte1 = -1;
+ byte2 = -1;
+ while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) {
+ if (dvalue.size > offset && ((dvalue.size) - offset) > 500) {
+ p = (char *)dvalue.data + offset - 1;
+ if (byte1 != -1 && byte2 != -1)
+ if (byte1 != p[0] || byte2 != p[1])
+ continue;
+ ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size);
+ if (ptag == V_ASN1_SEQUENCE) { /* ok, it might be a cert then. */
+ if (byte1 == -1 && byte2 == -1) {
+ byte1 = p[0];
+ byte2 = p[1];
+ }
+ /* include length of object header junk */
+ plen += p - ((char *) dvalue.data + offset - 1);
+ mycert = NULL;
+ p = (char *) dvalue.data + offset - 1;
+ d2i_X509(&mycert, (unsigned char **) &p, plen);
+ if (mycert == NULL) { /* must be garbage after all */
+ continue;
+ }
+ j++;
+ sprintf(oname, "cert.%02d.der", j);
+ if ((fout = open(oname, O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) {
+ fprintf(stderr, "could not open %s\n", oname);
+ continue;
+ }
+ write(fout, (char *) dvalue.data + offset - 1, plen);
+ close(fout);
+ write(find, oname, strlen(oname));
+ write(find, ": ", 2);
+ shortname = (char *) dvalue.data + offset - 1 + plen;
+ write(find, shortname, dvalue.size - plen - offset);
+ write(find, "\n", 1);
+ fprintf(stderr, "Extracted: %s (", oname);
+ write(fileno(stderr), shortname, dvalue.size - plen - offset);
+ fprintf(stderr, ")\n");
+ }
+ else {
+ /* fprintf(stderr, "Hmmm... ptag is %d, plen is %d\n", ptag, plen); */
+ }
+ }
+ }
+ close(find);
+ db->close(db);
+
+ return (0);
+}
+
diff --git a/tdeio/kssl/kssl/certbundle_Makefile b/tdeio/kssl/kssl/certbundle_Makefile
new file mode 100644
index 000000000..5a288f3b6
--- /dev/null
+++ b/tdeio/kssl/kssl/certbundle_Makefile
@@ -0,0 +1,43 @@
+##
+## Makefile for building and driving the CA cert extraction
+## Copyright (c) 1998 Ralf S. Engelschall, All Rights Reserved.
+##
+
+V=1.0
+
+SSLEAY_INC=/sw/pkg/ssleay/include
+SSLEAY_LIB=/sw/pkg/ssleay/lib
+
+CC=cc
+CFLAGS=-pipe -O -g -ggdb3 -Wall -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline
+LDFLAGS=-g -ggdb3
+
+all: extract
+
+extract: cert_extract
+ ./cert_extract cert7.db
+ ./cert_bundle cert7.db cert.index ca-cert-bundle.pem
+
+cert_extract.o: cert_extract.c
+ $(CC) $(CFLAGS) -I$(SSLEAY_INC) -o cert_extract.o -c cert_extract.c
+
+cert_extract: cert_extract.o
+ $(CC) $(LDFLAGS) -ocert_extract cert_extract.o -L$(SSLEAY_LIB) -lcrypto -ldb1
+
+clean:
+ -rm -f cert_extract.o
+ -rm -f cert_extract
+ -rm -f core *.core
+
+distclean: clean
+ -rm -f cert.*.der cert.index
+
+dist: distclean
+ gtar --no-recursion -cvf - `find * -depth -print | sort` |\
+ tardy --user_number=1000 --user_name=rse \
+ --group_number=1000 --group_name=en \
+ --prefix=certbundle-$(V) - |\
+ gzip --best >/tmp/certbundle-$(V).tar.gz && \
+ mv /tmp/certbundle-$(V).tar.gz ..
+ ls -l ../certbundle-$(V).tar.gz
+
diff --git a/tdeio/kssl/kssl/certkde b/tdeio/kssl/kssl/certkde
new file mode 100755
index 000000000..37c924f83
--- /dev/null
+++ b/tdeio/kssl/kssl/certkde
@@ -0,0 +1,75 @@
+:
+eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+##
+## Generate the KDE CA list TDEConfig file
+##
+
+%CERT = ();
+open(IDX, "<cert.index") || die;
+while (<IDX>) {
+ if (m|^(\S+):\s+(.+)\s*$|) {
+ $CERT{$2} = $1;
+ }
+}
+close(IDX);
+
+$date = `date`;
+$date =~ s|\n$||;
+open(BDL, ">ksslcalist") || die;
+foreach $cert (sort(keys(%CERT))) {
+ $file = $CERT{$cert};
+ print STDERR "Bundling: $cert ($file)\n";
+ $pem = `openssl x509 -in $file -inform DER -outform PEM`;
+ $pem =~ s|[\n\r]||g;
+ $pem =~ s|-----BEGIN CERTIFICATE-----||;
+ $pem =~ s|-----END CERTIFICATE-----||;
+ $subj = `openssl x509 -in $file -inform DER -noout -subject`;
+ $_ = $subj;
+ # We don't trust this anymore, so we keep our own copy
+ if ( /TrustCenter/ ) {
+ continue;
+ }
+ if ( /[Oo]bject/ || /[Cc]ode/ ) {
+ $codeSubj = 1;
+ } else {
+ $codeSubj = 0;
+ }
+ $subj =~ s|\n$||;
+ $subj =~ s/^subject= //;
+ $purpose = `openssl x509 -in $file -inform DER -noout -purpose`;
+ print BDL "\n";
+ print BDL "[$subj]\n";
+ print BDL "x509=$pem\n";
+ #
+ $_ = $purpose;
+ if ( /server CA : Yes\n/ || /client CA : Yes\n/ || (/Any Purpose CA : Yes\n/ && (/client : Yes\n/ || /server : Yes\n/ ))) {
+ $v_site="true";
+ } else {
+ $v_site="false";
+ }
+ #
+ if ( /MIME signing CA : Yes\n/ || /MIME encryption CA : Yes\n/ ) {
+ $v_email="true";
+ } else {
+ $v_email="false";
+ }
+ #
+ if ( /Any Purpose CA : Yes\n/ && $codeSubj == 1) {
+ $v_code="true";
+ } else {
+ $v_code="false";
+ }
+
+ # are some certificates really broken?
+ if ($v_code == "false" && $v_email == "false") {
+ $v_site = "true";
+ }
+
+ print BDL "site=$v_site\n";
+ print BDL "email=$v_email\n";
+ print BDL "code=$v_code\n";
+}
+close(BDL);
+
diff --git a/tdeio/kssl/kssl/certum.pem b/tdeio/kssl/kssl/certum.pem
new file mode 100644
index 000000000..b133fcb49
--- /dev/null
+++ b/tdeio/kssl/kssl/certum.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/certum1.pem b/tdeio/kssl/kssl/certum1.pem
new file mode 100644
index 000000000..aaf9cbc9a
--- /dev/null
+++ b/tdeio/kssl/kssl/certum1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICjTCCAXWgAwIBAgIDAQAhMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMxNTNaFw0xMjA3MTIxNjMxNTNaMEMxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xFzAVBgNVBAMTDkNlcnR1bSBM
+ZXZlbCBJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl73pZ9DFcn7Qy0qBZ
+K+So18cav7drUrJ8SiYOlDDVskt81+eIcL/4FelTSGjuAOvYdmm+HGYG998RPB0i
+Z+Ak67vXFJ537vRWOcu6aMjNuAwu8BOdc5eSgB0Y8X4+3LOYfugtaZa8mrEQ8Hit
+0yLE9UBcU9J+4PmkVGecmZ8jZQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQAlDS4aTmgK0YgmUvt/3zN7G2/ZrtBBCtONlUvC69c7
+TmLJWJ842y2AH7ryNXXkcsn6p0ZBTrTJ2tA2y/j2PXJeXrCkK/qAJIpM0l4u0MT7
+enY5akasduHp2NXMP9vDlgMy7elU2s3nkOT79gfh5XttC+5D/x4JDNi1DMAA9hk1
+6DK4zWmDVfjkiP/G3fEndtJgNDQsyqnaQ3E3bljv3f1KJTjZUvtA2Ml6MP2hFRhg
+ZPsxuhW8QXidQYNiua1h7XUUiPiERLDLWZmfY6dxGrHXjSTx3shHNaQM0qkDs9gS
+6UK8uWJN2bf2YBnvGmzy0IQvx5wDCH7h8AdaBD6DgIG1
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/certum2.pem b/tdeio/kssl/kssl/certum2.pem
new file mode 100644
index 000000000..a90ca2a91
--- /dev/null
+++ b/tdeio/kssl/kssl/certum2.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAiMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMDNaFw0xMjA3MTIxNjMyMDNaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyMQSaN5fA94hNE46
+bMKpGUb5yIPEowReGZzGttYBQnC6oUOy+iM3md8WerzXeBKf7iIZEDW2HAp7BKhS
+4rMB6taxT07vDtkNfEKwOk6X7dODw6KY4mxnzjmjh5pf2feKKJ3MoZxi2HAz2a6J
+vHKFMq8dAlGL2GBtLvzlFp2jwkMCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAWo3wgy+/0B7UiTCu4Wn1rvGRXIUtbPNp4Bc4PP/i
+1q6pPheIe0ooCopuqnDX9maTHhZeNpnApgCUSbyw71EaOremD7HjWXASRUTylhwL
+5FdSx+D6MgF2uW9uwZ+NErkeRJYT2aRXe5FBOVIseC4g93Ay0D8Hg50MkAC5pQqW
++8GSszT94NzT7ppIaMtq53PZpUtLGiL3UBZ5vUJ5pE4lLKD7Ce+pXzZevy/MnkMG
+D1L7LgjRWL17OcMlASFETyUTajNjvxMy+oM4C22rwHRh2WQrvgw5MO+Q3UyYA1r5
+VrSaqgQ1g06ZcQt+mhzoc2swlOSwm8iis8H6orR8xmCWrA==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/certum3.pem b/tdeio/kssl/kssl/certum3.pem
new file mode 100644
index 000000000..d6233c43c
--- /dev/null
+++ b/tdeio/kssl/kssl/certum3.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICjzCCAXegAwIBAgIDAQAjMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMTdaFw0xMjA3MTIxNjMyMTdaMEUxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGTAXBgNVBAMTEENlcnR1bSBM
+ZXZlbCBJSUkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZjBbfGFmlsLjPe
+pWaDwG0LqhF11lWKabaHi1sQhK3qomHY7Em7qpL11dUQ1vsMcnnpzz/J0AEH6KDh
++yAyXV1SE/tVToLYYByZK+JGacLYIYF9aCwV8AhqyzOGurO5QX6vLboXB2WNnwmX
+hyNVKUgnUVy4ktAR2qZJIw5Bjsn/AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAIsLt3vKCZqd/gui45ovm3FSO6FLjzzq4pagPvbN
+nZ39HrhRaCpqkHDAj71L5L27U3eW2D4ILL0iUmZadbC4i3at/PUL9mjhGlajcCN8
+EF6IXGT87Tbcii735jRaaXSbEY4YhNOg9DPBoD4uJMkA8Z0Y/6lYmk4S6KUMCzzt
+t5zZBiWjdd08yFi5VGMvpE74KVOMdMa3JNVaR0XvT0Q8yXo1XKCrY9OFIxnhVgDb
+hzr9fwjKWDwu8kxhT9khAETm0BU2Buu+CTasaJdT/bBR2YEx9qcN7XyXTeDtkOO5
+QeGSqFgzquwjWEbKhf7l/e+efdRCg+ikH3O5snHB6iS+dgg=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/certum4.pem b/tdeio/kssl/kssl/certum4.pem
new file mode 100644
index 000000000..decbac005
--- /dev/null
+++ b/tdeio/kssl/kssl/certum4.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAkMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMzVaFw0xMjA3MTIxNjMyMzVaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJVjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmyb1lKqCAKE4juAy
+6lpVNUl6aJ2DuWPSiJ3BBk3/6ty6I4Lr2Dpy1b1vjVelhaFsVKEDgK2JyQlk9XMq
+LPZI2Ql166mJiPKFg77aY/W78EcQfGyjnRvVcs0tG40mAs/p84OEpFcVe/RSqDrD
+/D7R01u+Wj5xLl0PUsFplIGDbikCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAPS99JujKGVRfa50TKfieq+uK1SxjidErYaZTb3cJ
+NNfQDYn6nk4lnrnab5EUVhO/NegP2yIu3YOnZGfxFDhvVozMTKKAB5r5XKOvzsP9
+9C9578PVMLozucfUMCSwau7Z4l5uuQOHuzjzlVLCibbbf4RwfvZ7hh5sB5c0pNbw
+RQq64RXQUUEvul/W9gUeT9ISHOsASGTq+HJ5i7vNARjukEAXW/maqs9vyTWWbGVI
+1FSOnVyteymq4Xk+9YlIyNPNyacgnsMnU72XKBLDS0KJdhIWALFAZI4dSh5WZNuW
+ZguUnEmeH81lLbR+p/N3iuN8+oSo8UXik92jxeUY2tQJUA==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo1.pem b/tdeio/kssl/kssl/comodo1.pem
new file mode 100644
index 000000000..536b087db
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo1.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo2.pem b/tdeio/kssl/kssl/comodo2.pem
new file mode 100644
index 000000000..fef46d9c7
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo2.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo3.pem b/tdeio/kssl/kssl/comodo3.pem
new file mode 100644
index 000000000..40c137095
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo3.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo4.pem b/tdeio/kssl/kssl/comodo4.pem
new file mode 100644
index 000000000..7490b02be
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo4.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo5.pem b/tdeio/kssl/kssl/comodo5.pem
new file mode 100644
index 000000000..824d542c1
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo5.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo6.pem b/tdeio/kssl/kssl/comodo6.pem
new file mode 100644
index 000000000..4b9f74824
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo6.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
+rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
+Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
+Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
+BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
+dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
+AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
+YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
+hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
+L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
+SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
+1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
+6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
+Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
+aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
+7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
+xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
+rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
+eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
+USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/comodo7.pem b/tdeio/kssl/kssl/comodo7.pem
new file mode 100644
index 000000000..58b02ea94
--- /dev/null
+++ b/tdeio/kssl/kssl/comodo7.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
+lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
+T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
+BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
+dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
+HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
+KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
+5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
+kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
+AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
+HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
+AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
+mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
+4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
+81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
+Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/dfn-root-ca-cert.pem b/tdeio/kssl/kssl/dfn-root-ca-cert.pem
new file mode 100644
index 000000000..eb8a054ac
--- /dev/null
+++ b/tdeio/kssl/kssl/dfn-root-ca-cert.pem
@@ -0,0 +1,39 @@
+-----BEGIN CERTIFICATE-----
+MIIG2jCCBcKgAwIBAgIDFc/9MA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJE
+RTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1E
+Rk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9w
+bGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNl
+cnRpZnlAcGNhLmRmbi5kZTAeFw0wMTEyMDExMjExMTZaFw0xMDAxMzExMjExMTZa
+MIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3Nu
+ZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0w
+KwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAf
+BgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMF5rhMt6zmhxK5oWPwT2FG7Up7T5DovHSD/YKPIRxsv
+DWmC4dTzByIBLnOmEflk+5KAqAYao6eY1qF0hR4WiS4DjCsn7l3zNo/4i2eF4EmG
+EksBygb4tRlTThcO7heFX+Du5qFoks+ONqa70RlwOr2l53KVwjMXBCtCLFSKRLVu
+xeh5+Smkm+FuOmwEugndM2n74Djjyf9DCOaHGZrHwVDh+Vpy5Ny4bKCSboujRxd5
+NxsStUshDVbTeS3B8TuzAJbywYWEE7erox+7WTfQr8ivSCBhrNJ36VRjAb8hiV9I
+uy2TmJYo2oPyC8a3eM3xj9Ku2IW3tS2zpfiIzt9xvFMCAwEAAaOCAwEwggL9MA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAYL+rX4SHijILELPs+g0MTRf33QMIHb
+BgNVHSMEgdMwgdCAFAYL+rX4SHijILELPs+g0MTRf33QoYGypIGvMIGsMQswCQYD
+VQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYD
+VQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRE
+Rk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0B
+CQEWEmNlcnRpZnlAcGNhLmRmbi5kZYIDFc/9MAsGA1UdDwQEAwIBBjARBglghkgB
+hvhCAQEEBAMCAAcwgaUGA1UdHwSBnTCBmjBLoEmgR4ZFaHR0cDovL3d3dy5kZm4t
+cGNhLmRlL2NlcnRpZmljYXRpb24veDUwOS9nMS9kYXRhL2NybHMvcm9vdC1jYS1j
+cmwuY3J4MEugSaBHhkVodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi94NTA5L2cxL2RhdGEvY3Jscy9yb290LWNhLWNybC5jcmwwOAYJYIZIAYb4QgED
+BCsWKWh0dHBzOi8vd3d3LmRmbi1wY2EuZGUvY2dpL2NoZWNrLXJldi5jZ2k/MEsG
+CWCGSAGG+EIBCAQ+FjxodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi9wb2xpY2llcy94NTA5cG9saWN5Lmh0bWwwOAYJYIZIAYb4QgENBCsWKVRoZSBE
+Rk4gVG9wLUxldmVsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MGQGA1UdIARdMFsw
+WQYLKwYBBAHZGoIsAQEwSjBIBggrBgEFBQcCARY8aHR0cDovL3d3dy5kZm4tcGNh
+LmRlL2NlcnRpZmljYXRpb24vcG9saWNpZXMveDUwOXBvbGljeS5odG1sMA0GCSqG
+SIb3DQEBBQUAA4IBAQAmbai6JMt7nkuavyvxKzLGn04Gyt0zKrp8zmERp4inktvY
+7p+vkaomYu2QYC7cHq0tlrPXQQhhetjiXGb+36aJtHDkEA0NwrJzYnHgPsvx7z0w
+ysENP4wxf97KsSWm07RY+f6/gIQF7Je7CW30Rzq7N6R0NMBs32mJgdn3ntqlFNw3
+Nbs050FEjPNq54RdawlJo85x+w+QJd7uQM4yZjHpRhvwgte9Ge1UqCUdpMsLHzeM
+KJ0B9GhwIIqOJCMiPgKjcUBrn6ehSX70POvXvjjE2+FzhPGTyTkS474d2UCAnL9q
+hPrdWXzBjOumOjhJutT1aecm9eljlshmh1cNen00
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/gd-class2-root.pem b/tdeio/kssl/kssl/gd-class2-root.pem
new file mode 100644
index 000000000..42e8d1eef
--- /dev/null
+++ b/tdeio/kssl/kssl/gd-class2-root.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/geotrust-global-1.pem b/tdeio/kssl/kssl/geotrust-global-1.pem
new file mode 100644
index 000000000..b69f0029b
--- /dev/null
+++ b/tdeio/kssl/kssl/geotrust-global-1.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/geotrust-global-2.pem b/tdeio/kssl/kssl/geotrust-global-2.pem
new file mode 100644
index 000000000..d2ea26636
--- /dev/null
+++ b/tdeio/kssl/kssl/geotrust-global-2.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
diff --git a/tdeio/kssl/kssl/globalsign-root-r1.pem b/tdeio/kssl/kssl/globalsign-root-r1.pem
new file mode 100644
index 000000000..f4ce4ca43
--- /dev/null
+++ b/tdeio/kssl/kssl/globalsign-root-r1.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/globalsign-root-r2.pem b/tdeio/kssl/kssl/globalsign-root-r2.pem
new file mode 100644
index 000000000..6f0f8db0d
--- /dev/null
+++ b/tdeio/kssl/kssl/globalsign-root-r2.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/icpbrasil.pem b/tdeio/kssl/kssl/icpbrasil.pem
new file mode 100644
index 000000000..53fa58c51
--- /dev/null
+++ b/tdeio/kssl/kssl/icpbrasil.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy
+MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG
+A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt
+YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD
+VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA
+isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj
+Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50
+QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt
+bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR
+yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID
+AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0
+cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f
+BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj
+cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1
+U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl
+YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos
+SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/
+t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u
+mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb
+K+9A46sd33oqK8n8
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/ipsservidores.pem b/tdeio/kssl/kssl/ipsservidores.pem
new file mode 100644
index 000000000..e5963e72f
--- /dev/null
+++ b/tdeio/kssl/kssl/ipsservidores.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD
+VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT
+IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD
+Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz
+MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE
+ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw
+FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu
+aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY
+XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1
+gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4
+Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY
+JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU
+dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14
+cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/ksslcalist b/tdeio/kssl/kssl/ksslcalist
new file mode 100644
index 000000000..a0761cf4a
--- /dev/null
+++ b/tdeio/kssl/kssl/ksslcalist
@@ -0,0 +1,787 @@
+
+[/C=US/ST=DC/L=Washington/O=ABA.ECOM, INC./CN=ABA.ECOM Root CA/Email=admin@digsigtrust.com]
+x509=MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0kqS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q=
+site=true
+email=true
+code=false
+
+[/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root]
+x509=MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+site=true
+email=true
+code=false
+
+[/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Class 1 CA Root]
+x509=MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+site=true
+email=true
+code=false
+
+[/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Public CA Root]
+x509=MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+site=true
+email=true
+code=false
+
+[/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Qualified CA Root]
+x509=MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
+site=true
+email=true
+code=false
+
+[/C=US/O=American Express Company, Inc./OU=American Express Technologies/CN=American Express Certificate Authority]
+x509=MIICkDCCAfkCAgCNMA0GCSqGSIb3DQEBBAUAMIGPMQswCQYDVQQGEwJVUzEnMCUGA1UEChMeQW1lcmljYW4gRXhwcmVzcyBDb21wYW55LCBJbmMuMSYwJAYDVQQLEx1BbWVyaWNhbiBFeHByZXNzIFRlY2hub2xvZ2llczEvMC0GA1UEAxMmQW1lcmljYW4gRXhwcmVzcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgwODE0MjIwMTAwWhcNMDYwODE0MjM1OTAwWjCBjzELMAkGA1UEBhMCVVMxJzAlBgNVBAoTHkFtZXJpY2FuIEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1lcmljYW4gRXhwcmVzcyBUZWNobm9sb2dpZXMxLzAtBgNVBAMTJkFtZXJpY2FuIEV4cHJlc3MgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ8kmShcr9FSm1BrZE7PyIo/KGzv8UTyQckvnCI8HOQ99dNMi4FOzVKnCRSZXXVs2U8amT0Ggi3E19oApyKkfqJfCFAF82VGHPC/k3Wmed6R/pZD9wlWGn0DAC3iYopGYDBOkw+48zB/lvYYeictvzaHhjZlmpybdm4RWySDYs+QIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAGgXYrhzi0xs60qlPqvlnS7SzYoHV/PGWZd2Fxf4Uo4nk9hY2Chs9KIEeorCdiSxArTfKPL386infiNIYYj0EWiuJl32oUtTJWrYKhQCDuCHIG6eGVxzkAsj4jGXIz/VIqLTBnvaN/XXtUFEF3pFAtmFRWbWjsfwegyZYiJpW+3S
+site=true
+email=false
+code=false
+
+[/C=US/O=American Express Company, Inc./OU=American Express Technologies/CN=American Express Global Certificate Authority]
+x509=MIIEBDCCAuygAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVTMScwJQYDVQQKEx5BbWVyaWNhbiBFeHByZXNzIENvbXBhbnksIEluYy4xJjAkBgNVBAsTHUFtZXJpY2FuIEV4cHJlc3MgVGVjaG5vbG9naWVzMTYwNAYDVQQDEy1BbWVyaWNhbiBFeHByZXNzIEdsb2JhbCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgwODE0MTkwNjAwWhcNMTMwODE0MjM1OTAwWjCBljELMAkGA1UEBhMCVVMxJzAlBgNVBAoTHkFtZXJpY2FuIEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1lcmljYW4gRXhwcmVzcyBUZWNobm9sb2dpZXMxNjA0BgNVBAMTLUFtZXJpY2FuIEV4cHJlc3MgR2xvYmFsIENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPAkJmYu++tKc3FTiUfLJjxTkpRMysKFtQ34w1e9Lyofahi3V68MABb6oLaQpvcaoS5mJsdoo4qTaWa1RlYtHYLqkAwKIsKJUI0F89Src0HwzxKsKLRvFJSWWUuekHWG3+JH6+HpT0N+h8onGGaetcFAZX38YW+tm3LPqV7Y8/nabpEQ+ky16n4g3qk5L/WI5IpvNcYgnCuGRjMK/DFVpWusFkDpzTVZbzIEw3u1D3t3cPNIuypSgs6vKW3xEW9t5gcAAe+a8yYNpnkTZ6/4qxx1rJG1a75AsN6cDLFphRlxkRNFyt/R/eayypaDedvFuKpbepALeFY+xteflEgR9a0CAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0gBBAwDjAMBgoqhkiG+Q8KAQUBMBkGA1UdDgQSBBBXRzV7NicRqAj8L0Yl6yRpMA0GCSqGSIb3DQEBBQUAA4IBAQDHYUWoinG5vjTpIXshzVYTmNUwY+kYqkuSFb8LHbvskmnFLsNhi+gwRcsQRsFzOFyLGdIr80DrfHKzLh4n43WVihybLsSVBYZy0FX0oZJSeVzb9Pjc5dcSsUDHPIbkMWVKyjfG3nZXGWlMRmn8Kq0WN3qTrPchSy3766lQy8HRQAjaA2mHpzdeVcHF7cTjjgwml5tcV0ty4/IDBdACOyYDQJCevgtbSQx48dVMVSng9v1MA6lUAjLRV1qFrEPtWzsWX6C/NdtLnnvo/+cNPDuom0lBRvVzTv+SZSGDE1Vx60k8f4gawhIoJaFGS0E3l3/sjvHUoZbCILZerakcHhGg
+site=true
+email=true
+code=false
+
+[/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Code Signing Root]
+x509=MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcgUm9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmluZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKOetv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+CchF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1SQdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2cvXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNAWshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Biu641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT98pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOnUxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWkLfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=
+site=false
+email=false
+code=true
+
+[/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Mobile Root]
+x509=MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAeFw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAnBgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+ghY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8ErqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9fIh96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbAB+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0at1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9m+pCDOjYVL5TZvU=
+site=true
+email=true
+code=false
+
+[/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root]
+x509=MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+site=true
+email=true
+code=false
+
+[/C=CA/ST=ON/L=Toronto/O=BankEngine Inc./OU=Certification Authority Division/CN=bankengine/Email=ca@bankengine.com]
+x509=MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9CYW5rRW5naW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlzaW9uMRMwEQYDVQQDEwpiYW5rZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBiYW5rZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNVBAoTD0JhbmtFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmJhbmtlbmdpbmUxIDAeBgkqhkiG9w0BCQEWEWNhQGJhbmtlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA14LoTUAl1/hEy+Kh1kLHiBdW2zD3V4IhM7xxTVKsYsIH56nr69ATTIxUP36eRzeZ137qt1AxHFjDCidk3m1Ul6l59ProPexdslLLM2npM3f2cteg+toyiYiSEJKjyzIu1xF1j9qzGkymSY/4DsXLZNk9FaczxMk/Ooc6Os1M3AverL4VG4rYIb6feR32cIKJ9Q1fGuyKk7ipq1XQfPW8a8TgZdbHbe7U9Gk3iasGMHHvpR9Ep3mGbgdTuQ98SBEuIwe1BUCGg/MXpVy48MNXfAMotBgGw4pl9yqSjMni2FB+E9Q9DHFs2RgXMqzKuo8zcPxKx2kZ6Arj8+27dw2clQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBauupHX9EhpC/r57d6b5kkeWvognxIP9//TO4iw3qbzIXEkPXmJmwVzlzoKJWqiya+aw19SP0+G6CzsFOBo/9ehmz+hZ8bhYX4MjlWzX5uTnkhz172j9fOBUmrTVPkcRIs6zjCD5PQAGoBPP1/Zdy2N36lZ0U7lg07Opirj/yJPSJeM2j0fwIFAroiVckvdT0BVwB6S/cPaAQGPghbbr1YGSmYrMriSv825ILJUfxzrJYunGR9FiY9Ob7+jwJwiZMS4CxSPktutxr/3hOvr1+ALS7IcVakhhA3PuZAJbdHFRclR9qMM8aBnBZmf+Uv3K3uhT+UBzzY654U9Yi1JYnA
+site=true
+email=true
+code=false
+
+[/C=BE/L=Brussels/O=BelSign NV/OU=BelSign Object Publishing Certificate Authority/CN=BelSign Object Publishing CA/Email=webmaster@belsign.be]
+x509=MIIDAzCCAmygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBuzELMAkGA1UEBhMCQkUxETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTgwNgYDVQQLEy9CZWxTaWduIE9iamVjdCBQdWJsaXNoaW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTElMCMGA1UEAxMcQmVsU2lnbiBPYmplY3QgUHVibGlzaGluZyBDQTEjMCEGCSqGSIb3DQEJARYUd2VibWFzdGVyQGJlbHNpZ24uYmUwHhcNOTcwOTE5MjIwMzAwWhcNMDcwOTE5MjIwMzAwWjCBuzELMAkGA1UEBhMCQkUxETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTgwNgYDVQQLEy9CZWxTaWduIE9iamVjdCBQdWJsaXNoaW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTElMCMGA1UEAxMcQmVsU2lnbiBPYmplY3QgUHVibGlzaGluZyBDQTEjMCEGCSqGSIb3DQEJARYUd2VibWFzdGVyQGJlbHNpZ24uYmUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQuH7a/7oJA3fm3LkHVngWxWtAmfGJVA5v8y2HeS+/+6Jn+h7mIz5DaDwk8dt8Xl7bLPyVF/bS8WAC+sFq2FIeP7mdkrR2Ig7tnn2VhAFgIgFCfgMkx9iqQHC33SmwQ9iNDXTgJYIhXAs0WbBj8zfuSKnfQnpOjXYhk0Mj4XVRRAgMBAAGjFTATMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQQFAAOBgQBjdhd8lvBTpV0BHFPOKcJ+daxMDaIIc7RqMf0CBhSZ3FQEpL/IloafMUMyJVf2hfYluze+oXkjyVcGJXFrRU/49AJAFoIir1TqMij2De6ZuksIUQ9uhiMhTC0liIHELg7xEyw4ipUCJMM6lWPkk45IuwhHcl+u5jpaR9Zxxp6aUg==
+site=false
+email=false
+code=true
+
+[/C=BE/L=Brussels/O=BelSign NV/OU=BelSign Secure Server Certificate Authority/CN=BelSign Secure Server CA/Email=webmaster@belsign.be]
+x509=MIIC8zCCAlygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBszELMAkGA1UEBhMCQkUxETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTQwMgYDVQQLEytCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSEwHwYDVQQDExhCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ0ExIzAhBgkqhkiG9w0BCQEWFHdlYm1hc3RlckBiZWxzaWduLmJlMB4XDTk3MDcxNjIyMDA1NFoXDTA3MDcxNjIyMDA1NFowgbMxCzAJBgNVBAYTAkJFMREwDwYDVQQHEwhCcnVzc2VsczETMBEGA1UEChMKQmVsU2lnbiBOVjE0MDIGA1UECxMrQmVsU2lnbiBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRlIEF1dGhvcml0eTEhMB8GA1UEAxMYQmVsU2lnbiBTZWN1cmUgU2VydmVyIENBMSMwIQYJKoZIhvcNAQkBFhR3ZWJtYXN0ZXJAYmVsc2lnbi5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1gESeJL4BEJ/yccig/x8R3AwK0kLPjZAkCjaIXODU/LE0RZAwFP/rqbGJLMnbaWzPTl3XagG9ubpvGMRTgZlcAqdk/miQIt/SoQOjRax1swIZBIM4ChLyKWEkBf7EUYu1qeFGMsYrmOasFgG9ADP+MQJGjUMofnuSv1t3v4mpTsCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgCgMA0GCSqGSIb3DQEBBAUAA4GBAGw9mcMF4h3K5S2qaIWLQDEgZhNo5lg6idCNdbLFYth9go/32TKBd/Y1W4UpzmeyubwrGXjP84f9RvGVdbIJVwMwwXrNckdxgMp9ncllPEcRIn36BwsoeKGT6AVFSOIyMko96FMcELfHc4wHUOH5yStTQfWDjeUJOUqOA2KqQGOL
+site=true
+email=false
+code=false
+
+[/C=CA/ST=ON/L=Toronto/O=CertEngine Inc./OU=Certification Authority Division/CN=certengine/Email=ca@certengine.com]
+x509=MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9DZXJ0RW5naW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlzaW9uMRMwEQYDVQQDEwpjZXJ0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBjZXJ0ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNVBAoTD0NlcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmNlcnRlbmdpbmUxIDAeBgkqhkiG9w0BCQEWEWNhQGNlcnRlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7aTXURShaeVt9u/dP3Q2dVib3jTCZvEyc6yfpGgaYWewXWuP4HOSfI4hGZblbpl+dzJc6RjhR+pguIRtbT5FJB8SJGjRqoujBEOQOxtVtc2fjM9Dqh0iOvMWWS6buxHG55GVrHAQaO5HXEScKQBa9ZyNmpSXPTEBrDMej1OAGOkc524/TZrgFPF4AiJLLkxCcP8NuzUKlW3WzNMSSoCtjkUKy4wjSLlAWCFM0T9Df6/+Z8ZUQTzHoKCDncH5Qnynd7DlOwKQ2JwwxRhYGiGVTUN0GUq7qA11kW3+vnbFesKQXoF6o2PVx9s2YXviI2NXXUjZ0pVnsnFCc45Pm8XojwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBP/aHOKJ00Akzc9HWM1X30hlWZFBaQi4pqD4Uhk8+pKzzwFP5DRLBOz8TYBbtdXrS6hxVMr2sqWmhVkuyepWhHZazKGyHY/y0FbOXsewAV1QxxSyx7ve89pCKv4/w0rQcP916iHc8Y/TCpmz7eITa3GId+8H/XTaBi8GBp9X9Ow8m25FmEB1NT+eJwefvfdKowjy4tSorKdW/eJspxNuTSRGmUy8G71W5dYvgpAlx6mdnHyzxEGvRYNNI2bS0ifXgbEFNWqSas9q34ea5KOpkJu8T/KyXfSb6rPOsBSb0twMowwGtCVH2C4Lw/8zo0EjhMpTOsPaub408PrZ+NQ2bl
+site=true
+email=true
+code=false
+
+[/C=DE/O=Deutsche Telekom AG/OU=TeleSec Trust Center/CN=Deutsche Telekom Root CA]
+x509=MIICjjCCAfegAwIBAgIBBjANBgkqhkiG9w0BAQQFADBtMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEdMBsGA1UECxMUVGVsZVNlYyBUcnVzdCBDZW50ZXIxITAfBgNVBAMTGERldXRzY2hlIFRlbGVrb20gUm9vdCBDQTAeFw05ODEyMDkwOTExMDBaFw0wNDEyMDkyMzU5MDBaMG0xCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR0wGwYDVQQLExRUZWxlU2VjIFRydXN0IENlbnRlcjEhMB8GA1UEAxMYRGV1dHNjaGUgVGVsZWtvbSBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBSz5BbO5EtdpcffqVjAIVxRDe7sanG0vV2HX4vVEa+42QZb2ZM7hwbK5pBQEmFDocPiONZp9ScFhHVmu2gYYlX2tzuypvtEYD0CRdiqj5f3+iRX0V/fgVdp1rQD0LME1zLRDJlViRC4BJZyKW/DB0AA1eP413pRAZHiDocw5iQIDAQABoz4wPDAPBgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjAZBgNVHQ4EEgQQLIdZH4sTgLL5hp0+En5YljANBgkqhkiG9w0BAQQFAAOBgQAP/nO1B4hvoAuJ6spQH5TelCsLJ15P9RyVJtqMllStGZE3Q12ryYuzzW+YOT3t3TXjcbftE5OD6IblKTMTE7w1e/0oL3BZ1dO0jSgTWTvI1XT5RcIHYKq4GFT5pWj/1wXVj7YFMS5BSvQQH2BHGguLGU2SVyDS71AZ6M3QcLy8Ng==
+site=true
+email=true
+code=false
+
+[/C=US/O=Digital Signature Trust Co./OU=DSTCA E1]
+x509=MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+site=true
+email=true
+code=false
+
+[/C=us/ST=Utah/L=Salt Lake City/O=Digital Signature Trust Co./OU=DSTCA X1/CN=DST RootCA X1/Email=ca@digsigtrust.com]
+x509=MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
+site=true
+email=false
+code=false
+
+[/C=US/O=Digital Signature Trust Co./OU=DSTCA E2]
+x509=MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+site=true
+email=true
+code=false
+
+[/C=us/ST=Utah/L=Salt Lake City/O=Digital Signature Trust Co./OU=DSTCA X2/CN=DST RootCA X2/Email=ca@digsigtrust.com]
+x509=MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
+site=true
+email=false
+code=false
+
+[/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048)]
+x509=MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
+site=false
+email=false
+code=false
+
+[/C=US/O=Entrust.net/OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab./OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Client Certification Authority]
+x509=MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapEPHayXOw=
+site=true
+email=true
+code=false
+
+[/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority]
+x509=MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+site=true
+email=true
+code=false
+
+[/C=US/O=Equifax/OU=Equifax Premium Certificate Authority]
+x509=MIIDIzCCAoygAwIBAgIENeHvHjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEuMCwGA1UECxMlRXF1aWZheCBQcmVtaXVtIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw05ODA4MjQyMjU0MjNaFw0xODA4MjQyMjU0MjNaME8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOoQaOBswIC8GGqN4g1Q0O0Q3En+pq2bPCMkdAb4qIpAm9OCwd5svmpPM269rrvPxkswf2Lbyqzp8ZSGhK/PWiRX4JEPWPs0lcIwY56hOLuAvNkR12X9k3oUT7X5DyZ7PNGJlDH3YSawLylYM4Q8L2YjTKyXhdX9LYupr/vhBgWwIDAQABo4IBCjCCAQYwcQYDVR0fBGowaDBmoGSgYqRgMF4xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODI0MjI1NDIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUFe6yKFmrbuX4z4uB9CThrj91G5gwHQYDVR0OBBYEFBXusihZq27l+M+LgfQk4a4/dRuYMAwGA1UdEwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAL0LnCepA9so3JipS9DRjqeoGlqR4Jzx9xh8LiKeNh/JqLXNRkpu+jUHG4YI65/iqPmdQS06rlxctl80BOv8KmCw+3TkhellOJbuFcfGd2MSvYpoH6tsfdrKXBPO6snrCVzFc+cSAdXZUwee4A+W8Iu0u0VIn4bFGVWgy5bFA/xI
+site=true
+email=true
+code=false
+
+[/C=US/O=Equifax/OU=Equifax Secure Certificate Authority]
+x509=MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+site=true
+email=true
+code=false
+
+[/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1]
+x509=MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+site=true
+email=true
+code=false
+
+[/C=US/O=Equifax Secure Inc./CN=Equifax Secure eBusiness CA-1]
+x509=MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+site=true
+email=true
+code=false
+
+[/C=US/O=Equifax Secure/OU=Equifax Secure eBusiness CA-2]
+x509=MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+site=true
+email=true
+code=false
+
+[/C=CA/ST=ON/L=Toronto/O=FortEngine Inc./OU=Certification Authority Division/CN=fortengine/Email=ca@fortengine.com]
+x509=MIIF3TCCA8WgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9Gb3J0RW5naW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlzaW9uMRMwEQYDVQQDEwpmb3J0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBmb3J0ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNVBAoTD0ZvcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmZvcnRlbmdpbmUxIDAeBgkqhkiG9w0BCQEWEWNhQGZvcnRlbmdpbmUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyr7GbpwDxx1v3EYbo0gcO+ligEhlDqG2e7u/AbWGoVAqc8+q6auUJUtz4i7oh0yNadu1o9kpXW+znkgO0zlrgjGskqqMO1ooppzTJdFy/P8gR6x1Iuv3kWtXOuzwPPEjv09LWlhyJsN+oU4ztTVf07I0Q9zYupcoDQ58XKRheI9KdDB2DYSmxywAWSLQwIeG0Qa7gvokeQlpkgkEC7viEecJ3752KXBJHnh7As51mxnlpmG6sDy67EliHDw5tHETRqbtnscGBjskGQBqR5xt7+QnnthZrN8HJHDoa9zgGephwizhkL44lXLFYK9W5XhFbblw2c+mAcHkokRiwD7CPeIoyD2a/Jcw3n5hegKTlNhd4BFGVF6JR7gFOFk2QfHXit5uthsij9Xhl7WAgQUqLgggD9MphqPf4nY66OZUJV9ZsmB+Qfp8UizB0WAOegactKVyRqHtRa+KIEXQXNtZgjcmMk9CYkP0nIbKtgKXaH6+9VMHNOryCnFE7pSsuPUkypncFWCHGSeiFO3w4w4J4csltxBADQzxfRu5KZnlToQN7bVpI/Q31tVXE5bjrJcq6Oj/OTqZ3ID+OqbkUdAg0ggjRKcTgxnLHd/AbMzJ6PsclDDf7cLs0WSlxMxQR/z5bNST1rNtT9rsiv2TOhfvCBxO9AOjBioO8PLO032HTNECAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAVyBpPWfT2VOyvVpslGKx8h0+CWP8cilygGRtZJ5dAJzc//1REAHdvK+TgZ4Foz3dqHhXI+RNN0FpzuWaYMjWZTS0kAmcOQuGY1Oo4PGlPHI21pNz29oFDTJr0ZmLBJ4JKVsE2soJg55jdk9MZHA7K//7HH9RsmrWZOE5DZDlrxp6+naixhMwnlPKKisIy9GNZUPqGdUWABMdB/BUVVNlNU5TtWpIXUClMd8a+eoKcItBeYXowkHOBpinPkDX3clFDIUfWiw0Ro08s8SrrFqR8Szwbrj52Xv1RM56oGqCjnkvJctxihODV7NcpxoAFjIZokDom0q6zPrrTUsLFQovPlovc3w5hmALiDMshaTvE1nm3Psn4yQ+FlRE8epTZrQiIGypZkZC6lcz0mYawueWcThYWGFhVG4ktQzOjjNRsNxopW+W7cF1zQTxiWUDnxIKSj7gtdQ2jiubxEEhfVagr8DMtAccNVTZVURpGi56TptOOuotrTqqC+2GviW4hlxvdvmuQN0OlXlUwzz2TrxcFamNnuA54lZw/8arLtxsFmHrcnPw53+1spumLD0S5UkxHNu40h6LIVpZz3H+0rLzuFofTfiyMjcfK2AyHQTgUCbsrvgNuLDQUbyFGVchdFUkhztX3DhEVnxnnrpY4BVjQdTqWIvw7lGlSuDCjxEQAOc=
+site=true
+email=true
+code=false
+
+[/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root]
+x509=MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+site=true
+email=false
+code=false
+
+[/C=JP/O=CyberTrust Japan, Inc./CN=CyberTrust JAPAN Root CA]
+x509=MIICETCCAXoCAU4wDQYJKoZIhvcNAQEEBQAwUTELMAkGA1UEBhMCSlAxHzAdBgNVBAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xITAfBgNVBAMTGEN5YmVyVHJ1c3QgSkFQQU4gUm9vdCBDQTAeFw05ODA4MDQwNzU3MDBaFw0wMzA4MDQyMzU5MDBaMFExCzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFuLCBJbmMuMSEwHwYDVQQDExhDeWJlclRydXN0IEpBUEFOIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALet/MpHEHaJ/Wes5HMGfIFLHda1fA5Hr+ymVHWoxP1lr+fIsbFsNDWN97lkVygLIVredP7ceC6GRhJMfxEf3JO9X75mmIa4t+xtSdOQ2eF5AFZouq1sHyw7H8ksjEOwBELqgXOmzjN1RQ2KRXIvqldV5AfDQ+J1Og+8PNCEzrrvAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAt6ZkowyAPBzE2O5BO+WGpJ5gXdYBMqhqZC0gcEC6ck5m+gdlTgOOC/1W4K07IKcy+rISHoDfHuN6GMxX2+bJNGDvdesQFtCkLnDYJCO4pXdzQvkHOt0BbAiTBzUmECVgKf8J5WSfabkWSfNc3SRjRpMNsFM2dbxIILsZto/QIv0=
+site=true
+email=false
+code=false
+
+[/C=JP/O=CyberTrust Japan, Inc./CN=CyberTrust JAPAN Secure Server CA]
+x509=MIICIzCCAYwCAU8wDQYJKoZIhvcNAQEEBQAwWjELMAkGA1UEBhMCSlAxHzAdBgNVBAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xKjAoBgNVBAMTIUN5YmVyVHJ1c3QgSkFQQU4gU2VjdXJlIFNlcnZlciBDQTAeFw05ODA4MDQwODA2MzJaFw0wMzA4MDQyMzU5MDBaMFoxCzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFuLCBJbmMuMSowKAYDVQQDEyFDeWJlclRydXN0IEpBUEFOIFNlY3VyZSBTZXJ2ZXIgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKwmo6G4b2rALBL52zEFkuf9+tSBtLjVKtWQ+vBDZfwSFcrs27lh3jNjN0+vADx/kjcbGHPlnzyI8RoTRP558sMmlQ8L8J4UByFsV8Jdw+JRsM2LX81fhjj4eZc57Oi/Ui6xXqqprozt7tfIty4xi7Q5kjt8gScHGgFEL0lzILbJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAaB17Eu5aeSkxygGsi1CpJ5ksAPw4Ghz/wtXwE/4bpzn1gBTrUfrAjXuEG1musTVRbqE+1xvsoJ7f4KWCluOxP9io8ct5gI738ESZfhT1I6MR42hLBTZuiOOrhqo4UwNCO9O5+eC/BenTX8NKp7b9t12QSfiasq1mpoIAk65g/yA=
+site=true
+email=false
+code=false
+
+[/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Root 5]
+x509=MIIDtjCCAp6gAwIBAgICAbYwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3QgU29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290IDUwHhcNOTgwODE0MTQ1MDAwWhcNMTMwODE0MjM1OTAwWjBwMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xHjAcBgNVBAMTFUdURSBDeWJlclRydXN0IFJvb3QgNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwSbj+KfHqXAeweuzlaAvR4RKJIG457SVJ6uHtHs6+Um2+7lvoramVcuByUc76/iQoigO5X/IwFu3CflzkE2qOHXKjlyq/AM5rVN1xLrOSA0KYjYPv9ci6UncfOwgQy73hgXe2thw9FZR48mgqavl0dmezn8tHGehfZrZtUln/EfGC/haoVNR1A2hG87FQhKC0joajwzy3N3fx+D17hZQdWywe00lboXjHMGGPEhtIthc+Tkqtt/mg5+95zvYb45EZ66p8My/QZ/mO80Sx7iDM29uThnAxTgWAc2i6rlqkWiBNQmbK9Vd8VMH7o5Zj7cH5stQf8/Ea30O03ln4y/iECAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0gBBAwDjAMBgoqhkiG+GMBAgEDMBkGA1UdDgQSBBB2CkkhOEyf3vjEScdxcZGdMA0GCSqGSIb3DQEBBQUAA4IBAQBBOtQYW9q43iEc4Y4J5fFoNP/elvQH9ac886xKsZv6kvqb7eYyIapKdsXcTzjl39WG5NXIdn2Y17HNj021kSNsi4rr6nzvFJTExvAfSi0ycWMrY5EmAgm2gB3t4sy4f9uHY8jh0GwmsTUdQGYQG82VVBgzYewTT9oT95mvPtDPjqZyorPDBZrJJ32SzH5SjbOrcG2eiZ9N6xp1wpiq1QIW1wyKvyXk6y28mOlYOBl8uTf+2+KZCHMGx5eDan0QAS8yuRcFSmXmL86+XlOmgumaUwqEdC2DysiUFnZflGEo8IWnObvXi9moshMdVAk0JH0ggX1mfqKQdFwQxr3sqxvC
+site=true
+email=true
+code=false
+
+[/C=US/O=GTE Corporation/CN=GTE CyberTrust Root]
+x509=MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY
+site=true
+email=false
+code=false
+
+[/C=BE/O=GlobalSign nv-sa/OU=Partners CA/CN=GlobalSign Partners CA]
+x509=MIIDnjCCAoagAwIBAgILAgAAAAAA1ni50a8wDQYJKoZIhvcNAQEEBQAwVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAwMDBaFw0wOTAxMjgxMjAwMDBaMF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xvYmFsU2lnbiBQYXJ0bmVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANIs+DKsShJ6N8gpkaWujG4eDsA0M4jlM3EWHHiEaMMYNFAuFj6xlIJPsZqfAPjGETXGaXuYAq0ABohs50wzKACIJ0Yfh7NxdWO8MruI3mYYDlAGk7T2vBQ3MD0i3z3/dX7ZChrFn7P80KyzCHqJ0wHoAFznSgs9TXsmordiBovaRt2TFz8/WwJLC7aIIBGSAK27xy7U40Wu9YlafI2krYVkMsAnjMbyioCShiRWWY10aKKDQrOePVBBhm8gbvb9ztMZ4zLMj+2aXm0fKPVSrG4YXvg90ZLlumwBiEsK8i3eZTMFQqBMqjF2vv2/gXj5cRxGXi0VlS0wWY5MQdFiqz0CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgAGMB0GA1UdDgQWBBRDJI1wFQhiVZxPDEAXXYZeD6JM+zAfBgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBm7bSIaRGZgiGDrKFti5uErQ8tyB6Mynt+rarUjt4H1p5Fx6W4nAc5YCVVGsBPGeXPFylJiRg1ZuXrKEBOV8mvs+S4IAWjO5VQkUmUKX0s5YhBpUWIXp2CJ/fS71u1T5++/jVlLFVkn+FR2iJhd7pYTo/GeVlZbjCAok+QbiELrdBoOZAQm+0iZW8eETjmf4zS8zltR9Uh6Op1OkHRrfYWnV0LIb3zH2MGJR3BHzVxLOsgGdXBsOw95W/tAgc/E3tmktZEwZj3X1CLelvCb22w0fjldKBAN6MlD+Q9ymQxk5BcMHu5OTGaXkzNuUFPUOQ9OK7IZtnHO11RR6ybq/Kt
+site=true
+email=true
+code=false
+
+[/C=BE/O=GlobalSign nv-sa/OU=Primary Class 1 CA/CN=GlobalSign Primary Class 1 CA]
+x509=MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4N88wDQYJKoZIhvcNAQEEBQAwVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MTUxMjAwMDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDEgQ0ExJjAkBgNVBAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAxIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSA1R9Eo1gijEjkjRw29cCFSDlcxlaY0V2vsfkN5wwZSSM28taGZvdgfMrzP125ybS53IpCCTkuPmgwBQprZcFm2nR/mY9EMrR1O+IWB+a7vn6ZSYUR5GnVF4GFWRW1CjD1yy6akErea9dZg0GBQs46mpuy09BLNf6jO77PhhTD+csTm53eznlhB1lGDiAfGtmlPNt7RC0g/vdafIXRkbycGPkv9Dqabv6RIV4yQ7okYCwKBGL5n/lNgiCe6o3M0S1pWtN5zBe2Yll3sSudA/EsJYuvQ4zFPhdF6q1lnK/uID+uqg701/WEn7GYOQlf3acIM7/xqwm5J2o9BOK5IqQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAAYwHQYDVR0OBBYEFPzgZvZaNZnrQB7SuB5DvJiOH4rDMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAJujCETO8pCdcfMyswVqterPKZjeVT6gFn0GekTWr9L6E1iM+BzHqx20G+9paJhcCDmP4Pf7SMwh57gz2wWqNCRsSuXpe2Deg7MfCr5BdfzMMEi3wSYdBDOqtnjtKsu6VpcybvcxlS5G8hTuJ8f3Yom5XFrTOIpk9Te08bM0ctXVIT1L13iT1zFmNR6j2EdJbxyt4YB/+JgkbHOsDsIadwKjJge3x2tdvILVKkgdY89QMqb7HBhHFQpbDFw4JJoEmKgISF98NIdjqy2NTAB3lBt2uvUWGKMVry+U9ikAdsEVF9PpN0121MtLKVkkrNpKoOpj3l9Usfrz0UXLxWS0cyE=
+site=true
+email=true
+code=false
+
+[/C=BE/O=GlobalSign nv-sa/OU=Primary Class 2 CA/CN=GlobalSign Primary Class 2 CA]
+x509=MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4jY0wDQYJKoZIhvcNAQEEBQAwVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAwMDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDIgQ0ExJjAkBgNVBAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkoz+7/RFjhdBbvzYvyFvqwadUsEsAJ0/joW4f0qPvaBjKspJJ65agvR04lWS/8LRqnmitvrVnYIET8ayxl5jpzq62O7rim+ftrsoQcAi+05IGgaS17/Xz7nZvThPOw1EblVB/vwJ29i/844h8egStfYTpdPGTJMisAL/7h0MxKhrT3VoVujcKBJQ96gknS4kOfsJBd7lo2RJIdBofnEwkbFg4Dn0UPh6TZgAa3x5uk7OSuK6Nh23xTYVlZxkQupfxLr1QAW+4TpZvYSnGbjeTVNQzgfR0lHT7w2BbObnbctdfD98zOxPgycl/3BQ9oNZdYQGZlgs3omNAKZJ+aVDdwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAAYwHQYDVR0OBBYEFHznsrEs3rGna+l2DOGj/U5sx7n2MB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAGPdWc6KeaqYnU7FiWQ3foqTZy8Q6m8nw413bfJcVpQZGmlgMEZdj/JtRTyONZd8L7hR4uiJvYjPJxwINFyIwWgk25GF5M/7+0ON6CUBG8QO9wBCSIYfJAhYWoyN8mtHLGiRsWlC/Q2NySbmkoamZG6Sxc4+PH1x4yOkq8fVqKnfgqc76IbVw08Y40TQ4NzzxWgu/qUvBYTIfkdCU2uHSv4y/14+cIy3qBXMF8L/RuzQ7C20bhIoqflA6evUZpdTqWlVwKmqsi7N0Wn0vvi7fGnuVKbbnvtapj7+mu+UUUt17tjU4ZrxAlYTiQ6nQouWi4UMG4W+Jq6rppm8IvFz30I=
+site=true
+email=true
+code=false
+
+[/C=BE/O=GlobalSign nv-sa/OU=Primary Class 3 CA/CN=GlobalSign Primary Class 3 CA]
+x509=MIIDrDCCApSgAwIBAgILAgAAAAAA1ni41sMwDQYJKoZIhvcNAQEEBQAwVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAwMDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDMgQ0ExJjAkBgNVBAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAzIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkV5WZdbAwAScv0fEXHt6MQH5WJaZ4xyEL9xWj631WYHVQ2ZdWpOMdcqp5xHBURAUYMks1HuvxneGq3onrm+VuQvKtkb7fhr0DRRt0slOsq7wVPZcQEw2SHToVIxlZhCnvSu3II0FSa14fdIkI1Dj8LR5mwE5/6870y3u4UmNjS88akFFL5vjPeES5JF1ns+gPjySgW+KLhjc4PKMjP2H2Qf0QJTJTk9D32dWb70DUHyZZ6S5PJFsAm6E1vxG98xvGD4X8O8LZBZX5qyG8UiqQ8HJJ3hzREXihX26/7Ph+xsFpEs7mRIlAVAUaq9d6sgM7uTa7EuLXGgTldzDtTA61wIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAAYwHQYDVR0OBBYEFMw2zBe0RZEv7c87MEh3+7UUmb7jMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFeyVMy9lRdkYIm2U5EMRZLDPahsw8yyGPV4QXTYfaMnr3cNWT6UHWn6idMMvRoB9D/o4Hcagiha5mLXt+M2yQ6feuPC08xZiQzvFovwNnciyqS2t8FCZwFAY8znOGSHWxSWZnstFO69SW3/d9DiTlvTgMJND8q4nYGXpzRux+OcSOW0qkX19mVMSPISwtKTjMIVJPMrUv/jCK64btYsEs85yxIq56l7X5g9o+HMpmOJXH0xdfnV1l3y0NQ9355xqA7c5CCXeOZ/U6QNUU+OOwOuow1aTcN55zVYcELJXqFetNkio0RTNaTQz3OAxc+fVph2+RRMd4eCydx+XTTVNnU=
+site=true
+email=true
+code=false
+
+[/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA]
+x509=MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+site=true
+email=true
+code=false
+
+[/C=CA/ST=ON/L=Toronto/O=MailEngine Inc./OU=Certification Authority Division/CN=mailengine/Email=ca@mailengine.com]
+x509=MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9NYWlsRW5naW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlzaW9uMRMwEQYDVQQDEwptYWlsZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBtYWlsZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNVBAoTD01haWxFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCm1haWxlbmdpbmUxIDAeBgkqhkiG9w0BCQEWEWNhQG1haWxlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqXmfsU+lx+NFmn6tN17RTOyaddHqLnr/3rzEDIyT9TN+tF9TG7jmK7lJJrj5arQ3nTFaLF8JuND2U1z/cLPw6/TX+1tE3v3CNUDSjaisyUDiUyp3TE8hMMMzzfZQn0JsGgNhhWxqyzjhRQGtKL4+xtn8VsF/8zGgZYke7nlmVKz/FslDFTnNoodLBAEGiu9JQS9qqpbSs20NdZ6LXPL2A4iTjnsNFBW3jIMVIn/JVVyaycU7ue2oFviDvLNpkVZcR7A+jjIdIumOc5VSF0y7y74cQC5YwkR2mLK7UBYDK6NCY3ta/C4M8NsM0FpmvRl0+A1ivZtVwqI98dxDtp7HeQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAjfNn5BCzxylBDakFQGWKE/P43PRibMOEzfd7+DzbYWIekoz3i00DwoH3b6j4gwlDJRAOq4dF6/Pt/uBOHDo/op+ef+9ErmKPd+ehXN9h37QbccTgz7DtVwA4iRlDRLru+JuXzT+OsCHuFZMOLJ+KD2JAGh3W68JjdcLkrlcptAU0wc5aOHPPfEBdIah8y8QtNzXRVzoBt8zzvgCARkXxTS2u/9QaXR1hML0JtDgQSSdZ6Kd8SN6yzqxD+buYD5sOfJmjBF/n3lqFHNMHnnGXy2TAXZtIAWzffU3A0cGPBN6FZ026a86HbF1X4k+xszhbJu/ikczyuWnCJIg3fTYSD
+site=true
+email=true
+code=false
+
+[/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte Personal Basic CA/Email=personal-basic@thawte.com]
+x509=MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+site=true
+email=true
+code=false
+
+[/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte Personal Freemail CA/Email=personal-freemail@thawte.com]
+x509=MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjPMPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRzneigQ==
+site=true
+email=true
+code=false
+
+[/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte Personal Premium CA/Email=personal-premium@thawte.com]
+x509=MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIHb4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+site=true
+email=true
+code=false
+
+[/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/Email=premium-server@thawte.com]
+x509=MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+site=true
+email=true
+code=false
+
+[/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/Email=server-certs@thawte.com]
+x509=MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+site=true
+email=true
+code=false
+
+[/O=Thawte/OU=Thawte Universal CA Root/CN=Thawte Universal CA Root]
+x509=MIIRIjCCCQoCAQAwDQYJKoZIhvcNAQEFBQAwVzEPMA0GA1UEChMGVGhhd3RlMSEwHwYDVQQLExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QxITAfBgNVBAMTGFRoYXd0ZSBVbml2ZXJzYWwgQ0EgUm9vdDAeFw05OTEyMDUxMzU2MDVaFw0zNzA0MDMxMzU2MDVaMFcxDzANBgNVBAoTBlRoYXd0ZTEhMB8GA1UECxMYVGhhd3RlIFVuaXZlcnNhbCBDQSBSb290MSEwHwYDVQQDExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QwgggiMA0GCSqGSIb3DQEBAQUAA4IIDwAwgggKAoIIAQDiiQVtw3+tpok6/7vHzZ03seHSIR6bYSoV53tXT1U80Lv52T0+przstK1TmhYC6wty/Yryj0QFxevT5b22RDnm+0e/ap4KlRjiaOLWltYhrYj99Rf109pCpZDtKZWWdTrah6HU9dOH3gVipuNmdJLPpby732j/cXVWQVk16zNaZlHy0qMKwYzOc1wRby2MlYyRsf3P5a1WlcyFkoOQVUHJwnft+aN0QgpoCPPQ0WX9Zyw0/yR/53nIBzslV92kDJg9vuDMGWXb8lSir0LUneKuhCMlCTMStWoedsSL2UkAbF66H/Ib2mfKJ6qjRCMbg4LO8qsz7VSk3MmrWWXROA7BPhtnj9Z1AeBVIt12d+yO3fTPeSJtuVcD9ZkIpzw+NPvEF64jWM0k8yPKagIolAGBNLRsa66LGsOj0gk8FlT1Nl8k459KoeJkxhbDpoF6JDZHjsFeDvv5FXgE1g5Z2Z1YZmLSlCkyMsh4uWb2tVbhbMYUS5ZSWZECJGpVR9c/tiMaYHeXLuJAr54EV56tEcXJQ3DvSLRerBxpLi6C1VuLvoK+GRRe5w0ix1Eb/x6b8TCPcTEGszQnj196ZoJPii0Tq0LPIVael45mNg+Wm+Ur9AKpKmqMLMTDuHAsLSkeP1B3Hm0qVORVCpE4ocW1ZqJ2Wu4Pv7Rn4ShuD+E2oYLRv9R34cRnMpN4yOdUU/4jeeZozCaQ9hBjXSpvkS2kczJRIfK7Fd+qJAhIBt6hnia/uoO/fKTIoIy90v+8hGknEyQYxEUYIyZeGBTKLoiHYqNT5iG3uIV7moW7FSZy+Ln3anQPST+SvqkFt5knv78JF0uZTK0REHzfdDH2jyZfqoiuOFfIVS3T+9gbUZm+JRs6usB9G+3O0km5z/PFfYmQgdhpSCAQo/jvklEYMosRGMA/G4VWzlfJ8oJkxt8CCS5KES+xJ203UvDwFmHxZ43fh3Kvh9rP+1CUbtSUheuKLOoh9ZZKRNXgzmp0RE3QBdOHFe020KSLZlVwk+5HBsF+LqUYeWfzKIXxcPcOg6R+VJ5adjLLZRu4zfvIKAPSVJHRp8WFQwgXdqXmL2cI2KGigi0M+MGvY9RQd21rRkpBhdWQX3ktxOzXEYdAiuFo4mT4VTL7b5Ms2nfZIcEX5TYsTn6Qf6yUKzJnvjhQdriuQbnXIcUJTGDIo1HENJtXN9/LyTNXi+v7dp8ZTcVqHypFrivtL42npQDLBPolYi50SBvKKoy627Z+9rsCfKnD21h4ob/w/hoQVRHO6GlOlmXGFwPWB2iMVIKuHCJVP/H0CZcowEb3TgslHfcH1wkdOhhXODvoMwbnj3hGHlv1BrbsuKYN8boTS9YYIN1pM0ozFa64yJiKJyyTvC377jO/ZuZNurabBlVgl0u8RM1+9KHYqi/AAighFmJ42whU8vz0NOPGjxxDV86QGkvcLjsokYk/eto1HY4s7kns9DOtyVOojJ8EUz4kHFLJEvliV6O87izrQHwgI3ArlflzF4rRwRxpprc4mmf3cB16WgxAz2IPhTzCAk5+tfbFKimEsx83KuGqckLE7Wsaj5IcXb7R8lvyq6qp0vW4pEErK5FuEkjKmNg3jcjtADC1tgROfpzahOzA+nvlHYikU0awlORcG6ElLA9IUneXCWzsWxgzgwLlgn7NhSEwEf0nT8/kHuw/pVds6SowGSqI5cNpOKtvOXF/hOFBw+HMKokgUi6DD2w5P0stFqwt8CSsAHP0m7MGPwW4FIUfq55cPJ5inQ5tO4AJ/ALqopd0ysf541bhw8qlpprAkOAkElPSwovavu0CQ15n4YmYee7LqsrDG9znpUalfGsWh7ZaKNfbJzxepb22Ud0fQ887Jsg6jSVhwUn0PBvJROqvHMIrlAEqDjDRW4srR+XD0QQDmw45LNYn1OZwWtl1zyrYyQAF5BOI7MM5+4dhMDZDA8ienKIGwi/F/PCAY7FUBKBMqS7G9XZ62NDk1JQR5RW1eAbcuICPmakgMz0QhUxlCco+WF5gk5qqYl3AUQYcXWCgDZxLQ/anFiGkh6rywS7ukjC4nt/fEAGLhglw2Gyot1AeFpa092f9NTohkCoyxwB7TQcQCbkvc9gYfmeZBE8G/FDHhZudQJ2zljf6pdyyck7vTgks/ZH9Tfe7pqE+q3uiA0CmqVUn4vr5Gc6HdarxdTbz87iR+JHDi3UTjkxlmhY5auU06HqWWX81sAD9W2n8Qyb69Shu/ofZfiT7tKCCblSi/66/YrT0cgHCy5hHmOFMtReAgM6PpijuHkVq+9/xHfxaO9bq9GwdYklXO4qPhurwUwTOnBZo/7q5/IgPR/cCRHJAuMo7LVOd3DxWjFl7aBosjXG7bADHGs5vQJKxoy8P2UTyo3Aunu4OrjLQOz6LB+rmebNcKeJ9a6he+Vox6AiWoowDmEbxuH2QVCbtdmL+numabl7JScdcNFMpVNns5EbhgDt12d/7edWH8bqe6xnOTFJz5luHriVPOXnMxrj5EHvs8JtxpAWg0ynTTn8f9C0oeMxVlXsekS/MVhhzi7LbvGkH5tDYT+2i/1iFo23gSlO3Z32NDFxbe3coAjVEegTTKEPIazAXXTK4KTW6dto7FEp2GFik+JI8nk0zb0ZrCNkxSGjd9PskVjSyz2lmvkjSimYizfJpzcJTE0UpQSLWXZgftqSyo8LuAi9RG9yDpOxwJajUCGEyb+ShgS58Y3L6KWW8cETPXQIDAQABMA0GCSqGSIb3DQEBBQUAA4IIAQBVmjRqIgZpCUUzx66pXMcJTpuGvEGQ1JRS9s0jKZRLIs3ovf6dzVLyve2rh8mrq0YEtL2iPyIwR1DAS4x2DwP1ktKxLcR6NZzJc4frpp/eD3ON03+Z2LqPb8Tzvhqui6KUNpDi5euNBfT8Zd+V8cSUTRdW1588j1A853e/lYYmZPtq/8ba6YyuQrtp5TPG2OkNxlUhScEMtKP5m0tc3oNPQQPOKnloOH3wVEkg9bYQ/wjcM2aWm/8G3gCe185WQ5pR/HDN9vBRo7fNtFyFYs1xt8YrIyvdw25AQvo3/zcc9npXlIeFI9fUycdfwU0vyQ3XXOycJe6eMIKRlnK4dR34CWhXl7ItS+4l7HokKe5y1JwT26vcAwrYShTJCFdEXaG1U4A08hSXz1Leog6KEOkU79BgvmGh8SVd1RhzP5MQypbus0DS26NVz1dapQ5PdUff6veQmm31cC4dFBw3ZARZULDccoZvnDc9XSivc1Xv0u4kdHQT79zbMUn7P2P10wg+M6XnnQreUyxRjmfbm0FlQVC91KSWbIe8EuCUx9PA5MtzWACD4awnhdadU51cvQo+A0OcDJH1bXv4QHJ1qxF2kSvhxqofcGl2cBUJ/pPQ1i23FWqbZ1y0aZ8lpn2K+30iqXHyzk6MuCEt3v5BcQ3/nexzprsHT4gOWEcufqnCx3jdunqeTuAwTmNvhdQgQen6/kNF5/uverLOpAUdIppYht/kzkyp/tgWpW/72M5We/XWIO/kR81jJP+5vvFIo8EBcua9wK3tJg3KNJ/8Ai0gTwUgriE9DMIgPD/wBITcz4n9uSWRjtBD5rMgq1wt1UCeoEvY9LLMffFYCo6H7YisNpbkVqARivKa0LNXozS7Gas44XRrIsQxzgHVGzbjHjhMM5PfQONZV06sbnseWj3FHVusyBCCNQIisvx16BCRjcR9eJNHnhydrGtiAliM1hwj1q94woCcpKokVBS1FJjG+CsaJMtxMgrimw5pa91+jGTRLmPvDn+xPohMnVXlyW4XBLdB/72KQcslMW9Edz9HsfyBiAeOBUkgtxHZaQMqA525M4Sa399640Zzo9iijFMZiFVMdLj2RIQr0RQtTjkukmj/afyFYhvrVU/vJYRiRZnW2E5vP1MIfR0GlYGAf09OdDaYteKHcJjc1/XcUhXmxtZ5ljl/j5XPq4BTrRsLRUAO1Bi9LN6Kd3b98kRHxiHQ5HTw2BgFyHwwcsff8bv8AjCp9EImWQ2TBYKhc+005ThdzVCQ/pT8E7y9/KiiiKdzxLKo0V2IxAKievEEyf6MdMnvHWRBn6welmdkrKsoQced98CYG24HwmR9WoNmVig2nOf7HHcOKKDE92t5OQQghMdXk7wboOq860LlqBH+/KxlzP34KIj0pZrlc1HgqJsNA3dO5eCYs4jafebGnnwUZsEuU0qSBzegfuk9CeQVfM/9uEGl755mncReBx2H+EGt6ucv0kFjGDf5FONN0OX3Q/0V4/k2cwYm3wFPqcNO3iBGd5i0eiQrO3UrTliNm12kxxagvDKIP6GD8wDI+NhY6WNdTCu18HJB2Kt3N9ZydK62NpzIpoNJS+DJVgspvgAwy93WyEKKANnsFdE0cfJbZIf2J9K364awkL8p2yGeNozjIC+VI1FsG8Kk1ebYAkNnoP6bUANEf7vkctXR5NqPkhRk+10UEBJKlQbJZQgpyiGjJjgRySffcGcE/cpIMn9jskV0MVBPh9kgcNIhcLHWEJ0zXXiDkW1Vguza5GJjx4FG1xllcipDGZC41yNNTBzgRKlmZ6zucXknJnhtcg71XUsjtXx8ZekXxjoLDd1eHlHDhrjsf8cnSqVG6GotGcGHo8uZk4dkolUUTLdDpZPX59JOeUDKZZlGPT96gHqIaswe5WszRvRQwNUfCbjNii6hJ+tdc6foawrlV4IqsPziVFJW8KupEsYjlgcknOC8RqW0IATaCZNj5dQuwn7FMe21FXSGF7mz8yaKHQJq2ho/6LrxBG2UUVTiWrRZgx1g0C1zzAe1Joz518aIke+Az10PoWDLRdRCItGxcB390LcwkDrGSG1n5TLaj9vjqOMdICWiHOFMuaT2xj9cWA27xrJ3ARaRnxcGDbdAPsyPjpxL4J1+mx4Fq4gi+tMoG1cUZEo+JCw4TSFpAHMu0FUtdPIV6JRDPkAqxsa5alveoswYUFRdTiqFbPaSiykZfufqSuAiKyW892bPd5pBdPI8FA10afVQg83NLyHbIkaK0PdRGpVX8gWLGhntO0XoNsJufvtXIgAfBlOprpPGj3EqMUWS545t5pkiwIP879xXZndPojYx+6ETjeXKo5V9AQxkcDtTQmiAx7udqAA1aZgMqGfYQ+Wqz5XgUZWkFz9CnbgEztN5ecjTihYykuDXou7XN0wvrLh7vkX28RgznHs3piTZvECrAOnDN4ur2LbzXoFOsBRrBz4f7ML2RCKVu7Pmb9b5cGW6CoNlqg4TL4MTI1OLQBb6zi/8TQT469isxTbCFVdIOOxVs7Qeuq3SQgYXDXPIV6a+lk2p8sD7eiEc9clwqYKQtfEM1HkQvoGm6VxhnHd5mqTDNyZXN8lSLPoI/9BfxmHA9Ha+/N5Oz6tRmXHH33701s8GVhkTUwttdFlIGZtTBS2dMlTT5SxTi2Q+1GR744AJFMz+FkZja3Fp+PnLJ/aIVLxFs84CyJTuQFv5QgLC/7DYLOsof17JJgGZpw==
+site=true
+email=false
+code=false
+
+[/C=CA/ST=ON/L=Toronto/O=TraderEngine Inc./OU=Certification Authority Division/CN=traderengine/Email=ca@traderengine.com]
+x509=MIID6TCCAtGgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRowGAYDVQQKExFUcmFkZXJFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2aXNpb24xFTATBgNVBAMTDHRyYWRlcmVuZ2luZTEiMCAGCSqGSIb3DQEJARYTY2FAdHJhZGVyZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGuMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGjAYBgNVBAoTEVRyYWRlckVuZ2luZSBJbmMuMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBEaXZpc2lvbjEVMBMGA1UEAxMMdHJhZGVyZW5naW5lMSIwIAYJKoZIhvcNAQkBFhNjYUB0cmFkZXJlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzyX5QE+5SN+zgNn1v3zp9HmP4hQOWW8WuEVItZVP9bt/xj5NeJd1kyPL/SqnF2qHcL3o/74r0Ga55aKHniwKYgQTlp5ELGfQ568QQeN9xNIHtUXeStI9zCNZyZC+4YqObdMR/ivKA/WsLfUVMl2lV5JzJJz1BOE0gKEYiEyzgIq5oLzkP/mOXoHRvWSZD2D0eHYIO7ovV2epVFK7g7p+dC4QoeIUEli+GF/Myg88dV/qmi+Sybck2RLPXa8Nh27/ETVQ7kE1Eafmx7EyCqIhG+5lwJAy3HwHUBwAYuzjiuZz5lD8aQmr8SKuvy3eOH9SVN5wh3YBlrNGwTStkESVLwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAWOPAUhZd3x9EQiFJcuxFTMd9qaxgcriCzJsM6D96sYGko9xTeLhX/lr1bliVYI5AlupoLXAdMzGHJkOgaTirKjQXrF9nymDdUWKe3TmwGob5016nQlH7qRKvGO3hka0rOGRK2U/2JT/4Qp8iH/DFi6cyMuP0q8n64SAkxZXLzUuFQXqf7U/SNjzb9XJQEIAdjp7eYd3Qb4jDsDcX0FrKMF1aVr0dCDnS7am7WTXPYCDGdSkPgEHEtLYIYH3lZp5sKdVZ9wl4F0WNFkRWRUr7AXPjw50uLmUNmKCd8JZLMGA1TRNSTi7U9EcrWt0OkMWm74T2WVnAgNsDv2WrWsGfj
+site=true
+email=true
+code=false
+
+[/C=US/O=United States Postal Service/OU=www.usps.com/CPS/CN=USPS Production CA 1]
+x509=MIIEeDCCA+GgAwIBAgICJ0swDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsTEHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4MTYyMTA2MzlaFw0yMDA4MTUxMzA2MjVaMG4xCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNwcy5jb20vQ1BTMR0wGwYDVQQDExRVU1BTIFByb2R1Y3Rpb24gQ0EgMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxta577JTOMrSdwxsNigwwtAoAnhxTg2JQsdZJ7OQCCfUl1oetnhEQGt0xo2rUYvopu1RptZ1F+x6VF5Wg+fwbcRJ9Be9BgsSxlXv6ajhKC+gQ4919P/Z3H3+qtR485yTxZnaYkab9XYkVAkKKesURUIL/w12Ax+nZYiipH9v0E8CAwEAAaOCAiswggInMIHPBgNVHSAEgccwgcQwgcEGB2CGSIb5bWUwgbUwIwYIKwYBBQUHAgETF2h0dHA6Ly93d3cudXNwcy5jb20vQ1BTMIGNBggrBgEFBQcCAjCBgBp+U2VlIFVTUFMgQ1BTIGF0IGh0dHA6Ly93d3cudXNwcy5jb20vQ1BTLiBUaGlzIGNlcnRpZmljYXRlIGlzIHRvIGJlIHVzZWQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggVVNQUyByZWd1bGF0aW9ucyBhbmQgcG9saWNpZXMuMCQGCWCGSIb5bWQCBgQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwJAYJYIZIhvltZAIIBBcwFaADAgEBoQMCAQKiAwIBAaMEAgInFTAkBglghkiG+W1kAgcEFzAVoAMCAQGhAwIBAqIDAgEBowQCAidLMBAGCWCGSIb5bWQCAQQDCgECMBAGCWCGSIb5bWQCAwQDCgEHMBkGCWCGSIb5bWQCBAQMMAqgCBoGTm9Sb2xlMB0GA1UdDgQWBBQl5aDvLXJPbZUfNx8g1sMBRAPH0DAfBgNVHSMEGDAWgBTTzoJ08y9LiWBypF4Rv191A6ICqzAdBgNVHRIEFjAUgRJyb290MTAwMDFAdXNwcy5jb20wIQYDVR0RBBowGIEWY2FhZG1pbkBlbWFpbC51c3BzLmNvbTAPBgNVHQ8BAf8EBQMDB8YAMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAcAmQhgkD1rSyWiOrPGVEr/WndJfcCC4EyFOXrWGpwjCKu2jTwWbAzS70nbA+qWPj718XgmaQb3C+LUJkQWJ/IiXBtc9WOTF3bqCT+Rqpw9wKcHbFtS2bl4N2zgJeyG3dgrDqW1kNCYdAh3G+xaiXBbxD++6tJgq8e0VfjlmoK4o=
+site=true
+email=true
+code=false
+
+[/C=US/O=United States Postal Service/OU=www.usps.com/CPS/CN=USPS Root CA]
+x509=MIIDbjCCAtegAwIBAgICJxEwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsTEHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4MTUxOTM1NThaFw0yMDA4MTUxOTM1NThaMGYxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNwcy5jb20vQ1BTMRUwEwYDVQQDEwxVU1BTIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALepJaxj2rCSz5Q2sAT/Fm52BFv1xjyfxrlCJlX7k3GFEWXJYSeIxF6b/ip4SlJqRZ+o+5G04yZd9UMUJrnePG0sZvVTfd7kVleyonn14bTaavck5bMo/p53luIOxwUDzOlR9pb8EcCWLXM1/1hzX/JINeVES9B+1QAehG3YJdjRAgMBAAGjggEpMIIBJTAkBglghkiG+W1kAgYEFzAVoAMCAQGhAwIBAqIDAgEBowQCAicRMCQGCWCGSIb5bWQCBwQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwEAYJYIZIhvltZAIBBAMKAQEwEAYJYIZIhvltZAIDBAMKAQYwUwYJYIZIhvltZAIEBEYwRKA0GjJDQSBNQVNURVIgUlNBIDEwMjQgQmVyIChTRUxGIFNJR04pIChDaHJ5c0FsaXMgQ1NQKaEMMAqhAwoBAKIDAwEAMB0GA1UdDgQWBBTTzoJ08y9LiWBypF4Rv191A6ICqzAdBgNVHREEFjAUgRJyb290MTAwMDFAdXNwcy5jb20wDwYDVR0PAQH/BAUDAwfGADAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAI7SbReJ5I5NalEKF2ARay289lC8DMpJqaw7qotxs9HL9hx+IkIh6av2EiAybbIYKhFpcdjKWUqYrTKYo5hjUW0jIfJRrqB3giO7nciBgas7CFr6y02kLHfLYKik//iMkFQtsLSDSguwPOvsY5vllP4Fo94aBCf2/0+o6iQIKyWa
+site=true
+email=true
+code=false
+
+[/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 1 Policy Validation Authority/CN=http://www.valicert.com//Email=info@valicert.com]
+x509=MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+site=true
+email=false
+code=false
+
+[/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//Email=info@valicert.com]
+x509=MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+site=true
+email=false
+code=false
+
+[/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 3 Policy Validation Authority/CN=http://www.valicert.com//Email=info@valicert.com]
+x509=MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+site=true
+email=false
+code=false
+
+[/L=ValiCert Validation Network/O=ValiCert, Inc./OU=Class 1 Validation Authority - OCSP/CN=http://www.valicert.net//Email=info@valicert.com]
+x509=MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZMddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMBAAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkwCwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0KazDawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDTNDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==
+site=false
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 4 Public Primary Certification Authority]
+x509=MIICMTCCAZoCBQKmAAABMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBaFw05OTEyMzEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LJ19njQrlpQ9OlQqZ+M1++RlHDo0iSQdomF1t+s5gEXMoDwnZNHvJplnR+Xrr/phnVjIIm9gFidBAydqMEk6QvlMXi9/C0MN2qeeIDpRnX57aP7E3vIwUzSo+/1PLBij0pdO92VZ48TucE81qcmm+zDO3rZTbxtm+gVAePwR6kCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBT3dPwnCR+QKri/AAa19oM/DJhuBUNlvP6Vxt/M3yv6ZiaYch6s7f/sdyZg9ysEvxwyR84Qu1E9oAuW2szaayc01znX1oYx7EteQSWQZGZQbE8DbqEOcY7l/AmyY7uvcxClf8exwI/VAx49byqYHwCaejcrOICdmHEPgPq0ook0Q==
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 1 Public Primary Certification Authority]
+x509=MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 1 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network]
+x509=MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 1 Public Primary Certification Authority - G3]
+x509=MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+site=true
+email=false
+code=false
+
+[/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/RPA (c)00/CN=Class 1 Public Primary OCSP Responder]
+x509=MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyhWzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEzy+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMTCE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5jb20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMXfH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD
+site=false
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 2 Public Primary Certification Authority]
+x509=MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 2 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network]
+x509=MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg==
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 2 Public Primary Certification Authority - G3]
+x509=MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+site=true
+email=false
+code=false
+
+[/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/RPA (c)00/CN=Class 2 Public Primary OCSP Responder]
+x509=MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKMRF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMTCE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5jb20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUEnPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1VsWJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN
+site=false
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority]
+x509=MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network]
+x509=MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3]
+x509=MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+site=true
+email=false
+code=false
+
+[/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/RPA (c)00/CN=Class 3 Public Primary OCSP Responder]
+x509=MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFWuXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrAPjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMTCE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggrBgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNpZ24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNjwKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJULBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnEKMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==
+site=false
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=Class 4 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network]
+x509=MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0ycyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRPT8qAkbYp
+site=true
+email=false
+code=false
+
+[/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3]
+x509=MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+site=true
+email=false
+code=false
+
+[/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/RPA (c)00/CN=Secure Server OCSP Responder]
+x509=MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4xFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJlIFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjktns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8CAwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEtNDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9SU0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYIKwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlzaWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEwCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBTZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8YdZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==
+site=false
+email=false
+code=false
+
+[/C=US/O=RSA Data Security, Inc./OU=Commercial Certification Authority]
+x509=MIICIzCCAZACBQJBAAAWMA0GCSqGSIb3DQEBAgUAMFwxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVyY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NDExMDQxODU4MzRaFw05OTExMDMxODU4MzRaMFwxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVyY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBmzANBgkqhkiG9w0BAQEFAAOBiQAwgYUCfgCk+4Fie84QJ93o975sbsZwmdu41QUDaSiCnHJ/lj+O7Kwpkj+KFPhCdr69XQO5kNTQvAayUTNfxMK/touPmbZiImDd298ggrTKoi8tUO2UMt7gVY3UaOLgTNLNBRYulWZcYVI4HlGogqHE7yXpCuaLK44xZtn42f29O2nZ6wIDAQABMA0GCSqGSIb3DQEBAgUAA34AdrW2EP4j9/dZYkuwX5zBaLxJu7NJbyFHXSudVMQAKD+YufKKg5tgf+tQx6sFEC097TgCwaVI0v5loMC86qYjFmZsGySp8+x5NRhPJsjjr1BKx6cxa9B8GJ1Qv6km+iYrRpwUqbtbMJhCKLVLU7tDCZJAuqiqWqTGtotXTcU=
+site=true
+email=false
+code=false
+
+[/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority]
+x509=MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+site=true
+email=false
+code=false
+
+[/C=US/O=VISA/OU=Visa International Service Association]
+x509=MIIDWDCCAkCgAwIBAgICAx0wDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMB4XDTAwMDgxNjIxNTIwMFoXDTIwMDgxNTIzNTkwMFowTTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxR1Nc0GV4SC0bGzOZ+p1BqzEBMJgLwiSzyDtbqnJcSZWov3auwz4lQnJ+fIdz0SV7TFK2m3gvfx1FpbC7wp6DMe4tJBGLqkXCuBHRIR8HD0gRgZDQ4Vy613hA7wymsvuCcZXFbMu2jJgpxKYkpvTyiNCsCP3UGlOjJtooTcwkskhL2iKoNaEqVhNDOtVPboKRkj6wr65B8DsvZM0eTk9t5o0oAw9o/+ahOb64D+qVIQBM0qFxqgUXhXB12DV8Gl4aWR41xTuE9ij8v91YThs1Cay12iIGWcO6+G/vI6a6siU6bbM+BWFk21mdyuxFwuIJmxGot/OQ6Vu9/0bR25Y9wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUy8PGY8recX/bp9f/QnT2y8y2UDIwDQYJKoZIhvcNAQEFBQADggEBALYYhKS+5n/N+0aRFH0AQHd3hrmNcR2c/vHY5QE/2aJgG826czQs7l4EksQiRFbs6vv3yQEW/ego7fje/Tw+LpiMjeN44s+Oi+CvwY1gFIKCVrGHLvDpEhUdPmkKrY6mWPSZ/BFG7vfJ7cavLLmGJdKX/k+d2DLhwmZRc4YN3XXjivr0ijVm3YhnrXmo/Gn12/qvlbSckB9fwRbJyAiAGtcD8l5xo1ZjHkU2fXG+MWd0hi/Z7IjCIL2ZTT1VBdCiWkxVIpjQ8XX0F/rY4/7iFOAPZfqy1mksM1DJJ6CskDFLFOXrY2TgPeP8EkrFloIt2iU5/tR/LkHHYkjXcUU7eJI=
+site=true
+email=true
+code=false
+
+[/C=US/O=VISA/OU=Visa International Service Association/CN=GP Root 2]
+x509=MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQkIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
+site=true
+email=true
+code=false
+
+[/C=US/O=VISA/OU=Visa International Service Association/CN=GP Root 3]
+x509=MIIDgDCCAmigAwIBAgICAx8wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDMwHhcNMDAwODE2MjMzNDAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrsQ7g06qNn33cJHxoQoh6pTpVMdOcM3GzGmNCr+hckmmejSRRkiY+TEi/vj9jOEASLhcDcL7wpmK+cQsXL0pbP9KXFLW5NjDiOsmoImdWRG6jtM5NJXcvnFUNtUvHI6NfaMOCYKqlbo8PRAQOBXX62CZXo2zJu/TrDtZ6b/VkZILMjwOJq7kSWgO9oCUCUwrczSYPlya4tIDeQGD0gNtp5Oa+4V59672AqIYT4/6A5IdPYbVTHw2o8yFwfLkdyFGxVSwkGzY7FawvnB0c6fZJffQ+wXDNXg4M/HoSoeZCfl04i3HUiyG4v1tDLduEMV5fhJo8phFPy5Y6TykuKTDUCAwEAAaNCMEAwHQYDVR0OBBYEFKJcbg1lCMH3TlvJbfDQVhs5gkO7MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQADjVYIs6Gt/XNC2WcsbprPvx7ITfJN0tk3yThEja6JDO+MmStKk/VtrGZKP1dqEKWiGhOmLOpi54D5vf3k/9oRnzlYbfVD8vT9pr+dsauaRgff4fBbP/5dWUAGrBgIR0w8TEhGzojhqLaedaag934btsSN7fAqUxVK2ylPOVPnUlijvtzkkC21yc6Y/yyGoQigyM73gjkJDMHC1KmkKg4zgcc8cMswbaRWt5tcfAIivuUHfW0k0Sex1h0eXEc8vy5u+ByESOz14aCVEc3nMOtc8Cl7dYICBrLzkznSDqzfXyQTFTBD9VDUx4OgQzlPZTS9punO4XS+IN/SchZLiUZ2
+site=true
+email=true
+code=false
+
+[/C=US/O=VISA/OU=Visa International Service Association/CN=GP Root 4]
+x509=MIICezCCAeSgAwIBAgICAyAwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDQwHhcNMDAwODE3MDAxOTAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuOvwj6Dm8eMAP15ynq4ED/RPzsraYjPq7lrCwfYuOIm0Dc+hrrkxs/2mx7bEbIMMgGE4Ogq+HAGgGRvn+3JtkmObpq8z9LRbGugo3kznN/EU8eAX4BRI7EQdeaVOquGkhHe9y0226nB+X6oXLEtbsOqF1GmoEekrNx27pgTum0ECAwEAAaNCMEAwHQYDVR0OBBYEFEPGSEDAD8YYWklJ5YGABk1f3dSFMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAKQZPXPOh9GfVhJcyDjl7vkSyNkB6p2DNMaia4t3epJ+h8dVIxSNwmhNGfJptOpHFJE7UYcY+nab4nscE9PmZh4KErldkMY7ExQizTWMLUVgAATI71gCxV2ZtJBt3lTXI+I5hCXDaKNio3nYmKFa0lyJ/eUWDPSrF0h+reuAwFWB
+site=true
+email=true
+code=false
+
+[/C=US/O=VISA/OU=Visa International Service Association/CN=GP Root 5]
+x509=MIICezCCAeSgAwIBAgICAyEwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDUwHhcNMDAwODE3MDAyODAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgNTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArQBu8qB8MREcQbA3j4OiQ8uXXwIgiQ1uvCqx8aVk79iOStZynZ5uH5qo+YUDrMEnaoTlZkhxml5CD4rin/aADyOsU8PBnwLE+FhG6vSpgq9tB0aG8S38BrgeVdU5YZKEi/HYijNOPBO11nH8az60HHoLh9U1ZjTDczJjWN8SayMCAwEAAaNCMEAwHQYDVR0OBBYEFCNO8wIEBNfSpwBWwc5JLIwVljMvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBADyUAYfyyM/hj665C+IcffEZrdHt9gFbNlMKgD6uNFZncG5DVE55zYvVUBky2Ek4NP22c0nrDkl6vxr36gcoJbsVSRxRSlWaOC8tD1j5edECZROMWZ8Qf10XPHTytep3gTaGbzJbBbQNoyZn8OQ1Dke9a8GRnQv0P5oRfJQWZ7aY
+site=true
+email=true
+code=false
+
+[/C=US/ST=Utah/L=Salt Lake City/O=Xcert EZ by DST/CN=Xcert EZ by DST/Email=ca@digsigtrust.com]
+x509=MIID+DCCAuCgAwIBAgIRANAeQJAAACdLAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEYMBYGA1UEChMPWGNlcnQgRVogYnkgRFNUMRgwFgYDVQQDEw9YY2VydCBFWiBieSBEU1QxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05OTA3MTQxNjE0MThaFw0wOTA3MTExNjE0MThaMIGMMQswCQYDVQQGEwJVUzENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxGDAWBgNVBAoTD1hjZXJ0IEVaIGJ5IERTVDEYMBYGA1UEAxMPWGNlcnQgRVogYnkgRFNUMSEwHwYJKoZIhvcNAQkBFhJjYUBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtVBjetL/3reh0qu2LfI/C1HUa1YS5tmL8ie/kl2GS+x244VpHNJ6eBiL70+o4y7iLB/caoBd3B1owHNQpOCDXJ0DYUJNDv9IYoil2BXKqa7ZpmKt5Hhxl9WqL/MUWqqJy2mDtTm4ZJXoKHTDjUJtCPETrobAgHtsCfv49H7/QAIrbQHamGKUVp1e2UsIBF5h3j4qBxhq0airmr6nWAKzP2BVJfNsbof6B+of505DBAsD50ELpkWglX8a/hznplQBgKL+DLMDnXrbXNhbnYId26OcnsiUNi3rlqh3lWc3OCw5vxsic4xDZhTnTt5v6xrp8dNJddVardKSiUb9SfO5xAgMBAAGjUzBRMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUCCBsZuuBCmxc1bWmPEHdHJaRJ3cwHQYDVR0OBBYEFAggbGbrgQpsXNW1pjxB3RyWkSd3MA0GCSqGSIb3DQEBBQUAA4IBAQBah1iPLat2IWtUDNnxQfZOzSue4x+boy1/2St9WMhnpCn16ezVvZY/o3P4xFs2fNBjLDQ5m0i4PW/2FMWeY+anNG7T6DOzxzwYbiOuQ5KZP5jFaTDxNjutuTCC1rZZFpYCCykSYbQRifcML5SQhZgonFNsfmPdc/QZ/0qB0bJSI/08SjTOWhvgUIrtT4GV2GDn5MQNu1g+WPdOaG8+Z8nLepcWJ+xCYRR2uwDF6wg9FX9LtiJdhzuQ9PPA/jez6dliDMDDWa9gvR8N26E0HzDEPYutsB0Ek+1f1eS/IDAE9EjpMwHRLpAnUrOb3jocq6mXf5vrwo3CbezcE9NGxXl8
+site=true
+email=true
+code=false
+
+[/O=Xcert International Inc./OU=Xcert Root CA]
+x509=MIIDYzCCAkugAwIBAgIQCgEBAQAAAnwAAAACAAAAAjANBgkqhkiG9w0BAQUFADA7MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhjZXJ0IFJvb3QgQ0EwHhcNMDAwODE4MTgxODE3WhcNMjUwODE1MTkwMzE3WjA7MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhjZXJ0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCotGGLHRw+kHtwMkBtjRbKNWFhteL7Fcn0IV6BG88inKyru2DQoDPeEVMaCQ87GhOp1IfMWPctUqmiwqk67c80naEC77jyuCtXiBCTtak1Y7sFQkMif79wXtMopVUoIEuTSY+nvz1AKA0Rr3ImCQU0CcWrAZNXoaxmVJginCPrugxknLY9++LGlsLPC0/qyDD6iivKHBGWGikAjOty1FFFqZ13INUSu7XyfwY4gk19kh7o1frIKUdpGhURjK+mLMEo9GlbaZ7kPBPuwKFg6kG/wmJLbaI3hDo+87AyroprbBPzOiEKe5ZYMylebqjKaaK+jgZFXfFmOVVKHFoksUvRAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFESoSTh1MWyrKOdx8tjUyK9BD0eRMB0GA1UdDgQWBBREqEk4dTFsqyjncfLY1MivQQ9HkTANBgkqhkiG9w0BAQUFAAOCAQEAPXNepQq7tRHD8WfREhqiRykRTE5ZNyCGCUDyRfFJeTkaPSXXLynQCAUVFPvkRGw/fl61UtiRWDyW+9RK7/EuwVYeTGkM2WAdSkcntQMz2xi721OeoXtRapDTpRXIggvAtzcydYVUXlUQfJE7qStgxjF2rMQwSQPEtlZApfBjr2lKiK/XqwvuOtu9E4OoO6LpuUX1UU2U8Fmp26E3Z9IUnqd71xmqFSNraXXREz5Y9PMB6IjElFbJwP7fT0dVH2uBTlTtE19y/CaGBDaPTxJNnFDiTlpWrLn9LB9YewUSB2M47xnj9DyRWqIlYle8xpSgd5zPNGLgv/t1POkbJhucZA==
+site=true
+email=true
+code=false
+
+[/O=Xcert International Inc./OU=Xcert Root CA 1024]
+x509=MIICaDCCAdGgAwIBAgIQCgEBAQAAAnwAAAADAAAAAjANBgkqhkiG9w0BAQUFADBAMSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xGzAZBgNVBAsTElhjZXJ0IFJvb3QgQ0EgMTAyNDAeFw0wMDA4MTgxODMxMzJaFw0yNTA4MTUxOTAwNTZaMEAxITAfBgNVBAoTGFhjZXJ0IEludGVybmF0aW9uYWwgSW5jLjEbMBkGA1UECxMSWGNlcnQgUm9vdCBDQSAxMDI0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDWvjeJEami90csKs9qACZlKESkiuTeoENVmURrvG64x87GY7bT6G/FmCskkbieorpxSN40ICF61tLFiTKlicbchYRU8p5I7cxEtgb/jsTOWa2fbOkiWME/FApDgIcZUlDjKAfIrBjisRqqo+Jgt3ZRByk5XkjpZnCBLjiavRl96wIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBSEecdPB1mxa8E6Nbq49NWZJ8i6DjAdBgNVHQ4EFgQUhHnHTwdZsWvBOjW6uPTVmSfIug4wDQYJKoZIhvcNAQEFBQADgYEAc7DhAO2uaNJgA0br+RzxpaZ8XDJ87AJh0xwdczEsuo69SU3I3dl3dUHnkiGabCnbp2xwhqBcw+TzMswBhFnXiDk486ji4hqwl80rF9xkBA+qanOU1usIxoBpTd561cU38ZIXPG3TiiHMZBCq3mKHH4+4+Kp1SvQILPXcZs/DOH4=
+site=true
+email=true
+code=false
+
+[/O=Xcert International Inc./OU=Xcert Root CA v1]
+x509=MIIC/zCCAecCEAoBAQEAAAJ8AAAABAAAAAIwDQYJKoZIhvcNAQEFBQAwPjEhMB8GA1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBSb290IENBIHYxMB4XDTAwMDgxODE4NDA1MFoXDTI1MDgxNTE5MDAzOFowPjEhMB8GA1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBSb290IENBIHYxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwZKr8rY1NgJID4X0Ti+CZc1IvrG3PbN7rroyNIY8mL/4sL37wsz2CZc4XI2lI07hyITmkGd0O6P2bpkrj8MH0pdRB08Ey56y+Dz3OOaWSjrrFW/nYuZDMweyDVrPlSk5Z4gTI9SMbV+OIeAx87XcmcXE7YUQfpLUoh08HwuzI+bAyySbbBCmzRTWo51Tj/ceQZq2Gx0IXPc5QcMe3kwmo2B8LhOHkWzXwiMv530ZH81b6pjFuUZ9NUbke4tK2ZPgBqvAzEr929oLMD+4XOAHE6jFMPy8hvaqvw5jL49JchDRnoX5Qe1IPHgM/aAqBhuv091nL+xIL1FJNiK3SM1J7wIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCo3LMgLv1XSBAP5o1gUht2HZxmoG/6aAbYp5zLoQyOJeiux986cK2p+CokvLzHqscJt7sQ6R9a1aIBRosFxKN1SQtAx7Frn9tYFmMyhFoQjWKWq5hmm7r6VggbumLz7zlr/GSxya7vXpThooD5CIMWEjaW2QmQ2Zg6rz2F2JEqkhxcuczVXHM4jntzUgy6n/KOv8h8ChO6cpGgOyDviSrDDIBpVnMQ9GAZ4B4WSmSr/EY60AvTl7Fc2ZysGDogB3oi+bcQZbrs5lPUquTDQbyb38LdmgFG1I5F7cnKFjSEjTJUPFRikI0aZlLN+hzMDPyx45PIp9nraGOP0H4uLd0p
+site=true
+email=false
+code=false
+
+[/O=Xcert International Inc./OU=Xcert Root CA v1 1024]
+x509=MIICBDCCAW0CEAoBAQEAAAJ8AAAABQAAAAIwDQYJKoZIhvcNAQEFBQAwQzEhMB8GA1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMR4wHAYDVQQLExVYY2VydCBSb290IENBIHYxIDEwMjQwHhcNMDAwODE4MTg1MDU2WhcNMjUwODE1MTkwMTA4WjBDMSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xHjAcBgNVBAsTFVhjZXJ0IFJvb3QgQ0EgdjEgMTAyNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApwnD0qmmGXDsKelFezbg6j7JmXBA0bZg9N0jx1l5nR6lvjVjAObALmxAU+bRdkbxoMuDRVSYGc97mjj4dDMzP6klICgmXShxRoYgPTArq+ZN+j/qREBM+3PU3JZ09E7kah0bl6B8MOHAc7YNond68Rj4SnFxnviodf5i+Ko9z30CAwEAATANBgkqhkiG9w0BAQUFAAOBgQB709VMf0yifnzXVmHZlZiFitdJ3IxHqgfsuNt5JJ7npZJXZgmPFLD+BPK9URC4OMOhEtuQg361Y1irM62XHkZQQhCsyKstHTVsxuZDUCgDoaz7EZX/6dVKD5HlA+SIMDwcdtGX8ArUh6AMmo9hztp+crM7UMCAhA8hIJRoKtqMvg==
+site=true
+email=false
+code=false
+
+[/C=WW/O=beTRUSTed/CN=beTRUSTed Root CAs/CN=beTRUSTed Root CA]
+x509=MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=
+site=true
+email=true
+code=false
+
+[/C=PL/O=Unizeto Sp. z o.o./CN=Certum CA]
+x509=MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
+site=true
+email=true
+code=false
+
+[/C=PL/O=Unizeto Sp. z o.o./CN=Certum Level I]
+x509=MIICjTCCAXWgAwIBAgIDAQAhMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA3MTIxNjMxNTNaFw0xMjA3MTIxNjMxNTNaMEMxCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xFzAVBgNVBAMTDkNlcnR1bSBMZXZlbCBJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl73pZ9DFcn7Qy0qBZK+So18cav7drUrJ8SiYOlDDVskt81+eIcL/4FelTSGjuAOvYdmm+HGYG998RPB0iZ+Ak67vXFJ537vRWOcu6aMjNuAwu8BOdc5eSgB0Y8X4+3LOYfugtaZa8mrEQ8Hit0yLE9UBcU9J+4PmkVGecmZ8jZQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAlDS4aTmgK0YgmUvt/3zN7G2/ZrtBBCtONlUvC69c7TmLJWJ842y2AH7ryNXXkcsn6p0ZBTrTJ2tA2y/j2PXJeXrCkK/qAJIpM0l4u0MT7enY5akasduHp2NXMP9vDlgMy7elU2s3nkOT79gfh5XttC+5D/x4JDNi1DMAA9hk16DK4zWmDVfjkiP/G3fEndtJgNDQsyqnaQ3E3bljv3f1KJTjZUvtA2Ml6MP2hFRhgZPsxuhW8QXidQYNiua1h7XUUiPiERLDLWZmfY6dxGrHXjSTx3shHNaQM0qkDs9gS6UK8uWJN2bf2YBnvGmzy0IQvx5wDCH7h8AdaBD6DgIG1
+site=true
+email=true
+code=false
+
+[/C=PL/O=Unizeto Sp. z o.o./CN=Certum Level II]
+x509=MIICjjCCAXagAwIBAgIDAQAiMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA3MTIxNjMyMDNaFw0xMjA3MTIxNjMyMDNaMEQxCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBMZXZlbCBJSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyMQSaN5fA94hNE46bMKpGUb5yIPEowReGZzGttYBQnC6oUOy+iM3md8WerzXeBKf7iIZEDW2HAp7BKhS4rMB6taxT07vDtkNfEKwOk6X7dODw6KY4mxnzjmjh5pf2feKKJ3MoZxi2HAz2a6JvHKFMq8dAlGL2GBtLvzlFp2jwkMCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAWo3wgy+/0B7UiTCu4Wn1rvGRXIUtbPNp4Bc4PP/i1q6pPheIe0ooCopuqnDX9maTHhZeNpnApgCUSbyw71EaOremD7HjWXASRUTylhwL5FdSx+D6MgF2uW9uwZ+NErkeRJYT2aRXe5FBOVIseC4g93Ay0D8Hg50MkAC5pQqW+8GSszT94NzT7ppIaMtq53PZpUtLGiL3UBZ5vUJ5pE4lLKD7Ce+pXzZevy/MnkMGD1L7LgjRWL17OcMlASFETyUTajNjvxMy+oM4C22rwHRh2WQrvgw5MO+Q3UyYA1r5VrSaqgQ1g06ZcQt+mhzoc2swlOSwm8iis8H6orR8xmCWrA==
+site=true
+email=true
+code=false
+
+[/C=PL/O=Unizeto Sp. z o.o./CN=Certum Level III]
+x509=MIICjzCCAXegAwIBAgIDAQAjMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA3MTIxNjMyMTdaFw0xMjA3MTIxNjMyMTdaMEUxCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGTAXBgNVBAMTEENlcnR1bSBMZXZlbCBJSUkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZjBbfGFmlsLjPepWaDwG0LqhF11lWKabaHi1sQhK3qomHY7Em7qpL11dUQ1vsMcnnpzz/J0AEH6KDh+yAyXV1SE/tVToLYYByZK+JGacLYIYF9aCwV8AhqyzOGurO5QX6vLboXB2WNnwmXhyNVKUgnUVy4ktAR2qZJIw5Bjsn/AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAIsLt3vKCZqd/gui45ovm3FSO6FLjzzq4pagPvbNnZ39HrhRaCpqkHDAj71L5L27U3eW2D4ILL0iUmZadbC4i3at/PUL9mjhGlajcCN8EF6IXGT87Tbcii735jRaaXSbEY4YhNOg9DPBoD4uJMkA8Z0Y/6lYmk4S6KUMCzztt5zZBiWjdd08yFi5VGMvpE74KVOMdMa3JNVaR0XvT0Q8yXo1XKCrY9OFIxnhVgDbhzr9fwjKWDwu8kxhT9khAETm0BU2Buu+CTasaJdT/bBR2YEx9qcN7XyXTeDtkOO5QeGSqFgzquwjWEbKhf7l/e+efdRCg+ikH3O5snHB6iS+dgg=
+site=true
+email=true
+code=false
+
+[/C=PL/O=Unizeto Sp. z o.o./CN=Certum Level IV]
+x509=MIICjjCCAXagAwIBAgIDAQAkMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA3MTIxNjMyMzVaFw0xMjA3MTIxNjMyMzVaMEQxCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBMZXZlbCBJVjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmyb1lKqCAKE4juAy6lpVNUl6aJ2DuWPSiJ3BBk3/6ty6I4Lr2Dpy1b1vjVelhaFsVKEDgK2JyQlk9XMqLPZI2Ql166mJiPKFg77aY/W78EcQfGyjnRvVcs0tG40mAs/p84OEpFcVe/RSqDrD/D7R01u+Wj5xLl0PUsFplIGDbikCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAPS99JujKGVRfa50TKfieq+uK1SxjidErYaZTb3cJNNfQDYn6nk4lnrnab5EUVhO/NegP2yIu3YOnZGfxFDhvVozMTKKAB5r5XKOvzsP99C9578PVMLozucfUMCSwau7Z4l5uuQOHuzjzlVLCibbbf4RwfvZ7hh5sB5c0pNbwRQq64RXQUUEvul/W9gUeT9ISHOsASGTq+HJ5i7vNARjukEAXW/maqs9vyTWWbGVI1FSOnVyteymq4Xk+9YlIyNPNyacgnsMnU72XKBLDS0KJdhIWALFAZI4dSh5WZNuWZguUnEmeH81lLbR+p/N3iuN8+oSo8UXik92jxeUY2tQJUA==
+site=true
+email=true
+code=false
+
+[/C=BR/O=ICP-Brasil/OU=Instituto Nacional de Tecnologia da Informacao - ITI/L=Brasilia/ST=DF/CN=Autoridade Certificadora Raiz Brasileira]
+x509=MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25hbCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJyYXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAyMzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsGA1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3JtYWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYDVQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVAisamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyjQo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYtbRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbURyEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwIDAQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFjcmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGlYjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75FosSzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0umlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPbK+9A46sd33oqK8n8
+site=true
+email=true
+code=false
+
+
+[/C=DE/ST=Hamburg/L=Hamburg/O=TC TrustCenter for Security in Data Networks GmbH/OU=TC TrustCenter Class 2 CA/Email=certificate@trustcenter.de]
+x509=MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+site=true
+email=true
+code=false
+
+[/C=DE/ST=Hamburg/L=Hamburg/O=TC TrustCenter for Security in Data Networks GmbH/OU=TC TrustCenter Class 3 CA/Email=certificate@trustcenter.de]
+x509=MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+site=true
+email=true
+code=false
+
+[/C=DE/O=Deutsches Forschungsnetz/OU=DFN-CERT GmbH/OU=DFN-PCA/CN=DFN Toplevel Certification Authority/Email=certify@pca.dfn.de]
+x509=MIIG2jCCBcKgAwIBAgIDFc/9MA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTAeFw0wMTEyMDExMjExMTZaFw0xMDAxMzExMjExMTZaMIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF5rhMt6zmhxK5oWPwT2FG7Up7T5DovHSD/YKPIRxsvDWmC4dTzByIBLnOmEflk+5KAqAYao6eY1qF0hR4WiS4DjCsn7l3zNo/4i2eF4EmGEksBygb4tRlTThcO7heFX+Du5qFoks+ONqa70RlwOr2l53KVwjMXBCtCLFSKRLVuxeh5+Smkm+FuOmwEugndM2n74Djjyf9DCOaHGZrHwVDh+Vpy5Ny4bKCSboujRxd5NxsStUshDVbTeS3B8TuzAJbywYWEE7erox+7WTfQr8ivSCBhrNJ36VRjAb8hiV9Iuy2TmJYo2oPyC8a3eM3xj9Ku2IW3tS2zpfiIzt9xvFMCAwEAAaOCAwEwggL9MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAYL+rX4SHijILELPs+g0MTRf33QMIHbBgNVHSMEgdMwgdCAFAYL+rX4SHijILELPs+g0MTRf33QoYGypIGvMIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZYIDFc/9MAsGA1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAAcwgaUGA1UdHwSBnTCBmjBLoEmgR4ZFaHR0cDovL3d3dy5kZm4tcGNhLmRlL2NlcnRpZmljYXRpb24veDUwOS9nMS9kYXRhL2NybHMvcm9vdC1jYS1jcmwuY3J4MEugSaBHhkVodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlvbi94NTA5L2cxL2RhdGEvY3Jscy9yb290LWNhLWNybC5jcmwwOAYJYIZIAYb4QgEDBCsWKWh0dHBzOi8vd3d3LmRmbi1wY2EuZGUvY2dpL2NoZWNrLXJldi5jZ2k/MEsGCWCGSAGG+EIBCAQ+FjxodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlvbi9wb2xpY2llcy94NTA5cG9saWN5Lmh0bWwwOAYJYIZIAYb4QgENBCsWKVRoZSBERk4gVG9wLUxldmVsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MGQGA1UdIARdMFswWQYLKwYBBAHZGoIsAQEwSjBIBggrBgEFBQcCARY8aHR0cDovL3d3dy5kZm4tcGNhLmRlL2NlcnRpZmljYXRpb24vcG9saWNpZXMveDUwOXBvbGljeS5odG1sMA0GCSqGSIb3DQEBBQUAA4IBAQAmbai6JMt7nkuavyvxKzLGn04Gyt0zKrp8zmERp4inktvY7p+vkaomYu2QYC7cHq0tlrPXQQhhetjiXGb+36aJtHDkEA0NwrJzYnHgPsvx7z0wysENP4wxf97KsSWm07RY+f6/gIQF7Je7CW30Rzq7N6R0NMBs32mJgdn3ntqlFNw3Nbs050FEjPNq54RdawlJo85x+w+QJd7uQM4yZjHpRhvwgte9Ge1UqCUdpMsLHzeMKJ0B9GhwIIqOJCMiPgKjcUBrn6ehSX70POvXvjjE2+FzhPGTyTkS474d2UCAnL9qhPrdWXzBjOumOjhJutT1aecm9eljlshmh1cNen00
+site=true
+email=false
+code=false
+
+[/C=AT/ST=Austria/L=Vienna/O=Arge Daten Oesterreichische Gesellschaft fuer Datenschutz/Email=a-cert@argedaten.at]
+x509=MIIDwzCCAyygAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmDELMAkGA1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAGA1UEChM5QXJnZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBmdWVyIERhdGVuc2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVuLmF0MB4XDTAxMDIxMjExMzAzMFoXDTA5MDIxMjExMzAzMFowgZgxCzAJBgNVBAYTAkFUMRAwDgYDVQQIEwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExQjBABgNVBAoTOUFyZ2UgRGF0ZW4gT2VzdGVycmVpY2hpc2NoZSBHZXNlbGxzY2hhZnQgZnVlciBEYXRlbnNjaHV0ejEiMCAGCSqGSIb3DQEJARYTYS1jZXJ0QGFyZ2VkYXRlbi5hdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwgsHqoNtmmrJ86+e1I4hOVBaL4kokqKN2IPOIL+1XwY8vfOOUfPEdhWpaC0ldt7VYrksgDiUccgH0FROANWK2GkfKMDzjjXHysR04uEbOm7Kqjqn0nproOGkFG+QvBZgs+Ws+HXNFJA6V76fU4+JXq4452LSK4Lr5YcBquu3NJECAwEAAaOCARkwggEVMB0GA1UdDgQWBBQ0j59zH/G31zRjgK1y2P//tSAWZjCBxQYDVR0jBIG9MIG6gBQ0j59zH/G31zRjgK1y2P//tSAWZqGBnqSBmzCBmDELMAkGA1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAGA1UEChM5QXJnZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBmdWVyIERhdGVuc2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVuLmF0ggEAMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQBFuJYncqMYB6gXQS3eDOI90BEHfFTKy/dVAV+K7QdAYikWmqgBheRdPKddJdccPy/Zl/p3ZT7GhDyC5f3wZjcuu8AJ27BNwbCAx54dgxgCNcyPm79nY8MRtEdEpoRGdSsFKJemz6hpXM++MWFciyrRWIIA44XB0Gv3US0spjsDPQ==
+site=true
+email=false
+code=false
+
+[/C=ES/ST=BARCELONA/L=BARCELONA/O=IPS Seguridad CA/OU=Certificaciones/CN=IPS SERVIDORES/Email=ips@mail.ips.es]
+x509=MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lYJN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsUdx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC
+site=true
+email=false
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Network Applications]
+x509=MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE
+site=true
+email=false
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC]
+x509=MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowftGzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
+site=true
+email=false
+code=false
+
+[/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services]
+x509=MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLzRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+site=true
+email=false
+code=false
+
+[/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services]
+x509=MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmjZ55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+site=true
+email=false
+code=false
+
+[/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services]
+x509=MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+site=true
+email=false
+code=false
+
+[/C=FI/O=Sonera/CN=Sonera Class1 CA]
+x509=MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+site=true
+email=false
+code=false
+
+[/C=FI/O=Sonera/CN=Sonera Class2 CA]
+x509=MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+site=true
+email=false
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware]
+x509=MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+site=true
+email=false
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC]
+x509=MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowftGzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
+site=true
+email=false
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Client Authentication and Email]
+x509=MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+site=false
+email=true
+code=false
+
+[/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Object]
+x509=MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujwNTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+site=false
+email=false
+code=true
+
+[/C=HU/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Expressz (Class C) Tanusitvanykiado]
+x509=MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBsZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A==
+site=true
+email=true
+code=false
+
+[/C=HU/ST=Hungary/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado]
+x509=MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+site=true
+email=true
+code=false
+
+[/C=HU/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Uzleti (Class B) Tanusitvanykiado]
+x509=MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI
+site=true
+email=true
+code=false
+
+[/C=be/O=Belgacom/OU=MTM/CN=Belgacom E-Trust Primary CA/mail=info@e-trust.be]
+x509=MIICiTCCAfKgAwIBAgIEN4dnrDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJiZTERMA8GA1UEChMIQmVsZ2Fjb20xDDAKBgNVBAsTA01UTTEkMCIGA1UEAxMbQmVsZ2Fjb20gRS1UcnVzdCBQcmltYXJ5IENBMR8wHQYKCZImiZPyLGQBAxQPaW5mb0BlLXRydXN0LmJlMB4XDTk4MTEwNDEzMDQzOVoXDTEwMDEyMTEzMDQzOVowdTELMAkGA1UEBhMCYmUxETAPBgNVBAoTCEJlbGdhY29tMQwwCgYDVQQLEwNNVE0xJDAiBgNVBAMTG0JlbGdhY29tIEUtVHJ1c3QgUHJpbWFyeSBDQTEfMB0GCgmSJomT8ixkAQMUD2luZm9AZS10cnVzdC5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqtm5s9VPak3FQdB7BGFqi3GBB9pk41huJ1XCrc4XsPz6ko0I8Bxy/7LDMf7gaoeXTMxDV6coeTq1g12kHWrxasU+FCIdWQZv8KYxd9ywSTjmywwP/qpyNIjaKDohWu50Kxuk21sTFrVzX8OujNLAPj2wy/Dsi4YLwsFEGFpjqNUCAwEAAaMmMCQwDwYDVR0TBAgwBgEB/wIBATARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEFBQADgYEAerKxpbF9M+nC4RvO05OMfwH9Gx1amq6rB1Ev7Ymr3VBCux//SrWknLFhKQpM6oNZSY2vhmnXgaxHqqRxblnvynxqblSK2qiSyfVms3lf1IsBniFjRjWTpcJfImIDcB1jI+hrSB0jECfY9t9HorrsgFBKbMRwpnrkdCJ/9oRiMn8=
+site=true
+email=false
+code=false
+
+[/C=US/OU=www.xrampsecurity.com/O=XRamp Security Services Inc/CN=XRamp Global Certification Authority]
+x509=MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxtqZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+site=true
+email=false
+code=false
+
+[/C=DK/O=TDC/CN=TDC OCES CA]
+x509=MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAyMTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw==
+site=true
+email=true
+code=false
+
+[/C=DK/O=TDC Internet/OU=TDC Internet Root CA]
+x509=MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
+site=true
+email=false
+code=false
+
+[/C=HU/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Minositett Kozjegyzoi (Class QA) Tanusitvanykiado/Email=info@netlock.hu]
+x509=MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJhbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko
+site=false
+email=true
+code=true
+
+[/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority]
+x509=MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQHmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/bvZ8=
+site=true
+email=true
+code=true
+
+[/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority]
+x509=MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJlxy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+site=true
+email=true
+code=true
+
+[/C=NL/O=Staat der Nederlanden/CN=Staat der Nederlanden Root CA]
+x509=MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsRiJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+site=true
+email=true
+code=true
+
+[/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA]
+x509=MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+site=true
+email=true
+code=true
+
+[/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2]
+x509=MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz4iIprn2DQKi6bA==
+site=true
+email=true
+code=true
+
+[/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA]
+x509=MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRcaanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+site=true
+email=true
+code=true
+
+[/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA 2]
+x509=MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+zdXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+site=true
+email=true
+code=true
+
+[/C=BM/O=QuoVadis Limited/OU=Root Certification Authority/CN=QuoVadis Root Certification Authority]
+x509=MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJhY3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOKSnQ2+Q==
+site=true
+email=true
+code=false
+
+[/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA]
+x509=MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+site=true
+email=true
+code=false
+
+[/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA]
+x509=MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQkCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+site=true
+email=true
+code=false
+
+[/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA]
+x509=MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCevEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+site=true
+email=true
+code=false
+
+[/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2]
+x509=MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+site=true
+email=true
+code=false
+
+[/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 3]
+x509=MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
+site=true
+email=true
+code=false
+
+[/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign]
+x509=MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+site=true
+email=true
+code=false
+
+[/C=CO/O=Sociedad Cameral de Certificaci\xC3\xB3n Digital - Certic\xC3\xA1mara S.A./CN=AC Ra\xC3\xADz Certic\xC3\xA1mara S.A]
+x509=MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==
+site=true
+email=true
+code=true
+
+[/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority]
+x509=MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+PwqyvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+site=true
+email=true
+code=false
+
+[/C=CH/O=WISeKey/OU=Copyright (c) 2005/OU=OISTE Foundation Endorsed/CN=OISTE WISeKey Global Root GA CA]
+x509=MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXahNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+site=true
+email=true
+code=false
+
+[/C=CH/O=SwissSign AG/CN=SwissSign Platinum CA - G2]
+x509=MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
+site=false
+email=true
+code=true
+
+[/C=CH/O=SwissSign AG/CN=SwissSign Gold CA - G2]
+x509=MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+site=true
+email=true
+code=true
+
+[/C=CH/O=SwissSign AG/CN=SwissSign Silver CA - G2]
+x509=MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+site=true
+email=true
+code=true
diff --git a/tdeio/kssl/kssl/localcerts b/tdeio/kssl/kssl/localcerts
new file mode 100644
index 000000000..150763522
--- /dev/null
+++ b/tdeio/kssl/kssl/localcerts
@@ -0,0 +1,36 @@
+certum.pem
+certum1.pem
+certum2.pem
+certum3.pem
+certum4.pem
+icpbrasil.pem
+dfn-root-ca-cert.pem
+argedaten-root-ca-cert.pem
+ipsservidores.pem
+utn-network.pem
+utn-sgc.pem
+comodo1.pem
+comodo2.pem
+comodo3.pem
+comodo4.pem
+comodo5.pem
+comodo6.pem
+comodo7.pem
+sonera1.pem
+sonera2.pem
+netlock1.pem
+netlock2.pem
+netlock3.pem
+belgacom.pem
+xgca.pem
+oces.pem
+tdca.pem
+netlock4.pem
+gd-class2-root.pem
+sf-class2-root.pem
+geotrust-global-1.pem
+geotrust-global-2.pem
+GeoTrust_Universal_CA.pem
+GeoTrust_Universal_CA2.pem
+quovadis.pem
+ac_offline_raiz_certicamara.pem
diff --git a/tdeio/kssl/kssl/mergelocal b/tdeio/kssl/kssl/mergelocal
new file mode 100755
index 000000000..4fc0f0ff3
--- /dev/null
+++ b/tdeio/kssl/kssl/mergelocal
@@ -0,0 +1,65 @@
+:
+eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+##
+## Merge the local certificates
+##
+
+$date = `date`;
+$date =~ s|\n$||;
+open(BDL, ">>ksslcalist") || die;
+open(CDL, ">>caroot/ca-bundle.crt") || die;
+open(IDX, "<localcerts") || die;
+
+while (<IDX>) {
+ $filename = $_;
+ chomp($filename);
+
+ stat($filename);
+ next if ! -r _;
+
+ print STDERR "Bundling: $filename\n";
+ $pem = `cat $filename`;
+ print CDL "\n$pem\n";
+ $pem =~ s|[\n\r]||g;
+ $pem =~ s|-----BEGIN CERTIFICATE-----||;
+ $pem =~ s|-----END CERTIFICATE-----||;
+ $subj = `openssl x509 -in $filename -inform PEM -noout -subject`;
+ $_ = $subj;
+ if ( /[Oo]bject/ || /[Cc]ode/ ) {
+ $codeSubj = 1;
+ } else {
+ $codeSubj = 0;
+ }
+ $subj =~ s|\n$||;
+ $subj =~ s/^subject= //;
+ $purpose = `openssl x509 -in $filename -inform PEM -noout -purpose`;
+ print BDL "\n";
+ print BDL "[$subj]\n";
+ print BDL "x509=$pem\n";
+ #
+ $_ = $purpose;
+ if ( /server CA : Yes\n/ || /client CA : Yes\n/ || (/Any Purpose CA : Yes\n/ && (/client : Yes\n/ || /server : Yes\n/ ))) {
+ print BDL "site=true\n";
+ } else {
+ print BDL "site=false\n";
+ }
+ #
+ if ( /MIME signing CA : Yes\n/ || /MIME encryption CA : Yes\n/ ) {
+ print BDL "email=true\n";
+ } else {
+ print BDL "email=false\n";
+ }
+ #
+ if ( /Any Purpose CA : Yes\n/ && $codeSubj == 1) {
+ print BDL "code=true\n";
+ } else {
+ print BDL "code=false\n";
+ }
+
+}
+close(BDL);
+close(CDL);
+close(IDX);
+
diff --git a/tdeio/kssl/kssl/netlock1.pem b/tdeio/kssl/kssl/netlock1.pem
new file mode 100644
index 000000000..5f7c1ce43
--- /dev/null
+++ b/tdeio/kssl/kssl/netlock1.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/netlock2.pem b/tdeio/kssl/kssl/netlock2.pem
new file mode 100644
index 000000000..c4e610816
--- /dev/null
+++ b/tdeio/kssl/kssl/netlock2.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/netlock3.pem b/tdeio/kssl/kssl/netlock3.pem
new file mode 100644
index 000000000..dd373608e
--- /dev/null
+++ b/tdeio/kssl/kssl/netlock3.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/netlock4.pem b/tdeio/kssl/kssl/netlock4.pem
new file mode 100644
index 000000000..3565fef78
--- /dev/null
+++ b/tdeio/kssl/kssl/netlock4.pem
@@ -0,0 +1,39 @@
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD
+EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz
+aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w
+MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l
+dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh
+bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq
+eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe
+r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5
+3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd
+vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
+mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC
+wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg
+hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0
+TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg
+ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg
+dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6
+b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl
+c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0
+ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3
+dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu
+ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo
+ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3
+Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
+ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA
+A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ
+MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+
+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR
+VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY
+83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3
+macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/oces.pem b/tdeio/kssl/kssl/oces.pem
new file mode 100644
index 000000000..32e08236c
--- /dev/null
+++ b/tdeio/kssl/kssl/oces.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw
+ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU
+REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr
+2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s
+2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU
+GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj
+dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r
+TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB
+AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv
+c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl
+ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu
+MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
+T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud
+HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD
+VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny
+bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ
+J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG
+SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom
+JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO
+inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y
+caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB
+mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ
+YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9
+BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/quovadis.pem b/tdeio/kssl/kssl/quovadis.pem
new file mode 100644
index 000000000..ea68f8876
--- /dev/null
+++ b/tdeio/kssl/kssl/quovadis.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/qvrca2.pem b/tdeio/kssl/kssl/qvrca2.pem
new file mode 100644
index 000000000..35cc4eb56
--- /dev/null
+++ b/tdeio/kssl/kssl/qvrca2.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/qvrca3.pem b/tdeio/kssl/kssl/qvrca3.pem
new file mode 100644
index 000000000..bda7b1aa5
--- /dev/null
+++ b/tdeio/kssl/kssl/qvrca3.pem
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/sf-class2-root.pem b/tdeio/kssl/kssl/sf-class2-root.pem
new file mode 100644
index 000000000..d552e65dd
--- /dev/null
+++ b/tdeio/kssl/kssl/sf-class2-root.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/sonera1.pem b/tdeio/kssl/kssl/sonera1.pem
new file mode 100644
index 000000000..c5dad57ac
--- /dev/null
+++ b/tdeio/kssl/kssl/sonera1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx
+MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG
+29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk
+oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk
+3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL
+qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN
+nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX
+ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H
+DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO
+TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
+kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w
+zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/sonera2.pem b/tdeio/kssl/kssl/sonera2.pem
new file mode 100644
index 000000000..36a998d22
--- /dev/null
+++ b/tdeio/kssl/kssl/sonera2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/staatdernederlandenrotca.pem b/tdeio/kssl/kssl/staatdernederlandenrotca.pem
new file mode 100644
index 000000000..c4eb117fa
--- /dev/null
+++ b/tdeio/kssl/kssl/staatdernederlandenrotca.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/startcom.pem b/tdeio/kssl/kssl/startcom.pem
new file mode 100644
index 000000000..957842c98
--- /dev/null
+++ b/tdeio/kssl/kssl/startcom.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx
+DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0
+Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
+YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0
+OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp
+bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp
+dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x
+18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5
+yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI
+LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G
+A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW
+zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT
+BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x
+GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh
+cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV
+HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G
+CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy
+BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j
+cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ
+YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/
+YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1
+ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p
+00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb
+cCOxgN8aIDjnfg==
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/startssl.pem b/tdeio/kssl/kssl/startssl.pem
new file mode 100644
index 000000000..960f2657b
--- /dev/null
+++ b/tdeio/kssl/kssl/startssl.pem
@@ -0,0 +1,44 @@
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/tcclass2-2011.pem b/tdeio/kssl/kssl/tcclass2-2011.pem
new file mode 100644
index 000000000..0c9d89e77
--- /dev/null
+++ b/tdeio/kssl/kssl/tcclass2-2011.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y
+AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw
+TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8
+/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/
+jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms
+Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/tcclass3-2011.pem b/tdeio/kssl/kssl/tcclass3-2011.pem
new file mode 100644
index 000000000..14f81c830
--- /dev/null
+++ b/tdeio/kssl/kssl/tcclass3-2011.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF
+Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw
+Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW
+w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE
+Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD
+2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/utn-network.pem b/tdeio/kssl/kssl/utn-network.pem
new file mode 100644
index 000000000..72b576a59
--- /dev/null
+++ b/tdeio/kssl/kssl/utn-network.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/utn-sgc.pem b/tdeio/kssl/kssl/utn-sgc.pem
new file mode 100644
index 000000000..1c747eb57
--- /dev/null
+++ b/tdeio/kssl/kssl/utn-sgc.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/kssl/xgca.pem b/tdeio/kssl/kssl/xgca.pem
new file mode 100644
index 000000000..f21e6d8b7
--- /dev/null
+++ b/tdeio/kssl/kssl/xgca.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
diff --git a/tdeio/kssl/ksslall.h b/tdeio/kssl/ksslall.h
new file mode 100644
index 000000000..0e34837bb
--- /dev/null
+++ b/tdeio/kssl/ksslall.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 __INC_KSSL_ALL_H
+#define __INC_KSSL_ALL_H
+#include <ksslcertificatefactory.h>
+#include <ksslinfodlg.h>
+#include <ksslx509map.h>
+#include <kssl.h>
+#include <ksslcertificatehome.h>
+#include <ksslpeerinfo.h>
+#include <ksslcertificate.h>
+#include <ksslconnectioninfo.h>
+#include <ksslsettings.h>
+#include <ksslcertificatecache.h>
+#include <ksslutils.h>
+#include <ksslpkcs7.h>
+#include <ksslpkcs12.h>
+#include <ksslcertchain.h>
+#include <ksslx509v3.h>
+#include <ksslsigners.h>
+#include <ksslsession.h>
+#endif
+
diff --git a/tdeio/kssl/ksslcallback.c b/tdeio/kssl/ksslcallback.c
new file mode 100644
index 000000000..59f342584
--- /dev/null
+++ b/tdeio/kssl/ksslcallback.c
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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.
+ */
+
+#ifdef KSSL_HAVE_SSL
+#ifndef _kde_ksslcallback_c
+#define _kde_ksslcallback_c
+
+X509 *KSSL_X509CallBack_ca;
+bool KSSL_X509CallBack_ca_found;
+
+extern "C" {
+static int X509Callback(int ok, X509_STORE_CTX *ctx) {
+
+ kdDebug(7029) << "X509Callback: ok = " << ok << " error = " << ctx->error << " depth = " << ctx->error_depth << endl;
+ // Here is how this works. We put "ok = 1;" in any case that we
+ // don't consider to be an error. In that case, it will return OK
+ // for the certificate check as long as there are no other critical
+ // errors. Don't forget that there can be multiple errors.
+ //
+ // Of course we can also put other code in here but any data returned
+ // back will not be threadsafe ofcourse.
+
+ if (KSSL_X509CallBack_ca)
+ {
+ if (KOSSL::self()->X509_cmp(ctx->current_cert, KSSL_X509CallBack_ca) != 0)
+ return 1; // Ignore errors for this certificate
+
+ KSSL_X509CallBack_ca_found = true;
+ }
+
+ if (!ok) {
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_CERT_REVOKED:
+ case X509_V_ERR_INVALID_CA:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_PURPOSE:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ default:
+ break;
+ }
+ }
+
+ return(ok);
+}
+}
+
+#endif
+#endif
+
diff --git a/tdeio/kssl/ksslcertchain.cc b/tdeio/kssl/ksslcertchain.cc
new file mode 100644
index 000000000..a401aec3d
--- /dev/null
+++ b/tdeio/kssl/ksslcertchain.cc
@@ -0,0 +1,216 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kssldefs.h"
+#include "ksslcertificate.h"
+#include "ksslcertchain.h"
+
+// this hack provided by Malte Starostik to avoid glibc/openssl bug
+// on some systems
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/pem.h>
+#include <openssl/stack.h>
+#include <openssl/safestack.h>
+#undef crypt
+#endif
+
+#include <kopenssl.h>
+#include <kdebug.h>
+#include <tqstringlist.h>
+
+
+
+#ifdef KSSL_HAVE_SSL
+#define sk_new d->kossl->sk_new
+#define sk_push d->kossl->sk_push
+#define sk_free d->kossl->sk_free
+#define sk_value d->kossl->sk_value
+#define sk_num d->kossl->sk_num
+#define sk_dup d->kossl->sk_dup
+#define sk_pop d->kossl->sk_pop
+#endif
+
+class KSSLCertChainPrivate {
+public:
+ KSSLCertChainPrivate() {
+ kossl = KOSSL::self();
+ }
+
+ ~KSSLCertChainPrivate() {
+ }
+
+ KOSSL *kossl;
+};
+
+KSSLCertChain::KSSLCertChain() {
+ d = new KSSLCertChainPrivate;
+ _chain = NULL;
+}
+
+
+KSSLCertChain::~KSSLCertChain() {
+#ifdef KSSL_HAVE_SSL
+ if (_chain) {
+ STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
+
+ for (;;) {
+ X509* x5 = sk_X509_pop(x);
+ if (!x5) break;
+ d->kossl->X509_free(x5);
+ }
+ sk_X509_free(x);
+ }
+#endif
+ delete d;
+}
+
+
+bool KSSLCertChain::isValid() {
+ return (_chain && depth() > 0);
+}
+
+
+KSSLCertChain *KSSLCertChain::replicate() {
+KSSLCertChain *x = new KSSLCertChain;
+TQPtrList<KSSLCertificate> ch = getChain();
+
+ x->setChain(ch); // this will do a deep copy for us
+ ch.setAutoDelete(true);
+return x;
+}
+
+
+int KSSLCertChain::depth() {
+#ifdef KSSL_HAVE_SSL
+ return sk_X509_num((STACK_OF(X509)*)_chain);
+#endif
+return 0;
+}
+
+
+TQPtrList<KSSLCertificate> KSSLCertChain::getChain() {
+TQPtrList<KSSLCertificate> cl;
+if (!_chain) return cl;
+#ifdef KSSL_HAVE_SSL
+STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
+
+ for (int i = 0; i < sk_X509_num(x); i++) {
+ X509* x5 = sk_X509_value(x, i);
+ if (!x5) continue;
+ KSSLCertificate *nc = new KSSLCertificate;
+ nc->setCert(d->kossl->X509_dup(x5));
+ cl.append(nc);
+ }
+
+#endif
+return cl;
+}
+
+
+void KSSLCertChain::setChain(TQPtrList<KSSLCertificate>& chain) {
+#ifdef KSSL_HAVE_SSL
+if (_chain) {
+ STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
+
+ for (;;) {
+ X509* x5 = sk_X509_pop(x);
+ if (!x5) break;
+ d->kossl->X509_free(x5);
+ }
+ sk_X509_free(x);
+ _chain = NULL;
+}
+
+ if (chain.count() == 0) return;
+ _chain = (void *)sk_new(NULL);
+ for (KSSLCertificate *x = chain.first(); x != 0; x = chain.next()) {
+ sk_X509_push((STACK_OF(X509)*)_chain, d->kossl->X509_dup(x->getCert()));
+ }
+
+#endif
+}
+
+
+void KSSLCertChain::setChain(void *stack_of_x509) {
+#ifdef KSSL_HAVE_SSL
+if (_chain) {
+ STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
+
+ for (;;) {
+ X509* x5 = sk_X509_pop(x);
+ if (!x5) break;
+ d->kossl->X509_free(x5);
+ }
+ sk_X509_free(x);
+ _chain = NULL;
+}
+
+if (!stack_of_x509) return;
+
+_chain = (void *)sk_new(NULL);
+STACK_OF(X509) *x = (STACK_OF(X509) *)stack_of_x509;
+
+ for (int i = 0; i < sk_X509_num(x); i++) {
+ X509* x5 = sk_X509_value(x, i);
+ if (!x5) continue;
+ sk_X509_push((STACK_OF(X509)*)_chain,d->kossl->X509_dup(x5));
+ }
+
+#else
+_chain = NULL;
+#endif
+}
+
+
+void KSSLCertChain::setChain(TQStringList chain) {
+ setCertChain(chain);
+}
+
+void KSSLCertChain::setCertChain(const TQStringList& chain) {
+ TQPtrList<KSSLCertificate> cl;
+ cl.setAutoDelete(true);
+ for (TQStringList::ConstIterator s = chain.begin(); s != chain.end(); ++s) {
+ KSSLCertificate *c = KSSLCertificate::fromString((*s).local8Bit());
+ if (c) {
+ cl.append(c);
+ }
+ }
+ setChain(cl);
+}
+
+
+#ifdef KSSL_HAVE_SSL
+#undef sk_new
+#undef sk_push
+#undef sk_free
+#undef sk_value
+#undef sk_num
+#undef sk_dup
+#undef sk_pop
+#endif
+
diff --git a/tdeio/kssl/ksslcertchain.h b/tdeio/kssl/ksslcertchain.h
new file mode 100644
index 000000000..eb6c27d44
--- /dev/null
+++ b/tdeio/kssl/ksslcertchain.h
@@ -0,0 +1,136 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 _KSSLCERTCHAIN_H
+#define _KSSLCERTCHAIN_H
+
+#include <tqglobal.h>
+#include <tqptrlist.h>
+#include <kdemacros.h>
+
+class TQString;
+class TQCString;
+class KSSL;
+class KSSLCertChainPrivate;
+class TQStringList;
+
+#include <ksslcertificate.h>
+
+/**
+ * KDE Certificate Chain Representation Class
+ *
+ * This class provides a representation for an X.509 certificate chain.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL, KSSLCertificate, KSSLPeerInfo
+ * @short KDE X.509 Certificate Chain
+ */
+class TDEIO_EXPORT KSSLCertChain {
+friend class KSSL;
+friend class KSSLPeerInfo;
+
+public:
+ /**
+ * Construct a KSSLCertChain object
+ */
+ KSSLCertChain();
+
+ /**
+ * Destroy this KSSLCertChain object
+ */
+ ~KSSLCertChain();
+
+ /**
+ * Determine if this represents a valid certificate chain
+ *
+ * @return true if it is a valid certificate chain
+ */
+ bool isValid();
+
+ /**
+ * Do a deep copy of the certificate chain.
+ *
+ * @return pointer to a new certificate chain object
+ *
+ * This is an expensive operation, and you are responsible for deleting
+ * the returned object yourself.
+ */
+ KSSLCertChain *replicate();
+
+ /**
+ * Set the raw chain from OpenSSL
+ * @internal
+ */
+ void setChain(void *stack_of_x509);
+
+ /**
+ * Set the certificate chain as a pointer list of KSSL certificates.
+ *
+ * @param chain the certificate chain
+ * @see KSSLCertificate
+ */
+ void setChain(TQPtrList<KSSLCertificate>& chain);
+
+ /**
+ * Set the certificate chain as a list of base64 encoded X.509
+ * certificates.
+ *
+ * @param chain the certificate chain
+ * @deprecated
+ */
+ void setChain(TQStringList chain) KDE_DEPRECATED;
+
+ /**
+ * Set the certificate chain as a list of base64 encoded X.509
+ * certificates.
+ *
+ * @param chain the certificate chain
+ */
+ void setCertChain(const TQStringList& chain);
+
+ /**
+ * Obtain a copy of the certificate chain.
+ *
+ * @return a deep copy of the certificate chain.
+ * @see KSSLCertificate
+ */
+ TQPtrList<KSSLCertificate> getChain();
+
+ /**
+ * Determine the number of entries (depth) of the chain.
+ *
+ * @return the number of entries in the certificate chain
+ */
+ int depth();
+
+ /**
+ * Read the raw chain in OpenSSL format
+ * @internal
+ */
+ void *rawChain() { return _chain; }
+
+private:
+ KSSLCertChainPrivate *d;
+ void *_chain;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslcertdlg.cc b/tdeio/kssl/ksslcertdlg.cc
new file mode 100644
index 000000000..3d51c1e85
--- /dev/null
+++ b/tdeio/kssl/ksslcertdlg.cc
@@ -0,0 +1,174 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 "ksslcertdlg.h"
+
+#include <kssl.h>
+
+#include <tqlayout.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqlistview.h>
+#include <tqframe.h>
+#include <tqlabel.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kseparator.h>
+#include <kdebug.h>
+
+
+class KSSLCertDlg::KSSLCertDlgPrivate {
+private:
+ friend class KSSLCertDlg;
+ TQLabel *p_message;
+ TQPushButton *p_pb_dontsend;
+ bool p_send_flag;
+};
+
+KSSLCertDlg::KSSLCertDlg(TQWidget *parent, const char *name, bool modal)
+ : KDialog(parent, name, modal), d(new KSSLCertDlgPrivate) {
+
+ TQBoxLayout * grid = new TQVBoxLayout( this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+
+ d->p_message = new TQLabel(TQString::null, this);
+ grid->addWidget(d->p_message);
+ setHost(_host);
+
+ _certs = new TQListView(this);
+ _certs->addColumn(i18n("Certificate"));
+ _certs->setResizeMode(TQListView::LastColumn);
+ TQFontMetrics fm( TDEGlobalSettings::generalFont() );
+ _certs->setMinimumHeight(4*fm.height());
+ grid->addWidget(_certs);
+
+ _save = new TQCheckBox(i18n("Save selection for this host."), this);
+ grid->addWidget(_save);
+
+ grid->addWidget(new KSeparator(KSeparator::HLine, this));
+
+ TQBoxLayout * h = new TQHBoxLayout( grid );
+ h->insertStretch(0);
+
+ _ok = new KPushButton(i18n("Send certificate"), this);
+ h->addWidget(_ok);
+ connect(_ok, TQT_SIGNAL(clicked()), TQT_SLOT(slotSend()));
+
+ d->p_pb_dontsend = new KPushButton(i18n("Do not send a certificate"), this);
+ h->addWidget(d->p_pb_dontsend);
+ connect(d->p_pb_dontsend, TQT_SIGNAL(clicked()), TQT_SLOT(slotDont()));
+
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ setCaption(i18n("KDE SSL Certificate Dialog"));
+#endif
+}
+
+
+KSSLCertDlg::~KSSLCertDlg() {
+ delete d;
+}
+
+
+void KSSLCertDlg::setup(TQStringList certs, bool saveChecked, bool sendChecked) {
+ setupDialog(certs, saveChecked, sendChecked);
+}
+
+void KSSLCertDlg::setupDialog(const TQStringList& certs, bool saveChecked, bool sendChecked) {
+ _save->setChecked(saveChecked);
+ d->p_send_flag = sendChecked;
+
+ if (sendChecked)
+ _ok->setDefault(true); // "do send" is the "default action".
+ else
+ d->p_pb_dontsend->setDefault(true); // "do not send" is the "default action".
+
+ for (TQStringList::ConstIterator i = certs.begin(); i != certs.end(); ++i) {
+ if ((*i).isEmpty())
+ continue;
+
+ new TQListViewItem(_certs, *i);
+ }
+
+ _certs->setSelected(_certs->firstChild(), true);
+}
+
+
+bool KSSLCertDlg::saveChoice() {
+ return _save->isChecked();
+}
+
+
+bool KSSLCertDlg::wantsToSend() {
+ return d->p_send_flag;
+}
+
+
+TQString KSSLCertDlg::getChoice() {
+ TQListViewItem *selected = _certs->selectedItem();
+ if (selected && d->p_send_flag)
+ return selected->text(0);
+ else
+ return TQString::null;
+}
+
+
+void KSSLCertDlg::setHost(const TQString& host) {
+ _host = host;
+ d->p_message->setText(i18n("The server <b>%1</b> requests a certificate.<p>"
+ "Select a certificate to use from the list below:")
+ .arg(_host));
+}
+
+
+void KSSLCertDlg::slotSend() {
+ d->p_send_flag = true;
+ accept();
+}
+
+
+void KSSLCertDlg::slotDont() {
+ d->p_send_flag = false;
+ reject();
+}
+
+
+TQDataStream& operator<<(TQDataStream& s, const KSSLCertDlgRet& r) {
+ s << TQ_INT8(r.ok?1:0) << r.choice << TQ_INT8(r.save?1:0) << TQ_INT8(r.send?1:0);
+ return s;
+}
+
+
+TQDataStream& operator>>(TQDataStream& s, KSSLCertDlgRet& r) {
+TQ_INT8 tmp;
+ s >> tmp; r.ok = (tmp == 1);
+ s >> r.choice;
+ s >> tmp; r.save = (tmp == 1);
+ s >> tmp; r.send = (tmp == 1);
+ return s;
+}
+
+
+#include "ksslcertdlg.moc"
+
diff --git a/tdeio/kssl/ksslcertdlg.h b/tdeio/kssl/ksslcertdlg.h
new file mode 100644
index 000000000..8d6f3d777
--- /dev/null
+++ b/tdeio/kssl/ksslcertdlg.h
@@ -0,0 +1,138 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 _KSSLCERTDLG_H
+#define _KSSLCERTDLG_H
+
+#include <tqstringlist.h>
+#include <kdialog.h>
+
+class TQWidget;
+class TQCheckBox;
+class TQRadioButton;
+class TQListView;
+class TQPushButton;
+
+/**
+ * KDE X.509 Certificate Dialog
+ *
+ * This class is used to create and display a dialog which contains the user's
+ * X.509 certificates and allows the user to present it during SSL sessions.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE X.509 Certificate Dialog
+ */
+class TDEIO_EXPORT KSSLCertDlg : public KDialog {
+ Q_OBJECT
+public:
+ /**
+ * Construct a KSSL certificate dialog
+ *
+ * @param parent the parent widget
+ * @param name the internal name of this instance
+ * @param modal create a modal dialog if set to true
+ */
+ KSSLCertDlg(TQWidget *parent=0L, const char *name=0L, bool modal=false);
+
+ /**
+ * Destroy this object and close the dialog
+ */
+ virtual ~KSSLCertDlg();
+
+ /**
+ * Setup the dialog. Call this before you display the dialog.
+ *
+ * @param certs the list of possible certificates
+ * @param saveChecked save the checked item for the future
+ * @param sendChecked send the checked item to the remote host
+ * @deprecated
+ */
+ void setup(TQStringList certs, bool saveChecked = false, bool sendChecked = true) KDE_DEPRECATED;
+
+ /**
+ * Setup the dialog. Call this before you display the dialog.
+ *
+ * @param certs the list of possible certificates
+ * @param saveChecked save the checked item for the future
+ * @param sendChecked send the checked item to the remote host
+ */
+ void setupDialog(const TQStringList& certs, bool saveChecked = false, bool sendChecked = true);
+
+ /**
+ * Obtain the name of the certificate the user wants to send
+ *
+ * @return the name of the certificate
+ */
+ TQString getChoice();
+
+ /**
+ * Determine if the user wants to send a certificate.
+ *
+ * @return true if the user wants to send a certificate
+ */
+ bool wantsToSend();
+
+ /**
+ * Determine if the user wants to save the choice for the future.
+ *
+ * @return true if the user wants to save the choice.
+ */
+ bool saveChoice();
+
+ /**
+ * Set the hostname that we are connecting to.
+ *
+ * @param host the hostname
+ */
+ void setHost(const TQString& host);
+
+private slots:
+ void slotSend();
+ void slotDont();
+
+private:
+ class KSSLCertDlgPrivate;
+ KSSLCertDlgPrivate *d;
+ TQCheckBox *_save;
+ TQRadioButton *_send, *_dont;
+ TQListView *_certs;
+ TQPushButton *_ok;
+ TQString _host;
+};
+
+
+class TDEIO_EXPORT KSSLCertDlgRet {
+public:
+ bool ok;
+ TQString choice;
+ bool send;
+ bool save;
+
+protected:
+ class KSSLCertDlgRetPrivate;
+ KSSLCertDlgRetPrivate *d;
+};
+
+TDEIO_EXPORT TQDataStream& operator<<(TQDataStream& s, const KSSLCertDlgRet& r);
+TDEIO_EXPORT TQDataStream& operator>>(TQDataStream& s, KSSLCertDlgRet& r);
+
+#endif
+
diff --git a/tdeio/kssl/ksslcertificate.cc b/tdeio/kssl/ksslcertificate.cc
new file mode 100644
index 000000000..8e2192f7d
--- /dev/null
+++ b/tdeio/kssl/ksslcertificate.cc
@@ -0,0 +1,1157 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+
+#include <unistd.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqfile.h>
+
+#include "kssldefs.h"
+#include "ksslcertificate.h"
+#include "ksslcertchain.h"
+#include "ksslutils.h"
+
+#include <kstandarddirs.h>
+#include <kmdcodec.h>
+#include <klocale.h>
+#include <tqdatetime.h>
+#include <ktempfile.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+// this hack provided by Malte Starostik to avoid glibc/openssl bug
+// on some systems
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/pem.h>
+#undef crypt
+#endif
+
+#include <kopenssl.h>
+#include <tqcstring.h>
+#include <kdebug.h>
+#include "ksslx509v3.h"
+
+
+
+static char hv[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+
+class KSSLCertificatePrivate {
+public:
+ KSSLCertificatePrivate() {
+ kossl = KOSSL::self();
+ _lastPurpose = KSSLCertificate::None;
+ }
+
+ ~KSSLCertificatePrivate() {
+ }
+
+ KSSLCertificate::KSSLValidation m_stateCache;
+ bool m_stateCached;
+ #ifdef KSSL_HAVE_SSL
+ X509 *m_cert;
+ #endif
+ KOSSL *kossl;
+ KSSLCertChain _chain;
+ KSSLX509V3 _extensions;
+ KSSLCertificate::KSSLPurpose _lastPurpose;
+};
+
+KSSLCertificate::KSSLCertificate() {
+ d = new KSSLCertificatePrivate;
+ d->m_stateCached = false;
+ TDEGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl");
+ #ifdef KSSL_HAVE_SSL
+ d->m_cert = NULL;
+ #endif
+}
+
+
+KSSLCertificate::KSSLCertificate(const KSSLCertificate& x) {
+ d = new KSSLCertificatePrivate;
+ d->m_stateCached = false;
+ TDEGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl");
+ #ifdef KSSL_HAVE_SSL
+ d->m_cert = NULL;
+ setCert(KOSSL::self()->X509_dup(const_cast<KSSLCertificate&>(x).getCert()));
+ KSSLCertChain *c = x.d->_chain.replicate();
+ setChain(c->rawChain());
+ delete c;
+ #endif
+}
+
+
+
+KSSLCertificate::~KSSLCertificate() {
+#ifdef KSSL_HAVE_SSL
+ if (d->m_cert)
+ d->kossl->X509_free(d->m_cert);
+#endif
+ delete d;
+}
+
+
+KSSLCertChain& KSSLCertificate::chain() {
+ return d->_chain;
+}
+
+
+KSSLCertificate *KSSLCertificate::fromX509(X509 *x5) {
+KSSLCertificate *n = NULL;
+#ifdef KSSL_HAVE_SSL
+ if (x5) {
+ n = new KSSLCertificate;
+ n->setCert(KOSSL::self()->X509_dup(x5));
+ }
+#endif
+return n;
+}
+
+
+KSSLCertificate *KSSLCertificate::fromString(TQCString cert) {
+KSSLCertificate *n = NULL;
+#ifdef KSSL_HAVE_SSL
+ if (cert.length() == 0)
+ return NULL;
+
+ TQByteArray qba, qbb = cert.copy();
+ KCodecs::base64Decode(qbb, qba);
+ unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
+ X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
+ if (!x5c) {
+ return NULL;
+ }
+
+ n = new KSSLCertificate;
+ n->setCert(x5c);
+#endif
+return n;
+}
+
+
+
+TQString KSSLCertificate::getSubject() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_subject_name(d->m_cert), 0, 0);
+ if (!t)
+ return rc;
+ rc = t;
+ d->kossl->OPENSSL_free(t);
+#endif
+return rc;
+}
+
+
+TQString KSSLCertificate::getSerialNumber() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ ASN1_INTEGER *aint = d->kossl->X509_get_serialNumber(d->m_cert);
+ if (aint) {
+ rc = ASN1_INTEGER_QString(aint);
+ // d->kossl->ASN1_INTEGER_free(aint); this makes the sig test fail
+ }
+#endif
+return rc;
+}
+
+
+TQString KSSLCertificate::getSignatureText() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+char *s;
+int n, i;
+
+ i = d->kossl->OBJ_obj2nid(d->m_cert->sig_alg->algorithm);
+ rc = i18n("Signature Algorithm: ");
+ rc += (i == NID_undef)?i18n("Unknown"):TQString(d->kossl->OBJ_nid2ln(i));
+
+ rc += "\n";
+ rc += i18n("Signature Contents:");
+ n = d->m_cert->signature->length;
+ s = (char *)d->m_cert->signature->data;
+ for (i = 0; i < n; i++) {
+ if (i%20 != 0) rc += ":";
+ else rc += "\n";
+ rc.append(hv[(s[i]&0xf0)>>4]);
+ rc.append(hv[s[i]&0x0f]);
+ }
+
+#endif
+
+return rc;
+}
+
+
+void KSSLCertificate::getEmails(TQStringList &to) const {
+ to.clear();
+#ifdef KSSL_HAVE_SSL
+ if (!d->m_cert)
+ return;
+
+ STACK *s = d->kossl->X509_get1_email(d->m_cert);
+ if (s) {
+ for(int n=0; n < s->num; n++) {
+ to.append(d->kossl->sk_value(s,n));
+ }
+ d->kossl->X509_email_free(s);
+ }
+#endif
+}
+
+
+TQString KSSLCertificate::getKDEKey() const {
+ return getSubject() + " (" + getMD5DigestText() + ")";
+}
+
+
+TQString KSSLCertificate::getMD5DigestFromKDEKey(const TQString &k) {
+ TQString rc;
+ int pos = k.findRev('(');
+ if (pos != -1) {
+ unsigned int len = k.length();
+ if (k.at(len-1) == ')') {
+ rc = k.mid(pos+1, len-pos-2);
+ }
+ }
+ return rc;
+}
+
+
+TQString KSSLCertificate::getMD5DigestText() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
+ return rc;
+ }
+
+ for (unsigned int j = 0; j < n; j++) {
+ if (j > 0)
+ rc += ":";
+ rc.append(hv[(md[j]&0xf0)>>4]);
+ rc.append(hv[md[j]&0x0f]);
+ }
+
+#endif
+
+return rc;
+}
+
+
+
+TQString KSSLCertificate::getMD5Digest() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
+ return rc;
+ }
+
+ for (unsigned int j = 0; j < n; j++) {
+ rc.append(hv[(md[j]&0xf0)>>4]);
+ rc.append(hv[md[j]&0x0f]);
+ }
+
+#endif
+
+return rc;
+}
+
+
+
+TQString KSSLCertificate::getKeyType() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
+ if (pkey) {
+ #ifndef NO_RSA
+ if (pkey->type == EVP_PKEY_RSA)
+ rc = "RSA";
+ else
+ #endif
+ #ifndef NO_DSA
+ if (pkey->type == EVP_PKEY_DSA)
+ rc = "DSA";
+ else
+ #endif
+ rc = "Unknown";
+ d->kossl->EVP_PKEY_free(pkey);
+ }
+#endif
+
+return rc;
+}
+
+
+
+TQString KSSLCertificate::getPublicKeyText() const {
+TQString rc = "";
+char *x = NULL;
+
+#ifdef KSSL_HAVE_SSL
+ EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
+ if (pkey) {
+ rc = i18n("Unknown", "Unknown key algorithm");
+ #ifndef NO_RSA
+ if (pkey->type == EVP_PKEY_RSA) {
+ rc = i18n("Key type: RSA (%1 bit)") + "\n";
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.rsa->n);
+ rc += i18n("Modulus: ");
+ rc = rc.arg(strlen(x)*4);
+ for (unsigned int i = 0; i < strlen(x); i++) {
+ if (i%40 != 0 && i%2 == 0)
+ rc += ":";
+ else if (i%40 == 0)
+ rc += "\n";
+ rc += x[i];
+ }
+ rc += "\n";
+ d->kossl->OPENSSL_free(x);
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.rsa->e);
+ rc += i18n("Exponent: 0x") + x + "\n";
+ d->kossl->OPENSSL_free(x);
+ }
+ #endif
+ #ifndef NO_DSA
+ if (pkey->type == EVP_PKEY_DSA) {
+ rc = i18n("Key type: DSA (%1 bit)") + "\n";
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.dsa->p);
+ rc += i18n("Prime: ");
+ // hack - this may not be always accurate
+ rc = rc.arg(strlen(x)*4) ;
+ for (unsigned int i = 0; i < strlen(x); i++) {
+ if (i%40 != 0 && i%2 == 0)
+ rc += ":";
+ else if (i%40 == 0)
+ rc += "\n";
+ rc += x[i];
+ }
+ rc += "\n";
+ d->kossl->OPENSSL_free(x);
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.dsa->q);
+ rc += i18n("160 bit prime factor: ");
+ for (unsigned int i = 0; i < strlen(x); i++) {
+ if (i%40 != 0 && i%2 == 0)
+ rc += ":";
+ else if (i%40 == 0)
+ rc += "\n";
+ rc += x[i];
+ }
+ rc += "\n";
+ d->kossl->OPENSSL_free(x);
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.dsa->g);
+ rc += TQString("g: ");
+ for (unsigned int i = 0; i < strlen(x); i++) {
+ if (i%40 != 0 && i%2 == 0)
+ rc += ":";
+ else if (i%40 == 0)
+ rc += "\n";
+ rc += x[i];
+ }
+ rc += "\n";
+ d->kossl->OPENSSL_free(x);
+
+ x = d->kossl->BN_bn2hex(pkey->pkey.dsa->pub_key);
+ rc += i18n("Public key: ");
+ for (unsigned int i = 0; i < strlen(x); i++) {
+ if (i%40 != 0 && i%2 == 0)
+ rc += ":";
+ else if (i%40 == 0)
+ rc += "\n";
+ rc += x[i];
+ }
+ rc += "\n";
+ d->kossl->OPENSSL_free(x);
+ }
+ #endif
+ d->kossl->EVP_PKEY_free(pkey);
+ }
+#endif
+
+return rc;
+}
+
+
+
+TQString KSSLCertificate::getIssuer() const {
+TQString rc = "";
+
+#ifdef KSSL_HAVE_SSL
+ char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), 0, 0);
+
+ if (!t)
+ return rc;
+
+ rc = t;
+ d->kossl->OPENSSL_free(t);
+#endif
+
+return rc;
+}
+
+void KSSLCertificate::setChain(void *c) {
+#ifdef KSSL_HAVE_SSL
+ d->_chain.setChain(c);
+#endif
+ d->m_stateCached = false;
+ d->m_stateCache = KSSLCertificate::Unknown;
+}
+
+void KSSLCertificate::setCert(X509 *c) {
+#ifdef KSSL_HAVE_SSL
+d->m_cert = c;
+if (c) {
+ d->_extensions.flags = 0;
+ d->kossl->X509_check_purpose(c, -1, 0); // setup the fields (!!)
+
+#if 0
+ kdDebug(7029) << "---------------- Certificate ------------------"
+ << endl;
+ kdDebug(7029) << getSubject() << endl;
+#endif
+
+ for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) {
+ X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j);
+ int id = d->kossl->X509_PURPOSE_get_id(ptmp);
+ for (int ca = 0; ca < 2; ca++) {
+ int idret = d->kossl->X509_check_purpose(c, id, ca);
+ if (idret == 1 || idret == 2) { // have it
+// kdDebug() << "PURPOSE: " << id << (ca?" CA":"") << endl;
+ if (!ca)
+ d->_extensions.flags |= (1L <<(id-1));
+ else d->_extensions.flags |= (1L <<(16+id-1));
+ } else {
+ if (!ca)
+ d->_extensions.flags &= ~(1L <<(id-1));
+ else d->_extensions.flags &= ~(1L <<(16+id-1));
+ }
+ }
+ }
+
+#if 0
+ kdDebug(7029) << "flags: " << TQString::number(c->ex_flags, 2)
+ << "\nkeyusage: " << TQString::number(c->ex_kusage, 2)
+ << "\nxkeyusage: " << TQString::number(c->ex_xkusage, 2)
+ << "\nnscert: " << TQString::number(c->ex_nscert, 2)
+ << endl;
+ if (c->ex_flags & EXFLAG_KUSAGE)
+ kdDebug(7029) << " --- Key Usage extensions found" << endl;
+ else kdDebug(7029) << " --- Key Usage extensions NOT found" << endl;
+
+ if (c->ex_flags & EXFLAG_XKUSAGE)
+ kdDebug(7029) << " --- Extended key usage extensions found" << endl;
+ else kdDebug(7029) << " --- Extended key usage extensions NOT found" << endl;
+
+ if (c->ex_flags & EXFLAG_NSCERT)
+ kdDebug(7029) << " --- NS extensions found" << endl;
+ else kdDebug(7029) << " --- NS extensions NOT found" << endl;
+
+ if (d->_extensions.certTypeSSLCA())
+ kdDebug(7029) << "NOTE: this is an SSL CA file." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SSL CA file." << endl;
+
+ if (d->_extensions.certTypeEmailCA())
+ kdDebug(7029) << "NOTE: this is an EMAIL CA file." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an EMAIL CA file." << endl;
+
+ if (d->_extensions.certTypeCodeCA())
+ kdDebug(7029) << "NOTE: this is a CODE CA file." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT a CODE CA file." << endl;
+
+ if (d->_extensions.certTypeSSLClient())
+ kdDebug(7029) << "NOTE: this is an SSL client." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SSL client." << endl;
+
+ if (d->_extensions.certTypeSSLServer())
+ kdDebug(7029) << "NOTE: this is an SSL server." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SSL server." << endl;
+
+ if (d->_extensions.certTypeNSSSLServer())
+ kdDebug(7029) << "NOTE: this is a NETSCAPE SSL server." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT a NETSCAPE SSL server." << endl;
+
+ if (d->_extensions.certTypeSMIME())
+ kdDebug(7029) << "NOTE: this is an SMIME certificate." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SMIME certificate." << endl;
+
+ if (d->_extensions.certTypeSMIMEEncrypt())
+ kdDebug(7029) << "NOTE: this is an SMIME encrypt cert." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SMIME encrypt cert." << endl;
+
+ if (d->_extensions.certTypeSMIMESign())
+ kdDebug(7029) << "NOTE: this is an SMIME sign cert." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT an SMIME sign cert." << endl;
+
+ if (d->_extensions.certTypeCRLSign())
+ kdDebug(7029) << "NOTE: this is a CRL signer." << endl;
+ else kdDebug(7029) << "NOTE: this is NOT a CRL signer." << endl;
+
+ kdDebug(7029) << "-----------------------------------------------"
+ << endl;
+#endif
+}
+#endif
+d->m_stateCached = false;
+d->m_stateCache = KSSLCertificate::Unknown;
+}
+
+X509 *KSSLCertificate::getCert() {
+#ifdef KSSL_HAVE_SSL
+ return d->m_cert;
+#endif
+return 0;
+}
+
+// pull in the callback. It's common across multiple files but we want
+// it to be hidden.
+
+#include "ksslcallback.c"
+
+
+bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p) {
+ return (validate(p) == KSSLCertificate::Ok);
+}
+
+
+bool KSSLCertificate::isValid() {
+ return isValid(KSSLCertificate::SSLServer);
+}
+
+
+int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const {
+int rc = 0;
+#ifdef KSSL_HAVE_SSL
+ if (p == KSSLCertificate::SSLServer) {
+ rc = X509_PURPOSE_SSL_SERVER;
+ } else if (p == KSSLCertificate::SSLClient) {
+ rc = X509_PURPOSE_SSL_CLIENT;
+ } else if (p == KSSLCertificate::SMIMEEncrypt) {
+ rc = X509_PURPOSE_SMIME_ENCRYPT;
+ } else if (p == KSSLCertificate::SMIMESign) {
+ rc = X509_PURPOSE_SMIME_SIGN;
+ } else if (p == KSSLCertificate::Any) {
+ rc = X509_PURPOSE_ANY;
+ }
+#endif
+return rc;
+}
+
+
+// For backward compatibility
+KSSLCertificate::KSSLValidation KSSLCertificate::validate() {
+ return validate(KSSLCertificate::SSLServer);
+}
+
+KSSLCertificate::KSSLValidation KSSLCertificate::validate(KSSLCertificate::KSSLPurpose purpose)
+{
+ KSSLValidationList result = validateVerbose(purpose);
+ if (result.isEmpty())
+ return KSSLCertificate::Ok;
+ else
+ return result.first();
+}
+
+//
+// See apps/verify.c in OpenSSL for the source of most of this logic.
+//
+
+// CRL files? we don't do that yet
+KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose)
+{
+ return validateVerbose(purpose, 0);
+}
+
+KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose, KSSLCertificate *ca)
+{
+ KSSLValidationList errors;
+ if (ca || (d->_lastPurpose != purpose)) {
+ d->m_stateCached = false;
+ }
+
+ if (!d->m_stateCached)
+ d->_lastPurpose = purpose;
+
+#ifdef KSSL_HAVE_SSL
+ X509_STORE *certStore;
+ X509_LOOKUP *certLookup;
+ X509_STORE_CTX *certStoreCTX;
+ int rc = 0;
+
+ if (!d->m_cert)
+ {
+ errors << KSSLCertificate::Unknown;
+ return errors;
+ }
+
+ if (d->m_stateCached) {
+ errors << d->m_stateCache;
+ return errors;
+ }
+
+ TQStringList qsl = TDEGlobal::dirs()->resourceDirs("kssl");
+
+ if (qsl.isEmpty()) {
+ errors << KSSLCertificate::NoCARoot;
+ return errors;
+ }
+
+ KSSLCertificate::KSSLValidation ksslv = Unknown;
+
+ for (TQStringList::Iterator j = qsl.begin(); j != qsl.end(); ++j) {
+ struct stat sb;
+ TQString _j = (*j) + "ca-bundle.crt";
+ if (-1 == stat(_j.ascii(), &sb)) {
+ continue;
+ }
+
+ certStore = d->kossl->X509_STORE_new();
+ if (!certStore) {
+ errors << KSSLCertificate::Unknown;
+ return errors;
+ }
+
+ X509_STORE_set_verify_cb_func(certStore, X509Callback);
+
+ certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file());
+ if (!certLookup) {
+ ksslv = KSSLCertificate::Unknown;
+ d->kossl->X509_STORE_free(certStore);
+ continue;
+ }
+
+ if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.ascii(), X509_FILETYPE_PEM)) {
+ // error accessing directory and loading pems
+ kdDebug(7029) << "KSSL couldn't read CA root: "
+ << _j << endl;
+ ksslv = KSSLCertificate::ErrorReadingRoot;
+ d->kossl->X509_STORE_free(certStore);
+ continue;
+ }
+
+ // This is the checking code
+ certStoreCTX = d->kossl->X509_STORE_CTX_new();
+
+ // this is a bad error - could mean no free memory.
+ // This may be the wrong thing to do here
+ if (!certStoreCTX) {
+ kdDebug(7029) << "KSSL couldn't create an X509 store context." << endl;
+ d->kossl->X509_STORE_free(certStore);
+ continue;
+ }
+
+ d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, NULL);
+ if (d->_chain.isValid()) {
+ d->kossl->X509_STORE_CTX_set_chain(certStoreCTX, (STACK_OF(X509)*)d->_chain.rawChain());
+ }
+
+ //kdDebug(7029) << "KSSL setting CRL.............." << endl;
+ // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
+
+ d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose));
+
+ KSSL_X509CallBack_ca = ca ? ca->d->m_cert : 0;
+ KSSL_X509CallBack_ca_found = false;
+
+ certStoreCTX->error = X509_V_OK;
+ rc = d->kossl->X509_verify_cert(certStoreCTX);
+ int errcode = certStoreCTX->error;
+ if (ca && !KSSL_X509CallBack_ca_found) {
+ ksslv = KSSLCertificate::Irrelevant;
+ } else {
+ ksslv = processError(errcode);
+ }
+ // For servers, we can try NS_SSL_SERVER too
+ if ( (ksslv != KSSLCertificate::Ok) &&
+ (ksslv != KSSLCertificate::Irrelevant) &&
+ purpose == KSSLCertificate::SSLServer) {
+ d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX,
+ X509_PURPOSE_NS_SSL_SERVER);
+
+ certStoreCTX->error = X509_V_OK;
+ rc = d->kossl->X509_verify_cert(certStoreCTX);
+ errcode = certStoreCTX->error;
+ ksslv = processError(errcode);
+ }
+ d->kossl->X509_STORE_CTX_free(certStoreCTX);
+ d->kossl->X509_STORE_free(certStore);
+ // end of checking code
+ //
+
+ //kdDebug(7029) << "KSSL Validation procedure RC: "
+ // << rc << endl;
+ //kdDebug(7029) << "KSSL Validation procedure errcode: "
+ // << errcode << endl;
+ //kdDebug(7029) << "KSSL Validation procedure RESULTS: "
+ // << ksslv << endl;
+
+ if (ksslv != NoCARoot && ksslv != InvalidCA) {
+ d->m_stateCached = true;
+ d->m_stateCache = ksslv;
+ }
+ break;
+ }
+
+ if (ksslv != KSSLCertificate::Ok)
+ errors << ksslv;
+#else
+ errors << KSSLCertificate::NoSSL;
+#endif
+ return errors;
+}
+
+
+
+KSSLCertificate::KSSLValidation KSSLCertificate::revalidate() {
+ return revalidate(KSSLCertificate::SSLServer);
+}
+
+
+KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p) {
+ d->m_stateCached = false;
+ return validate(p);
+}
+
+
+KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec) {
+KSSLCertificate::KSSLValidation rc;
+
+rc = KSSLCertificate::Unknown;
+#ifdef KSSL_HAVE_SSL
+ switch (ec) {
+ case X509_V_OK: // OK
+ rc = KSSLCertificate::Ok;
+ break;
+
+
+ case X509_V_ERR_CERT_REJECTED:
+ rc = KSSLCertificate::Rejected;
+ break;
+
+
+ case X509_V_ERR_CERT_UNTRUSTED:
+ rc = KSSLCertificate::Untrusted;
+ break;
+
+
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ rc = KSSLCertificate::SignatureFailed;
+ break;
+
+ case X509_V_ERR_INVALID_CA:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ rc = KSSLCertificate::InvalidCA;
+ break;
+
+
+ case X509_V_ERR_INVALID_PURPOSE:
+ rc = KSSLCertificate::InvalidPurpose;
+ break;
+
+
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ rc = KSSLCertificate::SelfSigned;
+ break;
+
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ rc = KSSLCertificate::SelfSignedChain;
+ break;
+
+ case X509_V_ERR_CERT_REVOKED:
+ rc = KSSLCertificate::Revoked;
+ break;
+
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ rc = KSSLCertificate::PathLengthExceeded;
+ break;
+
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ rc = KSSLCertificate::Expired;
+ kdDebug(7029) << "KSSL apparently this is expired. Not after: "
+ << getNotAfter() << endl;
+ break;
+
+ //case 1:
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ default:
+ rc = KSSLCertificate::Unknown;
+ break;
+}
+
+d->m_stateCache = rc;
+d->m_stateCached = true;
+#endif
+return rc;
+}
+
+
+TQString KSSLCertificate::getNotBefore() const {
+#ifdef KSSL_HAVE_SSL
+return ASN1_UTCTIME_QString(X509_get_notBefore(d->m_cert));
+#else
+return TQString::null;
+#endif
+}
+
+
+TQString KSSLCertificate::getNotAfter() const {
+#ifdef KSSL_HAVE_SSL
+return ASN1_UTCTIME_QString(X509_get_notAfter(d->m_cert));
+#else
+return TQString::null;
+#endif
+}
+
+
+TQDateTime KSSLCertificate::getQDTNotBefore() const {
+#ifdef KSSL_HAVE_SSL
+return ASN1_UTCTIME_QDateTime(X509_get_notBefore(d->m_cert), NULL);
+#else
+return TQDateTime::currentDateTime();
+#endif
+}
+
+
+TQDateTime KSSLCertificate::getQDTNotAfter() const {
+#ifdef KSSL_HAVE_SSL
+return ASN1_UTCTIME_QDateTime(X509_get_notAfter(d->m_cert), NULL);
+#else
+return TQDateTime::currentDateTime();
+#endif
+}
+
+
+int operator==(KSSLCertificate &x, KSSLCertificate &y) {
+#ifndef KSSL_HAVE_SSL
+ return 1;
+#else
+ if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) return 1;
+ return 0;
+#endif
+}
+
+
+KSSLCertificate *KSSLCertificate::replicate() {
+// The new certificate doesn't have the cached value. It's probably
+// better this way. We can't anticipate every reason for doing this.
+KSSLCertificate *newOne = new KSSLCertificate();
+#ifdef KSSL_HAVE_SSL
+ newOne->setCert(d->kossl->X509_dup(getCert()));
+ KSSLCertChain *c = d->_chain.replicate();
+ newOne->setChain(c->rawChain());
+ delete c;
+#endif
+return newOne;
+}
+
+
+TQString KSSLCertificate::toString() {
+return KCodecs::base64Encode(toDer());
+}
+
+
+TQString KSSLCertificate::verifyText(KSSLValidation x) {
+switch (x) {
+case KSSLCertificate::Ok:
+ return i18n("The certificate is valid.");
+case KSSLCertificate::PathLengthExceeded:
+case KSSLCertificate::ErrorReadingRoot:
+case KSSLCertificate::NoCARoot:
+ return i18n("Certificate signing authority root files could not be found so the certificate is not verified.");
+case KSSLCertificate::SelfSignedChain:
+case KSSLCertificate::InvalidCA:
+ return i18n("Certificate signing authority is unknown or invalid.");
+case KSSLCertificate::SelfSigned:
+ return i18n("Certificate is self-signed and thus may not be trustworthy.");
+case KSSLCertificate::Expired:
+ return i18n("Certificate has expired.");
+case KSSLCertificate::Revoked:
+ return i18n("Certificate has been revoked.");
+case KSSLCertificate::NoSSL:
+ return i18n("SSL support was not found.");
+case KSSLCertificate::Untrusted:
+ return i18n("Signature is untrusted.");
+case KSSLCertificate::SignatureFailed:
+ return i18n("Signature test failed.");
+case KSSLCertificate::Rejected:
+case KSSLCertificate::InvalidPurpose:
+ return i18n("Rejected, possibly due to an invalid purpose.");
+case KSSLCertificate::PrivateKeyFailed:
+ return i18n("Private key test failed.");
+case KSSLCertificate::InvalidHost:
+ return i18n("The certificate has not been issued for this host.");
+case KSSLCertificate::Irrelevant:
+ return i18n("This certificate is not relevant.");
+default:
+break;
+}
+
+return i18n("The certificate is invalid.");
+}
+
+
+TQByteArray KSSLCertificate::toDer() {
+TQByteArray qba;
+#ifdef KSSL_HAVE_SSL
+unsigned int certlen = d->kossl->i2d_X509(getCert(), NULL);
+unsigned char *cert = new unsigned char[certlen];
+unsigned char *p = cert;
+ // FIXME: return code!
+ d->kossl->i2d_X509(getCert(), &p);
+
+ // encode it into a QString
+ qba.duplicate((const char*)cert, certlen);
+ delete[] cert;
+#endif
+return qba;
+}
+
+
+
+TQByteArray KSSLCertificate::toPem() {
+TQByteArray qba;
+TQString thecert = toString();
+const char *header = "-----BEGIN CERTIFICATE-----\n";
+const char *footer = "-----END CERTIFICATE-----\n";
+
+ // We just do base64 on the ASN1
+ // 64 character lines (unpadded)
+ unsigned int xx = thecert.length() - 1;
+ for (unsigned int i = 0; i < xx/64; i++) {
+ thecert.insert(64*(i+1)+i, '\n');
+ }
+
+ thecert.prepend(header);
+
+ if (thecert[thecert.length()-1] != '\n')
+ thecert += "\n";
+
+ thecert.append(footer);
+
+ qba.duplicate(thecert.local8Bit(), thecert.length());
+return qba;
+}
+
+
+#define NETSCAPE_CERT_HDR "certificate"
+
+// what a piece of crap this is
+TQByteArray KSSLCertificate::toNetscape() {
+TQByteArray qba;
+#ifdef KSSL_HAVE_SSL
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ NETSCAPE_X509 nx;
+ ASN1_OCTET_STRING hdr;
+#else
+ ASN1_HEADER ah;
+ ASN1_OCTET_STRING os;
+#endif
+ KTempFile ktf;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ hdr.data = (unsigned char *)NETSCAPE_CERT_HDR;
+ hdr.length = strlen(NETSCAPE_CERT_HDR);
+ nx.header = &hdr;
+ nx.cert = getCert();
+
+ d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&nx);
+#else
+ os.data = (unsigned char *)NETSCAPE_CERT_HDR;
+ os.length = strlen(NETSCAPE_CERT_HDR);
+ ah.header = &os;
+ ah.data = (char *)getCert();
+ ah.meth = d->kossl->X509_asn1_meth();
+
+ d->kossl->ASN1_i2d_fp(ktf.fstream(),(unsigned char *)&ah);
+#endif
+
+ ktf.close();
+
+ TQFile qf(ktf.name());
+ qf.open(IO_ReadOnly);
+ char *buf = new char[qf.size()];
+ qf.readBlock(buf, qf.size());
+ qba.duplicate(buf, qf.size());
+ qf.close();
+ delete[] buf;
+
+ ktf.unlink();
+
+#endif
+return qba;
+}
+
+
+
+TQString KSSLCertificate::toText() {
+TQString text;
+#ifdef KSSL_HAVE_SSL
+KTempFile ktf;
+
+ d->kossl->X509_print(ktf.fstream(), getCert());
+ ktf.close();
+
+ TQFile qf(ktf.name());
+ qf.open(IO_ReadOnly);
+ char *buf = new char[qf.size()+1];
+ qf.readBlock(buf, qf.size());
+ buf[qf.size()] = 0;
+ text = buf;
+ delete[] buf;
+ qf.close();
+ ktf.unlink();
+#endif
+return text;
+}
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificate::setCert(TQString& cert) {
+#ifdef KSSL_HAVE_SSL
+TQByteArray qba, qbb = cert.local8Bit().copy();
+ KCodecs::base64Decode(qbb, qba);
+ unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
+ X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size());
+ if (x5c) {
+ setCert(x5c);
+ return true;
+ }
+#endif
+return false;
+}
+
+
+KSSLX509V3& KSSLCertificate::x509V3Extensions() {
+return d->_extensions;
+}
+
+
+bool KSSLCertificate::isSigner() {
+return d->_extensions.certTypeCA();
+}
+
+
+TQStringList KSSLCertificate::subjAltNames() const {
+ TQStringList rc;
+#ifdef KSSL_HAVE_SSL
+ STACK_OF(GENERAL_NAME) *names;
+ names = (STACK_OF(GENERAL_NAME)*)d->kossl->X509_get_ext_d2i(d->m_cert, NID_subject_alt_name, 0, 0);
+
+ if (!names) {
+ return rc;
+ }
+
+ int cnt = d->kossl->sk_GENERAL_NAME_num(names);
+
+ for (int i = 0; i < cnt; i++) {
+ const GENERAL_NAME *val = (const GENERAL_NAME *)d->kossl->sk_value(names, i);
+ if (val->type != GEN_DNS) {
+ continue;
+ }
+
+ TQString s = (const char *)d->kossl->ASN1_STRING_data(val->d.ia5);
+ if (!s.isEmpty() &&
+ /* skip subjectAltNames with embedded NULs */
+ s.length() == d->kossl->ASN1_STRING_length(val->d.ia5)) {
+ rc += s;
+ }
+ }
+ d->kossl->sk_free(names);
+#endif
+ return rc;
+}
+
+
+TQDataStream& operator<<(TQDataStream& s, const KSSLCertificate& r) {
+TQStringList qsl;
+TQPtrList<KSSLCertificate> cl = const_cast<KSSLCertificate&>(r).chain().getChain();
+
+ for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) {
+ qsl << c->toString();
+ }
+
+ cl.setAutoDelete(true);
+
+ s << const_cast<KSSLCertificate&>(r).toString() << qsl;
+
+return s;
+}
+
+
+TQDataStream& operator>>(TQDataStream& s, KSSLCertificate& r) {
+TQStringList qsl;
+TQString cert;
+
+s >> cert >> qsl;
+
+ if (r.setCert(cert) && !qsl.isEmpty())
+ r.chain().setCertChain(qsl);
+
+return s;
+}
+
+
+
diff --git a/tdeio/kssl/ksslcertificate.h b/tdeio/kssl/ksslcertificate.h
new file mode 100644
index 000000000..0c5f87323
--- /dev/null
+++ b/tdeio/kssl/ksslcertificate.h
@@ -0,0 +1,376 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLCERTIFICATE_H
+#define _KSSLCERTIFICATE_H
+
+
+// UPDATE: I like the structure of this class less and less every time I look
+// at it. I think it needs to change.
+//
+//
+// The biggest reason for making everything protected here is so that
+// the class can have all it's methods available even if openssl is not
+// available. Also, to create a new certificate you should use the
+// KSSLCertificateFactory, and to manage the user's database of certificates,
+// you should go through the KSSLCertificateHome.
+//
+// There should be no reason to touch the X509 stuff directly.
+//
+
+#include <tqcstring.h>
+#include <tqvaluelist.h>
+
+class TQString;
+class TQStringList;
+class TQCString;
+class KSSL;
+class KSSLCertificatePrivate;
+class TQDateTime;
+class KSSLCertChain;
+class KSSLX509V3;
+
+#include <tdelibs_export.h>
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#ifdef KSSL_HAVE_SSL
+typedef struct x509_st X509;
+#else
+class X509;
+#endif
+
+/**
+ * KDE X.509 Certificate
+ *
+ * This class represents an X.509 (SSL) certificate.
+ * Note: this object is VERY HEAVY TO COPY. Please try to use reference
+ * or pointer whenever possible
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE X.509 Certificate
+ */
+class TDEIO_EXPORT KSSLCertificate {
+friend class KSSL;
+friend class KSSLCertificateHome;
+friend class KSSLCertificateFactory;
+friend class KSSLCertificateCache;
+friend class KSSLCertChain;
+friend class KSSLPeerInfo;
+friend class KSSLPKCS12;
+friend class KSSLD;
+friend class KSMIMECryptoPrivate;
+
+
+public:
+ /**
+ * Destroy this X.509 certificate.
+ */
+ ~KSSLCertificate();
+
+ /**
+ * Create an X.509 certificate from a base64 encoded string.
+ * @param cert the certificate in base64 form
+ * @return the X.509 certificate, or NULL
+ */
+ static KSSLCertificate *fromString(TQCString cert);
+
+ /**
+ * Create an X.509 certificate from the internal representation.
+ * This one duplicates the X509 object for itself.
+ * @param x5 the OpenSSL representation of the certificate
+ * @return the X.509 certificate, or NULL
+ * @internal
+ */
+ static KSSLCertificate *fromX509(X509 *x5);
+
+ /**
+ * A CA certificate can be validated as Irrelevant when it was
+ * not used to sign any other relevant certificate.
+ */
+ enum KSSLValidation { Unknown, Ok, NoCARoot, InvalidPurpose,
+ PathLengthExceeded, InvalidCA, Expired,
+ SelfSigned, ErrorReadingRoot, NoSSL,
+ Revoked, Untrusted, SignatureFailed,
+ Rejected, PrivateKeyFailed, InvalidHost,
+ Irrelevant, SelfSignedChain
+ };
+
+ enum KSSLPurpose { None=0, SSLServer=1, SSLClient=2,
+ SMIMESign=3, SMIMEEncrypt=4, Any=5 };
+
+ typedef TQValueList<KSSLValidation> KSSLValidationList;
+
+ /**
+ * Convert this certificate to a string.
+ * @return the certificate in base64 format
+ */
+ TQString toString();
+
+ /**
+ * Get the subject of the certificate (X.509 map).
+ * @return the subject
+ */
+ TQString getSubject() const;
+
+ /**
+ * Get the issuer of the certificate (X.509 map).
+ * @return the issuer
+ */
+ TQString getIssuer() const;
+
+ /**
+ * Get the date that the certificate becomes valid on.
+ * @return the date as a string, localised
+ */
+ TQString getNotBefore() const;
+
+ /**
+ * Get the date that the certificate is valid until.
+ * @return the date as a string, localised
+ */
+ TQString getNotAfter() const;
+
+ /**
+ * Get the date that the certificate becomes valid on.
+ * @return the date
+ */
+ TQDateTime getQDTNotBefore() const;
+
+ /**
+ * Get the date that the certificate is valid until.
+ * @return the date
+ */
+ TQDateTime getQDTNotAfter() const;
+
+ /**
+ * Convert the certificate to DER (ASN.1) format.
+ * @return the binary data of the DER encoding
+ */
+ TQByteArray toDer();
+
+ /**
+ * Convert the certificate to PEM (base64) format.
+ * @return the binary data of the PEM encoding
+ */
+ TQByteArray toPem();
+
+ /**
+ * Convert the certificate to Netscape format.
+ * @return the binary data of the Netscape encoding
+ */
+ TQByteArray toNetscape();
+
+ /**
+ * Convert the certificate to OpenSSL plain text format.
+ * @return the OpenSSL text encoding
+ */
+ TQString toText();
+
+ /**
+ * Get the serial number of the certificate.
+ * @return the serial number as a string
+ */
+ TQString getSerialNumber() const;
+
+ /**
+ * Get the key type (RSA, DSA, etc).
+ * @return the key type as a string
+ */
+ TQString getKeyType() const;
+
+ /**
+ * Get the public key.
+ * @return the public key as a hexidecimal string
+ */
+ TQString getPublicKeyText() const;
+
+ /**
+ * Get the MD5 digest of the certificate.
+ * Result is padded with : to separate bytes - it's a text version!
+ * @return the MD5 digest in a hexidecimal string
+ */
+ TQString getMD5DigestText() const;
+
+ /**
+ * Get the MD5 digest of the certificate.
+ * @return the MD5 digest in a hexidecimal string
+ */
+ TQString getMD5Digest() const;
+
+ /**
+ * Get the signature.
+ * @return the signature in text format
+ */
+ TQString getSignatureText() const;
+
+ /**
+ * Check if this is a valid certificate. Will use cached data.
+ * @return true if it is valid
+ */
+ bool isValid();
+
+ /**
+ * Check if this is a valid certificate. Will use cached data.
+ * @param p the purpose to validate for
+ * @return true if it is valid
+ */
+ bool isValid(KSSLPurpose p);
+
+ /**
+ * The alternate subject name.
+ * @return string list with subjectAltName
+ */
+ TQStringList subjAltNames() const;
+
+ /**
+ * Check if this is a valid certificate. Will use cached data.
+ * @return the result of the validation
+ */
+ KSSLValidation validate();
+
+ /**
+ * Check if this is a valid certificate. Will use cached data.
+ * @param p the purpose to validate for
+ * @return the result of the validation
+ */
+ KSSLValidation validate(KSSLPurpose p);
+
+ /**
+ * Check if this is a valid certificate. Will use cached data.
+ * @param p the purpose to validate for
+ * @return all problems encountered during validation
+ */
+ KSSLValidationList validateVerbose(KSSLPurpose p);
+
+ /**
+ * Check if the certificate ca is a proper CA for this
+ * certificate.
+ * @param p the purpose to validate for
+ * @param ca the certificate to check
+ * @return all problems encountered during validation
+ */
+ KSSLValidationList validateVerbose(KSSLPurpose p, KSSLCertificate *ca);
+
+ /**
+ * Check if this is a valid certificate. Will NOT use cached data.
+ * @return the result of the validation
+ */
+ KSSLValidation revalidate();
+
+ /**
+ * Check if this is a valid certificate. Will NOT use cached data.
+ * @param p the purpose to validate for
+ * @return the result of the validation
+ */
+ KSSLValidation revalidate(KSSLPurpose p);
+
+ /**
+ * Get a reference to the certificate chain.
+ * @return reference to the chain
+ */
+ KSSLCertChain& chain();
+
+ /**
+ * Obtain the localized message that corresponds to a validation result.
+ * @param x the code to look up
+ * @return the message text corresponding to the validation code
+ */
+ static TQString verifyText(KSSLValidation x);
+
+ /**
+ * Explicitly make a copy of this certificate.
+ * @return a copy of the certificate
+ */
+ KSSLCertificate *replicate();
+
+ /**
+ * Copy constructor. Beware, this is very expensive.
+ * @param x the object to copy from
+ */
+ KSSLCertificate(const KSSLCertificate& x); // copy constructor
+
+ /**
+ * Re-set the certificate from a base64 string.
+ * @param cert the certificate to set to
+ * @return true on success
+ */
+ bool setCert(TQString& cert);
+
+ /**
+ * Access the X.509v3 parameters.
+ * @return reference to the extension object
+ * @see KSSLX509V3
+ */
+ KSSLX509V3& x509V3Extensions();
+
+ /**
+ * Check if this is a signer certificate.
+ * @return true if this is a signer certificate
+ */
+ bool isSigner();
+
+ /**
+ * FIXME: document
+ */
+ void getEmails(TQStringList& to) const;
+
+ /**
+ * KDEKey is a concatenation "Subject (MD5)", mostly needed for SMIME.
+ * The result of getKDEKey might change and should not be used for
+ * persistant storage.
+ */
+ TQString getKDEKey() const;
+
+ /**
+ * Aegypten semantics force us to search by MD5Digest only.
+ */
+ static TQString getMD5DigestFromKDEKey(const TQString& k);
+
+private:
+ TDEIO_EXPORT friend int operator!=(KSSLCertificate& x, KSSLCertificate& y);
+ TDEIO_EXPORT friend int operator==(KSSLCertificate& x, KSSLCertificate& y);
+
+ KSSLCertificatePrivate *d;
+ int purposeToOpenSSL(KSSLPurpose p) const;
+
+protected:
+ KSSLCertificate();
+
+ void setCert(X509 *c);
+ void setChain(void *c);
+ X509 *getCert();
+ KSSLValidation processError(int ec);
+};
+
+TDEIO_EXPORT TQDataStream& operator<<(TQDataStream& s, const KSSLCertificate& r);
+TDEIO_EXPORT TQDataStream& operator>>(TQDataStream& s, KSSLCertificate& r);
+
+TDEIO_EXPORT int operator==(KSSLCertificate& x, KSSLCertificate& y);
+TDEIO_EXPORT inline int operator!=(KSSLCertificate& x, KSSLCertificate& y)
+{ return !(x == y); }
+
+#endif
+
diff --git a/tdeio/kssl/ksslcertificatecache.cc b/tdeio/kssl/ksslcertificatecache.cc
new file mode 100644
index 000000000..2eecd66d6
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatecache.cc
@@ -0,0 +1,399 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000, 2001 George Staikos <staikos@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 "ksslcertificatecache.h"
+#include "ksslcertchain.h"
+#include "ksslcertificate.h"
+
+#include <stdlib.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kdatastream.h>
+
+
+class KSSLCertificateCache::KSSLCertificateCachePrivate {
+ public:
+ DCOPClient *dcc;
+
+ KSSLCertificateCachePrivate() { dcc = new DCOPClient; dcc->attach(); }
+ ~KSSLCertificateCachePrivate() { delete dcc;}
+
+};
+
+
+
+KSSLCertificateCache::KSSLCertificateCache() {
+ d = new KSSLCertificateCachePrivate;
+}
+
+
+KSSLCertificateCache::~KSSLCertificateCache() {
+ delete d;
+}
+
+
+void KSSLCertificateCache::saveToDisk() {
+ kdDebug() << "Deprecated function KSSLCertificateCache::saveToDisk() called" << endl;
+}
+
+
+void KSSLCertificateCache::clearList() {
+ kdDebug() << "Deprecated function KSSLCertificateCache::clearList() called" << endl;
+}
+
+
+void KSSLCertificateCache::loadDefaultPolicies() {
+ kdDebug() << "Deprecated function KSSLCertificateCache::loadDefaultPolicies() called" << endl;
+}
+
+
+void KSSLCertificateCache::reload() {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ d->dcc->call("kded", "kssld",
+ "cacheReload()",
+ data, rettype, retval);
+}
+
+
+void KSSLCertificateCache::addCertificate(KSSLCertificate& cert,
+ KSSLCertificatePolicy policy, bool permanent) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ arg << policy;
+ arg << permanent;
+ d->dcc->call("kded", "kssld",
+ "cacheAddCertificate(KSSLCertificate,KSSLCertificateCache::KSSLCertificatePolicy,bool)",
+ data, rettype, retval);
+}
+
+
+// KDE 4: Make it const TQString &
+KSSLCertificateCache::KSSLCertificatePolicy KSSLCertificateCache::getPolicyByCN(TQString& cn) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cn;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheGetPolicyByCN(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "KSSLCertificateCache::KSSLCertificatePolicy") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ KSSLCertificateCache::KSSLCertificatePolicy drc;
+ retStream >> drc;
+ return drc;
+ }
+return KSSLCertificateCache::Ambiguous;
+}
+
+
+KSSLCertificateCache::KSSLCertificatePolicy KSSLCertificateCache::getPolicyByCertificate(KSSLCertificate& cert) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheGetPolicyByCertificate(KSSLCertificate)",
+ data, rettype, retval);
+
+ if (rc && rettype == "KSSLCertificateCache::KSSLCertificatePolicy") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ KSSLCertificateCache::KSSLCertificatePolicy drc;
+ retStream >> drc;
+ return drc;
+ }
+return KSSLCertificateCache::Ambiguous;
+}
+
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificateCache::seenCN(TQString& cn) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cn;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheSeenCN(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLCertificateCache::seenCertificate(KSSLCertificate& cert) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheSeenCertificate(KSSLCertificate)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLCertificateCache::isPermanent(KSSLCertificate& cert) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheIsPermanent(KSSLCertificate)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificateCache::removeByCN(TQString& cn) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cn;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheRemoveByCN(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLCertificateCache::removeByCertificate(KSSLCertificate& cert) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheRemoveByCertificate(KSSLCertificate)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificateCache::modifyByCN(TQString& cn,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime& expires) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cn << policy << permanent << expires;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheModifyByCN(TQString,KSSLCertificateCache::KSSLCertificatePolicy,bool,TQDateTime)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLCertificateCache::modifyByCertificate(KSSLCertificate& cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime& expires) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert << policy << permanent << expires;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheModifyByCertificate(KSSLCertificate,KSSLCertificateCache::KSSLCertificatePolicy,bool,TQDateTime)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+TQStringList KSSLCertificateCache::getHostList(KSSLCertificate& cert) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheGetHostList(KSSLCertificate)",
+ data, rettype, retval);
+
+ if (rc && rettype == TQSTRINGLIST_OBJECT_NAME_STRING) {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ TQStringList drc;
+ retStream >> drc;
+ return drc;
+ }
+return TQStringList();
+}
+
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificateCache::addHost(KSSLCertificate& cert, TQString& host) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert << host;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheAddHost(KSSLCertificate,TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+// KDE 4: Make it const TQString &
+bool KSSLCertificateCache::removeHost(KSSLCertificate& cert, TQString& host) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert << host;
+ bool rc = d->dcc->call("kded", "kssld",
+ "cacheRemoveHost(KSSLCertificate,TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+TQStringList KSSLCertificateCache::getKDEKeyByEmail(const TQString &email) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << email;
+ bool rc = d->dcc->call("kded", "kssld",
+ "getKDEKeyByEmail(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == TQSTRINGLIST_OBJECT_NAME_STRING) {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ TQStringList drc;
+ retStream >> drc;
+ return drc;
+ }
+
+ return TQStringList();
+}
+
+
+KSSLCertificate *KSSLCertificateCache::getCertByMD5Digest(const TQString &key) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << key;
+ bool rc = d->dcc->call("kded", "kssld",
+ "getCertByMD5Digest(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "KSSLCertificate") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ KSSLCertificate *drc = new KSSLCertificate;
+ retStream >> *drc;
+ if (drc->getCert())
+ return drc;
+ delete drc; // should not happen too often if used in conjunction with getKDEKeyByEmail
+ }
+
+ return 0L;
+}
+
+
+TQDataStream& operator<<(TQDataStream& s, const KSSLCertificateCache::KSSLCertificatePolicy& p) {
+ s << (TQ_UINT32)p;
+return s;
+}
+
+
+TQDataStream& operator>>(TQDataStream& s, KSSLCertificateCache::KSSLCertificatePolicy& p) {
+ TQ_UINT32 pd;
+ s >> pd;
+ p = (KSSLCertificateCache::KSSLCertificatePolicy) pd;
+ return s;
+}
+
+
+
+
+
diff --git a/tdeio/kssl/ksslcertificatecache.h b/tdeio/kssl/ksslcertificatecache.h
new file mode 100644
index 000000000..924cb0f54
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatecache.h
@@ -0,0 +1,107 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000, 2001 George Staikos <staikos@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 _INCLUDE_KSSLCCACHE_H
+#define _INCLUDE_KSSLCCACHE_H
+
+class KSSLCertificate;
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdatetime.h>
+
+#include <tdelibs_export.h>
+
+class TDEIO_EXPORT KSSLCertificateCache {
+public:
+
+enum KSSLCertificatePolicy { Unknown, Reject, Accept, Prompt, Ambiguous };
+// Unknown: no policy has been set for this record
+// Reject: user has requested to not accept data from this site
+// Accept: user has requested to always accept data from this site
+// Prompt: user wishes to be prompted before accepting this certificate
+// You may need to set a [non-]permanent policy on this record after
+// the user is prompted.
+// Ambiguous: The state cannot be uniquely determined. Hopefully this
+// doesn't happen.
+
+ KSSLCertificateCache();
+ ~KSSLCertificateCache();
+
+ void addCertificate(KSSLCertificate& cert, KSSLCertificatePolicy policy,
+ bool permanent = true);
+
+ // WARNING! This is not a "secure" method. You need to actually
+ // do a getPolicyByCertificate to be cryptographically sure
+ // that this is an accepted certificate/site pair.
+ // (note that the site (CN) is encoded in the certificate
+ // so you should only accept certificates whose CN matches
+ // the exact FQDN of the site presenting it)
+ // If you're just doing an OpenSSL connection, I believe it
+ // tests this for you, but don't take my word for it.
+ KSSLCertificatePolicy getPolicyByCN(TQString& cn);
+
+ KSSLCertificatePolicy getPolicyByCertificate(KSSLCertificate& cert);
+
+ bool seenCN(TQString& cn);
+ bool seenCertificate(KSSLCertificate& cert);
+
+ bool removeByCN(TQString& cn);
+ bool removeByCertificate(KSSLCertificate& cert);
+
+ bool isPermanent(KSSLCertificate& cert);
+
+ bool modifyByCN(TQString& cn,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime& expires);
+
+ bool modifyByCertificate(KSSLCertificate& cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime& expires);
+
+ TQStringList getHostList(KSSLCertificate& cert);
+ bool addHost(KSSLCertificate& cert, TQString& host);
+ bool removeHost(KSSLCertificate& cert, TQString& host);
+
+ // SMIME
+ TQStringList getKDEKeyByEmail(const TQString &email);
+ KSSLCertificate *getCertByMD5Digest(const TQString &key);
+
+ void reload();
+
+ // You shouldn't need to call this but in some weird circumstances
+ // it might be necessary.
+ void saveToDisk();
+
+private:
+ class KSSLCertificateCachePrivate;
+ KSSLCertificateCachePrivate *d;
+
+ void loadDefaultPolicies();
+ void clearList();
+
+};
+
+
+TDEIO_EXPORT TQDataStream& operator<<(TQDataStream& s, const KSSLCertificateCache::KSSLCertificatePolicy& p);
+TDEIO_EXPORT TQDataStream& operator>>(TQDataStream& s, KSSLCertificateCache::KSSLCertificatePolicy& p);
+
+#endif
diff --git a/tdeio/kssl/ksslcertificatefactory.cc b/tdeio/kssl/ksslcertificatefactory.cc
new file mode 100644
index 000000000..66e272ced
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatefactory.cc
@@ -0,0 +1,122 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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 <ksslcertificatefactory.h>
+#include <ksslcertificate.h>
+#include <stdlib.h>
+
+//#include <kopenssl.h>
+
+KSSLCertificate*
+KSSLCertificateFactory::generateSelfSigned(KSSLKeyType /*keytype*/) {
+#if 0
+ //#ifdef KSSL_HAVE_SSL
+ X509_NAME *x509name = X509_NAME_new();
+ X509 *x509;
+ ASN1_UTCTIME *beforeafter;
+ KSSLCertificate *newcert;
+ int rc;
+
+ // FIXME: generate the private key
+ if (keytype == KEYTYPE_UNKNOWN || (key=EVP_PKEY_new()) == NULL) {
+ X509_NAME_free(x509name);
+ return NULL;
+ }
+
+ switch(keytype) {
+ case KEYTYPE_RSA:
+ if (!EVP_PKEY_assign_RSA(key, RSA_generate_key(newkey,0x10001,
+ req_cb,bio_err))) {
+
+ }
+ break;
+ case KEYTYPE_DSA:
+ if (!DSA_generate_key(dsa_params)) goto end;
+ if (!EVP_PKEY_assign_DSA(pkey,dsa_params)) goto end;
+ dsa_params=NULL;
+ if (pkey->type == EVP_PKEY_DSA)
+ digest=EVP_dss1();
+ break;
+ }
+
+ // FIXME: dn doesn't exist
+ // FIXME: allow the notAfter value to be parameterized
+ // FIXME: allow a password to lock the key with
+
+ // Fill in the certificate
+ X509_NAME_add_entry_by_NID(x509name, OBJ_txt2nid("CN"), 0x1001,
+ (unsigned char *) dn, -1, -1, 0);
+
+ x509 = X509_new();
+ rc = X509_set_issuer_name(x509, x509name);
+ if (rc != 0) {
+ X509_free(x509);
+ X509_NAME_free(x509name);
+ return NULL;
+ }
+ rc = X509_set_subject_name(x509, x509name);
+ if (rc != 0) {
+ X509_free(x509);
+ X509_NAME_free(x509name);
+ return NULL;
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(*x509), 0);
+
+ X509_NAME_free(x509name);
+
+ // Make it a 1 year certificate
+ beforeafter = ASN1_UTCTIME_new();
+ if (!X509_gmtime_adj(beforeafter, -60*60*24)) { // yesterday
+ X509_free(x509);
+ return NULL;
+ }
+ if (!X509_set_notBefore(x509, beforeafter)) {
+ X509_free(x509);
+ return NULL;
+ }
+ if (!X509_gmtime_adj(beforeafter, 60*60*24*364)) { // a year from yesterday
+ X509_free(x509);
+ return NULL;
+ }
+ if (!X509_set_notAfter(x509, beforeafter)) {
+ X509_free(x509);
+ return NULL;
+ }
+ ASN1_UTCTIME_free(beforeafter);
+
+ if (!X509_set_pubkey(x509, key)) {
+ X509_free(x509);
+ return NULL;
+ }
+
+ rc = X509_sign(x509, key, EVP_sha1());
+ if (rc != 0) {
+ X509_free(x509);
+ return NULL;
+ }
+
+ newCert = new KSSLCertificate;
+ newCert->setCert(x509);
+ return newCert;
+#else
+ return NULL;
+#endif
+}
+
diff --git a/tdeio/kssl/ksslcertificatefactory.h b/tdeio/kssl/ksslcertificatefactory.h
new file mode 100644
index 000000000..503c591a7
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatefactory.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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.
+ */
+
+// WARNING: THIS CODE IS INCOMPLETE AND MAY CHANGE WITHOUT NOTICE
+
+#ifndef _KSSLCERTIFICATEFACTORY_H
+#define _KSSLCERTIFICATEFACTORY_H
+
+#include <tdelibs_export.h>
+
+class KSSLCertificate;
+
+typedef enum {KEYTYPE_UNKNOWN, KEYTYPE_RSA, KEYTYPE_DSA} KSSLKeyType;
+
+class TDEIO_EXPORT KSSLCertificateFactory {
+
+public:
+
+ static KSSLCertificate* generateSelfSigned(KSSLKeyType keytype);
+ // static KSSLCertificate* generateSigned();
+ // static bool generateRequest();
+
+private:
+
+ class KSSLCertificateFactoryPrivate;
+ KSSLCertificateFactoryPrivate *d;
+
+protected:
+
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksslcertificatehome.cc b/tdeio/kssl/ksslcertificatehome.cc
new file mode 100644
index 000000000..39470c5ab
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatehome.cc
@@ -0,0 +1,246 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2005 George Staikos <staikos@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 <ksslcertificatehome.h>
+#include <ksslcertificate.h>
+#include <ksslpkcs12.h>
+
+#include <kresolver.h>
+#include <ksimpleconfig.h>
+
+using namespace KNetwork;
+
+TQStringList KSSLCertificateHome::getCertificateList() {
+KSimpleConfig cfg("ksslcertificates", false);
+TQStringList list = cfg.groupList();
+TQString defaultstr("<default>");
+TQString blankstr("");
+
+list.remove(defaultstr);
+list.remove(blankstr);
+
+return list;
+}
+
+
+// KDE 4: make it const TQString &
+void KSSLCertificateHome::setDefaultCertificate(TQString name, TQString host, bool send, bool prompt) {
+KSimpleConfig cfg("ksslauthmap", false);
+
+#ifdef Q_WS_WIN //temporary
+ cfg.setGroup(host);
+#else
+ cfg.setGroup(KResolver::domainToAscii(host));
+#endif
+ cfg.writeEntry("certificate", name);
+ cfg.writeEntry("send", send);
+ cfg.writeEntry("prompt", prompt);
+ cfg.sync();
+}
+
+
+// KDE 4: make it const TQString &
+void KSSLCertificateHome::setDefaultCertificate(KSSLPKCS12 *cert, TQString host, bool send, bool prompt) {
+ if (cert)
+ KSSLCertificateHome::setDefaultCertificate(cert->name(), host, send, prompt);
+}
+
+
+// KDE 4: make it const TQString &
+bool KSSLCertificateHome::addCertificate(TQString filename, TQString password, bool storePass) {
+KSSLPKCS12 *pkcs = KSSLPKCS12::loadCertFile(filename, password);
+
+ if (!pkcs) return false;
+
+ KSSLCertificateHome::addCertificate(pkcs, storePass?password:TQString(""));
+ delete pkcs;
+
+return true;
+}
+
+
+// KDE 4: make it const TQString &
+bool KSSLCertificateHome::addCertificate(KSSLPKCS12 *cert, TQString passToStore) {
+ if (!cert) return false;
+
+KSimpleConfig cfg("ksslcertificates", false);
+
+ cfg.setGroup(cert->name());
+ cfg.writeEntry("PKCS12Base64", cert->toString());
+ cfg.writeEntry("Password", passToStore);
+ cfg.sync();
+return true;
+}
+
+bool KSSLCertificateHome::deleteCertificate(const TQString &filename, const TQString &password) {
+KSSLPKCS12 *pkcs = KSSLPKCS12::loadCertFile(filename, password);
+
+ if (!pkcs) return false;
+
+ bool ok = deleteCertificate(pkcs);
+ delete pkcs;
+
+return ok;
+}
+
+bool KSSLCertificateHome::deleteCertificate(KSSLPKCS12 *cert) {
+ if (!cert) return false;
+
+ return deleteCertificateByName(cert->name());
+}
+
+bool KSSLCertificateHome::deleteCertificateByName(const TQString &name) {
+ if (name.isEmpty()) return false;
+
+KSimpleConfig cfg("ksslcertificates", false);
+
+ bool ok = cfg.deleteGroup(name);
+ cfg.sync();
+
+return ok;
+}
+
+// KDE 4: make it const TQString &
+KSSLPKCS12* KSSLCertificateHome::getCertificateByName(TQString name, TQString password) {
+KSimpleConfig cfg("ksslcertificates", false);
+ if (!cfg.hasGroup(name)) return NULL;
+
+ cfg.setGroup(name);
+
+ return KSSLPKCS12::fromString(cfg.readEntry("PKCS12Base64", ""), password);
+}
+
+
+// KDE 4: make it const TQString &
+KSSLPKCS12* KSSLCertificateHome::getCertificateByName(TQString name) {
+KSimpleConfig cfg("ksslcertificates", false);
+ if (!cfg.hasGroup(name)) return NULL;
+
+ cfg.setGroup(name);
+
+ return KSSLPKCS12::fromString(cfg.readEntry("PKCS12Base64", ""), cfg.readEntry("Password", ""));
+}
+
+
+// KDE 4: make it const TQString &
+bool KSSLCertificateHome::hasCertificateByName(TQString name) {
+KSimpleConfig cfg("ksslcertificates", false);
+ if (!cfg.hasGroup(name)) return false;
+ return true;
+}
+
+// KDE 4: make it const TQString &
+KSSLPKCS12* KSSLCertificateHome::getCertificateByHost(TQString host, TQString password, KSSLAuthAction *aa) {
+ return KSSLCertificateHome::getCertificateByName(KSSLCertificateHome::getDefaultCertificateName(host, aa), password);
+}
+
+
+// KDE 4: make it const TQString &
+TQString KSSLCertificateHome::getDefaultCertificateName(TQString host, KSSLAuthAction *aa) {
+KSimpleConfig cfg("ksslauthmap", false);
+
+#ifdef Q_WS_WIN //temporary
+ if (!cfg.hasGroup(host)) {
+#else
+ if (!cfg.hasGroup(KResolver::domainToAscii(host))) {
+#endif
+ if (aa) *aa = AuthNone;
+ return TQString::null;
+ } else {
+#ifdef Q_WS_WIN //temporary
+ cfg.setGroup(host);
+#else
+ cfg.setGroup(KResolver::domainToAscii(host));
+#endif
+ if (aa) {
+ bool tmp = cfg.readBoolEntry("send", false);
+ *aa = AuthSend;
+ if (!tmp) {
+ tmp = cfg.readBoolEntry("prompt", false);
+ *aa = AuthPrompt;
+ if (!tmp) {
+ *aa = AuthDont;
+ }
+ }
+ }
+ return cfg.readEntry("certificate", "");
+ }
+}
+
+
+TQString KSSLCertificateHome::getDefaultCertificateName(KSSLAuthAction *aa) {
+TDEConfig cfg("cryptodefaults", false);
+
+ cfg.setGroup("Auth");
+ if (aa) {
+ TQString am = cfg.readEntry("AuthMethod", "");
+ if (am == "send")
+ *aa = AuthSend;
+ else if (am == "prompt")
+ *aa = AuthPrompt;
+ else
+ *aa = AuthDont;
+ }
+
+return cfg.readEntry("DefaultCert", "");
+}
+
+
+// KDE 4: make it const TQString &
+KSSLPKCS12* KSSLCertificateHome::getDefaultCertificate(TQString password, KSSLAuthAction *aa) {
+TQString name = KSSLCertificateHome::getDefaultCertificateName(aa);
+KSimpleConfig cfg("ksslcertificates", false);
+
+ if (name.isEmpty()) return NULL;
+
+ cfg.setGroup(name);
+ return KSSLPKCS12::fromString(cfg.readEntry("PKCS12Base64", ""), password);
+}
+
+
+
+KSSLPKCS12* KSSLCertificateHome::getDefaultCertificate(KSSLAuthAction *aa) {
+TQString name = KSSLCertificateHome::getDefaultCertificateName(aa);
+KSimpleConfig cfg("ksslcertificates", false);
+
+ if (name.isEmpty()) return NULL;
+
+ cfg.setGroup(name);
+ return KSSLPKCS12::fromString(cfg.readEntry("PKCS12Base64", ""),
+ cfg.readEntry("Password", ""));
+}
+
+
+// KDE 4: make it const TQString &
+void KSSLCertificateHome::setDefaultCertificate(TQString name, bool send, bool prompt) {
+KSimpleConfig cfg("ksslauthmap", false);
+
+ cfg.setGroup("<default>");
+ cfg.writeEntry("defaultCertificate", name);
+ cfg.writeEntry("send", send);
+ cfg.writeEntry("prompt", prompt);
+}
+
+
+void KSSLCertificateHome::setDefaultCertificate(KSSLPKCS12 *cert, bool send, bool prompt) {
+ if (cert)
+ KSSLCertificateHome::setDefaultCertificate(cert->name(), send, prompt);
+}
+
diff --git a/tdeio/kssl/ksslcertificatehome.h b/tdeio/kssl/ksslcertificatehome.h
new file mode 100644
index 000000000..f8a18a423
--- /dev/null
+++ b/tdeio/kssl/ksslcertificatehome.h
@@ -0,0 +1,90 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLCERTIFICATEHOME_H
+#define _KSSLCERTIFICATEHOME_H
+
+class KSSLCertificate;
+class KSSLPKCS12;
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+#include <tdelibs_export.h>
+
+class TDEIO_EXPORT KSSLCertificateHome {
+
+public:
+
+ // AuthNone means there is no policy. AuthDont means _don't_ _send_!!
+ enum KSSLAuthAction {AuthNone, AuthSend, AuthPrompt, AuthDont};
+ /*
+ * These methods might dynamically allocate an object for you. Be sure
+ * to delete them when you are done.
+ */
+ static KSSLPKCS12* getCertificateByHost(TQString host, TQString password, KSSLAuthAction* aa);
+ static KSSLPKCS12* getCertificateByName(TQString name, TQString password);
+ static KSSLPKCS12* getCertificateByName(TQString name);
+ static TQString getDefaultCertificateName(TQString host, KSSLAuthAction *aa = NULL);
+ static TQString getDefaultCertificateName(KSSLAuthAction *aa = NULL);
+ static KSSLPKCS12* getDefaultCertificate(TQString password, KSSLAuthAction *aa = NULL);
+ static KSSLPKCS12* getDefaultCertificate(KSSLAuthAction *aa = NULL);
+ static bool hasCertificateByName(TQString name);
+
+
+ /*
+ * These set the default certificate for hosts without a policy.
+ */
+ static void setDefaultCertificate(TQString name, bool send = true, bool prompt = false);
+ static void setDefaultCertificate(KSSLPKCS12 *cert, bool send = true, bool prompt = false);
+
+
+ /*
+ * These set the default certificate for a host.
+ */
+ static void setDefaultCertificate(TQString name, TQString host, bool send = true, bool prompt = false);
+ static void setDefaultCertificate(KSSLPKCS12 *cert, TQString host, bool send = true, bool prompt = false);
+
+ /*
+ * These add a certificate to the repository.
+ * Returns: true on success, false error
+ */
+ static bool addCertificate(TQString filename, TQString password, bool storePass = false);
+ static bool addCertificate(KSSLPKCS12 *cert, TQString passToStore = TQString::null);
+
+ /*
+ * These deletes a certificate from the repository.
+ * Returns: true on success, false error
+ */
+ static bool deleteCertificate(const TQString &filename, const TQString &password);
+ static bool deleteCertificate(KSSLPKCS12 *cert);
+ static bool deleteCertificateByName(const TQString &name);
+
+ /*
+ * Returns the list of certificates available
+ */
+ static TQStringList getCertificateList();
+
+private:
+ class KSSLCertificateHomePrivate;
+ KSSLCertificateHomePrivate *d;
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksslconfig.h.cmake b/tdeio/kssl/ksslconfig.h.cmake
new file mode 100644
index 000000000..1be6bbba4
--- /dev/null
+++ b/tdeio/kssl/ksslconfig.h.cmake
@@ -0,0 +1,26 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2002 George Staikos <staikos@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 KSSLCONFIG_H
+#define KSSLCONFIG_H
+
+#cmakedefine KSSL_HAVE_SSL 1
+
+#endif
diff --git a/tdeio/kssl/ksslconfig.h.in b/tdeio/kssl/ksslconfig.h.in
new file mode 100644
index 000000000..c078298ec
--- /dev/null
+++ b/tdeio/kssl/ksslconfig.h.in
@@ -0,0 +1,26 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2002 George Staikos <staikos@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 KSSLCONFIG_H
+#define KSSLCONFIG_H
+
+#undef KSSL_HAVE_SSL
+
+#endif
diff --git a/tdeio/kssl/ksslconfig_win.h b/tdeio/kssl/ksslconfig_win.h
new file mode 100644
index 000000000..c078298ec
--- /dev/null
+++ b/tdeio/kssl/ksslconfig_win.h
@@ -0,0 +1,26 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2002 George Staikos <staikos@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 KSSLCONFIG_H
+#define KSSLCONFIG_H
+
+#undef KSSL_HAVE_SSL
+
+#endif
diff --git a/tdeio/kssl/ksslconnectioninfo.cc b/tdeio/kssl/ksslconnectioninfo.cc
new file mode 100644
index 000000000..ccc7fc780
--- /dev/null
+++ b/tdeio/kssl/ksslconnectioninfo.cc
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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 "ksslconnectioninfo.h"
+
+
+KSSLConnectionInfo::KSSLConnectionInfo() {
+ clean();
+}
+
+
+KSSLConnectionInfo::~KSSLConnectionInfo() {
+
+}
+
+
+void KSSLConnectionInfo::clean() {
+ m_iCipherUsedBits = 0;
+ m_iCipherBits = 0;
+ m_cipherName = "";
+}
+
+
+const TQString& KSSLConnectionInfo::getCipherVersion() const {
+ return m_cipherVersion;
+}
+
+
+const TQString& KSSLConnectionInfo::getCipherDescription() const {
+ return m_cipherDescription;
+}
+
+
+const TQString& KSSLConnectionInfo::getCipher() const {
+ return m_cipherName;
+}
+
+
+int KSSLConnectionInfo::getCipherUsedBits() const {
+ return m_iCipherUsedBits;
+}
+
+
+int KSSLConnectionInfo::getCipherBits() const {
+ return m_iCipherBits;
+}
+
+
+
diff --git a/tdeio/kssl/ksslconnectioninfo.h b/tdeio/kssl/ksslconnectioninfo.h
new file mode 100644
index 000000000..09fd5cdae
--- /dev/null
+++ b/tdeio/kssl/ksslconnectioninfo.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLCONNECTIONINFO_H
+#define _KSSLCONNECTIONINFO_H
+
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+class KSSL;
+
+/**
+ * KDE SSL Connection Information
+ *
+ * This class contains the information about an SSL connection. It is
+ * generally referenced through KSSL.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE SSL Connection Information
+ */
+class TDEIO_EXPORT KSSLConnectionInfo {
+friend class KSSL;
+public:
+ /**
+ * Destroy this object.
+ */
+ ~KSSLConnectionInfo();
+
+ /**
+ * Get the cipher in use.
+ * @return the cipher in use
+ */
+ const TQString& getCipher() const;
+
+ /**
+ * Describe the cipher in use.
+ * @return the cipher description (from OpenSSL)
+ */
+ const TQString& getCipherDescription() const;
+
+ /**
+ * Get the version of the cipher in use.
+ * @return the version of the cipher
+ */
+ const TQString& getCipherVersion() const;
+
+ /**
+ * Get the number of bits of the cipher that are actually used.
+ * @return the number of bits in use
+ */
+ int getCipherUsedBits() const;
+
+ /**
+ * Get bit-size of the cipher
+ * @return the number of bits
+ */
+ int getCipherBits() const;
+
+protected:
+ KSSLConnectionInfo();
+ void clean();
+
+ // These are here so KSSL can access them directly
+ // It's just as easy as making accessors - they're friends afterall!
+ int m_iCipherUsedBits, m_iCipherBits;
+ TQString m_cipherName;
+ TQString m_cipherDescription;
+ TQString m_cipherVersion;
+
+private:
+ class KSSLConnectionInfoPrivate;
+ KSSLConnectionInfoPrivate *d;
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksslcsessioncache.cc b/tdeio/kssl/ksslcsessioncache.cc
new file mode 100644
index 000000000..d39638717
--- /dev/null
+++ b/tdeio/kssl/ksslcsessioncache.cc
@@ -0,0 +1,120 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
+ *
+ * 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 <tqpair.h>
+#include <tqstring.h>
+#include <tqptrlist.h>
+
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+#include <kurl.h>
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#include "ksslcsessioncache.h"
+
+/*
+ * Operation:
+ *
+ * Sessions will be stored per running application, not KDE
+ * wide, to avoid security problems with hostile programs
+ * that negotiate sessions with weak cryptographic keys and store
+ * them for everybody to use - I really don't want that.
+ *
+ * Retrieval is organised similiar to George's thoughts in the KSSLD
+ * certificate cache: The cache is organised as a list, with the
+ * recently fetched (or stored) session first.
+ *
+ * The cache has an artificial limit of 32 sessions (should really
+ * be enough), and relies on the peer server for timeouts
+ *
+ */
+#define MAX_ENTRIES 32
+
+#ifdef KSSL_HAVE_SSL
+
+typedef QPair<TQString,TQString> KSSLCSession;
+typedef TQPtrList<KSSLCSession> KSSLCSessions;
+
+static KSSLCSessions *sessions = 0L;
+static KStaticDeleter<KSSLCSessions> med;
+
+
+static TQString URLtoKey(const KURL &kurl) {
+ return kurl.host() + ":" + kurl.protocol() + ":" + TQString::number(kurl.port());
+}
+
+
+static void setup() {
+ KSSLCSessions *ses = new KSSLCSessions;
+ ses->setAutoDelete(true);
+ med.setObject(sessions, ses);
+}
+
+#endif
+
+TQString KSSLCSessionCache::getSessionForURL(const KURL &kurl) {
+#ifdef KSSL_HAVE_SSL
+ if (!sessions) return TQString::null;
+ TQString key = URLtoKey(kurl);
+
+ for(KSSLCSession *it = sessions->first(); it; it=sessions->next()) {
+ if (it->first == key) {
+ sessions->take();
+ sessions->prepend(it);
+ return it->second;
+ }
+ }
+
+ // Negative caching disabled: cache pollution
+#if 0
+ kdDebug(7029) <<"Negative caching " <<key <<endl;
+ if (sessions->count() >= MAX_ENTRIES) sessions->removeLast();
+ sessions->prepend(new KSSLCSession(key, TQString::null));
+#endif
+
+#endif
+ return TQString::null;
+}
+
+
+void KSSLCSessionCache::putSessionForURL(const KURL &kurl, const TQString &session) {
+#ifdef KSSL_HAVE_SSL
+ if (!sessions) setup();
+ TQString key = URLtoKey(kurl);
+ KSSLCSession *it;
+
+ for(it = sessions->first(); it && it->first != key; it=sessions->next());
+
+ if (it) {
+ sessions->take();
+ it->second = session;
+ } else {
+ it = new KSSLCSession(key, session);
+ if (sessions->count() >= MAX_ENTRIES) sessions->removeLast();
+ }
+
+ sessions->prepend(it);
+#endif
+}
diff --git a/tdeio/kssl/ksslcsessioncache.h b/tdeio/kssl/ksslcsessioncache.h
new file mode 100644
index 000000000..9badfe279
--- /dev/null
+++ b/tdeio/kssl/ksslcsessioncache.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
+ *
+ * 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 __KSSLCSESSIONCACHE_H
+#define __KSSLCSESSIONCACHE_H
+
+#include <tdelibs_export.h>
+
+class KURL;
+class TQString;
+
+class TDEIO_EXPORT KSSLCSessionCache {
+ public:
+
+ /**
+ * Store a SSL session (client side only)
+ * @param kurl URL the key belongs to. Method, host and port are used
+ * @param session TQString representing session to store
+ */
+ static void putSessionForURL(const KURL &kurl, const TQString &session);
+
+ /**
+ * Retrieve a SSL session (client side only)
+ * @param kurl URL the key belongs to
+ * @return if a key can be found, TQString::null otherwise
+ */
+ static TQString getSessionForURL(const KURL &kurl);
+};
+
+#endif
diff --git a/tdeio/kssl/kssldefs.h b/tdeio/kssl/kssldefs.h
new file mode 100644
index 000000000..c33664b14
--- /dev/null
+++ b/tdeio/kssl/kssldefs.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 __kssldefs_h
+#define __kssldefs_h
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#ifdef HAVE_OLD_SSL_API
+#define OPENSSL_malloc Malloc
+#define OPENSSL_malloc_locked Malloc_locked
+#define OPENSSL_realloc Realloc
+#define OPENSSL_free Free
+#endif
+
+#endif
+
diff --git a/tdeio/kssl/ksslinfodlg.cc b/tdeio/kssl/ksslinfodlg.cc
new file mode 100644
index 000000000..289c3a8d2
--- /dev/null
+++ b/tdeio/kssl/ksslinfodlg.cc
@@ -0,0 +1,463 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000,2001 George Staikos <staikos@kde.org>
+ * Copyright (C) 2000 Malte Starostik <malte@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 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 "ksslinfodlg.h"
+
+#include <kssl.h>
+
+#include <tqlayout.h>
+#include <kpushbutton.h>
+#include <tqframe.h>
+#include <tqlabel.h>
+#include <tqscrollview.h>
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <ksqueezedtextlabel.h>
+#include <kurllabel.h>
+#include <kstdguiitem.h>
+//#include <kstandarddirs.h>
+//#include <krun.h>
+#include <kcombobox.h>
+#include "ksslcertificate.h"
+#include "ksslcertchain.h"
+#include "ksslsigners.h"
+
+
+class KSSLInfoDlg::KSSLInfoDlgPrivate {
+ private:
+ friend class KSSLInfoDlg;
+ bool m_secCon;
+ TQGridLayout *m_layout;
+ KComboBox *_chain;
+ KSSLCertificate *_cert;
+ KSSLCertificate::KSSLValidationList _cert_ksvl;
+
+ bool inQuestion;
+
+ TQLabel *_serialNum;
+ TQLabel *_csl;
+ TQLabel *_validFrom;
+ TQLabel *_validUntil;
+ TQLabel *_digest;
+
+ TQLabel *pixmap;
+ TQLabel *info;
+
+ KSSLCertBox *_subject, *_issuer;
+};
+
+
+
+KSSLInfoDlg::KSSLInfoDlg(bool secureConnection, TQWidget *parent, const char *name, bool modal)
+ : KDialog(parent, name, modal, (WFlags)TQt::WDestructiveClose), d(new KSSLInfoDlgPrivate) {
+ TQVBoxLayout *topLayout = new TQVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
+ d->m_secCon = secureConnection;
+ d->m_layout = new TQGridLayout(topLayout, 3, 3, KDialog::spacingHint());
+ d->m_layout->setColStretch(1, 1);
+ d->m_layout->setColStretch(2, 1);
+
+ d->pixmap = new TQLabel(this);
+ d->m_layout->addWidget(d->pixmap, 0, 0);
+
+ d->info = new TQLabel(this);
+ d->m_layout->addWidget(d->info, 0, 1);
+
+ if (KSSL::doesSSLWork()) {
+ if (d->m_secCon) {
+ d->pixmap->setPixmap(BarIcon("encrypted"));
+ d->info->setText(i18n("Current connection is secured with SSL."));
+ } else {
+ d->pixmap->setPixmap(BarIcon("decrypted"));
+ d->info->setText(i18n("Current connection is not secured with SSL."));
+ }
+ } else {
+ d->pixmap->setPixmap(BarIcon("decrypted"));
+ d->info->setText(i18n("SSL support is not available in this build of TDE."));
+ }
+ d->m_layout->addRowSpacing( 0, 50 ); // give minimum height to look better
+
+ TQHBoxLayout *buttonLayout = new TQHBoxLayout(topLayout, KDialog::spacingHint());
+ buttonLayout->addStretch( 1 );
+
+ KPushButton *button;
+
+ if (KSSL::doesSSLWork()) {
+ button = new KPushButton(KGuiItem(i18n("C&ryptography Configuration..."),"configure"), this);
+ connect(button, TQT_SIGNAL(clicked()), TQT_SLOT(launchConfig()));
+ buttonLayout->addWidget( button );
+ }
+
+ button = new KPushButton(KStdGuiItem::close(), this);
+ connect(button, TQT_SIGNAL(clicked()), TQT_SLOT(close()));
+ buttonLayout->addWidget( button );
+
+ button->setFocus();
+
+ setCaption(i18n("TDE SSL Information"));
+ d->inQuestion = false;
+ }
+
+
+KSSLInfoDlg::~KSSLInfoDlg() {
+ delete d;
+}
+
+void KSSLInfoDlg::launchConfig() {
+ TDEProcess p;
+ p << "tdecmshell" << "crypto";
+ p.start(TDEProcess::DontCare);
+}
+
+
+void KSSLInfoDlg::setSecurityInQuestion(bool isIt) {
+ d->inQuestion = isIt;
+ if (KSSL::doesSSLWork())
+ if (isIt) {
+ d->pixmap->setPixmap(BarIcon("halfencrypted"));
+ if (d->m_secCon) {
+ d->info->setText(i18n("The main part of this document is secured with SSL, but some parts are not."));
+ } else {
+ d->info->setText(i18n("Some of this document is secured with SSL, but the main part is not."));
+ }
+ } else {
+ if (d->m_secCon) {
+ d->pixmap->setPixmap(BarIcon("encrypted"));
+ d->info->setText(i18n("Current connection is secured with SSL."));
+ } else {
+ d->pixmap->setPixmap(BarIcon("decrypted"));
+ d->info->setText(i18n("Current connection is not secured with SSL."));
+ }
+ }
+}
+
+
+void KSSLInfoDlg::setup( KSSL & ssl, const TQString & ip, const TQString & url )
+{
+ setup(
+ &ssl.peerInfo().getPeerCertificate(),
+ ip,
+ url,
+ ssl.connectionInfo().getCipher(),
+ ssl.connectionInfo().getCipherDescription(),
+ ssl.connectionInfo().getCipherVersion(),
+ ssl.connectionInfo().getCipherUsedBits(),
+ ssl.connectionInfo().getCipherBits(),
+ ssl.peerInfo().getPeerCertificate().validate()
+ );
+}
+
+void KSSLInfoDlg::setup(KSSLCertificate *cert,
+ const TQString& ip, const TQString& url,
+ const TQString& cipher, const TQString& cipherdesc,
+ const TQString& sslversion, int usedbits, int bits,
+ KSSLCertificate::KSSLValidation /*certState*/) {
+ // Needed to put the GUI stuff here to get the layouting right
+
+ d->_cert = cert;
+
+ TQGridLayout *layout = new TQGridLayout(4, 2, KDialog::spacingHint());
+
+ layout->addWidget(new TQLabel(i18n("Chain:"), this), 0, 0);
+ d->_chain = new KComboBox(this);
+ layout->addMultiCellWidget(d->_chain, 1, 1, 0, 1);
+ connect(d->_chain, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotChain(int)));
+
+ d->_chain->clear();
+
+ if (cert->chain().isValid() && cert->chain().depth() > 1) {
+ d->_chain->setEnabled(true);
+ d->_chain->insertItem(i18n("0 - Site Certificate"));
+ int cnt = 0;
+ TQPtrList<KSSLCertificate> cl = cert->chain().getChain();
+ cl.setAutoDelete(true);
+ for (KSSLCertificate *c = cl.first(); c != 0; c = cl.next()) {
+ KSSLX509Map map(c->getSubject());
+ TQString id;
+ id = map.getValue("CN");
+ if (id.length() == 0)
+ id = map.getValue("O");
+ if (id.length() == 0)
+ id = map.getValue("OU");
+ d->_chain->insertItem(TQString::number(++cnt)+" - "+id);
+ }
+ d->_chain->setCurrentItem(0);
+ } else d->_chain->setEnabled(false);
+
+ layout->addWidget(new TQLabel(i18n("Peer certificate:"), this), 2, 0);
+ layout->addWidget(d->_subject = static_cast<KSSLCertBox*>(buildCertInfo(cert->getSubject())), 3, 0);
+ layout->addWidget(new TQLabel(i18n("Issuer:"), this), 2, 1);
+ layout->addWidget(d->_issuer = static_cast<KSSLCertBox*>(buildCertInfo(cert->getIssuer())), 3, 1);
+ d->m_layout->addMultiCell(layout, 1, 1, 0, 2);
+
+ layout = new TQGridLayout(11, 2, KDialog::spacingHint());
+ layout->setColStretch(1, 1);
+ TQLabel *ipl = new TQLabel(i18n("IP address:"), this);
+ layout->addWidget(ipl, 0, 0);
+ if (ip.isEmpty()) {
+ ipl->hide();
+ }
+ layout->addWidget(ipl = new TQLabel(ip, this), 0, 1);
+ if (ip.isEmpty()) {
+ ipl->hide();
+ }
+ layout->addWidget(new TQLabel(i18n("URL:"), this), 1, 0);
+ KSqueezedTextLabel *urlLabel = new KSqueezedTextLabel(url, this);
+ layout->addWidget(urlLabel, 1, 1);
+ layout->addWidget(new TQLabel(i18n("Certificate state:"), this), 2, 0);
+
+ layout->addWidget(d->_csl = new TQLabel("", this), 2, 1);
+
+ update();
+
+ layout->addWidget(new TQLabel(i18n("Valid from:"), this), 3, 0);
+ layout->addWidget(d->_validFrom = new TQLabel("", this), 3, 1);
+ layout->addWidget(new TQLabel(i18n("Valid until:"), this), 4, 0);
+ layout->addWidget(d->_validUntil = new TQLabel("", this), 4, 1);
+
+ layout->addWidget(new TQLabel(i18n("Serial number:"), this), 5, 0);
+ layout->addWidget(d->_serialNum = new TQLabel("", this), 5, 1);
+ layout->addWidget(new TQLabel(i18n("MD5 digest:"), this), 6, 0);
+ layout->addWidget(d->_digest = new TQLabel("", this), 6, 1);
+
+ layout->addWidget(new TQLabel(i18n("Cipher in use:"), this), 7, 0);
+ layout->addWidget(new TQLabel(cipher, this), 7, 1);
+ layout->addWidget(new TQLabel(i18n("Details:"), this), 8, 0);
+ layout->addWidget(new TQLabel(cipherdesc.simplifyWhiteSpace(), this), 8, 1);
+ layout->addWidget(new TQLabel(i18n("SSL version:"), this), 9, 0);
+ layout->addWidget(new TQLabel(sslversion, this), 9, 1);
+ layout->addWidget(new TQLabel(i18n("Cipher strength:"), this), 10, 0);
+ layout->addWidget(new TQLabel(i18n("%1 bits used of a %2 bit cipher").arg(usedbits).arg(bits), this), 10, 1);
+ d->m_layout->addMultiCell(layout, 2, 2, 0, 2);
+
+ displayCert(cert);
+}
+
+void KSSLInfoDlg::setCertState(const TQString &errorNrs)
+{
+ d->_cert_ksvl.clear();
+ TQStringList errors = TQStringList::split(':', errorNrs);
+ for(TQStringList::ConstIterator it = errors.begin();
+ it != errors.end(); ++it)
+ {
+ d->_cert_ksvl << (KSSLCertificate::KSSLValidation) (*it).toInt();
+ }
+}
+
+void KSSLInfoDlg::displayCert(KSSLCertificate *x) {
+ TQPalette cspl;
+
+ d->_serialNum->setText(x->getSerialNumber());
+
+ cspl = d->_validFrom->palette();
+ if (x->getQDTNotBefore() > TQDateTime::currentDateTime(Qt::UTC))
+ cspl.setColor(TQColorGroup::Foreground, TQColor(196,33,21));
+ else cspl.setColor(TQColorGroup::Foreground, TQColor(42,153,59));
+ d->_validFrom->setPalette(cspl);
+ d->_validFrom->setText(x->getNotBefore());
+
+ cspl = d->_validUntil->palette();
+ if (x->getQDTNotAfter() < TQDateTime::currentDateTime(Qt::UTC))
+ cspl.setColor(TQColorGroup::Foreground, TQColor(196,33,21));
+ else cspl.setColor(TQColorGroup::Foreground, TQColor(42,153,59));
+ d->_validUntil->setPalette(cspl);
+ d->_validUntil->setText(x->getNotAfter());
+
+ cspl = palette();
+
+ KSSLCertificate::KSSLValidation ksv;
+ KSSLCertificate::KSSLValidationList ksvl;
+ if ((x == d->_cert) && !d->_cert_ksvl.isEmpty()) {
+ ksvl = d->_cert_ksvl;
+ ksv = ksvl.first();
+ } else {
+ if (x == d->_cert)
+ ksvl = d->_cert->validateVerbose(KSSLCertificate::SSLServer);
+ else
+ ksvl = d->_cert->validateVerbose(KSSLCertificate::SSLServer, x);
+
+ if (ksvl.isEmpty())
+ ksvl << KSSLCertificate::Ok;
+
+ ksv = ksvl.first();
+
+ if (ksv == KSSLCertificate::SelfSigned) {
+ if (x->getQDTNotAfter() > TQDateTime::currentDateTime(Qt::UTC) &&
+ x->getQDTNotBefore() < TQDateTime::currentDateTime(Qt::UTC)) {
+ if (KSSLSigners().useForSSL(*x))
+ ksv = KSSLCertificate::Ok;
+ } else {
+ ksv = KSSLCertificate::Expired;
+ }
+ }
+ }
+
+ if (ksv == KSSLCertificate::Ok) {
+ cspl.setColor(TQColorGroup::Foreground, TQColor(42,153,59));
+ } else if (ksv != KSSLCertificate::Irrelevant) {
+ cspl.setColor(TQColorGroup::Foreground, TQColor(196,33,21));
+ }
+ d->_csl->setPalette(cspl);
+
+ TQString errorStr;
+ for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
+ it != ksvl.end(); ++it) {
+ if (!errorStr.isEmpty())
+ errorStr.append('\n');
+ errorStr += KSSLCertificate::verifyText(*it);
+ }
+
+ d->_csl->setText(errorStr);
+ d->_csl->setMinimumSize(d->_csl->sizeHint());
+
+ d->_subject->setValues(x->getSubject());
+ d->_issuer->setValues(x->getIssuer());
+
+ d->_digest->setText(x->getMD5DigestText());
+}
+
+
+void KSSLInfoDlg::slotChain(int x) {
+ if (x == 0) {
+ displayCert(d->_cert);
+ } else {
+ TQPtrList<KSSLCertificate> cl = d->_cert->chain().getChain();
+ cl.setAutoDelete(true);
+ for (int i = 0; i < x-1; i++)
+ cl.remove((unsigned int)0);
+ KSSLCertificate thisCert = *(cl.at(0));
+ cl.remove((unsigned int)0);
+ thisCert.chain().setChain(cl);
+ displayCert(&thisCert);
+ }
+}
+
+
+KSSLCertBox *KSSLInfoDlg::certInfoWidget(TQWidget *parent, const TQString &certName, TQWidget *mailCatcher) {
+ KSSLCertBox *result = new KSSLCertBox(parent);
+ if (!certName.isEmpty()) {
+ result->setValues(certName, mailCatcher);
+ }
+ return result;
+}
+
+
+KSSLCertBox::KSSLCertBox(TQWidget *parent, const char *name, WFlags f)
+: TQScrollView(parent, name, f)
+{
+ _frame = 0L;
+ setBackgroundMode(TQWidget::PaletteButton);
+ setValues(TQString::null, 0L);
+}
+
+
+void KSSLCertBox::setValues(TQString certName, TQWidget *mailCatcher) {
+ if (_frame) {
+ removeChild(_frame);
+ delete _frame;
+ }
+
+ if (certName.isEmpty()) {
+ _frame = new TQFrame(this);
+ addChild(_frame);
+ viewport()->setBackgroundMode(_frame->backgroundMode());
+ _frame->show();
+ updateScrollBars();
+ show();
+ return;
+ }
+
+ KSSLX509Map cert(certName);
+ TQString tmp;
+ viewport()->setBackgroundMode(TQWidget::PaletteButton);
+ _frame = new TQFrame(this);
+ TQGridLayout *grid = new TQGridLayout(_frame, 1, 2, KDialog::marginHint(), KDialog::spacingHint());
+ grid->setAutoAdd(true);
+ TQLabel *label = 0L;
+ if (!(tmp = cert.getValue("O")).isEmpty()) {
+ label = new TQLabel(i18n("Organization:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("OU")).isEmpty()) {
+ label = new TQLabel(i18n("Organizational unit:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("L")).isEmpty()) {
+ label = new TQLabel(i18n("Locality:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("ST")).isEmpty()) {
+ label = new TQLabel(i18n("Federal State","State:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("C")).isEmpty()) {
+ label = new TQLabel(i18n("Country:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("CN")).isEmpty()) {
+ label = new TQLabel(i18n("Common name:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ new TQLabel(tmp, _frame);
+ }
+ if (!(tmp = cert.getValue("Email")).isEmpty()) {
+ label = new TQLabel(i18n("Email:"), _frame);
+ label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ if (mailCatcher) {
+ KURLLabel *mail = new KURLLabel(tmp, tmp, _frame);
+ connect(mail, TQT_SIGNAL(leftClickedURL(const TQString &)), mailCatcher, TQT_SLOT(mailClicked(const TQString &)));
+ } else {
+ label = new TQLabel(tmp, _frame);
+ }
+ }
+ if (label && viewport()) {
+ viewport()->setBackgroundMode(label->backgroundMode());
+ }
+ addChild(_frame);
+ updateScrollBars();
+ _frame->show();
+ show();
+}
+
+
+TQScrollView *KSSLInfoDlg::buildCertInfo(const TQString &certName) {
+ return KSSLInfoDlg::certInfoWidget(this, certName, this);
+}
+
+void KSSLInfoDlg::urlClicked(const TQString &url) {
+ kapp->invokeBrowser(url);
+}
+
+void KSSLInfoDlg::mailClicked(const TQString &url) {
+ kapp->invokeMailer(url, TQString::null);
+}
+
+#include "ksslinfodlg.moc"
+// vim: ts=4 sw=4 et
diff --git a/tdeio/kssl/ksslinfodlg.h b/tdeio/kssl/ksslinfodlg.h
new file mode 100644
index 000000000..c73afbba1
--- /dev/null
+++ b/tdeio/kssl/ksslinfodlg.h
@@ -0,0 +1,173 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
+ * Copyright (C) 2000 Malte Starostik <malte@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 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 _KSSLINFODLG_H
+#define _KSSLINFODLG_H
+
+#include <kdialog.h>
+
+#include "ksslx509map.h"
+#include "ksslcertificate.h"
+#include "kssl.h"
+#include <tqscrollview.h>
+
+class TQWidget;
+class KSSLCertBox;
+class KSSLCertChain;
+
+
+/**
+ * KDE SSL Information Dialog
+ *
+ * This class creates a dialog that can be used to display information about
+ * an SSL session.
+ *
+ * There are NO GUARANTEES that KSSLInfoDlg will remain binary compatible/
+ * Contact staikos@kde.org for details if needed.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE SSL Information Dialog
+ */
+class TDEIO_EXPORT KSSLInfoDlg : public KDialog {
+ Q_OBJECT
+public:
+ /**
+ * Construct a KSSL Information Dialog
+ *
+ * @param secureConnection true if the connection is secured with SSL
+ * @param parent the parent widget
+ * @param name the internal name of this instance
+ * @param modal true if the dialog should be modal
+ */
+ KSSLInfoDlg(bool secureConnection, TQWidget *parent=0L, const char *name=0L, bool modal=false);
+
+ /**
+ * Destroy this dialog
+ */
+ virtual ~KSSLInfoDlg();
+
+ /**
+ * Tell the dialog if the connection has portions that may not be
+ * secure (ie. a mixture of secure and insecure frames)
+ *
+ * @param isIt true if security is in question
+ */
+ void setSecurityInQuestion(bool isIt);
+
+ /**
+ * Setup the dialog before showing it.
+ *
+ * @param cert the certificate presented by the site
+ * @param ip the ip of the remote host
+ * @param url the url being accessed
+ * @param cipher the cipher in use
+ * @param cipherdesc text description of the cipher in use
+ * @param sslversion the version of SSL in use (SSLv2, SSLv3, TLSv1, etc)
+ * @param usedbits the number of bits in the cipher key being used
+ * @param bits the bit-size of the cipher in use
+ * @param certState the certificate state (valid, invalid, etc)
+ */
+ void setup(KSSLCertificate *cert,
+ const TQString& ip, const TQString& url,
+ const TQString& cipher, const TQString& cipherdesc,
+ const TQString& sslversion, int usedbits, int bits,
+ KSSLCertificate::KSSLValidation certState);
+
+ /**
+ * Setup the dialog before showing it. This is a convenience version
+ * of the above method, and obtains the same information using the
+ * @param ssl parameter instead.
+ *
+ * @param ssl the ssl connection
+ * @param ip the ip of the remote host
+ * @param url the url being accessed
+ */
+ void setup( KSSL & ssl, const TQString & ip, const TQString & url );
+
+ /**
+ * Set the errors that were encountered while validating the site
+ * certificate.
+ */
+ void setCertState(const TQString &errorNrs);
+
+ /**
+ * Utility function to generate the widget which displays the detailed
+ * information about an X.509 certificate.
+ *
+ * @param parent the parent widget
+ * @param certName the name (subject) of the certificate
+ * @param mailCatcher the class which catches click events on e-mail
+ * addresses
+ */
+ static KSSLCertBox *certInfoWidget(TQWidget *parent, const TQString &certName, TQWidget *mailCatcher=0);
+
+private:
+ TQScrollView *buildCertInfo(const TQString &certName);
+ void displayCert(KSSLCertificate *x);
+
+ class KSSLInfoDlgPrivate;
+ KSSLInfoDlgPrivate *d;
+
+private slots:
+ void launchConfig();
+ void urlClicked(const TQString &url);
+ void mailClicked(const TQString &url);
+ void slotChain(int x);
+};
+
+
+/**
+ * KDE SSL Certificate Box
+ *
+ * This class creates a widget which formats and displays the contents of an
+ * SSL X.509 certificate. That is, it takes the "subject" of the certificate
+ * and displays everything contained therein.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSLInfoDlg
+ * @short KDE SSL Certificate Box
+ */
+class TDEIO_EXPORT KSSLCertBox : public TQScrollView {
+public:
+ /**
+ * Construct a certificate box
+ *
+ * @param parent the parent widget
+ * @param name the internal name of this instance
+ * @param f widget flags for the object
+ */
+ KSSLCertBox(TQWidget *parent=0L, const char *name=0L, WFlags f=0);
+
+ /**
+ * Change the contents of the widget
+ *
+ * @param certName the name ("subject") of the certificate
+ * @param mailCatcher the widget which catches the url open events
+ */
+ void setValues(TQString certName, TQWidget *mailCatcher=0L);
+
+private:
+ TQFrame *_frame;
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksslkeygen.cc b/tdeio/kssl/ksslkeygen.cc
new file mode 100644
index 000000000..541c63f02
--- /dev/null
+++ b/tdeio/kssl/ksslkeygen.cc
@@ -0,0 +1,223 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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 "ksslkeygen.h"
+#include "keygenwizard.h"
+#include "keygenwizard2.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kopenssl.h>
+#include <kprogress.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <tdewallet.h>
+
+#include <tqlineedit.h>
+#include <tqpushbutton.h>
+
+#include <assert.h>
+
+
+KSSLKeyGen::KSSLKeyGen(TQWidget *parent, const char *name, bool modal)
+:KWizard(parent,name,modal) {
+ _idx = -1;
+
+#ifdef KSSL_HAVE_SSL
+ page1 = new KGWizardPage1(this, "Wizard Page 1");
+ addPage(page1, i18n("TDE Certificate Request"));
+ page2 = new KGWizardPage2(this, "Wizard Page 2");
+ addPage(page2, i18n("TDE Certificate Request - Password"));
+ setHelpEnabled(page1, false);
+ setHelpEnabled(page2, false);
+ setFinishEnabled(page2, false);
+ connect(page2->_password1, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotPassChanged()));
+ connect(page2->_password2, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotPassChanged()));
+ connect(finishButton(), TQT_SIGNAL(clicked()), TQT_SLOT(slotGenerate()));
+#else
+ // tell him he doesn't have SSL
+#endif
+}
+
+
+KSSLKeyGen::~KSSLKeyGen() {
+
+}
+
+
+void KSSLKeyGen::slotPassChanged() {
+ setFinishEnabled(page2, page2->_password1->text() == page2->_password2->text() && page2->_password1->text().length() >= 4);
+}
+
+
+void KSSLKeyGen::slotGenerate() {
+ assert(_idx >= 0 && _idx <= 3); // for now
+
+
+ // Generate the CSR
+ int bits;
+ switch (_idx) {
+ case 0:
+ bits = 2048;
+ break;
+ case 1:
+ bits = 1024;
+ break;
+ case 2:
+ bits = 768;
+ break;
+ case 3:
+ bits = 512;
+ break;
+ default:
+ KMessageBox::sorry(NULL, i18n("Unsupported key size."), i18n("TDE SSL Information"));
+ return;
+ }
+
+ KProgressDialog *kpd = new KProgressDialog(this, "progress dialog", i18n("TDE"), i18n("Please wait while the encryption keys are generated..."));
+ kpd->progressBar()->setProgress(0);
+ kpd->show();
+ // FIXME - progress dialog won't show this way
+
+ int rc = generateCSR("This CSR" /*FIXME */, page2->_password1->text(), bits, 0x10001 /* This is the traditional exponent used */);
+ kpd->progressBar()->setProgress(100);
+
+#ifndef Q_OS_WIN //TODO: reenable for WIN32
+ if (rc == 0 && KWallet::Wallet::isEnabled()) {
+ rc = KMessageBox::questionYesNo(this, i18n("Do you wish to store the passphrase in your wallet file?"), TQString::null, i18n("Store"), i18n("Do Not Store"));
+ if (rc == KMessageBox::Yes) {
+ KWallet::Wallet *w = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), winId());
+ if (w) {
+ // FIXME: store passphrase in wallet
+ delete w;
+ }
+ }
+ }
+#endif
+
+ kpd->deleteLater();
+}
+
+
+int KSSLKeyGen::generateCSR(const TQString& name, const TQString& pass, int bits, int e) {
+#ifdef KSSL_HAVE_SSL
+ KOSSL *kossl = KOSSL::self();
+ int rc;
+
+ X509_REQ *req = kossl->X509_REQ_new();
+ if (!req) {
+ return -2;
+ }
+
+ EVP_PKEY *pkey = kossl->EVP_PKEY_new();
+ if (!pkey) {
+ kossl->X509_REQ_free(req);
+ return -4;
+ }
+
+ RSA *rsakey = kossl->RSA_generate_key(bits, e, NULL, NULL);
+ if (!rsakey) {
+ kossl->X509_REQ_free(req);
+ kossl->EVP_PKEY_free(pkey);
+ return -3;
+ }
+
+ rc = kossl->EVP_PKEY_assign(pkey, EVP_PKEY_RSA, (char *)rsakey);
+
+ rc = kossl->X509_REQ_set_pubkey(req, pkey);
+
+ // Set the subject
+ X509_NAME *n = kossl->X509_NAME_new();
+
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_countryName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_organizationName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_organizationalUnitName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_localityName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_stateOrProvinceName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_commonName, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+ kossl->X509_NAME_add_entry_by_txt(n, (char*)LN_pkcs9_emailAddress, MBSTRING_UTF8, (unsigned char*)name.local8Bit().data(), -1, -1, 0);
+
+ rc = kossl->X509_REQ_set_subject_name(req, n);
+
+
+ rc = kossl->X509_REQ_sign(req, pkey, kossl->EVP_md5());
+
+ // We write it to the database and then the caller can obtain it
+ // back from there. Yes it's inefficient, but it doesn't happen
+ // often and this way things are uniform.
+
+ TDEGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl");
+
+ TQString path = TDEGlobal::dirs()->saveLocation("kssl");
+ KTempFile csrFile(path + "csr_", ".der");
+
+ if (!csrFile.fstream()) {
+ kossl->X509_REQ_free(req);
+ kossl->EVP_PKEY_free(pkey);
+ return -5;
+ }
+
+ KTempFile p8File(path + "pkey_", ".p8");
+
+ if (!p8File.fstream()) {
+ kossl->X509_REQ_free(req);
+ kossl->EVP_PKEY_free(pkey);
+ return -5;
+ }
+
+ kossl->i2d_X509_REQ_fp(csrFile.fstream(), req);
+
+ kossl->i2d_PKCS8PrivateKey_fp(p8File.fstream(), pkey,
+ kossl->EVP_bf_cbc(), pass.local8Bit().data(),
+ pass.length(), 0L, 0L);
+
+ // FIXME Write tdeconfig entry to store the filenames under the md5 hash
+
+ kossl->X509_REQ_free(req);
+ kossl->EVP_PKEY_free(pkey);
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+
+TQStringList KSSLKeyGen::supportedKeySizes() {
+ TQStringList x;
+
+#ifdef KSSL_HAVE_SSL
+ x << i18n("2048 (High Grade)")
+ << i18n("1024 (Medium Grade)")
+ << i18n("768 (Low Grade)")
+ << i18n("512 (Low Grade)");
+#else
+ x << i18n("No SSL support.");
+#endif
+
+ return x;
+}
+
+
+#include "ksslkeygen.moc"
+
diff --git a/tdeio/kssl/ksslkeygen.h b/tdeio/kssl/ksslkeygen.h
new file mode 100644
index 000000000..5bb99a593
--- /dev/null
+++ b/tdeio/kssl/ksslkeygen.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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 _KSSLKEYGEN_H
+#define _KSSLKEYGEN_H
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <kwizard.h>
+
+
+class KOpenSSLProxy;
+class KGWizardPage1;
+class KGWizardPage2;
+
+/**
+ * KDE Key Generation dialog
+ *
+ * This is used to display a key generation dialog for cases such as the
+ * html \<keygen\> tag. It also does the certificate signing request generation.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL, KSSLCertificate, KSSLPKCS12
+ * @short KDE Key Generation Dialog
+ */
+class TDEIO_EXPORT KSSLKeyGen : public KWizard {
+ Q_OBJECT
+public:
+ /**
+ * Construct a keygen dialog.
+ * @param parent the parent widget
+ * @param name the internal name of this instance
+ * @param modal true if the dialog should be modal
+ */
+ KSSLKeyGen(TQWidget *parent=0L, const char *name=0L, bool modal=false);
+
+ /**
+ * Destroy this dialog.
+ */
+ virtual ~KSSLKeyGen();
+
+ /**
+ * List the supported key sizes.
+ * @return the supported key sizes
+ */
+ static TQStringList supportedKeySizes();
+
+ /**
+ * Generate the certificate signing request.
+ * @param name the name for the certificate
+ * @param pass the password for the request
+ * @param bits the bitsize for the key
+ * @param e the value of the "e" parameter in RSA
+ * @return 0 on success, non-zero on error
+ */
+ int generateCSR(const TQString& name, const TQString& pass, int bits, int e = 0x10001);
+
+ /**
+ * Set the key size.
+ * @param idx an index into supportedKeySizes()
+ */
+ void setKeySize(int idx) { _idx = idx; }
+
+private slots:
+ void slotPassChanged();
+ void slotGenerate();
+
+private:
+ class KSSLKeyGenPrivate;
+ KSSLKeyGenPrivate *d;
+ int _idx;
+ KGWizardPage1 *page1;
+ KGWizardPage2 *page2;
+};
+
+#endif
+
diff --git a/tdeio/kssl/ksslpeerinfo.cc b/tdeio/kssl/ksslpeerinfo.cc
new file mode 100644
index 000000000..d1c2d00fc
--- /dev/null
+++ b/tdeio/kssl/ksslpeerinfo.cc
@@ -0,0 +1,171 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqregexp.h>
+
+#include "ksslpeerinfo.h"
+#include <kdebug.h>
+
+#include <ksockaddr.h>
+#include <kextsock.h>
+#include <netsupp.h>
+#ifndef Q_WS_WIN //TODO kresolver not ported
+#include "kresolver.h"
+#endif
+
+#include "ksslx509map.h"
+
+class KSSLPeerInfoPrivate {
+public:
+ KSSLPeerInfoPrivate() {}
+ ~KSSLPeerInfoPrivate() { }
+ TQString peerHost;
+};
+
+
+
+KSSLPeerInfo::KSSLPeerInfo() {
+ d = new KSSLPeerInfoPrivate;
+}
+
+KSSLPeerInfo::~KSSLPeerInfo() {
+ delete d;
+}
+
+KSSLCertificate& KSSLPeerInfo::getPeerCertificate() {
+ return m_cert;
+}
+
+void KSSLPeerInfo::setPeerHost(TQString realHost) {
+ d->peerHost = realHost.stripWhiteSpace();
+ while(d->peerHost.endsWith("."))
+ d->peerHost.truncate(d->peerHost.length()-1);
+
+#ifdef Q_WS_WIN //TODO kresolver not ported
+ d->peerHost = d->peerHost.lower();
+#else
+ d->peerHost = TQString::fromLatin1(KNetwork::KResolver::domainToAscii(d->peerHost));
+#endif
+}
+
+bool KSSLPeerInfo::certMatchesAddress() {
+#ifdef KSSL_HAVE_SSL
+ KSSLX509Map certinfo(m_cert.getSubject());
+ TQStringList cns = TQStringList::split(TQRegExp("[ \n\r]"), certinfo.getValue("CN"));
+ cns += m_cert.subjAltNames();
+
+ for (TQStringList::Iterator cn = cns.begin(); cn != cns.end(); ++cn) {
+ if (cnMatchesAddress((*cn).stripWhiteSpace().lower()))
+ return true;
+ }
+
+#endif
+
+ return false;
+}
+
+
+bool KSSLPeerInfo::cnMatchesAddress(TQString cn) {
+#ifdef KSSL_HAVE_SSL
+ TQRegExp rx;
+
+ kdDebug(7029) << "Matching CN=[" << cn << "] to ["
+ << d->peerHost << "]" << endl;
+
+ // Check for invalid characters
+ if (TQRegExp("[^a-zA-Z0-9\\.\\*\\-]").search(cn) >= 0) {
+ kdDebug(7029) << "CN contains invalid characters! Failing." << endl;
+ return false;
+ }
+
+ // Domains can legally end with '.'s. We don't need them though.
+ while(cn.endsWith("."))
+ cn.truncate(cn.length()-1);
+
+ // Do not let empty CN's get by!!
+ if (cn.isEmpty())
+ return false;
+
+ // Check for IPv4 address
+ rx.setPattern("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
+ if (rx.exactMatch(d->peerHost))
+ return d->peerHost == cn;
+
+ // Check for IPv6 address here...
+ rx.setPattern("^\\[.*\\]$");
+ if (rx.exactMatch(d->peerHost))
+ return d->peerHost == cn;
+
+ if (cn.contains('*')) {
+ // First make sure that there are at least two valid parts
+ // after the wildcard (*).
+ TQStringList parts = TQStringList::split('.', cn, false);
+
+ while (parts.count() > 2)
+ parts.remove(parts.begin());
+
+ if (parts.count() != 2) {
+ return false; // we don't allow *.root - that's bad
+ }
+
+ if (parts[0].contains('*') || parts[1].contains('*')) {
+ return false;
+ }
+
+ // RFC2818 says that *.example.com should match against
+ // foo.example.com but not bar.foo.example.com
+ // (ie. they must have the same number of parts)
+ if (TQRegExp(cn, false, true).exactMatch(d->peerHost) &&
+ TQStringList::split('.', cn, false).count() ==
+ TQStringList::split('.', d->peerHost, false).count())
+ return true;
+
+ // *.example.com must match example.com also. Sigh..
+ if (cn.startsWith("*.")) {
+ TQString chopped = cn.mid(2);
+ if (chopped == d->peerHost) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // We must have an exact match in this case (insensitive though)
+ // (note we already did .lower())
+ if (cn == d->peerHost)
+ return true;
+#endif
+ return false;
+}
+
+
+void KSSLPeerInfo::reset() {
+ d->peerHost = TQString::null;
+}
+
+
+const TQString& KSSLPeerInfo::peerHost() const {
+ return d->peerHost;
+}
+
diff --git a/tdeio/kssl/ksslpeerinfo.h b/tdeio/kssl/ksslpeerinfo.h
new file mode 100644
index 000000000..a5cd017c9
--- /dev/null
+++ b/tdeio/kssl/ksslpeerinfo.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLPEERINFO_H
+#define _KSSLPEERINFO_H
+
+class KSSL;
+
+#include <tqglobal.h>
+#include <tqstringlist.h>
+#include <ksslcertificate.h>
+
+class KSSLPeerInfoPrivate;
+class KInetSocketAddress;
+
+/**
+ * KDE SSL Peer Data
+ *
+ * This class contains data about the peer of an SSL connection.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE SSL Peer Data
+ */
+class TDEIO_EXPORT KSSLPeerInfo {
+friend class KSSL;
+public:
+ /**
+ * Destroy this instance
+ */
+ ~KSSLPeerInfo();
+
+ /**
+ * Get a reference to the peer's certificate
+ *
+ * @return a reference to the peer's certificate
+ * @see KSSLCertificate
+ */
+ KSSLCertificate& getPeerCertificate();
+
+ /**
+ * Determine if the peer's certificate matches the address set with
+ * setPeerHost(). Note that this is a match in the "https"
+ * sense, taking into account, for instance, wildcards.
+ *
+ * @return true if it matches
+ * @see setPeerHost
+ */
+ bool certMatchesAddress();
+
+ /**
+ * Determine if the given "common name" matches the address set with
+ * setPeerHost(). Note that this is a match in the "https"
+ * sense, taking into account, for instance, wildcards.
+ *
+ * @return true if it matches
+ * @see setPeerHost
+ */
+ bool cnMatchesAddress(TQString cn);
+
+ /**
+ * Set the host that we are connected to. This is generally set by
+ * KSSL, and should be exactly what the user -thinks- he is connected
+ * to. (for instance, the host name in the url)
+ *
+ * @param host the hostname
+ */
+ void setPeerHost(TQString host = TQString::null);
+
+ /**
+ * Returns the host we are connected to.
+ */
+ const TQString& peerHost() const;
+
+ /**
+ * Clear out the host name.
+ */
+ void reset();
+
+protected:
+ KSSLPeerInfo();
+
+ KSSLCertificate m_cert;
+
+private:
+ KSSLPeerInfoPrivate *d;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslpemcallback.cc b/tdeio/kssl/ksslpemcallback.cc
new file mode 100644
index 000000000..2dfbb9146
--- /dev/null
+++ b/tdeio/kssl/ksslpemcallback.cc
@@ -0,0 +1,61 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kpassdlg.h>
+#include <klocale.h>
+#include "ksslpemcallback.h"
+
+int KSSLPemCallback(char *buf, int size, int rwflag, void *userdata) {
+#ifdef KSSL_HAVE_SSL
+ TQCString pass;
+ Q_UNUSED(userdata);
+ Q_UNUSED(rwflag);
+
+ if (!buf) return -1;
+ int rc = KPasswordDialog::getPassword(pass, i18n("Certificate password"));
+ if (rc != KPasswordDialog::Accepted) return -1;
+
+ const uint passlen = pass.length();
+ if (passlen > (unsigned int)size-1)
+ pass.truncate((unsigned int)size-1);
+
+ tqstrncpy(buf, pass.data(), size-1);
+
+ for (unsigned int i = 0; i < passlen; i++)
+ pass[i] = 0;
+ // To be sure that it doesn't optimise the previous loop away
+ for (unsigned int i = 0; i < passlen; i++)
+ pass[i] = pass[i];
+ buf[size-1] = 0;
+ return (int)passlen;
+#else
+ Q_UNUSED(buf);
+ Q_UNUSED(size);
+ Q_UNUSED(rwflag);
+ Q_UNUSED(userdata);
+ return -1;
+#endif
+}
+
+
diff --git a/tdeio/kssl/ksslpemcallback.h b/tdeio/kssl/ksslpemcallback.h
new file mode 100644
index 000000000..265edd099
--- /dev/null
+++ b/tdeio/kssl/ksslpemcallback.h
@@ -0,0 +1,29 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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 _kde_ksslpemcallback_h
+#define _kde_ksslpemcallback_h
+
+#include <tdelibs_export.h>
+
+int TDEIO_EXPORT KSSLPemCallback(char *buf, int size, int rwflag, void *userdata);
+
+#endif
+
diff --git a/tdeio/kssl/ksslpkcs12.cc b/tdeio/kssl/ksslpkcs12.cc
new file mode 100644
index 000000000..b8b23cf1c
--- /dev/null
+++ b/tdeio/kssl/ksslpkcs12.cc
@@ -0,0 +1,295 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kopenssl.h>
+
+#include <tqstring.h>
+#include <tqfile.h>
+#include <ksslall.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <kmdcodec.h>
+
+#include <assert.h>
+
+#ifdef KSSL_HAVE_SSL
+#define sk_new kossl->sk_new
+#define sk_push kossl->sk_push
+#define sk_free kossl->sk_free
+#define sk_value kossl->sk_value
+#define sk_num kossl->sk_num
+#define sk_dup kossl->sk_dup
+#define sk_pop kossl->sk_pop
+#endif
+
+
+KSSLPKCS12::KSSLPKCS12() {
+ _pkcs = NULL;
+ _pkey = NULL;
+ _cert = NULL;
+ _caStack = NULL;
+ kossl = KOSSL::self();
+}
+
+
+
+KSSLPKCS12::~KSSLPKCS12() {
+#ifdef KSSL_HAVE_SSL
+ if (_pkey) kossl->EVP_PKEY_free(_pkey);
+ if (_caStack) {
+ for (;;) {
+ X509* x5 = sk_X509_pop(_caStack);
+ if (!x5) break;
+ kossl->X509_free(x5);
+ }
+ sk_X509_free(_caStack);
+ }
+ if (_pkcs) kossl->PKCS12_free(_pkcs);
+#endif
+ if (_cert) delete _cert;
+}
+
+
+KSSLPKCS12* KSSLPKCS12::fromString(TQString base64, TQString password) {
+#ifdef KSSL_HAVE_SSL
+KTempFile ktf;
+
+ if (base64.isEmpty()) return NULL;
+ TQByteArray qba, qbb = TQCString(base64.latin1()).copy();
+ KCodecs::base64Decode(qbb, qba);
+ ktf.file()->writeBlock(qba);
+ ktf.close();
+ KSSLPKCS12* rc = loadCertFile(ktf.name(), password);
+ ktf.unlink();
+ return rc;
+#endif
+return NULL;
+}
+
+
+
+KSSLPKCS12* KSSLPKCS12::loadCertFile(TQString filename, TQString password) {
+#ifdef KSSL_HAVE_SSL
+TQFile qf(filename);
+PKCS12 *newpkcs = NULL;
+
+ if (!qf.open(IO_ReadOnly))
+ return NULL;
+
+ FILE *fp = fdopen(qf.handle(), "r");
+ if (!fp) return NULL;
+
+ newpkcs = KOSSL::self()->d2i_PKCS12_fp(fp, &newpkcs);
+
+ fclose(fp);
+ if (!newpkcs) {
+ KOSSL::self()->ERR_clear_error();
+ return NULL;
+ }
+
+ KSSLPKCS12 *c = new KSSLPKCS12;
+ c->setCert(newpkcs);
+
+ // Now we parse it to see if we can decrypt it and interpret it
+ if (!c->parse(password)) {
+ delete c; c = NULL;
+ }
+
+ return c;
+#endif
+return NULL;
+}
+
+
+void KSSLPKCS12::setCert(PKCS12 *c) {
+#ifdef KSSL_HAVE_SSL
+ _pkcs = c;
+#endif
+}
+
+
+bool KSSLPKCS12::changePassword(TQString pold, TQString pnew) {
+#ifdef KSSL_HAVE_SSL
+ // OpenSSL makes me cast away the const here. argh
+ return (0 == kossl->PKCS12_newpass(_pkcs,
+ pold.isNull() ? (char *)"" : (char *)pold.latin1(),
+ pnew.isNull() ? (char *)"" : (char *)pnew.latin1()));
+#endif
+return false;
+}
+
+
+bool KSSLPKCS12::parse(TQString pass) {
+#ifdef KSSL_HAVE_SSL
+X509 *x = NULL;
+
+ assert(_pkcs); // if you're calling this before pkcs gets set, it's a BUG!
+
+ if (_cert) delete _cert;
+ if (_pkey) kossl->EVP_PKEY_free(_pkey);
+ if (_caStack) {
+ for (;;) {
+ X509* x5 = sk_X509_pop(_caStack);
+ if (!x5) break;
+ kossl->X509_free(x5);
+ }
+ sk_X509_free(_caStack);
+ }
+ _pkey = NULL;
+ _caStack = NULL;
+ _cert = NULL;
+
+ int rc = kossl->PKCS12_parse(_pkcs, pass.latin1(), &_pkey, &x, &_caStack);
+
+ if (rc == 1) {
+ // kdDebug(7029) << "PKCS12_parse success" << endl;
+ if (x) {
+ _cert = new KSSLCertificate;
+ _cert->setCert(x);
+ if (_caStack) {
+ _cert->setChain(_caStack);
+ }
+ return true;
+ }
+ } else {
+ _caStack = NULL;
+ _pkey = NULL;
+ kossl->ERR_clear_error();
+ }
+#endif
+return false;
+}
+
+
+EVP_PKEY *KSSLPKCS12::getPrivateKey() {
+ return _pkey;
+}
+
+
+KSSLCertificate *KSSLPKCS12::getCertificate() {
+ return _cert;
+}
+
+
+TQString KSSLPKCS12::toString() {
+TQString base64;
+#ifdef KSSL_HAVE_SSL
+unsigned char *p;
+int len;
+
+ len = kossl->i2d_PKCS12(_pkcs, NULL);
+ if (len >= 0) {
+ char *buf = new char[len];
+ p = (unsigned char *)buf;
+ kossl->i2d_PKCS12(_pkcs, &p);
+ TQByteArray qba;
+ qba.setRawData(buf, len);
+ base64 = KCodecs::base64Encode(qba);
+ qba.resetRawData(buf, len);
+ delete[] buf;
+ }
+#endif
+return base64;
+}
+
+
+
+bool KSSLPKCS12::toFile(TQString filename) {
+#ifdef KSSL_HAVE_SSL
+TQFile out(filename);
+
+ if (!out.open(IO_WriteOnly)) return false;
+
+ int fd = out.handle();
+ FILE *fp = fdopen(fd, "w");
+
+ if (!fp) {
+ unlink(filename.latin1());
+ return false;
+ }
+
+ kossl->i2d_PKCS12_fp(fp, _pkcs);
+
+ fclose(fp);
+ return true;
+#endif
+return false;
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS12::validate() {
+ return validate(KSSLCertificate::SSLServer);
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS12::validate(KSSLCertificate::KSSLPurpose p) {
+#ifdef KSSL_HAVE_SSL
+KSSLCertificate::KSSLValidation xx = _cert->validate(p);
+ if (1 != kossl->X509_check_private_key(_cert->getCert(), _pkey)) {
+ xx = KSSLCertificate::PrivateKeyFailed;
+ }
+
+return xx;
+#else
+return KSSLCertificate::NoSSL;
+#endif
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS12::revalidate() {
+ return revalidate(KSSLCertificate::SSLServer);
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS12::revalidate(KSSLCertificate::KSSLPurpose p) {
+ return _cert->revalidate(p);
+}
+
+
+bool KSSLPKCS12::isValid() {
+return isValid(KSSLCertificate::SSLServer);
+}
+
+
+bool KSSLPKCS12::isValid(KSSLCertificate::KSSLPurpose p) {
+return (validate(p) == KSSLCertificate::Ok);
+}
+
+
+TQString KSSLPKCS12::name() {
+ return _cert->getSubject();
+}
+
+
+#ifdef KSSL_HAVE_SSL
+#undef sk_new
+#undef sk_push
+#undef sk_free
+#undef sk_value
+#undef sk_num
+#undef sk_pop
+#undef sk_dup
+#endif
+
diff --git a/tdeio/kssl/ksslpkcs12.h b/tdeio/kssl/ksslpkcs12.h
new file mode 100644
index 000000000..c9dff0d82
--- /dev/null
+++ b/tdeio/kssl/ksslpkcs12.h
@@ -0,0 +1,194 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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 _KSSLPKCS12_H
+#define _KSSLPKCS12_H
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/pkcs12.h>
+#undef crypt
+#else
+class PKCS12;
+class EVP_PKEY;
+class X509;
+#endif
+
+#include <ksslcertificate.h>
+#include <ksslcertchain.h>
+
+#ifndef STACK_OF
+#define STACK_OF(x) void
+#endif
+
+class KSSL;
+class KSSLPKCS12Private;
+class KOpenSSLProxy;
+
+/**
+ * KDE PKCS#12 Certificate
+ *
+ * As of yet, this class is being defined. if you use it, let it be known
+ * that BC will break on you until this message is removed.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL, KSSLCertificate
+ * @short KDE PKCS#12 Certificate
+ */
+class TDEIO_EXPORT KSSLPKCS12 {
+friend class KSSL;
+
+public:
+ /**
+ * Destroy this PKCS#12 certificate
+ */
+ virtual ~KSSLPKCS12();
+
+ /**
+ * The name of this certificate. This can be used to refer to the
+ * certificate instead of passing the object itself.
+ * @return the name of the certificate
+ */
+ TQString name();
+
+ /**
+ * Create a KSSLPKCS12 object from a Base64 in a TQString.
+ * @param base64 the base64 encoded certificate
+ * @param password a password for the certificate if encrypted
+ * @return the PKCS#12 object, or NULL on failure.
+ */
+ static KSSLPKCS12* fromString(TQString base64, TQString password = "");
+
+ /**
+ * Create a KSSLPKCS12 object by reading a PKCS#12 file.
+ * @param filename the filename of the certificate
+ * @param password a password for the certificate if encrypted
+ * @return the PKCS#12 object, or NULL on failure.
+ */
+ static KSSLPKCS12* loadCertFile(TQString filename, TQString password = "");
+
+ /**
+ * Convert to a Base64 string.
+ * @return the certificate in base64 form
+ */
+ TQString toString();
+
+ /**
+ * Raw set the PKCS12 object.
+ * @param c the openssl PKCS12 object
+ * @internal
+ */
+ void setCert(PKCS12 *c);
+
+ /**
+ * Change the password of the PKCS#12 in memory.
+ * @param pold the old password
+ * @param pnew the new password
+ * @return true on success
+ */
+ bool changePassword(TQString pold, TQString pnew);
+
+ /**
+ * Get the private key.
+ * @return the internal OpenSSL private key format
+ * @internal
+ */
+ EVP_PKEY *getPrivateKey();
+
+ /**
+ * Get the X.509 certificate.
+ * @return the X.509 certificate for the PKCS#12 object, or NULL
+ */
+ KSSLCertificate *getCertificate();
+
+ /**
+ * Write the PKCS#12 to a file in raw mode.
+ * @param filename the file to write to
+ * @return true on success
+ */
+ bool toFile(TQString filename);
+
+ /**
+ * Check the X.509 and private key to make sure they're valid.
+ * @return the result of the validation
+ * @see KSSLCertificate
+ */
+ KSSLCertificate::KSSLValidation validate();
+
+ /**
+ * Check the X.509 and private key to make sure they're valid.
+ * @param p the purpose to validate for
+ * @return the result of the validation
+ * @see KSSLCertificate
+ */
+ KSSLCertificate::KSSLValidation validate(KSSLCertificate::KSSLPurpose p);
+
+ /**
+ * Check the X.509 and private key to make sure they're valid.
+ * Ignore any cached validation result.
+ * @return the result of the validation
+ * @see KSSLCertificate
+ */
+ KSSLCertificate::KSSLValidation revalidate();
+
+ /**
+ * Check the X.509 and private key to make sure they're valid.
+ * Ignore any cached validation result.
+ * @param p the purpose to validate for
+ * @return the result of the validation
+ * @see KSSLCertificate
+ */
+ KSSLCertificate::KSSLValidation revalidate(KSSLCertificate::KSSLPurpose p);
+
+ /**
+ * Check if the X.509 and private key are valid.
+ * @return true if valid
+ */
+ bool isValid();
+
+ /**
+ * Check if the X.509 and private key are valid.
+ * @param p the purpose to validate for
+ * @return true if valid
+ */
+ bool isValid(KSSLCertificate::KSSLPurpose p);
+
+protected:
+ KSSLPKCS12();
+ bool parse(TQString pass);
+
+private:
+ KSSLPKCS12Private *d;
+ PKCS12 *_pkcs;
+ KOpenSSLProxy *kossl;
+ EVP_PKEY *_pkey;
+ KSSLCertificate *_cert;
+ STACK_OF(X509) *_caStack;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslpkcs7.cc b/tdeio/kssl/ksslpkcs7.cc
new file mode 100644
index 000000000..8db0000f0
--- /dev/null
+++ b/tdeio/kssl/ksslpkcs7.cc
@@ -0,0 +1,208 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kopenssl.h>
+
+#include <tqstring.h>
+#include <tqfile.h>
+#include <ksslall.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <kmdcodec.h>
+
+#include <assert.h>
+
+#ifdef KSSL_HAVE_SSL
+#define sk_new kossl->sk_new
+#define sk_push kossl->sk_push
+#define sk_free kossl->sk_free
+#define sk_value kossl->sk_value
+#define sk_num kossl->sk_num
+#define sk_dup kossl->sk_dup
+#endif
+
+
+KSSLPKCS7::KSSLPKCS7() {
+ _pkcs = NULL;
+ _cert = NULL;
+ kossl = KOSSL::self();
+}
+
+
+
+KSSLPKCS7::~KSSLPKCS7() {
+#ifdef KSSL_HAVE_SSL
+ if (_pkcs) kossl->PKCS7_free(_pkcs);
+#endif
+ if (_cert) delete _cert;
+}
+
+
+KSSLPKCS7* KSSLPKCS7::fromString(TQString base64) {
+#ifdef KSSL_HAVE_SSL
+KTempFile ktf;
+
+ if (base64.isEmpty()) return NULL;
+ TQByteArray qba, qbb = TQCString(base64.latin1()).copy();
+ KCodecs::base64Decode(qbb, qba);
+ ktf.file()->writeBlock(qba);
+ ktf.close();
+ KSSLPKCS7* rc = loadCertFile(ktf.name());
+ ktf.unlink();
+ return rc;
+#endif
+return NULL;
+}
+
+
+
+KSSLPKCS7* KSSLPKCS7::loadCertFile(TQString filename) {
+#ifdef KSSL_HAVE_SSL
+TQFile qf(filename);
+PKCS7 *newpkcs = NULL;
+
+ if (!qf.open(IO_ReadOnly))
+ return NULL;
+
+ FILE *fp = fdopen(qf.handle(), "r");
+ if (!fp) return NULL;
+
+ newpkcs = KOSSL::self()->d2i_PKCS7_fp(fp, &newpkcs);
+
+ if (!newpkcs) return NULL;
+
+ KSSLPKCS7 *c = new KSSLPKCS7;
+ c->setCert(newpkcs);
+
+ return c;
+#endif
+return NULL;
+}
+
+
+void KSSLPKCS7::setCert(PKCS7 *c) {
+#ifdef KSSL_HAVE_SSL
+ _pkcs = c;
+ //STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7);
+ //X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
+ // set _chain and _cert here.
+#endif
+}
+
+
+KSSLCertificate *KSSLPKCS7::getCertificate() {
+ return _cert;
+}
+
+
+KSSLCertChain *KSSLPKCS7::getChain() {
+ return _chain;
+}
+
+
+TQString KSSLPKCS7::toString() {
+TQString base64;
+#ifdef KSSL_HAVE_SSL
+unsigned char *p;
+int len;
+
+ len = kossl->i2d_PKCS7(_pkcs, NULL);
+ if (len >= 0) {
+ char *buf = new char[len];
+ p = (unsigned char *)buf;
+ kossl->i2d_PKCS7(_pkcs, &p);
+ TQByteArray qba;
+ qba.setRawData(buf, len);
+ base64 = KCodecs::base64Encode(qba);
+ qba.resetRawData(buf, len);
+ delete[] buf;
+ }
+#endif
+return base64;
+}
+
+
+
+bool KSSLPKCS7::toFile(TQString filename) {
+#ifdef KSSL_HAVE_SSL
+TQFile out(filename);
+
+ if (!out.open(IO_WriteOnly)) return false;
+
+ int fd = out.handle();
+ FILE *fp = fdopen(fd, "w");
+
+ if (!fp) {
+ unlink(filename.latin1());
+ return false;
+ }
+
+ kossl->i2d_PKCS7_fp(fp, _pkcs);
+
+ fclose(fp);
+ return true;
+#endif
+return false;
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS7::validate() {
+#ifdef KSSL_HAVE_SSL
+KSSLCertificate::KSSLValidation xx = _cert->validate();
+return xx;
+#else
+return KSSLCertificate::NoSSL;
+#endif
+}
+
+
+KSSLCertificate::KSSLValidation KSSLPKCS7::revalidate() {
+ if (_cert)
+ return _cert->revalidate();
+ return KSSLCertificate::Unknown;
+}
+
+
+bool KSSLPKCS7::isValid() {
+return (validate() == KSSLCertificate::Ok);
+}
+
+
+TQString KSSLPKCS7::name() {
+ if (_cert)
+ return _cert->getSubject();
+ return TQString();
+}
+
+
+#ifdef KSSL_HAVE_SSL
+#undef sk_new
+#undef sk_push
+#undef sk_free
+#undef sk_value
+#undef sk_num
+#undef sk_dup
+#endif
+
diff --git a/tdeio/kssl/ksslpkcs7.h b/tdeio/kssl/ksslpkcs7.h
new file mode 100644
index 000000000..c94b7bc7a
--- /dev/null
+++ b/tdeio/kssl/ksslpkcs7.h
@@ -0,0 +1,156 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 _KSSLPKCS7_H
+#define _KSSLPKCS7_H
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/pkcs7.h>
+#undef crypt
+#else
+class PKCS7;
+class X509;
+#endif
+
+//#include <kopenssl.h>
+#include <ksslcertificate.h>
+#include <ksslcertchain.h>
+
+#ifndef STACK_OF
+#define STACK_OF(x) void
+#endif
+
+class KSSL;
+class KSSLPKCS7Private;
+class KOpenSSLProxy;
+
+/**
+ * KDE PKCS#7 Certificate
+ *
+ * This class represents a PKCS#7 certificate
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE PKCS#7 Certificate
+ */
+class TDEIO_EXPORT KSSLPKCS7 {
+friend class KSSL;
+
+public:
+ /**
+ * Destroy this PKCS#7 certificate
+ */
+ virtual ~KSSLPKCS7();
+
+ /**
+ * The name of this certificate. This can be used to refer to the
+ * certificate instead of passing the object itself.
+ * @return the name of the certificate
+ */
+ TQString name();
+
+ /**
+ * Create a KSSLPKCS7 object from a Base64 in a TQString.
+ * @param base64 the base64 representation of the certificate
+ * @return a PKCS#7 object, or NULL on failure
+ */
+ static KSSLPKCS7* fromString(TQString base64);
+
+ /**
+ * Create a KSSLPKCS7 object by reading a PKCS#7 file.
+ * @param filename the filename to read the certificate from
+ * @return a PKCS#7 object, or NULL on failure
+ */
+ static KSSLPKCS7* loadCertFile(TQString filename);
+
+ /**
+ * Convert to a Base64 string.
+ * @return the PKCS#7 object in base64 form
+ */
+ TQString toString();
+
+ /**
+ * Raw set the PKCS7 object.
+ * @param c the PKCS7 object
+ * @internal
+ */
+ void setCert(PKCS7 *c);
+
+ /**
+ * Get the bottom level X.509 certificate.
+ * @return the certificate, or NULL on failure
+ * @see KSSLCertificate
+ */
+ KSSLCertificate *getCertificate();
+
+ /**
+ * Get the certificate chain.
+ * @return the certificate chain
+ * @see KSSLCertChain
+ */
+ KSSLCertChain *getChain();
+
+ /**
+ * Write the PKCS#7 to a file in raw mode.
+ * @param filename the filename to write
+ * @return true on success
+ */
+ bool toFile(TQString filename);
+
+ /**
+ * Check the chain to make sure it's valid.
+ * @return the result of the validation procedure
+ */
+ KSSLCertificate::KSSLValidation validate();
+
+ /**
+ * Check the chain to make sure it's valid.
+ * Ignore any cached validation result.
+ * @return the result of the validation
+ * @see KSSLCertificate
+ */
+ KSSLCertificate::KSSLValidation revalidate();
+
+ /**
+ * Return true if the chain is valid.
+ */
+ bool isValid();
+
+protected:
+ KSSLPKCS7();
+
+private:
+ KSSLPKCS7Private *d;
+ PKCS7 *_pkcs;
+ KOpenSSLProxy *kossl;
+ KSSLCertificate *_cert;
+ KSSLCertChain *_chain;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslsession.cc b/tdeio/kssl/ksslsession.cc
new file mode 100644
index 000000000..3c80233f1
--- /dev/null
+++ b/tdeio/kssl/ksslsession.cc
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 George Staikos <staikos@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 "ksslsession.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kopenssl.h>
+#include <kmdcodec.h>
+
+KSSLSession::KSSLSession() : _session(0L) {
+}
+
+
+KSSLSession::~KSSLSession() {
+#ifdef KSSL_HAVE_SSL
+ if (_session) {
+ KOpenSSLProxy::self()->SSL_SESSION_free(static_cast<SSL_SESSION*>(_session));
+ _session = 0L;
+ }
+#endif
+}
+
+
+TQString KSSLSession::toString() const {
+TQString rc;
+#ifdef KSSL_HAVE_SSL
+TQByteArray qba;
+SSL_SESSION *session = static_cast<SSL_SESSION*>(_session);
+unsigned int slen = KOpenSSLProxy::self()->i2d_SSL_SESSION(session, 0L);
+unsigned char *csess = new unsigned char[slen];
+unsigned char *p = csess;
+
+ if (!KOpenSSLProxy::self()->i2d_SSL_SESSION(session, &p)) {
+ delete[] csess;
+ return TQString::null;
+ }
+
+ // encode it into a QString
+ qba.duplicate((const char*)csess, slen);
+ delete[] csess;
+ rc = KCodecs::base64Encode(qba);
+#endif
+return rc;
+}
+
+
+KSSLSession *KSSLSession::fromString(const TQString& s) {
+KSSLSession *session = 0L;
+#ifdef KSSL_HAVE_SSL
+TQByteArray qba, qbb = s.local8Bit().copy();
+ KCodecs::base64Decode(qbb, qba);
+ unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
+ SSL_SESSION *ss = KOSSL::self()->d2i_SSL_SESSION(0L, &qbap, qba.size());
+ if (ss) {
+ session = new KSSLSession;
+ session->_session = ss;
+ }
+#endif
+return session;
+}
+
+
diff --git a/tdeio/kssl/ksslsession.h b/tdeio/kssl/ksslsession.h
new file mode 100644
index 000000000..394a4b91a
--- /dev/null
+++ b/tdeio/kssl/ksslsession.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 George Staikos <staikos@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 _KSSLSESSION_H
+#define _KSSLSESSION_H
+
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+class KSSL;
+
+class KSSLSessionPrivate;
+
+/**
+ * KDE SSL Session Information
+ *
+ * This class contains data about an SSL session.
+ * It is just used as a container that is taken from or passed to KSSL objects.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE SSL Session Information
+ */
+class TDEIO_EXPORT KSSLSession {
+friend class KSSL;
+public:
+ /**
+ * Destroy this instance
+ */
+ ~KSSLSession();
+
+ /**
+ * Convert to a base64 encoded string (so it can be copied safely)
+ */
+ TQString toString() const;
+
+ /**
+ * Create as session ID object from a base64 encoded string.
+ * @param s the session id in base64 encoded ASN.1 format
+ * @return a KSSLSession object, or 0L on error
+ */
+ static KSSLSession* fromString(const TQString& s);
+
+protected:
+ KSSLSession();
+ KSSLSession(const KSSLSession&);
+ void *_session;
+
+private:
+ KSSLSessionPrivate *d;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslsettings.cc b/tdeio/kssl/ksslsettings.cc
new file mode 100644
index 000000000..eb91ea9cb
--- /dev/null
+++ b/tdeio/kssl/ksslsettings.cc
@@ -0,0 +1,356 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <tqfile.h>
+#include <tqsortedlist.h>
+
+#include "ksslsettings.h"
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+
+// this hack provided by Malte Starostik to avoid glibc/openssl bug
+// on some systems
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/ssl.h>
+#undef crypt
+#endif
+#include <kopenssl.h>
+
+#ifdef KSSL_HAVE_SSL
+#define sk_new d->kossl->sk_new
+#define sk_push d->kossl->sk_push
+#define sk_free d->kossl->sk_free
+#define sk_value d->kossl->sk_value
+#define sk_num d->kossl->sk_num
+#define sk_dup d->kossl->sk_dup
+#define sk_pop d->kossl->sk_pop
+#endif
+
+ class CipherNode {
+ public:
+ CipherNode(const char *_name, int _keylen) :
+ name(_name), keylen(_keylen) {}
+ TQString name;
+ int keylen;
+ inline int operator==(CipherNode &x)
+ { return ((x.keylen == keylen) && (x.name == name)); }
+ inline int operator< (CipherNode &x) { return keylen < x.keylen; }
+ inline int operator<=(CipherNode &x) { return keylen <= x.keylen; }
+ inline int operator> (CipherNode &x) { return keylen > x.keylen; }
+ inline int operator>=(CipherNode &x) { return keylen >= x.keylen; }
+ };
+
+
+class KSSLSettingsPrivate {
+public:
+ KSSLSettingsPrivate() {
+ kossl = NULL; // try to delay this as long as possible
+ }
+ ~KSSLSettingsPrivate() {
+
+ }
+
+ KOSSL *kossl;
+ bool m_bUseEGD;
+ bool m_bUseEFile;
+ TQString m_EGDPath;
+ bool m_bSendX509;
+ bool m_bPromptX509;
+};
+
+//
+// FIXME
+// Implementation note: for now, we only read cipher settings from disk,
+// and do not store them in memory. This should change.
+//
+
+KSSLSettings::KSSLSettings(bool readConfig) {
+ d = new KSSLSettingsPrivate;
+ m_cfg = new TDEConfig("cryptodefaults", false, false);
+
+ if (!TDEGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl")) {
+ //kdDebug(7029) << "Error adding (kssl, share/apps/kssl)" << endl;
+ }
+
+ if (readConfig) load();
+}
+
+
+// we don't save settings incase it was a temporary object
+KSSLSettings::~KSSLSettings() {
+ delete m_cfg;
+ delete d;
+}
+
+
+bool KSSLSettings::sslv2() const {
+ return m_bUseSSLv2;
+}
+
+
+bool KSSLSettings::sslv3() const {
+ return m_bUseSSLv3;
+}
+
+
+bool KSSLSettings::tlsv1() const {
+ return m_bUseTLSv1;
+}
+
+
+// FIXME: we should make a default list available if this fails
+// since OpenSSL seems to just choose any old thing if it's given an
+// empty list. This behavior is not confirmed though.
+TQString KSSLSettings::getCipherList() {
+ TQString clist;
+#ifdef KSSL_HAVE_SSL
+ TQString tcipher;
+ bool firstcipher = true;
+ SSL_METHOD *meth = 0L;
+ TQPtrList<CipherNode> cipherList;
+
+ cipherList.setAutoDelete(true);
+
+ if (!d->kossl)
+ d->kossl = KOSSL::self();
+
+ if (m_bUseSSLv3 && m_bUseSSLv2)
+ meth = d->kossl->SSLv23_client_method();
+ else if(m_bUseSSLv3)
+ meth = d->kossl->SSLv3_client_method();
+ else if (m_bUseSSLv2)
+ meth = d->kossl->SSLv2_client_method();
+
+ SSL_CTX *ctx = d->kossl->SSL_CTX_new(meth);
+ SSL* ssl = d->kossl->SSL_new(ctx);
+ STACK_OF(SSL_CIPHER)* sk = d->kossl->SSL_get_ciphers(ssl);
+ int cnt = sk_SSL_CIPHER_num(sk);
+ for (int i=0; i< cnt; i++) {
+ SSL_CIPHER *sc = sk_SSL_CIPHER_value(sk,i);
+ if (!sc)
+ break;
+
+ if(!strcmp("SSLv2", d->kossl->SSL_CIPHER_get_version(sc)))
+ m_cfg->setGroup("SSLv2");
+ else
+ m_cfg->setGroup("SSLv3");
+
+ tcipher.sprintf("cipher_%s", sc->name);
+ int bits = d->kossl->SSL_CIPHER_get_bits(sc, NULL);
+ if (m_cfg->readBoolEntry(tcipher, bits >= 56)) {
+ CipherNode *xx = new CipherNode(sc->name,bits);
+ if (!cipherList.contains(xx))
+ cipherList.prepend(xx);
+ else
+ delete xx;
+ }
+ }
+ d->kossl->SSL_free(ssl);
+ d->kossl->SSL_CTX_free(ctx);
+
+ // Remove any ADH ciphers as per RFC2246
+ // Also remove NULL ciphers and 168bit ciphers
+ for (unsigned int i = 0; i < cipherList.count(); i++) {
+ CipherNode *j = 0L;
+ while ((j = cipherList.at(i)) != 0L) {
+ if (j->name.contains("ADH-") || j->name.contains("NULL-") || j->name.contains("DES-CBC3-SHA") || j->name.contains("FZA")) {
+ cipherList.remove(j);
+ } else {
+ break;
+ }
+ }
+ }
+
+ // now assemble the list cipher1:cipher2:cipher3:...:ciphern
+ while (!cipherList.isEmpty()) {
+ if (firstcipher)
+ firstcipher = false;
+ else clist.append(":");
+ clist.append(cipherList.getLast()->name);
+ cipherList.removeLast();
+ } // while
+
+ kdDebug(7029) << "Cipher list is: " << clist << endl;
+
+#endif
+ return clist;
+}
+
+// FIXME - sync these up so that we can use them with the control module!!
+void KSSLSettings::load() {
+ m_cfg->reparseConfiguration();
+
+ m_cfg->setGroup("TLS");
+ m_bUseTLSv1 = m_cfg->readBoolEntry("Enabled", true);
+
+ m_cfg->setGroup("SSLv2");
+ m_bUseSSLv2 = m_cfg->readBoolEntry("Enabled", false);
+
+ m_cfg->setGroup("SSLv3");
+ m_bUseSSLv3 = m_cfg->readBoolEntry("Enabled", true);
+
+ m_cfg->setGroup("Warnings");
+ m_bWarnOnEnter = m_cfg->readBoolEntry("OnEnter", false);
+ m_bWarnOnLeave = m_cfg->readBoolEntry("OnLeave", true);
+ m_bWarnOnUnencrypted = m_cfg->readBoolEntry("OnUnencrypted", true);
+ m_bWarnOnMixed = m_cfg->readBoolEntry("OnMixed", true);
+
+ m_cfg->setGroup("Validation");
+ m_bWarnSelfSigned = m_cfg->readBoolEntry("WarnSelfSigned", true);
+ m_bWarnExpired = m_cfg->readBoolEntry("WarnExpired", true);
+ m_bWarnRevoked = m_cfg->readBoolEntry("WarnRevoked", true);
+
+ m_cfg->setGroup("EGD");
+ d->m_bUseEGD = m_cfg->readBoolEntry("UseEGD", false);
+ d->m_bUseEFile = m_cfg->readBoolEntry("UseEFile", false);
+ d->m_EGDPath = m_cfg->readPathEntry("EGDPath");
+
+ m_cfg->setGroup("Auth");
+ d->m_bSendX509 = ("send" == m_cfg->readEntry("AuthMethod", ""));
+ d->m_bPromptX509 = ("prompt" == m_cfg->readEntry("AuthMethod", ""));
+
+ #ifdef KSSL_HAVE_SSL
+
+
+
+ #endif
+}
+
+
+void KSSLSettings::defaults() {
+ m_bUseTLSv1 = true;
+ m_bUseSSLv2 = false;
+ m_bUseSSLv3 = true;
+ m_bWarnOnEnter = false;
+ m_bWarnOnLeave = true;
+ m_bWarnOnUnencrypted = true;
+ m_bWarnOnMixed = true;
+ m_bWarnSelfSigned = true;
+ m_bWarnExpired = true;
+ m_bWarnRevoked = true;
+ d->m_bUseEGD = false;
+ d->m_bUseEFile = false;
+ d->m_EGDPath = "";
+}
+
+
+void KSSLSettings::save() {
+ m_cfg->setGroup("TLS");
+ m_cfg->writeEntry("Enabled", m_bUseTLSv1);
+
+ m_cfg->setGroup("SSLv2");
+ m_cfg->writeEntry("Enabled", m_bUseSSLv2);
+
+ m_cfg->setGroup("SSLv3");
+ m_cfg->writeEntry("Enabled", m_bUseSSLv3);
+
+ m_cfg->setGroup("Warnings");
+ m_cfg->writeEntry("OnEnter", m_bWarnOnEnter);
+ m_cfg->writeEntry("OnLeave", m_bWarnOnLeave);
+ m_cfg->writeEntry("OnUnencrypted", m_bWarnOnUnencrypted);
+ m_cfg->writeEntry("OnMixed", m_bWarnOnMixed);
+
+ m_cfg->setGroup("Validation");
+ m_cfg->writeEntry("WarnSelfSigned", m_bWarnSelfSigned);
+ m_cfg->writeEntry("WarnExpired", m_bWarnExpired);
+ m_cfg->writeEntry("WarnRevoked", m_bWarnRevoked);
+
+ m_cfg->setGroup("EGD");
+ m_cfg->writeEntry("UseEGD", d->m_bUseEGD);
+ m_cfg->writeEntry("UseEFile", d->m_bUseEFile);
+ m_cfg->writePathEntry("EGDPath", d->m_EGDPath);
+
+ m_cfg->sync();
+ // FIXME - ciphers
+#if 0
+#ifdef KSSL_HAVE_SSL
+ m_cfg->setGroup("SSLv2");
+ for (unsigned int i = 0; i < v2ciphers.count(); i++) {
+ TQString ciphername;
+ ciphername.sprintf("cipher_%s", v2ciphers[i].ascii());
+ if (v2selectedciphers.contains(v2ciphers[i])) {
+ m_cfg->writeEntry(ciphername, true);
+ } else m_cfg->writeEntry(ciphername, false);
+ }
+
+ m_cfg->setGroup("SSLv3");
+ for (unsigned int i = 0; i < v3ciphers.count(); i++) {
+ TQString ciphername;
+ ciphername.sprintf("cipher_%s", v3ciphers[i].ascii());
+ if (v3selectedciphers.contains(v3ciphers[i])) {
+ m_cfg->writeEntry(ciphername, true);
+ } else m_cfg->writeEntry(ciphername, false);
+ }
+#endif
+
+ m_cfg->sync();
+
+ // insure proper permissions -- contains sensitive data
+ TQString cfgName(TDEGlobal::dirs()->findResource("config", "cryptodefaults"));
+ if (!cfgName.isEmpty())
+ ::chmod(TQFile::encodeName(cfgName), 0600);
+#endif
+}
+
+
+bool KSSLSettings::warnOnEnter() const { return m_bWarnOnEnter; }
+void KSSLSettings::setWarnOnEnter(bool x) { m_bWarnOnEnter = x; }
+bool KSSLSettings::warnOnUnencrypted() const { return m_bWarnOnUnencrypted; }
+void KSSLSettings::setWarnOnUnencrypted(bool x) { m_bWarnOnUnencrypted = x; }
+bool KSSLSettings::warnOnLeave() const { return m_bWarnOnLeave; }
+void KSSLSettings::setWarnOnLeave(bool x) { m_bWarnOnLeave = x; }
+bool KSSLSettings::warnOnMixed() const { return m_bWarnOnMixed; }
+bool KSSLSettings::warnOnSelfSigned() const { return m_bWarnSelfSigned; }
+bool KSSLSettings::warnOnRevoked() const { return m_bWarnRevoked; }
+bool KSSLSettings::warnOnExpired() const { return m_bWarnExpired; }
+bool KSSLSettings::useEGD() const { return d->m_bUseEGD; }
+bool KSSLSettings::useEFile() const { return d->m_bUseEFile; }
+bool KSSLSettings::autoSendX509() const { return d->m_bSendX509; }
+bool KSSLSettings::promptSendX509() const { return d->m_bPromptX509; }
+
+void KSSLSettings::setTLSv1(bool enabled) { m_bUseTLSv1 = enabled; }
+void KSSLSettings::setSSLv2(bool enabled) { m_bUseSSLv2 = enabled; }
+void KSSLSettings::setSSLv3(bool enabled) { m_bUseSSLv3 = enabled; }
+
+TQString& KSSLSettings::getEGDPath() { return d->m_EGDPath; }
+
+#ifdef KSSL_HAVE_SSL
+#undef sk_new
+#undef sk_push
+#undef sk_free
+#undef sk_value
+#undef sk_num
+#undef sk_pop
+#undef sk_dup
+#endif
+
diff --git a/tdeio/kssl/ksslsettings.h b/tdeio/kssl/ksslsettings.h
new file mode 100644
index 000000000..18b55331f
--- /dev/null
+++ b/tdeio/kssl/ksslsettings.h
@@ -0,0 +1,224 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLSETTINGS_H
+#define _KSSLSETTINGS_H
+
+#include <tqstring.h>
+#include <tqvaluelist.h>
+#include <tdeconfig.h>
+
+class KSSLSettingsPrivate;
+
+/**
+ * KDE SSL Settings
+ *
+ * This class contains some of the SSL settings for easy use.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL
+ * @short KDE SSL Settings
+ */
+class TDEIO_EXPORT KSSLSettings {
+public:
+ /**
+ * Construct a KSSL Settings object
+ *
+ * @param readConfig read in the configuration immediately if true
+ */
+ KSSLSettings(bool readConfig = true);
+
+ /**
+ * Destroy this KSSL Settings object
+ */
+ ~KSSLSettings();
+
+ /**
+ * Does the user allow SSLv2
+ * @return true if the user allows SSLv2
+ */
+ bool sslv2() const;
+
+ /**
+ * Does the user allow SSLv3
+ * @return true if the user allows SSLv3
+ */
+ bool sslv3() const;
+
+ /**
+ * Does the user allow TLSv1
+ * @return true if the user allows TLSv1
+ */
+ bool tlsv1() const;
+
+ /**
+ * Does the user want to be warned on entering SSL mode
+ * @return true if the user wants to be warned
+ */
+ bool warnOnEnter() const;
+
+ /**
+ * Change the user's warnOnEnter() setting
+ * @since 3.3
+ * @param x true if the user is to be warned
+ * @see warnOnEnter
+ */
+ void setWarnOnEnter(bool x);
+
+ /**
+ * Does the user want to be warned on sending unencrypted data
+ * @return true if the user wants to be warned
+ * @see setWarnOnUnencrypted
+ */
+ bool warnOnUnencrypted() const;
+
+ /**
+ * Change the user's warnOnUnencrypted() setting
+ * @param x true if the user is to be warned
+ * @see warnOnUnencrypted
+ */
+ void setWarnOnUnencrypted(bool x);
+
+ /**
+ * Does the user want to be warned on leaving SSL mode
+ * @return true if the user wants to be warned
+ */
+ bool warnOnLeave() const;
+
+ /**
+ * Change the user's warnOnLeave() setting
+ * @since 3.3
+ * @param x true if the user is to be warned
+ * @see warnOnLeave
+ */
+ void setWarnOnLeave(bool x);
+
+ /**
+ * Does the user want to be warned during mixed SSL/non-SSL mode
+ * @return true if the user wants to be warned
+ */
+ bool warnOnMixed() const;
+
+ /**
+ * Do not use this
+ * @deprecated
+ */
+ bool warnOnSelfSigned() const KDE_DEPRECATED;
+
+ /**
+ * Do not use this
+ * @deprecated
+ */
+ bool warnOnRevoked() const KDE_DEPRECATED;
+
+ /**
+ * Do not use this
+ * @deprecated
+ */
+ bool warnOnExpired() const KDE_DEPRECATED;
+
+ /**
+ * Does the user want to use the Entropy Gathering Daemon?
+ * @return true if the user wants to use EGD
+ */
+ bool useEGD() const;
+
+ /**
+ * Does the user want to use an entropy file?
+ * @return true if the user wants to use an entropy file
+ */
+ bool useEFile() const;
+
+ /**
+ * Change the user's TLSv1 preference
+ * @param enabled true if TLSv1 is enabled
+ */
+ void setTLSv1(bool enabled);
+
+ /**
+ * Change the user's SSLv2 preference
+ * @param enabled true if SSLv2 is enabled
+ */
+ void setSSLv2(bool enabled);
+
+ /**
+ * Change the user's SSLv3 preference
+ * @param enabled true if SSLv3 is enabled
+ */
+ void setSSLv3(bool enabled);
+
+ /**
+ * Does the user want X.509 client certificates to always be sent when
+ * possible?
+ * @return true if the user always wants a certificate sent
+ */
+ bool autoSendX509() const;
+
+ /**
+ * Does the user want to be prompted to send X.509 client certificates
+ * when possible?
+ * @return true if the user wants to be prompted
+ */
+ bool promptSendX509() const;
+
+ /**
+ * Get the OpenSSL cipher list for selecting the list of ciphers to
+ * use in a connection.
+ * @return the cipher list
+ */
+ TQString getCipherList();
+
+ /**
+ * Get the configured path to the entropy gathering daemon or entropy
+ * file.
+ * @return the path
+ */
+ TQString& getEGDPath();
+
+ /**
+ * Load the user's settings.
+ */
+ void load();
+
+ /**
+ * Revert to default settings.
+ */
+ void defaults();
+
+ /**
+ * Save the current settings.
+ */
+ void save();
+
+private:
+ TDEConfig *m_cfg;
+ bool m_bUseSSLv2, m_bUseSSLv3, m_bUseTLSv1;
+ bool m_bWarnOnEnter, m_bWarnOnUnencrypted, m_bWarnOnLeave, m_bWarnOnMixed;
+ bool m_bWarnSelfSigned, m_bWarnRevoked, m_bWarnExpired;
+
+ TQValueList<TQString> v2ciphers, v2selectedciphers, v3ciphers, v3selectedciphers;
+ TQValueList<int> v2bits, v3bits;
+
+ KSSLSettingsPrivate *d;
+};
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslsigners.cc b/tdeio/kssl/ksslsigners.cc
new file mode 100644
index 000000000..028ddf555
--- /dev/null
+++ b/tdeio/kssl/ksslsigners.cc
@@ -0,0 +1,251 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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 <tqstring.h>
+#include <tqstringlist.h>
+#include "ksslcertificate.h"
+#include "ksslsigners.h"
+#include <stdlib.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kdatastream.h>
+
+
+KSSLSigners::KSSLSigners() {
+ dcc = new DCOPClient;
+ dcc->attach();
+}
+
+
+KSSLSigners::~KSSLSigners() {
+ delete dcc;
+}
+
+bool KSSLSigners::addCA(KSSLCertificate& cert,
+ bool ssl,
+ bool email,
+ bool code) {
+ return addCA(cert.toString(), ssl, email, code);
+}
+
+
+bool KSSLSigners::addCA(TQString cert,
+ bool ssl,
+ bool email,
+ bool code) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << cert;
+ arg << ssl << email << code;
+ bool rc = dcc->call("kded", "kssld",
+ "caAdd(TQString,bool,bool,bool)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLSigners::regenerate() {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ bool rc = dcc->call("kded", "kssld",
+ "caRegenerate()",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLSigners::useForSSL(KSSLCertificate& cert) {
+ return useForSSL(cert.getSubject());
+}
+
+
+bool KSSLSigners::useForSSL(TQString subject) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject;
+ bool rc = dcc->call("kded", "kssld",
+ "caUseForSSL(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLSigners::useForEmail(KSSLCertificate& cert) {
+ return useForEmail(cert.getSubject());
+}
+
+
+bool KSSLSigners::useForEmail(TQString subject) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject;
+ bool rc = dcc->call("kded", "kssld",
+ "caUseForEmail(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLSigners::useForCode(KSSLCertificate& cert) {
+ return useForCode(cert.getSubject());
+}
+
+
+bool KSSLSigners::useForCode(TQString subject) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject;
+ bool rc = dcc->call("kded", "kssld",
+ "caUseForCode(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+bool KSSLSigners::remove(KSSLCertificate& cert) {
+ return remove(cert.getSubject());
+}
+
+
+bool KSSLSigners::remove(TQString subject) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject;
+ bool rc = dcc->call("kded", "kssld",
+ "caRemove(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+TQStringList KSSLSigners::list() {
+ TQStringList drc;
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ bool rc = dcc->call("kded", "kssld",
+ "caList()",
+ data, rettype, retval);
+
+ if (rc && rettype == TQSTRINGLIST_OBJECT_NAME_STRING) {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ retStream >> drc;
+ }
+
+return drc;
+}
+
+
+TQString KSSLSigners::getCert(TQString subject) {
+ TQString drc;
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject;
+ bool rc = dcc->call("kded", "kssld",
+ "caGetCert(TQString)",
+ data, rettype, retval);
+
+ if (rc && rettype == TQSTRING_OBJECT_NAME_STRING) {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ retStream >> drc;
+ }
+
+return drc;
+}
+
+
+bool KSSLSigners::setUse(TQString subject, bool ssl, bool email, bool code) {
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << subject << ssl << email << code;
+ bool rc = dcc->call("kded", "kssld",
+ "caSetUse(TQString,bool,bool,bool)",
+ data, rettype, retval);
+
+ if (rc && rettype == "bool") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ bool drc;
+ retStream >> drc;
+ return drc;
+ }
+
+return false;
+}
+
+
+
+
diff --git a/tdeio/kssl/ksslsigners.h b/tdeio/kssl/ksslsigners.h
new file mode 100644
index 000000000..3149e852a
--- /dev/null
+++ b/tdeio/kssl/ksslsigners.h
@@ -0,0 +1,172 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 _INCLUDE_KSSLSIGNERS_H
+#define _INCLUDE_KSSLSIGNERS_H
+
+class KSSLCertificate;
+class DCOPClient;
+
+#include <tqstringlist.h>
+
+#include <tdelibs_export.h>
+
+// ### KDE4 - Fix constness
+/**
+ * KDE SSL Signer Database
+ *
+ * This class is used to manipulate the KDE SSL signer database. It
+ * communicates to the KDE SSL daemon via dcop for backend integration.
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL, KSSLCertificate
+ * @short KDE SSL Signer Database
+ */
+class TDEIO_EXPORT KSSLSigners {
+public:
+ /**
+ * Construct a KSSLSigner object.
+ */
+ KSSLSigners();
+
+ /**
+ * Destroy this KSSLSigner object.
+ */
+ ~KSSLSigners();
+
+ /**
+ * Add a signer to the database.
+ *
+ * @param cert the signer's certificate
+ * @param ssl allow it to sign for SSL
+ * @param email allow it to sign for S/MIME
+ * @param code allow it to sign for code signing
+ * @return true on success
+ */
+ bool addCA(KSSLCertificate& cert, bool ssl, bool email, bool code);
+
+ /**
+ * Add a signer to the database.
+ *
+ * @param cert the signer's certificate in base64 form
+ * @param ssl allow it to sign for SSL
+ * @param email allow it to sign for S/MIME
+ * @param code allow it to sign for code signing
+ * @return true on success
+ */
+ bool addCA(TQString cert, bool ssl, bool email, bool code);
+
+ /**
+ * Regenerate the signer-root file from the user's settings.
+ * @return true on success
+ */
+ bool regenerate();
+
+ /**
+ * Determine if a certificate can be used for SSL certificate signing
+ * @param cert the certificate
+ * @return true if it can be used for SSL
+ */
+ bool useForSSL(KSSLCertificate& cert);
+
+ /**
+ * Determine if a certificate can be used for SSL certificate signing
+ * @param subject the certificate subject
+ * @return true if it can be used for SSL
+ */
+ bool useForSSL(TQString subject);
+
+ /**
+ * Determine if a certificate can be used for S/MIME certificate signing
+ * @param cert the certificate
+ * @return true if it can be used for S/MIME
+ */
+ bool useForEmail(KSSLCertificate& cert);
+
+ /**
+ * Determine if a certificate can be used for S/MIME certificate signing
+ * @param subject the certificate subject
+ * @return true if it can be used for S/MIME
+ */
+ bool useForEmail(TQString subject);
+
+ /**
+ * Determine if a certificate can be used for code certificate signing
+ * @param cert the certificate
+ * @return true if it can be used for code
+ */
+ bool useForCode(KSSLCertificate& cert);
+
+ /**
+ * Determine if a certificate can be used for code certificate signing
+ * @param subject the certificate subject
+ * @return true if it can be used for code
+ */
+ bool useForCode(TQString subject);
+
+ /**
+ * Remove a certificate signer from the database
+ * @param cert the certificate to remove
+ * @return true on success
+ */
+ bool remove(KSSLCertificate& cert);
+
+ /**
+ * Remove a certificate signer from the database
+ * @param subject the subject of the certificate to remove
+ * @return true on success
+ */
+ bool remove(TQString subject);
+
+ /**
+ * List the signers in the database.
+ * @return the list of subjects in the database
+ * @see getCert
+ */
+ TQStringList list();
+
+ /**
+ * Get a signer certificate from the database.
+ *
+ * @param subject the subject of the certificate desired
+ * @return the base64 encoded certificate
+ */
+ TQString getCert(TQString subject);
+
+ /**
+ * Set the use of a particular entry in the certificate signer database.
+ * @param subject the subject of the certificate in question
+ * @param ssl allow this for SSL certificate signing
+ * @param email allow this for S/MIME certificate signing
+ * @param code allow this for code certificate signing
+ * @return true on success
+ */
+ bool setUse(TQString subject, bool ssl, bool email, bool code);
+
+private:
+ class KSSLSignersPrivate;
+ KSSLSignersPrivate *d;
+
+ DCOPClient *dcc;
+};
+
+
+#endif
diff --git a/tdeio/kssl/ksslutils.cc b/tdeio/kssl/ksslutils.cc
new file mode 100644
index 000000000..80651757f
--- /dev/null
+++ b/tdeio/kssl/ksslutils.cc
@@ -0,0 +1,94 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000,2001 George Staikos <staikos@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 "ksslutils.h"
+
+#include <tqstring.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <tqdatetime.h>
+
+#include "kopenssl.h"
+
+#ifdef KSSL_HAVE_SSL
+// This code is mostly taken from OpenSSL v0.9.5a
+// by Eric Young
+TQDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt) {
+TQDateTime qdt;
+char *v;
+int gmt=0;
+int i;
+int y=0,M=0,d=0,h=0,m=0,s=0;
+TQDate qdate;
+TQTime qtime;
+
+ i = tm->length;
+ v = (char *)tm->data;
+
+ if (i < 10) goto auq_err;
+ if (v[i-1] == 'Z') gmt=1;
+ for (i=0; i<10; i++)
+ if ((v[i] > '9') || (v[i] < '0')) goto auq_err;
+ y = (v[0]-'0')*10+(v[1]-'0');
+ if (y < 50) y+=100;
+ M = (v[2]-'0')*10+(v[3]-'0');
+ if ((M > 12) || (M < 1)) goto auq_err;
+ d = (v[4]-'0')*10+(v[5]-'0');
+ h = (v[6]-'0')*10+(v[7]-'0');
+ m = (v[8]-'0')*10+(v[9]-'0');
+ if ( (v[10] >= '0') && (v[10] <= '9') &&
+ (v[11] >= '0') && (v[11] <= '9'))
+ s = (v[10]-'0')*10+(v[11]-'0');
+
+ // localize the date and display it.
+ qdate.setYMD(y+1900, M, d);
+ qtime.setHMS(h,m,s);
+ qdt.setDate(qdate); qdt.setTime(qtime);
+ auq_err:
+ if (isGmt) *isGmt = gmt;
+return qdt;
+}
+
+
+TQString ASN1_UTCTIME_QString(ASN1_UTCTIME *tm) {
+ TQString qstr;
+ int gmt;
+ TQDateTime qdt = ASN1_UTCTIME_QDateTime(tm, &gmt);
+
+ qstr = TDEGlobal::locale()->formatDateTime(qdt, false, true);
+ if (gmt) {
+ qstr += " ";
+ qstr += i18n("GMT");
+ }
+ return qstr;
+}
+
+
+TQString ASN1_INTEGER_QString(ASN1_INTEGER *aint) {
+char *rep = KOSSL::self()->i2s_ASN1_INTEGER(NULL, aint);
+TQString yy = rep;
+KOSSL::self()->OPENSSL_free(rep);
+return yy;
+}
+
+
+#endif
+
diff --git a/tdeio/kssl/ksslutils.h b/tdeio/kssl/ksslutils.h
new file mode 100644
index 000000000..4c087374f
--- /dev/null
+++ b/tdeio/kssl/ksslutils.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _INCLUDE_KSSLUTILS_H
+#define _INCLUDE_KSSLUTILS_H
+
+#include <kdemacros.h>
+
+#ifdef Q_WS_WIN
+#include "ksslconfig_win.h"
+#else
+#include "ksslconfig.h"
+#endif
+
+#include <unistd.h>
+#ifdef KSSL_HAVE_SSL
+#define crypt _openssl_crypt
+#include <openssl/x509.h>
+#undef crypt
+#endif
+class TQString;
+class TQDateTime;
+
+
+#ifdef KSSL_HAVE_SSL
+// This functionality is missing in OpenSSL
+/**
+ * Convert an ASN1 UTCTIME value to a string. Uses KLocale settings.
+ *
+ * @param tm the OpenSSL ASN1_UTCTIME pointer
+ *
+ * @return the date formatted in a QString
+ * @see ASN1_UTCTIME_QDateTime
+ */
+KDE_EXPORT TQString ASN1_UTCTIME_QString(ASN1_UTCTIME *tm);
+
+/**
+ * Convert an ASN1 UTCTIME value to a TQDateTime. Uses KLocale settings.
+ *
+ * @param tm the OpenSSL ASN1_UTCTIME pointer
+ * @param isGmt set to 1 if the date is set to GMT
+ *
+ * @return the date formatted in a QDateTime
+ */
+KDE_EXPORT TQDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt);
+
+
+/**
+ * Convert an ASN1 INTEGER value to a string.
+ *
+ * @param aint the OpenSSL ASN1_INTEGER pointer
+ *
+ * @return the number formatted in a QString
+ */
+KDE_EXPORT TQString ASN1_INTEGER_QString(ASN1_INTEGER *aint);
+#endif
+
+
+
+
+#endif
diff --git a/tdeio/kssl/ksslx509map.cc b/tdeio/kssl/ksslx509map.cc
new file mode 100644
index 000000000..7896fdfcf
--- /dev/null
+++ b/tdeio/kssl/ksslx509map.cc
@@ -0,0 +1,103 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 George Staikos <staikos@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 "ksslx509map.h"
+#include <tqstringlist.h>
+#include <tqregexp.h>
+
+KSSLX509Map::KSSLX509Map(const TQString& name) {
+ parse(name);
+}
+
+
+KSSLX509Map::~KSSLX509Map() {
+
+}
+
+
+void KSSLX509Map::setValue(const TQString& key, const TQString& value) {
+ m_pairs.replace(key, value);
+}
+
+
+TQString KSSLX509Map::getValue(const TQString& key) const {
+ if (!m_pairs.contains(key)) {
+ return TQString::null;
+ }
+
+ return m_pairs[key];
+}
+
+static TQStringList tokenizeBy(const TQString& str, const TQRegExp& tok, bool keepEmpties = false) {
+TQStringList tokens;
+unsigned int head, tail;
+const char *chstr = str.ascii();
+unsigned int length = str.length();
+
+ if (length < 1) {
+ return tokens;
+ }
+
+ if (length == 1) {
+ tokens.append(str);
+ return tokens;
+ }
+
+ for(head = 0, tail = 0; tail < length-1; head = tail+1) {
+ TQString thisline;
+
+ tail = str.find(tok, head);
+
+ if (tail > length) // last token - none at end
+ tail = length;
+
+ if (tail-head > 0 || keepEmpties) { // it has to be at least 1 long!
+ thisline = &(chstr[head]);
+ thisline.truncate(tail-head);
+ tokens.append(thisline);
+ }
+ }
+ return tokens;
+}
+
+
+void KSSLX509Map::parse(const TQString& name) {
+TQStringList vl = tokenizeBy(name, TQRegExp("/[A-Za-z]+="), false);
+
+ m_pairs.clear();
+
+ for (TQStringList::Iterator j = vl.begin(); j != vl.end(); ++j) {
+ TQStringList apair = tokenizeBy(*j, TQRegExp("="), false);
+ if (m_pairs.contains(apair[0])) {
+ TQString oldValue = m_pairs[apair[0]];
+ oldValue += "\n";
+ oldValue += apair[1];
+ m_pairs.replace(apair[0], oldValue);
+ } else {
+ m_pairs.insert(apair[0], apair[1]);
+ }
+ }
+}
+
+
+void KSSLX509Map::reset(const TQString& name) {
+ parse(name);
+}
+
diff --git a/tdeio/kssl/ksslx509map.h b/tdeio/kssl/ksslx509map.h
new file mode 100644
index 000000000..f76413100
--- /dev/null
+++ b/tdeio/kssl/ksslx509map.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000-2003 George Staikos <staikos@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 _KSSLX509MAP_H
+#define _KSSLX509MAP_H
+
+#include <tqmap.h>
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+/**
+ * X.509 Map Parsing Class
+ *
+ * This class is used to parse and store a map as used in X.509 certificates.
+ * It is of the form /name=value/name=value/name=value
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KSSL, KSSLCertificate
+ * @short X.509 Map Parser
+ */
+class TDEIO_EXPORT KSSLX509Map {
+public:
+ /**
+ * Construct an X.509 Map
+ *
+ * @param name the map to parse
+ */
+ KSSLX509Map(const TQString& name);
+
+ /**
+ * Destroy this map
+ */
+ ~KSSLX509Map();
+
+ /**
+ * Set a value in the map
+ *
+ * @param key the key
+ * @param value the value
+ */
+ void setValue(const TQString& key, const TQString& value);
+
+ /**
+ * Get the value of an entry in the map
+ *
+ * @param key the key
+ *
+ * @return the value
+ */
+ TQString getValue(const TQString& key) const;
+
+ /**
+ * Reset (clear) the internal storage.
+ *
+ * @param name if this is not empty, it will be parsed and used as
+ * the new map internally
+ */
+ void reset(const TQString& name = "");
+
+private:
+ class KSSLX509MapPrivate;
+ KSSLX509MapPrivate *d;
+ TQMap<TQString, TQString> m_pairs;
+
+ void parse(const TQString& name);
+};
+
+#endif
diff --git a/tdeio/kssl/ksslx509v3.cc b/tdeio/kssl/ksslx509v3.cc
new file mode 100644
index 000000000..a3310b9db
--- /dev/null
+++ b/tdeio/kssl/ksslx509v3.cc
@@ -0,0 +1,143 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001 George Staikos <staikos@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ksslx509v3.h"
+#include <kopenssl.h>
+#include <kdebug.h>
+
+
+KSSLX509V3::KSSLX509V3() {
+ flags = 0;
+}
+
+
+KSSLX509V3::~KSSLX509V3() {
+}
+
+
+/* When reading this, please remember that
+ * !A || B is logically equivalent to A => B
+ */
+
+bool KSSLX509V3::certTypeCA() {
+#ifdef KSSL_HAVE_SSL
+ // First try CA without X509_PURPOSE_ANY CA, then just try SSLCA
+ return (flags & (65471L << 16)) ? true : certTypeSSLCA();
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSSLCA() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & ((1 << (16+X509_PURPOSE_NS_SSL_SERVER-1))|
+ (1 << (16+X509_PURPOSE_SSL_SERVER-1))|
+ (1 << (16+X509_PURPOSE_SSL_CLIENT-1)))) ? true :
+ (false || ((1 << (16+X509_PURPOSE_ANY-1)) &&
+ (certTypeSSLServer() ||
+ certTypeSSLClient() ||
+ certTypeNSSSLServer())));
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeEmailCA() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & ((1 << (16+X509_PURPOSE_SMIME_ENCRYPT-1))|
+ (1 << (16+X509_PURPOSE_SMIME_SIGN-1)))) ? true :
+ (false || ((1 << (16+X509_PURPOSE_ANY-1)) &&
+ certTypeSMIME()));
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeCodeCA() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (16+X509_PURPOSE_ANY-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSSLClient() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_SSL_CLIENT-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSSLServer() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_SSL_SERVER-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeNSSSLServer() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_NS_SSL_SERVER-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSMIME() {
+#ifdef KSSL_HAVE_SSL
+ return certTypeSMIMEEncrypt()||certTypeSMIMESign();
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSMIMEEncrypt() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_SMIME_ENCRYPT-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeSMIMESign() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_SMIME_SIGN-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+bool KSSLX509V3::certTypeCRLSign() {
+#ifdef KSSL_HAVE_SSL
+ return (flags & (1 << (X509_PURPOSE_CRL_SIGN-1))) ? true : false;
+#endif
+ return false;
+}
+
+
+
+
+
diff --git a/tdeio/kssl/ksslx509v3.h b/tdeio/kssl/ksslx509v3.h
new file mode 100644
index 000000000..c521f3e25
--- /dev/null
+++ b/tdeio/kssl/ksslx509v3.h
@@ -0,0 +1,122 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2001-2003 George Staikos <staikos@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 _KSSLX509V3_H
+#define _KSSLX509V3_H
+
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+// ### KDE4: fix constness of methods
+/**
+ * KDE X509v3 Flag Class
+ *
+ * This class is used to track X509v3 flags for
+ *
+ * @author George Staikos <staikos@kde.org>
+ * @see KExtendedSocket, TCPSlaveBase
+ * @short KDE SSL Class
+ */
+class TDEIO_EXPORT KSSLX509V3 {
+friend class KSSLCertificate;
+friend class KSSLCertificatePrivate;
+public:
+ /**
+ * Destroy this object
+ */
+ ~KSSLX509V3();
+
+ /**
+ * Determine if this certificate can be used by a certificate authority
+ * @return true if it can be used by a certificate authority
+ */
+ bool certTypeCA();
+
+ /**
+ * Determine if this certificate can be used by an SSL signer
+ * @return true if it can be used by an SSL signer
+ */
+ bool certTypeSSLCA();
+
+ /**
+ * Determine if this certificate can be used by an S/MIME signer
+ * @return true if it can be used by an S/MIME signer
+ */
+ bool certTypeEmailCA();
+
+ /**
+ * Determine if this certificate can be used by a code certificate signer
+ * @return true if it can be used by a code certificate signer
+ */
+ bool certTypeCodeCA();
+
+ /**
+ * Determine if this certificate can be used by an SSL client
+ * @return true if it can be used by an SSL client
+ */
+ bool certTypeSSLClient();
+
+ /**
+ * Determine if this certificate can be used by an SSL server
+ * @return true if it can be used by an SSL server
+ */
+ bool certTypeSSLServer();
+
+ /**
+ * Determine if this certificate can be used by a Netscape SSL server
+ * @return true if it can be used by a Netscape SSL server
+ */
+ bool certTypeNSSSLServer();
+
+ /**
+ * Determine if this certificate can be used for S/MIME
+ * @return true if it can be used for S/MIME
+ */
+ bool certTypeSMIME();
+
+ /**
+ * Determine if this certificate can be used for S/MIME encryption
+ * @return true if it can be used for S/MIME encryption
+ */
+ bool certTypeSMIMEEncrypt();
+
+ /**
+ * Determine if this certificate can be used for S/MIME signing
+ * @return true if it can be used for S/MIME signing
+ */
+ bool certTypeSMIMESign();
+
+ /**
+ * Determine if this certificate can be used for revocation signing
+ * @return true if it can be used for revocation signing
+ */
+ bool certTypeCRLSign();
+
+private:
+ class KSSLX509V3Private;
+ KSSLX509V3Private *d;
+
+protected:
+ KSSLX509V3();
+ long flags; // warning: this is only valid for up to 16 flags + 16 CA.
+};
+
+#endif
diff --git a/tdeio/kurifilterplugin.desktop b/tdeio/kurifilterplugin.desktop
new file mode 100644
index 000000000..5882b35ca
--- /dev/null
+++ b/tdeio/kurifilterplugin.desktop
@@ -0,0 +1,84 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=KURIFilter/Plugin
+Name=Enhanced Browsing Plugin
+Name[af]=Verbeterde Blaaiïng Inprop module
+Name[ar]=ملحقات التصÙØ­ المحسن
+Name[az]=TÉ™kmilləşmiÅŸ SÉ™yyah ÆlavÉ™si
+Name[bg]=Разширена приÑтавка за преглед
+Name[bn]=উনà§à¦¨à¦¤ বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ পà§à¦²à¦¾à¦—-ইন
+Name[br]=Lugant Furchal Gwellaet
+Name[bs]=Dodatak za napredno pretraživanje
+Name[ca]=Connector de navegació millorada
+Name[cs]=Modul rozšířeného procházení
+Name[csb]=Mòduł do rozszérzónégò przezeraniô
+Name[cy]=Ategyn Pori Hwylusach
+Name[da]=Udvidet netsøgnings-plugin
+Name[de]=Erweitertes Browser-Modul
+Name[el]=ΠÏόσθετο βελτιωμένης εξεÏεÏνησης
+Name[eo]=progresinta TTTum-kromaĵo
+Name[es]=Plugin de Navegación Mejorada
+Name[et]=Täiustatud brausimise plugin
+Name[eu]=Arakatze plugin hobetua
+Name[fa]=وصلۀ مرور اÙزوده
+Name[fi]=Laajennettu selauslisäosa
+Name[fr]=Module externe de navigation avancée
+Name[fy]=Plugin foar effisjinter browsen
+Name[ga]=Breiseán le haghaidh Brabhsála Feabhsaithe
+Name[gl]=Plugin de Navegación Mellorada
+Name[he]=תוסף לגלישה משופרת
+Name[hi]=à¤à¤¨à¤¹à¥ˆà¤‚सà¥à¤¡ बà¥à¤°à¤¾à¤‰à¤¸à¤¿à¤‚ग पà¥à¤²à¤—इन
+Name[hr]=Napredni dodatak za pretraživanje
+Name[hu]=Továbbfejlesztett böngészés bővítőmodul
+Name[id]=Plugin Browsing yang disempurnakan
+Name[is]=Ãforrit fyrir vafrara-endurbætur
+Name[it]=Plugin di navigazione avanzata
+Name[ja]=拡張ブラウズプラグイン
+Name[ka]=დეტáƒáƒšáƒ£áƒ áƒ˜ ჩვენების მáƒáƒ“ული
+Name[kk]=Жетілдірген шарлау модулі
+Name[km]=កម្មវិធី​ជំនួយ​រុករក​ដែល​បាន​ធ្វើ​ឲ្យ​ប្រសើរ
+Name[ko]=ë” ë‚˜ì€ ì°¾ì•„ê°€ê¸° 플러그ì¸
+Name[lb]=Erweiderte Browser-Plugin
+Name[lt]=Išplėstinio naršymo priedas
+Name[lv]=Uzlabotas PÄrlÅ«koÅ¡anas spraudnis
+Name[mk]=Приклучок за напредно разгледување
+Name[mn]=ӨргөтгөÑөн Хөтлөгчийн Plugin
+Name[ms]=Plug masuk Pelayar Ekstra
+Name[mt]=Plagin għal browsing estiż
+Name[nb]=Programtillegg for utvidet nettlesing
+Name[nds]=Nettkiekverwiedern-Plugin
+Name[ne]=विसà¥à¤¤à¤¾à¤°à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ पà¥à¤²à¤—इन
+Name[nl]=Verbeterd Browsen Plugin
+Name[nn]=Programtillegg for forbetring av nettlesaren
+Name[nso]=Tsenyo yeo e Hlohleleditswego ya Boinyakisi
+Name[oc]=Branquament de navegacion amilhorada
+Name[pa]=ਵਾਧੂ à¨à¨²à¨•à¨¾à¨°à¨¾ ਪਲੱਗਿੰਨ
+Name[pl]=Moduł do rozszerzonego przeglądania
+Name[pt]=Navegação Melhorada
+Name[pt_BR]=Plug-in de navegação melhorada
+Name[ro]=Modul de navigare avansată
+Name[ru]=Модуль раÑширенного проÑмотра
+Name[rw]=Icomeka ry'Ishakisha Ritunganyijwe
+Name[se]=Njuovžilut fierbmádatlogadeami lassemoduvla
+Name[sk]=Modul rozšíreného prehliadaÄa
+Name[sl]=Vstavek za izboljšano brskanje
+Name[sq]=Shtojcë e Përmirësuar për Shfletim
+Name[sr]=Прикључак за побољшано претраживање
+Name[sr@Latn]=PrikljuÄak za poboljÅ¡ano pretraživanje
+Name[sv]=Utökad webbläsning
+Name[ta]=மேமà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯ உலாவà¯à®®à¯ சொரà¯à®•à¯à®ªà¯à®ªà¯Šà®°à¯à®³à¯
+Name[te]=à°…à°­à°¿à°µà±à°°à±à°¦à±à°¦à°¿à°ªà°°à°šà°¿à°¨ à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°ªà±à°²à°—à°¿à°¨à±
+Name[tg]=Баланд Кардан
+Name[th]=ปลั๊à¸à¸­à¸´à¸™à¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¸”ูที่เสริมความสามารถ
+Name[tr]=Gelişmiş Tarayıcı Eklentisi
+Name[tt]=Kiñäytelgän Küsätü Östämäse
+Name[uk]=Втулок розширеної навігації
+Name[uz]=Tezlashtirilgan veb-koʻrish plagini
+Name[uz@cyrillic]=Тезлаштирилган веб-кўриш плагини
+Name[ven]=Pulagini ya burausu yo engedzhwaho
+Name[vi]=Bá»™ cầm phít duyệt tăng cÆ°á»ng
+Name[xh]=Iplagi yangaphakathi Ekhangela iincwadi Enyusiweyo
+Name[zh_CN]=增强的æµè§ˆæ’件
+Name[zh_HK]=增強功能的ç€è¦½å¤–掛程å¼
+Name[zh_TW]=增強的ç€è¦½å¤–掛程å¼
+Name[zu]=I-plugin Yomcingi Weqophela eliphezulu
diff --git a/tdeio/magic b/tdeio/magic
new file mode 100644
index 000000000..c12cec4ba
--- /dev/null
+++ b/tdeio/magic
@@ -0,0 +1,1065 @@
+# Magic data for KMimeMagic (originally for file(1) command)
+#
+# The format is 4-5 columns:
+# Column #1: byte number to begin checking from, ">" indicates continuation
+# Column #2: type of data to match
+# Column #3: contents of data to match
+# Column #4: MIME type of result
+
+#------------------------------------------------------------------------------
+# Localstuff: file(1) magic for locally observed files
+# Add any locally observed files here.
+
+#------------------------------------------------------------------------------
+# end local stuff
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# audio: file(1) magic for sound formats (see also "iff")
+#
+# Jan Nicolai Langfeldt (janl@ifi.uio.no), Dan Quinlan (quinlan@yggdrasil.com),
+# and others
+#
+
+# Sun/NeXT audio data
+0 string .snd
+>12 belong 1 audio/basic
+>12 belong 2 audio/basic
+>12 belong 3 audio/basic
+>12 belong 4 audio/basic
+>12 belong 5 audio/basic
+>12 belong 6 audio/basic
+>12 belong 7 audio/basic
+
+>12 belong 23 audio/x-adpcm
+>12 belong 24 audio/x-adpcm
+>12 belong 25 audio/x-adpcm
+>12 belong 26 audio/x-adpcm
+>12 belong 27 audio/x-adpcm
+
+# DEC systems (e.g. DECstation 5000) use a variant of the Sun/NeXT format
+# that uses little-endian encoding and has a different magic number
+0 lelong 0x0064732E
+>12 lelong 1 audio/x-adpcm
+>12 lelong 2 audio/x-adpcm
+>12 lelong 3 audio/x-adpcm
+>12 lelong 4 audio/x-adpcm
+>12 lelong 5 audio/x-adpcm
+>12 lelong 6 audio/x-adpcm
+>12 lelong 7 audio/x-adpcm
+# compressed (G.721 ADPCM)
+>12 lelong 23 audio/x-adpcm
+
+# Creative Labs AUDIO stuff
+0 string MThd audio/x-midi
+#0 string CTMF Creative Music (CMF) data
+#0 string SBI SoundBlaster instrument data
+#0 string Creative\ Voice\ File Creative Labs voice data
+
+# Real Audio (Magic .ra\0375)
+0 belong 0x2e7261fd audio/vnd.rn-realaudio
+0 string .RMF application/vnd.rn-realmedia
+
+# OGG files
+# For theora at position 87, see bug #109598
+0 string OggS application/ogg
+>28 string \x01vorbis audio/vorbis
+>28 string fLaC audio/x-oggflac
+>28 string \x80theora video/x-theora
+>87 string \x80theora video/x-theora
+>28 string Speex\ \ audio/x-speex
+>29 string video video/x-ogm
+>29 string FLAC audio/x-oggflac
+
+# FLAC files
+0 string fLaC audio/x-flac
+
+# Musepack files
+0 string MP+ audio/x-musepack
+
+# C64 PSID sound files
+0 string PSID audio/prs.sid
+
+
+#------------------------------------------------------------------------------
+# riff: file(1) magic for RIFF format
+# See
+#
+# http://www.seanet.com/users/matts/riffmci/riffmci.htm
+#
+
+# RIFF (little-endian) data
+0 string RIFF
+# RIFF MIDI format
+#>8 string RMID audio/x-midi?
+# Microsoft WAVE format (*.wav)
+>8 string WAVE audio/x-wav
+>>20 leshort 80 audio/mpeg
+>>20 leshort 85 audio/x-mp3
+# Corel Draw Picture
+#>8 string CDRA Corel Draw Picture
+# AVI == Audio Video Interleave
+>8 string AVI\040 video/x-msvideo
+
+# RIFF (big-endian) data
+0 string RIFX
+# RIFF MIDI format
+#>8 string RMID \b, MIDI
+# Microsoft WAVE format (*.wav)
+>8 string WAVE audio/x-wav
+# Corel Draw Picture
+#>8 string CDRA \b, Corel Draw Picture
+# AVI == Audio Video Interleave
+>8 string AVI\040 video/x-msvideo
+
+
+#------------------------------------------------------------------------------
+# iff: file(1) magic for Interchange File Format (see also "audio" & "images")
+#
+# Daniel Quinlan (quinlan@yggdrasil.com) -- IFF was designed by Electronic
+# Arts for file interchange. It has also been used by Apple, SGI, and
+# especially Commodore-Amiga.
+#
+# IFF files begin with an 8 byte FORM header, followed by a 4 character
+# FORM type, which is followed by the first chunk in the FORM.
+
+0 string FORM
+>8 string AIFF audio/x-aiff
+# AIFF-C audio data
+>8 string AIFC audio/x-aiff
+# IFF/8SVX audio data
+>8 string 8SVX audio/x-aiff
+#>8 string SAMP \b, SAMP sampled audio
+#>8 string DTYP \b, DTYP datatype description
+#>8 string PTCH \b, PTCH binary patch
+# image formats
+#>8 string ILBMBMHD \b, ILBM interleaved image
+# other formats
+#>8 string FTXT \b, FTXT formatted text
+
+#------------------------------------------------------------------------------
+# KSysV stuff: logfiles and packages belonging to KSysV
+#
+
+# KSysV logfiles
+0 string KDE\ System\ V\ Init\ Editor text/x-ksysv-log
+
+# KSysV init packages
+4 string KSysV
+>15 byte >0x01 application/x-ksysv-package
+
+#------------------------------------------------------------------------------
+# c-lang: file(1) magic for C programs or various scripts
+#
+
+# XPM icons (Greg Roelofs, newt@uchicago.edu)
+# ideally should go into "images", but entries below would tag XPM as C source
+0 string /*\ XPM image/x-xpm
+
+# this first will upset you if you're a PL/1 shop... (are there any left?)
+# in which case rm it; ascmagic will catch real C programs
+# C or REXX program text
+#0 string /* text/x-c
+# C++ program text
+#0 string // text/x-c++
+
+#------------------------------------------------------------------------------
+# commands: file(1) magic for various shells and interpreters
+#
+#0 string :\ shell archive or commands for antique kernel text
+0 string #!/bin/sh application/x-shellscript
+0 string #!\ /bin/sh application/x-shellscript
+0 string #!/bin/csh application/x-shellscript
+0 string #!\ /bin/csh application/x-shellscript
+# korn shell magic, sent by George Wu, gwu@clyde.att.com
+0 string #!/bin/ksh application/x-shellscript
+0 string #!\ /bin/ksh application/x-shellscript
+0 string #!/bin/zsh application/x-shellscript
+0 string #!\ /bin/zsh application/x-shellscript
+0 string #!/bin/tcsh application/x-shellscript
+0 string #!\ /bin/tcsh application/x-shellscript
+0 string #!/usr/local/tcsh application/x-shellscript
+0 string #!\ /usr/local/tcsh application/x-shellscript
+0 string #!/usr/local/bin/tcsh application/x-shellscript
+0 string #!\ /usr/local/bin/tcsh application/x-shellscript
+# /usr/bin paths for ksh, zsh and tcsh
+0 string #!/usr/bin/ksh application/x-shellscript
+0 string #!\ /usr/bin/ksh application/x-shellscript
+0 string #!/usr/bin/zsh application/x-shellscript
+0 string #!\ /usr/bin/zsh application/x-shellscript
+0 string #!/usr/bin/tcsh application/x-shellscript
+0 string #!\ /usr/bin/tcsh application/x-shellscript
+# bash shell magic, from Peter Tobias (tobias@server.et-inf.fho-emden.de)
+0 string #!/bin/bash application/x-shellscript
+0 string #!\ /bin/bash application/x-shellscript
+0 string #!/usr/local/bin/bash application/x-shellscript
+0 string #!\ /usr/local/bin/bash application/x-shellscript
+
+0 string #!\ /bin/env\ bash application/x-shellscript
+0 string #!/bin/env\ bash application/x-shellscript
+0 string #!\ /usr/bin/env\ bash application/x-shellscript
+0 string #!/usr/bin/env\ bash application/x-shellscript
+
+#
+0 string #!/bin/ash application/x-shellscript
+0 string #!\ /bin/ash application/x-shellscript
+# zsh/ash/ae/nawk/gawk magic from cameron@cs.unsw.oz.au (Cameron Simpson)
+0 string #!/usr/local/bin/zsh application/x-shellscript
+0 string #!\ /usr/local/bin/zsh application/x-shellscript
+0 string #!/usr/local/bin/ash application/x-shellscript
+0 string #!\ /usr/local/bin/ash application/x-shellscript
+#0 string #!/usr/local/bin/ae Neil Brown's ae
+#0 string #!\ /usr/local/bin/ae Neil Brown's ae
+0 string #!/bin/nawk application/x-nawk
+0 string #!\ /bin/nawk application/x-nawk
+0 string #!/usr/bin/nawk application/x-nawk
+0 string #!\ /usr/bin/nawk application/x-nawk
+0 string #!/usr/local/bin/nawk application/x-nawk
+0 string #!\ /usr/local/bin/nawk application/x-nawk
+0 string #!/bin/gawk application/x-gawk
+0 string #!\ /bin/gawk application/x-gawk
+0 string #!/usr/bin/gawk application/x-gawk
+0 string #!\ /usr/bin/gawk application/x-gawk
+0 string #!/usr/local/bin/gawk application/x-gawk
+0 string #!\ /usr/local/bin/gawk application/x-gawk
+#
+0 string #!/bin/awk application/x-awk
+0 string #!\ /bin/awk application/x-awk
+0 string #!/usr/bin/awk application/x-awk
+0 string #!\ /usr/bin/awk application/x-awk
+#0 string BEGIN application/x-awk
+
+# For Larry Wall's perl language. The ``eval'' line recognizes an
+# outrageously clever hack for USG systems.
+# Keith Waclena <keith@cerberus.uchicago.edu>
+0 string #!/bin/perl application/x-perl
+0 string #!\ /bin/perl application/x-perl
+0 string eval\ "exec\ /bin/perl application/x-perl
+0 string #!/usr/bin/perl application/x-perl
+0 string #!\ /usr/bin/perl application/x-perl
+0 string eval\ "exec\ /usr/bin/perl application/x-perl
+0 string #!/usr/local/bin/perl application/x-perl
+0 string #!\ /usr/local/bin/perl application/x-perl
+0 string eval\ "exec\ /usr/local/bin/perl application/x-perl
+0 string #!/bin/env\ perl application/x-perl
+0 string #!\ /bin/env\ perl application/x-perl
+0 string #!/usr/bin/env\ perl application/x-perl
+0 string #!\ /usr/bin/env\ perl application/x-perl
+
+# python.
+#
+0 string #!/bin/python application/x-python
+0 string #!\ /bin/python application/x-python
+0 string eval\ "exec\ /bin/python application/x-python
+0 string #!/usr/bin/python application/x-python
+0 string #!\ /usr/bin/python application/x-python
+0 string eval\ "exec\ /usr/bin/python application/x-python
+0 string #!/usr/local/bin/python application/x-python
+0 string #!\ /usr/local/bin/python application/x-python
+0 string eval\ "exec\ /usr/local/bin/python application/x-python
+0 string #!/bin/env\ python application/x-python
+0 string #!\ /bin/env\ python application/x-python
+0 string #!/usr/bin/env\ python application/x-python
+0 string #!\ /usr/bin/env\ python application/x-python
+
+# MAGIC as specified in Python/import.c (1.5 to 2.3.0a)
+# 20121 ( YEAR - 1995 ) + MONTH + DAY (little endian followed by "\r\n"
+# python 1.5/1.6 byte-compiled
+0 belong 0x994e0d0a application/x-python-bytecode
+# python 2.0 byte-compiled
+0 belong 0x87c60d0a application/x-python-bytecode
+# python 2.1 byte-compiled
+0 belong 0x2aeb0d0a application/x-python-bytecode
+# python 2.2 byte-compiled
+0 belong 0x2ded0d0a application/x-python-bytecode
+# python 2.3 byte-compiled
+0 belong 0x3bf20d0a application/x-python-bytecode
+
+# ruby
+0 string #!/bin/env\ ruby application/x-ruby
+0 string #!\ /bin/env\ ruby application/x-ruby
+0 string #!/usr/bin/env\ ruby application/x-ruby
+0 string #!\ /usr/bin/env\ ruby application/x-ruby
+
+#------------------------------------------------------------------------------
+# compress: file(1) magic for pure-compression formats (no archives)
+#
+# compress, gzip, pack, compact, huf, squeeze, crunch, freeze, yabba, whap, etc.
+#
+# Formats for various forms of compressed data
+# Formats for "compress" proper have been moved into "compress.c",
+# because it tries to uncompress it to figure out what's inside.
+
+# standard unix compress
+0 string \037\235 application/x-compress
+
+# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver)
+0 string \037\213 application/x-gzip
+
+# KOffice documents (gzipped, with an idenfication string in the 'orig filename' header)
+>10 string KOffice
+>>18 string application/x-kchart\004\006 application/x-kchart
+>>18 string application/x-kformula\004\006 application/x-kformula
+>>18 string application/x-killustrator\004\006 application/x-killustrator
+>>18 string application/x-kontour\004\006 application/x-kontour
+>>18 string application/x-kpresenter\004\006 application/x-kpresenter
+>>18 string application/x-kspread\004\006 application/x-kspread
+>>18 string application/x-kword\004\006 application/x-kword
+>>18 string application/x-krita\004\006 application/x-krita
+>>18 string application/x-kivio\004\006 application/x-kivio
+>>18 string application/x-karbon\004\006 application/x-karbon
+
+# Rosegarden documents (like old KOffice documents, gzipped with id string in header)
+>10 string audio/x-rosegarden\000 audio/x-rosegarden
+>10 string audio/x-rosegarden-device\000 audio/x-rosegarden-device
+
+#KOffice documents v1.2 and later (may 1 2002) using zip as a wrapper
+0 string PK\003\004 application/x-zip
+>30 string mimetype
+>>38 string application/x-kchart application/x-kchart
+>>38 string application/x-kformula application/x-kformula
+>>38 string application/x-kontour application/x-kontour
+>>38 string application/x-kpresenter application/x-kpresenter
+>>38 string application/x-kspread application/x-kspread
+>>38 string application/x-krita application/x-krita
+>>38 string application/x-kword application/x-kword
+>>38 string application/x-kivio application/x-kivio
+>>38 string application/x-karbon application/x-karbon
+
+#KOffice documents writen using the kzip rewrite used 'unx' based
+#zips; dislocating the mimetype. This was (temporarily) for koffice 1.3 (okt 2003).
+0 string PK\003\004
+>30 string mimetype
+>>55 string application/x-kchart application/x-kchart
+>>55 string application/x-kformula application/x-kformula
+>>55 string application/x-kontour application/x-kontour
+>>55 string application/x-kpresenter application/x-kpresenter
+>>55 string application/x-kspread application/x-kspread
+>>55 string application/x-krita application/x-krita
+>>55 string application/x-kword application/x-kword
+>>55 string application/x-kivio application/x-kivio
+>>55 string application/x-karbon application/x-karbon
+
+# OpenOffice.org 1.1 puts the mimetype into the header too
+0 string PK\003\004
+>30 string mimetype
+>>38 string application/vnd.sun.xml.calc application/vnd.sun.xml.calc
+>>38 string application/vnd.sun.xml.calc.template application/vnd.sun.xml.calc.template
+>>38 string application/vnd.sun.xml.draw application/vnd.sun.xml.draw
+>>38 string application/vnd.sun.xml.draw.template application/vnd.sun.xml.draw.template
+>>38 string application/vnd.sun.xml.impress application/vnd.sun.xml.impress
+>>38 string application/vnd.sun.xml.impress.template application/vnd.sun.xml.impress.template
+>>38 string application/vnd.sun.xml.writer application/vnd.sun.xml.writer
+>>38 string application/vnd.sun.xml.writer.master application/vnd.sun.xml.writer.master
+>>38 string application/vnd.sun.xml.writer.template application/vnd.sun.xml.writer.template
+>>38 string application/vnd.sun.xml.base application/vnd.sun.xml.base
+
+# OASIS OpenDocument (KOffice >= 1.4 and OpenOffice >= 2.0)
+0 string PK\003\004
+>30 string mimetype
+>>38 string application/vnd.oasis.opendocument.chart application/vnd.oasis.opendocument.chart
+>>38 string application/vnd.oasis.opendocument.formula application/vnd.oasis.opendocument.formula
+>>38 string application/vnd.oasis.opendocument.graphics application/vnd.oasis.opendocument.graphics
+>>38 string application/vnd.oasis.opendocument.graphics-template application/vnd.oasis.opendocument.graphics-template
+>>38 string application/vnd.oasis.opendocument.image application/vnd.oasis.opendocument.image
+>>38 string application/vnd.oasis.opendocument.presentation application/vnd.oasis.opendocument.presentation
+>>38 string application/vnd.oasis.opendocument.presentation-template application/vnd.oasis.opendocument.presentation-template
+>>38 string application/vnd.oasis.opendocument.spreadsheet application/vnd.oasis.opendocument.spreadsheet
+>>38 string application/vnd.oasis.opendocument.spreadsheet-template application/vnd.oasis.opendocument.spreadsheet-template
+>>38 string application/vnd.oasis.opendocument.text application/vnd.oasis.opendocument.text
+>>38 string application/vnd.oasis.opendocument.text-template application/vnd.oasis.opendocument.text-template
+
+# BZIP2
+0 string BZh application/x-bzip2
+
+# BZIP
+0 string BZ application/x-bzip
+
+# According to gzip.h, this is the correct byte order for packed data.
+0 string \037\036 application/octet-stream
+#
+# This magic number is byte-order-independent.
+#
+0 short 017437 application/octet-stream
+
+
+# ID Software's pak data archive
+0 string PACK application/x-pak
+
+# XXX - why *two* entries for "compacted data", one of which is
+# byte-order independent, and one of which is byte-order dependent?
+#
+# compacted data
+0 short 0x1fff application/octet-stream
+0 string \377\037 application/octet-stream
+# huf output
+0 short 0145405 application/octet-stream
+
+# Squeeze and Crunch...
+# These numbers were gleaned from the Unix versions of the programs to
+# handle these formats. Note that I can only uncrunch, not crunch, and
+# I didn't have a crunched file handy, so the crunch number is untested.
+# Keith Waclena <keith@cerberus.uchicago.edu>
+#0 leshort 0x76FF squeezed data (CP/M, DOS)
+#0 leshort 0x76FE crunched data (CP/M, DOS)
+
+# Freeze
+#0 string \037\237 Frozen file 2.1
+#0 string \037\236 Frozen file 1.0 (or gzip 0.5)
+
+# lzh?
+#0 string \037\240 LZH compressed data
+
+#POSIX tar archive
+257 string ustar\0 application/x-tar
+#GNU tar archive
+257 string ustar\040\040\0 application/x-tar
+
+# The SVR4 "cpio(4)" hints that there are additional formats, but they
+# are defined as "short"s; I think all the new formats are
+# character-header formats and thus are strings, not numbers.
+0 short 070707 application/x-cpio
+0 short 0143561 application/x-cpio
+0 string 070707 application/x-cpio
+0 string 070701 application/x-cpio
+0 string 070702 application/x-cpio
+
+0 string !<arch>\ndebian application/x-debian-package
+0 string =<ar> application/x-archive
+0 string !<arch> application/x-archive
+
+#------------------------------------------------------------------------------
+#
+# RPM: file(1) magic for Red Hat Packages Erik Troan (ewt@redhat.com)
+#
+0 beshort 0xedab
+>2 beshort 0xeedb application/x-rpm
+
+# lzw
+0 lelong&0x8080ffff 0x0000081a application/x-arc
+# squashed
+0 lelong&0x8080ffff 0x0000091a application/x-arc
+# uncompressed
+0 lelong&0x8080ffff 0x0000021a application/x-arc
+# packed
+0 lelong&0x8080ffff 0x0000031a application/x-arc
+# squeezed
+0 lelong&0x8080ffff 0x0000041a application/x-arc
+# crunched
+0 lelong&0x8080ffff 0x0000061a application/x-arc
+
+# LHARC/LHA archiver (Greg Roelofs, newt@uchicago.edu)
+2 string -lh0- application/x-lha
+2 string -lh1- application/x-lha
+2 string -lz4- application/x-lha
+2 string -lz5- application/x-lha
+# [never seen any but the last; -lh4- reported in comp.compression:]
+2 string -lzs- application/x-lha
+2 string -lh\40- application/x-lha
+2 string -lhd- application/x-lha
+2 string -lh2- application/x-lha
+2 string -lh3- application/x-lha
+2 string -lh4- application/x-lha
+2 string -lh5- application/x-lha
+2 string -lh6- application/x-lha
+2 string -lh7- application/x-lha
+
+# ARJ archiver (jason@jarthur.Claremont.EDU)
+0 leshort 0xea60 application/x-arj
+
+# RAR archiver (Greg Roelofs, newt@uchicago.edu)
+0 string Rar! application/x-rar
+
+# ZIP archives (Greg Roelofs, c/o zip-bugs@wkuvx1.wku.edu)
+0 string PK\003\004 application/x-zip
+# Alternate ZIP string (amc@arwen.cs.berkeley.edu)
+0 string PK00PK\003\004 application/x-zip
+
+# Zoo archiver
+20 lelong 0xfdc4a7dc application/x-zoo
+
+# Shell archives
+10 string #\ This\ is\ a\ shell\ archive application/x-shellscript
+
+# ACE archive
+7 string **ACE** application/x-ace
+
+
+#------------------------------------------------------------------------------
+# frame: file(1) magic for FrameMaker files
+#
+# This stuff came on a FrameMaker demo tape, most of which is
+# copyright, but this file is "published" as witness the following:
+#
+0 string \<MakerFile application/x-frame
+0 string \<MIFFile application/x-frame
+0 string \<MakerDictionary application/x-frame
+0 string \<MakerScreenFon application/x-frame
+0 string \<MML application/x-frame
+0 string \<Book application/x-frame
+0 string \<Maker application/x-frame
+
+#------------------------------------------------------------------------------
+# html: file(1) magic for HTML (HyperText Markup Language) docs
+#
+# from Daniel Quinlan <quinlan@yggdrasil.com>
+#
+0 string \<HEAD text/html
+0 string \<head text/html
+0 string \<BODY text/html
+0 string \<body text/html
+0 string \<TITLE text/html
+0 string \<title text/html
+0 string \<html text/html
+0 string \<HTML text/html
+0 string \<!-- text/html
+0 string \<h1 text/html
+0 string \<H1 text/html
+0 string \<!doctype\ HTML text/html
+0 string \<!DOCTYPE\ HTML text/html
+0 string \<!doctype\ html text/html
+0 string \<!DOCTYPE\ html text/html
+
+# PHP (offset should be "between 0 and 64"...)
+0 string \<?php application/x-php
+
+# Docbook
+0 string \<!doctype\ book\ public\ "-//OASIS//DTD\ DocBook text/docbook
+# Hack: <?xml (with version but no encoding etc.) with a docbook mimetype afterwards.
+0 string \<?xml
+>23 string \<!doctype\ book\ public\ "-//OASIS//DTD\ DocBook text/docbook
+>23 string \<!DOCTYPE\ book\ PUBLIC\ "-//OASIS//DTD\ DocBook text/docbook
+>23 string \<!doctype\ book\ public\ "-//KDE//DTD\ DocBook text/docbook
+>23 string \<!DOCTYPE\ book\ PUBLIC\ "-//KDE//DTD\ DocBook text/docbook
+
+# Extensible markup language (XML), a subset of SGML
+# from Marc Prud'hommeaux (marc@apocalypse.org)
+0 string \<?xml text/xml
+0 string \<?XML text/xml
+0 string \<?Xml text/xml
+
+
+#-----------------------------------------------------------------------------
+# troff stuff
+#
+0 string .\\" application/x-troff
+0 string '\\" application/x-troff
+0 string '.\\" application/x-troff
+0 string \\" application/x-troff
+
+#------------------------------------------------------------------------------
+# images: file(1) magic for image formats (see also "c-lang" for XPM bitmaps)
+#
+# originally from jef@helios.ee.lbl.gov (Jef Poskanzer),
+# additions by janl@ifi.uio.no as well as others. Jan also suggested
+# merging several one- and two-line files into here.
+#
+# XXX - byte order for GIF and TIFF fields?
+# [GRR: TIFF allows both byte orders; GIF is probably little-endian]
+#
+
+# [GRR: what the hell is this doing in here?]
+#0 string xbtoa btoa'd file
+
+# PBMPLUS
+# PBM file
+0 string P1 image/x-portable-bitmap
+# PGM file
+0 string P2 image/x-portable-greymap
+# PPM file
+0 string P3 image/x-portable-pixmap
+# PBM "rawbits" file
+0 string P4 image/x-portable-bitmap
+# PGM "rawbits" file
+0 string P5 image/x-portable-greymap
+# PPM "rawbits" file
+0 string P6 image/x-portable-pixmap
+
+# NIFF (Navy Interchange File Format, a modification of TIFF)
+# [GRR: this *must* go before TIFF]
+0 string IIN1 image/x-niff
+
+0 string II\x2a\x00
+>8 string CR\x02 image/x-raw
+
+# Phase One RAW image, big-endian
+32 string MMMMRawT image/x-raw
+# Phase One RAW image, little-endian
+32 string IIIITwaR image/x-raw
+# Canon RAW image
+6 string HEAPCCDR image/x-raw
+# Canon CR2 image (20D, 1Dmk2, ...)
+0 string II*\000\020\000\000\000CR image/x-raw
+# Minolta RAW image
+0 string \x00MRM image/x-raw
+# Fuji RAW image
+0 string FUJIFILM image/x-raw
+# Rollei RAW image
+0 string DSC-Image image/x-raw
+# Foveon RAW image
+0 string FOVb image/x-raw
+
+# TIFF and friends
+# TIFF file, big-endian
+0 string MM\x00\x2a image/tiff
+# TIFF file, little-endian
+0 string II\x2a\x00 image/tiff
+
+# GIF
+0 string GIF image/gif
+
+# JPEG images
+0 beshort 0xffd8 image/jpeg
+
+# JPEG2000 images
+0 beshort 0x0101010C6A50 image/jp2
+
+# PNG images
+0 string \x89PNG image/png
+
+# PC bitmaps (OS/2, Windoze BMP files) (Greg Roelofs, newt@uchicago.edu)
+0 string BM
+#(OS/2 1.x format)
+>14 byte 12 image/x-bmp
+#(OS/2 2.x format)
+>14 byte 64 image/x-bmp
+# (Windows 3.x format)
+>14 byte 40 image/x-bmp
+
+# PCX images (Nadeem Hasan)
+0 byte 10
+# Version 2.5
+>1 byte 0 image/x-pcx
+# Version 2.8 w/ palette
+>1 byte 2 image/x-pcx
+# Version 2.8 w/o pallete
+>1 byte 3 image/x-pcx
+# Version 3.0
+>1 byte 5 image/x-pcx
+
+#0 string IC icon
+#0 string PI pointer
+#0 string CI color icon
+#0 string CP color pointer
+#0 string BA bitmap array
+
+# Gimp's XCF
+0 string gimp\ xcf image/x-xcf-gimp
+
+# X11 cursor files
+0 string Xcur image/x-xcursor
+
+# EXR images
+0 lelong 0x762f3101 image/x-exr
+
+# SGI images (*.rgb, *.rgba, *.bw, *.sgi)
+0 beshort 474 image/x-rgb
+
+#------------------------------------------------------------------------------
+# lisp: file(1) magic for lisp programs
+#
+# various lisp types, from Daniel Quinlan (quinlan@yggdrasil.com)
+#0 string ;; text/plain
+# Emacs 18 - this is always correct, but not very magical.
+0 string \012( application/x-elc
+# Emacs 19
+0 string ;ELC\023\000\000\000 application/x-elc
+
+#------------------------------------------------------------------------------
+# mail.news: file(1) magic for mail and news
+#
+# There are tests to ascmagic.c to cope with mail and news.
+
+0 string Relay-Version: message/rfc822
+0 string #!\ rnews message/rfc822
+0 string N#!\ rnews message/rfc822
+0 string Forward\ to message/rfc822
+0 string Pipe\ to message/rfc822
+0 string Return-Path: message/rfc822
+0 string Return-Path: message/rfc822
+0 string Path: message/news
+0 string Xref: message/news
+0 string From: message/rfc822
+0 string From\x20 application/mbox
+0 string Article message/news
+#0 string BABYL message/x-gnu-rmail
+0 string Received: message/rfc822
+
+
+
+# TNEF files...
+0 lelong 0x223E9F78 application/ms-tnef
+
+
+#------------------------------------------------------------------------------
+# mswrite
+
+0 lelong 0xBE31 application/x-mswrite
+# with OLE objects
+0 lelong 0xBE32 application/x-mswrite
+
+#------------------------------------------------------------------------------
+# msword: file(1) magic for MS Word files
+#
+# Contributor claims:
+# Reversed-engineered MS Word magic numbers
+# Except that they are generic MSOffice magic numbers ! (DF)
+
+0 string \376\067\0\043 application/msword
+0 string \320\317\021\340\241\261 application/msword
+0 string \333\245-\0\0\0 application/msword
+2080 string Microsoft\ Word\ 6.0\ Document application/msword
+2112 string Microsoft\ Word\ document\ data application/msword
+
+# excel
+2080 string Microsoft\ Excel\ 5.0\ Worksheet application/msexcel
+
+#------------------------------------------------------------------------------
+# word perfect
+
+0 belong 0xff575053c405 application/wordperfect
+1 string WPC application/wordperfect
+
+#------------------------------------------------------------------------------
+# printer: file(1) magic for printer-formatted files
+#
+
+# PostScript
+0 string %! application/postscript
+>15 string EPS image/x-eps
+0 string \004%! application/postscript
+>16 string EPS image/x-eps
+
+# Acrobat
+0 string %PDF- application/pdf
+0 string \n%PDF- application/pdf
+
+#------------------------------------------------------------------------------
+# sc: file(1) magic for "sc" spreadsheet
+#
+38 string Spreadsheet application/x-sc
+
+#------------------------------------------------------------------------------
+# tex: file(1) magic for TeX files
+#
+# XXX - needs byte-endian stuff (big-endian and little-endian DVI?)
+#
+# From <conklin@talisman.kaleida.com>
+
+# Although we may know the offset of certain text fields in TeX DVI
+# and font files, we can't use them reliably because they are not
+# zero terminated. [but we do anyway, christos]
+0 string \367\002 application/x-dvi
+#0 string \367\203 TeX generic font data
+#0 string \367\131 TeX packed font data
+#0 string \367\312 TeX virtual font data
+# Maybe we should have a mimetype like x-tex-log, but in any case
+# text/plain is better than nothing. (David Faure)
+0 string This\ is\ TeX, text/plain
+0 string This\ is\ METAFONT, text/plain
+
+# XXX promoted from tex so that *.tfm is not mis-identified as mc68k file.
+# There is no way to detect TeX Font Metric (*.tfm) files without
+# breaking them apart and reading the data. The following patterns
+# match most *.tfm files generated by METAFONT or afm2tfm.
+2 string \000\021 application/x-tex-tfm
+>33 string >\0 application/x-tex-tfm
+2 string \000\022 application/x-tex-tfm
+>33 string >\0 application/x-tex-tfm
+
+# Texinfo and GNU Info, from Daniel Quinlan (quinlan@yggdrasil.com)
+#0 string \\input\ texinfo Texinfo source text
+#0 string This\ is\ Info\ file GNU Info text
+
+# correct TeX magic for Linux (and maybe more)
+# from Peter Tobias (tobias@server.et-inf.fho-emden.de)
+#
+0 leshort 0x02f7 application/x-dvi
+
+# RTF - Rich Text Format
+0 string {\\rtf text/rtf
+
+# UTF16 (UTF16 docs are not MP3s - see the next audio/x-mp3 check :))
+0 beshort 0xfffe text/plain
+
+#------------------------------------------------------------------------------
+# animation: file(1) magic for animation/movie formats
+#
+# animation formats
+# MPEG, FLI, DL originally from vax@ccwf.cc.utexas.edu (VaX#n8)
+# FLC, SGI, Apple originally from Daniel Quinlan (quinlan@yggdrasil.com)
+
+# MPEG animation format
+0 belong 0x000001b3 video/mpeg
+0 belong 0x000001ba video/mpeg
+
+# MPEG 1.0 audio (layer III,II,I)
+0 beshort&0xfff8 0xfff8
+>0 beshort&0x0006 0x0002 audio/x-mp3
+>0 beshort&0x0006 0x0004 audio/x-mp2
+>0 beshort&0x0006 0x0006 audio/mpeg
+
+# MPEG 2.0 audio (layer III,II,I)
+0 beshort&0xfff8 0xfff0
+>0 beshort&0x0006 0x0002 audio/x-mp3
+>0 beshort&0x0006 0x0004 audio/x-mp2
+>0 beshort&0x0006 0x0006 audio/mpeg
+
+# MPEG 2.5 audio (layer III,II,I)
+0 beshort&0xfff8 0xff80
+>0 beshort&0x0006 0x0002 audio/x-mp3
+>0 beshort&0x0006 0x0004 audio/x-mp2
+>0 beshort&0x0006 0x0006 audio/mpeg
+
+# MPEG-4 audio
+16 string M4A audio/mp4
+
+
+# FLI animation format
+0 leshort 0xAF11 video/x-flic
+# FLC animation format
+0 leshort 0xAF12 video/x-flic
+
+# SGI and Apple formats
+0 string MOVI video/sgi
+4 string moov video/quicktime
+4 string mdat video/quicktime
+4 string wide video/quicktime
+4 string free video/quicktime
+
+# DIF digital video file format <mpruett@sgi.com>
+#0 belong&0xffffff00 0x1f070000 DIF
+
+# Microsoft Advanced Streaming Format (ASF) <mpruett@sgi.com>
+0 belong 0x3026b275 video/x-ms-asf
+
+# MNG Video Format, <URL:http://www.libpng.org/pub/mng/spec/>
+0 string \x8aMNG video/x-mng
+
+# JNG Video Format, <URL:http://www.libpng.org/pub/mng/spec/>
+#0 string \x8bJNG JNG video data,
+
+# Vivo video (Wolfram Kleff)
+#3 string \x0D\x0AVersion:Vivo Vivo video data
+
+# VRML (Virtual Reality Modelling Language)
+#0 string/b #VRML\ V1.0\ ascii VRML 1 file
+#0 string/b #VRML\ V2.0\ utf8 ISO/IEC 14772 VRML 97 file
+
+#------------------------------------------------------------------------------
+# Databases
+#
+# GDBM magic numbers
+# Will be maintained as part of the GDBM distribution in the future.
+# <downsj@teeny.org>
+0 belong 0x13579ace application/x-gdbm
+0 lelong 0x13579ace application/x-gdbm
+0 string GDBM application/x-gdbm
+#
+0 belong 0x061561 application/x-dbm
+#
+# Executables
+#
+0 string \177ELF
+>4 byte 0
+>4 byte 1
+>4 byte 2
+>5 byte 0
+>5 byte 1
+>>16 leshort 0
+>>16 leshort 1 application/x-object
+>>16 leshort 2 application/x-executable
+>>16 leshort 3 application/x-sharedlib
+>>16 leshort 4 application/x-core
+>5 byte 2
+>>16 beshort 0
+>>16 beshort 1 application/x-object
+>>16 beshort 2 application/x-executable
+>>16 beshort 3 application/x-sharedlib
+>>16 beshort 4 application/x-core
+
+# MS Access database (95 or newer, i.e. MS Jet 3.0 or newer)
+4 string Standard\ Jet\ DB application/x-msaccess
+
+#
+# DOS
+0 string MZ application/x-msdos-program
+#
+# KDE desktop file
+0 string [Desktop\ Entry] application/x-desktop
+0 string [Desktop\ Action application/x-desktop
+0 string [KDE\ Desktop\ Entry] application/x-desktop
+0 string \#\ Config\ File application/x-desktop
+0 string \#\ KDE\ Config\ File application/x-desktop
+# xmcd database file for kscd
+0 string \#\ xmcd text/xmcd
+# SQLite database files
+0 string **\ This\ file\ contains\ an\ SQLite application/x-sqlite2
+0 string SQLite\ format\ 3 application/x-sqlite3
+
+#------------------------------------------------------------------------------
+# Java
+
+0 short 0xcafe
+>2 short 0xbabe application/x-java
+
+# vcard / vcalendar
+0 string BEGIN:VCALENDAR text/x-vcalendar
+0 string begin:vcalendar text/x-vcalendar
+0 string BEGIN:VCARD text/x-vcard
+0 string begin:vcard text/x-vcard
+
+# LDIF / LDAP interchange format
+0 string dn:\ cn= text/x-ldif
+
+# applix
+#------------------------------------------------------------------------------
+# applix: file(1) magic for Applixware
+# From: Peter Soos <sp@osb.hu>
+#
+0 string *BEGIN
+>7 string WORDS application/x-applixword
+>7 string GRAPHICS application/x-applixgraphics
+#>7 string RASTER application/x-applix
+>7 string SPREADSHEETS application/x-applixspread
+#>7 string MACRO application/x-applix
+#>7 string BUILDER application/x-applix
+
+#------------------------------------------------------------------------------
+# diff: file(1) magic for diff(1) output
+#
+0 string diff\ text/x-diff
+0 string ***\ text/x-diff
+0 string Only\ in\ text/x-diff
+0 string Common\ subdirectories:\ text/x-diff
+
+
+#------------------------------------------------------------------------------
+# flash: file(1) magic for Macromedia Flash file format
+#
+# See
+#
+# http://www.macromedia.com/software/flash/open/
+#
+0 string FWS application/x-shockwave-flash
+
+#------------------------------------------------------------------------------
+# DjVu (Leon Bottou <leonb@research.att.com>):
+#
+4 string FORM
+>12 string DJVU image/x-djvu
+>12 string DJVM image/x-djvu
+>12 string BM44 image/x-djvu
+>12 string PM44 image/x-djvu
+
+#------------------------------------------------------------------------------
+# adi: file(1) magic for ADi's objects
+# From Gregory McGarry <g.mcgarry@ieee.org>
+#
+0 leshort 0x521c application/x-executable # COFF DSP21k
+>18 lelong &02 application/x-executable # executable,
+>18 lelong ^02
+>>18 lelong &01 application/x-executable # static object,
+>>18 lelong ^01 application/x-executable # relocatable object,
+>18 lelong &010 application/x-executable # stripped
+>18 lelong ^010 application/x-executable # not stripped
+
+#------------------------------------------------------------------------------
+# alliant: file(1) magic for Alliant FX series a.out files
+#
+# If the FX series is the one that had a processor with a 68K-derived
+# instruction set, the "short" should probably become "beshort" and the
+# "long" should probably become "belong".
+# If it's the i860-based one, they should probably become either the
+# big-endian or little-endian versions, depending on the mode they ran
+# the 860 in....
+#
+0 short 0420 application/x-executable # 0420 Alliant virtual executable
+>2 short &0x0020 application/x-sharedlib # common library
+>16 long >0 application/x-sharedlib # not stripped
+0 short 0421 application/x-executable # 0421 Alliant compact executable
+>2 short &0x0020 application/x-sharedlib # common library
+>16 long >0 application/x-sharedlib # not stripped
+#-----------------------------------------------------------
+
+# alpha architecture description
+#
+
+0 leshort 0603 application/x-executable # COFF format alpha
+>22 leshort&030000 !020000 application/x-executable # executable
+>24 leshort 0410 application/x-executable # pure
+>24 leshort 0413 application/x-executable # paged
+>22 leshort&020000 !0 application/x-executable # dynamically linked
+>16 lelong !0 application/x-executable # not stripped
+>16 lelong 0 application/x-executable # stripped
+>22 leshort&030000 020000 application/x-sharedlib # shared library
+>24 leshort 0407 application/x-executable # object
+
+# Basic recognition of Digital UNIX core dumps - Mike Bremford <mike@opac.bl.uk>
+#
+# The actual magic number is just "Core", followed by a 2-byte version
+# number; however, treating any file that begins with "Core" as a Digital
+# UNIX core dump file may produce too many false hits, so we include one
+# byte of the version number as well; DU 5.0 appears only to be up to
+# version 2.
+#
+0 string Core\001 application/x-core # Alpha COFF format core dump (Digital UNIX)
+0 string Core\002 application/x-core # Alpha COFF format core dump (Digital UNIX)
+
+#------------------------------------------------------------------------------
+# Win95 InternetShortcut (URL): (Helge Deller <deller@gmx.de>):
+#
+1 string InternetShortcut application/x-mswinurl
+
+#------------------------------------------------------------------------------
+# amigaos: file(1) magic for AmigaOS binary formats:
+
+#
+# From ignatios@cs.uni-bonn.de (Ignatios Souvatzis)
+# Some formats are still missing: AmigaOS special IFF's, e.g.: FORM....CTLG
+# (the others should be separate, anyway)
+#
+0 belong 0x000003f3 application/x-executable # AmigaOS loadseg()ble executable/binary
+0 belong 0x000003e7 application/x-sharedlib # AmigaOS object/library data
+
+0 string %TGIF application/x-tgif
+
+0 string #FIG application/x-xfig
+0 string #LyX\ 1 application/x-lyx
+
+#------------------------------------------------------------------------------
+# VRML
+0 string #VRML model/vrml
+
+#------------------------------------------------------------------------------
+# KWallet file
+0 string KWALLET\012\015\000\015\012 application/x-kde-wallet
+
+#------------------------------------------------------------------------------
+# ICA Client configuration files
+0 string [WFClient] application/x-ica
+1 string [WFClient] application/x-ica
+0 string [ApplicationServers] application/x-ica
+1 string [ApplicationServers] application/x-ica
+0 string [ICA application/x-ica
+1 string [ICA application/x-ica
+0 string [Program\ Neighborhood application/x-ica
+1 string [Program\ Neighborhood application/x-ica
+
+#------------------------------------------------------------------------------
+# CD image files (ISO is imported from file 4.07)
+32769 string CD001 application/x-iso
+32633 string CD001 application/x-iso
+
+# CDR-wins bin-with-cue files
+#0 belong 0x00FFFFFF application/x-cuebin
+
+# FITS (see RFC 4047)
+# The SIMPLE keyword is always on the first line, NAXIS on the third.
+# Lines are supposed to be exactly 80 characters long.
+# FITS files can be different but then they are not application/fits anymore.
+0 string SIMPLE\ \ =\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ T application/fits
+>160 string NAXIS\ \ \ =\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 2 image/fits
+>160 string NAXIS\ \ \ =\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 3 image/fits
+
+# kate: space-indent off; replace-tabs off;
diff --git a/tdeio/misc/CMakeLists.txt b/tdeio/misc/CMakeLists.txt
new file mode 100644
index 000000000..3bfdb0980
--- /dev/null
+++ b/tdeio/misc/CMakeLists.txt
@@ -0,0 +1,100 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+add_subdirectory( tdesendbugmail )
+add_subdirectory( kpac )
+add_subdirectory( tdesasl )
+add_subdirectory( kssld )
+add_subdirectory( tdefile )
+add_subdirectory( tdewalletd )
+add_subdirectory( tdentlm )
+
+add_definitions(
+ -D_LARGEFILE64_SOURCE
+)
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_BINARY_DIR}/tdeio
+ ${CMAKE_BINARY_DIR}/tdeio/tdeio
+ ${CMAKE_BINARY_DIR}/tdeio/kssl
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdefx
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/kssl
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install( FILES uiserver.h DESTINATION ${INCLUDE_INSTALL_DIR}/tdeio )
+
+
+##### other data ################################
+
+install(FILES
+ tdeio_uiserver.desktop tdemailservice.protocol
+ telnet.protocol rlogin.protocol rtsp.protocol
+ ssh.protocol mms.protocol mmst.protocol mmsu.protocol
+ pnm.protocol rtspt.protocol rtspu.protocol
+ DESTINATION ${SERVICES_INSTALL_DIR} )
+
+install( FILES fileshareset DESTINATION ${BIN_INSTALL_DIR}
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE SETUID )
+
+
+#### tdeio_uiserver ###############################
+
+set( target tdeio_uiserver )
+
+set( ${target}_SRCS
+ uiserver.cpp uiserver.skel
+)
+
+tde_add_tdeinit_executable( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeio-shared
+ DEPENDENCIES dcopidl
+)
+
+
+##### tdemailservice ##############################
+
+set( target tdemailservice )
+
+tde_add_executable( ${target}
+ SOURCES ${target}.cpp
+ LINK tdecore-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
+
+
+##### tdetelnetservice ############################
+
+set( target tdetelnetservice )
+
+tde_add_executable( ${target}
+ SOURCES ${target}.cpp
+ LINK tdeui-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
+
+tde_install_symlink( ${target} ${BIN_INSTALL_DIR}/filesharelist )
diff --git a/tdeio/misc/Makefile.am b/tdeio/misc/Makefile.am
new file mode 100644
index 000000000..6a250cf8a
--- /dev/null
+++ b/tdeio/misc/Makefile.am
@@ -0,0 +1,60 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Torben Weis (weis@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.
+
+AM_CPPFLAGS = -D_LARGEFILE64_SOURCE
+
+INCLUDES= -I$(srcdir)/.. -I$(top_srcdir) -I$(srcdir)/../kssl -I../kssl $(all_includes) $(SSL_INCLUDES)
+
+SUBDIRS = . tdesendbugmail kpac tdesasl kssld tdefile tdewalletd tdentlm
+
+lib_LTLIBRARIES =
+tdeinit_LTLIBRARIES = tdeio_uiserver.la
+bin_PROGRAMS = tdemailservice tdetelnetservice
+
+observer_DIR = $(top_srcdir)/tdeio/tdeio
+
+tdeio_uiserver_la_SOURCES = uiserver.cpp uiserver.skel observer.stub
+tdeio_uiserver_la_LIBADD = $(LIB_KIO) $(LIB_TDEUI) $(LIB_QT) $(top_builddir)/dcop/libDCOP.la $(LIB_TDECORE)
+tdeio_uiserver_la_LDFLAGS = $(all_libraries) -module -avoid-version
+
+METASOURCES = AUTO
+
+kde_services_DATA = tdeio_uiserver.desktop
+
+tdemailservice_SOURCES = tdemailservice.cpp
+tdemailservice_LDADD = $(LIB_TDECORE)
+tdemailservice_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+
+tdetelnetservice_SOURCES = tdetelnetservice.cpp
+tdetelnetservice_LDADD = $(LIB_TDEUI)
+tdetelnetservice_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+
+protocol_DATA = tdemailservice.protocol telnet.protocol rlogin.protocol rtsp.protocol ssh.protocol \
+ mms.protocol mmst.protocol mmsu.protocol pnm.protocol rtspt.protocol rtspu.protocol
+protocoldir = $(kde_servicesdir)
+
+kiomiscdir = $(includedir)/tdeio
+kiomisc_HEADERS = uiserver.h
+
+
+bin_SCRIPTS = fileshareset
+install-exec-local:
+ @-rm -f $(DESTDIR)$(bindir)/filesharelist
+ @$(LN_S) fileshareset $(DESTDIR)$(bindir)/filesharelist
+ @(chown root $(DESTDIR)$(bindir)/fileshareset && chmod 4755 $(DESTDIR)$(bindir)/fileshareset) || echo "Was not able to make fileshareset setuid root"
+
diff --git a/tdeio/misc/fileshareset b/tdeio/misc/fileshareset
new file mode 100755
index 000000000..4c921ba38
--- /dev/null
+++ b/tdeio/misc/fileshareset
@@ -0,0 +1,430 @@
+#!/usr/bin/perl -T
+use strict;
+
+########################################
+# config files
+$nfs_exports::default_options = '*(ro,all_squash)';
+$nfs_exports::conf_file = '/etc/exports';
+$smb_exports::conf_file = '/etc/samba/smb.conf';
+my $authorisation_file = '/etc/security/fileshare.conf';
+my $authorisation_group = 'fileshare';
+
+
+########################################
+# Copyright (C) 2001-2002 MandrakeSoft (pixel@mandrakesoft.com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+########################################
+my $uid = $<;
+my $username = getpwuid($uid);
+
+########################################
+# errors
+my $usage =
+"usage: fileshareset --add <dir>
+ fileshareset --remove <dir>";
+my $not_enabled =
+qq(File sharing is not enabled.
+To enable file sharing put
+"FILESHARING=yes" in $authorisation_file);
+
+my $not_simple_enabled =
+qq(Simple file sharing is not enabled.
+To enable simple file sharing put
+"SHARINGMODE=simple" in $authorisation_file);
+
+my $non_authorised =
+qq(You are not authorised to use file sharing
+To grant you the rights:
+- put "RESTRICT=no" in $authorisation_file
+- or put user "$username" in group "$authorisation_group");
+
+my $no_export_method = "can't export anything: no nfs, no smb";
+
+my %exit_codes = reverse (
+ 1 => $non_authorised,
+ 2 => $usage,
+
+# when adding
+ 3 => "already exported",
+ 4 => "invalid mount point",
+
+# when removing
+ 5 => "not exported",
+
+ 6 => $no_export_method,
+
+ 7 => $not_enabled,
+
+ 8 => $not_simple_enabled,
+
+ 255 => "various",
+);
+
+################################################################################
+# correct PATH needed to call /etc/init.d/... ? seems not, but...
+%ENV = ();#(PATH => '/bin:/sbin:/usr/bin:/usr/sbin');
+
+my $modify = $0 =~ /fileshareset/;
+
+authorisation::check($modify);
+
+my @exports = (
+ -e $nfs_exports::conf_file ? nfs_exports::read() : (),
+ -e $smb_exports::conf_file ? smb_exports::read() : (),
+ );
+@exports or error($no_export_method);
+
+if ($modify) {
+ my ($cmd, $dir) = @ARGV;
+ $< = $>;
+ @ARGV == 2 && ($cmd eq '--add' || $cmd eq '--remove') or error($usage);
+
+ verify_mntpoint($dir);
+
+ if ($cmd eq '--add') {
+ my @errs = map { eval { $_->add($dir) }; $@ } @exports;
+ grep { !$_ } @errs or error("already exported");
+ } else {
+ my @errs = map { eval { $_->remove($dir) }; $@ } @exports;
+ grep { !$_ } @errs or error("not exported");
+ }
+ foreach my $export (@exports) {
+ $export->write;
+ $export->update_server;
+ }
+}
+my @mntpoints = grep {$_} uniq(map { map { $_->{mntpoint} } @$_ } @exports);
+print "$_\n" foreach grep { own($_) } @mntpoints;
+
+
+sub own { $uid == 0 || (stat($_[0]))[4] == $uid }
+
+sub verify_mntpoint {
+ local ($_) = @_;
+ my $ok = 1;
+ $ok &&= m|^/|;
+ $ok &&= !m|/\.\./|;
+ $ok &&= !m|[\0\n\r]|;
+ $ok &&= -d $_;
+ $ok &&= own($_);
+ $ok or error("invalid mount point");
+}
+
+sub error {
+ my ($string) = @_;
+ print STDERR "$string\n";
+ exit($exit_codes{$string} || 255);
+}
+sub member { my $e = shift; foreach (@_) { $e eq $_ and return 1 } 0 }
+sub uniq { my %l; $l{$_} = 1 foreach @_; grep { delete $l{$_} } @_ }
+
+
+################################################################################
+package authorisation;
+
+sub read_conf {
+ my ($exclusive_lock) = @_;
+ open F_lock, $authorisation_file; # don't care if it's missing
+ flock(F_lock, $exclusive_lock ? 2 : 1) or die "can't lock";
+ my %conf;
+ foreach (<F_lock>) {
+ s/#.*//; # remove comments
+ s/^\s+//;
+ s/\s+$//;
+ /^$/ and next;
+ my ($cmd, $value) = split('=', $_, 2);
+ $conf{$cmd} = $value || warn qq(suspicious line "$_" in $authorisation_file\n);
+ }
+ # no close F_lock, keep it locked
+ \%conf
+}
+
+sub check {
+ my ($exclusive_lock) = @_;
+ my $conf = read_conf($exclusive_lock);
+ if (lc($conf->{FILESHARING}) eq 'no') {
+ ::error($not_enabled);
+ }
+
+ if (lc($conf->{SHARINGMODE}) eq 'advanced') {
+ ::error($not_simple_enabled);
+ }
+
+ if (lc($conf->{FILESHAREGROUP} ne '')) {
+ $authorisation_group = lc($conf->{FILESHAREGROUP});
+ }
+
+ if (lc($conf->{RESTRICT}) eq 'no') {
+ # ok, access granted for everybody
+ } else {
+ my @l;
+ while (@l = getgrent) {
+ last if $l[0] eq $authorisation_group;
+ }
+ ::member($username, split(' ', $l[3])) or ::error($non_authorised);
+ }
+}
+
+################################################################################
+package exports;
+
+sub find {
+ my ($exports, $mntpoint) = @_;
+ foreach (@$exports) {
+ $_->{mntpoint} eq $mntpoint and return $_;
+ }
+ undef;
+}
+
+sub add {
+ my ($exports, $mntpoint) = @_;
+ foreach (@$exports) {
+ $_->{mntpoint} eq $mntpoint and die 'add';
+ }
+ push @$exports, my $e = { mntpoint => $mntpoint };
+ $e;
+}
+
+sub remove {
+ my ($exports, $mntpoint) = @_;
+ my @l = grep { $_->{mntpoint} ne $mntpoint } @$exports;
+ @l < @$exports or die 'remove';
+ @$exports = @l;
+}
+
+
+################################################################################
+package nfs_exports;
+
+use vars qw(@ISA $conf_file $default_options);
+BEGIN { @ISA = 'exports' }
+
+sub read {
+ my $file = $conf_file;
+ local *F;
+ open F, $file or return [];
+
+ my ($prev_raw, $prev_line, %e, @l);
+ my $line_nb = 0;
+ foreach my $raw (<F>) {
+ $line_nb++;
+ local $_ = $raw;
+ $raw .= "\n" if !/\n/;
+
+ s/#.*//; # remove comments
+
+ s/^\s+//;
+ s/\s+$//; # remove unuseful spaces to help regexps
+
+ if (/^$/) {
+ # blank lines ignored
+ $prev_raw .= $raw;
+ next;
+ }
+
+ if (/\\$/) {
+ # line continue across lines
+ chop; # remove the backslash
+ $prev_line .= "$_ ";
+ $prev_raw .= $raw;
+ next;
+ }
+ my $line = $prev_line . $_;
+ my $raw_line = $prev_raw . $raw;
+ ($prev_line, $prev_raw) = ('', '');
+
+ my ($mntpoint, $options) = $line =~ /("[^"]*"|\S+)\s+(.*)/ or die "$file:$line_nb: bad line $line\n";
+
+ # You can also specify spaces or any other unusual characters in the
+ # export path name using a backslash followed by the character code as
+ # 3 octal digits.
+ $mntpoint =~ s/\\(\d{3})/chr(oct $1)/ge;
+
+ # not accepting weird characters that would break the output
+ $mntpoint =~ m/[\0\n\r]/ and die "i won't handle this";
+ push @l, { mntpoint => $mntpoint, option => $options, raw => $raw_line };
+ }
+ bless \@l, 'nfs_exports';
+}
+
+sub write {
+ my ($nfs_exports) = @_;
+ foreach (@$nfs_exports) {
+ if (!exists $_->{options}) {
+ $_->{options} = $default_options;
+ }
+ if (!exists $_->{raw}) {
+ my $mntpoint = $_->{mntpoint} =~ /\s/ ? qq("$_->{mntpoint}") : $_->{mntpoint};
+ $_->{raw} = sprintf("%s %s\n", $mntpoint, $_->{options});
+ }
+ }
+ local *F;
+ open F, ">$conf_file" or die "can't write $conf_file";
+ print F $_->{raw} foreach @$nfs_exports;
+}
+
+sub update_server {
+ if (fork) {
+ system('/usr/sbin/exportfs', '-r');
+ if (system('PATH=/bin:/sbin pidof rpc.mountd >/dev/null') != 0 ||
+ system('PATH=/bin:/sbin pidof nfsd >/dev/null') != 0) {
+ # trying to start the server...
+ system('/etc/init.d/portmap start') if system('/etc/init.d/portmap status') != 0;
+ if ( -f '/etc/init.d/nfs' ) {
+ system('/etc/init.d/nfs', $_) foreach 'stop', 'start';
+ }
+ elsif ( -f '/etc/init.d/nfs-kernel-server' ) {
+ system('/etc/init.d/nfs-kernel-server', $_) foreach 'stop', 'start';
+ }
+ }
+ exit 0;
+ }
+}
+
+################################################################################
+package smb_exports;
+
+use vars qw(@ISA $conf_file);
+BEGIN { @ISA = 'exports' }
+
+sub read {
+ my ($s, @l);
+ local *F;
+ open F, $conf_file;
+ local $_;
+ while (<F>) {
+ if (/^\s*\[.*\]/ || eof F) {
+ #- first line in the category
+ my ($label) = $s =~ /^\s*\[(.*)\]/;
+ my ($mntpoint) = $s =~ /^\s*path\s*=\s*(.*)/m;
+ push @l, { mntpoint => $mntpoint, raw => $s, label => $label };
+ $s = '';
+ }
+ $s .= $_;
+ }
+ bless \@l, 'smb_exports';
+}
+
+sub write {
+ my ($smb_exports) = @_;
+ foreach (@$smb_exports) {
+ if (!exists $_->{raw}) {
+ $_->{raw} = <<EOF;
+
+[$_->{label}]
+ path = $_->{mntpoint}
+ comment = $_->{mntpoint}
+ public = yes
+ guest ok = yes
+ writable = no
+ wide links = no
+EOF
+ }
+ }
+ local *F;
+ open F, ">$conf_file" or die "can't write $conf_file";
+ print F $_->{raw} foreach @$smb_exports;
+}
+
+sub add {
+ my ($exports, $mntpoint) = @_;
+ my $e = $exports->exports::add($mntpoint);
+ $e->{label} = name_mangle($mntpoint, map { $_->{label} } @$exports);
+}
+
+sub name_mangle {
+ my ($input, @others) = @_;
+
+ local $_ = $input;
+
+ # 1. first only keep legal characters. "/" is also kept for the moment
+ tr|a-z|A-Z|;
+ s|[^A-Z0-9#\-_!/]|_|g; # "$" is allowed except at the end, remove it in any case
+
+ # 2. removing non-interesting parts
+ s|^/||;
+ s|^home/||;
+ s|_*/_*|/|g;
+ s|_+|_|g;
+
+ # 3. if size is too small (!), make it bigger
+ $_ .= "_" while length($_) < 3;
+
+ # 4. if size is too big, shorten it
+ while (length > 12) {
+ my ($s) = m|.*?/(.*)|;
+ if (length($s) > 8 && !grep { /\Q$s/ } @others) {
+ # dropping leading directories when the resulting is still long and meaningful
+ $_ = $s;
+ next;
+ }
+ s|(.*)[0-9#\-_!/]|$1| and next;
+
+ # inspired by "Christian Brolin" "Long names are doom" on comp.lang.functional
+ s|(.+)[AEIOU]|$1| and next; # allButFirstVowels
+ s|(.*)(.)\2|$1$2| and next; # adjacentDuplicates
+
+ s|(.*).|$1|; # booh, :'-(
+ }
+
+ # 5. remove "/"s still there
+ s|/|_|g;
+
+ # 6. resolving conflicts
+ my $l = join("|", map { quotemeta } @others);
+ my $conflicts = qr|^($l)$|;
+ if (/$conflicts/) {
+ A: while (1) {
+ for (my $nb = 1; length("$_$nb") <= 12; $nb++) {
+ if ("$_$nb" !~ /$conflicts/) {
+ $_ = "$_$nb";
+ last A;
+ }
+ }
+ $_ or die "can't find a unique name";
+ # can't find a unique name, dropping the last letter
+ s|(.*).|$1|;
+ }
+ }
+
+ # 7. done
+ $_;
+}
+
+sub update_server {
+ if (fork) {
+ system('/usr/bin/killall -HUP smbd 2>/dev/null');
+ if (system('PATH=/bin:/sbin pidof smbd >/dev/null') != 0 ||
+ system('PATH=/bin:/sbin pidof nmbd >/dev/null') != 0) {
+# trying to start the server...
+ if ( -f '/etc/init.d/smb' ) {
+ system('/etc/init.d/smb', $_) foreach 'stop', 'start';
+ }
+ elsif ( -f '/etc/init.d/samba' ) {
+ system('/etc/init.d/samba', $_) foreach 'stop', 'start';
+ }
+ elsif ( -f '/etc/rc.d/rc.samba' ) {
+ system('/etc/rc.d/rc.samba', $_) foreach 'stop', 'start';
+ }
+ else {
+ print STDERR "Error: Can't find the samba init script \n";
+ }
+ }
+ exit 0;
+ }
+}
diff --git a/tdeio/misc/kpac/CMakeLists.txt b/tdeio/misc/kpac/CMakeLists.txt
new file mode 100644
index 000000000..14af52de1
--- /dev/null
+++ b/tdeio/misc/kpac/CMakeLists.txt
@@ -0,0 +1,66 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_BINARY_DIR}/kjs
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore/network
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+ ${CMAKE_SOURCE_DIR}/kded
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+##### other data ################################
+
+install(FILES proxyscout.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded )
+install(FILES eventsrc DESTINATION ${DATA_INSTALL_DIR}/proxyscout )
+
+
+##### kded_proxyscout ###########################
+
+set( target kded_proxyscout )
+
+set( ${target}_SRCS
+ proxyscout.cpp proxyscout.skel script.cpp
+ downloader.cpp discovery.cpp
+)
+
+set( ${target}_SKELS
+ proxyscout.h
+)
+
+tde_add_kpart( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeinit_kded-shared kjs-shared ${RESOLV_LIBRARIES}
+ DEPENDENCIES dcopidl
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
+
+
+##### kpac_dhcp_helper ##########################
+
+set( target kpac_dhcp_helper )
+
+# FIXME on Gentoo this binary is not suided
+tde_add_executable( ${target} SETUID
+ SOURCES kpac_dhcp_helper.c
+ DESTINATION ${BIN_INSTALL_DIR}
+)
diff --git a/tdeio/misc/kpac/Makefile.am b/tdeio/misc/kpac/Makefile.am
new file mode 100644
index 000000000..beb6a4b86
--- /dev/null
+++ b/tdeio/misc/kpac/Makefile.am
@@ -0,0 +1,30 @@
+
+kde_module_LTLIBRARIES = kded_proxyscout.la
+bin_PROGRAMS = kpac_dhcp_helper
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libltdl -I$(top_srcdir)/kded -I$(top_builddir)/kjs \
+ -I$(top_srcdir)/tdecore/network $(all_includes)
+METASOURCES = AUTO
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+kded_proxyscout_la_SOURCES = proxyscout.skel proxyscout.cpp script.cpp \
+ downloader.cpp discovery.cpp
+kded_proxyscout_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_proxyscout_la_LIBADD = $(LIB_KIO) $(top_builddir)/kjs/libkjs.la $(LIB_KDED) $(LIB_QT) \
+ $(top_builddir)/dcop/libDCOP.la $(LIB_TDECORE) $(LIBRESOLV)
+
+kpac_dhcp_helper_SOURCES = kpac_dhcp_helper.c
+kpac_dhcp_helper_CFLAGS = $(KDE_USE_FPIE)
+kpac_dhcp_helper_LDFLAGS = $(KDE_USE_PIE)
+kpac_dhcp_helper_LDADD = $(LIBSOCKET)
+
+noinst_HEADERS = proxyscout.h script.h downloader.h discovery.h
+
+servicesdir = $(kde_servicesdir)/kded
+services_DATA = proxyscout.desktop
+
+proxyscoutdatadir = $(kde_datadir)/proxyscout
+proxyscoutdata_DATA = eventsrc
+
+install-exec-local:
+ @(chown root $(DESTDIR)$(bindir)/kpac_dhcp_helper && chmod 4755 $(DESTDIR)$(bindir)/kpac_dhcp_helper) || echo "Please make kpac_dhcp_helper setuid root"
diff --git a/tdeio/misc/kpac/README b/tdeio/misc/kpac/README
new file mode 100644
index 000000000..d211ae07b
--- /dev/null
+++ b/tdeio/misc/kpac/README
@@ -0,0 +1,9 @@
+Proxy Auto Configuration is a means to use a JavaScript function to
+determine the proxy to use based on the requested URL.
+It is described in detail here:
+http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html
+
+Also implemented by this library are parts of the now expired Internet Draft
+at http://www.wrec.org/Drafts/draft-cooper-webi-wpad-00.txt about WPAD
+(Web Proxy Automatic Discovery). The discovery implemented discovery methods
+are DHCP and DNS "Well known Aliases".
diff --git a/tdeio/misc/kpac/README.wpad b/tdeio/misc/kpac/README.wpad
new file mode 100644
index 000000000..f63d25764
--- /dev/null
+++ b/tdeio/misc/kpac/README.wpad
@@ -0,0 +1,73 @@
+Web Proxy Auto Discovery (WPAD)
+===============================
+
+This README is intended for network administrators who want to enable the
+users on their network to fully automatically find the proxy settings.
+
+Automatic proxy discovery works in two steps:
+1) Find a configuration script
+2) Determine a proxy to use by running that script
+
+The configuration script is a "PAC" (JavaScript) file just as in plain Proxy
+Auto Configuration as described here:
+http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html
+
+The WPAD part of the process (#1 above) described here is about how to find
+this script without having the users enter its URL into the proxy settings.
+(All they have to do in a WPAD-enabled network is to select "Automatically
+detected script file" in KDE's proxy setup.
+
+There are two alternative ways to discover the PAC script's URL implemented
+in KDE:
+
+1. DHCP based autodiscovery
+
+ If you are running a DHCP server on your network anyway, you might
+ want to use this approach; all you have to do is to add the WPAD
+ option (numeric 252 or hex fc) as a string containing the URL to the
+ PAC script.
+
+ To do so with older versions of ISC dhcpd, add this to
+ /etc/dhcpd.conf, either globally or just for the subnets you want to
+ enable WPAD for:
+
+ option option-252 "http://example.com/path/to/proxyconfig.pac";
+
+ Or, for newer ISC dhcpd versions, add this globally:
+
+ option wpad code 252 = text;
+
+ and this either globally or for the WPAD subnets:
+
+ option wpad "http://example.com/path/to/proxyconfig.pac";
+
+ For other DHCP servers, please consult the reference manual on how
+ to add an option by number if WPAD support is not built-in.
+
+2. DNS based autodiscovery
+
+ If you don't run a DHCP server or prefer DNS based discovery, you
+ need to configure one of your hosts to have the name
+ wpad.example.com and make sure the PAC script is available as
+ http://wpad.example.com/wpad.dat If your network consists of several
+ subdomains, like a.example.com and b.example.com you can either
+ provide both http://a.example.com/wpad.dat and
+ http://b.example.com/wpad.dat or just http://example.com/wpad.dat
+ When a client searches for that script, it will search for a host
+ named "wpad" in its own domain, then in the next higher level domain
+ until success or if only the TLD is left (i.e. wpad.com will never
+ be tried)
+
+Note that DHCP is the preferred approach since it's more flexible than DNS
+as it doesn't require a well known host name nor a fixed location
+(/wpad.dat) for the PAC script. It is also the first method tried before
+resorting to DNS, so if you use DNS there will be a noticeable delay of 5
+seconds while waiting for a DHCP reply.
+
+However, DHCP requires a helper program, kpac_dhcp_helper to be installed
+suid root. If you consider this a security problem, just delete that program
+or remove its suid permissions and use DNS instead. If the helper cannot
+execute as root, the 5 seconds delay will also go away.
+
+If you have further questions or comments, please contact me: Malte
+Starostik <malte@kde.org>
diff --git a/tdeio/misc/kpac/TODO b/tdeio/misc/kpac/TODO
new file mode 100644
index 000000000..ce5cd6a11
--- /dev/null
+++ b/tdeio/misc/kpac/TODO
@@ -0,0 +1 @@
+* Make use of badProxy() in KProtocolManager to enable fallbacks
diff --git a/tdeio/misc/kpac/configure.in.in b/tdeio/misc/kpac/configure.in.in
new file mode 100644
index 000000000..a65b9a1c8
--- /dev/null
+++ b/tdeio/misc/kpac/configure.in.in
@@ -0,0 +1,26 @@
+dnl some setgroups() implementations seem to have short* instead of gid_t*
+dnl and use some flags in the fiels that follows the gids
+AC_MSG_CHECKING([for setgroups with short argument])
+AC_CACHE_VAL([kde_cv_shortsetgroups],[
+ AC_TRY_RUN([
+ int main()
+ {
+ short x[4];
+ x[0] = x[1] = 1;
+ if (getgroups(1, x) == 0) if (setgroups(1, x) == -1) exit(1);
+
+ if (getgroups(1, x) == -1) exit(1);
+ if (x[1] != 1) exit(1);
+ x[1] = 2;
+ if (getgroups(1, x) == -1) exit(1);
+ if (x[1] != 2) exit(1);
+ exit(0);
+ }
+ ],[kde_cv_shortsetgroups="yes"],[kde_cv_shortsetgroups="no"])
+])
+AC_MSG_RESULT($kde_cv_shortsetgroups)
+if test "$kde_cv_shortsetgroups" = "yes"; then
+ AC_DEFINE(HAVE_SHORTSETGROUPS,1,[if setgroups() takes short *as second arg])
+fi
+
+AC_CHECK_HEADERS(arpa/nameser8_compat.h sys/param.h)
diff --git a/tdeio/misc/kpac/dhcp.h b/tdeio/misc/kpac/dhcp.h
new file mode 100644
index 000000000..41643ae3a
--- /dev/null
+++ b/tdeio/misc/kpac/dhcp.h
@@ -0,0 +1,78 @@
+/* This file is part of the KDE Libraries
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+
+/* See RFC 2131 for details */
+
+#ifndef __dhcp_h__
+#define __dhcp_h__
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#define DHCP_OPT_LEN 312
+
+struct dhcp_msg
+{
+#define DHCP_BOOTREQUEST 1
+#define DHCP_BOOTREPLY 2
+ uint8_t op; /* operation */
+ uint8_t htype; /* hwaddr type */
+ uint8_t hlen; /* hwaddr len */
+ uint8_t hops;
+ uint32_t xid; /* transaction id */
+ uint16_t secs; /* seconds since protocol start */
+#define DHCP_BROADCAST 1
+ uint16_t flags;
+ uint32_t ciaddr; /* client IP */
+ uint32_t yiaddr; /* "your" IP */
+ uint32_t siaddr; /* server IP */
+ uint32_t giaddr; /* gateway IP */
+ uint8_t chaddr[16]; /* client hwaddr */
+ uint8_t sname[64]; /* server name */
+ uint8_t file[128]; /* bootstrap file */
+ uint8_t options[DHCP_OPT_LEN];
+};
+
+/* first four bytes in options */
+#define DHCP_MAGIC1 0x63
+#define DHCP_MAGIC2 0x82
+#define DHCP_MAGIC3 0x53
+#define DHCP_MAGIC4 0x63
+
+/* DHCP message types */
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER 2
+#define DHCP_REQUEST 3
+#define DHCP_DECLINE 4
+#define DHCP_ACK 5
+#define DHCP_NAK 6
+#define DHCP_RELEASE 7
+#define DHCP_INFORM 8
+
+/* option types */
+#define DHCP_OPT_MSGTYPE 0x35
+#define DHCP_OPT_PARAMREQ 0x37
+#define DHCP_OPT_WPAD 0xfc
+#define DHCP_OPT_END 0xff
+
+#endif
+
+/* vim: ts=4 sw=4 noet
+ */
diff --git a/tdeio/misc/kpac/discovery.cpp b/tdeio/misc/kpac/discovery.cpp
new file mode 100644
index 000000000..4f33d1389
--- /dev/null
+++ b/tdeio/misc/kpac/discovery.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 "config.h"
+
+#include <netdb.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <arpa/nameser.h>
+#ifdef HAVE_ARPA_NAMESER8_COMPAT_H
+#include <arpa/nameser8_compat.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+// Basically, the BSDs need this before resolv.h
+#include <sys/param.h>
+#endif
+#include <resolv.h>
+#include <sys/utsname.h>
+
+#include <tqtimer.h>
+
+#include <klocale.h>
+#include <kprocio.h>
+#include <kurl.h>
+
+#include "discovery.moc"
+
+namespace KPAC
+{
+ Discovery::Discovery( TQObject* parent )
+ : Downloader( parent ),
+ m_helper( new KProcIO )
+ {
+ connect( m_helper, TQT_SIGNAL( readReady( KProcIO* ) ), TQT_SLOT( helperOutput() ) );
+ connect( m_helper, TQT_SIGNAL( processExited( TDEProcess* ) ), TQT_SLOT( failed() ) );
+ *m_helper << "kpac_dhcp_helper";
+
+ if ( !m_helper->start() )
+ TQTimer::singleShot( 0, this, TQT_SLOT( failed() ) );
+ }
+
+ bool Discovery::initHostName()
+ {
+ struct utsname uts;
+
+ if (uname (&uts) > -1)
+ {
+ struct hostent *hent = gethostbyname (uts.nodename);
+ if (hent != 0)
+ m_hostname = TQString::fromLocal8Bit( hent->h_name );
+ }
+
+ // If no hostname, try gethostname as a last resort.
+ if (m_hostname.isEmpty())
+ {
+ char buf [256];
+ if (gethostname (buf, sizeof(buf)) == 0)
+ {
+ buf[255] = '\0';
+ m_hostname = TQString::fromLocal8Bit( buf );
+ }
+ }
+ return !m_hostname.isEmpty();
+ }
+
+ bool Discovery::checkDomain() const
+ {
+ // If a domain has a SOA record, don't traverse any higher.
+ // Returns true if no SOA can be found (domain is "ok" to use)
+ // Stick to old resolver interface for portability reasons.
+ union
+ {
+ HEADER header;
+ unsigned char buf[ PACKETSZ ];
+ } response;
+ int len = res_query( m_hostname.local8Bit(), C_IN, T_SOA,
+ response.buf, sizeof( response.buf ) );
+ if ( len <= int( sizeof( response.header ) ) ||
+ ntohs( response.header.ancount ) != 1 ) return true;
+ unsigned char* pos = response.buf + sizeof( response.header );
+ unsigned char* end = response.buf + len;
+ // skip query section
+ pos += dn_skipname( pos, end ) + QFIXEDSZ;
+ if ( pos >= end ) return true;
+ // skip answer domain
+ pos += dn_skipname( pos, end );
+ short type;
+ GETSHORT( type, pos );
+ return type != T_SOA;
+ }
+
+ void Discovery::failed()
+ {
+ setError( i18n( "Could not find a usable proxy configuration script" ) );
+
+ // If this is the first DNS query, initialize our host name or abort
+ // on failure. Otherwise abort if the current domain (which was already
+ // queried for a host called "wpad" contains a SOA record)
+ bool firstQuery = m_hostname.isEmpty();
+ if ( ( firstQuery && !initHostName() ) ||
+ ( !firstQuery && !checkDomain() ) )
+ {
+ emit result( false );
+ return;
+ }
+
+ int dot = m_hostname.find( '.' );
+ if ( dot >= 0 )
+ {
+ m_hostname.remove( 0, dot + 1 ); // remove one domain level
+ download( KURL( "http://wpad." + m_hostname + "./wpad.dat" ) );
+ }
+ else emit result( false );
+ }
+
+ void Discovery::helperOutput()
+ {
+ m_helper->disconnect( this );
+ TQString line;
+ m_helper->readln( line );
+ download( KURL( line.stripWhiteSpace() ) );
+ }
+}
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/discovery.h b/tdeio/misc/kpac/discovery.h
new file mode 100644
index 000000000..a1443ad8c
--- /dev/null
+++ b/tdeio/misc/kpac/discovery.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 KPAC_DISCOVERY_H
+#define KPAC_DISCOVERY_H
+
+#include <tqobject.h>
+
+#include "downloader.h"
+
+class KProcIO;
+
+namespace KPAC
+{
+ class Discovery : public Downloader
+ {
+ Q_OBJECT
+ public:
+ Discovery( TQObject* );
+
+ protected slots:
+ virtual void failed();
+
+ private slots:
+ void helperOutput();
+
+ private:
+ bool initHostName();
+ bool checkDomain() const;
+
+ KProcIO* m_helper;
+ TQString m_hostname;
+ };
+}
+
+#endif // KPAC_DISCOVERY_H
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/downloader.cpp b/tdeio/misc/kpac/downloader.cpp
new file mode 100644
index 000000000..c94cc9b72
--- /dev/null
+++ b/tdeio/misc/kpac/downloader.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 <cstdlib>
+#include <cstring>
+
+#include <tqtextcodec.h>
+
+#include <kcharsets.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <tdeio/job.h>
+
+#include "downloader.moc"
+
+namespace KPAC
+{
+ Downloader::Downloader( TQObject* parent )
+ : TQObject( parent )
+ {
+ }
+
+ void Downloader::download( const KURL& url )
+ {
+ m_data.resize( 0 );
+ m_script = TQString::null;
+ m_scriptURL = url;
+
+ TDEIO::TransferJob* job = TDEIO::get( url, false, false );
+ connect( job, TQT_SIGNAL( data( TDEIO::Job*, const TQByteArray& ) ),
+ TQT_SLOT( data( TDEIO::Job*, const TQByteArray& ) ) );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job* ) ), TQT_SLOT( result( TDEIO::Job* ) ) );
+ }
+
+ void Downloader::failed()
+ {
+ emit result( false );
+ }
+
+ void Downloader::setError( const TQString& error )
+ {
+ m_error = error;
+ }
+
+ void Downloader::data( TDEIO::Job*, const TQByteArray& data )
+ {
+ unsigned offset = m_data.size();
+ m_data.resize( offset + data.size() );
+ std::memcpy( m_data.data() + offset, data.data(), data.size() );
+ }
+
+ void Downloader::result( TDEIO::Job* job )
+ {
+ if ( !job->error() && !static_cast< TDEIO::TransferJob* >( job )->isErrorPage() )
+ {
+ bool dummy;
+ m_script = TDEGlobal::charsets()->codecForName(
+ job->queryMetaData( "charset" ), dummy )->toUnicode( m_data );
+ emit result( true );
+ }
+ else
+ {
+ if ( job->error() )
+ setError( i18n( "Could not download the proxy configuration script:\n%1" )
+ .arg( job->errorString() ) );
+ else setError( i18n( "Could not download the proxy configuration script" ) ); // error page
+ failed();
+ }
+ }
+}
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/downloader.h b/tdeio/misc/kpac/downloader.h
new file mode 100644
index 000000000..808e09378
--- /dev/null
+++ b/tdeio/misc/kpac/downloader.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 KPAC_DOWNLOADER_H
+#define KPAC_DOWNLOADER_H
+
+#include <tqobject.h>
+
+#include <kurl.h>
+
+namespace TDEIO { class Job; }
+
+namespace KPAC
+{
+ class Downloader : public TQObject
+ {
+ Q_OBJECT
+ public:
+ Downloader( TQObject* );
+
+ void download( const KURL& );
+ const KURL& scriptURL() { return m_scriptURL; }
+ const TQString& script() { return m_script; }
+ const TQString& error() { return m_error; }
+
+ signals:
+ void result( bool );
+
+ protected:
+ virtual void failed();
+ void setError( const TQString& );
+
+ private slots:
+ void data( TDEIO::Job*, const TQByteArray& );
+ void result( TDEIO::Job* );
+
+ private:
+ TQByteArray m_data;
+ KURL m_scriptURL;
+ TQString m_script;
+ TQString m_error;
+ };
+}
+
+#endif // KPAC_DOWNLOADER_H
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/eventsrc b/tdeio/misc/kpac/eventsrc
new file mode 100644
index 000000000..c44443a03
--- /dev/null
+++ b/tdeio/misc/kpac/eventsrc
@@ -0,0 +1,530 @@
+[!Global!]
+IconName=proxy
+Comment=Automatic Proxy Configuration
+Comment[af]=Outomatiese Proksie Opstelling
+Comment[ar]=تهيئة آلية للخادم الوكيل
+Comment[az]=Avtomatik Vəkil Quraşdırılması
+Comment[bg]=Ðвтоматично наÑтройване на прокÑи Ñървъра
+Comment[bn]=সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশন
+Comment[br]=Kefluniadur emgefreekh ar proksi
+Comment[bs]=Automatsko podešavanje proxy-ja
+Comment[ca]=Configuració automàtica del servidor d'intercanvi
+Comment[cs]=Automatické nastavení proxy
+Comment[csb]=Aùtokònfigùracëjô pòstrzédnika
+Comment[cy]=Ffurweddiad Awtomatig o'r Dirprwy
+Comment[da]=Automatisk proxy-indstilling
+Comment[de]=Autom. Proxy-Einrichtung
+Comment[el]=Αυτόματη ÏÏθμιση διαμεσολαβητή
+Comment[eo]=AÅ­tomata Prokuragordo
+Comment[es]=Configuración automática del Proxy
+Comment[et]=Automaatne proxy konfigureerimine
+Comment[eu]=Proxy-aren konfigurazio automatikoa
+Comment[fa]=پیکربندی خودکار پیشکار
+Comment[fi]=Automaattiset proxy-asetukset
+Comment[fr]=Configuration automatique du serveur mandataire
+Comment[fy]=Automatyske proxy ynstelling
+Comment[ga]=Uathchumraíocht an tSeachfhreastalaí
+Comment[gl]=Configuración Automática do Proxy
+Comment[he]=הגדרות פרוקסי ×וטומטיות
+Comment[hi]=सà¥à¤µà¤šà¤²à¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¼à¤¿à¤—रेटर
+Comment[hr]=Automatsko podešavanje proxyja
+Comment[hu]=Automatikus proxybeállítás
+Comment[id]=Konfigurasi Proxi Otomatis
+Comment[is]=Sjálfvirkar stillingar milliþjóns
+Comment[it]=Configurazione automatica proxy
+Comment[ja]=自動プロキシ設定
+Comment[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ თვითგáƒáƒ›áƒáƒ áƒ—ვáƒ
+Comment[kk]=Ðвтоматты түрде прокÑиді баптау
+Comment[km]=ការ​កំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​ប្រូកស៊ី​ដោយ​ស្វáŸáž™â€‹áž”្រវážáŸ’ážáž·
+Comment[ko]=스스로 프ë¡ì‹œ 설정
+Comment[lb]=Automatesch Proxy-Configuratioun
+Comment[lt]=Automatinis proxy derinimas
+Comment[mk]=ÐвтоматÑка конфигурација на прокÑи
+Comment[mn]=Ðвтомат итгÑмжилÑгчийн тохиргоо
+Comment[ms]=Penyelarasan Proksi Automatik
+Comment[nb]=Automatisk mellomtjenerinnstilling
+Comment[nds]=Proxy automaatsch instellen
+Comment[ne]=सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन
+Comment[nl]=Automatische proxyconfiguratie
+Comment[nn]=Automatisk mellomtenaroppsett
+Comment[pa]=ਸਵੈ-ਚਾਲਤ ਪਰਾਕਸੀ ਸੰਰਚਨਾ
+Comment[pl]=Autokonfiguracja pośrednika
+Comment[pt]=Configuração Automática do 'Proxy'
+Comment[pt_BR]=Configuração Automática do Proxy
+Comment[ro]=Configurare automată "proxy"
+Comment[ru]=ÐвтонаÑтройка прокÑи
+Comment[rw]=Iboneza rya Nyabubasha Ryikoresha
+Comment[se]=Automáhtalaš gaskabálváheiveheapmi
+Comment[sk]=Automatická konfigurácia proxy
+Comment[sl]=Samodejne nastavitve posrednika
+Comment[sq]=Kofigurimi Automatik i Proxy-t
+Comment[sr]=ÐутоматÑко подешавање прокÑија
+Comment[sr@Latn]=Automatsko podešavanje proksija
+Comment[sv]=Automatisk proxyinställning
+Comment[ta]=தானியகà¯à®• பதிலாள௠வடிவமைபà¯à®ªà¯
+Comment[te]=à°¸à±à°µà°¯à°‚చాలిత à°ªà±à°°à°¾à°•à±à°¸à±€ రూపకరణం
+Comment[tg]=Шакли Ðвтоматӣ Вакил Кардашуда
+Comment[th]=ปรับà¹à¸•à¹ˆà¸‡à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸­à¸±à¸•à¹‚นมัติ
+Comment[tr]=Otomatik Vekil Sunucu Yapılandırması
+Comment[tt]=Proxy'nı Aqıllı Caylaw
+Comment[uk]=Ðвтоматичне Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– Ñервера
+Comment[uz]=Proksini avtomatik ravishda moslash
+Comment[uz@cyrillic]=ПрокÑини автоматик равишда моÑлаш
+Comment[vi]=Cấu hình ủy nhiệm tự động.
+Comment[wa]=Apontiaedje otomatike do procsi
+Comment[zh_CN]=自动代ç†é…ç½®
+Comment[zh_HK]=自動代ç†çµ„æ…‹
+Comment[zh_TW]=自動代ç†çµ„æ…‹
+
+[script-error]
+Name=Invalid proxy script
+Name[af]=Ongeldige proksie skrip
+Name[ar]=نص برمجي غير صالح
+Name[az]=Hökmsüz vəkil skripti
+Name[bg]=Ðевалиден Ñкрипт за прокÑи Ñървъра
+Name[bn]=অবৈধ পà§à¦°à¦•à§à¦¸à¦¿ সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ
+Name[br]=N'eo ket mat an urzhiaoug proksi
+Name[bs]=Neispravna proxy skripta
+Name[ca]=Script del servidor intermedi no vàlid
+Name[cs]=Neplatný proxy skript
+Name[csb]=Falszëwi skript pòstrzédnika
+Name[cy]=Sgript dirprwy annilys
+Name[da]=Ugyldigt proxy-script
+Name[de]=Ungültiges Proxy-Skript
+Name[el]=Μη έγκυÏο σενάÏιο διαμεσολαβητή
+Name[eo]=Nevalida prokurila skripto
+Name[es]=Procedimiento inválido del proxy
+Name[et]=Vigane proxy skript
+Name[eu]=Proxy-aren script baliogabea
+Name[fa]=دست‌نوشتۀ پیشکار نامعتبر
+Name[fi]=Virheellinen proxy-skripti
+Name[fr]=Script de serveur mandataire non valable
+Name[fy]=Unjildich proxy skript
+Name[ga]=Script neamhbhailí seachfhreastalaí
+Name[gl]=Guión de proxy inválido
+Name[he]=תסריט Proxy ×œ× ×ª×§×™×Ÿ
+Name[hi]=अवैध पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ
+Name[hr]=Neispravna proxy skripta
+Name[hu]=Érvénytelen proxy-szkript
+Name[id]=Skrip proxi tidak sah
+Name[is]=Ógild milliþjónsskrifta
+Name[it]=Script proxy non valido
+Name[ja]=無効ãªãƒ—ロキシスクリプト
+Name[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ მცდáƒáƒ áƒ˜ სკრიპტი
+Name[kk]=ЖарамÑыз прокÑи Ñкрипті
+Name[km]=ស្គ្រីប​ប្រូកស៊ី​មិន​ážáŸ’រឹមážáŸ’រូវ
+Name[ko]=올바르지 ì•Šì€ í”„ë¡ì‹œ 스í¬ë¦½íŠ¸
+Name[lb]=Ongültegt Proxy-Skript
+Name[lt]=Blogas proxy scenarijas
+Name[mk]=Ðевалидна прокÑи Ñкрипта
+Name[mn]=Хүчингүй итгÑмжилÑгч Ñкрипт
+Name[ms]=Skrip proksi tidak sah
+Name[nb]=Ugyldig mellomtjenerskript
+Name[nds]=Proxyskript gellt nich
+Name[ne]=अवैदà¥à¤¯ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ
+Name[nl]=Ongeldig proxyscript
+Name[nn]=Ugyldig mellomtenarskript
+Name[pa]=ਗਲਤ ਪਰਾਕਸੀ ਸਕà©à¨°à¨¿à¨ªà¨Ÿ
+Name[pl]=Niepoprawny skrypt pośrednika
+Name[pt]=Configuração de 'proxy' inválida
+Name[pt_BR]=Script de proxy inválido
+Name[ro]=Script "proxy" eronat
+Name[ru]=Ðеверный Ñкрипт прокÑи
+Name[rw]=Inyandikoporogaramu ya Nyabubasha ntiyemewe
+Name[se]=Gustohis gaskabálváskripta
+Name[sk]=Zlý proxy skript
+Name[sl]=Neveljaven posredniški skript
+Name[sq]=Proxy Skripta është e gabuar
+Name[sr]=ÐеиÑправна прокÑи Ñкрипта
+Name[sr@Latn]=Neispravna proksi skripta
+Name[sv]=Ogiltigt proxyskript
+Name[ta]=செலà¯à®²à®¾à®¤ பதிலாள௠எழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®®à¯
+Name[te]=చెలà±à°²à°¨à°¿ à°ªà±à°°à°¾à°•à±à°¸à±€ à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà±
+Name[tg]=ДаÑтнавиÑи вакил кардашуда ношоÑм
+Name[th]=สคริปต์ของพร็อà¸à¸‹à¸µ ไม่ถูà¸à¸•à¹‰à¸­à¸‡
+Name[tr]=Geçersiz vekil sunucu betiği
+Name[tt]=Proxy ämerlege bozıq
+Name[uk]=Ðеправильний Ñкрипт Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐºÑÑ–
+Name[uz]=Proksi skripti haqiqiy emas
+Name[uz@cyrillic]=ПрокÑи Ñкрипти ҳақиқий ÑмаÑ
+Name[vi]=Tập lệnh ủy nhiệm không hợp lệ
+Name[zh_CN]=无效的代ç†è„šæœ¬
+Name[zh_HK]=ä¸åˆæ³•çš„代ç†ä¼ºæœå™¨ script
+Name[zh_TW]=ä¸åˆæ³• proxy 命令稿檔案
+Comment=The downloaded proxy configuration script is invalid
+Comment[af]=Die proksie skipt wat afgelaai was is ongeldig
+Comment[ar]=النص البرمجي الذي تم تنزيله غير صالح
+Comment[az]=Endirilən vəkil quraşdırma skripti kökmsüzdür
+Comment[bg]=ИзтеглениÑÑ‚ Ñкрипт за наÑтройване на прокÑи Ñървъра е невалиден
+Comment[bn]=ডাউনলোড করা পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশন সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà¦Ÿà¦¿ অবৈধ
+Comment[br]=N'eo ket mat urzhiaoug kefluniadur ar proksi
+Comment[bs]=Downloadovana skripta za podešavanje proxy-ja je neispravna
+Comment[ca]=L'script de configuració del servidor intermedi descarregat no és vàlid
+Comment[cs]=Stažený konfiguraÄní skript pro proxy je neplatný
+Comment[csb]=Zladowóny skript kònfigùracëji pòstrzédnika je falszëwi
+Comment[cy]=Mae'r sgript ffurfweddu'r dirprwy a chafodd ei lawrlwytho yn annilys
+Comment[da]=Det hentede proxy-indstillingsscript er ugyldigt
+Comment[de]=Das heruntergeladene Proxy-Einrichtungsskript ist nicht verwendbar
+Comment[el]=Το σενάÏιο ÏÏθμισης διαμεσολαβητή που λήφθηκε δεν είναι έγκυÏο
+Comment[eo]=La ÅarÄita prokuragordoskript estas nevalida
+Comment[es]=El procedimiento descargado para la configuración del proxy es inválido
+Comment[et]=Allalaaditud proxy seadistuse skript on vigane
+Comment[eu]=Deskargatutako proxy-aren konfigurazioko script-a baliogabea da
+Comment[fa]=دست‌نوشتۀ پیکربندی پیشکار بارگیری‌شده، نامعتبر است
+Comment[fi]=Ladattu proxy-asetusskripti on virheellinen
+Comment[fr]=Le script téléchargé de configuration du serveur mandataire n'est pas valable
+Comment[fy]=It ynladen proxy ynstellings skript is ûnjildich
+Comment[ga]=Is neamhbhailí í script chumraíocht an tseachfhreastalaí a íosluchtaíodh
+Comment[gl]=O guión de configuración descarregado do proxy non é válido
+Comment[he]=תסריט הגדרת הפרוקסי שהורד ×œ× ×ª×§×™×Ÿ
+Comment[hi]=ङाउनलोडेड पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¼à¤¿à¤—रेटर सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ अवैध है।
+Comment[hr]=Preuzeta skripta konfiguriranja proxyja je neispravna
+Comment[hu]=A letöltött proxybeállító szkript érvénytelen
+Comment[id]=Skrip konfigurasi proxy yang diunduh tidak valid
+Comment[is]=Sótt milliþjónsskrifta er ógild
+Comment[it]=Lo script di configurazione proxy scaricato non è valido
+Comment[ja]=ダウンロードã•ã‚ŒãŸãƒ—ロキシ設定スクリプトã¯ç„¡åŠ¹ã§ã™ã€‚
+Comment[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ გáƒáƒ›áƒáƒ áƒ—ვის ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული სკრიპტი მცდáƒáƒ áƒ˜áƒ
+Comment[kk]=Жүктеп алынған прокÑи баптау Ñкрипті жарамÑыз
+Comment[km]=ស្គ្រីប​កំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធប្រូកស៊ី​ដែល​បាន​ទាញយក មិន​ážáŸ’រឹមážáŸ’រូវ​ឡើយ
+Comment[ko]=ë‚´ë ¤ë°›ì€ í”„ë¡ì‹œ 설정 스í¬ë¦½íŠ¸ê°€ 올바르지 않습니다.
+Comment[lb]=D'Proxy-Configuratiounsskript, dat erofgelude gouf, ass ongülteg
+Comment[lt]=Atsisiųstas proxy derinimo scenarijus yra blogas
+Comment[mk]=Симнатата Ñкрипта за конфигурација на прокÑи е навалидна
+Comment[mn]=ТатагдÑан итгÑмжилÑгч тохируулгын Ñкрипт хүчингүй
+Comment[ms]=Skrip penyelarasan proksi yang dimuat turun tidak sah
+Comment[nb]=Det nedlastede skriptet for mellomtjener-innstillinger er ugyldig
+Comment[nds]=Dat Skript för't Instellen vun den Proxy gellt nich
+Comment[ne]=डाउनलोड गरिà¤à¤•à¥‹ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ अवैदà¥à¤¯ छ
+Comment[nl]=Het opgehaalde proxyconfiguratiescript is ongeldig
+Comment[nn]=Det nedlasta skriptet for mellomtenaroppsett er ugyldig
+Comment[pa]=ਡਾਊਨਲੋਡ ਪਰਾਕਸੀ ਸੰਰਚਨਾ ਸਕà©à¨°à¨¿à¨ªà¨Ÿ ਜਾਇਜ਼ ਨਹੀਂ ਹੈ
+Comment[pl]=Pobrany skrypt konfiguracji pośrednika jest nieprawidłowy
+Comment[pt]=A configuração do 'proxy' transferida é inválida
+Comment[pt_BR]=O script de configuração do proxy baixado é inválido
+Comment[ro]=Scriptul de configurare "proxy" este eronat
+Comment[ru]=Загруженный Ñкрипт наÑтройки прокÑи Ñодержит ошибки
+Comment[rw]=inyandikoporogaramu y'iboneza rya Nyabubasha yakuruwe ntiyemewe
+Comment[se]=Viežžojuvvon gaskabálváskripta lea gustomeahttun
+Comment[sk]=Stiahnutý konfiguraÄný skript proxy nie je správny
+Comment[sl]=Naložen nastavitveni skript posrednika je neveljaven
+Comment[sq]=Skripta për Konfigurimin e Proxy-t ishte e gabuar
+Comment[sr]=Преузета Ñкрипта за подешавање прокÑија је неиÑправна
+Comment[sr@Latn]=Preuzeta skripta za podešavanje proksija je neispravna
+Comment[sv]=Det nerladdade proxyinställningsskriptet är ogiltigt
+Comment[ta]=இறகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ பதிலாள௠வடிவமைபà¯à®ªà¯ எழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®®à¯ செலà¯à®²à®¾à®¤à¯
+Comment[te]=డౌనౠలోడౠచేయబడినౠపà±à°°à°¾à°•à±à°¸à±€ రూపకరణపౠసà±à°•à±à°°à°¿à°ªà±à°Ÿà± చెలà±à°²à°¦à±
+Comment[tg]=Шакли даÑтнавиÑи вакил кардашуда ношоÑм фаровир
+Comment[th]=สคริปต์สำหรับà¸à¸²à¸£à¸›à¸£à¸±à¸šà¹à¸•à¹ˆà¸‡à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸—ี่ดาวน์โหลดมาไม่ถูà¸à¸•à¹‰à¸­à¸‡
+Comment[tr]=Vekil sunucu yapılandırma dosyası geçersiz
+Comment[tt]=Proxy caylaw öçen iñderelgän ämerlek bozıq bulğan
+Comment[uk]=Звантажений Ñкрипт Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– Ñервера неправильний
+Comment[uz]=Proksini moslash uchun yozib olingan skript haqiqiy emas
+Comment[uz@cyrillic]=ПрокÑини моÑлаш учун ёзиб олинган Ñкрипт ҳақиқий ÑмаÑ
+Comment[vi]=Tập lệnh cấu hình ủy nhiệm đã được tải xuống không phải là hợp lệ.
+Comment[zh_CN]=下载的代ç†é…置脚本是无效的
+Comment[zh_HK]=剛下載的代ç†ä¼ºæœå™¨çµ„æ…‹ script 語法有誤
+Comment[zh_TW]=代ç†çµ„æ…‹çš„ script 檔案語法有誤
+default_presentation=16
+
+[download-error]
+Name=Script download error
+Name[af]=Skrip aflaai fout
+Name[ar]=خطأ أثناء تنزيل النص البرمجي
+Name[az]=Skript endirmə xətası
+Name[be]=Памылка ÑцÑÐ³Ð²Ð°Ð½Ð½Ñ ÑцÑнара
+Name[bg]=Грешка при изтеглÑне на Ñкрипта
+Name[bn]=সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ ডাউনলোডে সমসà§à¦¯à¦¾
+Name[br]=Fazi en ur enkargañ an urzhiaoug
+Name[bs]=Greška pri downloadu skripte
+Name[ca]=Error descàrrega de l'script
+Name[cs]=Chyba ve stažení skriptu
+Name[csb]=Fela zladënkù skriptu
+Name[cy]=Gwall wrth lawrlwytho'r sgript
+Name[da]=Script download-fejl
+Name[de]=Fehler beim Herunterladen des Skripts
+Name[el]=Σφάλμα λήψης σεναÏίου
+Name[eo]=Skripta ÅarÄeraro
+Name[es]=Error de descarga del procedimiento
+Name[et]=Viga skripti allalaadimisel
+Name[eu]=Errorea script-a deskargatzean
+Name[fa]=خطای بارگیری دست‌نوشته
+Name[fi]=Skriptin latausvirhe
+Name[fr]=Erreur de téléchargement du script
+Name[fy]=Skript ynlaad flater
+Name[ga]=Earráid íoslódála scripte
+Name[gl]=Erro de descarga do guión
+Name[he]=שגי××” בהורדת התסריט
+Name[hi]=सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ डाउनलोड तà¥à¤°à¥à¤Ÿà¤¿
+Name[hr]=Pogreška pri preuzimanju skripte
+Name[hu]=Szkriptletöltési hiba
+Name[id]=Kesalahan mengambil skrip
+Name[is]=Villa við hleðslu skriftu
+Name[it]=Errore di scaricamento script
+Name[ja]=スクリプトã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã‚¨ãƒ©ãƒ¼
+Name[ka]=სკრიპტის ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვის შეცდáƒáƒáƒ›
+Name[kk]=Скриптті жүктеп алу қатеÑÑ–
+Name[km]=កំហុស​ទាញយក​ស្គ្រីប
+Name[ko]=스í¬ë¦½íŠ¸ 내려받기 오류
+Name[lb]=Feeler beim Erofluede vum Skript
+Name[lt]=scenarijaus atsisiuntimo klaida
+Name[lv]=Skripta lejuplÄdes kļūda
+Name[mk]=Грешка при Ñимнување на Ñкрипта
+Name[mn]=Скрипт татахад алдаа
+Name[ms]=Ralat muat turun skrip
+Name[nb]=Skript nedlastingsfeil
+Name[nds]=Skript-Daallaadfehler
+Name[ne]=सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ डाउनलोड तà¥à¤°à¥à¤Ÿà¤¿
+Name[nl]=Fout bij downloaden van script
+Name[nn]=Feil ved skriptnedlasting
+Name[pa]=ਸਕà©à¨°à¨¿à¨ªà¨Ÿ ਡਾਊਨਲੋਡ ਗਲਤੀ
+Name[pl]=BÅ‚Ä…d pobierania skryptu
+Name[pt]=Erro de transferência da configuração
+Name[pt_BR]=Erro de download de script
+Name[ro]=Eroare de transfer a scriptului
+Name[ru]=Ошибка загрузки Ñкрипта
+Name[rw]=Ikosa ry'ikurura inyandikoporogaramu
+Name[se]=Meattáhus skripta vieÄÄadettiin
+Name[sk]=Chyba poÄas sÅ¥ahovania skriptu
+Name[sl]=Napaka nalaganju skripta
+Name[sq]=Skripta nuk pat sukses të Ngarkohet
+Name[sr]=Грешка приликом преузимања Ñкрипте
+Name[sr@Latn]=Greška prilikom preuzimanja skripte
+Name[sv]=Nerladdningsfel för skript
+Name[ta]=எழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆ இறகà¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯ பிழை
+Name[te]=à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± డౌనౠలోడౠదోషం
+Name[tg]=Хатои даÑÑ‚Ð½Ð°Ð²Ð¸Ñ Ñ„Ð°Ñ€Ð¾Ð²Ð¸Ñ€
+Name[th]=ข้อผิดพลาดในà¸à¸²à¸£à¸”าวน์โหลดสคริปต์
+Name[tr]=Betik indirme hatası
+Name[tt]=Ämerlek iñderü xatarı
+Name[uk]=Помилка Ð·Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñкрипту
+Name[uz]=Skriptni yozib olishda xato roʻy berdi
+Name[uz@cyrillic]=Скриптни ёзиб олишда хато рўй берди
+Name[vi]=Lỗi tải xuống tập lệnh
+Name[zh_CN]=脚本下载错误
+Name[zh_HK]=Script 下載錯誤
+Name[zh_TW]=Script 下載錯誤
+Comment=The proxy configuration script could not be downloaded
+Comment[af]=Die proksie opstelling skrip kon nie afgelaai word nie
+Comment[ar]=تعذر تنزيل النص البرمجي لإعداد الخادم الوكيل
+Comment[az]=VÆkil qurÄŸuları skripti endirilÉ™ bilmÉ™di
+Comment[bg]=Скриптът за наÑтройване на прокÑи Ñървъра не може да бъде изтеглен
+Comment[bn]=পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশন সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ ডাউনলোড করা যায়নি
+Comment[br]=Ne m'eus ket enkargañ urzhiaoug kefluniadur ar proksi
+Comment[bs]=Nisam mogao downloadovati skriptu za podešavanje proxy-ja
+Comment[ca]=L'script de configuració del servidor intermedi no es pot descarregar
+Comment[cs]=Nelze stáhnout konfiguraÄní skript pro proxy
+Comment[csb]=Nie je mòżno zladowac skriptu kònfiguracëji pòstrzédnika
+Comment[cy]=Y sgript ffurfweddu'r dirprwy
+Comment[da]=Proxy-indstillingsscriptet kunne ikke hentes
+Comment[de]=Das Proxy-Einrichtungsskript lässt sich nicht herunterladen
+Comment[el]=Το σενάÏιο ÏÏθμισης διαμεσολαβητή ήταν αδÏνατο να ανακτηθεί
+Comment[eo]=Ne eblas ÅarÄi la prokuragordoskripton
+Comment[es]=El procedimiento de configuración del proxy no se pudo descargar
+Comment[et]=Proxy seadistuse skripti ei õnnestu alla laadida
+Comment[eu]=Proxy-aren konfigurazioko script-a ezin izan da deskargatu
+Comment[fa]=دست‌نوشتۀ پیکربندی پیشکار بارگیری نشد
+Comment[fi]=Proxyn asetusskriptiä ei voitu ladata
+Comment[fr]=Le script de configuration du serveur mandataire n'a pas pu être téléchargé
+Comment[fy]=It ynladen fan de proxy ynstellings skript is net slagge
+Comment[ga]=Níorbh fhéidir script chumraíochta an tseachfhreastalaí a íoslódáil
+Comment[gl]=Non se pudo descarregar o guión de configuración do proxy
+Comment[he]=×œ× ×™×›×•×œ להוריד ×ת תסריט הגדרות הפרוקסי
+Comment[hi]=पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¼à¤¿à¤—रेशन सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ डाउनलोड नही की जा सकी।
+Comment[hr]=Skripta konfiguriranja proxyja nije mogla biti preuzetom s Interneta
+Comment[hu]=A proxybeállító szkript letöltése nem sikerült
+Comment[id]= Skrip konfigurasi proxy tidak dapat diunduh
+Comment[is]=Gat ekki sótt stillingaskriftu milliþjóns
+Comment[it]=Impossibile scaricare lo script di configurazione proxy
+Comment[ja]=プロキシ設定スクリプトをダウンロードã§ãã¾ã›ã‚“ã§ã—ãŸ
+Comment[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ გáƒáƒ›áƒáƒ áƒ—ვის სკრიპტის ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრვერ ხერხდებáƒ
+Comment[kk]=Бұл прокÑи Ñкрипт жүктеп алынбайды
+Comment[km]=មិន​អាច​ទាញយក​ស្គ្រីប​កំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​ប្រូកស៊ី
+Comment[ko]=프ë¡ì‹œ 설정 스í¬ë¦½íŠ¸ë¥¼ 내려받지 못합니다
+Comment[lb]=D'Proxy-Konfiguratiounsskript konnt net erofgeluede ginn
+Comment[lt]=Proxy derinimo scenarijus negali būti atsisiųstas
+Comment[mk]=Скриптата за конфигурација на прокÑи не можеше да Ñе Ñимне
+Comment[mn]=ИтгÑмжилÑгч тохиргооны Ñкрипт татагдахгүй байна
+Comment[ms]=Skrip penyelarasan proksi tidak boleh dimuat turun
+Comment[nb]=Klarte ikke å laste ned skiptet for mellomtjener-innstillinger
+Comment[nds]=Dat Skript för't Instellen vun den Proxy lett sik nich daalladen
+Comment[ne]=पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ डाउनलोड हà¥à¤¨ सकà¥à¤¨à¥‡ छैन
+Comment[nl]=Het proxyconfiguratiescript kon niet worden opgehaald
+Comment[nn]=Klarte ikkje lasta ned skript for mellomtenaroppsett
+Comment[pa]=ਪਰਾਕਸੀ ਸੰਰਚਨਾ ਸਕà©à¨°à¨¿à¨ªà¨Ÿ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ
+Comment[pl]=Nie można pobrać skryptu konfiguracji pośrednika
+Comment[pt]=A configuração do 'proxy' não pôde ser transferida
+Comment[pt_BR]=O script de configuração do proxy não pode ser carregado
+Comment[ro]=Nu am putut transfera scriptul de configurare "proxy"
+Comment[ru]=Ðе удаётÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ Ñкрипт наÑтройки прокÑи
+Comment[rw]=Inyandikoporogaramu y'iboneza rya Nyabubasha ntiyashoboye gukururwa
+Comment[se]=Ii sáhttán gaskbálváheivehanskripta viežžat
+Comment[sk]=Nebolo možné stiahnúť konfiguraÄný skript pre proxy
+Comment[sl]=Nastavitveni skript posrednika ni mogel biti naložen
+Comment[sq]=Skripta për Konfigurimin e Proxy-t nuk pat sukses të ngarkohet
+Comment[sr]=Скрипта за подешавање прокÑија не може бити преузета
+Comment[sr@Latn]=Skripta za podešavanje proksija ne može biti preuzeta
+Comment[sv]=Proxyinställningsskriptet kunde inte laddas ner
+Comment[ta]=பதிலாள௠வடிவமைபà¯à®ªà¯ எழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆ இறகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ
+Comment[te]=à°ªà±à°°à°¾à°•à±à°¸à±€ రూపకరణపౠసà±à°•à±à°°à°¿à°ªà±à°Ÿà± ని డౌనౠలోడౠచేయలేకపోయాం
+Comment[tg]=Шакли даÑтнавиÑи вакил кардашуда фаровир наметавонад
+Comment[th]=ไม่สามารถดาวน์โหลดสคริปต์สำหรับปรับà¹à¸•à¹ˆà¸‡à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¹„ด้
+Comment[tr]=Vekil sunucu yapılandırma dosyası indirilemedi
+Comment[tt]=Bu proxy caylaw ämerlegen iñderep bulmadı
+Comment[uk]=Ðе вдаєтьÑÑ Ð·Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Ñкрипт Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– Ñервера
+Comment[uz]=Proksini moslash uchun skriptni yozib olib boʻlmadi
+Comment[uz@cyrillic]=ПрокÑини моÑлаш учун Ñкриптни ёзиб олиб бўлмади
+Comment[vi]=Không thể tải xuống tập lệnh cấu hình ủy nhiệm.
+Comment[zh_CN]=代ç†é…置脚本无法下载
+Comment[zh_HK]=無法å–得代ç†ä¼ºæœå™¨çµ„æ…‹ script 檔案
+Comment[zh_TW]=無法å–得代ç†çµ„æ…‹ script 檔案
+default_presentation=16
+
+[evaluation-error]
+Name=Script evaluation error
+Name[af]=Skrip evaluasie fout
+Name[ar]=خطأ ÙÙŠ تقييم النص البرمجي
+Name[az]=Skript icra xətası
+Name[bg]=Грешка при обработка на Ñкрипта
+Name[bn]=সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ চালানোয় সমসà§à¦¯à¦¾
+Name[bs]=Greška pri procjeni skripte
+Name[ca]=Error en l'avaluació de l'script
+Name[cs]=Chyba v analýze skriptu
+Name[csb]=Fela zrëszëniô skriptu
+Name[cy]=Gwall wrth werthuso'r sgript
+Name[da]=Script evalueringsfejl
+Name[de]=Skript-Überprüfungsfehler
+Name[el]=Σφάλμα επικÏÏωσης σεναÏίου
+Name[eo]=Skripta ruleraro
+Name[es]=Error de evaluación del procedimiento
+Name[et]=Viga skripti käivitamisel
+Name[eu]=Script-aren ebaluazioko errorea
+Name[fa]=خطای ارزیابی دست‌نوشته
+Name[fi]=Skriptin määritysvirhe
+Name[fr]=Erreur d'évaluation du script
+Name[fy]=Beoardiele skript flater
+Name[ga]=Earráid agus an script á luacháil
+Name[gl]=Erro de evaluación do guión
+Name[he]=שגי×ת הרצה בתסריט
+Name[hi]=सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ इवेलà¥à¤¯à¥‚à¤à¤¶à¤¨ तà¥à¤°à¥à¤Ÿà¤¿
+Name[hr]=Pogreška pri procjenjivanju skripte
+Name[hu]=Szkriptkiértékelési hiba
+Name[id]=Kesalahan menjalankan skrip
+Name[is]=Túlkunarvilla skriftu
+Name[it]=Errore di valutazione script
+Name[ja]=スクリプト評価エラー
+Name[ka]=სკრიპტის დáƒáƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბის შეცდáƒáƒ›áƒ
+Name[kk]=Скрипт талдау қатеÑÑ–
+Name[km]=កំហុស​វាយážáž˜áŸ’លៃរបស់ស្គ្រីប
+Name[ko]=스í¬ë¦½íŠ¸ í‰ê°€ 오류
+Name[lb]=Feeler beim Evaluéieren vum Skript
+Name[lt]=Scenarijaus analizÄ—s klaida
+Name[mk]=Грешка при евалуација на Ñкрипта
+Name[mn]=Скрипт үнÑлÑÑ…Ñд алдаа
+Name[ms]=Ralat penilaian skrip
+Name[nb]=Skript evalueringsfeil
+Name[nds]=Skript-Pröövfehler
+Name[ne]=सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ मूलà¥à¤¯à¤¾à¤‚कन तà¥à¤°à¥à¤Ÿà¤¿
+Name[nl]=Fout bij evalueren van script
+Name[nn]=Feil ved skriptevaluering
+Name[pa]=ਸਕà©à¨°à¨¿à¨ªà¨Ÿ à¨à¨µà©‚ਲੇਸ਼ਨ ਗਲਤੀ
+Name[pl]=BÅ‚Ä…d wykonywania skryptu
+Name[pt]=Erro de avaliação da configuração
+Name[pt_BR]=Erro de avaliação de script
+Name[ro]=Eroare de analiză a scriptului
+Name[ru]=Ошибка разбора Ñкрипта
+Name[rw]=Ikosa ry'isuzuma ry'inyandikoporogaramu
+Name[sk]=Chyba kontroly skriptu
+Name[sl]=Napaka pri ocenjevanju skripta
+Name[sq]=Gabim i vlerësimit të skriptës
+Name[sr]=Грешка приликом израчунавања у Ñкрипти
+Name[sr@Latn]=GreÅ¡ka prilikom izraÄunavanja u skripti
+Name[sv]=Utvärderingsfel för skript
+Name[ta]=எழà¯à®¤à¯à®¤à®¾à®•à¯à®• மதிபà¯à®ªà¯€à®Ÿà¯à®Ÿà¯à®ªà¯ பிழை
+Name[te]=à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± నిరà±à°µà°¹à°£ దోషం
+Name[tg]=Фикри хатои даÑтнавиÑ
+Name[th]=ข้อผิดพลาดในà¸à¸²à¸£à¸›à¸£à¸°à¹€à¸¡à¸´à¸™à¸ªà¸„ริปต์
+Name[tr]=Betik çalıştırma hatası
+Name[tt]=Ämerlek eçtälegen uqığanda xata çıqtı
+Name[uk]=Помилка Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñкрипту
+Name[uz]=Skriptni tekshirishda xato roʻy berdi
+Name[uz@cyrillic]=Скриптни текширишда хато рўй берди
+Name[vi]=Lỗi định lượng tập lệnh
+Name[zh_CN]=脚本求值错误
+Name[zh_HK]=Script 執行錯誤
+Name[zh_TW]=Script 執行錯誤
+Comment=There was an error executing the proxy configuration script
+Comment[af]=Daar was 'n fout met die uitvoer van die proksie opstell skrip
+Comment[ar]=لقد حصل خطأ كبير أدى الى خروج البرنامج
+Comment[az]=Vəkil qurğuları skripti işə salınırkən xəta baş verdi
+Comment[bg]=Грешка по време на изпълнение на Ñкрипта за наÑтройване на прокÑи Ñървъра
+Comment[bn]=পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশন সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ চালাতে সমসà§à¦¯à¦¾ দেখা দিয়েছে
+Comment[br]=Degouezhet ez eus ur fazi en ur seveniñ urzhiaoug kefluniadur ar proksi
+Comment[bs]=Došlo je do greške pri izvršavanju skripte za podešavanje proxy-ja
+Comment[ca]=Hi ha hagut un error executant l'script de configuració del servidor intermedi
+Comment[cs]=Nastala chyba pÅ™i spouÅ¡tÄ›ní konfiguraÄního skriptu proxy
+Comment[csb]=Pòkôza sã fela, òb czas zrëszëniô skriptu kònfigùracëji pòstrzédnika
+Comment[cy]=Digwyddodd gwall wrth weithredu'r sgript ffurfweddu'r dirprwy
+Comment[da]=Der opstod en fejl ved kørslen af proxy-indstillingsscriptet
+Comment[de]=Fehler beim Ausführen des Proxy-Einrichtungsskripts
+Comment[el]=Συνέβη ένα σφάλμα στην εκτέλεση του σεναÏίου ÏÏθμισης διαμεσολαβητή
+Comment[eo]=Okazis eraro dum rulo de la prokuragordoskripto
+Comment[es]=Se produjo un error al ejecutarse el procedimiento de configuración del proxy
+Comment[et]=Ilmnes tõsine viga proxy seadistuse skripti käivitamisel
+Comment[eu]=Errorea gertatu da proxy-a konfiguratzeko script-ean
+Comment[fa]=هنگام اجرای دست‌نوشتۀ پیکربندی پیشکار، خطایی وجود داشت
+Comment[fi]=Proxy-skriptin suorittamisessa tapahtui virhe
+Comment[fr]=Une erreur s'est produite lors de l'exécution du script de configuration du serveur mandataire
+Comment[fy]=Der wie in flater by it útfoeren fan de proxy ynstellings skript
+Comment[ga]=Tharla earráid agus script chumraíocht an tseachfhreastalaí á rith
+Comment[gl]=Houbo un erro executando o guión de configuración do proxi
+Comment[he]=×ירעה שגי××” בעת הרצת תסריט הגדרות בפרוקסי
+Comment[hi]=पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¼à¤¿à¤—रेशन सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ चलाने में तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ
+Comment[hr]=Došlo je do pogreške pri izvršavanju konfiguracijske skripte proxyja
+Comment[hu]=Hiba történt a proxybeállító szkript végrehajtása közben
+Comment[id]=Kesalahan sewaktu menjalankan skrip konfigurasi proxy
+Comment[is]=Það kom upp villa við keyrslu stillingaskriftu milliþjóns
+Comment[it]=Si è verificato un errore durante l'esecuzione dello script di configurazione proxy
+Comment[ja]=プロキシ設定スクリプトã®å®Ÿè¡Œä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
+Comment[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ გáƒáƒ›áƒáƒ áƒ—ვის სკრიპტის გáƒáƒ›áƒáƒ§áƒ”ნების შეცდáƒáƒ›áƒ
+Comment[kk]=ПрокÑи баптау Ñкриптті орындау кезінде қате пайда болды
+Comment[km]=មាន​កំហុស​មួយ​ក្នុងការប្រážáž·áž”ážáŸ’ážáž·â€‹ážŸáŸ’គ្រីបកំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​ប្រូកស៊ី
+Comment[ko]=프ë¡ì‹œ 설정 스í¬ë¦¬íŠ¸ë¥¼ ì‹¤í–‰í•˜ëŠ”ë° ë¬¸ì œê°€ 있습니다
+Comment[lb]=Et gouf e Feeler beim Ausféiere vum Proxy-Konfiguratiounsskript
+Comment[lt]=Paleidžiant proxy derinimo scenarijų įvyko klaida
+Comment[mk]=Имаше грешка при извршувањето на Ñкриптата за конфигурација на прокÑи
+Comment[mn]=итгÑмжилÑгч тохируулгын Ñкрипт ажиллуулж байхад алдаа
+Comment[ms]=Terdapat ralat melaksanakan skrip penyelarasan proksi
+Comment[nb]=Det oppsto en alvorlig feil under kjøringen av skriptet for mellomtjener-innstillinger
+Comment[nds]=Bi't Utföhren vun dat Proxy-Instellenskript hett dat en Fehler geven
+Comment[ne]=पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ कारà¥à¤¯à¤¾à¤¨à¥à¤µà¤¯à¤¨ गरà¥à¤¦à¤¾ तà¥à¤°à¥à¤Ÿà¤¿ थियो
+Comment[nl]=Er deed zich een fout voor tijdens het uitvoeren van het proxyconfiguratiescript
+Comment[nn]=Feil ved køyring av skript for mellomtenaroppsett
+Comment[pa]=ਪਰਾਕਸੀ ਸੰਰਚਨਾ ਸਕà©à¨°à¨¿à¨ªà¨Ÿ ਚਲਾਉਣ ਵਿੱਚ ਗਲਤੀ ਆਈ ਹੈ
+Comment[pl]=Wystąpił błąd w czasie wykonywania skryptu konfiguracji pośrednika
+Comment[pt]=Ocorreu um erro ao efectuar a configuração do 'proxy'
+Comment[pt_BR]=Ocorreu um erro ao executar o script de configuração do proxy.
+Comment[ro]=A apărut o eroare la execuţia scriptului de configurare "proxy"
+Comment[ru]=Ошибка при выполнении Ñкрипта наÑтройки прокÑи
+Comment[rw]=Habaye ikosa mu gutangiza inyandikoporogaramu y'iboneza rya Nyabubasha
+Comment[se]=Meattáhus vuojedettiin gaskabálváheivehanskripta
+Comment[sk]=Vyskytla sa chyba poÄas spustenia konfiguraÄného skriptu proxy
+Comment[sl]=Prišlo je do napake pri izvajanju nastavitvenega skripta posrednika
+Comment[sq]=Është paraqitur një gabim gjatë ekzekutimit të skriptës për konfigurimin e proxy-t
+Comment[sr]=ДеÑила Ñе грешка приликом извршавања Ñкрипте за подешавање прокÑија
+Comment[sr@Latn]=Desila se greška prilikom izvršavanja skripte za podešavanje proksija
+Comment[sv]=Fel uppstod vid körning av proxyinställningsskriptet
+Comment[ta]=பதிலாள௠வடிவமைபà¯à®ªà¯ எழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯à®ªà¯‹à®¤à¯ ஒர௠பிழை நேரà¯à®¨à¯à®¤à®¤à¯
+Comment[te]=à°ªà±à°°à°¾à°•à±à°¸à±€ రూపకరణపౠసà±à°•à±à°°à°¿à°ªà±à°Ÿà± నిరà±à°µà°¹à°£à°²à±Š దోషం à°µà±à°¨à±à°¨à°¦à°¿
+Comment[tg]=Хато фаразани дар шакли даÑтнавиÑи вакил кардашуда
+Comment[th]=เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¸ªà¸±à¹ˆà¸‡à¹ƒà¸«à¹‰à¸ªà¸„ริปต์ปรับà¹à¸•à¹ˆà¸‡à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸—ำงาน
+Comment[tr]=Vekil sunucu yapılandırma dosyası çalıştırılamadı
+Comment[tt]=Proxy caylaw ämerelegen eşlätkändä xata çıqtı
+Comment[uk]=Виникла помилка при Ñпробі виконати Ñкрипт Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– Ñервера
+Comment[uz]=Proksini moslash uchun skriptni ishga tushirishda xato roʻy berdi
+Comment[uz@cyrillic]=ПрокÑини моÑлаш учун Ñкриптни ишга туширишда хато рўй берди
+Comment[vi]=Gặp lỗi khi thực hiện tập lệnh cấu hình ủy nhiệm.
+Comment[zh_CN]=执行代ç†é…置脚本出现错误
+Comment[zh_HK]=代ç†ä¼ºæœå™¨çµ„態檔案執行錯誤
+Comment[zh_TW]=proxy 代ç†çµ„態檔案執行錯誤
+default_presentation=0
diff --git a/tdeio/misc/kpac/kpac_dhcp_helper.c b/tdeio/misc/kpac/kpac_dhcp_helper.c
new file mode 100644
index 000000000..906e89dfa
--- /dev/null
+++ b/tdeio/misc/kpac/kpac_dhcp_helper.c
@@ -0,0 +1,229 @@
+/* This file is part of the KDE Libraries
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <config.h>
+#include <sys/types.h>
+#include <grp.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "dhcp.h"
+
+#ifndef INADDR_NONE /* some OSes don't define this */
+#define INADDR_NONE -1
+#endif
+
+int set_gid(gid_t);
+int set_uid(uid_t);
+int get_port(const char *);
+int init_socket(void);
+uint32_t send_request(int);
+void get_reply(int, uint32_t);
+
+int set_gid(gid_t gid)
+{
+#ifdef HAVE_SHORTSETGROUPS
+ short x[2];
+ x[0] = gid;
+ x[1] = 73; /* catch errors */
+ if (setgroups(1, x) == -1)
+ return -1;
+#else
+ if (setgroups(1, &gid) == -1)
+ return -1;
+#endif
+ return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
+}
+
+int set_uid(uid_t uid)
+{
+ return setuid(uid);
+}
+
+/* All functions below do an exit(1) on the slightest error */
+
+/* Returns the UDP port number for the given service name */
+int get_port(const char *service)
+{
+ struct servent *serv = getservbyname(service, "udp");
+ if (serv == NULL)
+ exit(1);
+
+ return serv->s_port;
+}
+
+/* Opens the UDP socket, binds to the bootpc port and drops root privileges */
+int init_socket()
+{
+ struct sockaddr_in addr;
+ struct protoent *proto;
+ int sock;
+ int bcast = 1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = get_port("bootpc");
+
+ if ((proto = getprotobyname("udp")) == NULL ||
+ (sock = socket(AF_INET, SOCK_DGRAM, proto->p_proto)) == -1)
+ exit(1);
+
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) == -1 ||
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &bcast, sizeof(bcast)) == -1 ||
+ bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+ exit(1);
+
+ if (set_gid(getgid()) != 0 || /* we don't need it anymore */
+ set_uid(getuid()) != 0)
+ exit(1);
+ return sock;
+}
+
+/* Fills the DHCPINFORM request packet, returns the transaction id */
+uint32_t send_request(int sock)
+{
+ char hostname[256];
+ struct hostent *hent;
+ struct sockaddr_in addr;
+ struct dhcp_msg request;
+ uint8_t *offs = request.options;
+
+ hostname[0] = '\0';
+ hostname[255] = '\0';
+ if (gethostname(hostname, 255) == -1 ||
+ strlen(hostname) == 0 ||
+ (hent = gethostbyname(hostname)) == NULL)
+ exit(1);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_NONE;
+ addr.sin_port = get_port("bootps");
+
+ memset(&request, 0, sizeof(request));
+ request.op = DHCP_BOOTREQUEST;
+ srand(time(NULL));
+ request.xid = rand();
+ request.ciaddr = *(uint32_t*)*hent->h_addr_list;
+
+ *offs++ = DHCP_MAGIC1;
+ *offs++ = DHCP_MAGIC2;
+ *offs++ = DHCP_MAGIC3;
+ *offs++ = DHCP_MAGIC4;
+
+ *offs++ = DHCP_OPT_MSGTYPE;
+ *offs++ = 1; /* length */
+ *offs++ = DHCP_INFORM;
+
+ *offs++ = DHCP_OPT_PARAMREQ;
+ *offs++ = 1; /* length */
+ *offs++ = DHCP_OPT_WPAD;
+
+ *offs++ = DHCP_OPT_END;
+
+ if (sendto(sock, &request, sizeof(request), 0,
+ (struct sockaddr *)&addr, sizeof(addr)) != sizeof(request))
+ exit(1);
+
+ return request.xid;
+}
+
+/* Reads the reply from the socket, checks it and outputs the URL to STDOUT */
+void get_reply(int sock, uint32_t xid)
+{
+ struct dhcp_msg reply;
+ int len;
+ char wpad[DHCP_OPT_LEN + 1];
+ uint8_t wpad_len;
+ uint8_t *offs = reply.options;
+ uint8_t *end;
+
+ if ((len = recvfrom(sock, &reply, sizeof(reply), 0, NULL, NULL)) <= 0)
+ exit(1);
+
+ end = (uint8_t *)&reply + len;
+ if (end < offs + 4 ||
+ end > &reply.options[DHCP_OPT_LEN] ||
+ reply.op != DHCP_BOOTREPLY ||
+ reply.xid != xid ||
+ *offs++ != DHCP_MAGIC1 ||
+ *offs++ != DHCP_MAGIC2 ||
+ *offs++ != DHCP_MAGIC3 ||
+ *offs++ != DHCP_MAGIC4)
+ exit(1);
+
+ for ( ; offs < end - 1; offs += *offs+1)
+ {
+ switch (*offs++)
+ {
+ case DHCP_OPT_END:
+ exit(1);
+ case DHCP_OPT_MSGTYPE:
+ if (*offs != 1 || (offs >= end - 1) || *(offs + 1) != DHCP_ACK)
+ exit(1);
+ break;
+ case DHCP_OPT_WPAD:
+ memset(wpad, 0, sizeof(wpad));
+ wpad_len = *offs++;
+ if (offs >= end)
+ exit(1);
+ if (wpad_len > end - offs)
+ wpad_len = end - offs;
+ strncpy(wpad, (char *)offs, wpad_len);
+ wpad[wpad_len] = 0;
+ printf("%s\n", wpad);
+ close(sock);
+ exit(0);
+ }
+ }
+ exit(1);
+}
+
+int main()
+{
+ fd_set rfds;
+ struct timeval tv;
+ int sock;
+ uint32_t xid;
+
+ sock = init_socket();
+ xid = send_request(sock);
+
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ if (select(sock + 1, &rfds, NULL, NULL, &tv) == 1 && FD_ISSET(sock, &rfds))
+ get_reply(sock, xid);
+
+ close(sock);
+ exit(1);
+}
+
+/* vim: ts=4 sw=4 noet
+ */
diff --git a/tdeio/misc/kpac/kpactest.pac b/tdeio/misc/kpac/kpactest.pac
new file mode 100644
index 000000000..69e5aaad7
--- /dev/null
+++ b/tdeio/misc/kpac/kpactest.pac
@@ -0,0 +1,169 @@
+// This is a script to test KPAC.
+// To use it: set this script as proxy config file and run
+// dcop kded proxyscout proxyForURL http://blah (URL doesn't matter)
+// The answer must be http://<your IP>/<test results>
+// If you see "failed" in the output, lookup the test name in the comments
+// below and let me now at <malte@kde.org> or try to fix it yourself
+
+function FindProxyForURL( url, host )
+{
+ var result = "PROXY http://" + myIPAddress();
+
+ // plainhost1
+ if ( !isPlainHostName( "foo" ) )
+ result += "/plainhost1=failed"
+ // plainhost2
+ if ( isPlainHostName( "foo.bar" ) )
+ result += "/plainhost2=failed";
+
+ // dnsdomain1
+ if ( !dnsDomainIs( "foo.bar", "bar" ) )
+ result += "/dnsdomain1=failed";
+ // dnsdomain2
+ if ( dnsDomainIs( "foo.baz", "bar" ) )
+ result += "/dnsdomain2=failed";
+
+ // localordomain1
+ if ( !localHostOrDomainIs( "foo", "bar" ) )
+ result += "/localordomain1=failed";
+ // localordomain2
+ if ( !localHostOrDomainIs( "foo.bar", "foo.bar" ) )
+ result += "/localordomain2=failed";
+ // localordomain3
+ if ( !localHostOrDomainIs( "foo", "foo.baz" ) )
+ result += "/localordomain3=failed";
+ // localordomain4
+ if ( localHostOrDomainIs( "foo.bar", "foo.baz" ) )
+ result += "/localordomain4=failed";
+
+ // isresolvable1
+ // on failure make sure you can resolve www.kde.org correctly :-)
+ if ( !isResolvable( "www.kde.org" ) ) result += "/isresolvable1=failed";
+ // isresolvable2
+ // on failure make sure dummy.invalid doesn't resolve :-)
+ if ( isResolvable( "dummy.invalid" ) ) result += "/isresolvable2=failed";
+
+ // isinnet1
+ // on failure check if localhost resolves to 127.0.0.1 as it should
+ if ( isInNet( "localhost", "1.2.3.4", "255.0.0.0" ) )
+ result += "/isinnet1=failed";
+ // isinnet2
+ if ( isInNet( "1.2.3.4", "1.2.3.5", "255.255.255.255" ) )
+ result += "/isinnet2=failed";
+ // isinnet3
+ if ( !isInNet( "1.2.3.4", "1.2.3.5", "255.255.255.0" ) )
+ result += "/isinnet3=failed";
+
+ // dnsresolve1
+ // on failure check if localhost resolves to 127.0.0.1 as it should
+ if ( dnsResolve( "localhost" ) != "127.0.0.1" )
+ result += "/dnsresolve1=failed";
+
+ // dnslevels1
+ if ( dnsDomainLevels( "foo" ) != 0 )
+ result += "/dnslevels1=failed";
+ // dnslevels2
+ if ( dnsDomainLevels( "foo.bar" ) != 1 )
+ result += "/dnslevels2=failed";
+ // dnslevels3
+ if ( dnsDomainLevels( "foo.bar.baz" ) != 2 )
+ result += "/dnslevels3=failed";
+
+ // shexp1
+ if ( !shExpMatch( "foobar", "foobar" ) )
+ result += "/shexp1=failed";
+ // shexp2
+ if ( shExpMatch( "FoObAr", "foobar" ) )
+ result += "/shexp2=failed";
+ // shexp3
+ if ( !shExpMatch( "Foobar", "?oobar" ) )
+ result += "/shexp3=failed";
+ // shexp4
+ if ( !shExpMatch( "FoObAr", "*b*" ) )
+ result += "/shexp4=failed";
+ // shexp5
+ if ( shExpMatch( "FoObAr", "*x*" ) )
+ result += "/shexp5=failed";
+ // shexp6
+ if ( shExpMatch( "www.kde.org", "*.kde" ) )
+ result += "/shexp6=failed";
+
+ var now = new Date;
+ var days = new Array( "sun", "mon", "tue", "wed", "thu", "fri", "sat" );
+ var months = new Array( "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" );
+
+ // weekday1
+ if ( !weekdayRange( "sun", "sat" ) )
+ result += "/weekday1=failed";
+ // weekday2
+ if ( !weekdayRange( "sat", "sun" ) )
+ result += "/weekday2=failed";
+ // weekday3
+ if ( !weekdayRange( days[ now.getDay() ] ) )
+ result += "/weekday3=failed";
+ // weekday4
+ if ( weekdayRange( now.getDay() ? "sun" : "mon" ) )
+ result += "/weekday4=failed";
+
+ // date1
+ if ( !dateRange( now.getDate() ) )
+ result += "/date1=failed";
+ // date2
+ if ( !dateRange( now.getDate(), 31 ) )
+ result += "/date2=failed";
+ // date3
+ if ( !dateRange( 1, now.getDate() ) )
+ result += "/date3=failed";
+ // date4
+ if ( dateRange( now.getDay() > 5 ? 1 : 6, now.getDay() > 5 ? 3 : 8 ) )
+ result += "/date4=failed";
+ // date5
+ if ( !dateRange( months[ now.getMonth() ] ) )
+ result += "/date5=failed";
+ // date6
+ if ( !dateRange( months[ now.getMonth() ], "dec" ) )
+ result += "/date6=failed";
+ // date7
+ if ( !dateRange( "dec", months[ now.getMonth() ] ) )
+ result += "/date7=failed";
+ // date8
+ if ( !dateRange( now.getFullYear() ) )
+ result += "/date8=failed";
+ // date9
+ if ( dateRange( now.getFullYear() - 1 ) )
+ result += "/date9=failed";
+ // date10
+ // if this fails, check your clock first :-)
+ if ( dateRange( 1, "jan", 1990, 31, "dec", 2000 ) )
+ result += "/date10=failed";
+ // date11
+ // if this fails, check your clock first :-)
+ if ( !dateRange( 1, "jan", 2000, 31, "dec", 3000 ) )
+ result += "/date11=failed";
+
+ // time1
+ if ( !timeRange( now.getHours() ) )
+ result += "/time1=failed";
+ // time2
+ if ( !timeRange( now.getHours(), now.getMinutes(), 0, 0 ) )
+ result += "/time2=failed";
+ // time3
+ if ( !timeRange( now.getHours(), now.getMinutes(), now.getSeconds(), 0, 0, 0 ) )
+ result += "/time3=failed";
+ // time4
+ if ( timeRange( now.getHours() > 5 ? 1 : 6, now.getHours() > 5 ? 3 : 8 ) )
+ result += "/time4=failed";
+ // time5
+ if ( now.getHours() == now.getUTCHours() )
+ result += "/time5=skipped";
+ else if ( timeRange( now.getUTCHours() ) )
+ result += "/time5=failed";
+ // time6
+ if ( now.getHours() == now.getUTCHours() )
+ result += "/time6=skipped";
+ else if ( !timeRange( now.getUTCHours(), "GMT" ) )
+ result += "/time6=failed";
+
+ return result;
+}
+
diff --git a/tdeio/misc/kpac/proxyscout.cpp b/tdeio/misc/kpac/proxyscout.cpp
new file mode 100644
index 000000000..b651e2313
--- /dev/null
+++ b/tdeio/misc/kpac/proxyscout.cpp
@@ -0,0 +1,196 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 <cstdlib>
+#include <ctime>
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <knotifyclient.h>
+#include <kprotocolmanager.h>
+
+#include "proxyscout.moc"
+#include "discovery.h"
+#include "script.h"
+
+namespace KPAC
+{
+ ProxyScout::QueuedRequest::QueuedRequest( const KURL& u )
+ : transaction( kapp->dcopClient()->beginTransaction() ),
+ url( u )
+ {
+ }
+
+ ProxyScout::ProxyScout( const TQCString& name )
+ : KDEDModule( name ),
+ m_instance( new TDEInstance( "proxyscout" ) ),
+ m_downloader( 0 ),
+ m_script( 0 ),
+ m_suspendTime( 0 )
+ {
+ }
+
+ ProxyScout::~ProxyScout()
+ {
+ delete m_script;
+ delete m_instance;
+ }
+
+ TQString ProxyScout::proxyForURL( const KURL& url )
+ {
+ if ( m_suspendTime )
+ {
+ if ( std::time( 0 ) - m_suspendTime < 300 ) return "DIRECT";
+ m_suspendTime = 0;
+ }
+
+ // Never use a proxy for the script itself
+ if ( m_downloader && url.equals( m_downloader->scriptURL(), true ) ) return "DIRECT";
+
+ if ( m_script ) return handleRequest( url );
+
+ if ( m_downloader || startDownload() )
+ {
+ m_requestQueue.append( url );
+ return TQString::null;
+ }
+ else return "DIRECT";
+ }
+
+ ASYNC ProxyScout::blackListProxy( const TQString& proxy )
+ {
+ m_blackList[ proxy ] = std::time( 0 );
+ }
+
+ ASYNC ProxyScout::reset()
+ {
+ delete m_script;
+ m_script = 0;
+ delete m_downloader;
+ m_downloader = 0;
+ m_blackList.clear();
+ m_suspendTime = 0;
+ KProtocolManager::reparseConfiguration();
+ }
+
+ bool ProxyScout::startDownload()
+ {
+ switch ( KProtocolManager::proxyType() )
+ {
+ case KProtocolManager::WPADProxy:
+ m_downloader = new Discovery( this );
+ break;
+ case KProtocolManager::PACProxy:
+ m_downloader = new Downloader( this );
+ m_downloader->download( KURL( KProtocolManager::proxyConfigScript() ) );
+ break;
+ default:
+ return false;
+ }
+ connect( m_downloader, TQT_SIGNAL( result( bool ) ),
+ TQT_SLOT( downloadResult( bool ) ) );
+ return true;
+ }
+
+ void ProxyScout::downloadResult( bool success )
+ {
+ KNotifyClient::Instance notifyInstance( m_instance );
+ if ( success )
+ try
+ {
+ m_script = new Script( m_downloader->script() );
+ }
+ catch ( const Script::Error& e )
+ {
+ KNotifyClient::event( "script-error", i18n(
+ "The proxy configuration script is invalid:\n%1" )
+ .arg( e.message() ) );
+ success = false;
+ }
+ else KNotifyClient::event( "download-error", m_downloader->error() );
+
+ for ( RequestQueue::ConstIterator it = m_requestQueue.begin();
+ it != m_requestQueue.end(); ++it )
+ {
+ TQCString type = TQSTRING_OBJECT_NAME_STRING;
+ TQByteArray data;
+ TQDataStream ds( data, IO_WriteOnly );
+ if ( success ) ds << handleRequest( ( *it ).url );
+ else ds << TQString( "DIRECT" );
+ kapp->dcopClient()->endTransaction( ( *it ).transaction, type, data );
+ }
+ m_requestQueue.clear();
+ m_downloader->deleteLater();
+ m_downloader = 0;
+ // Suppress further attempts for 5 minutes
+ if ( !success ) m_suspendTime = std::time( 0 );
+ }
+
+ TQString ProxyScout::handleRequest( const KURL& url )
+ {
+ try
+ {
+ TQString result = m_script->evaluate( url );
+ TQStringList proxies = TQStringList::split( ';', result );
+ for ( TQStringList::ConstIterator it = proxies.begin();
+ it != proxies.end(); ++it )
+ {
+ TQString proxy = ( *it ).stripWhiteSpace();
+ if ( proxy.left( 5 ) == "PROXY" )
+ {
+ KURL proxyURL( proxy = proxy.mid( 5 ).stripWhiteSpace() );
+ // If the URL is invalid or the URL is valid but in opaque
+ // format which indicates a port number being present in
+ // this particular case, simply calling setProtocol() on
+ // it trashes the whole URL.
+ int len = proxyURL.protocol().length();
+ if ( !proxyURL.isValid() || proxy.find( ":/", len ) != len )
+ proxy.prepend("http://");
+ BlackList::Iterator it = m_blackList.find( proxy );
+ if ( it == m_blackList.end() ) return proxy;
+ else if ( std::time( 0 ) - *it > 1800 ) // 30 minutes
+ {
+ // black listing expired
+ m_blackList.remove( it );
+ return proxy;
+ }
+ }
+ else return "DIRECT";
+ }
+ // FIXME: blacklist
+ }
+ catch ( const Script::Error& e )
+ {
+ KNotifyClient::Instance notifyInstance( m_instance );
+ KNotifyClient::event( "evaluation-error", i18n(
+ "The proxy configuration script returned an error:\n%1" )
+ .arg( e.message() ) );
+ }
+ return "DIRECT";
+ }
+
+ extern "C" KDE_EXPORT KDEDModule* create_proxyscout( const TQCString& name )
+ {
+ return new ProxyScout( name );
+ }
+}
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/proxyscout.desktop b/tdeio/misc/kpac/proxyscout.desktop
new file mode 100644
index 000000000..02e402b50
--- /dev/null
+++ b/tdeio/misc/kpac/proxyscout.desktop
@@ -0,0 +1,131 @@
+[Desktop Entry]
+Type=Service
+Name=Proxy Scout
+Name[af]=Proksie Verkenner
+Name[az]=Vəkil Skout
+Name[bg]=Проучване на прокÑи Ñървъри
+Name[bn]=পà§à¦°à¦•à§à¦¸à¦¿ সà§à¦•à¦¾à¦‰à¦Ÿ
+Name[ca]=Explorador del servidor intermedi
+Name[cs]=Proxy vyhledávaÄ
+Name[csb]=Pòstrzédnik (proxy)
+Name[cy]=Arweinydd Dirprwy
+Name[de]=Automatische Proxy-Einrichtung
+Name[el]=Διαμεσολαβητής Scout
+Name[eo]=Prokurilo
+Name[es]=Explorador del proxy
+Name[fa]=پیشکار Scout
+Name[fi]=Proxy-tiedustelija
+Name[fy]=Proxy ferkenner
+Name[gl]=Proxy Explorador
+Name[he]=מחפש שרתי Proxy
+Name[hi]= पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सà¥à¤•à¤¾à¤‰à¤Ÿ
+Name[hr]=Proxy izvidnik
+Name[is]=Milliþjóns leitari
+Name[it]=Esploratore proxy
+Name[ja]=プロキシを探ã™
+Name[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ თვითგáƒáƒ›áƒáƒ áƒ—ვáƒ
+Name[kk]=ПрокÑиді автобапату
+Name[ko]=프ë¡ì‹œ 찾기
+Name[lb]=Proxy-Scout
+Name[lt]=Proxy paieška
+Name[mk]=ПрокÑи Ñкаут
+Name[mn]=ИтгÑмжилÑгчийн зам хайгч
+Name[ms]=Scout Proksi
+Name[nb]=Mellomtjenerspeiding
+Name[ne]=पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ सà¥à¤•à¤¾à¤‰à¤Ÿ
+Name[nn]=Mellomtenarspeiding
+Name[pa]=ਪਰਾਕਸੀ ਸਕਾਊਟ
+Name[pl]=Pośrednik (proxy)
+Name[pt]=Escuteiro do 'Proxy'
+Name[pt_BR]=Saída do Proxy
+Name[ru]=ÐвтонаÑтройка прокÑи
+Name[rw]=Igifasha Nyabubasha
+Name[se]=Gaskabálvaohci
+Name[sk]=Prieskumník proxy
+Name[sr]=ПрокÑи извиђач
+Name[sr@Latn]=Proksi izviÄ‘aÄ
+Name[sv]=Proxy-scout
+Name[ta]=பதிலாள௠தேடà¯
+Name[te]=à°ªà±à°°à°¾à°•à±à°¸à±€ వేగà±
+Name[tg]=Разведкачӣ Вакил Кардашуда
+Name[tr]=Vekil Sunucu
+Name[tt]=Proxy Saqçısı
+Name[uk]=Розвідник прокÑÑ– Ñервера
+Name[uz]=Proksi skaut
+Name[uz@cyrillic]=ПрокÑи Ñкаут
+Name[zh_CN]=代ç†æœç´¢
+Comment=Automatic proxy configuration
+Comment[af]=Outomatiese proksie opstelling
+Comment[bg]=Ðвтоматично наÑтройване на прокÑи Ñървъра
+Comment[bn]=সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশন
+Comment[br]=Kefluniadur emgefreekh ar proksi
+Comment[bs]=Automatsko podešavanje proxy-ja
+Comment[ca]=Configuració automàtica de l'intermediari
+Comment[cs]=Automatické nastavení proxy
+Comment[csb]=Aòtokònfigùracëjô pòstrzédnika
+Comment[cy]=Ffurweddiad Awtomatig o'r Dirprwy
+Comment[da]=Automatisk proxy-indstilling
+Comment[de]=Sucht nach einem Proxy-Server und richtet ihn ein
+Comment[el]=Αυτόματη ÏÏθμιση διαμεσολαβητή
+Comment[eo]=AÅ­tomata Prokuragordo
+Comment[es]=Configuración automática del Proxy
+Comment[et]=Automaatne proxy konfigureerimine
+Comment[eu]=Proxy-aren konfigurazio automatikoa
+Comment[fa]=پیکربندی خودکار پیشکار
+Comment[fi]=Automaattiset proxy-asetukset
+Comment[fr]=Configuration automatique du serveur mandataire
+Comment[fy]=Automatyske proxy ynstelling
+Comment[ga]=Uathchumraíocht an tseachfhreastalaí
+Comment[gl]=Configuración Automática do Proxi
+Comment[he]=הגדרות מתווך ×וטומטיות
+Comment[hi]=सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¼à¤¿à¤—रेशन
+Comment[hr]=Automatsko konfiguriranje proxyja
+Comment[hu]=Automatikus proxybeállítás
+Comment[id]=Konfigurasi proxi otomatis
+Comment[is]=Sjálfvirkar stillingar milliþjóns
+Comment[it]=Configurazione automatica proxy
+Comment[ja]=自動プロキシ設定
+Comment[ka]=პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ თვითგáƒáƒ›áƒáƒ áƒ—ვáƒ
+Comment[kk]=ПрокÑиді автоматты түрде бапату
+Comment[km]=ការ​កំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​ប្រូកស៊ី​ដោយ​ស្វáŸáž™áž”្រវážáŸ’ážáž·
+Comment[lb]=Automatesch Proxy-Configuratioun
+Comment[lt]=Automatinis proxy derinimas
+Comment[mk]=ÐвтоматÑка конфигурација на прокÑи
+Comment[ms]=Penyelarasan Proksi Automatik
+Comment[nb]=Automatisk mellomtjeneroppsett
+Comment[nds]=Proxy automaatsch instellen
+Comment[ne]=सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन
+Comment[nl]=Automatische proxyconfiguratie
+Comment[nn]=Automatisk mellomtenaroppsett
+Comment[pa]=ਸਵੈ-ਚਾਲਿਤ ਪਰਾਕਸੀ ਸੰਰਚਨਾ
+Comment[pl]=Autokonfiguracja pośrednika
+Comment[pt]=Configuração automática de 'proxy'
+Comment[pt_BR]=Configuração automática do proxy
+Comment[ro]=Configurare automată pentru proxy
+Comment[ru]=ÐвтонаÑтройка прокÑи-Ñервера
+Comment[rw]=Iboneza rya Nyabubasha Yikoresha
+Comment[se]=Automáhtalaš gaskabálváheiveheapmi
+Comment[sk]=Automatická konfigurácia proxy
+Comment[sl]=Samodejne nastavitve posrednika
+Comment[sr]=ÐутоматÑко подешавање прокÑија
+Comment[sr@Latn]=Automatsko podešavanje proksija
+Comment[sv]=Automatisk proxyinställning
+Comment[ta]=தானியகà¯à®• பதிலாள௠வடிவமைபà¯à®ªà¯
+Comment[te]=à°¸à±à°µà°¯à°‚చాలక à°ªà±à°°à°¾à°•à±à°¸à±€ రూపకరణం
+Comment[tg]=Танзими прокÑи бо автоматикӣ
+Comment[th]=à¸à¸²à¸£à¸›à¸£à¸±à¸šà¹à¸•à¹ˆà¸‡à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸­à¸±à¸•à¹‚นมัติ
+Comment[tr]=Otomatik vekil sunucu yapılandırması
+Comment[tt]=Proxy'nıñ üzzihenle caylanu
+Comment[uk]=Ðвтоматичне Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– Ñервера
+Comment[uz]=Proksini avtomatik ravishda moslash
+Comment[uz@cyrillic]=ПрокÑини автоматик равишда моÑлаш
+Comment[vi]=Cấu hình ủy nhiệm tự động.
+Comment[zh_CN]=自动代ç†é…ç½®
+Comment[zh_HK]=自動代ç†ä¼ºæœå™¨çµ„æ…‹
+Comment[zh_TW]=自動代ç†çµ„æ…‹
+ServiceTypes=KDEDModule
+X-TDE-ModuleType=Library
+X-TDE-Library=proxyscout
+X-TDE-FactoryName=proxyscout
+X-TDE-Kded-autoload=false
+X-TDE-Kded-load-on-demand=true
diff --git a/tdeio/misc/kpac/proxyscout.h b/tdeio/misc/kpac/proxyscout.h
new file mode 100644
index 000000000..78c8fc237
--- /dev/null
+++ b/tdeio/misc/kpac/proxyscout.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 KPAC_PROXYSCOUT_H
+#define KPAC_PROXYSCOUT_H
+
+#include <tqmap.h>
+
+#include <kdedmodule.h>
+#include <kurl.h>
+
+#include <time.h>
+
+class DCOPClientTransaction;
+class TDEInstance;
+
+namespace KPAC
+{
+ class Downloader;
+ class Script;
+
+ class ProxyScout : public KDEDModule
+ {
+ Q_OBJECT
+ K_DCOP
+ public:
+ ProxyScout( const TQCString& );
+ virtual ~ProxyScout();
+
+ k_dcop:
+ TQString proxyForURL( const KURL& url );
+ ASYNC blackListProxy( const TQString& proxy );
+ ASYNC reset();
+
+ private slots:
+ void downloadResult( bool );
+
+ private:
+ bool startDownload();
+ TQString handleRequest( const KURL& url );
+
+ TDEInstance* m_instance;
+ Downloader* m_downloader;
+ Script* m_script;
+
+ struct QueuedRequest
+ {
+ QueuedRequest() : transaction( 0 ) {}
+ QueuedRequest( const KURL& );
+
+ DCOPClientTransaction* transaction;
+ KURL url;
+ };
+ typedef TQValueList< QueuedRequest > RequestQueue;
+ RequestQueue m_requestQueue;
+
+ typedef TQMap< TQString, time_t > BlackList;
+ BlackList m_blackList;
+ time_t m_suspendTime;
+ };
+}
+
+#endif // KPAC_PROXYSCOUT_H
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/script.cpp b/tdeio/misc/kpac/script.cpp
new file mode 100644
index 000000000..55faef8a1
--- /dev/null
+++ b/tdeio/misc/kpac/script.cpp
@@ -0,0 +1,465 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 <cstdlib>
+#include <vector>
+#include <algorithm>
+#include <ctime>
+#include <cstring>
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <tqregexp.h>
+#include <tqstring.h>
+
+#include <kurl.h>
+#include <kjs/object.h>
+#include <kresolver.h>
+
+#include "script.h"
+
+using namespace KJS;
+
+TQString UString::qstring() const
+{
+ return TQString( reinterpret_cast< const TQChar* >( data() ), size() );
+}
+
+UString::UString( const TQString &s )
+{
+ UChar* data = new UChar[ s.length() ];
+ std::memcpy( data, s.unicode(), s.length() * sizeof( UChar ) );
+ rep = Rep::create( data, s.length() );
+}
+
+namespace
+{
+ class Address
+ {
+ public:
+ struct Error {};
+ static Address resolve( const UString& host )
+ { return Address( host.qstring(), false ); }
+ static Address parse( const UString& ip )
+ { return Address( ip.qstring(), true ); }
+
+ operator in_addr_t() const {
+ const sockaddr_in* sin = m_address;
+ return sin->sin_addr.s_addr;
+ }
+
+ operator String() const { return String( m_address.ipAddress().toString() ); }
+
+ private:
+ Address( const TQString& host, bool numeric )
+ {
+ int flags = 0;
+
+ if ( numeric )
+ flags = KNetwork::KResolver::NoResolve;
+
+ KNetwork::KResolverResults addresses =
+ KNetwork::KResolver::resolve( host, TQString::null, flags,
+ KNetwork::KResolver::IPv4Family );
+
+ if ( addresses.isEmpty() )
+ throw Error();
+
+ m_address = addresses.first().address().asInet();
+ }
+
+ KNetwork::KInetSocketAddress m_address;
+ };
+
+ struct Function : public ObjectImp
+ {
+ struct ResolveError {};
+
+ virtual bool implementsCall() const { return true; }
+
+ static int findString( const UString& s, const char* const* values )
+ {
+ int index = 0;
+ UString lower = s.toLower();
+ for ( const char* const* p = values; *p; ++p, ++index )
+ if ( lower == *p ) return index;
+ return -1;
+ }
+
+ static const tm* getTime( ExecState* exec, const List& args )
+ {
+ time_t now = std::time( 0 );
+ if ( args[ args.size() - 1 ].toString( exec ).toLower() == "gmt" )
+ return std::gmtime( &now );
+ else return std::localtime( &now );
+ }
+
+ Boolean checkRange( int value, int min, int max )
+ {
+ return ( min <= max && value >= min && value <= max ) ||
+ ( min > max && ( value <= min || value >= max ) );
+ }
+ };
+
+ // isPlainHostName( host )
+ // @returns true if @p host doesn't contains a domain part
+ struct IsPlainHostName : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 1 ) return Undefined();
+ return Boolean( args[ 0 ].toString( exec ).find( "." ) == -1 );
+ }
+ };
+
+ // dnsDomainIs( host, domain )
+ // @returns true if the domain part of @p host matches @p domain
+ struct DNSDomainIs : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 2 ) return Undefined();
+ TQString host = args[ 0 ].toString( exec ).qstring().lower();
+ TQString domain = args[ 1 ].toString( exec ).qstring().lower();
+ return Boolean( host.endsWith( domain ) );
+ }
+ };
+
+ // localHostOrDomainIs( host, fqdn )
+ // @returns true if @p host is unqualified or equals @p fqdn
+ struct LocalHostOrDomainIs : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 2 ) return Undefined();
+ UString host = args[ 0 ].toString( exec ).toLower();
+ if ( host.find( "." ) == -1 ) return Boolean( true );
+ UString fqdn = args[ 1 ].toString( exec ).toLower();
+ return Boolean( host == fqdn );
+ }
+ };
+
+ // isResolvable( host )
+ // @returns true if host can be resolved via DNS
+ struct IsResolvable : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 1 ) return Undefined();
+ try { ::Address::resolve( args[ 0 ].toString( exec ) ); }
+ catch ( const Address::Error& ) { return Boolean( false ); }
+ return Boolean( true );
+ }
+ };
+
+ // isInNet( host, subnet, mask )
+ // @returns true if @p host is within the IP subnet
+ // specified via @p subnet and @p mask
+ struct IsInNet : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 3 ) return Undefined();
+ try
+ {
+ in_addr_t host = Address::resolve( args[ 0 ].toString( exec ) );
+ in_addr_t subnet = Address::parse( args[ 1 ].toString( exec ) );
+ in_addr_t mask = Address::parse( args[ 2 ].toString( exec ) );
+ return Boolean( ( host & mask ) == ( subnet & mask ) );
+ }
+ catch ( const Address::Error& )
+ {
+ return Undefined();
+ }
+ }
+ };
+
+ // dnsResolve( host )
+ // @returns the IP address of @p host in dotted quad notation
+ struct DNSResolve : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 1 ) return Undefined();
+ try { return String(Address::resolve( args[ 0 ].toString( exec ))); }
+ catch ( const Address::Error& ) { return Undefined(); }
+ }
+ };
+
+ // myIpAddress()
+ // @returns the local machine's IP address in dotted quad notation
+ struct MyIpAddress : public Function
+ {
+ virtual Value call( ExecState*, Object&, const List& args )
+ {
+ if ( args.size() ) return Undefined();
+ char hostname[ 256 ];
+ gethostname( hostname, 255 );
+ hostname[ 255 ] = 0;
+ try { return String(Address::resolve( hostname )); }
+ catch ( const Address::Error& ) { return Undefined(); }
+ }
+ };
+
+ // dnsDomainLevels( host )
+ // @returns the number of dots ('.') in @p host
+ struct DNSDomainLevels : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 1 ) return Undefined();
+ UString host = args[ 0 ].toString( exec );
+ if ( host.isNull() ) return Number( 0 );
+ return Number( std::count(
+ host.data(), host.data() + host.size(), '.' ) );
+ }
+ };
+
+ // shExpMatch( str, pattern )
+ // @returns true if @p str matches the shell @p pattern
+ struct ShExpMatch : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() != 2 ) return Undefined();
+ TQRegExp pattern( args[ 1 ].toString( exec ).qstring(), true, true );
+ return Boolean( pattern.exactMatch(args[ 0 ].toString( exec ).qstring()) );
+ }
+ };
+
+ // weekdayRange( day [, "GMT" ] )
+ // weekdayRange( day1, day2 [, "GMT" ] )
+ // @returns true if the current day equals day or between day1 and day2 resp.
+ // If the last argument is "GMT", GMT timezone is used, otherwise local time
+ struct WeekdayRange : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() < 1 || args.size() > 3 ) return Undefined();
+ static const char* const days[] =
+ { "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 };
+ int d1 = findString( args[ 0 ].toString( exec ), days );
+ if ( d1 == -1 ) return Undefined();
+
+ int d2 = findString( args[ 1 ].toString( exec ), days );
+ if ( d2 == -1 ) d2 = d1;
+ return checkRange( getTime( exec, args )->tm_wday, d1, d2 );
+ }
+ };
+
+ // dateRange( day [, "GMT" ] )
+ // dateRange( day1, day2 [, "GMT" ] )
+ // dateRange( month [, "GMT" ] )
+ // dateRange( month1, month2 [, "GMT" ] )
+ // dateRange( year [, "GMT" ] )
+ // dateRange( year1, year2 [, "GMT" ] )
+ // dateRange( day1, month1, day2, month2 [, "GMT" ] )
+ // dateRange( month1, year1, month2, year2 [, "GMT" ] )
+ // dateRange( day1, month1, year1, day2, month2, year2 [, "GMT" ] )
+ // @returns true if the current date (GMT or local time according to
+ // presence of "GMT" as last argument) is within the given range
+ struct DateRange : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() < 1 || args.size() > 7 ) return Undefined();
+ static const char* const months[] =
+ { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "nov", "dec", 0 };
+
+ std::vector< int > values;
+ for ( int i = 0; i < args.size(); ++i )
+ {
+ int value = -1;
+ if ( args[ i ].isA( NumberType ) )
+ value = args[ i ].toInteger( exec );
+ else value = findString( args[ i ].toString( exec ), months );
+ if ( value >= 0 ) values.push_back( value );
+ else break;
+ }
+
+ const tm* now = getTime( exec, args );
+
+ // day1, month1, year1, day2, month2, year2
+ if ( values.size() == 6 )
+ return checkRange( ( now->tm_year + 1900 ) * 372 + now->tm_mon * 31 + now->tm_mday,
+ values[ 2 ] * 372 + values[ 1 ] * 31 + values[ 0 ],
+ values[ 5 ] * 372 + values[ 4 ] * 31 + values[ 3 ] );
+
+ // day1, month1, day2, month2
+ else if ( values.size() == 4 &&
+ values[ 1 ] < 12 &&
+ values[ 3 ] < 12 )
+ return checkRange( now->tm_mon * 31 + now->tm_mday,
+ values[ 1 ] * 31 + values[ 0 ],
+ values[ 3 ] * 31 + values[ 2 ] );
+
+ // month1, year1, month2, year2
+ else if ( values.size() == 4 )
+ return checkRange( ( now->tm_year + 1900 ) * 12 + now->tm_mon,
+ values[ 1 ] * 12 + values[ 0 ],
+ values[ 3 ] * 12 + values[ 2 ] );
+
+ // year1, year2
+ else if ( values.size() == 2 &&
+ values[ 0 ] >= 1000 &&
+ values[ 1 ] >= 1000 )
+ return checkRange( now->tm_year + 1900, values[ 0 ], values[ 1 ] );
+
+ // day1, day2
+ else if ( values.size() == 2 &&
+ args[ 0 ].isA( NumberType ) &&
+ args[ 1 ].isA( NumberType ) )
+ return checkRange( now->tm_mday, values[ 0 ], values[ 1 ] );
+
+ // month1, month2
+ else if ( values.size() == 2 )
+ return checkRange( now->tm_mon, values[ 0 ], values[ 1 ] );
+
+ // year
+ else if ( values.size() == 1 && values[ 0 ] >= 1000 )
+ return checkRange( now->tm_year + 1900, values[ 0 ], values[ 0 ] );
+
+ // day
+ else if ( values.size() == 1 && args[ 0 ].isA( NumberType ) )
+ return checkRange( now->tm_mday, values[ 0 ], values[ 0 ] );
+
+ // month
+ else if ( values.size() == 1 )
+ return checkRange( now->tm_mon, values[ 0 ], values[ 0 ] );
+
+ else return Undefined();
+ }
+ };
+
+ // timeRange( hour [, "GMT" ] )
+ // timeRange( hour1, hour2 [, "GMT" ] )
+ // timeRange( hour1, min1, hour2, min2 [, "GMT" ] )
+ // timeRange( hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ] )
+ // @returns true if the current time (GMT or local based on presence
+ // of "GMT" argument) is within the given range
+ struct TimeRange : public Function
+ {
+ virtual Value call( ExecState* exec, Object&, const List& args )
+ {
+ if ( args.size() < 1 || args.size() > 7 ) return Undefined();
+
+ std::vector< int > values;
+ for ( int i = 0; i < args.size(); ++i )
+ if ( args[ i ].isA( NumberType ) )
+ values.push_back( args[ i ].toInteger( exec ) );
+ else break;
+
+ const tm* now = getTime( exec, args );
+
+ // hour1, min1, sec1, hour2, min2, sec2
+ if ( values.size() == 6 )
+ return checkRange( now->tm_hour * 3600 + now->tm_min * 60 + now->tm_sec,
+ values[ 0 ] * 3600 + values[ 1 ] * 60 + values[ 2 ],
+ values[ 3 ] * 3600 + values[ 4 ] * 60 + values[ 5 ] );
+
+ // hour1, min1, hour2, min2
+ else if ( values.size() == 4 )
+ return checkRange( now->tm_hour * 60 + now->tm_min,
+ values[ 0 ] * 60 + values[ 1 ],
+ values[ 2 ] * 60 + values[ 3 ] );
+
+ // hour1, hour2
+ else if ( values.size() == 2 )
+ return checkRange( now->tm_hour, values[ 0 ], values[ 1 ] );
+
+ // hour
+ else if ( values.size() == 1 )
+ return checkRange( now->tm_hour, values[ 0 ], values[ 0 ] );
+
+ else return Undefined();
+ }
+ };
+
+ void registerFunctions( ExecState* exec, Object& global )
+ {
+ global.put( exec, "isPlainHostName",
+ Object( new IsPlainHostName ) );
+ global.put( exec, "dnsDomainIs",
+ Object( new DNSDomainIs ) );
+ global.put( exec, "localHostOrDomainIs",
+ Object( new LocalHostOrDomainIs ) );
+ global.put( exec, "isResolvable",
+ Object( new IsResolvable ) );
+ global.put( exec, "isInNet",
+ Object( new IsInNet ) );
+ global.put( exec, "dnsResolve",
+ Object( new DNSResolve ) );
+ global.put( exec, "myIpAddress",
+ Object( new MyIpAddress ) );
+ global.put( exec, "dnsDomainLevels",
+ Object( new DNSDomainLevels ) );
+ global.put( exec, "shExpMatch",
+ Object( new ShExpMatch ) );
+ global.put( exec, "weekdayRange",
+ Object( new WeekdayRange ) );
+ global.put( exec, "dateRange",
+ Object( new DateRange ) );
+ global.put( exec, "timeRange",
+ Object( new TimeRange ) );
+ }
+}
+
+namespace KPAC
+{
+ Script::Script( const TQString& code )
+ {
+ ExecState* exec = m_interpreter.globalExec();
+ Object global = m_interpreter.globalObject();
+ registerFunctions( exec, global );
+
+ Completion result = m_interpreter.evaluate( code );
+ if ( result.complType() == Throw )
+ throw Error( result.value().toString( exec ).qstring() );
+ }
+
+ TQString Script::evaluate( const KURL& url )
+ {
+ ExecState *exec = m_interpreter.globalExec();
+ Value findFunc = m_interpreter.globalObject().get( exec, "FindProxyForURL" );
+ Object findObj = Object::dynamicCast( findFunc );
+ if (!findObj.isValid() || !findObj.implementsCall())
+ throw Error( "No such function FindProxyForURL" );
+
+ Object thisObj;
+ List args;
+ args.append(String(url.url()));
+ args.append(String(url.host()));
+ Value retval = findObj.call( exec, thisObj, args );
+
+ if ( exec->hadException() ) {
+ Value ex = exec->exception();
+ exec->clearException();
+ throw Error( ex.toString( exec ).qstring() );
+ }
+
+ return retval.toString( exec ).qstring();
+ }
+}
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kpac/script.h b/tdeio/misc/kpac/script.h
new file mode 100644
index 000000000..49ba0b6a3
--- /dev/null
+++ b/tdeio/misc/kpac/script.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2003 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 KPAC_SCRIPT_H
+#define KPAC_SCRIPT_H
+
+#include <tqstring.h>
+
+#include <kjs/interpreter.h>
+
+class KURL;
+
+namespace KPAC
+{
+ class Script
+ {
+ public:
+ class Error
+ {
+ public:
+ Error( const TQString& message )
+ : m_message( message ) {}
+ const TQString& message() const { return m_message; }
+
+ private:
+ TQString m_message;
+ };
+
+ Script( const TQString& code );
+ TQString evaluate( const KURL& );
+
+ private:
+ KJS::Interpreter m_interpreter;
+ };
+}
+
+#endif // KPAC_SCRIPT_H
+
+// vim: ts=4 sw=4 et
diff --git a/tdeio/misc/kssld/CMakeLists.txt b/tdeio/misc/kssld/CMakeLists.txt
new file mode 100644
index 000000000..813ce44f0
--- /dev/null
+++ b/tdeio/misc/kssld/CMakeLists.txt
@@ -0,0 +1,47 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdeio/kssl
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeio/kssl
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install(FILES kssld.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded )
+
+
+##### kded_kssld ###########################
+
+set( target kded_kssld )
+
+set( ${target}_SRCS
+ kssld.cpp kssld.skel
+)
+
+tde_add_kpart( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeinit_kded-shared
+ DEPENDENCIES dcopidl
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/tdeio/misc/kssld/Makefile.am b/tdeio/misc/kssld/Makefile.am
new file mode 100644
index 000000000..09ddfe440
--- /dev/null
+++ b/tdeio/misc/kssld/Makefile.am
@@ -0,0 +1,33 @@
+# This file is part of the KDE libraries
+# Copyright (C) 2001 George Staikos <staikos@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.
+
+INCLUDES= -I$(srcdir)/.. -I$(top_srcdir) $(SSL_INCLUDES) -I$(top_srcdir)/tdeio/kssl -I$(top_builddir)/tdeio/kssl $(all_includes)
+
+kde_module_LTLIBRARIES = kded_kssld.la
+
+kded_kssld_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_kssld_la_LIBADD = $(LIB_KIO) $(LIB_KDED) $(LIB_QT) $(top_builddir)/dcop/libDCOP.la $(LIB_TDECORE)
+kded_kssld_la_SOURCES = kssld.cpp kssld.skel
+
+METASOURCES = AUTO
+
+noinst_HEADERS = kssld.h
+
+services_DATA = kssld.desktop
+servicesdir = $(kde_servicesdir)/kded
+
diff --git a/tdeio/misc/kssld/kssld.cpp b/tdeio/misc/kssld/kssld.cpp
new file mode 100644
index 000000000..aa561cc8b
--- /dev/null
+++ b/tdeio/misc/kssld/kssld.cpp
@@ -0,0 +1,1027 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2001-2005 George Staikos <staikos@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.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqtimer.h>
+
+#include "kssld.h"
+#include <tdeconfig.h>
+#include <ksimpleconfig.h>
+#include <ksslcertchain.h>
+#include <ksslcertificate.h>
+#include <ksslcertificatehome.h>
+#include <ksslpkcs12.h>
+#include <ksslx509map.h>
+#include <tqptrlist.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <tqfile.h>
+#include <tqsortedlist.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <tqdatetime.h>
+
+#include <kmdcodec.h>
+#include <kopenssl.h>
+
+// See design notes at end
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_kssld(const TQCString &name) {
+ return new KSSLD(name);
+ }
+
+ KDE_EXPORT void *__kde_do_unload;
+}
+
+
+static void updatePoliciesConfig(TDEConfig *cfg) {
+ TQStringList groups = cfg->groupList();
+
+ for (TQStringList::Iterator i = groups.begin(); i != groups.end(); ++i) {
+ if ((*i).isEmpty() || *i == "General") {
+ continue;
+ }
+
+ cfg->setGroup(*i);
+
+ // remove it if it has expired
+ if (!cfg->readBoolEntry("Permanent") && cfg->readDateTimeEntry("Expires") < TQDateTime::currentDateTime()) {
+ cfg->deleteGroup(*i);
+ continue;
+ }
+
+ TQString encodedCertStr = cfg->readEntry("Certificate");
+ TQCString encodedCert = encodedCertStr.local8Bit();
+ KSSLCertificate *newCert = KSSLCertificate::fromString(encodedCert);
+ if (!newCert) {
+ cfg->deleteGroup(*i);
+ continue;
+ }
+
+ KSSLCertificateCache::KSSLCertificatePolicy policy = (KSSLCertificateCache::KSSLCertificatePolicy) cfg->readNumEntry("Policy");
+ bool permanent = cfg->readBoolEntry("Permanent");
+ TQDateTime expires = cfg->readDateTimeEntry("Expires");
+ TQStringList hosts = cfg->readListEntry("Hosts");
+ TQStringList chain = cfg->readListEntry("Chain");
+ cfg->deleteGroup(*i);
+
+ cfg->setGroup(newCert->getMD5Digest());
+ cfg->writeEntry("Certificate", encodedCertStr);
+ cfg->writeEntry("Policy", policy);
+ cfg->writeEntry("Permanent", permanent);
+ cfg->writeEntry("Expires", expires);
+ cfg->writeEntry("Hosts", hosts);
+ cfg->writeEntry("Chain", chain);
+ delete newCert;
+ }
+
+ cfg->setGroup("General");
+ cfg->writeEntry("policies version", 2);
+
+ cfg->sync();
+}
+
+
+KSSLD::KSSLD(const TQCString &name) : KDEDModule(name)
+{
+// ----------------------- FOR THE CACHE ------------------------------------
+ cfg = new KSimpleConfig("ksslpolicies", false);
+ cfg->setGroup("General");
+ if (2 != cfg->readNumEntry("policies version", 0)) {
+ ::updatePoliciesConfig(cfg);
+ }
+ TDEGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl");
+ caVerifyUpdate();
+ cacheLoadDefaultPolicies();
+ certList.setAutoDelete(false);
+ kossl = KOSSL::self();
+
+// ----------------------- FOR THE HOME -------------------------------------
+}
+
+
+KSSLD::~KSSLD()
+{
+// ----------------------- FOR THE CACHE ------------------------------------
+ cacheClearList();
+ delete cfg;
+
+// ----------------------- FOR THE HOME -------------------------------------
+}
+
+
+
+
+// A node in the cache
+class KSSLCNode {
+ public:
+ KSSLCertificate *cert;
+ KSSLCertificateCache::KSSLCertificatePolicy policy;
+ bool permanent;
+ TQDateTime expires;
+ TQStringList hosts;
+ KSSLCNode() { cert = 0L;
+ policy = KSSLCertificateCache::Unknown;
+ permanent = true;
+ }
+ ~KSSLCNode() { delete cert; }
+};
+
+
+
+void KSSLD::cacheSaveToDisk() {
+KSSLCNode *node;
+
+ cfg->setGroup("General");
+ cfg->writeEntry("policies version", 2);
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (node->permanent ||
+ node->expires > TQDateTime::currentDateTime()) {
+ // First convert to a binary format and then write the
+ // tdeconfig entry write the (CN, policy, cert) to
+ // KSimpleConfig
+ cfg->setGroup(node->cert->getMD5Digest());
+ cfg->writeEntry("Certificate", node->cert->toString());
+ cfg->writeEntry("Policy", node->policy);
+ cfg->writeEntry("Expires", node->expires);
+ cfg->writeEntry("Permanent", node->permanent);
+ cfg->writeEntry("Hosts", node->hosts);
+
+ // Also write the chain
+ TQStringList qsl;
+ TQPtrList<KSSLCertificate> cl =
+ node->cert->chain().getChain();
+ for (KSSLCertificate *c = cl.first();
+ c != 0;
+ c = cl.next()) {
+ //kdDebug() << "Certificate in chain: "
+ // << c->toString() << endl;
+ qsl << c->toString();
+ }
+
+ cl.setAutoDelete(true);
+ cfg->writeEntry("Chain", qsl);
+ }
+ }
+
+ cfg->sync();
+
+ // insure proper permissions -- contains sensitive data
+ TQString cfgName(TDEGlobal::dirs()->findResource("config", "ksslpolicies"));
+
+ if (!cfgName.isEmpty()) {
+ ::chmod(TQFile::encodeName(cfgName), 0600);
+ }
+}
+
+
+void KSSLD::cacheReload() {
+ cacheClearList();
+ delete cfg;
+ cfg = new KSimpleConfig("ksslpolicies", false);
+ cacheLoadDefaultPolicies();
+}
+
+
+void KSSLD::cacheClearList() {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ certList.remove(node);
+ delete node;
+ }
+
+ skEmail.clear();
+ skMD5Digest.clear();
+}
+
+
+void KSSLD::cacheLoadDefaultPolicies() {
+TQStringList groups = cfg->groupList();
+
+ for (TQStringList::Iterator i = groups.begin();
+ i != groups.end();
+ ++i) {
+ if ((*i).isEmpty() || *i == "General") {
+ continue;
+ }
+
+ cfg->setGroup(*i);
+
+ // remove it if it has expired
+ if (!cfg->readBoolEntry("Permanent") &&
+ cfg->readDateTimeEntry("Expires") <
+ TQDateTime::currentDateTime()) {
+ cfg->deleteGroup(*i);
+ continue;
+ }
+
+ TQCString encodedCert;
+ KSSLCertificate *newCert;
+
+ encodedCert = cfg->readEntry("Certificate").local8Bit();
+ newCert = KSSLCertificate::fromString(encodedCert);
+
+ if (!newCert) {
+ continue;
+ }
+
+ KSSLCNode *n = new KSSLCNode;
+ n->cert = newCert;
+ n->policy = (KSSLCertificateCache::KSSLCertificatePolicy) cfg->readNumEntry("Policy");
+ n->permanent = cfg->readBoolEntry("Permanent");
+ n->expires = cfg->readDateTimeEntry("Expires");
+ n->hosts = cfg->readListEntry("Hosts");
+ newCert->chain().setCertChain(cfg->readListEntry("Chain"));
+ certList.append(n);
+ searchAddCert(newCert);
+ }
+}
+
+
+void KSSLD::cacheAddCertificate(KSSLCertificate cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ node->policy = policy;
+ node->permanent = permanent;
+
+ if (!permanent) {
+ node->expires = TQDateTime::currentDateTime();
+ // FIXME: make this configurable
+ node->expires = TQT_TQDATETIME_OBJECT(node->expires.addSecs(3600));
+ }
+
+ cacheSaveToDisk();
+ return;
+ }
+ }
+
+ KSSLCNode *n = new KSSLCNode;
+ n->cert = cert.replicate();
+ n->policy = policy;
+ n->permanent = permanent;
+ // remove the old one
+ cacheRemoveByCertificate(*(n->cert));
+ certList.prepend(n);
+
+ if (!permanent) {
+ n->expires = TQDateTime::currentDateTime();
+ n->expires = TQT_TQDATETIME_OBJECT(n->expires.addSecs(3600));
+ }
+
+ searchAddCert(n->cert);
+ cacheSaveToDisk();
+}
+
+
+KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCN(TQString cn) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
+ if (!node->permanent &&
+ node->expires < TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ delete node;
+ continue;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ cacheSaveToDisk();
+ return node->policy;
+ }
+ }
+
+ cacheSaveToDisk();
+
+return KSSLCertificateCache::Unknown;
+}
+
+
+KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCertificate(KSSLCertificate cert) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent &&
+ node->expires < TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ delete node;
+ cacheSaveToDisk();
+ return KSSLCertificateCache::Unknown;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ return node->policy;
+ }
+ }
+
+return KSSLCertificateCache::Unknown;
+}
+
+
+bool KSSLD::cacheSeenCN(TQString cn) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
+ if (!node->permanent &&
+ node->expires < TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ delete node;
+ cacheSaveToDisk();
+ continue;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheSeenCertificate(KSSLCertificate cert) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent &&
+ node->expires < TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ delete node;
+ cacheSaveToDisk();
+ return false;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheIsPermanent(KSSLCertificate cert) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent && node->expires <
+ TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ delete node;
+ cacheSaveToDisk();
+ return false;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ return node->permanent;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheRemoveBySubject(TQString subject) {
+KSSLCNode *node;
+bool gotOne = false;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (node->cert->getSubject() == subject) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ gotOne = true;
+ }
+ }
+
+ cacheSaveToDisk();
+
+return gotOne;
+}
+
+
+bool KSSLD::cacheRemoveByCN(TQString cn) {
+KSSLCNode *node;
+bool gotOne = false;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ gotOne = true;
+ }
+ }
+
+ cacheSaveToDisk();
+
+return gotOne;
+}
+
+
+bool KSSLD::cacheRemoveByCertificate(KSSLCertificate cert) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ cacheSaveToDisk();
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheModifyByCN(TQString cn,
+ KSSLCertificateCache::KSSLCertificatePolicy policy, bool permanent,
+ TQDateTime expires) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
+ node->permanent = permanent;
+ node->expires = expires;
+ node->policy = policy;
+ certList.remove(node);
+ certList.prepend(node);
+ cacheSaveToDisk();
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheModifyByCertificate(KSSLCertificate cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime expires) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ node->permanent = permanent;
+ node->expires = expires;
+ node->policy = policy;
+ certList.remove(node);
+ certList.prepend(node);
+ cacheSaveToDisk();
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+TQStringList KSSLD::cacheGetHostList(KSSLCertificate cert) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent && node->expires <
+ TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ cacheSaveToDisk();
+ return TQStringList();
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ return node->hosts;
+ }
+ }
+
+return TQStringList();
+}
+
+
+bool KSSLD::cacheAddHost(KSSLCertificate cert, TQString host) {
+KSSLCNode *node;
+
+ if (host.isEmpty())
+ return true;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent && node->expires <
+ TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ cacheSaveToDisk();
+ return false;
+ }
+
+ if (!node->hosts.contains(host)) {
+ node->hosts << host;
+ }
+
+ certList.remove(node);
+ certList.prepend(node);
+ cacheSaveToDisk();
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+bool KSSLD::cacheRemoveHost(KSSLCertificate cert, TQString host) {
+KSSLCNode *node;
+
+ for (node = certList.first(); node; node = certList.next()) {
+ if (cert == *(node->cert)) {
+ if (!node->permanent && node->expires <
+ TQDateTime::currentDateTime()) {
+ certList.remove(node);
+ cfg->deleteGroup(node->cert->getMD5Digest());
+ searchRemoveCert(node->cert);
+ delete node;
+ cacheSaveToDisk();
+ return false;
+ }
+ node->hosts.remove(host);
+ certList.remove(node);
+ certList.prepend(node);
+ cacheSaveToDisk();
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////
+
+void KSSLD::caVerifyUpdate() {
+ TQString path = TDEGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt";
+ if (!TQFile::exists(path))
+ return;
+
+ cfg->setGroup(TQString::null);
+ TQ_UINT32 newStamp = TDEGlobal::dirs()->calcResourceHash("config", "ksslcalist", true);
+ TQ_UINT32 oldStamp = cfg->readUnsignedNumEntry("ksslcalistStamp");
+ if (oldStamp != newStamp)
+ {
+ caRegenerate();
+ cfg->writeEntry("ksslcalistStamp", newStamp);
+ cfg->sync();
+ }
+}
+
+bool KSSLD::caRegenerate() {
+TQString path = TDEGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt";
+
+TQFile out(path);
+
+ if (!out.open(IO_WriteOnly))
+ return false;
+
+TDEConfig cfg("ksslcalist", true, false);
+
+TQStringList x = cfg.groupList();
+
+ for (TQStringList::Iterator i = x.begin();
+ i != x.end();
+ ++i) {
+ if ((*i).isEmpty() || *i == "<default>") continue;
+
+ cfg.setGroup(*i);
+
+ if (!cfg.readBoolEntry("site", false)) continue;
+
+ TQString cert = cfg.readEntry("x509", "");
+ if (cert.length() <= 0) continue;
+
+ unsigned int xx = cert.length() - 1;
+ for (unsigned int j = 0; j < xx/64; j++) {
+ cert.insert(64*(j+1)+j, '\n');
+ }
+ out.writeBlock("-----BEGIN CERTIFICATE-----\n", 28);
+ out.writeBlock(cert.latin1(), cert.length());
+ out.writeBlock("\n-----END CERTIFICATE-----\n\n", 28);
+ out.flush();
+ }
+
+return true;
+}
+
+
+
+bool KSSLD::caAdd(TQString certificate, bool ssl, bool email, bool code) {
+KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit());
+
+ if (!x) return false;
+
+TDEConfig cfg("ksslcalist", false, false);
+
+ cfg.setGroup(x->getSubject());
+ cfg.writeEntry("x509", certificate);
+ cfg.writeEntry("site", ssl);
+ cfg.writeEntry("email", email);
+ cfg.writeEntry("code", code);
+
+ cfg.sync();
+ delete x;
+
+return true;
+}
+
+
+/**
+ * @internal
+ * Returns a list of certificates as QStrings read from the given file
+ */
+static TQStringList caReadCerticatesFromFile(TQString filename) {
+
+ TQStringList certificates;
+ TQString certificate, temp;
+ TQFile file(filename);
+
+ if (!file.open(IO_ReadOnly))
+ return certificates;
+
+ while (!file.atEnd()) {
+ file.readLine(temp, 999);
+ if (temp.startsWith("-----BEGIN CERTIFICATE-----")) {
+ certificate = TQString::null;
+ continue;
+ }
+
+ if (temp.startsWith("-----END CERTIFICATE-----")) {
+ certificates.append(certificate);
+ certificate = TQString::null;
+ continue;
+ }
+
+ certificate += temp.stripWhiteSpace();
+ }
+
+ file.close();
+
+ return certificates;
+}
+
+bool KSSLD::caAddFromFile(TQString filename, bool ssl, bool email, bool code) {
+
+ TQStringList certificates;
+ certificates = caReadCerticatesFromFile(filename);
+ if (certificates.isEmpty())
+ return false;
+
+ bool ok = true;
+
+ for (TQStringList::Iterator it = certificates.begin();
+ it != certificates.end(); ++it ) {
+ ok &= caAdd(*it, ssl, email, code);
+ }
+
+ return ok;
+}
+
+bool KSSLD::caRemoveFromFile(TQString filename) {
+
+ TQStringList certificates;
+ certificates = caReadCerticatesFromFile(filename);
+ if (certificates.isEmpty())
+ return false;
+
+ bool ok = true;
+
+ for (TQStringList::Iterator it = certificates.begin();
+ it != certificates.end(); ++it ) {
+ TQString certificate = *it;
+ KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit());
+ ok &= x && caRemove(x->getSubject());
+ delete x;
+ }
+
+ return ok;
+}
+
+
+TQStringList KSSLD::caList() {
+TQStringList x;
+TDEConfig cfg("ksslcalist", true, false);
+
+ x = cfg.groupList();
+ x.remove("<default>");
+
+return x;
+}
+
+
+bool KSSLD::caUseForSSL(TQString subject) {
+TDEConfig cfg("ksslcalist", true, false);
+
+ if (!cfg.hasGroup(subject))
+ return false;
+
+ cfg.setGroup(subject);
+return cfg.readBoolEntry("site", false);
+}
+
+
+
+bool KSSLD::caUseForEmail(TQString subject) {
+TDEConfig cfg("ksslcalist", true, false);
+
+ if (!cfg.hasGroup(subject))
+ return false;
+
+ cfg.setGroup(subject);
+return cfg.readBoolEntry("email", false);
+}
+
+
+
+bool KSSLD::caUseForCode(TQString subject) {
+TDEConfig cfg("ksslcalist", true, false);
+
+ if (!cfg.hasGroup(subject))
+ return false;
+
+ cfg.setGroup(subject);
+return cfg.readBoolEntry("code", false);
+}
+
+
+bool KSSLD::caRemove(TQString subject) {
+TDEConfig cfg("ksslcalist", false, false);
+ if (!cfg.hasGroup(subject))
+ return false;
+
+ cfg.deleteGroup(subject);
+ cfg.sync();
+
+return true;
+}
+
+
+TQString KSSLD::caGetCert(TQString subject) {
+TDEConfig cfg("ksslcalist", true, false);
+ if (!cfg.hasGroup(subject))
+ return TQString::null;
+
+ cfg.setGroup(subject);
+
+return cfg.readEntry("x509", TQString::null);
+}
+
+
+bool KSSLD::caSetUse(TQString subject, bool ssl, bool email, bool code) {
+TDEConfig cfg("ksslcalist", false, false);
+ if (!cfg.hasGroup(subject))
+ return false;
+
+ cfg.setGroup(subject);
+
+ cfg.writeEntry("site", ssl);
+ cfg.writeEntry("email", email);
+ cfg.writeEntry("code", code);
+ cfg.sync();
+
+return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void KSSLD::searchAddCert(KSSLCertificate *cert) {
+ skMD5Digest.insert(cert->getMD5Digest(), cert, true);
+
+ TQStringList mails;
+ cert->getEmails(mails);
+ for(TQStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) {
+ TQString email = static_cast<const TQString &>(*iter).lower();
+ TQMap<TQString, TQPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email);
+
+ if (it == skEmail.end())
+ it = skEmail.insert(email, TQPtrVector<KSSLCertificate>());
+
+ TQPtrVector<KSSLCertificate> &elem = *it;
+
+ if (elem.findRef(cert) == -1) {
+ unsigned int n = 0;
+ for(; n < elem.size(); n++) {
+ if (!elem.at(n)) {
+ elem.insert(n, cert);
+ break;
+ }
+ }
+ if (n == elem.size()) {
+ elem.resize(n+1);
+ elem.insert(n, cert);
+ }
+ }
+ }
+}
+
+
+void KSSLD::searchRemoveCert(KSSLCertificate *cert) {
+ skMD5Digest.remove(cert->getMD5Digest());
+
+ TQStringList mails;
+ cert->getEmails(mails);
+ for(TQStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) {
+ TQMap<TQString, TQPtrVector<KSSLCertificate> >::iterator it = skEmail.find(static_cast<const TQString &>(*iter).lower());
+
+ if (it == skEmail.end())
+ break;
+
+ TQPtrVector<KSSLCertificate> &elem = *it;
+
+ int n = elem.findRef(cert);
+ if (n != -1)
+ elem.remove(n);
+ }
+}
+
+
+TQStringList KSSLD::getKDEKeyByEmail(const TQString &email) {
+ TQStringList rc;
+ TQMap<TQString, TQPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email.lower());
+
+ kdDebug() << "GETKDEKey " << email.latin1() << endl;
+
+ if (it == skEmail.end())
+ return rc;
+
+ TQPtrVector<KSSLCertificate> &elem = *it;
+ for (unsigned int n = 0; n < elem.size(); n++) {
+ KSSLCertificate *cert = elem.at(n);
+ if (cert) {
+ rc.append(cert->getKDEKey());
+ }
+ }
+
+ kdDebug() << "ergebnisse: " << rc.size() << " " << elem.size() << endl;
+ return rc;
+}
+
+
+KSSLCertificate KSSLD::getCertByMD5Digest(const TQString &key) {
+ TQMap<TQString, KSSLCertificate *>::iterator iter = skMD5Digest.find(key);
+
+ kdDebug() << "Searching cert for " << key.latin1() << endl;
+
+ if (iter != skMD5Digest.end())
+ return **iter;
+
+ KSSLCertificate rc; // FIXME: Better way to return a not found condition?
+ kdDebug() << "Not found: " << rc.toString().latin1() << endl;
+ return rc;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+//
+// Certificate Home methods
+//
+
+TQStringList KSSLD::getHomeCertificateList() {
+ return KSSLCertificateHome::getCertificateList();
+}
+
+bool KSSLD::addHomeCertificateFile(TQString filename, TQString password, bool storePass) {
+ return KSSLCertificateHome::addCertificate(filename, password, storePass);
+}
+
+bool KSSLD::addHomeCertificatePKCS12(TQString base64cert, TQString passToStore) {
+ bool ok;
+ KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, passToStore);
+ ok = KSSLCertificateHome::addCertificate(pkcs12, passToStore);
+ delete pkcs12;
+ return ok;
+}
+
+bool KSSLD::deleteHomeCertificateByFile(TQString filename, TQString password) {
+ return KSSLCertificateHome::deleteCertificate(filename, password);
+}
+
+bool KSSLD::deleteHomeCertificateByPKCS12(TQString base64cert, TQString password) {
+ bool ok;
+ KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, password);
+ ok = KSSLCertificateHome::deleteCertificate(pkcs12);
+ delete pkcs12;
+ return ok;
+}
+
+bool KSSLD::deleteHomeCertificateByName(TQString name) {
+ return KSSLCertificateHome::deleteCertificateByName(name);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#include "kssld.moc"
+
+
+/*
+
+ DESIGN - KSSLCertificateCache
+ ------
+
+ This is the first implementation and I think this cache actually needs
+ experimentation to determine which implementation works best. My current
+ options are:
+
+ (1) Store copies of the X509 certificates in a TQPtrList using a self
+ organizing heuristic as described by Munro and Suwanda.
+ (2) Store copies of the X509 certificates in a tree structure, perhaps
+ a redblack tree, avl tree, or even just a simple binary tree.
+ (3) Store the CN's in a tree or list and use them as a hash to retrieve
+ the X509 certificates.
+ (4) Create "nodes" containing the X509 certificate and place them in
+ two structures concurrently, one organized by CN, the other by
+ X509 serial number.
+
+ This implementation uses (1). (4) is definitely attractive, but I don't
+ think it will be necessary to go so crazy with performance, and perhaps
+ end up performing poorly in situations where there are very few entries in
+ the cache (which is most likely the case most of the time). The style of
+ heuristic is move-to-front, not swap-forward. This seems to make more
+ sense because the typical user will hit a site at least a few times in a
+ row before moving to a new one.
+
+ What I worry about most with respect to performance is that cryptographic
+ routines are expensive and if we have to perform them on each X509
+ certificate until the right one is found, we will perform poorly.
+
+ All in all, this code is actually quite crucial for performance on SSL
+ website, especially those with many image files loaded via SSL. If a
+ site loads 15 images, we will have to run through this code 15 times.
+ A heuristic for self organization will make each successive lookup faster.
+ Sounds good, doesn't it?
+
+ DO NOT ATTEMPT TO GUESS WHICH CERTIFICATES ARE ACCEPTIBLE IN YOUR CODE!!
+ ALWAYS USE THE CACHE. IT MAY CHECK THINGS THAT YOU DON'T THINK OF, AND
+ ALSO IF THERE IS A BUG IN THE CHECKING CODE, IF IT IS ALL CONTAINED IN
+ THIS LIBRARY, A MINOR FIX WILL FIX ALL APPLICATIONS.
+ */
+
diff --git a/tdeio/misc/kssld/kssld.desktop b/tdeio/misc/kssld/kssld.desktop
new file mode 100644
index 000000000..7054f8bad
--- /dev/null
+++ b/tdeio/misc/kssld/kssld.desktop
@@ -0,0 +1,156 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KDEDModule
+X-TDE-ModuleType=Library
+X-TDE-Library=kssld
+X-TDE-FactoryName=kssld
+X-TDE-Kded-autoload=false
+X-TDE-Kded-load-on-demand=true
+Name=KSSL Daemon Module
+Name[af]=Kssl Bediener Module
+Name[ar]=وحدة مراقب KSSL
+Name[az]=KSSL Demon Modulu
+Name[be]=Модуль ÑервіÑа KSSL
+Name[bg]=Демон KSSL
+Name[bn]=KSSL ডিমন মডিউল
+Name[br]=Mollad an diaoul KSSL
+Name[ca]=Mòdul del dimoni KSSL
+Name[cs]=Modul démona KSSL
+Name[csb]=KSSL
+Name[cy]=Modiwl Daemon KSSL
+Name[da]=KSSL Dæmonmodul
+Name[de]=SSL-Dienst
+Name[el]=ΆÏθÏωμα δαίμονα KSSL
+Name[eo]=SSL-demono-modulo
+Name[es]=Módulo de demonio KSSL
+Name[et]=KSSL deemoni moodul
+Name[eu]=KSSL daemon modulua
+Name[fa]=پیمانۀ شبح KSSL
+Name[fi]=KSSL-palvelinmoduuli
+Name[fr]=Module démon KSSL
+Name[ga]=Modúl Deamhain KSSL
+Name[gl]=Módulo do Demo KSSL
+Name[he]=מודול תהליך הרקע של SSL
+Name[hi]=KSSL ङेमन घटक
+Name[hr]=Modul KSSL demona
+Name[hu]=KSSL szolgáltatásmodul
+Name[id]=Modul Daemon KSSL
+Name[is]=KSSL þjónseining
+Name[it]=Modulo demone KSSL
+Name[ja]=KSSL デーモンモジュール
+Name[ka]=KSSL გუშáƒáƒ’ის მáƒáƒ“ული
+Name[kk]=KSSL қызметтің модулі
+Name[km]=ម៉ូឌុល Daemon KSSL
+Name[ko]=KSSL ë°ëª¬ 모듈
+Name[lb]=KSSL-Dämonmodul
+Name[lt]=KSSL tarnybos modulis
+Name[lv]=KSSL DÄ“mona Modulis
+Name[mn]=KSSL Daemon Modul
+Name[ms]=Modul Daemon KSSL
+Name[mt]=Modulu daemon KSSL
+Name[nb]=KSSL nisse-modul
+Name[nds]=KSSL-Dämoon
+Name[ne]=KSSL डेइमन मोडà¥à¤¯à¥à¤²
+Name[nl]=KSSL daemon-module
+Name[nn]=KSSL-nissemodul
+Name[nso]=Seripa sa Daemon ya KSSL
+Name[pa]=KSSL ਡਾਇਮੋਨ ਮੈਡੀਊਲ
+Name[pl]=KSSL
+Name[pt]=Módulo do Servidor de KSSL
+Name[pt_BR]=Módulo do Serviço do KSSL
+Name[ro]=Modul demon KSSL
+Name[ru]=Служба KSSL
+Name[rw]=Igice Dayimoni KSSL
+Name[se]=KSSL-bálvámoduvla
+Name[sk]=Modul démona KSSL
+Name[sl]=Strežniški modul KSSL
+Name[sq]=Demoni për Modulin KSSL
+Name[sr]=KSSL демон модул
+Name[sr@Latn]=KSSL demon modul
+Name[sv]=KSSL-demonmodul
+Name[ta]=KSSL டெமான௠பகà¯à®¤à®¿
+Name[te]=కెఎసౠఎసౠఎలౠసూతà±à°°à°§à°¾à°°à°¿ మాడà±à°¯à±‚à°²à±
+Name[tg]=Модули Демон KSSL
+Name[th]=โมดูลเดมอน KSSL
+Name[tr]=KSSL Program Modülü
+Name[tt]=KSSL Xezmäteneñ Modulı
+Name[uk]=Модуль демону KSSL
+Name[uz]=KSSL xizmatining moduli
+Name[uz@cyrillic]=KSSL хизматининг модули
+Name[ven]=Modulu wa Daemon wa KSSL
+Name[vi]=Mô-Ä‘un trình ná»n KSSL
+Name[xh]=Isicatshulwa se KSSL Daemon
+Name[zh_CN]=KSSL 守护进程模å—
+Name[zh_HK]=KSSL 伺æœç¨‹å¼æ¨¡çµ„
+Name[zh_TW]=KSSL 伺æœç¨‹å¼æ¨¡çµ„
+Name[zu]=Ingxenye ye-daemon ye-KSSL
+Comment=KSSL daemon module for KDED
+Comment[af]=KSSL bediener module vir KDED
+Comment[be]=Модуль ÑервіÑа KSSL Ð´Ð»Ñ KDED
+Comment[bg]=Модул демон за KSSL за KDED
+Comment[bn]=KDED-র জনà§à¦¯ KSSL ডিমন মডিউল
+Comment[br]=Mollad an diaoul KSSL evit KDED
+Comment[bs]=KSSL Daemon Module za KDED
+Comment[ca]=Mòdul del dimoni KSSL per a KDED
+Comment[cs]=Modul démona KSSL pro KDED
+Comment[csb]=Ùsłëżnota SSL w KDED
+Comment[da]=KSSL Dæmonmodul for KDED
+Comment[de]=Unterstützung für SSL-Verschlüsselung in KDED
+Comment[el]=ΆÏθÏωμα δαίμονα KSSL για το KDED
+Comment[eo]=SSL-demono-modulo por KDED
+Comment[es]=Módulo de demonio KSSL para KDED
+Comment[et]=KDED KSSL deemoni moodul
+Comment[eu]=KSSL daemon modulua KDEDrako
+Comment[fa]=پیمانۀ شبح KSSL برای KDED
+Comment[fi]=KSSL-palvelinmoduuli KDED:lle
+Comment[fr]=Module démon KSSL pour KDED
+Comment[fy]=KSSL daemon module foar KDED
+Comment[ga]=Modúl deamhain KSSL le haghaidh KDED
+Comment[gl]=Módulo do Demo KSSL para KDED
+Comment[he]=מודול תהליך רקע של SSL עבור KDED
+Comment[hi]=केडीईडी के लिठकेà¤à¤¸à¤à¤¸à¤à¤² डेमन मॉडà¥à¤¯à¥‚ल
+Comment[hr]=KSSL demon modul za KDED
+Comment[hu]=KSSL szolgáltatásmodul a KDED-hez
+Comment[id]=Modul daemon KSSL untuk KDED
+Comment[is]=KSSL þjónseining fyrir KDED
+Comment[it]=Modulo demone KSSL per KDED
+Comment[ja]=KDED 用 㮠KSSL デーモンモジュール
+Comment[ka]=KSSL გუშáƒáƒ’ის მáƒáƒ“ული KDED-სთვის
+Comment[kk]=KDED KSSL куәліктерді баÑқару қызметтің модулі
+Comment[km]=ម៉ូឌុល daemon KSSL សម្រាប់ KDED
+Comment[lb]=KSSL-Dämonmodul fir KDED
+Comment[lt]=KSSL tarnybos modulis, skirtas KDED
+Comment[lv]=KSSL Dēmona Modulis priekš KDED
+Comment[mk]=KSSL даемон модул за KDED
+Comment[ms]=Modul Daemon KSSL untuk KDED
+Comment[nb]=KSSL nissemodul for KDED
+Comment[nds]=KSSL-Dämoonmoduul för KDED
+Comment[ne]=KDED का लागि डेइमन मोडà¥à¤¯à¥à¤² KSSL
+Comment[nl]=KSSL daemon-module voor KDED
+Comment[nn]=KSSL-nissemodul for KDED
+Comment[pa]=KDED ਲਈ KSSL ਪੇਸ਼ਕਾਰੀ
+Comment[pl]=Obsługa SSL w KDED
+Comment[pt]=Módulo servidor de KSSL para o KDED
+Comment[pt_BR]=Módulo de serviço KSSL para o KDED
+Comment[ro]=Modul demon KSSL pentru KDED
+Comment[ru]=Управление Ñертификатами SSL
+Comment[rw]=Igice cya dayimoni KSSL cya KDED
+Comment[se]=KDED:a KSSL-bálvámoduvla
+Comment[sk]=Modul démona KSSL pre KDED
+Comment[sl]=Strežniški modul KSSL za KDED
+Comment[sr]=KSSL демон модул за KDED
+Comment[sr@Latn]=KSSL demon modul za KDED
+Comment[sv]=KSSL-demonmodul för KDED
+Comment[ta]=KDEDகà¯à®•à®¾à®© KSSL டெமான௠பகà¯à®¤à®¿
+Comment[te]=కెడిఈడి కొరకౠకెఎసౠఎసౠఎలౠసూతà±à°°à°§à°¾à°°à°¿ మాడà±à°¯à±‚à°²à±
+Comment[tg]=Модули Демон KSSL брои KDED
+Comment[th]=โมดูลเดมอน KSSL สำหรับ KDED
+Comment[tr]=KDED için KSSL program biirmi
+Comment[tt]=KDED öçen KSSL xezmät
+Comment[uk]=Модуль демону KSSL Ð´Ð»Ñ KDED
+Comment[uz]=KDED uchun KSSL xizmatining moduli
+Comment[uz@cyrillic]=KDED учун KSSL хизматининг модули
+Comment[vi]=Mô-Ä‘un trình ná»n KSSL cho KDED.
+Comment[zh_CN]=KDED çš„ KSSL 守护进程模å—
+Comment[zh_HK]=KDED 使用的 SSL 伺æœç¨‹å¼æ¨¡çµ„
+Comment[zh_TW]=KDED 使用的 KSSL 伺æœç¨‹å¼æ¨¡çµ„
diff --git a/tdeio/misc/kssld/kssld.h b/tdeio/misc/kssld/kssld.h
new file mode 100644
index 000000000..028a30809
--- /dev/null
+++ b/tdeio/misc/kssld/kssld.h
@@ -0,0 +1,154 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2001-2005 George Staikos <staikos@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 __KSSLD_H__
+#define __KSSLD_H__
+
+#include <kded/kdedmodule.h>
+#include <ksslcertificate.h>
+#include <ksslcertificatecache.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqvaluelist.h>
+#include <tqmap.h>
+#include <tqptrvector.h>
+
+
+class KSimpleConfig;
+class KSSLCNode;
+class KOpenSSLProxy;
+
+class KSSLD : public KDEDModule
+{
+ Q_OBJECT
+ K_DCOP
+
+public:
+
+ KSSLD(const TQCString &name);
+
+ virtual ~KSSLD();
+
+k_dcop:
+ //
+ // Certificate Cache methods
+ //
+ void cacheAddCertificate(KSSLCertificate cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent = true);
+ KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCN(TQString cn);
+
+ KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCertificate(KSSLCertificate cert);
+
+ bool cacheSeenCN(TQString cn);
+ bool cacheSeenCertificate(KSSLCertificate cert);
+
+ bool cacheRemoveByCN(TQString cn);
+ bool cacheRemoveBySubject(TQString subject);
+ bool cacheRemoveByCertificate(KSSLCertificate cert);
+
+ bool cacheIsPermanent(KSSLCertificate cert);
+
+ void cacheReload();
+
+ bool cacheModifyByCN(TQString cn,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime expires);
+
+ bool cacheModifyByCertificate(KSSLCertificate cert,
+ KSSLCertificateCache::KSSLCertificatePolicy policy,
+ bool permanent,
+ TQDateTime expires);
+
+ TQStringList cacheGetHostList(KSSLCertificate cert);
+
+ bool cacheAddHost(KSSLCertificate cert, TQString host);
+
+ bool cacheRemoveHost(KSSLCertificate cert, TQString host);
+
+ /* Certificate Authorities */
+ void caVerifyUpdate();
+ bool caRegenerate();
+
+ TQStringList caList();
+
+ bool caUseForSSL(TQString subject);
+
+ bool caUseForEmail(TQString subject);
+
+ bool caUseForCode(TQString subject);
+
+ bool caAdd(TQString certificate, bool ssl, bool email, bool code);
+
+ bool caAddFromFile(TQString filename, bool ssl, bool email, bool code);
+
+ bool caRemove(TQString subject);
+
+ bool caRemoveFromFile(TQString filename);
+
+ TQString caGetCert(TQString subject);
+
+ bool caSetUse(TQString subject, bool ssl, bool email, bool code);
+
+ TQStringList getKDEKeyByEmail(const TQString &email);
+
+ KSSLCertificate getCertByMD5Digest(const TQString &key);
+
+ //
+ // Certificate Home methods
+ //
+
+ TQStringList getHomeCertificateList();
+
+ bool addHomeCertificateFile(TQString filename, TQString password, bool storePass /*=false*/);
+
+ bool addHomeCertificatePKCS12(TQString base64cert, TQString passToStore);
+
+ bool deleteHomeCertificateByFile(TQString filename, TQString password);
+
+ bool deleteHomeCertificateByPKCS12(TQString base64cert, TQString password);
+
+ bool deleteHomeCertificateByName(TQString name);
+
+private:
+
+ void cacheClearList();
+ void cacheSaveToDisk();
+ void cacheLoadDefaultPolicies();
+
+ // for the cache portion:
+ KSimpleConfig *cfg;
+ TQPtrList<KSSLCNode> certList;
+
+ // Our pointer to OpenSSL
+ KOpenSSLProxy *kossl;
+
+ //
+ void searchAddCert(KSSLCertificate *cert);
+ void searchRemoveCert(KSSLCertificate *cert);
+
+ TQMap<TQString, TQPtrVector<KSSLCertificate> > skEmail;
+ TQMap<TQString, KSSLCertificate *> skMD5Digest;
+};
+
+
+#endif
diff --git a/tdeio/misc/mms.protocol b/tdeio/misc/mms.protocol
new file mode 100644
index 000000000..8fde7c000
--- /dev/null
+++ b/tdeio/misc/mms.protocol
@@ -0,0 +1,73 @@
+[Protocol]
+helper=true
+exec=
+defaultMimetype=uri/mms
+protocol=mms
+input=none
+output=none
+reading=false
+Icon=www
+Class=:internet
+Description=Microsoft Media Server Protocol
+Description[af]=Microsoft Media Bediener Protokol
+Description[be]=Пратакол Microsoft Media Server
+Description[bn]=মাইকà§à¦°à§‹à¦¸à¦«à§â€Œà¦Ÿ মিডিয়া সারà§à¦­à¦¾à¦° পà§à¦°à§‹à¦Ÿà§‹à¦•à¦²
+Description[bs]=Microsoft Media Server protokol
+Description[ca]=Protocol Microsoft Media Server
+Description[cs]=Microsoft Media Server protokol
+Description[csb]=Protokól Microsoft Media Server
+Description[da]=Microsoft Medieserver-protokol
+Description[de]=Microsoft Media Server Protokoll
+Description[el]=ΠÏωτόκολλο Microsoft Media Server
+Description[es]=Protocolo Microsoft Media Server
+Description[et]=Microsoft Media Server protokoll
+Description[eu]=Microsoft Media Server protokoloa
+Description[fa]=قرارداد کارساز رسانۀ میکروساÙت
+Description[fi]=Microsoft Media -palvelinprotokolla
+Description[fr]=Protocole Microsoft Media Server
+Description[gl]=Protocolo Microsoft Media Server
+Description[he]=שרת פרוטוקול של מדייה של מיקרוספט
+Description[hi]=माइकà¥à¤°à¥‹à¤¸à¥‰à¤«à¤¼à¥à¤Ÿ मीडिया सरà¥à¤µà¤° पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤²
+Description[hr]=Protokol Microsoft Media poslužitelja
+Description[hu]=MMS protokoll
+Description[id]=Protokol Server Microsoft Media
+Description[is]=Microsoft Media Server samskiptaregla
+Description[it]=Protocollo Microsoft Media Server
+Description[ja]=Microsoft メディアサーãƒãƒ—ロトコル
+Description[ka]=Microsoft Media Server პრáƒáƒ¢áƒáƒ™áƒáƒšáƒ˜
+Description[kk]=Microsoft Media Server протоколы
+Description[km]=ពិធីការ​ម៉ាស៊ីន​បម្រី Microsoft Media
+Description[lb]=Microsoft-Media Server-Protokoll
+Description[lt]=Microsoft media serverio protokolas
+Description[lv]=Microsoft Media Server protokols
+Description[mk]=Microsoft Media Server-протокол
+Description[ms]=Protokol Pelayan Media Microsoft
+Description[nds]=Microsoft-Medienserverprotokoll
+Description[ne]=माइकà¥à¤°à¥‹à¤¸à¤«à¥à¤Ÿ मिडिया सरà¥à¤­à¤° पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¤²
+Description[nl]=Microsoft Media Server-protocol
+Description[nn]=Microsoft Media Server-protokoll
+Description[pa]=Microsoft Media ਸਰਵਰ ਪà©à¨°à©‹à¨Ÿà©‹à¨•à¨¾à¨²
+Description[pl]=Protokół Microsoft Media Server
+Description[pt]=Protocolo Microsoft Media Server
+Description[pt_BR]=Protocolo do Microsoft Media Server
+Description[ro]=Protocol Microsoft Media Server
+Description[ru]=Протокол Microsoft Media Server
+Description[rw]=Porotokole Igihuza Seriveri ya Microsoft
+Description[se]=Microsoft Media Server-protokolla
+Description[sk]=Protokol pre Microsoft Media Server
+Description[sl]=Protokol Microsoft Media Server
+Description[sr]=Microsoft Media Server протокол
+Description[sr@Latn]=Microsoft Media Server protokol
+Description[sv]=Microsoft mediaserver-protokoll
+Description[ta]=மைகà¯à®°à¯‹à®šà®¾à®ªà¯à®Ÿà¯ ஊடக சேவக நெறிமà¯à®±à¯ˆ
+Description[te]=మైకà±à°°à±Šà°¸à°¾à°«à±à°Ÿà± మీడియా సెరà±à°µà°°à± à°ªà±à°°à±Šà°Ÿà±Šà°•à°¾à°²à±
+Description[tg]=Протоколи медиа Ñервер барои Microsoft
+Description[th]=โปรโตคอลสำหรับเซิรฟเวอร์จัดà¸à¸²à¸£à¸ªà¸·à¹ˆà¸­à¸‚องไมโครซอฟต์ (MMS)
+Description[tr]=Microsoft Media Server Protokolü
+Description[tt]=Microsoft Media Server Protokolı
+Description[uk]=Протокол медіа Ñервера Microsoft
+Description[vi]=Giao thức trình phục vụ phương tiện Microsoft™.
+Description[zh_CN]=Microsoft 媒体æœåŠ¡å™¨åè®®
+Description[zh_HK]=Microsoft Media Server å”定
+Description[zh_TW]=Microsoft Media Server å”定
+URIMode=url
diff --git a/tdeio/misc/mmst.protocol b/tdeio/misc/mmst.protocol
new file mode 100644
index 000000000..1f0f7636b
--- /dev/null
+++ b/tdeio/misc/mmst.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=uri/mmst
+exec=
+protocol=mmst
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/mmsu.protocol b/tdeio/misc/mmsu.protocol
new file mode 100644
index 000000000..deda935fc
--- /dev/null
+++ b/tdeio/misc/mmsu.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=uri/mmsu
+exec=
+protocol=mmsu
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/pnm.protocol b/tdeio/misc/pnm.protocol
new file mode 100644
index 000000000..3ca3a7d23
--- /dev/null
+++ b/tdeio/misc/pnm.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=uri/pnm
+exec=
+protocol=pnm
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/rlogin.protocol b/tdeio/misc/rlogin.protocol
new file mode 100644
index 000000000..3b103a905
--- /dev/null
+++ b/tdeio/misc/rlogin.protocol
@@ -0,0 +1,13 @@
+[Protocol]
+exec=tdetelnetservice %u
+protocol=rlogin
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+DocPath=tdeioslave/rlogin.html
+Icon=konsole
diff --git a/tdeio/misc/rtsp.protocol b/tdeio/misc/rtsp.protocol
new file mode 100644
index 000000000..301312260
--- /dev/null
+++ b/tdeio/misc/rtsp.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=audio/x-pn-realaudio
+exec=
+protocol=rtsp
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/rtspt.protocol b/tdeio/misc/rtspt.protocol
new file mode 100644
index 000000000..9e4fe9626
--- /dev/null
+++ b/tdeio/misc/rtspt.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=uri/rtspt
+exec=
+protocol=rtspt
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/rtspu.protocol b/tdeio/misc/rtspu.protocol
new file mode 100644
index 000000000..9cc9299f6
--- /dev/null
+++ b/tdeio/misc/rtspu.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+defaultMimetype=uri/rtspu
+exec=
+protocol=rtspu
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=www
+Class=:internet
+URIMode=url
diff --git a/tdeio/misc/ssh.protocol b/tdeio/misc/ssh.protocol
new file mode 100644
index 000000000..b0c098f8f
--- /dev/null
+++ b/tdeio/misc/ssh.protocol
@@ -0,0 +1,13 @@
+[Protocol]
+exec=tdetelnetservice %u
+protocol=ssh
+input=none
+output=none
+helper=true
+listing=false
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=konsole
+
diff --git a/tdeio/misc/tdefile/CMakeLists.txt b/tdeio/misc/tdefile/CMakeLists.txt
new file mode 100644
index 000000000..9e90b956c
--- /dev/null
+++ b/tdeio/misc/tdefile/CMakeLists.txt
@@ -0,0 +1,39 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdefile
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### tdefile #####################################
+
+set( target tdefile )
+
+set( ${target}_SRCS
+ fileprops.cpp
+)
+
+tde_add_executable( ${target}
+ SOURCES ${${target}_SRCS}
+ LINK tdeio-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+) \ No newline at end of file
diff --git a/tdeio/misc/tdefile/Makefile.am b/tdeio/misc/tdefile/Makefile.am
new file mode 100644
index 000000000..21cdb0627
--- /dev/null
+++ b/tdeio/misc/tdefile/Makefile.am
@@ -0,0 +1,10 @@
+METASOURCES = AUTO
+
+noinst_HEADERS = fileprops.h
+INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/tdeio/tdeio $(all_includes)
+
+bin_PROGRAMS = tdefile
+tdefile_SOURCES = fileprops.cpp
+tdefile_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+tdefile_LDADD = $(LIB_KIO)
+
diff --git a/tdeio/misc/tdefile/README b/tdeio/misc/tdefile/README
new file mode 100644
index 000000000..d063b6d58
--- /dev/null
+++ b/tdeio/misc/tdefile/README
@@ -0,0 +1,4 @@
+This is a commandline frontend to KFileMetaInfo. It allows
+to read and write meta information of files.
+
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/tdeio/misc/tdefile/fileprops.cpp b/tdeio/misc/tdefile/fileprops.cpp
new file mode 100644
index 000000000..bb209fbc0
--- /dev/null
+++ b/tdeio/misc/tdefile/fileprops.cpp
@@ -0,0 +1,480 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 <iostream>
+
+#include <tqfile.h>
+#include <tqptrlist.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <tdefilemetainfo.h>
+#include <klocale.h>
+#include <kpropertiesdialog.h>
+
+#include "fileprops.h"
+
+#define KFILEVERSION "0.2"
+#define INDENT "\t"
+
+using namespace std;
+
+static TQString beatifyValue( const TQString& value )
+{
+ if ( value.isNull() )
+ return TQString("(no value for key available)");
+ else if ( value.isEmpty() )
+ return TQString("(empty)");
+
+ return value;
+}
+
+FileProps::FileProps( const TQString& path, const TQStringList& suppliedGroups )
+ : m_dirty( false )
+{
+ m_info = new KFileMetaInfo(path, TQString::null, KFileMetaInfo::Everything);
+ m_userSuppliedGroups = !suppliedGroups.isEmpty();
+ m_groupsToUse = m_userSuppliedGroups ? suppliedGroups : m_info->groups();
+}
+
+FileProps::~FileProps()
+{
+ sync();
+ delete m_info;
+}
+
+bool FileProps::sync()
+{
+ if ( !m_dirty )
+ return true;
+
+ return m_info->applyChanges();
+}
+
+bool FileProps::isValid() const
+{
+ return m_info->isValid();
+}
+
+TQStringList FileProps::supportedGroups() const
+{
+ return m_info->supportedGroups();
+}
+
+TQStringList FileProps::availableGroups() const
+{
+ return m_info->groups();
+}
+
+TQStringList FileProps::supportedKeys( const TQString& group ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ return g.supportedKeys();
+}
+
+TQStringList FileProps::availableKeys( const TQString& group ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ TQStringList allKeys = g.keys();
+ TQStringList ret;
+ TQStringList::ConstIterator it = allKeys.begin();
+ for ( ; it != allKeys.end(); ++it )
+ {
+ if ( g.item( *it ).isValid() )
+ ret.append( *it );
+ }
+
+ return ret;
+}
+
+TQStringList FileProps::preferredKeys( const TQString& group ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ return g.preferredKeys();
+}
+
+TQString FileProps::getValue( const TQString& group,
+ const TQString& key ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ return FileProps::createKeyValue( g, key );
+}
+
+bool FileProps::setValue( const TQString& group,
+ const TQString& key, const TQString &value )
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ bool wasAdded = false;
+ if ( !g.isValid() )
+ {
+ if ( m_info->addGroup( group ) )
+ {
+ wasAdded = true;
+ g = m_info->group( group );
+ }
+ else
+ return false;
+ }
+
+ bool ok = g[key].setValue( value );
+
+ if ( !ok && wasAdded ) // remove the created group again
+ (void) m_info->removeGroup( group );
+
+ m_dirty |= ok;
+ return ok;
+}
+
+TQStringList FileProps::allValues( const TQString& group ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ return FileProps::createKeyValueList( g, g.keys() );
+}
+
+TQStringList FileProps::preferredValues( const TQString& group ) const
+{
+ KFileMetaInfoGroup g = m_info->group( group );
+ return FileProps::createKeyValueList( g, g.preferredKeys() );
+}
+
+// static helper:
+// creates strings like
+// "group: translatedKey: value"
+TQString FileProps::createKeyValue( const KFileMetaInfoGroup& g,
+ const TQString& key )
+{
+ static const int MAX_SPACE = 25;
+ KFileMetaInfoItem item = g.item( key );
+
+ TQString result("%1");
+ result = result.arg( (item.isValid() ? item.translatedKey() : key) + ":",
+ -MAX_SPACE );
+ result.append( beatifyValue( item.string() ) );
+
+ TQString group("%1");
+ group = group.arg( g.translatedName() + ":", -MAX_SPACE );
+ result.prepend( group );
+
+ return result;
+}
+
+// static
+TQStringList FileProps::createKeyValueList( const KFileMetaInfoGroup& g,
+ const TQStringList& keys )
+{
+ TQStringList result;
+ TQStringList::ConstIterator it = keys.begin();
+
+ for ( ; it != keys.end(); ++it )
+ result.append( FileProps::createKeyValue( g, *it ) );
+
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+
+// tdefile --mimetype --listsupported --listavailable --listpreferred --listwritable --getValue "key" --setValue "key=value" --allValues --preferredValues --dialog --quiet file [file...]
+// "key" may be a list of keys, separated by commas
+static KCmdLineOptions options[] =
+{
+ { "m", 0, 0 }, // short option for --mimetype
+ { "nomimetype", I18N_NOOP("Do not print the mimetype of the given file(s)"), 0 },
+
+ { "ls", 0, 0 }, // short option for --listsupported
+ { "listsupported <mimetype>",
+ I18N_NOOP("List all supported metadata keys of the given file(s). "
+ "If mimetype is not specified, the mimetype of the given "
+ "files is used." ), "file" },
+
+ { "lp", 0, 0 }, // short option for --listpreferred
+ { "listpreferred <mimetype>",
+ I18N_NOOP("List all preferred metadata keys of the given file(s). "
+ "If mimetype is not specified, the mimetype of the given "
+ "files is used." ), "file" },
+
+ { "la", 0, 0 }, // short option for --listavailable
+ { "listavailable",
+ I18N_NOOP("List all metadata keys which have a value in the given "
+ "file(s)."), 0 },
+
+ { "sm", 0, 0 }, // short option for --supportedMimetypes
+ { "supportedMimetypes",
+ I18N_NOOP("Prints all mimetypes for which metadata support is "
+ "available."), 0 },
+
+ { "q", 0, 0 }, // short option for --quiet
+ { "quiet",
+ I18N_NOOP("Do not print a warning when more than one file was given "
+ "and they do not all have the same mimetype."), 0 },
+
+ { "av", 0, 0 }, // short option for --allValues
+ { "allValues",
+ I18N_NOOP("Prints all metadata values, available in the given "
+ "file(s)."), 0 },
+
+ { "pv", 0, 0 }, // short option for --preferredValues
+ { "preferredValues",
+ I18N_NOOP("Prints the preferred metadata values, available in the "
+ "given file(s)."), 0 },
+
+ { "dialog",
+ I18N_NOOP("Opens a TDE properties dialog to allow viewing and "
+ "modifying of metadata of the given file(s)"), 0 },
+
+ { "getValue <key>",
+ I18N_NOOP("Prints the value for 'key' of the given file(s). 'key' "
+ "may also be a comma-separated list of keys"), 0 },
+
+ { "setValue <key=value>",
+ I18N_NOOP("Attempts to set the value 'value' for the metadata key "
+ "'key' for the given file(s)"), 0 },
+
+ { "!groups <arguments>", I18N_NOOP("The group to get values from or set values to"),
+ 0 },
+
+ { "+[files]",
+ I18N_NOOP("The file (or a number of files) to operate on."), 0 },
+ KCmdLineLastOption
+};
+
+
+//
+// helper functions
+//
+
+static void printSupportedMimeTypes()
+{
+ TQStringList allMimeTypes = KFileMetaInfoProvider::self()->supportedMimeTypes();
+ if ( allMimeTypes.isEmpty() )
+ {
+ cout <<
+ i18n("No support for metadata extraction found.").local8Bit().data()
+ << endl;
+ return;
+ }
+
+ cout << i18n("Supported MimeTypes:").local8Bit().data() << endl;
+
+ TQStringList::ConstIterator it = allMimeTypes.begin();
+ for ( ; it != allMimeTypes.end(); it++ )
+ cout << (*it).local8Bit().data() << endl;
+}
+
+// caller needs to delete the returned list!
+static KFileItemList * fileItemList( const TDECmdLineArgs *args )
+{
+ KFileItemList * items = new KFileItemList();
+ items->setAutoDelete( true );
+ for ( int i = 0; i < args->count(); i++ )
+ items->append( new KFileItem( KFileItem::Unknown,
+ KFileItem::Unknown,
+ args->url( i ) ));
+ return items;
+}
+
+static void showPropertiesDialog( const TDECmdLineArgs *args )
+{
+ KFileItemList *items = fileItemList( args );
+ new KPropertiesDialog( *items, 0L, "props dialog", true );
+ delete items;
+}
+
+static void printMimeTypes( const TDECmdLineArgs *args )
+{
+ for ( int i = 0; i < args->count(); i++ )
+ {
+ KURL url = args->url( i );
+ KMimeType::Ptr mt = KMimeType::findByURL( url );
+ cout << args->arg(i) << ": " << mt->comment().local8Bit().data() << " ("
+ << mt->name().local8Bit().data() << ")" << endl;
+ }
+}
+
+static void printList( const TQStringList& list )
+{
+ TQStringList::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it )
+ cout << (*it).local8Bit().data() << endl;
+ cout << endl;
+}
+
+static void processMetaDataOptions( const TQPtrList<FileProps> propList,
+ TDECmdLineArgs *args )
+{
+// tdefile --mimetype --supportedMimetypes --listsupported --listavailable --listpreferred --listwritable --getValue "key" --setValue "key=value" --allValues --preferredValues --dialog --quiet file [file...]
+// "key" may be a list of keys, separated by commas
+
+ TQString line("-- -------------------------------------------------------");
+ FileProps *props;
+ TQPtrListIterator<FileProps> it( propList );
+ for ( ; (props = it.current()); ++it )
+ {
+ TQString file = props->fileName() + " ";
+ TQString fileString = line.replace( 3, file.length(), file );
+ cout << TQFile::encodeName( fileString ).data() << endl;
+
+ if ( args->isSet( "listsupported" ) )
+ {
+ cout << "=Supported Keys=" << endl;
+ printList( props->supportedKeys() );
+ }
+ if ( args->isSet( "listpreferred" ) )
+ {
+ cout << "=Preferred Keys=" << endl;
+ printList( props->preferredKeys() );
+ }
+ if ( args->isSet( "listavailable" ) )
+ {
+ cout << "=Available Keys=" << endl;
+ TQStringList groups = props->availableGroups();
+ TQStringList::ConstIterator git = groups.begin();
+ for ( ; git != groups.end(); ++git )
+ {
+ cout << "Group: " << (*git).local8Bit().data() << endl;
+ printList( props->availableKeys( *git ) );
+ }
+ }
+// if ( args->isSet( "listwritable" ) )
+// {
+// cout << "TODO :)" << endl;
+// }
+ if ( args->isSet( "getValue" ) )
+ {
+ cout << "=Value=" << endl;
+ TQString key = TQString::fromLocal8Bit( args->getOption("getValue"));
+ TQStringList::ConstIterator git = props->groupsToUse().begin();
+ for ( ; git != props->groupsToUse().end(); ++git )
+ cout << props->getValue( *git, key ).local8Bit().data() << endl;
+ }
+
+ if ( args->isSet( "setValue" ) )
+ {
+ // separate key and value from the line "key=value"
+ TQString cmd = TQString::fromLocal8Bit( args->getOption("setValue"));
+ TQString key = cmd.section( '=', 0, 0 );
+ TQString value = cmd.section( '=', 1 );
+
+ // either use supplied groups or all supported groups
+ // (not only the available!)
+ TQStringList groups = props->userSuppliedGroups() ?
+ props->groupsToUse() :
+ props->supportedGroups();
+
+ TQStringList::ConstIterator git = groups.begin();
+ for ( ; git != groups.end(); ++git )
+ props->setValue( *git, key, value );
+ }
+
+ if ( args->isSet( "allValues" ) )
+ {
+ cout << "=All Values=" << endl;
+ TQStringList groups = props->availableGroups();
+ TQStringList::ConstIterator group = groups.begin();
+ for ( ; group != groups.end(); ++group )
+ printList( props->allValues( *group ) );
+ }
+ if ( args->isSet( "preferredValues" ) && !args->isSet("allValues") )
+ {
+ cout << "=Preferred Values=" << endl;
+ TQStringList groups = props->availableGroups();
+ TQStringList::ConstIterator group = groups.begin();
+ for ( ; group != groups.end(); ++group )
+ printList( props->preferredValues( *group ) );
+ }
+ }
+
+}
+
+int main( int argc, char **argv )
+{
+ TDEAboutData about(
+ "tdefile", I18N_NOOP( "tdefile" ), KFILEVERSION,
+ I18N_NOOP("A commandline tool to read and modify metadata of files." ),
+ TDEAboutData::License_LGPL, "(c) 2002, Carsten Pfeiffer",
+ 0 /*text*/, "http://devel-home.kde.org/~pfeiffer/",
+ "pfeiffer@kde.org" );
+
+ about.addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org",
+ "http://devel-home.kde.org/~pfeiffer/" );
+
+ TDECmdLineArgs::init( argc, argv, &about );
+
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ bool useGUI = args->isSet( "dialog" );
+
+ TDEApplication app( useGUI, useGUI );
+
+ TQPtrList<FileProps> m_props;
+ m_props.setAutoDelete( true );
+
+ bool quiet = args->isSet( "quiet" );
+
+ if ( args->isSet( "supportedMimetypes" ) )
+ printSupportedMimeTypes();
+
+ int files = args->count();
+ if ( files == 0 )
+ TDECmdLineArgs::usage( i18n("No files specified") ); // exit()s
+
+ if ( args->isSet( "dialog" ) )
+ {
+ showPropertiesDialog( args );
+ return true;
+ }
+
+ TQStringList groupsToUse;
+ QCStringList suppliedGroups = args->getOptionList( "groups" );
+ QCStringList::ConstIterator it = suppliedGroups.begin();
+ for ( ; it != suppliedGroups.end(); ++it )
+ groupsToUse.append( TQString::fromLocal8Bit( (*it) ) );
+
+ TQString mimeType;
+
+ for ( int i = 0; i < files; i++ )
+ {
+ if ( args->isSet( "mimetype" ) )
+ printMimeTypes( args );
+
+ FileProps *props = new FileProps( args->url(i).path(), groupsToUse );
+ if ( props->isValid() )
+ m_props.append( props );
+ else
+ {
+ if ( !quiet )
+ {
+ cerr << args->arg(i) << ": " <<
+ i18n("Cannot determine metadata").local8Bit().data() << endl;
+ }
+ delete props;
+ }
+ }
+
+
+ processMetaDataOptions( m_props, args );
+
+ m_props.clear(); // force destruction/sync of props
+ cout.flush();
+
+ return 0;
+}
diff --git a/tdeio/misc/tdefile/fileprops.h b/tdeio/misc/tdefile/fileprops.h
new file mode 100644
index 000000000..45a79239d
--- /dev/null
+++ b/tdeio/misc/tdefile/fileprops.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 KFILEPROPS_H
+#define KFILEPROPS_H
+
+#include <tqstring.h>
+
+#include <tdefilemetainfo.h>
+
+class FileProps
+{
+public:
+ FileProps( const TQString& path, const TQStringList& suppliedGroups );
+ virtual ~FileProps();
+
+ bool isValid() const;
+
+ TQString fileName() const { return m_info->path(); }
+
+ TQStringList supportedGroups() const;
+ TQStringList availableGroups() const;
+ TQStringList translatedGroups();
+
+ const TQStringList& groupsToUse() const { return m_groupsToUse; }
+ bool userSuppliedGroups() const { return m_userSuppliedGroups; }
+
+ TQStringList supportedKeys( const TQString& group ) const;
+ TQStringList availableKeys( const TQString& group ) const;
+ TQStringList preferredKeys( const TQString& group ) const;
+
+ TQStringList supportedKeys() const { return m_info->supportedKeys(); }
+ TQStringList preferredKeys() const { return m_info->preferredKeys(); }
+
+ TQString getValue( const TQString& group, const TQString& key ) const;
+ bool setValue( const TQString& group,
+ const TQString& key, const TQString &value );
+
+ TQStringList allValues( const TQString& group ) const;
+ TQStringList preferredValues( const TQString& group ) const;
+
+ bool isReadOnly( const TQString& group, const TQString& key );
+
+private:
+ static TQString createKeyValue( const KFileMetaInfoGroup& g,
+ const TQString& key );
+ static TQStringList createKeyValueList( const KFileMetaInfoGroup&,
+ const TQStringList& );
+ bool sync();
+
+ KFileMetaInfo *m_info;
+ bool m_dirty;
+ bool m_userSuppliedGroups;
+
+ TQStringList m_groupsToUse;
+
+};
+
+#endif // KFILEPROPS_H
diff --git a/tdeio/misc/tdeio_uiserver.desktop b/tdeio/misc/tdeio_uiserver.desktop
new file mode 100644
index 000000000..bba0a7c7c
--- /dev/null
+++ b/tdeio/misc/tdeio_uiserver.desktop
@@ -0,0 +1,100 @@
+[Desktop Entry]
+Type=Service
+Name=tdeio_uiserver
+Name[de]=Server der graphischen Oberfläche
+Name[fy]=Kio_uiserver
+Name[ja]=kio_uiサーãƒ
+Name[mn]=График гадаргуугийн Ñервер
+Name[nds]=tdeio_uiserver, Server för de graafsche Böversiet
+Name[nl]=Kio_uiserver
+Name[nso]=kio_uiseabi
+Name[ro]=Kio_uiserver
+Name[sv]=Kio-gränssnittsserver
+Name[ta]=kio_uiசேவையகமà¯
+Name[te]=కేà°à°“_à°¯à±à°à°¸à±†à°°à±à°µà°°à±
+Exec=tdeio_uiserver
+Comment=TDE's Progress Info UI server
+Comment[af]=TDE se vordering inligting UI bediener
+Comment[ar]=خادم معلومات تقدم واجهة كيدي
+Comment[az]=TDE'nin İrəliləmə Bilgisi İstifadaçi Ara Üz Vericisi
+Comment[be]=Сервер паведамленнÑÑž аб выкананні дзеÑннÑÑž
+Comment[bg]=Сървър за отчитане на прогреÑа (TDE's Progress Info UI server)
+Comment[bn]=কে.ডি.ই. অগà§à¦°à¦—তি তথà§à¦¯ UI সারà§à¦­à¦¾à¦°
+Comment[br]=Servijer stlenn EA Progress TDE
+Comment[bs]=TDEov Progess Info UI server
+Comment[ca]=Servidor d'informació de progrés del TDE
+Comment[cs]=UI server zobrazující informace o průběhu
+Comment[csb]=Serwer wëdowiédzë ò pòkròkù procesë
+Comment[cy]=Gweinydd UI TDE i Ddangos Cynnydd
+Comment[da]=TDE's fremgangsinfo-UI-server
+Comment[de]=Ein UI-Server, der Fortschrittsinformationen darstellt
+Comment[el]=ΕξυπηÏετητής πληÏοφοÏιών Ï€Ïοόδου πεÏιβάλλοντος χÏήσης του TDE
+Comment[eo]=Progresinforma servo
+Comment[es]=Servidor UI de información de progreso de TDE
+Comment[et]=TDE edenemise info UI server
+Comment[eu]=TDEren aurrerapen-informazioen UI zerbitzaria
+Comment[fa]=اطلاعات پیشرÙت کارساز UI TDE
+Comment[fi]=TDE:n edistymispalkin käyttöliittymäpalvelin
+Comment[fr]=Serveur graphique d'infos de progression de TDE
+Comment[fy]=TDE's tsjinner foar ynformaasje oer de fuortgong
+Comment[gl]=Servidor UI de Información de Progreso de TDE
+Comment[he]=שרת ממשק מידע ההתקדמות של TDE
+Comment[hi]=केडीई का पà¥à¤°à¥‹à¤—à¥à¤°à¥‡à¤¸ जानकारी UI सरà¥à¤µà¤°
+Comment[hr]=TDEov Progess Info UI poslužitelj
+Comment[hu]=TDE folyamatinformációs kiszolgáló
+Comment[id]=Perkembangan TDE mengenai info server UI
+Comment[is]=Þjónn sem sýnir framvindu ferla
+Comment[it]=Server informazioni avanzamento di TDE
+Comment[ja]=TDE 進æ—情報 UI サーãƒ
+Comment[ka]=TDE-ს მáƒáƒœáƒáƒªáƒ”მთრგáƒáƒ“áƒáƒªáƒ”მის სერვერი
+Comment[kk]=TDE деректерді алу-беруді бақылау Ñервері
+Comment[km]=ម៉ាស៊ីន​បម្រើ UI នៃ​ពáŸážáŸŒáž˜áž¶áž“​វឌ្ážáž“ភាព​របស់ TDE
+Comment[ko]=TDEì—ì„œ 보다 ë°œì „ëœ ì •ë³´ UI 서버
+Comment[lb]=UI-Server vu TDE, dee Fortschrëttsinformatiounen uweist
+Comment[lt]=TDE eigos informacijos UI serveris
+Comment[lv]=TDE Progresa Info UI serveris
+Comment[mk]=TDE Ñервер за информации за прогреÑот
+Comment[mn]=ПрогреÑÑ Ð¼ÑдÑÑллÑÑÑ€ дүрÑлÑгдÑÑн Ñ…ÑÑ€ÑглÑгчийн харьцах Ñ…ÑÑгийн Ñервер
+Comment[ms]=Pelayan Info UI TDE
+Comment[mt]=Server tal-progress tal-UI TDE
+Comment[nb]=TDE UI-tjener for framgangsinfo
+Comment[nds]=Server för graafsche Vörankamen-Informatschonen
+Comment[ne]=TDE को पà¥à¤°à¤—ति सूचना UI सरà¥à¤­à¤°
+Comment[nl]=TDE's server voor informatie over de voortgang.
+Comment[nn]=TDE UI-tenar for framgangsinfo
+Comment[nso]=Seabi sa UI ya Tshedimoso ya Tswelopele ya TDE
+Comment[oc]=Servor d'informacion de progress TDE
+Comment[pa]=TDE ਦੀ ਤਰੱਕੀ ਜਾਣਕਾਰੀ UI ਸਰਵਰ
+Comment[pl]=Serwer informacji o postępie procesu
+Comment[pt]=Servidor de informações sobre o progresso das operações
+Comment[pt_BR]=Servidor de informação de progresso do TDE
+Comment[ro]=Server informaţii de progres TDE
+Comment[ru]=Сервер монитора передачи данных TDE
+Comment[rw]=Amakuru y'Aho bigeze ya TDE Seriveri UI
+Comment[se]=TDE:a ovdánandieđuid UI-bálvá
+Comment[sk]=TDE Progres Info UI server
+Comment[sl]=Strežnik TDE's Progress Info UI
+Comment[sq]=UI Shërbyesi për Informimin e Progresit të TDEs
+Comment[sr]=TDE-ов UI Ñервер информација о напретку
+Comment[sr@Latn]=TDE-ov UI server informacija o napretku
+Comment[sv]=TDE:s server för förloppsinformation
+Comment[ta]=கேடிஇயின௠மà¯à®©à¯à®©à¯‡à®±à¯à®± தகவல௠மà¯à®•à®ªà¯à®ªà¯à®ªà¯ சேவையகமà¯
+Comment[te]=కెడిఈ యొకà±à°• à°ªà±à°°à°—తి సమాచార యూఠసెరà±à°µà°°à±
+Comment[tg]=Инкишофи TDE's Info UI Сервер
+Comment[th]=เซิร์ฟเวอร์à¹à¸ªà¸”งข้อมูลความคืบหน้าของ TDE
+Comment[tr]=TDE'nin İlerleme Bilgisi arayüz sunucusu
+Comment[tt]=TDE'nıñ Alğakiteşne Küzätü servere
+Comment[uk]=Сервер графічного інтерфейÑу інформації про розвиток TDE
+Comment[uz]=TDE'ning maʼlumot uzatishni nazorat qilish serveri
+Comment[uz@cyrillic]=TDE'нинг маълумот узатишни назорат қилиш Ñервери
+Comment[ven]=UI siva ya mafhungo a mwelaphanda a TDE
+Comment[vi]=Trình phục vụ giao diện ngÆ°á»i dùng cho thông tin tiến hành của TDE.
+Comment[xh]=Umcedisi we UI Wenqubela Yenkcukacha we TDE
+Comment[zh_CN]=TDE 的进度信æ¯ç”¨æˆ·ç•Œé¢æœåŠ¡å™¨
+Comment[zh_HK]=TDE 的進度資訊介é¢ä¼ºæœç¨‹å¼
+Comment[zh_TW]=TDE 的進度資訊使用者介é¢ä¼ºæœå™¨
+Comment[zu]=Umlekeleli we-UI Yolwazi Lwenqubo lwe-TDE
+ServiceTypes=
+# It is a server
+X-DCOP-ServiceType=Unique
+X-TDE-StartupNotify=false
diff --git a/tdeio/misc/tdemailservice.cpp b/tdeio/misc/tdemailservice.cpp
new file mode 100644
index 000000000..3f9b04feb
--- /dev/null
+++ b/tdeio/misc/tdemailservice.cpp
@@ -0,0 +1,45 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+static const KCmdLineOptions options[] =
+{
+ { "+url", 0, 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char **argv )
+{
+ KLocale::setMainCatalogue("tdelibs");
+ TDECmdLineArgs::init( argc, argv, "tdemailservice", I18N_NOOP("KMailService"), I18N_NOOP("Mail service"), "unknown" );
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication a( false, false );
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ if ( args->count() != 1 )
+ return 1;
+
+ a.invokeMailer(KURL(args->arg(0)), a.startupId(), true);
+
+ return 0;
+}
diff --git a/tdeio/misc/tdemailservice.protocol b/tdeio/misc/tdemailservice.protocol
new file mode 100644
index 000000000..240c76aca
--- /dev/null
+++ b/tdeio/misc/tdemailservice.protocol
@@ -0,0 +1,15 @@
+[Protocol]
+exec=tdemailservice %u
+protocol=mailto
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+DocPath=tdeioslave/mailto.html
+Icon=mail_new
+Class=:internet
+URIMode=mailto
diff --git a/tdeio/misc/tdentlm/CMakeLists.txt b/tdeio/misc/tdentlm/CMakeLists.txt
new file mode 100644
index 000000000..dc26da9a1
--- /dev/null
+++ b/tdeio/misc/tdentlm/CMakeLists.txt
@@ -0,0 +1,43 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/tdecore
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install(FILES tdentlm.h DESTINATION ${INCLUDE_INSTALL_DIR}/tdeio )
+
+
+##### tdentlm ###################################
+
+set( target tdentlm )
+
+set( ${target}_SRCS
+ tdentlm.cpp des.cpp
+)
+
+tde_add_library( ${target} SHARED
+ SOURCES ${${target}_SRCS}
+ VERSION 0.0.0
+ LINK tdecore-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tdeio/misc/tdentlm/Makefile.am b/tdeio/misc/tdentlm/Makefile.am
new file mode 100644
index 000000000..16164dbe3
--- /dev/null
+++ b/tdeio/misc/tdentlm/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES=$(all_includes)
+
+lib_LTLIBRARIES = libtdentlm.la
+METASOURCES = AUTO
+
+tdentlmincludedir = $(includedir)/tdeio
+tdentlminclude_HEADERS = tdentlm.h
+
+libtdentlm_la_SOURCES = tdentlm.cpp des.cpp
+libtdentlm_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined
+libtdentlm_la_LIBADD = $(LIB_TDECORE) $(LIB_QT)
+
diff --git a/tdeio/misc/tdentlm/des.cpp b/tdeio/misc/tdentlm/des.cpp
new file mode 100644
index 000000000..bb4fab88b
--- /dev/null
+++ b/tdeio/misc/tdentlm/des.cpp
@@ -0,0 +1,513 @@
+
+/* Sofware DES functions
+ * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted from
+ * the 1977 public-domain program by Jim Gillogly
+ * Modified for additional speed - 6 December 1988 Phil Karn
+ * Modified for parameterized key schedules - Jan 1991 Phil Karn
+ * Callers now allocate a key schedule as follows:
+ * kn = (char (*)[8])malloc(sizeof(char) * 8 * 16);
+ * or
+ * char kn[16][8];
+ */
+
+/* modified in order to use the libmcrypt API by Nikos Mavroyanopoulos
+ * All modifications are placed under the license of libmcrypt.
+ */
+
+/* $Id$ */
+
+#include <string.h>
+#include <kswap.h>
+#include "des.h"
+
+static void permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
+static void permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
+static void perminit_ip (DES_KEY * key);
+static void spinit (DES_KEY * key);
+static void perminit_fp (DES_KEY * key);
+static TQ_UINT32 f (DES_KEY * key, TQ_UINT32 r, char *subkey);
+
+
+/* Tables defined in the Data Encryption Standard documents */
+
+/* initial permutation IP */
+static const char ip[] = {
+ 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+/* final permutation IP^-1 */
+static const char fp[] = {
+ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/* expansion operation matrix
+ * This is for reference only; it is unused in the code
+ * as the f() function performs it implicitly for speed
+ */
+#ifdef notdef
+static const char ei[] = {
+ 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1
+};
+#endif
+
+/* permuted choice table (key) */
+static const char pc1[] = {
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+};
+
+/* number left rotations of pc1 */
+static const char totrot[] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+};
+
+/* permuted choice key (table) */
+static const char pc2[] = {
+ 14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32
+};
+
+/* The (in)famous S-boxes */
+static const char si[8][64] = {
+ /* S1 */
+ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
+
+ /* S2 */
+ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
+
+ /* S3 */
+ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
+
+ /* S4 */
+ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
+
+ /* S5 */
+ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
+
+ /* S6 */
+ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
+
+ /* S7 */
+ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
+
+ /* S8 */
+ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
+
+};
+
+/* 32-bit permutation function P used on the output of the S-boxes */
+static const char p32i[] = {
+ 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25
+};
+
+/* End of DES-defined tables */
+
+/* Lookup tables initialized once only at startup by desinit() */
+
+/* bit 0 is left-most in byte */
+static const int bytebit[] = {
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const int nibblebit[] = {
+ 010, 04, 02, 01
+};
+
+/* Allocate space and initialize DES lookup arrays
+ * mode == 0: standard Data Encryption Algorithm
+ */
+static int
+desinit (DES_KEY * key)
+{
+
+ spinit (key);
+ perminit_ip (key);
+ perminit_fp (key);
+
+ return 0;
+}
+
+
+/* Set key (initialize key schedule array) */
+int
+ntlm_des_set_key (DES_KEY * dkey, char *user_key, int /*len*/)
+{
+ char pc1m[56]; /* place to modify pc1 into */
+ char pcr[56]; /* place to rotate pc1 into */
+ int i, j, l;
+ int m;
+
+ memset(dkey, 0, sizeof (DES_KEY));
+ desinit (dkey);
+
+ /* Clear key schedule */
+
+
+ for (j = 0; j < 56; j++)
+ { /* convert pc1 to bits of key */
+ l = pc1[j] - 1; /* integer bit location */
+ m = l & 07; /* find bit */
+ pc1m[j] = (user_key[l >> 3] & /* find which key byte l is in */
+ bytebit[m]) /* and which bit of that byte */
+ ? 1 : 0; /* and store 1-bit result */
+
+ }
+ for (i = 0; i < 16; i++)
+ { /* key chunk for each iteration */
+ for (j = 0; j < 56; j++) /* rotate pc1 the right amount */
+ pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l : l - 28];
+ /* rotate left and right halves independently */
+ for (j = 0; j < 48; j++)
+ { /* select bits individually */
+ /* check bit that goes to kn[j] */
+ if (pcr[pc2[j] - 1])
+ {
+ /* mask it in if it's there */
+ l = j % 6;
+ dkey->kn[i][j / 6] |= bytebit[l] >> 2;
+ }
+ }
+ }
+ return 0;
+}
+
+/* In-place encryption of 64-bit block */
+static void
+ntlm_des_encrypt (DES_KEY * key, unsigned char *block)
+{
+ TQ_UINT32 left, right;
+ char *knp;
+ TQ_UINT32 work[2]; /* Working data storage */
+
+ permute_ip (block, key, (unsigned char *) work); /* Initial Permutation */
+ left = KFromToBigEndian(work[0]);
+ right = KFromToBigEndian(work[1]);
+
+ /* Do the 16 rounds.
+ * The rounds are numbered from 0 to 15. On even rounds
+ * the right half is fed to f() and the result exclusive-ORs
+ * the left half; on odd rounds the reverse is done.
+ */
+ knp = &key->kn[0][0];
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+
+ /* Left/right half swap, plus byte swap if little-endian */
+ work[1] = KFromToBigEndian( left );
+ work[0] = KFromToBigEndian( right );
+
+ permute_fp ((unsigned char *) work, key, block); /* Inverse initial permutation */
+}
+
+/* Permute inblock with perm */
+static void
+permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
+{
+ unsigned char *ib, *ob; /* ptr to input or output block */
+ char *p, *q;
+ int j;
+
+ /* Clear output block */
+ memset(outblock, 0, 8);
+
+ ib = inblock;
+ for (j = 0; j < 16; j += 2, ib++)
+ { /* for each input nibble */
+ ob = outblock;
+ p = key->iperm[j][(*ib >> 4) & 0xf];
+ q = key->iperm[j + 1][*ib & 0xf];
+ /* and each output byte, OR the masks together */
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ }
+}
+
+/* Permute inblock with perm */
+static void
+permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
+{
+ unsigned char *ib, *ob; /* ptr to input or output block */
+ char *p, *q;
+ int j;
+
+ /* Clear output block */
+ memset(outblock, 0, 8);
+
+ ib = inblock;
+ for (j = 0; j < 16; j += 2, ib++)
+ { /* for each input nibble */
+ ob = outblock;
+ p = key->fperm[j][(*ib >> 4) & 0xf];
+ q = key->fperm[j + 1][*ib & 0xf];
+ /* and each output byte, OR the masks together */
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ }
+}
+
+/* The nonlinear function f(r,k), the heart of DES */
+static TQ_UINT32
+f (DES_KEY * key, TQ_UINT32 r, char *subkey)
+{
+ TQ_UINT32 *spp;
+ TQ_UINT32 rval, rt;
+ int er;
+
+#ifdef TRACE
+ printf ("f(%08lx, %02x %02x %02x %02x %02x %02x %02x %02x) = ",
+ r,
+ subkey[0], subkey[1], subkey[2],
+ subkey[3], subkey[4], subkey[5], subkey[6], subkey[7]);
+#endif
+ /* Run E(R) ^ K through the combined S & P boxes.
+ * This code takes advantage of a convenient regularity in
+ * E, namely that each group of 6 bits in E(R) feeding
+ * a single S-box is a contiguous segment of R.
+ */
+ subkey += 7;
+
+ /* Compute E(R) for each block of 6 bits, and run thru boxes */
+ er = ((int) r << 1) | ((r & 0x80000000) ? 1 : 0);
+ spp = &key->sp[7][0];
+ rval = spp[(er ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt = (TQ_UINT32) r >> 3;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rt |= (r & 1) << 5;
+ rval |= spp[((int) rt ^ *subkey) & 0x3f];
+#ifdef TRACE
+ printf (" %08lx\n", rval);
+#endif
+ return rval;
+}
+
+/* initialize a perm array */
+static void
+perminit_ip (DES_KEY * key)
+{
+ int l, j, k;
+ int i, m;
+
+ /* Clear the permutation array */
+ memset(key->iperm, 0, 16 * 16 * 8);
+
+ for (i = 0; i < 16; i++) /* each input nibble position */
+ for (j = 0; j < 16; j++) /* each possible input nibble */
+ for (k = 0; k < 64; k++)
+ { /* each output bit position */
+ l = ip[k] - 1; /* where does this bit come from */
+ if ((l >> 2) != i) /* does it come from input posn? */
+ continue; /* if not, bit k is 0 */
+ if (!(j & nibblebit[l & 3]))
+ continue; /* any such bit in input? */
+ m = k & 07; /* which bit is this in the byte */
+ key->iperm[i][j][k >> 3] |= bytebit[m];
+ }
+}
+
+static void
+perminit_fp (DES_KEY * key)
+{
+ int l, j, k;
+ int i, m;
+
+ /* Clear the permutation array */
+ memset(key->fperm, 0, 16 * 16 * 8);
+
+ for (i = 0; i < 16; i++) /* each input nibble position */
+ for (j = 0; j < 16; j++) /* each possible input nibble */
+ for (k = 0; k < 64; k++)
+ { /* each output bit position */
+ l = fp[k] - 1; /* where does this bit come from */
+ if ((l >> 2) != i) /* does it come from input posn? */
+ continue; /* if not, bit k is 0 */
+ if (!(j & nibblebit[l & 3]))
+ continue; /* any such bit in input? */
+ m = k & 07; /* which bit is this in the byte */
+ key->fperm[i][j][k >> 3] |= bytebit[m];
+ }
+}
+
+/* Initialize the lookup table for the combined S and P boxes */
+static void
+spinit (DES_KEY * key)
+{
+ char pbox[32];
+ int p, i, s, j, rowcol;
+ TQ_UINT32 val;
+
+ /* Compute pbox, the inverse of p32i.
+ * This is easier to work with
+ */
+ for (p = 0; p < 32; p++)
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (p32i[i] - 1 == p)
+ {
+ pbox[p] = i;
+ break;
+ }
+ }
+ }
+ for (s = 0; s < 8; s++)
+ { /* For each S-box */
+ for (i = 0; i < 64; i++)
+ { /* For each possible input */
+ val = 0;
+ /* The row number is formed from the first and last
+ * bits; the column number is from the middle 4
+ */
+ rowcol = (i & 32) | ((i & 1) ? 16 : 0) | ((i >> 1) & 0xf);
+ for (j = 0; j < 4; j++)
+ { /* For each output bit */
+ if (si[s][rowcol] & (8 >> j))
+ {
+ val |= 1L << (31 - pbox[4 * s + j]);
+ }
+ }
+ key->sp[s][i] = val;
+ }
+ }
+}
+
+int
+ntlm_des_ecb_encrypt (const void *plaintext, int len, DES_KEY * akey,
+ unsigned char output[8])
+{
+ int j;
+ const unsigned char *plain = (const unsigned char *) plaintext;
+
+ for (j = 0; j < len / 8; j++)
+ {
+ memcpy (&output[j * 8], &plain[j * 8], 8);
+ ntlm_des_encrypt (akey, &output[j * 8]);
+ }
+
+ if (j == 0 && len != 0)
+ return -1; /* no blocks were encrypted */
+ return 0;
+}
diff --git a/tdeio/misc/tdentlm/des.h b/tdeio/misc/tdentlm/des.h
new file mode 100644
index 000000000..0f6f59dc9
--- /dev/null
+++ b/tdeio/misc/tdentlm/des.h
@@ -0,0 +1,19 @@
+#ifndef KNTLM_DES_H
+#define KNTLM_DES_H
+
+#include <tqglobal.h>
+
+typedef struct des_key
+{
+ char kn[16][8];
+ TQ_UINT32 sp[8][64];
+ char iperm[16][16][8];
+ char fperm[16][16][8];
+} DES_KEY;
+
+int
+ntlm_des_ecb_encrypt (const void *plaintext, int len, DES_KEY * akey, unsigned char output[8]);
+int
+ntlm_des_set_key (DES_KEY * dkey, char *user_key, int len);
+
+#endif /* KNTLM_DES_H */
diff --git a/tdeio/misc/tdentlm/kswap.h b/tdeio/misc/tdentlm/kswap.h
new file mode 100644
index 000000000..9eca243de
--- /dev/null
+++ b/tdeio/misc/tdentlm/kswap.h
@@ -0,0 +1,428 @@
+/*
+ This file is part of the KDE libraries.
+ Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+
+ 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 KSWAP_H
+#define KSWAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqglobal.h>
+
+/**
+ * \defgroup KSWAP Byte-swapping functions
+ * kswap.h contains functions that will help converting
+ * 16, 32 and 64 bit length data between little-endian and
+ * big-endian representations.
+ *
+ * The KSWAP_16, KSWAP_32 and KSWAP_64 functions are always
+ * swaps the byte order of the supplied argument (which should be
+ * 16, 32 or 64 bit wide). These functions are inline, and tries to
+ * use the most optimized function of the underlying system
+ * (bswap_xx functions from byteswap.h in GLIBC, or ntohs and ntohl
+ * on little-endian machines, and if neither are applicable, some fast
+ * custom code).
+ *
+ * The KFromTo{Little|Big}Endian functions are for converting big-endian and
+ * little-endian data to and from the machine endianness.
+ */
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+
+ inline TQ_UINT16 KSWAP_16( TQ_UINT16 b ) { return bswap_16( b ); }
+ inline TQ_INT16 KSWAP_16( TQ_INT16 b ) { return bswap_16( (TQ_UINT16)b ); }
+ inline TQ_UINT32 KSWAP_32( TQ_UINT32 b ) { return bswap_32( b ); }
+ inline TQ_INT32 KSWAP_32( TQ_INT32 b ) { return bswap_32( (TQ_UINT32)b ); }
+ inline TQ_UINT64 KSWAP_64( TQ_UINT64 b ) { return bswap_64( b ); }
+ inline TQ_INT64 KSWAP_64( TQ_INT64 b ) { return bswap_64( (TQ_UINT64)b ); }
+
+#else /* HAVE_BYTESWAP_H */
+#ifdef WORDS_BIGENDIAN
+ inline TQ_UINT16 KSWAP_16( TQ_UINT16 b )
+ {
+ return (((b) & 0x00ff) << 8 | ((b) & 0xff00) >> 8);
+ }
+
+ inline TQ_INT16 KSWAP_16( TQ_INT16 b )
+ {
+ return ((((TQ_UINT16)b) & 0x00ff) << 8 | (((TQ_UINT16)b) & 0xff00) >> 8);
+ }
+
+ inline TQ_UINT32 KSWAP_32( TQ_UINT32 b )
+ {
+ return
+ ((((b) & 0xff000000) >> 24) | (((b) & 0x00ff0000) >> 8) | \
+ (((b) & 0x0000ff00) << 8) | (((b) & 0x000000ff) << 24));
+ }
+
+ inline TQ_INT32 KSWAP_32( TQ_INT32 b )
+ {
+ return
+ (((((TQ_UINT32)b) & 0xff000000) >> 24) | ((((TQ_UINT32)b) & 0x00ff0000) >> 8) | \
+ ((((TQ_UINT32)b) & 0x0000ff00) << 8) | ((((TQ_UINT32)b) & 0x000000ff) << 24));
+ }
+#else /* WORDS_BIGENDIAN */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+ inline TQ_UINT16 KSWAP_16( TQ_UINT16 b ) { return htons(b); }
+ inline TQ_INT16 KSWAP_16( TQ_INT16 b ) { return htons((TQ_UINT16)b); }
+ inline TQ_UINT32 KSWAP_32( TQ_UINT32 b ) { return htonl(b); }
+ inline TQ_INT32 KSWAP_32( TQ_INT32 b ) { return htonl((TQ_UINT32)b); }
+#endif
+ inline TQ_UINT64 KSWAP_64( TQ_UINT64 b )
+ {
+ union {
+ TQ_UINT64 ll;
+ TQ_UINT32 l[2];
+ } w, r;
+ w.ll = b;
+ r.l[0] = KSWAP_32( w.l[1] );
+ r.l[1] = KSWAP_32( w.l[0] );
+ return r.ll;
+ }
+
+ inline TQ_INT64 KSWAP_64( TQ_INT64 b )
+ {
+ union {
+ TQ_UINT64 ll;
+ TQ_UINT32 l[2];
+ } w, r;
+ w.ll = (TQ_UINT64) b;
+ r.l[0] = KSWAP_32( w.l[1] );
+ r.l[1] = KSWAP_32( w.l[0] );
+ return r.ll;
+ }
+#endif /* !HAVE_BYTESWAP_H */
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_UINT16 KFromToBigEndian( TQ_UINT16 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_UINT16 *out, TQ_UINT16 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_UINT32 KFromToBigEndian( TQ_UINT32 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_UINT32 *out, TQ_UINT32 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_UINT64 KFromToBigEndian( TQ_UINT64 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_UINT64 *out, TQ_UINT64 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_INT16 KFromToBigEndian( TQ_INT16 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_INT16 *out, TQ_INT16 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_INT32 KFromToBigEndian( TQ_INT32 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_INT32 *out, TQ_INT32 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline TQ_INT64 KFromToBigEndian( TQ_INT64 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( TQ_INT64 *out, TQ_INT64 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_UINT16 KFromToLittleEndian( TQ_UINT16 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_UINT16 *out, TQ_UINT16 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_UINT32 KFromToLittleEndian( TQ_UINT32 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_UINT32 *out, TQ_UINT32 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_UINT64 KFromToLittleEndian( TQ_UINT64 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_UINT64 *out, TQ_UINT64 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_INT16 KFromToLittleEndian( TQ_INT16 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_INT16 *out, TQ_INT16 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_INT32 KFromToLittleEndian( TQ_INT32 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_INT32 *out, TQ_INT32 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline TQ_INT64 KFromToLittleEndian( TQ_INT64 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( TQ_INT64 *out, TQ_INT64 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+#endif /* KSWAP_H */
diff --git a/tdeio/misc/tdentlm/tdentlm.cpp b/tdeio/misc/tdentlm/tdentlm.cpp
new file mode 100644
index 000000000..2ef5d1cb6
--- /dev/null
+++ b/tdeio/misc/tdentlm/tdentlm.cpp
@@ -0,0 +1,389 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2004 Szombathelyi Gy�gy <gyurco@freemail.hu>
+
+ The implementation is based on the documentation and sample code
+ at http://davenport.sourceforge.net/ntlm.html
+ The DES encryption functions are from libntlm
+ at http://josefsson.org/libntlm/
+
+ 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 <string.h>
+
+#include <tqdatetime.h>
+#include <kapplication.h>
+#include <kswap.h>
+#include <kmdcodec.h>
+#include <kdebug.h>
+
+#include "des.h"
+#include "tdentlm.h"
+
+TQString KNTLM::getString( const TQByteArray &buf, const SecBuf &secbuf, bool unicode )
+{
+ //watch for buffer overflows
+ TQ_UINT32 offset;
+ TQ_UINT16 len;
+ offset = KFromToLittleEndian((TQ_UINT32)secbuf.offset);
+ len = KFromToLittleEndian(secbuf.len);
+ if ( offset > buf.size() ||
+ offset + len > buf.size() ) return TQString::null;
+
+ TQString str;
+ const char *c = buf.data() + offset;
+
+ if ( unicode ) {
+ str = UnicodeLE2TQString( (TQChar*) c, len >> 1 );
+ } else {
+ str = TQString::fromLatin1( c, len );
+ }
+ return str;
+}
+
+TQByteArray KNTLM::getBuf( const TQByteArray &buf, const SecBuf &secbuf )
+{
+ TQByteArray ret;
+ TQ_UINT32 offset;
+ TQ_UINT16 len;
+ offset = KFromToLittleEndian((TQ_UINT32)secbuf.offset);
+ len = KFromToLittleEndian(secbuf.len);
+ //watch for buffer overflows
+ if ( offset > buf.size() ||
+ offset + len > buf.size() ) return ret;
+ ret.duplicate( buf.data() + offset, buf.size() );
+ return ret;
+}
+
+void KNTLM::addString( TQByteArray &buf, SecBuf &secbuf, const TQString &str, bool unicode )
+{
+ TQByteArray tmp;
+
+ if ( unicode ) {
+ tmp = QString2UnicodeLE( str );
+ addBuf( buf, secbuf, tmp );
+ } else {
+ const char *c;
+ c = str.latin1();
+ tmp.setRawData( c, str.length() );
+ addBuf( buf, secbuf, tmp );
+ tmp.resetRawData( c, str.length() );
+ }
+}
+
+void KNTLM::addBuf( TQByteArray &buf, SecBuf &secbuf, TQByteArray &data )
+{
+ TQ_UINT32 offset;
+ TQ_UINT16 len, maxlen;
+ offset = (buf.size() + 1) & 0xfffffffe;
+ len = data.size();
+ maxlen = data.size();
+
+ secbuf.offset = KFromToLittleEndian((TQ_UINT32)offset);
+ secbuf.len = KFromToLittleEndian(len);
+ secbuf.maxlen = KFromToLittleEndian(maxlen);
+ buf.resize( offset + len );
+ memcpy( buf.data() + offset, data.data(), data.size() );
+}
+
+bool KNTLM::getNegotiate( TQByteArray &negotiate, const TQString &domain, const TQString &workstation, TQ_UINT32 flags )
+{
+ TQByteArray rbuf( sizeof(Negotiate) );
+
+ rbuf.fill( 0 );
+ memcpy( rbuf.data(), "NTLMSSP", 8 );
+ ((Negotiate*) rbuf.data())->msgType = KFromToLittleEndian( (TQ_UINT32)1 );
+ if ( !domain.isEmpty() ) {
+ flags |= Negotiate_Domain_Supplied;
+ addString( rbuf, ((Negotiate*) rbuf.data())->domain, domain );
+ }
+ if ( !workstation.isEmpty() ) {
+ flags |= Negotiate_WS_Supplied;
+ addString( rbuf, ((Negotiate*) rbuf.data())->domain, workstation );
+ }
+ ((Negotiate*) rbuf.data())->flags = KFromToLittleEndian( flags );
+ negotiate = rbuf;
+ return true;
+}
+
+bool KNTLM::getAuth( TQByteArray &auth, const TQByteArray &challenge, const TQString &user,
+ const TQString &password, const TQString &domain, const TQString &workstation,
+ bool forceNTLM, bool forceNTLMv2 )
+{
+ TQByteArray rbuf( sizeof(Auth) );
+ Challenge *ch = (Challenge *) challenge.data();
+ TQByteArray response;
+ uint chsize = challenge.size();
+ bool unicode = false;
+ TQString dom;
+
+ //challenge structure too small
+ if ( chsize < 32 ) return false;
+
+ unicode = KFromToLittleEndian(ch->flags) & Negotiate_Unicode;
+ if ( domain.isEmpty() )
+ dom = getString( challenge, ch->targetName, unicode );
+ else
+ dom = domain;
+
+ rbuf.fill( 0 );
+ memcpy( rbuf.data(), "NTLMSSP", 8 );
+ ((Auth*) rbuf.data())->msgType = KFromToLittleEndian( (TQ_UINT32)3 );
+ ((Auth*) rbuf.data())->flags = ch->flags;
+ TQByteArray targetInfo = getBuf( challenge, ch->targetInfo );
+
+// if ( forceNTLMv2 || (!targetInfo.isEmpty() && (KFromToLittleEndian(ch->flags) & Negotiate_Target_Info)) /* may support NTLMv2 */ ) {
+// if ( KFromToLittleEndian(ch->flags) & Negotiate_NTLM ) {
+// if ( targetInfo.isEmpty() ) return false;
+// response = getNTLMv2Response( dom, user, password, targetInfo, ch->challengeData );
+// addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
+// } else {
+// if ( !forceNTLM ) {
+// response = getLMv2Response( dom, user, password, ch->challengeData );
+// addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
+// } else
+// return false;
+// }
+// } else { //if no targetinfo structure and NTLMv2 or LMv2 not forced, try the older methods
+
+ response = getNTLMResponse( password, ch->challengeData );
+ addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
+ response = getLMResponse( password, ch->challengeData );
+ addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
+// }
+ if ( !dom.isEmpty() )
+ addString( rbuf, ((Auth*) rbuf.data())->domain, dom, unicode );
+ addString( rbuf, ((Auth*) rbuf.data())->user, user, unicode );
+ if ( !workstation.isEmpty() )
+ addString( rbuf, ((Auth*) rbuf.data())->workstation, workstation, unicode );
+
+ auth = rbuf;
+
+ return true;
+}
+
+TQByteArray KNTLM::getLMResponse( const TQString &password, const unsigned char *challenge )
+{
+ TQByteArray hash, answer;
+
+ hash = lmHash( password );
+ hash.resize( 21 );
+ memset( hash.data() + 16, 0, 5 );
+ answer = lmResponse( hash, challenge );
+ hash.fill( 0 );
+ return answer;
+}
+
+TQByteArray KNTLM::lmHash( const TQString &password )
+{
+ TQByteArray keyBytes( 14 );
+ TQByteArray hash( 16 );
+ DES_KEY ks;
+ const char *magic = "KGS!@#$%";
+
+ keyBytes.fill( 0 );
+ strncpy( keyBytes.data(), password.upper().latin1(), 14 );
+
+ convertKey( (unsigned char*) keyBytes.data(), &ks );
+ ntlm_des_ecb_encrypt( magic, 8, &ks, (unsigned char*) hash.data() );
+
+ convertKey( (unsigned char*) keyBytes.data() + 7, &ks );
+ ntlm_des_ecb_encrypt( magic, 8, &ks, (unsigned char*) hash.data() + 8 );
+
+ keyBytes.fill( 0 );
+ memset( &ks, 0, sizeof (ks) );
+
+ return hash;
+}
+
+TQByteArray KNTLM::lmResponse( const TQByteArray &hash, const unsigned char *challenge )
+{
+ DES_KEY ks;
+ TQByteArray answer( 24 );
+
+ convertKey( (unsigned char*) hash.data(), &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() );
+
+ convertKey( (unsigned char*) hash.data() + 7, &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() + 8 );
+
+ convertKey( (unsigned char*) hash.data() + 14, &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() + 16 );
+
+ memset( &ks, 0, sizeof (ks) );
+ return answer;
+}
+
+TQByteArray KNTLM::getNTLMResponse( const TQString &password, const unsigned char *challenge )
+{
+ TQByteArray hash, answer;
+
+ hash = ntlmHash( password );
+ hash.resize( 21 );
+ memset( hash.data() + 16, 0, 5 );
+ answer = lmResponse( hash, challenge );
+ hash.fill( 0 );
+ return answer;
+}
+
+TQByteArray KNTLM::ntlmHash( const TQString &password )
+{
+ KMD4::Digest digest;
+ TQByteArray ret, unicode;
+ unicode = QString2UnicodeLE( password );
+
+ KMD4 md4( unicode );
+ md4.rawDigest( digest );
+ ret.duplicate( (const char*) digest, sizeof( digest ) );
+ return ret;
+}
+
+TQByteArray KNTLM::getNTLMv2Response( const TQString &target, const TQString &user,
+ const TQString &password, const TQByteArray &targetInformation,
+ const unsigned char *challenge )
+{
+ TQByteArray hash = ntlmv2Hash( target, user, password );
+ TQByteArray blob = createBlob( targetInformation );
+ return lmv2Response( hash, blob, challenge );
+}
+
+TQByteArray KNTLM::getLMv2Response( const TQString &target, const TQString &user,
+ const TQString &password, const unsigned char *challenge )
+{
+ TQByteArray hash = ntlmv2Hash( target, user, password );
+ TQByteArray clientChallenge( 8 );
+ for ( uint i = 0; i<8; i++ ) {
+ clientChallenge.data()[i] = TDEApplication::random() % 0xff;
+ }
+ return lmv2Response( hash, clientChallenge, challenge );
+}
+
+TQByteArray KNTLM::ntlmv2Hash( const TQString &target, const TQString &user, const TQString &password )
+{
+ TQByteArray hash1 = ntlmHash( password );
+ TQByteArray key, ret;
+ TQString id = user.upper() + target.upper();
+ key = QString2UnicodeLE( id );
+ ret = hmacMD5( key, hash1 );
+ return ret;
+}
+
+TQByteArray KNTLM::lmv2Response( const TQByteArray &hash,
+ const TQByteArray &clientData, const unsigned char *challenge )
+{
+ TQByteArray data( 8 + clientData.size() );
+ memcpy( data.data(), challenge, 8 );
+ memcpy( data.data() + 8, clientData.data(), clientData.size() );
+ TQByteArray mac = hmacMD5( data, hash );
+ mac.resize( 16 + clientData.size() );
+ memcpy( mac.data() + 16, clientData.data(), clientData.size() );
+ return mac;
+}
+
+TQByteArray KNTLM::createBlob( const TQByteArray &targetinfo )
+{
+ TQByteArray blob( sizeof(Blob) + 4 + targetinfo.size() );
+ blob.fill( 0 );
+
+ Blob *bl = (Blob *) blob.data();
+ bl->signature = KFromToBigEndian( (TQ_UINT32) 0x01010000 );
+ TQ_UINT64 now = TQDateTime::currentDateTime().toTime_t();
+ now += (TQ_UINT64)3600*(TQ_UINT64)24*(TQ_UINT64)134774;
+ now *= (TQ_UINT64)10000000;
+ bl->timestamp = KFromToLittleEndian( now );
+ for ( uint i = 0; i<8; i++ ) {
+ bl->challenge[i] = TDEApplication::random() % 0xff;
+ }
+ memcpy( blob.data() + sizeof(Blob), targetinfo.data(), targetinfo.size() );
+ return blob;
+}
+
+TQByteArray KNTLM::hmacMD5( const TQByteArray &data, const TQByteArray &key )
+{
+ TQ_UINT8 ipad[64], opad[64];
+ KMD5::Digest digest;
+ TQByteArray ret;
+
+ memset( ipad, 0x36, sizeof(ipad) );
+ memset( opad, 0x5c, sizeof(opad) );
+ for ( int i = key.size()-1; i >= 0; i-- ) {
+ ipad[i] ^= key[i];
+ opad[i] ^= key[i];
+ }
+
+ TQByteArray content( data.size()+64 );
+ memcpy( content.data(), ipad, 64 );
+ memcpy( content.data() + 64, data.data(), data.size() );
+ KMD5 md5( content );
+ md5.rawDigest( digest );
+ content.resize( sizeof(digest) + 64 );
+ memcpy( content.data(), opad, 64 );
+ memcpy( content.data() + 64, digest, sizeof(digest) );
+ md5.reset();
+ md5.update( content );
+ md5.rawDigest( digest );
+
+ ret.duplicate( (const char*) digest, sizeof( digest ) );
+ return ret;
+}
+
+/*
+* turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+* The key schedule ks is also set.
+*/
+void KNTLM::convertKey( unsigned char *key_56, void* ks )
+{
+ unsigned char key[8];
+
+ key[0] = key_56[0];
+ key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+ key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+ key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+ key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+ key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+ key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+ key[7] = (key_56[6] << 1) & 0xFF;
+
+ for ( uint i=0; i<8; i++ ) {
+ unsigned char b = key[i];
+ bool needsParity = (((b>>7) ^ (b>>6) ^ (b>>5) ^ (b>>4) ^ (b>>3) ^ (b>>2) ^ (b>>1)) & 0x01) == 0;
+ if ( needsParity )
+ key[i] |= 0x01;
+ else
+ key[i] &= 0xfe;
+ }
+
+ ntlm_des_set_key ( (DES_KEY*) ks, (char*) &key, sizeof (key));
+
+ memset (&key, 0, sizeof (key));
+}
+
+TQByteArray KNTLM::QString2UnicodeLE( const TQString &target )
+{
+ TQByteArray unicode( target.length() * 2 );
+ for ( uint i = 0; i < target.length(); i++ ) {
+ ((TQ_UINT16*)unicode.data())[ i ] = KFromToLittleEndian( target[i].unicode() );
+ }
+ return unicode;
+}
+
+TQString KNTLM::UnicodeLE2TQString( const TQChar* data, uint len )
+{
+ TQString ret;
+ for ( uint i = 0; i < len; i++ ) {
+ ret += KFromToLittleEndian( data[ i ].unicode() );
+ }
+ return ret;
+}
diff --git a/tdeio/misc/tdentlm/tdentlm.h b/tdeio/misc/tdentlm/tdentlm.h
new file mode 100644
index 000000000..06b8febab
--- /dev/null
+++ b/tdeio/misc/tdentlm/tdentlm.h
@@ -0,0 +1,233 @@
+/*
+ This file is part of the KDE libraries.
+ Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+
+ 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 KNTLM_H
+#define KNTLM_H
+
+#include <tqglobal.h>
+#include <tqcstring.h>
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+/**
+ * @short KNTLM class implements the NTLM authentication protocol.
+ *
+ * The KNTLM class is useful for creating the authentication structures which
+ * can be used for various servers which implements NTLM type authentication.
+ * A comprehensive description of the NTLM authentication protocol can be found
+ * at http://davenport.sourceforge.net/ntlm.html
+ * The class also contains methods to create the LanManager and NT (MD4) hashes
+ * of a password.
+ * This class doesn't maintain any state information, so all methods are static.
+ */
+
+class TDEIO_EXPORT KNTLM {
+public:
+
+ enum Flags {
+ Negotiate_Unicode = 0x00000001,
+ Negotiate_OEM = 0x00000002,
+ Request_Target = 0x00000004,
+ Negotiate_Sign = 0x00000010,
+ Negotiate_Seal = 0x00000020,
+ Negotiate_Datagram_Style = 0x00000040,
+ Negotiate_LM_Key = 0x00000080,
+ Negotiate_Netware = 0x00000100,
+ Negotiate_NTLM = 0x00000200,
+ Negotiate_Domain_Supplied = 0x00001000,
+ Negotiate_WS_Supplied = 0x00002000,
+ Negotiate_Local_Call = 0x00004000,
+ Negotiate_Always_Sign = 0x00008000,
+ Target_Type_Domain = 0x00010000,
+ Target_Type_Server = 0x00020000,
+ Target_Type_Share = 0x00040000,
+ Negotiate_NTLM2_Key = 0x00080000,
+ Request_Init_Response = 0x00100000,
+ Request_Accept_Response = 0x00200000,
+ Request_NonNT_Key = 0x00400000,
+ Negotiate_Target_Info = 0x00800000,
+ Negotiate_128 = 0x20000000,
+ Negotiate_Key_Exchange = 0x40000000,
+ Negotiate_56 = 0x80000000
+ };
+
+ typedef struct
+ {
+ TQ_UINT16 len;
+ TQ_UINT16 maxlen;
+ TQ_UINT32 offset;
+ } SecBuf;
+
+ /**
+ * The NTLM Type 1 structure
+ */
+ typedef struct
+ {
+ char signature[8]; /* "NTLMSSP\0" */
+ TQ_UINT32 msgType; /* 1 */
+ TQ_UINT32 flags;
+ SecBuf domain;
+ SecBuf workstation;
+ } Negotiate;
+
+ /**
+ * The NTLM Type 2 structure
+ */
+ typedef struct
+ {
+ char signature[8];
+ TQ_UINT32 msgType; /* 2 */
+ SecBuf targetName;
+ TQ_UINT32 flags;
+ TQ_UINT8 challengeData[8];
+ TQ_UINT32 context[2];
+ SecBuf targetInfo;
+ } Challenge;
+
+ /**
+ * The NTLM Type 3 structure
+ */
+ typedef struct
+ {
+ char signature[8];
+ TQ_UINT32 msgType; /* 3 */
+ SecBuf lmResponse;
+ SecBuf ntResponse;
+ SecBuf domain;
+ SecBuf user;
+ SecBuf workstation;
+ SecBuf sessionKey;
+ TQ_UINT32 flags;
+ } Auth;
+
+ typedef struct
+ {
+ TQ_UINT32 signature;
+ TQ_UINT32 reserved;
+ TQ_UINT64 timestamp;
+ TQ_UINT8 challenge[8];
+ TQ_UINT8 unknown[4];
+ //Target info block - variable length
+ } Blob;
+
+ /**
+ * Creates the initial message (type 1) which should be sent to the server.
+ *
+ * @param negotiate - a buffer where the Type 1 message will returned.
+ * @param domain - the domain name which should be send with the message.
+ * @param workstation - the workstation name which should be send with the message.
+ * @param flags - various flags, in most cases the defaults will good.
+ *
+ * @return true if creating the structure succeeds, false otherwise.
+ */
+ static bool getNegotiate( TQByteArray &negotiate, const TQString &domain = TQString::null,
+ const TQString &workstation = TQString::null,
+ TQ_UINT32 flags = Negotiate_Unicode | Request_Target | Negotiate_NTLM );
+ /**
+ * Creates the type 3 message which should be sent to the server after
+ * the challenge (type 2) received.
+ *
+ * @param auth - a buffer where the Type 3 message will returned.
+ * @param challenge - the Type 2 message returned by the server.
+ * @param user - user's name.
+ * @param password - user's password.
+ * @param domain - the target domain. If left empty, it will be extracted
+ * from the challenge.
+ * @param workstation - the user's workstation.
+ * @param forceNTLM - force the use of NTLM authentication (either v1 or v2).
+ * @param forceNTLMv2 - force the use of NTLMv2 or LMv2 authentication. If false, NTLMv2
+ * support is autodetected from the challenge.
+ *
+ * @return true if auth filled with the Type 3 message, false if an error occured
+ * (challenge data invalid, or NTLM authentication forced, but the challenge data says
+ * no NTLM supported).
+ */
+ static bool getAuth( TQByteArray &auth, const TQByteArray &challenge, const TQString &user,
+ const TQString &password, const TQString &domain = TQString::null,
+ const TQString &workstation = TQString::null, bool forceNTLM = false, bool forceNTLMv2 = false );
+
+ /**
+ * Returns the LanManager response from the password and the server challenge.
+ */
+ static TQByteArray getLMResponse( const TQString &password, const unsigned char *challenge );
+ /**
+ * Calculates the LanManager hash of the specified password.
+ */
+ static TQByteArray lmHash( const TQString &password );
+ /**
+ * Calculates the LanManager response from the LanManager hash and the server challenge.
+ */
+ static TQByteArray lmResponse( const TQByteArray &hash, const unsigned char *challenge );
+
+ /**
+ * Returns the NTLM response from the password and the server challenge.
+ */
+ static TQByteArray getNTLMResponse( const TQString &password, const unsigned char *challenge );
+ /**
+ * Returns the NTLM hash (MD4) from the password.
+ */
+ static TQByteArray ntlmHash( const TQString &password );
+
+ /**
+ * Calculates the NTLMv2 response.
+ */
+ static TQByteArray getNTLMv2Response( const TQString &target, const TQString &user,
+ const TQString &password, const TQByteArray &targetInformation,
+ const unsigned char *challenge );
+
+ /**
+ * Calculates the LMv2 response.
+ */
+ static TQByteArray getLMv2Response( const TQString &target, const TQString &user,
+ const TQString &password, const unsigned char *challenge );
+
+ /**
+ * Returns the NTLMv2 hash.
+ */
+ static TQByteArray ntlmv2Hash( const TQString &target, const TQString &user, const TQString &password );
+
+ /**
+ * Calculates the LMv2 response.
+ */
+ static TQByteArray lmv2Response( const TQByteArray &hash,
+ const TQByteArray &clientData, const unsigned char *challenge );
+
+ /**
+ * Extracts a string field from an NTLM structure.
+ */
+ static TQString getString( const TQByteArray &buf, const SecBuf &secbuf, bool unicode );
+ /**
+ * Extracts a byte array from an NTLM structure.
+ */
+ static TQByteArray getBuf( const TQByteArray &buf, const SecBuf &secbuf );
+
+ static TQByteArray createBlob( const TQByteArray &targetinfo );
+
+ static TQByteArray hmacMD5( const TQByteArray &data, const TQByteArray &key );
+private:
+ static TQByteArray QString2UnicodeLE( const TQString &target );
+ static TQString UnicodeLE2TQString( const TQChar* data, uint len );
+
+ static void addBuf( TQByteArray &buf, SecBuf &secbuf, TQByteArray &data );
+ static void addString( TQByteArray &buf, SecBuf &secbuf, const TQString &str, bool unicode = false );
+ static void convertKey( unsigned char *key_56, void* ks );
+};
+
+#endif /* KNTLM_H */
diff --git a/tdeio/misc/tdesasl/CMakeLists.txt b/tdeio/misc/tdesasl/CMakeLists.txt
new file mode 100644
index 000000000..d48322d93
--- /dev/null
+++ b/tdeio/misc/tdesasl/CMakeLists.txt
@@ -0,0 +1,42 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### headers ###################################
+
+install(FILES tdesasl.h DESTINATION ${INCLUDE_INSTALL_DIR}/tdeio )
+
+
+##### tdesasl ###################################
+
+set( target tdesasl )
+
+set( ${target}_SRCS
+ tdesasl.cpp
+)
+
+tde_add_library( ${target} SHARED
+ SOURCES ${${target}_SRCS}
+ VERSION 1.2.0
+ LINK tdecore-shared
+ DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/tdeio/misc/tdesasl/Makefile.am b/tdeio/misc/tdesasl/Makefile.am
new file mode 100644
index 000000000..4ebde7e8d
--- /dev/null
+++ b/tdeio/misc/tdesasl/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES=$(all_includes)
+
+lib_LTLIBRARIES = libtdesasl.la
+METASOURCES = AUTO
+
+tdesaslincludedir = $(includedir)/tdeio
+tdesaslinclude_HEADERS = tdesasl.h
+
+libtdesasl_la_SOURCES = tdesasl.cpp
+libtdesasl_la_LDFLAGS = $(all_libraries) -version-info 3:0:2 -no-undefined
+libtdesasl_la_LIBADD = $(LIB_TDECORE) $(LIB_QT)
+
diff --git a/tdeio/misc/tdesasl/tdesasl.cpp b/tdeio/misc/tdesasl/tdesasl.cpp
new file mode 100644
index 000000000..ef0768f98
--- /dev/null
+++ b/tdeio/misc/tdesasl/tdesasl.cpp
@@ -0,0 +1,285 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001-2002 Michael Häckel <haeckel@kde.org>
+ $Id$
+
+ 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 "tdesasl.h"
+
+#include <kmdcodec.h>
+#include <kurl.h>
+
+#include <tqstrlist.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+KDESasl::KDESasl(const KURL &aUrl)
+{
+ mProtocol = aUrl.protocol();
+ mUser = aUrl.user();
+ mPass = aUrl.pass();
+ mFirst = true;
+}
+
+KDESasl::KDESasl(const TQString &aUser, const TQString &aPass,
+ const TQString &aProtocol)
+{
+ mProtocol = aProtocol;
+ mUser = aUser;
+ mPass = aPass;
+ mFirst = true;
+}
+
+KDESasl::~KDESasl() {
+}
+
+TQCString KDESasl::chooseMethod(const TQStrIList aMethods)
+{
+ if (aMethods.contains("DIGEST-MD5")) mMethod = "DIGEST-MD5";
+ else if (aMethods.contains("CRAM-MD5")) mMethod = "CRAM-MD5";
+ else if (aMethods.contains("PLAIN")) mMethod = "PLAIN";
+ else if (aMethods.contains("LOGIN")) mMethod = "LOGIN";
+ else mMethod = TQCString();
+ return mMethod;
+}
+
+void KDESasl::setMethod(const TQCString &aMethod)
+{
+ mMethod = aMethod.upper();
+}
+
+TQByteArray KDESasl::getPlainResponse()
+{
+ TQCString user = mUser.utf8();
+ TQCString pass = mPass.utf8();
+ int userlen = user.length();
+ int passlen = pass.length();
+ // result = $user\0$user\0$pass (no trailing \0)
+ TQByteArray result(2 * userlen + passlen + 2);
+ if ( userlen ) {
+ memcpy( result.data(), user.data(), userlen );
+ memcpy( result.data() + userlen + 1, user.data(), userlen );
+ }
+ if ( passlen )
+ memcpy( result.data() + 2 * userlen + 2, pass.data(), passlen );
+ result[userlen] = result[2*userlen+1] = '\0';
+ return result;
+}
+
+TQByteArray KDESasl::getLoginResponse()
+{
+ TQByteArray result = (mFirst) ? mUser.utf8() : mPass.utf8();
+ mFirst = !mFirst;
+ if (result.size()) result.resize(result.size() - 1);
+ return result;
+}
+
+TQByteArray KDESasl::getCramMd5Response(const TQByteArray &aChallenge)
+{
+ uint i;
+ TQByteArray secret = mPass.utf8();
+ int len = mPass.utf8().length();
+ secret.resize(len);
+ if (secret.size() > 64)
+ {
+ KMD5 md5(secret);
+ secret.duplicate((const char*)(&(md5.rawDigest()[0])), 16);
+ len = 16;
+ }
+ secret.resize(64);
+ for (i = len; i < 64; i++) secret[i] = 0;
+ TQByteArray XorOpad(64);
+ for (i = 0; i < 64; i++) XorOpad[i] = secret[i] ^ 0x5C;
+ TQByteArray XorIpad(64);
+ for (i = 0; i < 64; i++) XorIpad[i] = secret[i] ^ 0x36;
+ KMD5 md5;
+ md5.update(XorIpad);
+ md5.update(aChallenge);
+ KMD5 md5a;
+ md5a.update(XorOpad);
+ md5a.update(md5.rawDigest(), 16);
+ TQByteArray result = mUser.utf8();
+ len = mUser.utf8().length();
+ result.resize(len + 33);
+ result[len] = ' ';
+ TQCString ch = md5a.hexDigest();
+ for (i = 0; i < 32; i++) result[i+len+1] = *(ch.data() + i);
+ return result;
+}
+
+TQByteArray KDESasl::getDigestMd5Response(const TQByteArray &aChallenge)
+{
+ mFirst = !mFirst;
+ if (mFirst) return TQByteArray();
+ TQCString str, realm, nonce, qop, algorithm, charset;
+ TQCString nc = "00000001";
+ unsigned int a, b, c, d;
+ a = 0;
+ while (a < aChallenge.size())
+ {
+ b = a;
+ while (b < aChallenge.size() && aChallenge[b] != '=') b++;
+ c = b + 1;
+ if (aChallenge[c] == '"')
+ {
+ d = c + 1;
+ while (d < aChallenge.size() && aChallenge[d] != '"') d++;
+ c++;
+ } else {
+ d = c;
+ while (d < aChallenge.size() && aChallenge[d] != ',') d++;
+ }
+ str = TQCString(aChallenge.data() + c, d - c + 1);
+ if (tqstrnicmp(aChallenge.data() + a, "realm=", 6) == 0) realm = str;
+ else if (tqstrnicmp(aChallenge.data() + a, "nonce=", 6) == 0) nonce = str;
+ else if (tqstrnicmp(aChallenge.data() + a, "qop=", 4) == 0) qop = str;
+ else if (tqstrnicmp(aChallenge.data() + a, "algorithm=", 10) == 0)
+ algorithm = str;
+ else if (tqstrnicmp(aChallenge.data() + a, "charset=", 8) == 0)
+ charset = str;
+ a = (d < aChallenge.size() && aChallenge[d] == '"') ? d + 2 : d + 1;
+ }
+ if (qop.isEmpty()) qop = "auth";
+ qop = "auth";
+ bool utf8 = tqstricmp(charset, "utf-8") == 0;
+ TQCString digestUri = TQCString(mProtocol.latin1()) + "/" + realm;
+
+ /* Calculate the response */
+ /* Code based on code from the http io-slave
+ Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
+ Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2000,2001 George Staikos <staikos@kde.org> */
+ KMD5 md, md2;
+ TQCString HA1, HA2;
+ TQCString cnonce;
+ cnonce.setNum((1 + static_cast<int>(100000.0*rand()/(RAND_MAX+1.0))));
+ cnonce = KCodecs::base64Encode( cnonce );
+
+ // Calculate H(A1)
+ TQCString authStr = (utf8) ? mUser.utf8() : TQCString(mUser.latin1());
+ authStr += ':';
+ authStr += realm;
+ authStr += ':';
+ authStr += (utf8) ? mPass.utf8() : TQCString(mPass.latin1());
+
+ md.update( authStr );
+ authStr = "";
+ if ( algorithm == "md5-sess" )
+ {
+ authStr += ':';
+ authStr += nonce;
+ authStr += ':';
+ authStr += cnonce;
+ }
+ md2.reset();
+ /* SASL authentication uses rawDigest here, whereas HTTP authentication uses
+ hexDigest() */
+ md2.update(md.rawDigest(), 16);
+ md2.update( authStr );
+ md2.hexDigest( HA1 );
+
+ // Calcualte H(A2)
+ authStr = "AUTHENTICATE:";
+ authStr += digestUri;
+ if ( qop == "auth-int" || qop == "auth-conf" )
+ {
+ authStr += ":00000000000000000000000000000000";
+ }
+ md.reset();
+ md.update( authStr );
+ md.hexDigest( HA2 );
+
+ // Calcualte the response.
+ authStr = HA1;
+ authStr += ':';
+ authStr += nonce;
+ authStr += ':';
+ if ( !qop.isEmpty() )
+ {
+ authStr += nc;
+ authStr += ':';
+ authStr += cnonce;
+ authStr += ':';
+ authStr += qop;
+ authStr += ':';
+ }
+ authStr += HA2;
+ md.reset();
+ md.update( authStr );
+ TQCString response = md.hexDigest();
+ /* End of response calculation */
+
+ TQCString result;
+ if (utf8)
+ {
+ result = "charset=utf-8,username=\"" + mUser.utf8();
+ } else {
+ result = "charset=iso-8859-1,username=\"" + TQCString(mUser.latin1());
+ }
+ result += "\",realm=\"" + realm + "\",nonce=\"" + nonce;
+ result += "\",nc=" + nc + ",cnonce=\"" + cnonce;
+ result += "\",digest-uri=\"" + digestUri;
+ result += "\",response=" + response + ",qop=" + qop;
+ TQByteArray ba;
+ ba.duplicate(result.data(), result.length());
+ return ba;
+}
+
+TQByteArray KDESasl::getBinaryResponse(const TQByteArray &aChallenge, bool aBase64)
+{
+ if (aBase64)
+ {
+ TQByteArray ba;
+ KCodecs::base64Decode(aChallenge, ba);
+ KCodecs::base64Encode(getBinaryResponse(ba, false), ba);
+ return ba;
+ }
+ if (tqstricmp(mMethod, "PLAIN") == 0) return getPlainResponse();
+ if (tqstricmp(mMethod, "LOGIN") == 0) return getLoginResponse();
+ if (tqstricmp(mMethod, "CRAM-MD5") == 0)
+ return getCramMd5Response(aChallenge);
+ if (tqstricmp(mMethod, "DIGEST-MD5") == 0)
+ return getDigestMd5Response(aChallenge);
+// return getDigestMd5Response(TQCString("realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"));
+ return TQByteArray();
+}
+
+TQCString KDESasl::getResponse(const TQByteArray &aChallenge, bool aBase64)
+{
+ TQByteArray ba = getBinaryResponse(aChallenge, aBase64);
+ return TQCString(ba.data(), ba.size() + 1);
+}
+
+TQCString KDESasl::method() const {
+ return mMethod;
+}
+
+bool KDESasl::clientStarts() const {
+ return method() == "PLAIN";
+}
+
+bool KDESasl::dialogComplete( int n ) const {
+ if ( method() == "PLAIN" || method() == "CRAM-MD5" )
+ return n >= 1;
+ if ( method() == "LOGIN" || method() == "DIGEST-MD5" )
+ return n >= 2;
+ return true;
+}
+
+bool KDESasl::isClearTextMethod() const {
+ return method() == "PLAIN" || method() == "LOGIN" ;
+}
diff --git a/tdeio/misc/tdesasl/tdesasl.h b/tdeio/misc/tdesasl/tdesasl.h
new file mode 100644
index 000000000..0c57096a8
--- /dev/null
+++ b/tdeio/misc/tdesasl/tdesasl.h
@@ -0,0 +1,169 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001-2002 Michael Häckel <haeckel@kde.org>
+ $Id$
+
+ 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 TDESASL_H
+#define TDESASL_H
+
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+class KURL;
+class TQStrIList;
+
+/**
+ * This library can create responses for SASL authentication for a given
+ * challenge and a given secret. This way of authentication is common for
+ * SMTP, POP3, IMAP and LDAP.
+ *
+ * SASL is one way strong encryption and therefore useful for authentication,
+ * but not for secret information transfer.
+ * It is possibly to prove with SASL to know a shared secret like a password.
+ * It is not possible with SASL to transfer any other information in an
+ * encrypted way. For that purpose OpenPGP or SSL are useful.
+ *
+ * Currently PLAIN (RFC 2595), LOGIN (not really a SASL mechanism, but
+ * used like that in IMAP and SMTP), CRAM-MD5 (RFC 2195) and
+ * DIGEST-MD5 (RFC 2831) authentication are supported. PLAIN and
+ * LOGIN transmit the credentials in the clear (apart from a possible
+ * base64 encoding).
+ *
+ * For KDE 3.2, the API has been extended to allow transparent use of
+ * all currently supported SASL mechanisms. Example:
+ * \code
+ * KDESasl sasl( myUser, myPass, myProtocol );
+ * if ( !sasl.chooseMethod( myMechanismsSupportedByServer ) )
+ * return false; // couldn't agree on a method
+ *
+ * int numResponses = 0;
+ * if ( sasl.clientStarts() ) { // check whether we're supposed to start the dialog
+ * ++numResponses;
+ * mySendAuthCommand( sasl.method(), sasl.getResponse() );
+ * } else {
+ * mySendAuthCommand( sasl.method() );
+ * }
+ * for ( ; !sasl.dialogComplete( numResponses ) ; ++numResponses ) {
+ * TQByteArray challenge = myRecvChallenge();
+ * mySendResponse( sasl.getResponse( challenge ) );
+ * }
+ * return myCheckSuccess();
+ * \endcode
+ *
+ * @author Michael Häckel <haeckel@kde.org>
+ * @version $Id$
+ */
+
+class TDEIO_EXPORT KDESasl
+{
+
+public:
+ /**
+ * Construct a sasl object and initialize it with the username and password
+ * passed via the url.
+ */
+ KDESasl(const KURL &aUrl);
+ /**
+ * This is a conveniece function and differs from the above function only by
+ * what arguments it accepts.
+ */
+ KDESasl(const TQString &aUser, const TQString &aPass, const TQString &aProtocol);
+ /*
+ * You need to have a virtual destructor!
+ */
+ virtual ~KDESasl();
+ /**
+ * @returns the most secure method from the given methods and use it for
+ * further operations.
+ */
+ virtual TQCString chooseMethod(const TQStrIList aMethods);
+ /**
+ * Explicitely set the SASL method used.
+ */
+ virtual void setMethod(const TQCString &aMethod);
+ /**
+ * @return the SASL method used.
+ * @since 3.2
+ */
+ TQCString method() const;
+ /**
+ * @param numCalls number of times getResponse() has been called.
+ * @return whether the challenge/response dialog has completed
+ *
+ * @since 3.2
+ */
+ bool dialogComplete( int numCalls ) const;
+ /**
+ * @return whether the currently selected mechanism results in
+ * cleartext passwords being sent over the network and thus should
+ * be used only under TLS/SSL cover or for legacy servers.
+ *
+ * @since 3.2
+ */
+ bool isClearTextMethod() const;
+ /**
+ * Creates a response using the formerly chosen SASL method.
+ * For LOGIN authentication you have to call this function twice. KDESasl
+ * realizes on its own, if you are calling it for the first or for the
+ * second time.
+ * @param aChallenge is the challenge sent to create a response for
+ * @param aBase64 specifies, whether the authentication protocol uses base64
+ * encoding. The challenge is decoded from base64 and the response is
+ * encoded base64 if set to true.
+ */
+ TQCString getResponse(const TQByteArray &aChallenge=TQByteArray(), bool aBase64 = true);
+ /**
+ * Create a response as above but place it in a QByteArray
+ */
+ TQByteArray getBinaryResponse(const TQByteArray &aChallenge=TQByteArray(), bool aBase64=true);
+ /**
+ * Returns true if the client is supposed to initiate the
+ * challenge-respinse dialog with an initial response (which most
+ * protocols can transfer alongside the authentication command as an
+ * optional second parameter). This method relieves the sasl user
+ * from knowing details about the mechanism. If true, use
+ * #getResponse() with a null challenge.
+ *
+ * @since 3.2
+ */
+ bool clientStarts() const;
+protected:
+ /**
+ * PLAIN authentication as described in RFC 2595
+ */
+ virtual TQByteArray getPlainResponse();
+ /**
+ * LOGIN authentication
+ */
+ virtual TQByteArray getLoginResponse();
+ /**
+ * CRAM-MD5 authentication as described in RFC 2195
+ */
+ virtual TQByteArray getCramMd5Response(const TQByteArray &aChallenge);
+ /**
+ * DIGEST-MD5 authentication as described in RFC 2831
+ */
+ virtual TQByteArray getDigestMd5Response(const TQByteArray &aChallenge);
+
+private:
+ TQString mProtocol, mUser, mPass;
+ TQCString mMethod;
+ bool mFirst;
+};
+
+#endif
diff --git a/tdeio/misc/tdesendbugmail/CMakeLists.txt b/tdeio/misc/tdesendbugmail/CMakeLists.txt
new file mode 100644
index 000000000..3dffadb22
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/CMakeLists.txt
@@ -0,0 +1,37 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### tdesendbugmail ##############################
+
+set( target tdesendbugmail )
+
+set( ${target}_SRCS
+ main.cpp smtp.cpp
+)
+
+tde_add_executable( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeio-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
diff --git a/tdeio/misc/tdesendbugmail/Makefile.am b/tdeio/misc/tdesendbugmail/Makefile.am
new file mode 100644
index 000000000..f9087a4fe
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/Makefile.am
@@ -0,0 +1,26 @@
+# This file is part of the KDE libraries
+# Copyright (C) 2000 Stephan Kulow <coolo@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.
+
+bin_PROGRAMS = tdesendbugmail
+INCLUDES= -I$(srcdir)/.. $(all_includes)
+
+tdesendbugmail_SOURCES = main.cpp smtp.cpp
+tdesendbugmail_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+tdesendbugmail_LDADD = ../../libtdeio.la
+
+METASOURCES = AUTO
diff --git a/tdeio/misc/tdesendbugmail/main.cpp b/tdeio/misc/tdesendbugmail/main.cpp
new file mode 100644
index 000000000..162e6ad5c
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/main.cpp
@@ -0,0 +1,142 @@
+// $Id$
+
+#include <sys/types.h>
+#include "main.h"
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <tqtextstream.h>
+
+#include <kapplication.h>
+#include <kemailsettings.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <tdeconfig.h>
+
+#include "smtp.h"
+
+static KCmdLineOptions options[] = {
+ { "subject <argument>", I18N_NOOP("Subject line"), 0 },
+ { "recipient <argument>", I18N_NOOP("Recipient"), "submit@bugs.kde.org" },
+ KCmdLineLastOption
+};
+
+void BugMailer::slotError(int errornum) {
+ kdDebug() << "slotError\n";
+ TQString str, lstr;
+
+ switch(errornum) {
+ case SMTP::CONNECTERROR:
+ lstr = i18n("Error connecting to server.");
+ break;
+ case SMTP::NOTCONNECTED:
+ lstr = i18n("Not connected.");
+ break;
+ case SMTP::CONNECTTIMEOUT:
+ lstr = i18n("Connection timed out.");
+ break;
+ case SMTP::INTERACTTIMEOUT:
+ lstr = i18n("Time out waiting for server interaction.");
+ break;
+ default:
+ lstr = sm->getLastLine().stripWhiteSpace();
+ lstr = i18n("Server said: \"%1\"").arg(lstr);
+ }
+ fputs(lstr.utf8().data(), stdout);
+ fflush(stdout);
+
+ ::exit(1);
+}
+
+void BugMailer::slotSend() {
+ kdDebug() << "slotSend\n";
+ ::exit(0);
+}
+
+int main(int argc, char **argv) {
+
+ KLocale::setMainCatalogue("tdelibs");
+ TDEAboutData d("tdesendbugmail", I18N_NOOP("KSendBugMail"), "1.0",
+ I18N_NOOP("Sends a short bug report to submit@bugs.kde.org"),
+ TDEAboutData::License_GPL, "(c) 2000 Stephan Kulow");
+ d.addAuthor("Stephan Kulow", I18N_NOOP("Author"), "coolo@kde.org");
+
+ TDECmdLineArgs::init(argc, argv, &d);
+ TDECmdLineArgs::addCmdLineOptions(options);
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ TDEApplication a(false, false);
+
+ TQCString recipient = args->getOption("recipient");
+ if (recipient.isEmpty())
+ recipient = "submit@bugs.kde.org";
+ else {
+ if (recipient.at(0) == '\'') {
+ recipient = recipient.mid(1).left(recipient.length() - 2);
+ }
+ }
+ kdDebug() << "recp \"" << recipient << "\"\n";
+
+ TQCString subject = args->getOption("subject");
+ if (subject.isEmpty())
+ subject = "(no subject)";
+ else {
+ if (subject.at(0) == '\'')
+ subject = subject.mid(1).left(subject.length() - 2);
+ }
+ TQTextIStream input(stdin);
+ TQString text, line;
+ while (!input.eof()) {
+ line = input.readLine();
+ text += line + "\r\n";
+ }
+ kdDebug() << text << endl;
+
+ KEMailSettings emailConfig;
+ emailConfig.setProfile(emailConfig.defaultProfileName());
+ TQString fromaddr = emailConfig.getSetting(KEMailSettings::EmailAddress);
+ if (!fromaddr.isEmpty()) {
+ TQString name = emailConfig.getSetting(KEMailSettings::RealName);
+ if (!name.isEmpty())
+ fromaddr = name + TQString::fromLatin1(" <") + fromaddr + TQString::fromLatin1(">");
+ } else {
+ struct passwd *p;
+ p = getpwuid(getuid());
+ fromaddr = TQString::fromLatin1(p->pw_name);
+ fromaddr += "@";
+ char buffer[256];
+ buffer[0] = '\0';
+ if(!gethostname(buffer, sizeof(buffer)))
+ buffer[sizeof(buffer)-1] = '\0';
+ fromaddr += buffer;
+ }
+ kdDebug() << "fromaddr \"" << fromaddr << "\"" << endl;
+
+ TQString server = emailConfig.getSetting(KEMailSettings::OutServer);
+ if (server.isEmpty())
+ server=TQString::fromLatin1("bugs.kde.org");
+
+ SMTP *sm = new SMTP;
+ BugMailer bm(sm);
+
+ TQObject::connect(sm, TQT_SIGNAL(messageSent()), &bm, TQT_SLOT(slotSend()));
+ TQObject::connect(sm, TQT_SIGNAL(error(int)), &bm, TQT_SLOT(slotError(int)));
+ sm->setServerHost(server);
+ sm->setPort(25);
+ sm->setSenderAddress(fromaddr);
+ sm->setRecipientAddress(recipient);
+ sm->setMessageSubject(subject);
+ sm->setMessageHeader(TQString::fromLatin1("From: %1\r\nTo: %2\r\n").arg(fromaddr).arg(recipient.data()));
+ sm->setMessageBody(text);
+ sm->sendMessage();
+
+ int r = a.exec();
+ kdDebug() << "execing " << r << endl;
+ delete sm;
+ return r;
+}
+
+#include "main.moc"
diff --git a/tdeio/misc/tdesendbugmail/main.h b/tdeio/misc/tdesendbugmail/main.h
new file mode 100644
index 000000000..39d424bef
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/main.h
@@ -0,0 +1,20 @@
+#ifndef BUG_MAILER_H
+#define BUG_MAILER_H "$Id$"
+
+#include <tqobject.h>
+
+class SMTP;
+
+class BugMailer : public TQObject {
+ Q_OBJECT
+public:
+ BugMailer(SMTP* s) : TQObject(0, "mailer"), sm(s) {}
+
+public slots:
+ void slotError(int);
+ void slotSend();
+private:
+ SMTP *sm;
+};
+
+#endif
diff --git a/tdeio/misc/tdesendbugmail/smtp.cpp b/tdeio/misc/tdesendbugmail/smtp.cpp
new file mode 100644
index 000000000..d282782fc
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/smtp.cpp
@@ -0,0 +1,336 @@
+/* $Id$ */
+
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <kdebug.h>
+
+#include "smtp.h"
+
+SMTP::SMTP(char *serverhost, unsigned short int port, int timeout)
+{
+ struct utsname uts;
+
+ serverHost = serverhost;
+ hostPort = port;
+ timeOut = timeout * 1000;
+
+ senderAddress = "user@example.net";
+ recipientAddress = "user@example.net";
+ messageSubject = "(no subject)";
+ messageBody = "empty";
+ messageHeader = "";
+
+ connected = false;
+ finished = false;
+
+ sock = 0L;
+ state = INIT;
+ serverState = NONE;
+
+ uname(&uts);
+ domainName = uts.nodename;
+
+
+ if(domainName.isEmpty())
+ domainName = "somemachine.example.net";
+
+ kdDebug() << "SMTP object created" << endl;
+
+ connect(&connectTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(connectTimerTick()));
+ connect(&timeOutTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(connectTimedOut()));
+ connect(&interactTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(interactTimedOut()));
+
+ // some sendmail will give 'duplicate helo' error, quick fix for now
+ connect(this, TQT_SIGNAL(messageSent()), TQT_SLOT(closeConnection()));
+}
+
+SMTP::~SMTP()
+{
+ if(sock){
+ delete sock;
+ sock = 0L;
+ }
+ connectTimer.stop();
+ timeOutTimer.stop();
+}
+
+void SMTP::setServerHost(const TQString& serverhost)
+{
+ serverHost = serverhost;
+}
+
+void SMTP::setPort(unsigned short int port)
+{
+ hostPort = port;
+}
+
+void SMTP::setTimeOut(int timeout)
+{
+ timeOut = timeout;
+}
+
+void SMTP::setSenderAddress(const TQString& sender)
+{
+ senderAddress = sender;
+ int index = senderAddress.find('<');
+ if (index == -1)
+ return;
+ senderAddress = senderAddress.mid(index + 1);
+ index = senderAddress.find('>');
+ if (index != -1)
+ senderAddress = senderAddress.left(index);
+ senderAddress = senderAddress.simplifyWhiteSpace();
+ while (1) {
+ index = senderAddress.find(' ');
+ if (index != -1)
+ senderAddress = senderAddress.mid(index + 1); // take one side
+ else
+ break;
+ }
+ index = senderAddress.find('@');
+ if (index == -1)
+ senderAddress.append("@localhost"); // won't go through without a local mail system
+
+}
+
+void SMTP::setRecipientAddress(const TQString& recipient)
+{
+ recipientAddress = recipient;
+}
+
+void SMTP::setMessageSubject(const TQString& subject)
+{
+ messageSubject = subject;
+}
+
+void SMTP::setMessageBody(const TQString& message)
+{
+ messageBody = message;
+}
+
+void SMTP::setMessageHeader(const TQString &header)
+{
+ messageHeader = header;
+}
+
+void SMTP::openConnection(void)
+{
+ kdDebug() << "started connect timer" << endl;
+ connectTimer.start(100, true);
+}
+
+void SMTP::closeConnection(void)
+{
+ socketClose(sock);
+}
+
+void SMTP::sendMessage(void)
+{
+ if(!connected)
+ connectTimerTick();
+ if(state == FINISHED && connected){
+ kdDebug() << "state was == FINISHED\n" << endl;
+ finished = false;
+ state = IN;
+ writeString = TQString::fromLatin1("helo %1\r\n").arg(domainName);
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ }
+ if(connected){
+ kdDebug() << "enabling read on sock...\n" << endl;
+ interactTimer.start(timeOut, true);
+ sock->enableRead(true);
+ }
+}
+#include <stdio.h>
+
+void SMTP::connectTimerTick(void)
+{
+ connectTimer.stop();
+// timeOutTimer.start(timeOut, true);
+
+ kdDebug() << "connectTimerTick called..." << endl;
+
+ if(sock){
+ delete sock;
+ sock = 0L;
+ }
+
+ kdDebug() << "connecting to " << serverHost << ":" << hostPort << " ..... " << endl;
+ sock = new TDESocket(serverHost.ascii(), hostPort);
+
+ if(sock == 0L || sock->socket() < 0) {
+ timeOutTimer.stop();
+ kdDebug() << "connection failed!" << endl;
+ socketClose(sock);
+ emit error(CONNECTERROR);
+ connected = false;
+ return;
+ }
+ connected = true;
+ finished = false;
+ state = INIT;
+ serverState = NONE;
+
+ connect(sock, TQT_SIGNAL(readEvent(TDESocket *)), this, TQT_SLOT(socketRead(TDESocket *)));
+ connect(sock, TQT_SIGNAL(closeEvent(TDESocket *)), this, TQT_SLOT(socketClose(TDESocket *)));
+ // sock->enableRead(true);
+ timeOutTimer.stop();
+ kdDebug() << "connected" << endl;
+}
+
+void SMTP::connectTimedOut(void)
+{
+ timeOutTimer.stop();
+
+ if(sock)
+ sock->enableRead(false);
+ kdDebug() << "socket connection timed out" << endl;
+ socketClose(sock);
+ emit error(CONNECTTIMEOUT);
+}
+
+void SMTP::interactTimedOut(void)
+{
+ interactTimer.stop();
+
+ if(sock)
+ sock->enableRead(false);
+ kdDebug() << "time out waiting for server interaction" << endl;
+ socketClose(sock);
+ emit error(INTERACTTIMEOUT);
+}
+
+void SMTP::socketRead(TDESocket *socket)
+{
+ int n, nl;
+
+ kdDebug() << "socketRead() called..." << endl;
+ interactTimer.stop();
+
+ if(socket == 0L || socket->socket() < 0)
+ return;
+ n = read(socket->socket(), readBuffer, SMTP_READ_BUFFER_SIZE-1 );
+
+ if(n < 0)
+ return;
+
+ readBuffer[n] = '\0';
+ lineBuffer += readBuffer;
+ nl = lineBuffer.find('\n');
+ if(nl == -1)
+ return;
+ lastLine = lineBuffer.left(nl);
+ lineBuffer = lineBuffer.right(lineBuffer.length() - nl - 1);
+ processLine(&lastLine);
+ if(connected)
+ interactTimer.start(timeOut, true);
+}
+
+void SMTP::socketClose(TDESocket *socket)
+{
+ timeOutTimer.stop();
+ disconnect(sock, TQT_SIGNAL(readEvent(TDESocket *)), this, TQT_SLOT(socketRead(TDESocket *)));
+ disconnect(sock, TQT_SIGNAL(closeEvent(TDESocket *)), this, TQT_SLOT(socketClose(TDESocket *)));
+ socket->enableRead(false);
+ kdDebug() << "connection terminated" << endl;
+ connected = false;
+ if(socket){
+ delete socket;
+ socket = 0L;
+ sock = 0L;
+ }
+ emit connectionClosed();
+}
+
+void SMTP::processLine(TQString *line)
+{
+ int i, stat;
+ TQString tmpstr;
+
+ i = line->find(' ');
+ tmpstr = line->left(i);
+ if(i > 3)
+ kdDebug() << "warning: SMTP status code longer then 3 digits: " << tmpstr << endl;
+ stat = tmpstr.toInt();
+ serverState = (SMTPServerStatus)stat;
+ lastState = state;
+
+ kdDebug() << "smtp state: [" << stat << "][" << *line << "]" << endl;
+
+ switch(stat){
+ case GREET: //220
+ state = IN;
+ writeString = TQString::fromLatin1("helo %1\r\n").arg(domainName);
+ kdDebug() << "out: " << writeString << endl;
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ break;
+ case GOODBYE: //221
+ state = QUIT;
+ break;
+ case SUCCESSFUL://250
+ switch(state){
+ case IN:
+ state = READY;
+ writeString = TQString::fromLatin1("mail from: %1\r\n").arg(senderAddress);
+ kdDebug() << "out: " << writeString << endl;
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ break;
+ case READY:
+ state = SENTFROM;
+ writeString = TQString::fromLatin1("rcpt to: %1\r\n").arg(recipientAddress);
+ kdDebug() << "out: " << writeString << endl;
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ break;
+ case SENTFROM:
+ state = SENTTO;
+ writeString = TQString::fromLatin1("data\r\n");
+ kdDebug() << "out: " << writeString << endl;
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ break;
+ case DATA:
+ state = FINISHED;
+ finished = true;
+ sock->enableRead(false);
+ emit messageSent();
+ break;
+ default:
+ state = CERROR;
+ kdDebug() << "smtp error (state error): [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
+ socketClose(sock);
+ emit error(COMMAND);
+ break;
+ }
+ break;
+ case READYDATA: //354
+ state = DATA;
+ writeString = TQString::fromLatin1("Subject: %1\r\n").arg(messageSubject);
+ writeString += messageHeader;
+ writeString += "\r\n";
+ writeString += messageBody;
+ writeString += TQString::fromLatin1(".\r\n");
+ kdDebug() << "out: " << writeString;
+ write(sock->socket(), writeString.ascii(), writeString.length());
+ break;
+ case ERROR: //501
+ state = CERROR;
+ kdDebug() << "smtp error (command error): [" << lastState << "]:[" << stat << "][" << *line << "]\n" << endl;
+ socketClose(sock);
+ emit error(COMMAND);
+ break;
+ case UNKNOWN: //550
+ state = CERROR;
+ kdDebug() << "smtp error (unknown user): [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
+ socketClose(sock);
+ emit error(UNKNOWNUSER);
+ break;
+ default:
+ state = CERROR;
+ kdDebug() << "unknown response: [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
+ socketClose(sock);
+ emit error(UNKNOWNRESPONSE);
+ }
+}
+
+#include "smtp.moc"
diff --git a/tdeio/misc/tdesendbugmail/smtp.h b/tdeio/misc/tdesendbugmail/smtp.h
new file mode 100644
index 000000000..acdb4a3c3
--- /dev/null
+++ b/tdeio/misc/tdesendbugmail/smtp.h
@@ -0,0 +1,144 @@
+/* $Id$ */
+
+#ifndef SMTP_H
+#define SMTP_H
+
+#include <tqobject.h>
+#include <tqtimer.h>
+#include <ksock.h>
+
+/*int SMTPServerStatus[] = {
+ 220, // greeting from server
+ 221, // server acknolages goodbye
+ 250, // command successful
+ 354, // ready to receive data
+ 501, // error
+ 550, // user unknown
+ 0 // null
+};
+
+int SMTPClientStatus[] = {
+ 50, // not logged in yet.
+ 100, // logged in, got 220
+ 150, // sent helo, got 250
+ 200, // sent mail from, got 250
+ 250, // sent rctp to, got 250
+ 300, // data sent, got 354
+ 350, // sent data/., got 250
+ 400, // send quit, got 221
+ 450, // finished, logged out
+ 0 // null
+};
+*/
+
+#define DEFAULT_SMTP_PORT 25
+#define DEFAULT_SMTP_SERVER localhost
+#define DEFAULT_SMTP_TIMEOUT 60
+
+#define SMTP_READ_BUFFER_SIZE 256
+
+class SMTP:public QObject
+{
+ Q_OBJECT
+public:
+ SMTP(char *serverhost = 0, unsigned short int port = 0, int timeout = DEFAULT_SMTP_TIMEOUT);
+ ~SMTP();
+
+ void setServerHost(const TQString& serverhost);
+ void setPort(unsigned short int port);
+ void setTimeOut(int timeout);
+
+ bool isConnected(){return connected;};
+ bool isFinished(){return finished;};
+ TQString getLastLine(){return lastLine;};
+
+ void setSenderAddress(const TQString& sender);
+ void setRecipientAddress(const TQString& recipient);
+ void setMessageSubject(const TQString& subject);
+ void setMessageBody(const TQString& message);
+ void setMessageHeader(const TQString &header);
+
+ typedef enum {
+ NONE = 0, // null
+ GREET = 220, // greeting from server
+ GOODBYE = 221, // server acknolages quit
+ SUCCESSFUL = 250, // command successful
+ READYDATA = 354, // server ready to receive data
+ ERROR = 501, // error
+ UNKNOWN = 550 // user unknown
+ }SMTPServerStatus;
+
+ typedef enum {
+ INIT = 50, // not logged in yet
+ IN = 100, // logged in, got 220
+ READY = 150, // sent HELO, got 250
+ SENTFROM = 200, // sent MAIL FROM:, got 250
+ SENTTO = 250, // sent RCTP TO:, got 250
+ DATA = 300, // DATA sent, got 354
+ FINISHED = 350, // finished sending data, got 250
+ QUIT = 400, // sent QUIT, got 221
+ OUT = 450, // finished, logged out
+ CERROR = 500 // didn't finish, had error or connection drop
+ }SMTPClientStatus;
+
+ typedef enum {
+ NOERROR = 0,
+ CONNECTERROR = 10,
+ NOTCONNECTED = 11,
+ CONNECTTIMEOUT = 15,
+ INTERACTTIMEOUT = 16,
+ UNKNOWNRESPONSE = 20,
+ UNKNOWNUSER = 30,
+ COMMAND = 40
+ }SMTPError;
+
+protected:
+ void processLine(TQString *line);
+
+public slots:
+ void openConnection();
+ void sendMessage();
+ void closeConnection();
+
+ void connectTimerTick();
+ void connectTimedOut();
+ void interactTimedOut();
+
+ void socketRead(TDESocket *);
+ void socketClose(TDESocket *);
+
+signals:
+ void connectionClosed();
+ void messageSent();
+ void error(int);
+
+private:
+ TQString serverHost;
+ unsigned short int hostPort;
+ int timeOut;
+
+ bool connected;
+ bool finished;
+
+ TQString senderAddress;
+ TQString recipientAddress;
+ TQString messageSubject;
+ TQString messageBody, messageHeader;
+
+ SMTPClientStatus state;
+ SMTPClientStatus lastState;
+ SMTPServerStatus serverState;
+
+ TQString domainName;
+
+ TDESocket *sock;
+ TQTimer connectTimer;
+ TQTimer timeOutTimer;
+ TQTimer interactTimer;
+
+ char readBuffer[SMTP_READ_BUFFER_SIZE];
+ TQString lineBuffer;
+ TQString lastLine;
+ TQString writeString;
+};
+#endif
diff --git a/tdeio/misc/tdetelnetservice.cpp b/tdeio/misc/tdetelnetservice.cpp
new file mode 100644
index 000000000..655a5b32a
--- /dev/null
+++ b/tdeio/misc/tdetelnetservice.cpp
@@ -0,0 +1,112 @@
+/*
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+ based on tdemailservice.cpp,
+ Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <ksimpleconfig.h>
+
+static const KCmdLineOptions options[] =
+{
+ {"+url", 0, 0},
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KLocale::setMainCatalogue("tdelibs");
+ TDECmdLineArgs::init(argc, argv, "tdetelnetservice", I18N_NOOP("telnet service"),
+ I18N_NOOP("telnet protocol handler"), "unknown");
+ TDECmdLineArgs::addCmdLineOptions(options);
+
+ TDEApplication app;
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ if (args->count() != 1)
+ return 1;
+
+ TDEConfig *config = new TDEConfig("kdeglobals", true);
+ config->setGroup("General");
+ TQString terminal = config->readPathEntry("TerminalApplication", "konsole");
+
+ KURL url(args->arg(0));
+ TQStringList cmd;
+ if (terminal == "konsole")
+ cmd << "--noclose";
+
+ cmd << "-e";
+ if ( url.protocol() == "telnet" )
+ cmd << "telnet";
+ else if ( url.protocol() == "ssh" )
+ cmd << "ssh";
+ else if ( url.protocol() == "rlogin" )
+ cmd << "rlogin";
+ else {
+ kdError() << "Invalid protocol " << url.protocol() << endl;
+ return 2;
+ }
+
+ if (!app.authorize("shell_access"))
+ {
+ KMessageBox::sorry(0,
+ i18n("You do not have permission to access the %1 protocol.").arg(url.protocol()));
+ return 3;
+ }
+
+ if (!url.user().isEmpty())
+ {
+ cmd << "-l";
+ cmd << url.user();
+ }
+
+ TQString host;
+ if (!url.host().isEmpty())
+ host = url.host(); // telnet://host
+ else if (!url.path().isEmpty())
+ host = url.path(); // telnet:host
+
+ if (host.isEmpty() || host.startsWith("-"))
+ {
+ kdError() << "Invalid hostname " << host << endl;
+ return 2;
+ }
+
+ cmd << host;
+
+ if (url.port()){
+ if ( url.protocol() == "ssh" )
+ cmd << "-p" << TQString::number(url.port());
+ else
+ cmd << TQString::number(url.port());
+ }
+
+ app.tdeinitExec(terminal, cmd);
+
+ return 0;
+}
+
+// vim: ts=4 sw=4 noet
diff --git a/tdeio/misc/tdewalletd/CMakeLists.txt b/tdeio/misc/tdewalletd/CMakeLists.txt
new file mode 100644
index 000000000..2d0d2ef28
--- /dev/null
+++ b/tdeio/misc/tdewalletd/CMakeLists.txt
@@ -0,0 +1,49 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdewallet/client
+ ${CMAKE_SOURCE_DIR}/tdewallet/backend
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install(FILES tdewalletd.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded )
+
+
+#### kded_tdewalletd ##############################
+
+set( target kded_tdewalletd )
+
+set( ${target}_SRCS
+ tdewalletd.cpp tdewalletd.skel ktimeout.cpp tdewalletwizard.ui
+ kbetterthankdialogbase.ui
+)
+
+tde_add_kpart( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeinit_kded-shared tdewalletbackend-shared
+ DEPENDENCIES dcopidl
+ DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/tdeio/misc/tdewalletd/Makefile.am b/tdeio/misc/tdewalletd/Makefile.am
new file mode 100644
index 000000000..5d52fa810
--- /dev/null
+++ b/tdeio/misc/tdewalletd/Makefile.am
@@ -0,0 +1,35 @@
+# This file is part of the KDE libraries
+# Copyright (C) 2002 George Staikos <staikos@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.
+
+INCLUDES= -I$(srcdir)/.. -I$(top_srcdir) -I$(top_srcdir)/tdewallet/backend -I$(top_builddir)/tdewallet/backend -I$(top_srcdir)/tdewallet/client -I$(top_builddir)/tdewallet/client $(all_includes)
+
+kde_module_LTLIBRARIES = kded_tdewalletd.la
+
+kded_tdewalletd_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_tdewalletd_la_LIBADD = $(LIB_KIO) ../../../tdewallet/backend/libtdewalletbackend.la ../../../tdewallet/client/libtdewalletclient.la $(LIB_KDED) $(LIB_QT) $(top_builddir)/dcop/libDCOP.la $(LIB_TDECORE) $(LIB_TDEUI)
+kded_tdewalletd_la_SOURCES = tdewalletd.cpp tdewalletd.skel ktimeout.cpp tdewalletwizard.ui kbetterthankdialogbase.ui
+
+METASOURCES = AUTO
+
+noinst_HEADERS = tdewalletd.h ktimeout.h tdewalletwizard.ui.h
+
+services_DATA = tdewalletd.desktop
+servicesdir = $(kde_servicesdir)/kded
+
+tdewalletwizard.lo: tdewalletwizard.ui tdewalletwizard.ui.h
+kbetterthankdialogbase.lo: kbetterthankdialogbase.ui kbetterthankdialogbase.ui.h
diff --git a/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui b/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui
new file mode 100644
index 000000000..a02d5def7
--- /dev/null
+++ b/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui
@@ -0,0 +1,154 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KBetterThanKDialogBase</class>
+<widget class="TQDialog">
+ <property name="name">
+ <cstring>KBetterThanKDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>479</width>
+ <height>109</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="resizeMode">
+ <enum>Fixed</enum>
+ </property>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>_label</cstring>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>_allowOnce</cstring>
+ </property>
+ <property name="text">
+ <string>Allow &amp;Once</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>_allowAlways</cstring>
+ </property>
+ <property name="text">
+ <string>Allow &amp;Always</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>_deny</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Deny</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>_denyForever</cstring>
+ </property>
+ <property name="text">
+ <string>Deny &amp;Forever</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>_allowOnce</sender>
+ <signal>clicked()</signal>
+ <receiver>KBetterThanKDialogBase</receiver>
+ <slot>clicked()</slot>
+ </connection>
+ <connection>
+ <sender>_allowAlways</sender>
+ <signal>clicked()</signal>
+ <receiver>KBetterThanKDialogBase</receiver>
+ <slot>clicked()</slot>
+ </connection>
+ <connection>
+ <sender>_deny</sender>
+ <signal>clicked()</signal>
+ <receiver>KBetterThanKDialogBase</receiver>
+ <slot>clicked()</slot>
+ </connection>
+ <connection>
+ <sender>_denyForever</sender>
+ <signal>clicked()</signal>
+ <receiver>KBetterThanKDialogBase</receiver>
+ <slot>clicked()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">kactivelabel.h</include>
+ <include location="local" impldecl="in implementation">kbetterthankdialogbase.ui.h</include>
+</includes>
+<Q_SLOTS>
+ <slot access="private">clicked()</slot>
+ <slot>setLabel( const TQString &amp; label )</slot>
+ <slot access="private">init()</slot>
+ <slot access="protected">accept()</slot>
+ <slot access="protected">reject()</slot>
+</Q_SLOTS>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kactivelabel.h</includehint>
+</includehints>
+</UI>
diff --git a/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui.h b/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui.h
new file mode 100644
index 000000000..2b3e16b0d
--- /dev/null
+++ b/tdeio/misc/tdewalletd/kbetterthankdialogbase.ui.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+void KBetterThanKDialogBase::clicked()
+{
+ if (sender() == _allowOnce) {
+ done(0);
+ } else if (sender() == _allowAlways) {
+ done(1);
+ } else if (sender() == _deny) {
+ done(2);
+ } else if (sender() == _denyForever) {
+ done(3);
+ }
+}
+
+
+void KBetterThanKDialogBase::setLabel( const TQString & label )
+{
+ _label->setText(label);
+}
+
+
+void KBetterThanKDialogBase::init()
+{
+ _allowOnce->setFocus();
+}
+
+
+void KBetterThanKDialogBase::accept()
+{
+ setResult(0);
+}
+
+
+void KBetterThanKDialogBase::reject()
+{
+ TQDialog::reject();
+ setResult(2);
+}
diff --git a/tdeio/misc/tdewalletd/ktimeout.cpp b/tdeio/misc/tdewalletd/ktimeout.cpp
new file mode 100644
index 000000000..c431ecf69
--- /dev/null
+++ b/tdeio/misc/tdewalletd/ktimeout.cpp
@@ -0,0 +1,84 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 George Staikos <staikos@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 "ktimeout.h"
+
+KTimeout::KTimeout(int size)
+: TQObject(), _timers(size) {
+ _timers.setAutoDelete(true);
+}
+
+
+KTimeout::~KTimeout() {
+ clear();
+}
+
+
+void KTimeout::clear() {
+ _timers.clear();
+}
+
+
+void KTimeout::removeTimer(int id) {
+ TQTimer *t = _timers.find(id);
+ if (t != 0L) {
+ _timers.remove(id); // autodeletes
+ }
+}
+
+
+void KTimeout::addTimer(int id, int timeout) {
+ if (_timers.find(id) != 0L) {
+ return;
+ }
+
+ TQTimer *t = new TQTimer;
+ connect(t, TQT_SIGNAL(timeout()), this, TQT_SLOT(timeout()));
+ t->start(timeout);
+ _timers.insert(id, t);
+}
+
+
+void KTimeout::resetTimer(int id, int timeout) {
+ TQTimer *t = _timers.find(id);
+ if (t) {
+ t->changeInterval(timeout);
+ }
+}
+
+
+void KTimeout::timeout() {
+ const TQTimer *t = static_cast<const TQTimer*>(sender());
+ if (t) {
+ TQIntDictIterator<TQTimer> it(_timers);
+ for (; it.current(); ++it) {
+ if (it.current() == t) {
+ emit timedOut(it.currentKey());
+ return;
+ }
+ }
+ }
+}
+
+
+#include "ktimeout.moc"
+
diff --git a/tdeio/misc/tdewalletd/ktimeout.h b/tdeio/misc/tdewalletd/ktimeout.h
new file mode 100644
index 000000000..441e4ed77
--- /dev/null
+++ b/tdeio/misc/tdewalletd/ktimeout.h
@@ -0,0 +1,52 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2003 George Staikos <staikos@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 _KTIMEOUT_H_
+#define _KTIMEOUT_H_
+
+#include <tqintdict.h>
+#include <tqobject.h>
+#include <tqtimer.h>
+
+// @internal
+class KTimeout : public TQObject {
+ Q_OBJECT
+ public:
+ KTimeout(int size = 29);
+ virtual ~KTimeout();
+
+ signals:
+ void timedOut(int id);
+
+ public slots:
+ void resetTimer(int id, int timeout);
+ void addTimer(int id, int timeout);
+ void removeTimer(int id);
+ void clear();
+
+ private slots:
+ void timeout();
+
+ private:
+ TQIntDict<TQTimer> _timers;
+};
+
+#endif
diff --git a/tdeio/misc/tdewalletd/tdewalletd.cpp b/tdeio/misc/tdewalletd/tdewalletd.cpp
new file mode 100644
index 000000000..a8b3ade1a
--- /dev/null
+++ b/tdeio/misc/tdewalletd/tdewalletd.cpp
@@ -0,0 +1,1514 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2002-2004 George Staikos <staikos@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 "kbetterthankdialogbase.h"
+#include "tdewalletwizard.h"
+#include "tdewalletd.h"
+#include "ktimeout.h"
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kactivelabel.h>
+#include <kapplication.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpassdlg.h>
+#include <kstandarddirs.h>
+#include <tdewalletentry.h>
+#include <twin.h>
+
+#include <tqdir.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+#include <tqregexp.h>
+#include <tqstylesheet.h>
+#include <tqvbox.h>
+
+#include <assert.h>
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_tdewalletd(const TQCString &name) {
+ return new KWalletD(name);
+ }
+}
+
+
+class KWalletTransaction {
+ public:
+ KWalletTransaction() {
+ tType = Unknown;
+ transaction = 0L;
+ client = 0L;
+ modal = false;
+ }
+
+ ~KWalletTransaction() {
+ // Don't delete these!
+ transaction = 0L;
+ client = 0L;
+ }
+
+ enum Type { Unknown, Open, ChangePassword, OpenFail };
+ DCOPClient *client;
+ DCOPClientTransaction *transaction;
+ Type tType;
+ TQCString rawappid, returnObject;
+ TQCString appid;
+ uint wId;
+ TQString wallet;
+ bool modal;
+};
+
+
+KWalletD::KWalletD(const TQCString &name)
+: KDEDModule(name), _failed(0) {
+ srand(time(0));
+ _showingFailureNotify = false;
+ _transactions.setAutoDelete(true);
+ _timeouts = new KTimeout(17);
+ _closeIdle = false;
+ _idleTime = 0;
+ connect(_timeouts, TQT_SIGNAL(timedOut(int)), this, TQT_SLOT(timedOut(int)));
+ reconfigure();
+ TDEGlobal::dirs()->addResourceType("tdewallet", "share/apps/tdewallet");
+ connect(TDEApplication::dcopClient(),
+ TQT_SIGNAL(applicationRemoved(const TQCString&)),
+ this,
+ TQT_SLOT(slotAppUnregistered(const TQCString&)));
+ _dw = new KDirWatch(this, "KWallet Directory Watcher");
+ _dw->addDir(TDEGlobal::dirs()->saveLocation("tdewallet"));
+ _dw->startScan(true);
+ connect(_dw, TQT_SIGNAL(dirty(const TQString&)), this, TQT_SLOT(emitWalletListDirty()));
+}
+
+
+KWalletD::~KWalletD() {
+ delete _timeouts;
+ _timeouts = 0;
+
+ closeAllWallets();
+ _transactions.clear();
+}
+
+
+int KWalletD::generateHandle() {
+ int rc;
+
+ // ASSUMPTION: RAND_MAX is fairly large.
+ do {
+ rc = rand();
+ } while (_wallets.find(rc) || rc == 0);
+
+ return rc;
+}
+
+
+void KWalletD::processTransactions() {
+ static bool processing = false;
+
+ if (processing) {
+ return;
+ }
+
+ processing = true;
+
+ // Process remaining transactions
+ KWalletTransaction *xact;
+ while (!_transactions.isEmpty()) {
+ xact = _transactions.first();
+ TQCString replyType;
+ int res;
+
+ assert(xact->tType != KWalletTransaction::Unknown);
+
+ switch (xact->tType) {
+ case KWalletTransaction::Open:
+ res = doTransactionOpen(xact->appid, xact->wallet, xact->wId, xact->modal);
+ replyType = "int";
+ if (!xact->returnObject.isEmpty()) {
+ DCOPRef(xact->rawappid, xact->returnObject).send("walletOpenResult", res);
+ }
+
+ // multiple requests from the same client
+ // should not produce multiple password
+ // dialogs on a failure
+ if (res < 0) {
+ TQPtrListIterator<KWalletTransaction> it(_transactions);
+ KWalletTransaction *x;
+ while ((x = it.current()) && x != xact) {
+ ++it;
+ }
+ if (x) {
+ ++it;
+ }
+ while ((x = it.current())) {
+ if (xact->appid == x->appid && x->tType == KWalletTransaction::Open && x->wallet == xact->wallet && x->wId == xact->wId) {
+ x->tType = KWalletTransaction::OpenFail;
+ }
+ ++it;
+ }
+ }
+ break;
+ case KWalletTransaction::OpenFail:
+ res = -1;
+ replyType = "int";
+ if (!xact->returnObject.isEmpty()) {
+ DCOPRef(xact->rawappid, xact->returnObject).send("walletOpenResult", res);
+ }
+ break;
+ case KWalletTransaction::ChangePassword:
+ doTransactionChangePassword(xact->appid, xact->wallet, xact->wId);
+ // fall through - no return
+ default:
+ _transactions.removeRef(xact);
+ continue;
+ }
+
+ if (xact->returnObject.isEmpty() && xact->tType != KWalletTransaction::ChangePassword) {
+ TQByteArray replyData;
+ TQDataStream stream(replyData, IO_WriteOnly);
+ stream << res;
+ xact->client->endTransaction(xact->transaction, replyType, replyData);
+ }
+ _transactions.removeRef(xact);
+ }
+
+ processing = false;
+}
+
+
+void KWalletD::openAsynchronous(const TQString& wallet, const TQCString& returnObject, uint wId) {
+ DCOPClient *dc = callingDcopClient();
+ if (!dc) {
+ return;
+ }
+
+ TQCString appid = dc->senderId();
+ if (!_enabled ||
+ !TQRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) {
+ DCOPRef(appid, returnObject).send("walletOpenResult", -1);
+ return;
+ }
+
+ TQCString peerName = friendlyDCOPPeerName();
+
+ KWalletTransaction *xact = new KWalletTransaction;
+
+ xact->appid = peerName;
+ xact->rawappid = appid;
+ xact->client = callingDcopClient();
+ xact->wallet = wallet;
+ xact->wId = wId;
+ xact->tType = KWalletTransaction::Open;
+ xact->returnObject = returnObject;
+ _transactions.append(xact);
+
+ DCOPRef(appid, returnObject).send("walletOpenResult", 0);
+
+ TQTimer::singleShot(0, this, TQT_SLOT(processTransactions()));
+ checkActiveDialog();
+}
+
+
+int KWalletD::openPath(const TQString& path, uint wId) {
+ if (!_enabled) { // guard
+ return -1;
+ }
+
+ // FIXME: setup transaction
+ int rc = internalOpen(friendlyDCOPPeerName(), path, true, wId);
+ return rc;
+}
+
+
+int KWalletD::open(const TQString& wallet, uint wId) {
+ if (!_enabled) { // guard
+ return -1;
+ }
+
+ if (!TQRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) {
+ return -1;
+ }
+
+ TQCString appid = friendlyDCOPPeerName();
+
+ KWalletTransaction *xact = new KWalletTransaction;
+ _transactions.append(xact);
+
+ xact->appid = appid;
+ xact->client = callingDcopClient();
+ xact->transaction = xact->client->beginTransaction();
+ xact->wallet = wallet;
+ xact->wId = wId;
+ xact->tType = KWalletTransaction::Open;
+ xact->modal = true; // mark dialogs as modal, the app has blocking wait
+ TQTimer::singleShot(0, this, TQT_SLOT(processTransactions()));
+ checkActiveDialog();
+ return 0; // process later
+}
+
+
+// Sets up a dialog that will be shown by tdewallet.
+void KWalletD::setupDialog( TQWidget* dialog, WId wId, const TQCString& appid, bool modal ) {
+ if( wId != 0 )
+ KWin::setMainWindow( dialog, wId ); // correct, set dialog parent
+ else {
+ if( appid.isEmpty())
+ kdWarning() << "Using tdewallet without parent window!" << endl;
+ else
+ kdWarning() << "Application '" << appid << "' using tdewallet without parent window!" << endl;
+ // allow dialog activation even if it interrupts, better than trying hacks
+ // with keeping the dialog on top or on all desktops
+ kapp->updateUserTimestamp();
+ }
+ if( modal )
+ KWin::setState( dialog->winId(), NET::Modal );
+ else
+ KWin::clearState( dialog->winId(), NET::Modal );
+ activeDialog = dialog;
+}
+
+// If there's a dialog already open and another application tries some operation that'd lead to
+// opening a dialog, that application will be blocked by this dialog. A proper solution would
+// be to set the second application's window also as a parent for the active dialog, so that
+// KWin properly handles focus changes and so on, but there's currently no support for multiple
+// dialog parents. Hopefully to be done in KDE4, for now just use all kinds of bad hacks to make
+// sure the user doesn't overlook the active dialog.
+void KWalletD::checkActiveDialog() {
+ if( !activeDialog || !activeDialog->isShown())
+ return;
+ kapp->updateUserTimestamp();
+ KWin::setState( activeDialog->winId(), NET::KeepAbove );
+ KWin::setOnAllDesktops( activeDialog->winId(), true );
+ KWin::forceActiveWindow( activeDialog->winId());
+}
+
+int KWalletD::doTransactionOpen(const TQCString& appid, const TQString& wallet, uint wId, bool modal) {
+ if (_firstUse && !wallets().contains(KWallet::Wallet::LocalWallet())) {
+ // First use wizard
+ KWalletWizard *wiz = new KWalletWizard(0);
+ setupDialog( wiz, wId, appid, modal );
+ int rc = wiz->exec();
+ if (rc == TQDialog::Accepted) {
+ TDEConfig cfg("tdewalletrc");
+ cfg.setGroup("Wallet");
+ cfg.writeEntry("First Use", false);
+ cfg.writeEntry("Enabled", wiz->_useWallet->isChecked());
+ cfg.writeEntry("Close When Idle", wiz->_closeIdle->isChecked());
+ cfg.writeEntry("Use One Wallet", !wiz->_networkWallet->isChecked());
+ cfg.sync();
+ reconfigure();
+
+ if (!wiz->_useWallet->isChecked()) {
+ delete wiz;
+ return -1;
+ }
+
+ // Create the wallet
+ KWallet::Backend *b = new KWallet::Backend(KWallet::Wallet::LocalWallet());
+ TQByteArray p;
+ p.duplicate(wiz->_pass1->text().utf8(), wiz->_pass1->text().length());
+ b->open(p);
+ b->createFolder(KWallet::Wallet::PasswordFolder());
+ b->createFolder(KWallet::Wallet::FormDataFolder());
+ b->close(p);
+ p.fill(0);
+ delete b;
+ delete wiz;
+ } else {
+ delete wiz;
+ return -1;
+ }
+ } else if (_firstUse) {
+ TDEConfig cfg("tdewalletrc");
+ _firstUse = false;
+ cfg.setGroup("Wallet");
+ cfg.writeEntry("First Use", false);
+ cfg.sync();
+ }
+
+ int rc = internalOpen(appid, wallet, false, wId, modal);
+ return rc;
+}
+
+int KWalletD::tryOpen(const TQString& wallet, const TQCString& password)
+{
+ if (isOpen(wallet))
+ return 0;
+
+ if (_tryOpenBlocked.isActive()) {
+ kdDebug() << "tryOpen is active.." << endl;
+ return -1;
+ }
+
+ if (!KWallet::Backend::exists(wallet))
+ return -2;
+
+ KWallet::Backend *b = new KWallet::Backend(wallet, false /*isPath*/);
+ int rc = b->open(TQByteArray().duplicate(password, strlen(password)));
+ if (rc == 0) {
+ _wallets.insert(rc = generateHandle(), b);
+ _passwords[wallet] = password;
+ b->ref();
+ _tryOpenBlocked.stop();
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << wallet;
+ emitDCOPSignal("walletOpened(TQString)", data);
+ }
+ else {
+ delete b;
+ // make sure that we're not bombed with a dictionary attack
+ _tryOpenBlocked.start (30 * 1000, true /*single shot*/);
+ if (++_failed > 5) {
+ _failed = 0;
+ TQTimer::singleShot(0, this, TQT_SLOT(notifyFailures()));
+ }
+
+ rc = -1;
+ }
+ return rc;
+}
+
+int KWalletD::internalOpen(const TQCString& appid, const TQString& wallet, bool isPath, WId w, bool modal) {
+ int rc = -1;
+ bool brandNew = false;
+
+ TQCString thisApp;
+ if (appid.isEmpty()) {
+ thisApp = "TDE System";
+ } else {
+ thisApp = appid;
+ }
+
+ if (implicitDeny(wallet, thisApp)) {
+ return -1;
+ }
+
+ for (TQIntDictIterator<KWallet::Backend> i(_wallets); i.current(); ++i) {
+ if (i.current()->walletName() == wallet) {
+ rc = i.currentKey();
+ break;
+ }
+ }
+
+ if (rc == -1) {
+ if (_wallets.count() > 20) {
+ kdDebug() << "Too many wallets open." << endl;
+ return -1;
+ }
+
+ KWallet::Backend *b = new KWallet::Backend(wallet, isPath);
+ KPasswordDialog *kpd = 0L;
+ bool emptyPass = false;
+ if ((isPath && TQFile::exists(wallet)) || (!isPath && KWallet::Backend::exists(wallet))) {
+ int pwless = b->open(TQByteArray());
+ if (0 != pwless || !b->isOpen()) {
+ if (pwless == 0) {
+ // release, start anew
+ delete b;
+ b = new KWallet::Backend(wallet, isPath);
+ }
+ kpd = new KPasswordDialog(KPasswordDialog::Password, false, 0);
+ if (appid.isEmpty()) {
+ kpd->setPrompt(i18n("<qt>TDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.").arg(TQStyleSheet::escape(wallet)));
+ } else {
+ kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the wallet '<b>%2</b>'. Please enter the password for this wallet below.").arg(TQStyleSheet::escape(appid)).arg(TQStyleSheet::escape(wallet)));
+ }
+ brandNew = false;
+ kpd->setButtonOK(KGuiItem(i18n("&Open"),"fileopen"));
+ } else {
+ emptyPass = true;
+ }
+ } else if (wallet == KWallet::Wallet::LocalWallet() ||
+ wallet == KWallet::Wallet::NetworkWallet()) {
+ // Auto create these wallets.
+ kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0);
+ if (appid.isEmpty()) {
+ kpd->setPrompt(i18n("TDE has requested to open the wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request."));
+ } else {
+ kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the TDE wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request.").arg(TQStyleSheet::escape(appid)));
+ }
+ brandNew = true;
+ kpd->setButtonOK(KGuiItem(i18n("&Open"),"fileopen"));
+ } else {
+ kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0);
+ if (appid.length() == 0) {
+ kpd->setPrompt(i18n("<qt>TDE has requested to create a new wallet named '<b>%1</b>'. Please choose a password for this wallet, or cancel to deny the application's request.").arg(TQStyleSheet::escape(wallet)));
+ } else {
+ kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to create a new wallet named '<b>%2</b>'. Please choose a password for this wallet, or cancel to deny the application's request.").arg(TQStyleSheet::escape(appid)).arg(TQStyleSheet::escape(wallet)));
+ }
+ brandNew = true;
+ kpd->setButtonOK(KGuiItem(i18n("C&reate"),"filenew"));
+ }
+
+ if (kpd) {
+ kpd->setCaption(i18n("TDE Wallet Service"));
+ kpd->setAllowEmptyPasswords(true);
+ }
+
+ const char *p = 0L;
+ while (!b->isOpen()) {
+ assert(kpd); // kpd can't be null if isOpen() is false
+ setupDialog( kpd, w, appid, modal );
+ if (kpd->exec() == KDialog::Accepted) {
+ p = kpd->password();
+ int rc = b->open(TQByteArray().duplicate(p, strlen(p)));
+ if (!b->isOpen()) {
+ kpd->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br>(Error code %2: %3)").arg(TQStyleSheet::escape(wallet)).arg(rc).arg(KWallet::Backend::openRCToString(rc)));
+ kpd->clearPassword();
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (!emptyPass && (!p || !b->isOpen())) {
+ delete b;
+ delete kpd;
+ return -1;
+ }
+
+ if (emptyPass && _openPrompt && !isAuthorizedApp(appid, wallet, w)) {
+ delete b;
+ delete kpd;
+ return -1;
+ }
+
+ _wallets.insert(rc = generateHandle(), b);
+ if (emptyPass) {
+ _passwords[wallet] = "";
+ } else {
+ _passwords[wallet] = p;
+ }
+ _handles[appid].append(rc);
+
+ delete kpd; // don't refactor this!! Argh I hate KPassDlg
+
+ if (brandNew) {
+ createFolder(rc, KWallet::Wallet::PasswordFolder());
+ createFolder(rc, KWallet::Wallet::FormDataFolder());
+ }
+
+ b->ref();
+ if (_closeIdle && _timeouts) {
+ _timeouts->addTimer(rc, _idleTime);
+ }
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << wallet;
+ if (brandNew) {
+ emitDCOPSignal("walletCreated(TQString)", data);
+ }
+ emitDCOPSignal("walletOpened(TQString)", data);
+ if (_wallets.count() == 1 && _launchManager) {
+ TDEApplication::startServiceByDesktopName("tdewalletmanager-tdewalletd");
+ }
+ } else {
+ if (!_handles[appid].contains(rc) && _openPrompt && !isAuthorizedApp(appid, wallet, w)) {
+ return -1;
+ }
+ _handles[appid].append(rc);
+ _wallets.find(rc)->ref();
+ }
+
+ return rc;
+}
+
+
+bool KWalletD::isAuthorizedApp(const TQCString& appid, const TQString& wallet, WId w) {
+ int response = 0;
+
+ TQCString thisApp;
+ if (appid.isEmpty()) {
+ thisApp = "TDE System";
+ } else {
+ thisApp = appid;
+ }
+
+ if (!implicitAllow(wallet, thisApp)) {
+ KBetterThanKDialogBase *dialog = new KBetterThanKDialogBase;
+ if (appid.isEmpty()) {
+ dialog->setLabel(i18n("<qt>TDE has requested access to the open wallet '<b>%1</b>'.").arg(TQStyleSheet::escape(wallet)));
+ } else {
+ dialog->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.").arg(TQStyleSheet::escape(TQString(appid))).arg(TQStyleSheet::escape(wallet)));
+ }
+ setupDialog( dialog, w, appid, false );
+ response = dialog->exec();
+ delete dialog;
+ }
+
+ if (response == 0 || response == 1) {
+ if (response == 1) {
+ TDEConfig cfg("tdewalletrc");
+ cfg.setGroup("Auto Allow");
+ TQStringList apps = cfg.readListEntry(wallet);
+ if (!apps.contains(thisApp)) {
+ apps += thisApp;
+ _implicitAllowMap[wallet] += thisApp;
+ cfg.writeEntry(wallet, apps);
+ cfg.sync();
+ }
+ }
+ } else if (response == 3) {
+ TDEConfig cfg("tdewalletrc");
+ cfg.setGroup("Auto Deny");
+ TQStringList apps = cfg.readListEntry(wallet);
+ if (!apps.contains(thisApp)) {
+ apps += thisApp;
+ _implicitDenyMap[wallet] += thisApp;
+ cfg.writeEntry(wallet, apps);
+ cfg.sync();
+ }
+ return false;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+
+int KWalletD::deleteWallet(const TQString& wallet) {
+ TQString path = TDEGlobal::dirs()->saveLocation("tdewallet") + TQDir::separator() + wallet + ".kwl";
+
+ if (TQFile::exists(path)) {
+ close(wallet, true);
+ TQFile::remove(path);
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << wallet;
+ emitDCOPSignal("walletDeleted(TQString)", data);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+void KWalletD::changePassword(const TQString& wallet, uint wId) {
+ TQCString appid = friendlyDCOPPeerName();
+
+ KWalletTransaction *xact = new KWalletTransaction;
+
+ xact->appid = appid;
+ xact->client = callingDcopClient();
+ xact->wallet = wallet;
+ xact->wId = wId;
+ xact->tType = KWalletTransaction::ChangePassword;
+
+ _transactions.append(xact);
+
+ TQTimer::singleShot(0, this, TQT_SLOT(processTransactions()));
+ checkActiveDialog();
+}
+
+
+void KWalletD::doTransactionChangePassword(const TQCString& appid, const TQString& wallet, uint wId) {
+ TQIntDictIterator<KWallet::Backend> it(_wallets);
+ KWallet::Backend *w = 0L;
+ int handle = -1;
+ bool reclose = false;
+
+ for (; it.current(); ++it) {
+ if (it.current()->walletName() == wallet) {
+ break;
+ }
+ }
+
+ if (!it.current()) {
+ handle = doTransactionOpen(appid, wallet, wId,false);
+ if (-1 == handle) {
+ KMessageBox::sorryWId(wId, i18n("Unable to open wallet. The wallet must be opened in order to change the password."), i18n("TDE Wallet Service"));
+ return;
+ }
+
+ w = _wallets.find(handle);
+ reclose = true;
+ } else {
+ handle = it.currentKey();
+ w = it.current();
+ }
+
+ assert(w);
+
+ KPasswordDialog *kpd;
+ kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0);
+ kpd->setPrompt(i18n("<qt>Please choose a new password for the wallet '<b>%1</b>'.").arg(TQStyleSheet::escape(wallet)));
+ kpd->setCaption(i18n("TDE Wallet Service"));
+ kpd->setAllowEmptyPasswords(true);
+ setupDialog( kpd, wId, appid, false );
+ if (kpd->exec() == KDialog::Accepted) {
+ const char *p = kpd->password();
+ if (p) {
+ _passwords[wallet] = p;
+ TQByteArray pa;
+ pa.duplicate(p, strlen(p));
+ int rc = w->close(pa);
+ if (rc < 0) {
+ KMessageBox::sorryWId(wId, i18n("Error re-encrypting the wallet. Password was not changed."), i18n("TDE Wallet Service"));
+ reclose = true;
+ } else {
+ rc = w->open(pa);
+ if (rc < 0) {
+ KMessageBox::sorryWId(wId, i18n("Error reopening the wallet. Data may be lost."), i18n("TDE Wallet Service"));
+ reclose = true;
+ }
+ }
+ }
+ }
+
+ delete kpd;
+
+ if (reclose) {
+ close(handle, true);
+ }
+}
+
+
+int KWalletD::close(const TQString& wallet, bool force) {
+ int handle = -1;
+ KWallet::Backend *w = 0L;
+
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets);
+ it.current();
+ ++it) {
+ if (it.current()->walletName() == wallet) {
+ handle = it.currentKey();
+ w = it.current();
+ break;
+ }
+ }
+
+ return closeWallet(w, handle, force);
+}
+
+
+int KWalletD::closeWallet(KWallet::Backend *w, int handle, bool force) {
+ if (w) {
+ const TQString& wallet = w->walletName();
+ assert(_passwords.contains(wallet));
+ if (w->refCount() == 0 || force) {
+ invalidateHandle(handle);
+ if (_closeIdle && _timeouts) {
+ _timeouts->removeTimer(handle);
+ }
+ _wallets.remove(handle);
+ if (_passwords.contains(wallet)) {
+ w->close(TQByteArray().duplicate(_passwords[wallet].data(), _passwords[wallet].length()));
+ _passwords[wallet].fill(0);
+ _passwords.remove(wallet);
+ }
+ doCloseSignals(handle, wallet);
+ delete w;
+ return 0;
+ }
+ return 1;
+ }
+
+ return -1;
+}
+
+
+int KWalletD::close(int handle, bool force) {
+ TQCString appid = friendlyDCOPPeerName();
+ KWallet::Backend *w = _wallets.find(handle);
+ bool contains = false;
+
+ if (w) { // the handle is valid
+ if (_handles.contains(appid)) { // we know this app
+ if (_handles[appid].contains(handle)) {
+ // the app owns this handle
+ _handles[appid].remove(_handles[appid].find(handle));
+ contains = true;
+ if (_handles[appid].isEmpty()) {
+ _handles.remove(appid);
+ }
+ }
+ }
+
+ // watch the side effect of the deref()
+ if ((contains && w->deref() == 0 && !_leaveOpen) || force) {
+ if (_closeIdle && _timeouts) {
+ _timeouts->removeTimer(handle);
+ }
+ _wallets.remove(handle);
+ if (force) {
+ invalidateHandle(handle);
+ }
+ if (_passwords.contains(w->walletName())) {
+ w->close(TQByteArray().duplicate(_passwords[w->walletName()].data(), _passwords[w->walletName()].length()));
+ _passwords[w->walletName()].fill(0);
+ _passwords.remove(w->walletName());
+ }
+ doCloseSignals(handle, w->walletName());
+ delete w;
+ return 0;
+ }
+ return 1; // not closed
+ }
+
+ return -1; // not open to begin with, or other error
+}
+
+
+bool KWalletD::isOpen(const TQString& wallet) const {
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets);
+ it.current();
+ ++it) {
+ if (it.current()->walletName() == wallet) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool KWalletD::isOpen(int handle) {
+ if (handle == 0) {
+ return false;
+ }
+
+ KWallet::Backend *rc = _wallets.find(handle);
+
+ if (rc == 0 && ++_failed > 5) {
+ _failed = 0;
+ TQTimer::singleShot(0, this, TQT_SLOT(notifyFailures()));
+ } else if (rc != 0) {
+ _failed = 0;
+ }
+
+ return rc != 0;
+}
+
+
+TQStringList KWalletD::wallets() const {
+ TQString path = TDEGlobal::dirs()->saveLocation("tdewallet");
+ TQDir dir(path, "*.kwl");
+ TQStringList rc;
+
+ dir.setFilter(TQDir::Files | TQDir::NoSymLinks);
+
+ const TQFileInfoList *list = dir.entryInfoList();
+ TQFileInfoListIterator it(*list);
+ TQFileInfo *fi;
+ while ((fi = it.current()) != 0L) {
+ TQString fn = fi->fileName();
+ if (fn.endsWith(".kwl")) {
+ fn.truncate(fn.length()-4);
+ }
+ rc += fn;
+ ++it;
+ }
+ return rc;
+}
+
+
+void KWalletD::sync(int handle) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ }
+}
+
+
+TQStringList KWalletD::folderList(int handle) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ return b->folderList();
+ }
+
+ return TQStringList();
+}
+
+
+bool KWalletD::hasFolder(int handle, const TQString& f) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ return b->hasFolder(f);
+ }
+
+ return false;
+}
+
+
+bool KWalletD::removeFolder(int handle, const TQString& f) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ bool rc = b->removeFolder(f);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << b->walletName();
+ emitDCOPSignal("folderListUpdated(TQString)", data);
+ return rc;
+ }
+
+ return false;
+}
+
+
+bool KWalletD::createFolder(int handle, const TQString& f) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ bool rc = b->createFolder(f);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << b->walletName();
+ emitDCOPSignal("folderListUpdated(TQString)", data);
+ return rc;
+ }
+
+ return false;
+}
+
+
+TQByteArray KWalletD::readMap(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry *e = b->readEntry(key);
+ if (e && e->type() == KWallet::Wallet::Map) {
+ return e->map();
+ }
+ }
+
+ return TQByteArray();
+}
+
+
+TQMap<TQString,TQByteArray> KWalletD::readMapList(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ TQPtrList<KWallet::Entry> e = b->readEntryList(key);
+ TQMap<TQString, TQByteArray> rc;
+ TQPtrListIterator<KWallet::Entry> it(e);
+ KWallet::Entry *entry;
+ while ((entry = it.current())) {
+ if (entry->type() == KWallet::Wallet::Map) {
+ rc.insert(entry->key(), entry->map());
+ }
+ ++it;
+ }
+ return rc;
+ }
+
+ return TQMap<TQString, TQByteArray>();
+}
+
+
+TQByteArray KWalletD::readEntry(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry *e = b->readEntry(key);
+ if (e) {
+ return e->value();
+ }
+ }
+
+ return TQByteArray();
+}
+
+
+TQMap<TQString, TQByteArray> KWalletD::readEntryList(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ TQPtrList<KWallet::Entry> e = b->readEntryList(key);
+ TQMap<TQString, TQByteArray> rc;
+ TQPtrListIterator<KWallet::Entry> it(e);
+ KWallet::Entry *entry;
+ while ((entry = it.current())) {
+ rc.insert(entry->key(), entry->value());
+ ++it;
+ }
+ return rc;
+ }
+
+ return TQMap<TQString, TQByteArray>();
+}
+
+
+TQStringList KWalletD::entryList(int handle, const TQString& folder) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ return b->entryList();
+ }
+
+ return TQStringList();
+}
+
+
+TQString KWalletD::readPassword(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry *e = b->readEntry(key);
+ if (e && e->type() == KWallet::Wallet::Password) {
+ return e->password();
+ }
+ }
+
+ return TQString::null;
+}
+
+
+TQMap<TQString, TQString> KWalletD::readPasswordList(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ TQPtrList<KWallet::Entry> e = b->readEntryList(key);
+ TQMap<TQString, TQString> rc;
+ TQPtrListIterator<KWallet::Entry> it(e);
+ KWallet::Entry *entry;
+ while ((entry = it.current())) {
+ if (entry->type() == KWallet::Wallet::Password) {
+ rc.insert(entry->key(), entry->password());
+ }
+ ++it;
+ }
+ return rc;
+ }
+
+ return TQMap<TQString, TQString>();
+}
+
+
+int KWalletD::writeMap(int handle, const TQString& folder, const TQString& key, const TQByteArray& value) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry e;
+ e.setKey(key);
+ e.setValue(value);
+ e.setType(KWallet::Wallet::Map);
+ b->writeEntry(&e);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int KWalletD::writeEntry(int handle, const TQString& folder, const TQString& key, const TQByteArray& value, int entryType) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry e;
+ e.setKey(key);
+ e.setValue(value);
+ e.setType(KWallet::Wallet::EntryType(entryType));
+ b->writeEntry(&e);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int KWalletD::writeEntry(int handle, const TQString& folder, const TQString& key, const TQByteArray& value) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry e;
+ e.setKey(key);
+ e.setValue(value);
+ e.setType(KWallet::Wallet::Stream);
+ b->writeEntry(&e);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int KWalletD::writePassword(int handle, const TQString& folder, const TQString& key, const TQString& value) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ KWallet::Entry e;
+ e.setKey(key);
+ e.setValue(value);
+ e.setType(KWallet::Wallet::Password);
+ b->writeEntry(&e);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int KWalletD::entryType(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ if (!b->hasFolder(folder)) {
+ return KWallet::Wallet::Unknown;
+ }
+ b->setFolder(folder);
+ if (b->hasEntry(key)) {
+ return b->readEntry(key)->type();
+ }
+ }
+
+ return KWallet::Wallet::Unknown;
+}
+
+
+bool KWalletD::hasEntry(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ if (!b->hasFolder(folder)) {
+ return false;
+ }
+ b->setFolder(folder);
+ return b->hasEntry(key);
+ }
+
+ return false;
+}
+
+
+int KWalletD::removeEntry(int handle, const TQString& folder, const TQString& key) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ if (!b->hasFolder(folder)) {
+ return 0;
+ }
+ b->setFolder(folder);
+ bool rc = b->removeEntry(key);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return rc ? 0 : -3;
+ }
+
+ return -1;
+}
+
+
+void KWalletD::slotAppUnregistered(const TQCString& app) {
+ if (_handles.contains(app)) {
+ TQValueList<int> l = _handles[app];
+ for (TQValueList<int>::Iterator i = l.begin(); i != l.end(); ++i) {
+ _handles[app].remove(*i);
+ KWallet::Backend *w = _wallets.find(*i);
+ if (w && !_leaveOpen && 0 == w->deref()) {
+ close(w->walletName(), true);
+ }
+ }
+ _handles.remove(app);
+ }
+}
+
+
+void KWalletD::invalidateHandle(int handle) {
+ for (TQMap<TQCString,TQValueList<int> >::Iterator i = _handles.begin();
+ i != _handles.end();
+ ++i) {
+ i.data().remove(handle);
+ }
+}
+
+
+KWallet::Backend *KWalletD::getWallet(const TQCString& appid, int handle) {
+ if (handle == 0) {
+ return 0L;
+ }
+
+ KWallet::Backend *w = _wallets.find(handle);
+
+ if (w) { // the handle is valid
+ if (_handles.contains(appid)) { // we know this app
+ if (_handles[appid].contains(handle)) {
+ // the app owns this handle
+ _failed = 0;
+ if (_closeIdle && _timeouts) {
+ _timeouts->resetTimer(handle, _idleTime);
+ }
+ return w;
+ }
+ }
+ }
+
+ if (++_failed > 5) {
+ _failed = 0;
+ TQTimer::singleShot(0, this, TQT_SLOT(notifyFailures()));
+ }
+
+ return 0L;
+}
+
+
+void KWalletD::notifyFailures() {
+ if (!_showingFailureNotify) {
+ _showingFailureNotify = true;
+ KMessageBox::information(0, i18n("There have been repeated failed attempts to gain access to a wallet. An application may be misbehaving."), i18n("TDE Wallet Service"));
+ _showingFailureNotify = false;
+ }
+}
+
+
+void KWalletD::doCloseSignals(int handle, const TQString& wallet) {
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << handle;
+ emitDCOPSignal("walletClosed(int)", data);
+
+ TQByteArray data2;
+ TQDataStream ds2(data2, IO_WriteOnly);
+ ds2 << wallet;
+ emitDCOPSignal("walletClosed(TQString)", data2);
+
+ if (_wallets.isEmpty()) {
+ emitDCOPSignal("allWalletsClosed()", TQByteArray());
+ }
+}
+
+
+int KWalletD::renameEntry(int handle, const TQString& folder, const TQString& oldName, const TQString& newName) {
+ KWallet::Backend *b;
+
+ if ((b = getWallet(friendlyDCOPPeerName(), handle))) {
+ b->setFolder(folder);
+ int rc = b->renameEntry(oldName, newName);
+ // write changes to disk immediately
+ TQByteArray p;
+ TQString wallet = b->walletName();
+ p.duplicate(_passwords[wallet].data(), _passwords[wallet].length());
+ b->sync(p);
+ p.fill(0);
+ emitFolderUpdated(b->walletName(), folder);
+ return rc;
+ }
+
+ return -1;
+}
+
+
+TQStringList KWalletD::users(const TQString& wallet) const {
+ TQStringList rc;
+
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets);
+ it.current();
+ ++it) {
+ if (it.current()->walletName() == wallet) {
+ for (TQMap<TQCString,TQValueList<int> >::ConstIterator hit = _handles.begin(); hit != _handles.end(); ++hit) {
+ if (hit.data().contains(it.currentKey())) {
+ rc += hit.key();
+ }
+ }
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+bool KWalletD::disconnectApplication(const TQString& wallet, const TQCString& application) {
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets);
+ it.current();
+ ++it) {
+ if (it.current()->walletName() == wallet) {
+ if (_handles[application].contains(it.currentKey())) {
+ _handles[application].remove(it.currentKey());
+
+ if (_handles[application].isEmpty()) {
+ _handles.remove(application);
+ }
+
+ if (it.current()->deref() == 0) {
+ close(it.current()->walletName(), true);
+ }
+
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << wallet;
+ ds << application;
+ emitDCOPSignal("applicationDisconnected(TQString,TQCString)", data);
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+void KWalletD::emitFolderUpdated(const TQString& wallet, const TQString& folder) {
+ TQByteArray data;
+ TQDataStream ds(data, IO_WriteOnly);
+ ds << wallet;
+ ds << folder;
+ emitDCOPSignal("folderUpdated(TQString,TQString)", data);
+}
+
+
+void KWalletD::emitWalletListDirty() {
+ emitDCOPSignal("walletListDirty()", TQByteArray());
+}
+
+
+void KWalletD::reconfigure() {
+ TDEConfig cfg("tdewalletrc");
+ cfg.setGroup("Wallet");
+ _firstUse = cfg.readBoolEntry("First Use", true);
+ _enabled = cfg.readBoolEntry("Enabled", true);
+ _launchManager = cfg.readBoolEntry("Launch Manager", true);
+ _leaveOpen = cfg.readBoolEntry("Leave Open", false);
+ bool idleSave = _closeIdle;
+ _closeIdle = cfg.readBoolEntry("Close When Idle", false);
+ _openPrompt = cfg.readBoolEntry("Prompt on Open", true);
+ int timeSave = _idleTime;
+ // in minutes!
+ _idleTime = cfg.readNumEntry("Idle Timeout", 10) * 60 * 1000;
+
+ if (cfg.readBoolEntry("Close on Screensaver", false)) {
+ connectDCOPSignal("kdesktop", "KScreensaverIface", "KDE_start_screensaver()", "closeAllWallets()", false);
+ } else {
+ disconnectDCOPSignal("kdesktop", "KScreensaverIface", "KDE_start_screensaver()", "closeAllWallets()");
+ }
+
+ // Handle idle changes
+ if (_closeIdle) {
+ if (_idleTime != timeSave) { // Timer length changed
+ TQIntDictIterator<KWallet::Backend> it(_wallets);
+ for (; it.current(); ++it) {
+ _timeouts->resetTimer(it.currentKey(), _idleTime);
+ }
+ }
+
+ if (!idleSave) { // add timers for all the wallets
+ TQIntDictIterator<KWallet::Backend> it(_wallets);
+ for (; it.current(); ++it) {
+ _timeouts->addTimer(it.currentKey(), _idleTime);
+ }
+ }
+ } else {
+ _timeouts->clear();
+ }
+
+ // Update the implicit allow stuff
+ _implicitAllowMap.clear();
+ cfg.setGroup("Auto Allow");
+ TQStringList entries = cfg.entryMap("Auto Allow").keys();
+ for (TQStringList::Iterator i = entries.begin(); i != entries.end(); ++i) {
+ _implicitAllowMap[*i] = cfg.readListEntry(*i);
+ }
+
+ // Update the implicit allow stuff
+ _implicitDenyMap.clear();
+ cfg.setGroup("Auto Deny");
+ entries = cfg.entryMap("Auto Deny").keys();
+ for (TQStringList::Iterator i = entries.begin(); i != entries.end(); ++i) {
+ _implicitDenyMap[*i] = cfg.readListEntry(*i);
+ }
+
+ // Update if wallet was enabled/disabled
+ if (!_enabled) { // close all wallets
+ while (!_wallets.isEmpty()) {
+ TQIntDictIterator<KWallet::Backend> it(_wallets);
+ if (!it.current()) { // necessary?
+ break;
+ }
+ closeWallet(it.current(), it.currentKey(), true);
+ }
+ }
+}
+
+
+bool KWalletD::isEnabled() const {
+ return _enabled;
+}
+
+
+bool KWalletD::folderDoesNotExist(const TQString& wallet, const TQString& folder) {
+ if (!wallets().contains(wallet)) {
+ return true;
+ }
+
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets); it.current(); ++it) {
+ if (it.current()->walletName() == wallet) {
+ return it.current()->folderDoesNotExist(folder);
+ }
+ }
+
+ KWallet::Backend *b = new KWallet::Backend(wallet);
+ b->open(TQByteArray());
+ bool rc = b->folderDoesNotExist(folder);
+ delete b;
+ return rc;
+}
+
+
+bool KWalletD::keyDoesNotExist(const TQString& wallet, const TQString& folder, const TQString& key) {
+ if (!wallets().contains(wallet)) {
+ return true;
+ }
+
+ for (TQIntDictIterator<KWallet::Backend> it(_wallets); it.current(); ++it) {
+ if (it.current()->walletName() == wallet) {
+ return it.current()->entryDoesNotExist(folder, key);
+ }
+ }
+
+ KWallet::Backend *b = new KWallet::Backend(wallet);
+ b->open(TQByteArray());
+ bool rc = b->entryDoesNotExist(folder, key);
+ delete b;
+ return rc;
+}
+
+
+bool KWalletD::implicitAllow(const TQString& wallet, const TQCString& app) {
+ return _implicitAllowMap[wallet].contains(TQString::fromLocal8Bit(app));
+}
+
+
+bool KWalletD::implicitDeny(const TQString& wallet, const TQCString& app) {
+ return _implicitDenyMap[wallet].contains(TQString::fromLocal8Bit(app));
+}
+
+
+TQCString KWalletD::friendlyDCOPPeerName() {
+ DCOPClient *dc = callingDcopClient();
+ if (!dc) {
+ return "";
+ }
+ return dc->senderId().replace(TQRegExp("-[0-9]+$"), "");
+}
+
+
+void KWalletD::timedOut(int id) {
+ KWallet::Backend *w = _wallets.find(id);
+ if (w) {
+ closeWallet(w, id, true);
+ }
+}
+
+
+void KWalletD::closeAllWallets() {
+ TQIntDict<KWallet::Backend> tw = _wallets;
+
+ for (TQIntDictIterator<KWallet::Backend> it(tw); it.current(); ++it) {
+ closeWallet(it.current(), it.currentKey(), true);
+ }
+
+ tw.clear();
+
+ // All of this should be basically noop. Let's just be safe.
+ _wallets.clear();
+
+ for (TQMap<TQString,TQCString>::Iterator it = _passwords.begin();
+ it != _passwords.end();
+ ++it) {
+ it.data().fill(0);
+ }
+ _passwords.clear();
+}
+
+
+TQString KWalletD::networkWallet() {
+ return KWallet::Wallet::NetworkWallet();
+}
+
+
+TQString KWalletD::localWallet() {
+ return KWallet::Wallet::LocalWallet();
+}
+
+
+#include "tdewalletd.moc"
diff --git a/tdeio/misc/tdewalletd/tdewalletd.desktop b/tdeio/misc/tdewalletd/tdewalletd.desktop
new file mode 100644
index 000000000..1e65fe0df
--- /dev/null
+++ b/tdeio/misc/tdewalletd/tdewalletd.desktop
@@ -0,0 +1,151 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KDEDModule
+X-TDE-ModuleType=Library
+X-TDE-Library=tdewalletd
+X-TDE-FactoryName=tdewalletd
+X-TDE-Kded-autoload=false
+X-TDE-Kded-load-on-demand=true
+Name=KWallet Daemon Module
+Name[af]=KBeursie Bediener Module
+Name[ar]=مراقب وحدة KWallet
+Name[az]=KWallet Demon Modulu
+Name[be]=Модуль ÑервіÑа KWallet
+Name[bg]=Демон Портфейл
+Name[bn]=কে-ওয়ালেট ডিমন মডিউল
+Name[br]=Mollad an diaoul KWallet
+Name[ca]=Mòdul del dimoni KWallet
+Name[cs]=Modul démona KWallet
+Name[csb]=Pòrtfel
+Name[cy]=Modiwl Daemon KWaled
+Name[da]=KWallet Dæmonmodul
+Name[de]=Digitale Brieftasche
+Name[el]=ΆÏθÏωμα δαίμονα KWallet
+Name[eo]=Sekreteja demono-modulo
+Name[es]=Módulo de demonio KWallet
+Name[et]=KWalleti deemoni moodul
+Name[eu]=KWallet daemon modulua
+Name[fa]=پیمانه شبح KWallet
+Name[fi]=KWallet-palvelinmoduuli
+Name[fr]=Module démon KWallet
+Name[ga]=Modúl Deamhain KWallet
+Name[gl]=Módulo do Demo KWallet
+Name[he]=מודול תהליך הרקע של KWallet
+Name[hi]=केवैलट डेमन मॉडà¥à¤¯à¥‚ल
+Name[hr]=Modul KWallet demona
+Name[hu]=KWallet szolgáltatás
+Name[id]=Modul Daemon KWallet
+Name[is]=KWallet þjónseining
+Name[it]=Modulo demone KWallet
+Name[ja]=KWallet デーモンモジュール
+Name[ka]=KWallet გუშáƒáƒ’ის მáƒáƒ“ული
+Name[kk]=KWallet әмиÑн қызметтің модулі
+Name[km]=ម៉ូឌុល Daemon KWallet
+Name[ko]=K지갑 ë°ëª¬ 모듈
+Name[lb]=KWallet-Dämonmodul
+Name[lt]=TDE slaptažodinių tarnybos modulis
+Name[lv]=KWallet DÄ“mona Modulis
+Name[mn]=KWallet Daemon Модул
+Name[ms]=Modul Daemon KWallet
+Name[nb]=KWallet nisseprogramtillegg
+Name[nds]=KWallet-Dämoon
+Name[ne]=KWallet डेइमन मोडà¥à¤¯à¥à¤²
+Name[nl]=KWallet daemon-module
+Name[nn]=KWallet-nissemodul
+Name[pa]=KWallet ਪੇਸ਼ਕਾਰੀ ਮੈਡੀਊਲ
+Name[pl]=Portfel
+Name[pt]=Módulo do Servidor do KWallet
+Name[pt_BR]=Módulo do Serviço do KWallet
+Name[ro]=Modul demon KWallet
+Name[ru]=Служба бумажника
+Name[rw]=Igice Dayimoni KUruhago
+Name[se]=KWallet-bálvámoduvla
+Name[sk]=Modul démona KWallet
+Name[sl]=Modul demona KListnica
+Name[sq]=Demoni për Modulin KWallet
+Name[sr]=KWallet демон модул
+Name[sr@Latn]=KWallet demon modul
+Name[sv]=Kwallet-demonmodul
+Name[ta]=KWallet டெமான௠பகà¯à®¤à®¿
+Name[te]=కెవాలెటౠసూతà±à°°à°§à°¾à°°à°¿ మాడà±à°¯à±‚à°²à±
+Name[tg]=Модули Демон KWallet
+Name[th]=โมดูลเดมอน KWallet
+Name[tr]=KWallet Program Modülü
+Name[tt]=KWallet Xezmäteneñ Modulı
+Name[uk]=Модуль демону KWallet
+Name[uz]=KWallet xizmatining moduli
+Name[uz@cyrillic]=KWallet хизматининг модули
+Name[vi]=Mô-Ä‘un trình ná»n KWallet
+Name[zh_CN]=KWallet 守护进程模å—
+Name[zh_HK]=KWAllet 伺æœç¨‹å¼æ¨¡çµ„
+Name[zh_TW]=KWAllet æœå‹™ç¨‹å¼æ¨¡çµ„
+Comment=KWallet daemon module for KDED
+Comment[af]=KBeursie bediener module vir KDED
+Comment[be]=Модуль ÑервіÑа KWallet Ð´Ð»Ñ KDED
+Comment[bg]=Модул демон за ÑиÑтемата Портфейл за KDED
+Comment[bn]=KDED-র জনà§à¦¯ কে-ওয়ালেট ডিমন মডিউল
+Comment[br]=Mollad an diaoul KWallet evit KDED
+Comment[bs]=KWallet daemon modul za KDED
+Comment[ca]=Mòdul del dimoni KWallet per a KDED
+Comment[cs]=Modul démona KWallet pro KDED
+Comment[csb]=Mòduł KWallet w KDED
+Comment[da]=KWallet Dæmonmodul for KDED
+Comment[de]=Unterstützung für die digitale Brieftasche "KWallet"
+Comment[el]=ΆÏθÏωμα δαίμονα KWallet για το KDED
+Comment[eo]=Sekreteja demono-modulo por KDED
+Comment[es]=Módulo de demonio KWallet para KDED
+Comment[et]=KDED KWalleti deemoni moodul
+Comment[eu]=KWallet daemon modulua KDEDrako
+Comment[fa]=پیمانۀ شبح KWallet برای KDED
+Comment[fi]=KWallet palvelinmoduuli KDED:lle
+Comment[fr]=Module démon KWallet pour KDED
+Comment[fy]=KWallet daemon module foar KDED
+Comment[ga]=Modúl deamhain KWallet le haghaidh KDED
+Comment[gl]=Demo de KWallet para KDED
+Comment[he]=מודול תהליך רקע של KWallet עבור KDED
+Comment[hi]=केडीईडी के लिठके-वॉलेट डेमन मॉडà¥à¤¯à¥‚ल
+Comment[hr]=KWallet demon modul za KDED
+Comment[hu]=KWallet szolgáltatásmodul a KDED-hez
+Comment[id]=Modul daemon KWallet untuk KDED
+Comment[is]=KWallet þjónseining fyrir KDED
+Comment[it]=Modulo demone KWallet per KDED
+Comment[ja]=KDED 用㮠KWallet デーモンモジュール
+Comment[ka]=KSSL მáƒáƒ“ული TDE-სთვის
+Comment[kk]=TDE KWallet әмиÑнін баÑқару қызметтің модулі
+Comment[km]=ម៉ូឌុល daemon KWallet សម្រាប់ KDED
+Comment[lb]=KWallet-Dämonmodul fir KDED
+Comment[lt]=TDE slaptažodinių tarnybos modulis skirtas KDED
+Comment[lv]=KWallet Dēmona Modulis priekš KDED
+Comment[mk]=KWallet даемон модул за KDED
+Comment[ms]=Modul Daemon KWallet untuk KDED
+Comment[nb]=KWallet nissemodul for KDED
+Comment[nds]=KWallet-Dämoonmoduul för KDED
+Comment[ne]=KDED का लागि डेइमन मोडà¥à¤¯à¥à¤² KWallet
+Comment[nl]=KWallet daemon-module voor KDED
+Comment[nn]=KWallet-nissemodul for KDED
+Comment[pa]=KDED ਲਈ KWallet ਪੇਸ਼ਕਾਰੀ ਮੈਡੀਊਲ
+Comment[pl]=Moduł KWallet w KDED
+Comment[pt]=Módulo servidor do KWallet para o KDED
+Comment[pt_BR]=Módulo do serviço de carteira para o TDE
+Comment[ro]=Modul demon KWallet pentru KDED
+Comment[ru]=Управление бумажником TDE
+Comment[rw]=Igice cya dayimoni KUruhago cya KDED
+Comment[se]=KDED:a KWallet-bálvámoduvla
+Comment[sk]=Modul démona KWallet pre KDED
+Comment[sl]=Modul demona KListnica za KDED
+Comment[sr]=KWallet демон модул за KDED
+Comment[sr@Latn]=KWallet demon modul za KDED
+Comment[sv]=Kwallet-demonmodul för KDED
+Comment[ta]=KDEDகà¯à®•à®¾à®© KWallet Daemon தொகà¯à®¤à®¿
+Comment[te]=కెడిఈడి కొరకౠకెవాలెటౠసూతà±à°°à°§à°¾à°°à°¿ మాడà±à°¯à±‚à°²à±
+Comment[tg]=Модули Демон KWallet барои KDED
+Comment[th]=โมดูลเดมอน KWallet สำหรับ KDED
+Comment[tr]=KDED için KWallet program modülü
+Comment[tt]=KDED öçen KWallet xezmäteneñ modulı
+Comment[uk]=Модуль демону торбинок KWallet Ð´Ð»Ñ KDED
+Comment[uz]=KDED uchun KWallet xizmatining moduli
+Comment[uz@cyrillic]=KDED учун KWallet хизматининг модули
+Comment[vi]=Mô-Ä‘un trình ná»n KWallet cho KDED.
+Comment[zh_CN]=KDED çš„ KWallet 守护进程模å—
+Comment[zh_HK]=KDED çš„ KWallet 伺æœç¨‹å¼æ¨¡çµ„
+Comment[zh_TW]=KDED çš„ KWallet æœå‹™ç¨‹å¼æ¨¡çµ„
diff --git a/tdeio/misc/tdewalletd/tdewalletd.h b/tdeio/misc/tdewalletd/tdewalletd.h
new file mode 100644
index 000000000..b3a315413
--- /dev/null
+++ b/tdeio/misc/tdewalletd/tdewalletd.h
@@ -0,0 +1,199 @@
+/*
+ This file is part of the KDE libraries
+
+ Copyright (c) 2002-2004 George Staikos <staikos@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 _KWALLETD_H_
+#define _KWALLETD_H_
+
+#include <kded/kdedmodule.h>
+#include <tqintdict.h>
+#include <tqstring.h>
+#include <tqwidget.h>
+#include <tqtimer.h>
+#include <tqguardedptr.h>
+#include "tdewalletbackend.h"
+
+#include <time.h>
+#include <stdlib.h>
+
+class KDirWatch;
+class KTimeout;
+
+// @Private
+class KWalletTransaction;
+
+class KWalletD : public KDEDModule {
+ Q_OBJECT
+ K_DCOP
+ public:
+ KWalletD(const TQCString &name);
+ virtual ~KWalletD();
+
+ k_dcop:
+ // Is the wallet enabled? If not, all open() calls fail.
+ virtual bool isEnabled() const;
+
+ // Open and unlock the wallet
+ virtual int open(const TQString& wallet, uint wId);
+ // Open and unlock the wallet
+ virtual int tryOpen(const TQString& wallet, const TQCString& passwd);
+ // Open and unlock the wallet with this path
+
+ virtual int openPath(const TQString& path, uint wId);
+
+ // Asynchronous open - must give the object to return the handle
+ // to.
+ virtual void openAsynchronous(const TQString& wallet, const TQCString& returnObject, uint wId);
+
+ // Close and lock the wallet
+ // If force = true, will close it for all users. Behave. This
+ // can break applications, and is generally intended for use by
+ // the wallet manager app only.
+ virtual int close(const TQString& wallet, bool force);
+ virtual int close(int handle, bool force);
+
+ // Save to disk but leave open
+ virtual ASYNC sync(int handle);
+
+ // Physically deletes the wallet from disk.
+ virtual int deleteWallet(const TQString& wallet);
+
+ // Returns true if the wallet is open
+ virtual bool isOpen(const TQString& wallet) const;
+ virtual bool isOpen(int handle);
+
+ // List the users of this wallet
+ virtual TQStringList users(const TQString& wallet) const;
+
+ // Change the password of this wallet
+ virtual void changePassword(const TQString& wallet, uint wId);
+
+ // A list of all wallets
+ virtual TQStringList wallets() const;
+
+ // A list of all folders in this wallet
+ virtual TQStringList folderList(int handle);
+
+ // Does this wallet have this folder?
+ virtual bool hasFolder(int handle, const TQString& folder);
+
+ // Create this folder
+ virtual bool createFolder(int handle, const TQString& folder);
+
+ // Remove this folder
+ virtual bool removeFolder(int handle, const TQString& folder);
+
+ // List of entries in this folder
+ virtual TQStringList entryList(int handle, const TQString& folder);
+
+ // Read an entry. If the entry does not exist, it just
+ // returns an empty result. It is your responsibility to check
+ // hasEntry() first.
+ virtual TQByteArray readEntry(int handle, const TQString& folder, const TQString& key);
+ virtual TQByteArray readMap(int handle, const TQString& folder, const TQString& key);
+ virtual TQString readPassword(int handle, const TQString& folder, const TQString& key);
+ virtual TQMap<TQString, TQByteArray> readEntryList(int handle, const TQString& folder, const TQString& key);
+ virtual TQMap<TQString, TQByteArray> readMapList(int handle, const TQString& folder, const TQString& key);
+ virtual TQMap<TQString, TQString> readPasswordList(int handle, const TQString& folder, const TQString& key);
+
+ // Rename an entry. rc=0 on success.
+ virtual int renameEntry(int handle, const TQString& folder, const TQString& oldName, const TQString& newName);
+
+ // Write an entry. rc=0 on success.
+ virtual int writeEntry(int handle, const TQString& folder, const TQString& key, const TQByteArray& value, int entryType);
+ virtual int writeEntry(int handle, const TQString& folder, const TQString& key, const TQByteArray& value);
+ virtual int writeMap(int handle, const TQString& folder, const TQString& key, const TQByteArray& value);
+ virtual int writePassword(int handle, const TQString& folder, const TQString& key, const TQString& value);
+
+ // Does the entry exist?
+ virtual bool hasEntry(int handle, const TQString& folder, const TQString& key);
+
+ // What type is the entry?
+ virtual int entryType(int handle, const TQString& folder, const TQString& key);
+
+ // Remove an entry. rc=0 on success.
+ virtual int removeEntry(int handle, const TQString& folder, const TQString& key);
+
+ // Disconnect an app from a wallet
+ virtual bool disconnectApplication(const TQString& wallet, const TQCString& application);
+
+ virtual void reconfigure();
+
+ // Determine
+ virtual bool folderDoesNotExist(const TQString& wallet, const TQString& folder);
+ virtual bool keyDoesNotExist(const TQString& wallet, const TQString& folder, const TQString& key);
+
+ virtual void closeAllWallets();
+
+ virtual TQString networkWallet();
+
+ virtual TQString localWallet();
+
+ private slots:
+ void slotAppUnregistered(const TQCString& app);
+ void emitWalletListDirty();
+ void timedOut(int);
+ void notifyFailures();
+ void processTransactions();
+
+ private:
+ int internalOpen(const TQCString& appid, const TQString& wallet, bool isPath = false, WId w = 0, bool modal = false);
+ bool isAuthorizedApp(const TQCString& appid, const TQString& wallet, WId w);
+ // This also validates the handle. May return NULL.
+ KWallet::Backend* getWallet(const TQCString& appid, int handle);
+ // Generate a new unique handle.
+ int generateHandle();
+ // Invalidate a handle (remove it from the TQMap)
+ void invalidateHandle(int handle);
+ // Emit signals about closing wallets
+ void doCloseSignals(int,const TQString&);
+ void emitFolderUpdated(const TQString&, const TQString&);
+ // Internal - close this wallet.
+ int closeWallet(KWallet::Backend *w, int handle, bool force);
+ // Implicitly allow access for this application
+ bool implicitAllow(const TQString& wallet, const TQCString& app);
+ bool implicitDeny(const TQString& wallet, const TQCString& app);
+ TQCString friendlyDCOPPeerName();
+
+ void doTransactionChangePassword(const TQCString& appid, const TQString& wallet, uint wId);
+ int doTransactionOpen(const TQCString& appid, const TQString& wallet, uint wId, bool modal);
+
+ void setupDialog( TQWidget* dialog, WId wId, const TQCString& appid, bool modal );
+ void checkActiveDialog();
+
+ TQIntDict<KWallet::Backend> _wallets;
+ TQMap<TQCString,TQValueList<int> > _handles;
+ TQMap<TQString,TQCString> _passwords;
+ KDirWatch *_dw;
+ int _failed;
+
+ bool _leaveOpen, _closeIdle, _launchManager, _enabled;
+ bool _openPrompt, _firstUse, _showingFailureNotify;
+ int _idleTime;
+ TQMap<TQString,TQStringList> _implicitAllowMap, _implicitDenyMap;
+ KTimeout *_timeouts;
+ TQTimer _tryOpenBlocked;
+
+ TQPtrList<KWalletTransaction> _transactions;
+ TQGuardedPtr< TQWidget > activeDialog;
+};
+
+
+#endif
diff --git a/tdeio/misc/tdewalletd/tdewalletwizard.ui b/tdeio/misc/tdewalletd/tdewalletwizard.ui
new file mode 100644
index 000000000..aa3a1c09d
--- /dev/null
+++ b/tdeio/misc/tdewalletd/tdewalletwizard.ui
@@ -0,0 +1,545 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KWalletWizard</class>
+<widget class="TQWizard">
+ <property name="name">
+ <cstring>KWalletWizard</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>556</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KDE Wallet Wizard</string>
+ </property>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>page1</cstring>
+ </property>
+ <attribute name="title">
+ <string>Introduction</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>20</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>&lt;u&gt;KWallet&lt;/u&gt; - The KDE Wallet System</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="margin">
+ <number>26</number>
+ </property>
+ <property name="text">
+ <string>Welcome to KWallet, the KDE Wallet System. KWallet allows you to store your passwords and other personal information on disk in an encrypted file, preventing others from viewing the information. This wizard will tell you about KWallet and help you configure it for the first time.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="TQButtonGroup" row="2" column="1">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>_basic</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Basic setup (recommended)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="TQRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>_advanced</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Advanced setup</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>page4</cstring>
+ </property>
+ <attribute name="title">
+ <string>Information</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>The KDE Wallet system stores your data in a &lt;i&gt;wallet&lt;/i&gt; file on your local hard disk. The data is only written in encrypted form, presently using the blowfish algorithm with your password as the key. When a wallet is opened, the wallet manager application will launch and display an icon in the system tray. You can use this application to manage your wallets. It even permits you to drag wallets and wallet contents, allowing you to easily copy a wallet to a remote system.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>page2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Password Selection</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Various applications may attempt to use the KDE wallet to store passwords or other information such as web form data and cookies. If you would like these applications to use the wallet, you must enable it now and choose a password. The password you choose &lt;i&gt;cannot&lt;/i&gt; be recovered if it is lost, and will allow anyone who knows it to obtain all the information contained in the wallet.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget" row="3" column="1">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Enter a new password:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_pass1</cstring>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Verify password:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_pass2</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLineEdit">
+ <property name="name">
+ <cstring>_pass1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ <widget class="TQLineEdit">
+ <property name="name">
+ <cstring>_pass2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>_useWallet</cstring>
+ </property>
+ <property name="text">
+ <string>Yes, I wish to use the KDE wallet to store my personal information.</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>101</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>111</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="4" column="1">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLabel" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>_matchLabel</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>page3</cstring>
+ </property>
+ <attribute name="title">
+ <string>Security Level</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>The KDE Wallet system allows you to control the level of security of your personal data. Some of these settings do impact usability. While the default settings are generally acceptable for most users, you may wish to change some of them. You may further tune these settings from the KWallet control module.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>121</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQCheckBox" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>_networkWallet</cstring>
+ </property>
+ <property name="text">
+ <string>Store network passwords and local passwords in separate wallet files</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>_closeIdle</cstring>
+ </property>
+ <property name="text">
+ <string>Automatically close idle wallets</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+</widget>
+<connections>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel1_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel2_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>_pass1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>_pass2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>clicked()</signal>
+ <receiver>_pass1</receiver>
+ <slot>setFocus()</slot>
+ </connection>
+ <connection>
+ <sender>_useWallet</sender>
+ <signal>clicked()</signal>
+ <receiver>KWalletWizard</receiver>
+ <slot>passwordPageUpdate()</slot>
+ </connection>
+ <connection>
+ <sender>_pass1</sender>
+ <signal>textChanged(const TQString&amp;)</signal>
+ <receiver>KWalletWizard</receiver>
+ <slot>passwordPageUpdate()</slot>
+ </connection>
+ <connection>
+ <sender>_pass2</sender>
+ <signal>textChanged(const TQString&amp;)</signal>
+ <receiver>KWalletWizard</receiver>
+ <slot>passwordPageUpdate()</slot>
+ </connection>
+ <connection>
+ <sender>_advanced</sender>
+ <signal>clicked()</signal>
+ <receiver>KWalletWizard</receiver>
+ <slot>setAdvanced()</slot>
+ </connection>
+ <connection>
+ <sender>_basic</sender>
+ <signal>clicked()</signal>
+ <receiver>KWalletWizard</receiver>
+ <slot>setBasic()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>_basic</tabstop>
+ <tabstop>_advanced</tabstop>
+ <tabstop>_useWallet</tabstop>
+ <tabstop>_pass1</tabstop>
+ <tabstop>_pass2</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">tqcheckbox.h</include>
+ <include location="global" impldecl="in implementation">klocale.h</include>
+ <include location="local" impldecl="in implementation">tdewalletwizard.ui.h</include>
+</includes>
+<Q_SLOTS>
+ <slot access="private">passwordPageUpdate()</slot>
+ <slot access="private">init()</slot>
+ <slot>setAdvanced()</slot>
+ <slot>setBasic()</slot>
+ <slot access="private">destroy()</slot>
+</Q_SLOTS>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/tdeio/misc/tdewalletd/tdewalletwizard.ui.h b/tdeio/misc/tdewalletd/tdewalletwizard.ui.h
new file mode 100644
index 000000000..a42635e9b
--- /dev/null
+++ b/tdeio/misc/tdewalletd/tdewalletwizard.ui.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+void KWalletWizard::passwordPageUpdate()
+{
+ bool fe = !_useWallet->isChecked() || _pass1->text() == _pass2->text();
+ if (_basic->isChecked()) {
+ setFinishEnabled(page2, fe);
+ } else {
+ setNextEnabled(page2, fe);
+ setFinishEnabled(page3, fe);
+ }
+
+ if (_useWallet->isChecked()) {
+ if (_pass1->text() == _pass2->text()) {
+ if (_pass1->text().isEmpty()) {
+ _matchLabel->setText(i18n("<qt>Password is empty. <b>(WARNING: Insecure)"));
+ } else {
+ _matchLabel->setText(i18n("Passwords match."));
+ }
+ } else {
+ _matchLabel->setText(i18n("Passwords do not match."));
+ }
+ } else {
+ _matchLabel->setText(TQString::null);
+ }
+
+}
+
+
+void KWalletWizard::init()
+{
+ setHelpEnabled(page1, false);
+ setHelpEnabled(page2, false);
+ setHelpEnabled(page3, false);
+ setHelpEnabled(page4, false);
+ setAppropriate(page3, false);
+ setAppropriate(page4, false);
+ setFinishEnabled(page2, true);
+}
+
+
+void KWalletWizard::setAdvanced()
+{
+ setAppropriate(page3, true);
+ setAppropriate(page4, true);
+ bool fe = !_useWallet->isChecked() || _pass1->text() == _pass2->text();
+ setFinishEnabled(page2, false);
+ setNextEnabled(page2, fe);
+ setFinishEnabled(page3, fe);
+}
+
+
+void KWalletWizard::setBasic()
+{
+ setAppropriate(page3, false);
+ setAppropriate(page4, false);
+ bool fe = !_useWallet->isChecked() || _pass1->text() == _pass2->text();
+ setFinishEnabled(page3, false);
+ setFinishEnabled(page2, fe);
+}
+
+
+void KWalletWizard::destroy()
+{
+ _pass1->clear();
+ _pass2->clear();
+}
diff --git a/tdeio/misc/telnet.protocol b/tdeio/misc/telnet.protocol
new file mode 100644
index 000000000..062fb1d4f
--- /dev/null
+++ b/tdeio/misc/telnet.protocol
@@ -0,0 +1,13 @@
+[Protocol]
+exec=tdetelnetservice %u
+protocol=telnet
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+DocPath=tdeioslave/telnet.html
+Icon=konsole
diff --git a/tdeio/misc/uiserver.cpp b/tdeio/misc/uiserver.cpp
new file mode 100644
index 000000000..6ba92a6a2
--- /dev/null
+++ b/tdeio/misc/uiserver.cpp
@@ -0,0 +1,1413 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+ David Faure <faure@kde.org>
+ 2001 George Staikos <staikos@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.
+*/
+// -*- mode: c++; c-basic-offset: 4 -*-
+
+#include <tqtimer.h>
+
+#include <tqregexp.h>
+#include <tqheader.h>
+#include <tqevent.h>
+
+#include <ksqueezedtextlabel.h>
+#include <tdeconfig.h>
+#include <kstandarddirs.h>
+#include <kuniqueapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include <kstatusbar.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <tdesu/client.h>
+#include <twin.h>
+#include <kdialog.h>
+#include <ksystemtray.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+
+#include <tqcheckbox.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqpopupmenu.h>
+#include <tqheader.h>
+
+#include "observer_stub.h"
+#include "observer.h" // for static methods only
+#include "tdeio/defaultprogress.h"
+#include "tdeio/jobclasses.h"
+#include "uiserver.h"
+#include "passdlg.h"
+#include "tdeio/renamedlg.h"
+#include "tdeio/skipdlg.h"
+#include "slavebase.h" // for QuestionYesNo etc.
+#include <ksslinfodlg.h>
+#include <ksslcertdlg.h>
+#include <ksslcertificate.h>
+#include <ksslcertchain.h>
+
+
+// pointer for main instance of UIServer
+UIServer* uiserver;
+
+// ToolBar field IDs
+enum { TOOL_CANCEL, TOOL_CONFIGURE };
+
+// StatusBar field IDs
+enum { ID_TOTAL_FILES = 1, ID_TOTAL_SIZE, ID_TOTAL_TIME, ID_TOTAL_SPEED };
+
+//static
+int UIServer::s_jobId = 0;
+
+static const int defaultColumnWidth[] = { 70, // SIZE_OPERATION
+ 160, // LOCAL_FILENAME
+ 40, // RESUME
+ 60, // COUNT
+ 30, // PROGRESS
+ 65, // TOTAL
+ 70, // SPEED
+ 70, // REMAINING_TIME
+ 450 // URL
+};
+
+class UIServerSystemTray:public KSystemTray
+{
+ public:
+ UIServerSystemTray(UIServer* uis)
+ :KSystemTray(uis)
+ {
+ KPopupMenu* pop= contextMenu();
+ pop->insertItem(i18n("Settings..."), uis, TQT_SLOT(slotConfigure()));
+ pop->insertItem(i18n("Remove"), uis, TQT_SLOT(slotRemoveSystemTrayIcon()));
+ setPixmap(loadIcon("filesave"));
+ //actionCollection()->action("file_quit")->setEnabled(true);
+ KStdAction::quit(TQT_TQOBJECT(uis), TQT_SLOT(slotQuit()), actionCollection());
+ }
+};
+
+class ProgressConfigDialog:public KDialogBase
+{
+ public:
+ ProgressConfigDialog(TQWidget* parent);
+ ~ProgressConfigDialog() {}
+ void setChecked(int i, bool on);
+ bool isChecked(int i) const;
+ friend class UIServer;
+ private:
+ TQCheckBox *m_showSystemTrayCb;
+ TQCheckBox *m_keepOpenCb;
+ TQCheckBox *m_toolBarCb;
+ TQCheckBox *m_statusBarCb;
+ TQCheckBox *m_headerCb;
+ TQCheckBox *m_fixedWidthCb;
+ KListView *m_columns;
+ TQCheckListItem *(m_items[ListProgress::TB_MAX]);
+};
+
+ProgressConfigDialog::ProgressConfigDialog(TQWidget *parent)
+:KDialogBase(KDialogBase::Plain,i18n("Configure Network Operation Window"),KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel,
+ KDialogBase::Ok, parent, "configprog", false)
+{
+ TQVBoxLayout *layout=new TQVBoxLayout(plainPage(),spacingHint());
+ m_showSystemTrayCb=new TQCheckBox(i18n("Show system tray icon"), plainPage());
+ m_keepOpenCb=new TQCheckBox(i18n("Keep network operation window always open"), plainPage());
+ m_headerCb=new TQCheckBox(i18n("Show column headers"), plainPage());
+ m_toolBarCb=new TQCheckBox(i18n("Show toolbar"), plainPage());
+ m_statusBarCb=new TQCheckBox(i18n("Show statusbar"), plainPage());
+ m_fixedWidthCb=new TQCheckBox(i18n("Column widths are user adjustable"), plainPage());
+ TQLabel *label=new TQLabel(i18n("Show information:"), plainPage());
+ m_columns=new KListView(plainPage());
+
+ m_columns->addColumn("info");
+ m_columns->setSorting(-1);
+ m_columns->header()->hide();
+
+ m_items[ListProgress::TB_ADDRESS] =new TQCheckListItem(m_columns, i18n("URL"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_REMAINING_TIME] =new TQCheckListItem(m_columns, i18n("Remaining Time", "Rem. Time"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_SPEED] =new TQCheckListItem(m_columns, i18n("Speed"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_TOTAL] =new TQCheckListItem(m_columns, i18n("Size"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_PROGRESS] =new TQCheckListItem(m_columns, i18n("%"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_COUNT] =new TQCheckListItem(m_columns, i18n("Count"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_RESUME] =new TQCheckListItem(m_columns, i18n("Resume", "Res."), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_LOCAL_FILENAME] =new TQCheckListItem(m_columns, i18n("Local Filename"), TQCheckListItem::CheckBox);
+ m_items[ListProgress::TB_OPERATION] =new TQCheckListItem(m_columns, i18n("Operation"), TQCheckListItem::CheckBox);
+
+ layout->addWidget(m_showSystemTrayCb);
+ layout->addWidget(m_keepOpenCb);
+ layout->addWidget(m_headerCb);
+ layout->addWidget(m_toolBarCb);
+ layout->addWidget(m_statusBarCb);
+ layout->addWidget(m_fixedWidthCb);
+ layout->addWidget(label);
+ layout->addWidget(m_columns);
+}
+
+void ProgressConfigDialog::setChecked(int i, bool on)
+{
+ if (i>=ListProgress::TB_MAX)
+ return;
+ m_items[i]->setOn(on);
+}
+
+bool ProgressConfigDialog::isChecked(int i) const
+{
+ if (i>=ListProgress::TB_MAX)
+ return false;
+ return m_items[i]->isOn();
+}
+
+ProgressItem::ProgressItem( ListProgress* view, TQListViewItem *after, TQCString app_id, int job_id,
+ bool showDefault )
+ : TQListViewItem( view, after ) {
+
+ listProgress = view;
+
+ m_iTotalSize = 0;
+ m_iTotalFiles = 0;
+ m_iProcessedSize = 0;
+ m_iProcessedFiles = 0;
+ m_iSpeed = 0;
+
+ m_sAppId = app_id;
+ m_iJobId = job_id;
+ m_visible = true;
+ m_defaultProgressVisible = showDefault;
+
+ // create dialog, but don't show it
+ defaultProgress = new TDEIO::DefaultProgress( false );
+ defaultProgress->setOnlyClean( true );
+ connect ( defaultProgress, TQT_SIGNAL( stopped() ), this, TQT_SLOT( slotCanceled() ) );
+ connect ( &m_showTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT(slotShowDefaultProgress()) );
+
+ if ( showDefault ) {
+ m_showTimer.start( 500, true );
+ }
+}
+
+bool ProgressItem::keepOpen() const
+{
+ return defaultProgress->keepOpen();
+}
+
+void ProgressItem::finished()
+{
+ defaultProgress->finished();
+}
+
+ProgressItem::~ProgressItem() {
+ delete defaultProgress;
+}
+
+
+void ProgressItem::setTotalSize( TDEIO::filesize_t size ) {
+ m_iTotalSize = size;
+
+ // It's already in the % column...
+ //setText( listProgress->lv_total, TDEIO::convertSize( m_iTotalSize ) );
+
+ defaultProgress->slotTotalSize( 0, m_iTotalSize );
+}
+
+
+void ProgressItem::setTotalFiles( unsigned long files ) {
+ m_iTotalFiles = files;
+
+ defaultProgress->slotTotalFiles( 0, m_iTotalFiles );
+}
+
+
+void ProgressItem::setTotalDirs( unsigned long dirs ) {
+ defaultProgress->slotTotalDirs( 0, dirs );
+}
+
+
+void ProgressItem::setProcessedSize( TDEIO::filesize_t size ) {
+ m_iProcessedSize = size;
+
+ setText( ListProgress::TB_TOTAL, TDEIO::convertSize( size ) );
+
+ defaultProgress->slotProcessedSize( 0, size );
+}
+
+
+void ProgressItem::setProcessedFiles( unsigned long files ) {
+ m_iProcessedFiles = files;
+
+ TQString tmps = i18n("%1 / %2").arg( m_iProcessedFiles ).arg( m_iTotalFiles );
+ setText( ListProgress::TB_COUNT, tmps );
+
+ defaultProgress->slotProcessedFiles( 0, m_iProcessedFiles );
+}
+
+
+void ProgressItem::setProcessedDirs( unsigned long dirs ) {
+ defaultProgress->slotProcessedDirs( 0, dirs );
+}
+
+
+void ProgressItem::setPercent( unsigned long percent ) {
+ const TQString tmps = TDEIO::DefaultProgress::makePercentString( percent, m_iTotalSize, m_iTotalFiles );
+ setText( ListProgress::TB_PROGRESS, tmps );
+
+ defaultProgress->slotPercent( 0, percent );
+}
+
+void ProgressItem::setInfoMessage( const TQString & msg ) {
+ TQString plainTextMsg(msg);
+ plainTextMsg.replace( TQRegExp( "</?b>" ), TQString() );
+ plainTextMsg.replace( TQRegExp( "<img.*>" ), TQString() );
+ setText( ListProgress::TB_PROGRESS, plainTextMsg );
+
+ defaultProgress->slotInfoMessage( 0, msg );
+}
+
+void ProgressItem::setSpeed( unsigned long bytes_per_second ) {
+ m_iSpeed = bytes_per_second;
+ m_remainingSeconds = TDEIO::calculateRemainingSeconds( m_iTotalSize, m_iProcessedSize, m_iSpeed );
+
+ TQString tmps, tmps2;
+ if ( m_iSpeed == 0 ) {
+ tmps = i18n( "Stalled");
+ tmps2 = tmps;
+ } else {
+ tmps = i18n( "%1/s").arg( TDEIO::convertSize( m_iSpeed ));
+ tmps2 = TDEIO::convertSeconds( m_remainingSeconds );
+ }
+ setText( ListProgress::TB_SPEED, tmps );
+ setText( ListProgress::TB_REMAINING_TIME, tmps2 );
+
+ defaultProgress->slotSpeed( 0, m_iSpeed );
+}
+
+
+void ProgressItem::setCopying( const KURL& from, const KURL& to ) {
+ setText( ListProgress::TB_OPERATION, i18n("Copying") );
+ setText( ListProgress::TB_ADDRESS, from.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, to.fileName() );
+
+ defaultProgress->slotCopying( 0, from, to );
+}
+
+
+void ProgressItem::setMoving( const KURL& from, const KURL& to ) {
+ setText( ListProgress::TB_OPERATION, i18n("Moving") );
+ setText( ListProgress::TB_ADDRESS, from.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, to.fileName() );
+
+ defaultProgress->slotMoving( 0, from, to );
+}
+
+
+void ProgressItem::setCreatingDir( const KURL& dir ) {
+ setText( ListProgress::TB_OPERATION, i18n("Creating") );
+ setText( ListProgress::TB_ADDRESS, dir.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, dir.fileName() );
+
+ defaultProgress->slotCreatingDir( 0, dir );
+}
+
+
+void ProgressItem::setDeleting( const KURL& url ) {
+ setText( ListProgress::TB_OPERATION, i18n("Deleting") );
+ setText( ListProgress::TB_ADDRESS, url.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, url.fileName() );
+
+ defaultProgress->slotDeleting( 0, url );
+}
+
+void ProgressItem::setTransferring( const KURL& url ) {
+ setText( ListProgress::TB_OPERATION, i18n("Loading") );
+ setText( ListProgress::TB_ADDRESS, url.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, url.fileName() );
+
+ defaultProgress->slotTransferring( 0, url );
+}
+
+void ProgressItem::setText(ListProgress::ListProgressFields field, const TQString& text)
+{
+ if (listProgress->m_lpcc[field].enabled)
+ {
+ TQString t=text;
+ if ((field==ListProgress::TB_ADDRESS) && (listProgress->m_fixedColumnWidths))
+// if (((field==ListProgress::TB_LOCAL_FILENAME) || (field==ListProgress::TB_ADDRESS)) && (listProgress->m_fixedColumnWidths))
+ {
+ m_fullLengthAddress=text;
+ listProgress->m_squeezer->resize(listProgress->columnWidth(listProgress->m_lpcc[field].index),50);
+ listProgress->m_squeezer->setText(t);
+ t=listProgress->m_squeezer->text();
+ }
+ TQListViewItem::setText(listProgress->m_lpcc[field].index,t);
+ }
+}
+
+void ProgressItem::setStating( const KURL& url ) {
+ setText( ListProgress::TB_OPERATION, i18n("Examining") );
+ setText( ListProgress::TB_ADDRESS, url.url() );
+ setText( ListProgress::TB_LOCAL_FILENAME, url.fileName() );
+
+ defaultProgress->slotStating( 0, url );
+}
+
+void ProgressItem::setMounting( const TQString& dev, const TQString & point ) {
+ setText( ListProgress::TB_OPERATION, i18n("Mounting") );
+ setText( ListProgress::TB_ADDRESS, point ); // ?
+ setText( ListProgress::TB_LOCAL_FILENAME, dev ); // ?
+
+ defaultProgress->slotMounting( 0, dev, point );
+}
+
+void ProgressItem::setUnmounting( const TQString & point ) {
+ setText( ListProgress::TB_OPERATION, i18n("Unmounting") );
+ setText( ListProgress::TB_ADDRESS, point ); // ?
+ setText( ListProgress::TB_LOCAL_FILENAME, "" ); // ?
+
+ defaultProgress->slotUnmounting( 0, point );
+}
+
+void ProgressItem::setCanResume( TDEIO::filesize_t offset ) {
+ /*
+ TQString tmps;
+ // set canResume
+ if ( _resume ) {
+ tmps = i18n("Yes");
+ } else {
+ tmps = i18n("No");
+ }
+ setText( listProgress->lv_resume, tmps );
+ */
+ defaultProgress->slotCanResume( 0, offset );
+}
+
+
+void ProgressItem::slotCanceled() {
+ emit jobCanceled( this );
+}
+
+// Called 0.5s after the job has been started
+void ProgressItem::slotShowDefaultProgress() {
+ if (defaultProgress)
+ {
+ if ( m_visible && m_defaultProgressVisible )
+ defaultProgress->show();
+ else
+ defaultProgress->hide();
+ }
+}
+
+void ProgressItem::slotToggleDefaultProgress() {
+ setDefaultProgressVisible( !m_defaultProgressVisible );
+}
+
+// Called when a rename or skip dialog pops up
+// We want to prevent someone from killing the job in the uiserver then
+void ProgressItem::setVisible( bool visible ) {
+ if ( m_visible != visible )
+ {
+ m_visible = visible;
+ updateVisibility();
+ }
+}
+
+// Can be toggled by the user
+void ProgressItem::setDefaultProgressVisible( bool visible ) {
+ if ( m_defaultProgressVisible != visible )
+ {
+ m_defaultProgressVisible = visible;
+ updateVisibility();
+ }
+}
+
+// Update according to state
+void ProgressItem::updateVisibility()
+{
+ if (defaultProgress)
+ {
+ if ( m_visible && m_defaultProgressVisible )
+ {
+ m_showTimer.start(250, true); // Show delayed
+ }
+ else
+ {
+ m_showTimer.stop();
+ defaultProgress->hide();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+ListProgress::ListProgress (TQWidget *parent, const char *name)
+: KListView (parent, name)
+{
+
+ // enable selection of more than one item
+ setMultiSelection( true );
+
+ setAllColumnsShowFocus( true );
+
+ m_lpcc[TB_OPERATION].title=i18n("Operation");
+ m_lpcc[TB_LOCAL_FILENAME].title=i18n("Local Filename");
+ m_lpcc[TB_RESUME].title=i18n("Resume", "Res.");
+ m_lpcc[TB_COUNT].title=i18n("Count");
+ m_lpcc[TB_PROGRESS].title=i18n("%");
+ m_lpcc[TB_TOTAL].title=i18n("Size");
+ m_lpcc[TB_SPEED].title=i18n("Speed");
+ m_lpcc[TB_REMAINING_TIME].title=i18n("Remaining Time", "Rem. Time");
+ m_lpcc[TB_ADDRESS].title=i18n("URL");
+ readSettings();
+
+ applySettings();
+
+ //used for squeezing the text in local file name and url
+ m_squeezer=new KSqueezedTextLabel(this);
+ m_squeezer->hide();
+ connect(header(),TQT_SIGNAL(sizeChange(int,int,int)),this,TQT_SLOT(columnWidthChanged(int)));
+}
+
+
+ListProgress::~ListProgress() {
+}
+
+void ListProgress::applySettings()
+{
+ int iEnabledCols=0;
+
+ // Update listcolumns to show
+ for (int i=0; i<TB_MAX; i++)
+ {
+ if ( !m_lpcc[i].enabled )
+ continue;
+
+ iEnabledCols++;
+
+ // Add new or reuse existing column
+ if ( iEnabledCols > columns() )
+ m_lpcc[i].index=addColumn(m_lpcc[i].title, m_fixedColumnWidths?m_lpcc[i].width:-1);
+ else
+ {
+ m_lpcc[i].index = iEnabledCols - 1;
+ setColumnText(m_lpcc[i].index, m_lpcc[i].title);
+ }
+
+ setColumnWidth(m_lpcc[i].index, m_lpcc[i].width); //yes, this is required here, alexxx
+ if (m_fixedColumnWidths)
+ setColumnWidthMode(m_lpcc[i].index, Manual);
+ }
+
+ // Remove unused columns. However we must keep one column left
+ // Otherwise the listview will be emptied
+ while( iEnabledCols < columns() && columns() > 1 )
+ removeColumn( columns() - 1 );
+
+ if ( columns() == 0 )
+ addColumn( "" );
+
+ if ( !m_showHeader || iEnabledCols == 0 )
+ header()->hide();
+ else
+ header()->show();
+}
+
+void ListProgress::readSettings() {
+ TDEConfig config("uiserverrc");
+
+ // read listview geometry properties
+ config.setGroup( "ProgressList" );
+ for ( int i = 0; i < TB_MAX; i++ ) {
+ TQString tmps="Col"+TQString::number(i);
+ m_lpcc[i].width=config.readNumEntry( tmps, 0);
+ if (m_lpcc[i].width==0) m_lpcc[i].width=defaultColumnWidth[i];
+
+ tmps="Enabled"+TQString::number(i);
+ m_lpcc[i].enabled=config.readBoolEntry(tmps,true);
+ }
+ m_showHeader=config.readBoolEntry("ShowListHeader",true);
+ m_fixedColumnWidths=config.readBoolEntry("FixedColumnWidths",false);
+
+ m_lpcc[TB_RESUME].enabled=false;
+}
+
+void ListProgress::columnWidthChanged(int column)
+{
+ //resqueeze if necessary
+ if ((m_lpcc[TB_ADDRESS].enabled) && (column==m_lpcc[TB_ADDRESS].index))
+ {
+ for (TQListViewItem* lvi=firstChild(); lvi!=0; lvi=lvi->nextSibling())
+ {
+ ProgressItem *pi=(ProgressItem*)lvi;
+ pi->setText(TB_ADDRESS,pi->fullLengthAddress());
+ }
+ }
+ writeSettings();
+}
+
+void ListProgress::writeSettings() {
+ TDEConfig config("uiserverrc");
+
+ // write listview geometry properties
+ config.setGroup( "ProgressList" );
+ for ( int i = 0; i < TB_MAX; i++ ) {
+ if (!m_lpcc[i].enabled) {
+ TQString tmps= "Enabled" + TQString::number(i);
+ config.writeEntry( tmps, false );
+ continue;
+ }
+ m_lpcc[i].width=columnWidth(m_lpcc[i].index);
+ TQString tmps="Col"+TQString::number(i);
+ config.writeEntry( tmps, m_lpcc[i].width);
+ }
+ config.writeEntry("ShowListHeader", m_showHeader);
+ config.writeEntry("FixedColumnWidths", m_fixedColumnWidths);
+ config.sync();
+}
+
+
+//------------------------------------------------------------
+
+
+UIServer::UIServer()
+:KMainWindow(0, "")
+,DCOPObject("UIServer")
+,m_shuttingDown(false)
+,m_configDialog(0)
+,m_contextMenu(0)
+,m_systemTray(0)
+{
+
+ readSettings();
+
+ // setup toolbar
+ toolBar()->insertButton("editdelete", TOOL_CANCEL,
+ TQT_SIGNAL(clicked()), TQT_TQOBJECT(this),
+ TQT_SLOT(slotCancelCurrent()), FALSE, i18n("Cancel"));
+ toolBar()->insertButton("configure", TOOL_CONFIGURE,
+ TQT_SIGNAL(clicked()), TQT_TQOBJECT(this),
+ TQT_SLOT(slotConfigure()), true, i18n("Settings..."));
+
+ toolBar()->setBarPos( KToolBar::Left );
+
+ // setup statusbar
+ statusBar()->insertItem( i18n(" Files: %1 ").arg( 0 ), ID_TOTAL_FILES);
+ statusBar()->insertItem( i18n("Remaining Size", " Rem. Size: %1 kB ").arg( "0" ), ID_TOTAL_SIZE);
+ statusBar()->insertItem( i18n("Remaining Time", " Rem. Time: 00:00:00 "), ID_TOTAL_TIME);
+ statusBar()->insertItem( i18n(" %1 kB/s ").arg("0"), ID_TOTAL_SPEED);
+
+ // setup listview
+ listProgress = new ListProgress( this, "progresslist" );
+
+ setCentralWidget( listProgress );
+
+ connect( listProgress, TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( slotSelection() ) );
+ connect( listProgress, TQT_SIGNAL( executed( TQListViewItem* ) ),
+ TQT_SLOT( slotToggleDefaultProgress( TQListViewItem* ) ) );
+ connect( listProgress, TQT_SIGNAL( contextMenu( KListView*, TQListViewItem *, const TQPoint &)),
+ TQT_SLOT(slotShowContextMenu(KListView*, TQListViewItem *, const TQPoint&)));
+
+
+ // setup animation timer
+ updateTimer = new TQTimer( this );
+ connect( updateTimer, TQT_SIGNAL( timeout() ),
+ TQT_SLOT( slotUpdate() ) );
+ m_bUpdateNewJob=false;
+
+ setCaption(i18n("Progress Dialog"));
+ setMinimumSize( 150, 50 );
+ resize( m_initWidth, m_initHeight);
+
+ applySettings();
+
+/* if ((m_bShowList) && (m_keepListOpen))
+ {
+ cerr<<"show() !"<<endl;
+ show();
+ }
+ else*/
+ hide();
+}
+
+UIServer::~UIServer() {
+ updateTimer->stop();
+}
+
+void UIServer::applySettings()
+{
+ if ((m_showSystemTray) && (m_systemTray==0))
+ {
+ m_systemTray=new UIServerSystemTray(this);
+ m_systemTray->show();
+ }
+ else if ((m_showSystemTray==false) && (m_systemTray!=0))
+ {
+ delete m_systemTray;
+ m_systemTray=0;
+ }
+
+ if (m_showStatusBar==false)
+ statusBar()->hide();
+ else
+ statusBar()->show();
+ if (m_showToolBar==false)
+ toolBar()->hide();
+ else
+ toolBar()->show();
+}
+
+void UIServer::slotShowContextMenu(KListView*, TQListViewItem* item, const TQPoint& pos)
+{
+ if (m_contextMenu==0)
+ {
+ m_contextMenu=new TQPopupMenu(this);
+ m_idCancelItem = m_contextMenu->insertItem(i18n("Cancel Job"), this, TQT_SLOT(slotCancelCurrent()));
+// m_contextMenu->insertItem(i18n("Toggle Progress"), this, TQT_SLOT(slotToggleDefaultProgress()));
+ m_contextMenu->insertSeparator();
+ m_contextMenu->insertItem(i18n("Settings..."), this, TQT_SLOT(slotConfigure()));
+ }
+ if ( item )
+ item->setSelected( true );
+ bool enabled = false;
+ TQListViewItemIterator it( listProgress );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ enabled = true;
+ break;
+ }
+ }
+ m_contextMenu->setItemEnabled( m_idCancelItem, enabled);
+
+ m_contextMenu->popup(pos);
+}
+
+void UIServer::slotRemoveSystemTrayIcon()
+{
+ m_showSystemTray=false;
+ applySettings();
+ writeSettings();
+}
+
+void UIServer::slotConfigure()
+{
+ if (m_configDialog==0)
+ {
+ m_configDialog=new ProgressConfigDialog(0);
+// connect(m_configDialog,TQT_SIGNAL(cancelClicked()), this, TQT_SLOT(slotCancelConfig()));
+ connect(m_configDialog,TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotApplyConfig()));
+ connect(m_configDialog,TQT_SIGNAL(applyClicked()), this, TQT_SLOT(slotApplyConfig()));
+ }
+ m_configDialog->m_showSystemTrayCb->setChecked(m_showSystemTray);
+ m_configDialog->m_keepOpenCb->setChecked(m_keepListOpen);
+ m_configDialog->m_toolBarCb->setChecked(m_showToolBar);
+ m_configDialog->m_statusBarCb->setChecked(m_showStatusBar);
+ m_configDialog->m_headerCb->setChecked(listProgress->m_showHeader);
+ m_configDialog->m_fixedWidthCb->setChecked(listProgress->m_fixedColumnWidths);
+ for (int i=0; i<ListProgress::TB_MAX; i++)
+ {
+ m_configDialog->setChecked(i, listProgress->m_lpcc[i].enabled);
+ }
+ m_configDialog->show();
+}
+
+void UIServer::slotApplyConfig()
+{
+ m_showSystemTray=m_configDialog->m_showSystemTrayCb->isChecked();
+ m_keepListOpen=m_configDialog->m_keepOpenCb->isChecked();
+ m_showToolBar=m_configDialog->m_toolBarCb->isChecked();
+ m_showStatusBar=m_configDialog->m_statusBarCb->isChecked();
+ listProgress->m_showHeader=m_configDialog->m_headerCb->isChecked();
+ listProgress->m_fixedColumnWidths=m_configDialog->m_fixedWidthCb->isChecked();
+ for (int i=0; i<ListProgress::TB_MAX; i++)
+ listProgress->m_lpcc[i].enabled=m_configDialog->isChecked(i);
+
+
+ applySettings();
+ listProgress->applySettings();
+ writeSettings();
+ listProgress->writeSettings();
+}
+
+int UIServer::newJob( TQCString observerAppId, bool showProgress )
+{
+ kdDebug(7024) << "UIServer::newJob observerAppId=" << observerAppId << ". "
+ << "Giving id=" << s_jobId+1 << endl;
+
+ TQListViewItemIterator it( listProgress );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->itemBelow() == 0L ) { // this will find the end of list
+ break;
+ }
+ }
+
+ // increment counter
+ s_jobId++;
+
+ bool show = !m_bShowList && showProgress;
+
+ ProgressItem *item = new ProgressItem( listProgress, it.current(), observerAppId, s_jobId, show );
+ connect( item, TQT_SIGNAL( jobCanceled( ProgressItem* ) ),
+ TQT_SLOT( slotJobCanceled( ProgressItem* ) ) );
+
+ if ( m_bShowList && !updateTimer->isActive() )
+ updateTimer->start( 1000 );
+
+ m_bUpdateNewJob=true;
+
+ return s_jobId;
+}
+
+
+ProgressItem* UIServer::findItem( int id )
+{
+ TQListViewItemIterator it( listProgress );
+
+ ProgressItem *item;
+
+ for ( ; it.current(); ++it ) {
+ item = (ProgressItem*) it.current();
+ if ( item->jobId() == id ) {
+ return item;
+ }
+ }
+
+ return 0L;
+}
+
+
+void UIServer::setItemVisible( ProgressItem * item, bool visible )
+{
+ item->setVisible( visible );
+ // Check if we were the last one to be visible
+ // or the first one -> hide/show the list in that case
+ // (Note that the user could have hidden the listview by hand yet, no time)
+ if ( m_bShowList ) {
+ m_bUpdateNewJob = true;
+ slotUpdate();
+ }
+}
+
+// Called by Observer when opening a skip or rename dialog
+void UIServer::setJobVisible( int id, bool visible )
+{
+ kdDebug(7024) << "UIServer::setJobVisible id=" << id << " visible=" << visible << endl;
+ ProgressItem *item = findItem( id );
+ Q_ASSERT( item );
+ if ( item )
+ setItemVisible( item, visible );
+}
+
+void UIServer::jobFinished( int id )
+{
+ kdDebug(7024) << "UIServer::jobFinished id=" << id << endl;
+ ProgressItem *item = findItem( id );
+
+ // remove item from the list and delete the corresponding defaultprogress
+ if ( item ) {
+ if ( item->keepOpen() )
+ item->finished();
+ else
+ delete item;
+ }
+}
+
+
+void UIServer::totalSize( int id, unsigned long size )
+{ totalSize64(id, size); }
+
+void UIServer::totalSize64( int id, TDEIO::filesize_t size )
+{
+// kdDebug(7024) << "UIServer::totalSize " << id << " " << TDEIO::number(size) << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setTotalSize( size );
+ }
+}
+
+void UIServer::totalFiles( int id, unsigned long files )
+{
+ kdDebug(7024) << "UIServer::totalFiles " << id << " " << (unsigned int) files << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setTotalFiles( files );
+ }
+}
+
+void UIServer::totalDirs( int id, unsigned long dirs )
+{
+ kdDebug(7024) << "UIServer::totalDirs " << id << " " << (unsigned int) dirs << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setTotalDirs( dirs );
+ }
+}
+
+void UIServer::processedSize( int id, unsigned long size )
+{ processedSize64(id, size); }
+
+void UIServer::processedSize64( int id, TDEIO::filesize_t size )
+{
+ //kdDebug(7024) << "UIServer::processedSize " << id << " " << TDEIO::number(size) << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setProcessedSize( size );
+ }
+}
+
+void UIServer::processedFiles( int id, unsigned long files )
+{
+ //kdDebug(7024) << "UIServer::processedFiles " << id << " " << (unsigned int) files << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setProcessedFiles( files );
+ }
+}
+
+void UIServer::processedDirs( int id, unsigned long dirs )
+{
+ kdDebug(7024) << "UIServer::processedDirs " << id << " " << (unsigned int) dirs << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setProcessedDirs( dirs );
+ }
+}
+
+void UIServer::percent( int id, unsigned long ipercent )
+{
+ //kdDebug(7024) << "UIServer::percent " << id << " " << (unsigned int) ipercent << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setPercent( ipercent );
+ }
+}
+
+void UIServer::speed( int id, unsigned long bytes_per_second )
+{
+ //kdDebug(7024) << "UIServer::speed " << id << " " << (unsigned int) bytes_per_second << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setSpeed( bytes_per_second );
+ }
+}
+
+void UIServer::infoMessage( int id, const TQString & msg )
+{
+ //kdDebug(7024) << "UIServer::infoMessage " << id << " " << msg << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setInfoMessage( msg );
+ }
+}
+
+void UIServer::canResume( int id, unsigned long offset )
+{ canResume64(id, offset); }
+
+void UIServer::canResume64( int id, TDEIO::filesize_t offset )
+{
+ //kdDebug(7024) << "UIServer::canResume " << id << " " << offset << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setCanResume( offset );
+ }
+}
+
+void UIServer::copying( int id, KURL from, KURL to )
+{
+ //kdDebug(7024) << "UIServer::copying " << id << " " << from.url() << " " << to.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setCopying( from, to );
+ }
+}
+
+void UIServer::moving( int id, KURL from, KURL to )
+{
+ //kdDebug(7024) << "UIServer::moving " << id << " " << from.url() << " " << to.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setMoving( from, to );
+ }
+}
+
+void UIServer::deleting( int id, KURL url )
+{
+ //kdDebug(7024) << "UIServer::deleting " << id << " " << url.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setDeleting( url );
+ }
+}
+
+void UIServer::transferring( int id, KURL url )
+{
+ //kdDebug(7024) << "UIServer::transferring " << id << " " << url.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setTransferring( url );
+ }
+}
+
+void UIServer::creatingDir( int id, KURL dir )
+{
+ kdDebug(7024) << "UIServer::creatingDir " << id << " " << dir.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setCreatingDir( dir );
+ }
+}
+
+void UIServer::stating( int id, KURL url )
+{
+ kdDebug(7024) << "UIServer::stating " << id << " " << url.url() << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setStating( url );
+ }
+}
+
+void UIServer::mounting( int id, TQString dev, TQString point )
+{
+ kdDebug(7024) << "UIServer::mounting " << id << " " << dev << " " << point << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setMounting( dev, point );
+ }
+}
+
+void UIServer::unmounting( int id, TQString point )
+{
+ kdDebug(7024) << "UIServer::unmounting " << id << " " << point << endl;
+
+ ProgressItem *item = findItem( id );
+ if ( item ) {
+ item->setUnmounting( point );
+ }
+}
+
+void UIServer::killJob( TQCString observerAppId, int progressId )
+{
+ // Contact the object "TDEIO::Observer" in the application <appId>
+ Observer_stub observer( observerAppId, "TDEIO::Observer" );
+ // Tell it to kill the job
+ observer.killJob( progressId );
+}
+
+void UIServer::slotJobCanceled( ProgressItem *item ) {
+ kdDebug(7024) << "UIServer::slotJobCanceled appid=" << item->appId() << " jobid=" << item->jobId() << endl;
+ // kill the corresponding job
+ killJob( item->appId(), item->jobId() );
+
+ // TDEIO::Job, when killed, should call back jobFinished(), but we can't
+ // really rely on that - the app may have crashed
+ delete item;
+}
+
+
+void UIServer::slotQuit()
+{
+ m_shuttingDown = true;
+ kapp->quit();
+}
+
+void UIServer::slotUpdate() {
+ // don't do anything if we don't have any inserted progress item
+ // or if they're all hidden
+ TQListViewItemIterator lvit( listProgress );
+ bool visible = false;
+ for ( ; lvit.current(); ++lvit )
+ if ( ((ProgressItem*)lvit.current())->isVisible() ) {
+ visible = true;
+ break;
+ }
+
+ if ( !visible || !m_bShowList ) {
+ if (!m_keepListOpen) hide();
+ updateTimer->stop();
+ return;
+ }
+
+ // Calling show() is conditional, so that users can close the window
+ // and it only pops up back when a new job is started
+ if (m_bUpdateNewJob)
+ {
+ m_bUpdateNewJob=false;
+ show();
+
+ // Make sure we'll be called back
+ if ( m_bShowList && !updateTimer->isActive() )
+ updateTimer->start( 1000 );
+ }
+
+ int iTotalFiles = 0;
+ TDEIO::filesize_t iTotalSize = 0;
+ int iTotalSpeed = 0;
+ unsigned int totalRemTime = 0; // in seconds
+
+ ProgressItem *item;
+
+ // count totals for statusbar
+ TQListViewItemIterator it( listProgress );
+
+ for ( ; it.current(); ++it ) {
+ item = (ProgressItem*) it.current();
+ if ( item->totalSize() != 0 ) {
+ iTotalSize += ( item->totalSize() - item->processedSize() );
+ }
+ iTotalFiles += ( item->totalFiles() - item->processedFiles() );
+ iTotalSpeed += item->speed();
+
+ if ( item->remainingSeconds() > totalRemTime ) {
+ totalRemTime = item->remainingSeconds();
+ }
+ }
+
+ // update statusbar
+ statusBar()->changeItem( i18n( " Files: %1 ").arg( iTotalFiles ), ID_TOTAL_FILES);
+ statusBar()->changeItem( i18n( "Remaining Size", " Rem. Size: %1 ").arg( TDEIO::convertSize( iTotalSize ) ),
+ ID_TOTAL_SIZE);
+ statusBar()->changeItem( i18n( "Remaining Time", " Rem. Time: %1 ").arg( TDEIO::convertSeconds( totalRemTime ) ),
+ ID_TOTAL_TIME);
+ statusBar()->changeItem( i18n( " %1/s ").arg( TDEIO::convertSize( iTotalSpeed ) ),
+ ID_TOTAL_SPEED);
+
+}
+
+void UIServer::setListMode( bool list )
+{
+ m_bShowList = list;
+ TQListViewItemIterator it( listProgress );
+ for ( ; it.current(); ++it ) {
+ // When going to list mode -> hide all progress dialogs
+ // When going back to separate dialogs -> show them all
+ ((ProgressItem*) it.current())->setDefaultProgressVisible( !list );
+ }
+
+ if (m_bShowList)
+ {
+ show();
+ updateTimer->start( 1000 );
+ }
+ else
+ {
+ hide();
+ updateTimer->stop();
+ }
+}
+
+void UIServer::slotToggleDefaultProgress( TQListViewItem *item ) {
+ ((ProgressItem*) item )->slotToggleDefaultProgress();
+}
+
+
+void UIServer::slotSelection() {
+ TQListViewItemIterator it( listProgress );
+
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ toolBar()->setItemEnabled( TOOL_CANCEL, TRUE);
+ return;
+ }
+ }
+ toolBar()->setItemEnabled( TOOL_CANCEL, FALSE);
+}
+
+// This code is deprecated, slaves go to Observer::openPassDlg now,
+// but this is kept for compat (DCOP calls to tdeio_uiserver).
+TQByteArray UIServer::openPassDlg( const TDEIO::AuthInfo &info )
+{
+ kdDebug(7024) << "UIServer::openPassDlg: User= " << info.username
+ << ", Msg= " << info.prompt << endl;
+ TDEIO::AuthInfo inf(info);
+ int result = TDEIO::PasswordDialog::getNameAndPassword( inf.username, inf.password,
+ &inf.keepPassword, inf.prompt,
+ inf.readOnly, inf.caption,
+ inf.comment, inf.commentLabel );
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ if ( result == TQDialog::Accepted )
+ inf.setModified( true );
+ else
+ inf.setModified( false );
+ stream << inf;
+ return data;
+}
+
+int UIServer::messageBox( int progressId, int type, const TQString &text, const TQString &caption, const TQString &buttonYes, const TQString &buttonNo )
+{
+ return Observer::messageBox( progressId, type, text, caption, buttonYes, buttonNo );
+}
+
+void UIServer::showSSLInfoDialog(const TQString &url, const TDEIO::MetaData &meta)
+{
+ return showSSLInfoDialog(url,meta,0);
+}
+
+void UIServer::showSSLInfoDialog(const TQString &url, const TDEIO::MetaData &meta, int mainwindow)
+{
+ KSSLInfoDlg *kid = new KSSLInfoDlg(meta["ssl_in_use"].upper()=="TRUE", 0L /*parent?*/, 0L, true);
+ KSSLCertificate *x = KSSLCertificate::fromString(meta["ssl_peer_certificate"].local8Bit());
+ if (x) {
+ // Set the chain back onto the certificate
+ TQStringList cl =
+ TQStringList::split(TQString("\n"), meta["ssl_peer_chain"]);
+ TQPtrList<KSSLCertificate> ncl;
+
+ ncl.setAutoDelete(true);
+ for (TQStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
+ KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
+ if (y) ncl.append(y);
+ }
+
+ if (ncl.count() > 0)
+ x->chain().setChain(ncl);
+
+ kdDebug(7024) << "ssl_cert_errors=" << meta["ssl_cert_errors"] << endl;
+ kid->setCertState(meta["ssl_cert_errors"]);
+ TQString ip = meta.contains("ssl_proxied") ? "" : meta["ssl_peer_ip"];
+ kid->setup( x,
+ ip,
+ url, // the URL
+ meta["ssl_cipher"],
+ meta["ssl_cipher_desc"],
+ meta["ssl_cipher_version"],
+ meta["ssl_cipher_used_bits"].toInt(),
+ meta["ssl_cipher_bits"].toInt(),
+ KSSLCertificate::KSSLValidation(meta["ssl_cert_state"].toInt()));
+ kdDebug(7024) << "Showing SSL Info dialog" << endl;
+#ifndef Q_WS_WIN
+ if( mainwindow != 0 )
+ KWin::setMainWindow( kid, mainwindow );
+#endif
+ kid->exec();
+ delete x;
+ kdDebug(7024) << "SSL Info dialog closed" << endl;
+ } else {
+ KMessageBox::information( 0L, // parent ?
+ i18n("The peer SSL certificate appears to be corrupt."), i18n("SSL") );
+ }
+ // Don't delete kid!!
+}
+
+KSSLCertDlgRet UIServer::showSSLCertDialog(const TQString& host, const TQStringList& certList)
+{
+ return showSSLCertDialog( host, certList, 0 );
+}
+
+KSSLCertDlgRet UIServer::showSSLCertDialog(const TQString& host, const TQStringList& certList, int mainwindow)
+{
+ KSSLCertDlgRet rc;
+ rc.ok = false;
+ if (!certList.isEmpty()) {
+ KSSLCertDlg *kcd = new KSSLCertDlg(0L, 0L, true);
+ kcd->setupDialog(certList);
+ kcd->setHost(host);
+ kdDebug(7024) << "Showing SSL certificate dialog" << endl;
+#ifndef Q_WS_WIN
+ if( mainwindow != 0 )
+ KWin::setMainWindow( kcd, mainwindow );
+#endif
+ kcd->exec();
+ rc.ok = true;
+ rc.choice = kcd->getChoice();
+ rc.save = kcd->saveChoice();
+ rc.send = kcd->wantsToSend();
+ kdDebug(7024) << "SSL certificate dialog closed" << endl;
+ delete kcd;
+ }
+ return rc;
+}
+
+
+TQByteArray UIServer::open_RenameDlg( int id,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ int mode,
+ unsigned long sizeSrc,
+ unsigned long sizeDest,
+ unsigned long ctimeSrc,
+ unsigned long ctimeDest,
+ unsigned long mtimeSrc,
+ unsigned long mtimeDest
+ )
+{ return open_RenameDlg64(id, caption, src, dest, mode, sizeSrc, sizeDest,
+ ctimeSrc, ctimeDest, mtimeSrc, mtimeDest); }
+
+
+TQByteArray UIServer::open_RenameDlg64( int id,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ int mode,
+ TDEIO::filesize_t sizeSrc,
+ TDEIO::filesize_t sizeDest,
+ unsigned long ctimeSrc,
+ unsigned long ctimeDest,
+ unsigned long mtimeSrc,
+ unsigned long mtimeDest
+ )
+{
+ // Hide existing dialog box if any
+ ProgressItem *item = findItem( id );
+ if ( item )
+ setItemVisible( item, false );
+ TQString newDest;
+ kdDebug(7024) << "Calling TDEIO::open_RenameDlg" << endl;
+ TDEIO::RenameDlg_Result result = TDEIO::open_RenameDlg( caption, src, dest,
+ (TDEIO::RenameDlg_Mode) mode, newDest,
+ sizeSrc, sizeDest,
+ (time_t)ctimeSrc, (time_t)ctimeDest,
+ (time_t)mtimeSrc, (time_t)mtimeDest );
+ kdDebug(7024) << "TDEIO::open_RenameDlg done" << endl;
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ stream << TQ_UINT8(result) << newDest;
+ if ( item && result != TDEIO::R_CANCEL )
+ setItemVisible( item, true );
+ return data;
+}
+
+int UIServer::open_SkipDlg( int id,
+ int /*bool*/ multi,
+ const TQString & error_text )
+{
+ // Hide existing dialog box if any
+ ProgressItem *item = findItem( id );
+ if ( item )
+ setItemVisible( item, false );
+ kdDebug(7024) << "Calling TDEIO::open_SkipDlg" << endl;
+ TDEIO::SkipDlg_Result result = TDEIO::open_SkipDlg( (bool)multi, error_text );
+ if ( item && result != TDEIO::S_CANCEL )
+ setItemVisible( item, true );
+ return (TDEIO::SkipDlg_Result) result;
+}
+
+
+void UIServer::readSettings() {
+ TDEConfig config("uiserverrc");
+ config.setGroup( "UIServer" );
+ m_showStatusBar=config.readBoolEntry("ShowStatusBar",false);
+ m_showToolBar=config.readBoolEntry("ShowToolBar",true);
+ m_keepListOpen=config.readBoolEntry("KeepListOpen",false);
+ m_initWidth=config.readNumEntry("InitialWidth",460);
+ m_initHeight=config.readNumEntry("InitialHeight",150);
+ m_bShowList = config.readBoolEntry( "ShowList", false );
+ m_showSystemTray=config.readBoolEntry("ShowSystemTray", false);
+}
+
+void UIServer::writeSettings() {
+ TDEConfig config("uiserverrc");
+ config.setGroup( "UIServer" );
+ config.writeEntry("InitialWidth",width());
+ config.writeEntry("InitialHeight",height());
+ config.writeEntry("ShowStatusBar", m_showStatusBar);
+ config.writeEntry("ShowToolBar", m_showToolBar);
+ config.writeEntry("KeepListOpen", m_keepListOpen);
+ config.writeEntry("ShowList", m_bShowList);
+ config.writeEntry("ShowSystemTray", m_showSystemTray);
+}
+
+
+void UIServer::slotCancelCurrent() {
+ TQListViewItemIterator it( listProgress );
+ ProgressItem *item;
+
+ // kill selected jobs
+ for ( ; it.current() ; ++it )
+ {
+ if ( it.current()->isSelected() ) {
+ item = (ProgressItem*) it.current();
+ killJob( item->appId(), item->jobId() );
+ return;
+ }
+ }
+}
+
+void UIServer::resizeEvent(TQResizeEvent* e)
+{
+ KMainWindow::resizeEvent(e);
+ writeSettings();
+}
+
+bool UIServer::queryClose()
+{
+ if (( !m_shuttingDown ) && !kapp->sessionSaving()) {
+ hide();
+ return false;
+ }
+ return true;
+}
+
+UIServer* UIServer::createInstance()
+{
+ return new UIServer;
+}
+
+//------------------------------------------------------------
+
+extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
+{
+ KLocale::setMainCatalogue("tdelibs");
+ // GS 5/2001 - I changed the name to "TDE" to make it look better
+ // in the titles of dialogs which are displayed.
+ TDEAboutData aboutdata("tdeio_uiserver", I18N_NOOP("TDE"),
+ "0.8", I18N_NOOP("TDE Progress Information UI Server"),
+ TDEAboutData::License_GPL, "(C) 2000, David Faure & Matt Koss");
+ // Who's the maintainer ? :)
+ aboutdata.addAuthor("David Faure",I18N_NOOP("Developer"),"faure@kde.org");
+ aboutdata.addAuthor("Matej Koss",I18N_NOOP("Developer"),"koss@miesto.sk");
+
+ TDECmdLineArgs::init( argc, argv, &aboutdata );
+ // TDECmdLineArgs::addCmdLineOptions( options );
+ KUniqueApplication::addCmdLineOptions();
+
+ if (!KUniqueApplication::start())
+ {
+ kdDebug(7024) << "tdeio_uiserver is already running!" << endl;
+ return (0);
+ }
+
+ KUniqueApplication app;
+
+ // This app is started automatically, no need for session management
+ app.disableSessionManagement();
+ app.dcopClient()->setDaemonMode( true );
+
+ uiserver = UIServer::createInstance();
+
+// app.setMainWidget( uiserver );
+
+ return app.exec();
+}
+
+#include "uiserver.moc"
diff --git a/tdeio/misc/uiserver.h b/tdeio/misc/uiserver.h
new file mode 100644
index 000000000..baf495dfe
--- /dev/null
+++ b/tdeio/misc/uiserver.h
@@ -0,0 +1,430 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+ 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 __tdeio_uiserver_h__
+#define __tdeio_uiserver_h__
+
+#include <tqintdict.h>
+#include <tqdatetime.h>
+#include <tqtimer.h>
+
+#include <dcopobject.h>
+#include <tdeio/global.h>
+#include <tdeio/authinfo.h>
+#include <kurl.h>
+#include <kmainwindow.h>
+#include <kdatastream.h>
+#include <klistview.h>
+#include <ksslcertdlg.h>
+
+class ListProgress;
+class KSqueezedTextLabel;
+class ProgressItem;
+class UIServer;
+
+namespace TDEIO {
+ class Job;
+ class DefaultProgress;
+}
+
+
+struct ListProgressColumnConfig
+{
+ TQString title;
+ int index;
+ int width;
+ bool enabled;
+};
+
+/**
+* List view in the UIServer.
+* @internal
+*/
+class TDEIO_EXPORT ListProgress : public KListView {
+
+ Q_OBJECT
+
+public:
+
+ ListProgress (TQWidget *parent = 0, const char *name = 0 );
+
+ virtual ~ListProgress();
+
+ /**
+ * Field constants
+ */
+ enum ListProgressFields {
+ TB_OPERATION = 0,
+ TB_LOCAL_FILENAME = 1,
+ TB_RESUME = 2,
+ TB_COUNT = 3, //lv_count
+ TB_PROGRESS = 4, // lv_progress
+ TB_TOTAL = 5,
+ TB_SPEED = 6,
+ TB_REMAINING_TIME = 7,
+ TB_ADDRESS = 8,
+ TB_MAX = 9
+ };
+
+ friend class ProgressItem;
+ friend class UIServer;
+protected slots:
+ void columnWidthChanged(int column);
+protected:
+
+ void writeSettings();
+ void readSettings();
+ void applySettings();
+ void createColumns();
+
+ bool m_showHeader;
+ bool m_fixedColumnWidths;
+ ListProgressColumnConfig m_lpcc[TB_MAX];
+ //hack, alexxx
+ KSqueezedTextLabel *m_squeezer;
+};
+
+/**
+* One item in the ListProgress
+* @internal
+*/
+class TDEIO_EXPORT ProgressItem : public TQObject, public TQListViewItem {
+
+ Q_OBJECT
+
+public:
+ ProgressItem( ListProgress* view, TQListViewItem *after, TQCString app_id, int job_id,
+ bool showDefault = true );
+ ~ProgressItem();
+
+ TQCString appId() { return m_sAppId; }
+ int jobId() { return m_iJobId; }
+
+ bool keepOpen() const;
+ void finished();
+
+ void setVisible( bool visible );
+ void setDefaultProgressVisible( bool visible );
+ bool isVisible() const { return m_visible; }
+
+ void setTotalSize( TDEIO::filesize_t bytes );
+ void setTotalFiles( unsigned long files );
+ void setTotalDirs( unsigned long dirs );
+
+ void setProcessedSize( TDEIO::filesize_t size );
+ void setProcessedFiles( unsigned long files );
+ void setProcessedDirs( unsigned long dirs );
+
+ void setPercent( unsigned long percent );
+ void setSpeed( unsigned long bytes_per_second );
+ void setInfoMessage( const TQString & msg );
+
+ void setCopying( const KURL& from, const KURL& to );
+ void setMoving( const KURL& from, const KURL& to );
+ void setDeleting( const KURL& url );
+ void setTransferring( const KURL& url );
+ void setCreatingDir( const KURL& dir );
+ void setStating( const KURL& url );
+ void setMounting( const TQString & dev, const TQString & point );
+ void setUnmounting( const TQString & point );
+
+ void setCanResume( TDEIO::filesize_t offset );
+
+ TDEIO::filesize_t totalSize() { return m_iTotalSize; }
+ unsigned long totalFiles() { return m_iTotalFiles; }
+ TDEIO::filesize_t processedSize() { return m_iProcessedSize; }
+ unsigned long processedFiles() { return m_iProcessedFiles; }
+ unsigned long speed() { return m_iSpeed; }
+ unsigned int remainingSeconds() { return m_remainingSeconds; }
+
+ const TQString& fullLengthAddress() const {return m_fullLengthAddress;}
+ void setText(ListProgress::ListProgressFields field, const TQString& text);
+public slots:
+ void slotShowDefaultProgress();
+ void slotToggleDefaultProgress();
+
+protected slots:
+ void slotCanceled();
+
+signals:
+ void jobCanceled( ProgressItem* );
+
+protected:
+ void updateVisibility();
+
+ // ids that uniquely identify this progress item
+ TQCString m_sAppId;
+ int m_iJobId;
+
+ // whether shown or not (it is hidden if a rename dialog pops up for the same job)
+ bool m_visible;
+ bool m_defaultProgressVisible;
+
+ // parent listview
+ ListProgress *listProgress;
+
+ // associated default progress dialog
+ TDEIO::DefaultProgress *defaultProgress;
+
+ // we store these values for calculation of totals ( for statusbar )
+ TDEIO::filesize_t m_iTotalSize;
+ unsigned long m_iTotalFiles;
+ TDEIO::filesize_t m_iProcessedSize;
+ unsigned long m_iProcessedFiles;
+ unsigned long m_iSpeed;
+ int m_remainingSeconds;
+ TQTimer m_showTimer;
+ TQString m_fullLengthAddress;
+};
+
+class TQResizeEvent;
+class TQHideEvent;
+class TQShowEvent;
+class ProgressConfigDialog;
+class TQPopupMenu;
+class UIServerSystemTray;
+
+/**
+ * It's purpose is to show progress of IO operations.
+ * There is only one instance of this window for all jobs.
+ *
+ * All IO operations ( jobs ) are displayed in this window, one line per operation.
+ * User can cancel operations with Cancel button on toolbar.
+ *
+ * Double clicking an item in the list opens a small download window ( DefaultProgress ).
+ *
+ * @short Graphical server for progress information with an optional all-in-one progress window.
+ * @author David Faure <faure@kde.org>
+ * @author Matej Koss <koss@miesto.sk>
+ *
+ * @internal
+ */
+class TDEIO_EXPORT UIServer : public KMainWindow, public DCOPObject {
+
+ K_DCOP
+ Q_OBJECT
+
+ UIServer();
+ virtual ~UIServer();
+
+public:
+ static UIServer* createInstance();
+
+k_dcop:
+
+ /**
+ * Signal a new job
+ * @param appId the DCOP application id of the job's parent application
+ * @see TDEIO::Observer::newJob
+ * @param showProgress whether to popup the progress for the job.
+ * Usually true, but may be false when we use tdeio_uiserver for
+ * other things, like SSL dialogs.
+ * @return the job id
+ */
+ int newJob( TQCString appId, bool showProgress );
+
+ ASYNC jobFinished( int id );
+
+ ASYNC totalSize( int id, unsigned long size );
+ ASYNC totalSize64( int id, TDEIO::filesize_t size );
+ ASYNC totalFiles( int id, unsigned long files );
+ ASYNC totalDirs( int id, unsigned long dirs );
+
+ ASYNC processedSize( int id, unsigned long bytes );
+ ASYNC processedSize64( int id, TDEIO::filesize_t bytes );
+ ASYNC processedFiles( int id, unsigned long files );
+ ASYNC processedDirs( int id, unsigned long dirs );
+
+ ASYNC percent( int id, unsigned long ipercent );
+ ASYNC speed( int id, unsigned long bytes_per_second );
+ ASYNC infoMessage( int id, const TQString & msg );
+
+ ASYNC copying( int id, KURL from, KURL to );
+ ASYNC moving( int id, KURL from, KURL to );
+ ASYNC deleting( int id, KURL url );
+ ASYNC transferring( int id, KURL url );
+ ASYNC creatingDir( int id, KURL dir );
+ ASYNC stating( int id, KURL url );
+
+ ASYNC mounting( int id, TQString dev, TQString point );
+ ASYNC unmounting( int id, TQString point );
+
+ ASYNC canResume( int id, unsigned long offset );
+ ASYNC canResume64( int id, TDEIO::filesize_t offset );
+
+ /**
+ * @deprecated (it blocks other apps).
+ * Use TDEIO::PasswordDialog::getNameAndPassword instead.
+ * To be removed in KDE 4.0.
+ */
+ TQByteArray openPassDlg( const TDEIO::AuthInfo &info );
+
+ /**
+ * Popup a message box.
+ * @param id The message identifier.
+ * @param type type of message box: QuestionYesNo, WarningYesNo, WarningContinueCancel...
+ * This enum is defined in slavebase.h, it currently is:
+ * QuestionYesNo = 1, WarningYesNo = 2, WarningContinueCancel = 3,
+ * WarningYesNoCancel = 4, Information = 5, SSLMessageBox = 6
+ * @param text Message string. May contain newlines.
+ * @param caption Message box title.
+ * @param buttonYes The text for the first button.
+ * The default is i18n("&Yes").
+ * @param buttonNo The text for the second button.
+ * The default is i18n("&No").
+ * Note: for ContinueCancel, buttonYes is the continue button and buttonNo is unused.
+ * and for Information, none is used.
+ * @return a button code, as defined in KMessageBox, or 0 on communication error.
+ */
+ int messageBox( int id, int type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo );
+
+ /**
+ * @deprecated (it blocks other apps).
+ * Use TDEIO::open_RenameDlg instead.
+ * To be removed in KDE 4.0.
+ */
+ TQByteArray open_RenameDlg64( int id,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ int /* TDEIO::RenameDlg_Mode */ mode,
+ TDEIO::filesize_t sizeSrc,
+ TDEIO::filesize_t sizeDest,
+ unsigned long /* time_t */ ctimeSrc,
+ unsigned long /* time_t */ ctimeDest,
+ unsigned long /* time_t */ mtimeSrc,
+ unsigned long /* time_t */ mtimeDest
+ );
+ /**
+ * @deprecated (it blocks other apps).
+ * Use TDEIO::open_RenameDlg instead.
+ * To be removed in KDE 4.0.
+ */
+ TQByteArray open_RenameDlg( int id,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ int /* TDEIO::RenameDlg_Mode */ mode,
+ unsigned long sizeSrc,
+ unsigned long sizeDest,
+ unsigned long /* time_t */ ctimeSrc,
+ unsigned long /* time_t */ ctimeDest,
+ unsigned long /* time_t */ mtimeSrc,
+ unsigned long /* time_t */ mtimeDest
+ );
+
+ /**
+ * @deprecated (it blocks other apps).
+ * Use TDEIO::open_SkipDlg instead.
+ * To be removed in KDE 4.0.
+ */
+ int open_SkipDlg( int id,
+ int /*bool*/ multi,
+ const TQString & error_text );
+
+ /**
+ * Switch to or from list mode - called by the kcontrol module
+ */
+ void setListMode( bool list );
+
+ /**
+ * Hide or show a job. Typically, we hide a job while a "skip" or "rename" dialog
+ * is being shown for this job. This prevents killing it from the uiserver.
+ */
+ void setJobVisible( int id, bool visible );
+
+ /**
+ * Show a SSL Information Dialog
+ */
+ void showSSLInfoDialog(const TQString &url, const TDEIO::MetaData &data, int mainwindow);
+
+ /**
+ * @deprecated
+ */
+ void showSSLInfoDialog(const TQString &url, const TDEIO::MetaData &data);
+
+ /*
+ * Show an SSL Certificate Selection Dialog
+ */
+ KSSLCertDlgRet showSSLCertDialog(const TQString& host, const TQStringList& certList, int mainwindow);
+
+ /*
+ * @deprecated
+ */
+ KSSLCertDlgRet showSSLCertDialog(const TQString& host, const TQStringList& certList);
+
+public slots:
+ void slotConfigure();
+ void slotRemoveSystemTrayIcon();
+protected slots:
+
+ void slotUpdate();
+ void slotQuit();
+
+ void slotCancelCurrent();
+
+ void slotToggleDefaultProgress( TQListViewItem * );
+ void slotSelection();
+
+ void slotJobCanceled( ProgressItem * );
+ void slotApplyConfig();
+ void slotShowContextMenu(KListView*, TQListViewItem *item, const TQPoint& pos);
+
+protected:
+
+ ProgressItem* findItem( int id );
+
+ virtual void resizeEvent(TQResizeEvent* e);
+ virtual bool queryClose();
+
+ void setItemVisible( ProgressItem * item, bool visible );
+
+ TQTimer* updateTimer;
+ ListProgress* listProgress;
+
+ KToolBar::BarPosition toolbarPos;
+ TQString properties;
+
+ void applySettings();
+ void readSettings();
+ void writeSettings();
+private:
+
+ void killJob( TQCString observerAppId, int progressId );
+
+ int m_initWidth;
+ int m_initHeight;
+ int m_idCancelItem;
+ bool m_bShowList;
+ bool m_showStatusBar;
+ bool m_showToolBar;
+ bool m_keepListOpen;
+ bool m_showSystemTray;
+ bool m_shuttingDown;
+
+ // true if there's a new job that hasn't been shown yet.
+ bool m_bUpdateNewJob;
+ ProgressConfigDialog *m_configDialog;
+ TQPopupMenu* m_contextMenu;
+ UIServerSystemTray *m_systemTray;
+
+ static int s_jobId;
+ friend class no_bogus_warning_from_gcc;
+};
+
+// -*- mode: c++; c-basic-offset: 2 -*-
+#endif
diff --git a/tdeio/pics/CMakeLists.txt b/tdeio/pics/CMakeLists.txt
new file mode 100644
index 000000000..b04b9c7d4
--- /dev/null
+++ b/tdeio/pics/CMakeLists.txt
@@ -0,0 +1,14 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+##### other data ################################
+
+tde_install_icons( DESTINATION ${DATA_INSTALL_DIR}/tdeio_uiserver/icons )
diff --git a/tdeio/pics/Makefile.am b/tdeio/pics/Makefile.am
new file mode 100644
index 000000000..ce10461b5
--- /dev/null
+++ b/tdeio/pics/Makefile.am
@@ -0,0 +1,3 @@
+kiouiservericonsdir = $(kde_datadir)/tdeio_uiserver/icons
+kiouiservericons_ICON = AUTO
+
diff --git a/tdeio/pics/cr16-app-tdeio_uiserver.png b/tdeio/pics/cr16-app-tdeio_uiserver.png
new file mode 100644
index 000000000..41b3f4367
--- /dev/null
+++ b/tdeio/pics/cr16-app-tdeio_uiserver.png
Binary files differ
diff --git a/tdeio/proxytype.pl b/tdeio/proxytype.pl
new file mode 100755
index 000000000..553db53f7
--- /dev/null
+++ b/tdeio/proxytype.pl
@@ -0,0 +1,11 @@
+#!/usr/bin/perl
+# the script is called with interpreter, so don't worry about the path
+
+while(<>)
+{
+ $useproxy = 1 if /UseProxy=true/;
+ $usepac = 1 if /Proxy Config Script=.*\S/;
+}
+printf ("# DELETE UseProxy\n");
+$proxytype = $useproxy ? ($usepac ? 2 : 1) : 0;
+print "ProxyType=$proxytype\n" if $proxytype;
diff --git a/tdeio/renamedlgplugin.desktop b/tdeio/renamedlgplugin.desktop
new file mode 100644
index 000000000..d6a9f8f1f
--- /dev/null
+++ b/tdeio/renamedlgplugin.desktop
@@ -0,0 +1,84 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=RenameDlg/Plugin
+Comment=Plugin for the Rename Dialog
+Comment[af]=Inplak vir die Herbenaam Dialoog
+Comment[ar]=ملحق لمربع حوار إعادة التسمية
+Comment[az]=YenidÉ™n Adlandırma Dialoqu Üçün ÆlavÉ™
+Comment[bg]=ПриÑтавка за диалога за преименуване
+Comment[bn]=পরিবরà§à¦¤à¦¨
+Comment[bs]=Dodatak za Rename dijalog
+Comment[ca]=Connector per al diàleg de reanomenar
+Comment[cs]=Modul pro přejmenovávací dialog
+Comment[csb]=Pligins dialogòwegò òkna Zmianë miona
+Comment[cy]=Ategyn am yr Ymgom Ail-enwi
+Comment[da]=Plugin til omdøbningsdialog
+Comment[de]=Erweiterung für den Umbenennen-Dialog
+Comment[el]=ΠÏόσθετο για το διάλογο μετονομασίας
+Comment[en_GB]=Plugin for the Rename Dialogue
+Comment[eo]=Kromaĵo por la alinoma dialogo
+Comment[es]=Plugin para el diálogo de renombrado
+Comment[et]=Ãœmbernimetamise dialoogi plugin
+Comment[eu]=Berrizendatze elkarrizketa-koadroen plugin-a
+Comment[fa]=وصله برای محاورۀ تغییر نام
+Comment[fi]=Lisäosa uudelleennimeämisikkunalle
+Comment[fr]=Module externe pour la boîte de dialogue de renommage
+Comment[fy]=Plugin foar it 'Omneame'-dialooch
+Comment[ga]=Breiseán le haghaidh na dialóige athainmnithe
+Comment[gl]=Plugin para o Diálogo de Renomeamento
+Comment[he]=תוסף לדו־שיח שינוי הש×
+Comment[hi]=रीनेम डायलॉग के लिठपà¥à¤²à¤—इन
+Comment[hr]=Dodatak dijaloga za preimenovanja
+Comment[hu]=Bővítőmodul az átnevezési párbeszédablakhoz
+Comment[id]=Plugin untuk Dialog Ubah Nama
+Comment[is]=Ãforrit fyrir 'endurnefna' gluggann
+Comment[it]=Plugin per la finestra di dialogo "rinomina"
+Comment[ja]=åå‰å¤‰æ›´ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ç”¨ãƒ—ラグイン
+Comment[ka]=გáƒáƒ“áƒáƒ áƒ¥áƒ›áƒ”ვის დიáƒáƒšáƒáƒ’ის მáƒáƒ“ული
+Comment[kk]=Ðтауын өзгерту диалогтың модулі
+Comment[km]=កម្មវិធីជំនួយ​ážáž¶áž„ក្នុង​សម្រាប់​ប្រអប់ ប្ážáž¼ážšážˆáŸ’មោះ
+Comment[ko]=ì´ë¦„ 바꾸기 대화창용 플러그ì¸
+Comment[lb]=Plugin fir den Ëmbenennen-Dialog
+Comment[lt]=Priedas pervadinimo dialogui
+Comment[lv]=Spraudnis PÄrsaukÅ¡anas Dialogam
+Comment[mk]=Приклучок за дијалогот за преименување
+Comment[mn]=ÐÑÑ€ өөрчилөх-Диалогийн Plugin
+Comment[ms]=Plug masuk untuk namakan semula Dialog
+Comment[mt]=Plugin għad-djalogu biex tbiddel l-isem
+Comment[nb]=Programtillegg for omnavningsdialogen
+Comment[nds]=Plugin för den Ümnömen-Dialoog
+Comment[ne]=पà¥à¤¨: नामकरण संवादका लागि पà¥à¤²à¤—इन
+Comment[nl]=Plugin voor de 'Hernoemen'-dialoog
+Comment[nn]=Tillegg til dialogen for namnebyte
+Comment[nso]=Tsenyo ya Poledisano ya Theoleswa
+Comment[pa]=ਨਾਂ-ਤਬਦੀਲੀ ਪà©à©±à¨›à¨—ਿੱਛ ਤਾਕੀ ਲਈ ਪਲੱਗਿੰਨ
+Comment[pl]=Wtyczka do okna dialogowego Zmiana nazwy
+Comment[pt]='Plugin' para a Janela de Mudança do Nome
+Comment[pt_BR]=Plug-in para o Diálogo Renomear
+Comment[ro]=Modul pentru dialogul de redenumire
+Comment[ru]=Модуль Ð´Ð»Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð° переименованиÑ
+Comment[rw]=Icomeka ry'Ikiganiro cyo guhindura izina
+Comment[se]=Lassemoduvla nammarievdadanláseža várás
+Comment[sk]=Modul pre premenovací dialóg
+Comment[sl]=Vstavek za pogovorno okno za preimenovanje
+Comment[sq]=Shtojca për Dialogun Riemrim
+Comment[sr]=Прикључак за дијалог за преименовање
+Comment[sr@Latn]=PrikljuÄak za dijalog za preimenovanje
+Comment[sv]=Insticksprogram för Byt namn-dialogrutan
+Comment[ta]=மறà¯à®ªà¯†à®¯à®°à®¿à®Ÿà®²à¯ உரையாடலà¯à®•à¯à®•à®¾à®© சொரà¯à®•à¯à®ªà¯à®ªà¯Šà®°à¯à®³à¯
+Comment[te]=పేరౠమారà±à°šà± సంభాషణ కొరకౠపà±à°²à°—à°¿à°¨à±
+Comment[tg]=Барои Тирезаи Диалогӣ Ðоми Ðав Гузоштани ПайваÑтан
+Comment[th]=ปลั๊à¸à¸­à¸´à¸™à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸¥à¹ˆà¸­à¸‡à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸Šà¸·à¹ˆà¸­
+Comment[tr]=Yeniden İsimlendir İletişim Kutusu İçin Eklenti
+Comment[tt]=İsem Quşu Dialogı öçen Östämä
+Comment[uk]=Втулок Ð´Ð»Ñ Ð´Ñ–Ð°Ð»Ð¾Ð³Ñƒ перейменуваннÑ
+Comment[uz]=Nomini oʻzgartirish dialogi uchun plagin
+Comment[uz@cyrillic]=Ðомини ўзгартириш диалоги учун плагин
+Comment[ven]=Pulagini uitela u rinulula nyambedzano
+Comment[vi]=Bộ cầm phít cho hộp thoại thay đổi tên.
+Comment[wa]=Tchôke-divins pol purnea di rlomaedje
+Comment[xh]=Iplagi yangaphakathi Yencoko yababini Yokunika igama elitsha
+Comment[zh_CN]=é‡å‘½å对è¯çš„æ’件
+Comment[zh_HK]=æ›´åå°è©±ç›’的外掛程å¼
+Comment[zh_TW]=æ›´åå°è©±ç›’的外掛程å¼
+Comment[zu]=I-plugin Yengxoxo Yokuqamba kabusha
diff --git a/tdeio/tdecmodule.desktop b/tdeio/tdecmodule.desktop
new file mode 100644
index 000000000..5cbe9b786
--- /dev/null
+++ b/tdeio/tdecmodule.desktop
@@ -0,0 +1,109 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=TDECModule
+Name=TDE Control Module
+Name[af]=TDE Beheer Module
+Name[ar]=وحدة تحكم كيدي
+Name[az]=TDE Ä°darÉ™ Modulu
+Name[be]=Модуль ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½Ñ TDE
+Name[bg]=Контролен модул на TDE
+Name[bn]=কে.ডি.ই. নিয়নà§à¦¤à§à¦°à¦£ মডিউল
+Name[br]=Mollad kreizenn ren TDE
+Name[bs]=TDE kontrolni modul
+Name[ca]=Mòdul de control del TDE
+Name[cs]=Ovládací modul TDE
+Name[csb]=Kòntrolny mòduł pùltu TDE
+Name[cy]=Modiwl Rheolaeth TDE
+Name[da]=TDE-kontrolmodul
+Name[de]=TDE-Kontrollmodul
+Name[el]=ΆÏθÏωμα ελέγχου του TDE
+Name[eo]=TDE Agordmodulo
+Name[es]=Módulo de control de TDE
+Name[et]=TDE juhtimismoodul
+Name[eu]=TDEren kontrol-modulua
+Name[fa]=پیمانۀ کنترل TDE
+Name[fi]=TDE:n ohjausmoduuli
+Name[fr]=Module de configuration de TDE
+Name[fy]=TDE konfiguraasjemodule
+Name[ga]=Modúl Rialaithe TDE
+Name[gl]=Módulo de Controlo de TDE
+Name[he]=מודול תצורה של TDE
+Name[hi]=केडीई नियंतà¥à¤°à¤£ घटक
+Name[hr]=TDE kontrolni modul
+Name[hu]=TDE beállítómodul
+Name[id]=Modul Kontrol TDE
+Name[is]=TDE stjórneining
+Name[it]=Modulo di controllo TDE
+Name[ja]=TDE コントロールモジュール
+Name[ka]=TDE-ს კáƒáƒœáƒ¢áƒ áƒáƒšáƒ˜áƒ¡ პულტი
+Name[kk]=TDE баÑқару модулі
+Name[km]=ម៉ូឌុល​ážáŸ’ážšáž½ážâ€‹áž–áž·áž“áž·ážáŸ’យ​របស់ TDE
+Name[ko]=TDE 제어 모듈
+Name[lb]=TDE-Kontrollmodul
+Name[lt]=TDE valdymo modulis
+Name[lv]=TDE kontroles modulis
+Name[mk]=TDE Контролен Модул
+Name[mn]=TDED-Ð¥Ñналтын Модул
+Name[ms]=Modul Kawalan TDE
+Name[nb]=TDE kontrollpanel-modul
+Name[nds]=TDE-Kuntrullmoduul
+Name[ne]=TDE नियनà¥à¤¤à¥à¤°à¤£ मोडà¥à¤¯à¥à¤²
+Name[nl]=TDE Configuratiemodule
+Name[nn]=TDE-kontrollmodul
+Name[nso]=Seripa sa Taolo ya TDE
+Name[pa]=TDE ਕੰਟਰੋਲ ਮੈਡੀਊਲ
+Name[pl]=Moduł centrum sterowania TDE
+Name[pt]=Módulo de Controlo do TDE
+Name[pt_BR]=Módulo de Controle do TDE
+Name[ro]=Modul de control TDE
+Name[ru]=Модуль ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ TDE
+Name[rw]=Igice cy'Igenzura TDE
+Name[se]=TDE stivrrenmoduvla
+Name[sk]=Ovládací modul TDE
+Name[sl]=Nadzorni modul TDE
+Name[sq]=Modula Kontrolues - TDE
+Name[sr]=TDE-ов контролни модул
+Name[sr@Latn]=TDE-ov kontrolni modul
+Name[ss]=Sahluko sekulawula se TDE
+Name[sv]=TDE-inställningsmodul
+Name[ta]=கேடிஇ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ கூறà¯
+Name[te]=కెడిఈ నియంతà±à°°à°£ మాడà±à°¯à±‚à°²à±
+Name[tg]=Модулӣ TDE Control
+Name[th]=โมดูลควบคุมของ TDE
+Name[tr]=TDE Kontrol Modülü
+Name[tt]=TDE İdärä Modulı
+Name[uk]=Модуль центра ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ TDE
+Name[uz]=TDE boshqaruv moduli
+Name[uz@cyrillic]=TDE бошқарув модули
+Name[ven]=Phanele ndangula ya phirinthara
+Name[vi]=Mô-Ä‘un Ä‘iá»u khiển TDE
+Name[wa]=Module di contrôle TDE
+Name[xh]=Ulawulo Lwesicatshulwa we TDE
+Name[zh_CN]=TDE 控制模å—
+Name[zh_HK]=TDE 控制模組
+Name[zh_TW]=TDE 控制模組
+Name[zu]=Ingxenye ye-TDE Control
+
+[PropertyDef::X-TDE-FactoryName]
+Type=TQString
+
+[PropertyDef::X-TDE-RootOnly]
+Type=bool
+
+# a list of all components this KCM belongs to
+[PropertyDef::X-TDE-ParentComponents]
+Type=TQStringList
+
+# the id of the parent in the TreeList
+[PropertyDef::X-TDE-CfgDlgHierarchy]
+Type=TQString
+
+# sets the order of the modules in the TreeList/IconList
+[PropertyDef::X-TDE-Weight]
+Type=int
+
+[PropertyDef::X-TDE-RootOnly]
+Type=bool
+
+[PropertyDef::X-TDE-IsHiddenByDefault]
+Type=bool
diff --git a/tdeio/tdefile/CMakeLists.txt b/tdeio/tdefile/CMakeLists.txt
new file mode 100644
index 000000000..4fa7b3e82
--- /dev/null
+++ b/tdeio/tdefile/CMakeLists.txt
@@ -0,0 +1,76 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdefx
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/bookmarks
+ ${LIBART_INCLUDE_DIRS}
+)
+
+
+##### headers ###################################
+
+install( FILES
+ tdefiledialog.h kencodingfiledialog.h
+ kdiroperator.h tdefileview.h tdefilefiltercombo.h
+ tdefiledetailview.h kcombiview.h kdiskfreesp.h
+ tdefileiconview.h krecentdocument.h
+ kurlrequester.h tdefilepreview.h tdefile.h
+ kurlcombobox.h kurlrequesterdlg.h kopenwith.h kpropsdlg.h
+ kicondialog.h kdirsize.h kpreviewwidgetbase.h kimagefilepreview.h tdefilesharedlg.h
+ tdefiletreeview.h tdefiletreeviewitem.h tdefiletreebranch.h
+ kdirselectdialog.h kurlbar.h kpropertiesdialog.h knotifydialog.h
+ kcustommenueditor.h ${CMAKE_CURRENT_BINARY_DIR}/knotifywidgetbase.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} )
+
+
+##### other data ################################
+
+install( FILES
+ kpropsdlgplugin.desktop
+ DESTINATION ${SERVICETYPES_INSTALL_DIR} )
+
+
+##### tdefile #####################################
+
+set( target tdefile )
+
+set( ${target}_SRCS
+ tdefilefiltercombo.cpp tdefileview.cpp tdefileiconview.cpp
+ krecentdocument.cpp tdefiledialog.cpp kdiroperator.cpp
+ tdefiledetailview.cpp kcombiview.cpp kurlrequester.cpp
+ tdefilepreview.cpp kurlcombobox.cpp kurlrequesterdlg.cpp
+ kopenwith.cpp kpropertiesdialog.cpp kicondialog.cpp
+ kdirsize.cpp krecentdirs.cpp kdiskfreesp.cpp kimagefilepreview.cpp
+ tdefilesharedlg.cpp kurlbar.cpp kmetaprops.cpp kpreviewprops.cpp
+ tdefiletreeview.cpp tdefiletreeviewitem.cpp tdefiletreebranch.cpp
+ kdirselectdialog.cpp tdefilebookmarkhandler.cpp tdefilemetainfowidget.cpp
+ kcustommenueditor.cpp knotifywidgetbase.ui knotifydialog.cpp
+ tdefilespeedbar.cpp kpreviewwidgetbase.cpp tdefilemetapreview.cpp
+ kpropertiesdesktopbase.ui kpropertiesdesktopadvbase.ui
+ kpropertiesmimetypebase.ui kencodingfiledialog.cpp
+ kacleditwidget.cpp
+)
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+)
diff --git a/tdeio/tdefile/ChangeLog b/tdeio/tdefile/ChangeLog
new file mode 100644
index 000000000..79ac59808
--- /dev/null
+++ b/tdeio/tdefile/ChangeLog
@@ -0,0 +1,725 @@
+Sat Feb 26 00:26:55 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp:
+ lottsa changes, e.g. action handling more clear now.
+ fixed completed item not clearning the previous selection
+
+ * tdefileviewitem.cpp:
+ fixed unreadable pixmap not shown, when files were deleted
+
+ * tdefiledialog.cpp (selectedURLs):
+ re-enabled the hack to support multi-selection, until we have something
+ better
+
+ * kcombiview.*:
+ forward the sorting to the right view (or should it apply to the dir-
+ view as well?) Sort of broken tho.
+
+Sun Feb 20 01:50:44 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.*, tdefiledialog.* (saveConfig):
+ implemented loading, saving and applying configuration
+
+ * tdefiledialog.cpp (setURL):
+ KDirComboBox is now a combo for recent directories as well as the
+ root-dir, home-dir and Desktop-dir.
+ Recent dirs will be saved in kdeglobals.
+
+Fri Feb 18 23:35:04 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefilefilter.cpp (eventFilter):
+ intercept Key_Return and Key_Enter in the filter-combo and emit
+ filterChanged instead of letting the dialog close
+
+Thu Feb 17 19:09:54 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledialog.{cpp,h} (KDirComboBox):
+ Added KDirComboBox and replaced the directory combobox with it. It
+ even does something now :) Items need to be indented tho.
+
+ * tdefilereader.cpp, kdiroperator.{cpp,h}:
+ fixed showHidden default
+
+Tue Feb 15 14:21:41 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefile.h (class KFile):
+ added a small class that contains all the enums now.
+ cleaned up the enums (hope not too many apps will be broken)
+ added flags for "Existing files only" and "local files only"
+
+ * all views (setSelected()):
+ replaced highlightItem(item) with setSelected(item, bool) which makes
+ it more suitable and more consistent with Qt.
+ added selectionChanged() method (necessary for multiselection)
+
+ * tdefileview.*:
+ added invertSelection()
+
+ * tdefiledialog.cpp:
+ made it work with multiselection
+ added static methods for multiselection
+ added getOpenURL(), getOpenURLs and getSaveURL()
+
+ * kdiroperator.cpp (setSorting):
+ added setSorting() and sorting() to keep sorting when switching views
+ a few cosmetic and KAction changes
+
+Sun Feb 13 00:45:12 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledialog.cpp (completion):
+ small fix: completion and auto-directory following works also
+ without protocol-part in the location.
+
+Sat Feb 12 15:30:40 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileview.h:
+ made setSorting() and sortReversed() virtual so that subclasses
+ can intercept that to show sorting order
+
+ * tdefiledetailview.cpp,h (setSortIndicator):
+ enable header-clicking again to set the sorting
+
+Fri Feb 11 12:17:59 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledialog.cpp (KFileDialog):
+ fixed filefilter not being applied in constructor
+
+Thu Feb 10 17:06:36 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp (connectView):
+ - Now that KToggleAction is fixed, I can commit the new stuff:
+ Offer Actions for all the common functionality, i.e. sorting, setting
+ the view, home(), cdUp(), back, forward, etc.
+ All actions are exposed through a QActionCollection
+
+ BTW, I'd really like to have a way to change the state of an action
+ without it calling the associated slot. For now I use blockSignals()
+ (thanks, Simon), but this sucks.
+
+ - renamed fileList to fileView (that was an old relic of KDE 1)
+
+ * tdefiledialog.*:
+ - make use of the new Actions and fill the toolbar again (up, back,
+ forward, reload, home).
+
+ - the combo in the toolbar is going to change, it does nothing now
+ (only shows the Root and Desktop dirs with a nice icon).
+
+Thu Feb 10 12:59:29 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * kdiroperator.cpp (insertNewFiles):
+ aahhh, finally fixed that infinite loop in KFileView::mergeLists
+ clear the view before calling view->addItemList( currentContents );
+
+ * tdefilereader.cpp (setURL):
+ don't disable dirWatch update (setAutoUpdate) when setting a remote URL
+
+Fri Feb 4 12:42:37 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledetailview.cpp (insertItem):
+ - don't let QListView sort the items
+ I disabled clicking at the headers for now, will fix that later
+ - don't flicker on mimetype-pixmap update
+
+Thu Feb 3 12:15:16 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileview.h + all views where necessary
+ added selectAll()
+ added isSelected( const KFileViewItem * )
+ added const KFileViewItemList * selectedItems()
+ added const KFileViewItemList * items()
+
+ spiced up documentation of KFileView a bit
+
+Sun Jan 30 22:20:14 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileviewitem.cpp (pixmap):
+ fixed some issues for different pixmap sizes
+
+ * tdefileiconview.{h,cpp} (setPixmapSize):
+ added configurability for different pixmap sizes
+
+Sun Jan 30 16:49:12 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileview.h + all views:
+ A view can now have a name (setViewName() and viewName())
+ This is useful to differentiate views and to display the names in a
+ popupmenu for switching between views.
+
+Sun Jan 30 12:41:04 2000 Werner Trobin <wtrobin@carinthia.com>
+ The preview mode works again. It's very similar to the Qt-2.1 QFD
+ preview mode - but it's not totally the same. There are some rough
+ edges which have to be ironed out, but it works :)
+ For further information, see tdefilepreview.*
+ Note: kpreview and so on are obsolete (IMHO)
+
+Sat Jan 29 15:33:37 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ Time to add some changelogs again, all the recent hard work of the
+ restructuring is only in CVS-log...
+
+ * tdefileview.cpp (compareItems):
+ - added support to disable sorting directories first (QDir::DirsFirst)
+ - added support to sort by date and to sort reversed
+ - removed unused findCompletion method
+ - sort case insensitive by default
+ - some optimization for mergeList
+ - fixed infinite loop in mergeLists, when the lists are the same
+ (I think another one is still there, but I'm tired now)
+ - changed setSortMode stuff: Switching-mode replaced with
+ sortReversed(). The enum Switching will be removed, soon.
+ - made setSortMode public
+
+ * tdefileviewitem.cpp:
+ - added time_t mTime() to enable sorting by modification time
+
+ * kdiroperator.cpp:
+ - offer sorting options in popupmenu
+ - use checkAccess before creating directories. I guess this will again
+ change when the new kio will be used, tho.
+ - show progress widget at the bottom (otherwise the header of e.g.
+ the detail-view would be covered).
+ - Added LGPL copyright header
+
+ * tdefilewidget.cpp (connectSignals):
+ - connect to all signals of KDirOperator
+ - directly connect SIGNAL to SIGNAL -> removed slotFileHighlighted etc.
+ - fixed some sorting/merging bugs
+
+ * {tdefiledialog,kdiroperator}.{cpp,h};
+ - support for disabling chdir (some apps may not want KFileDialog /
+ KFileReader change the working directory under their feet)
+ - Added LGPL header in cpp-file
+
+ * tdefilereader.cpp (stat):
+ - fixed: some special files were recognized as directories
+
+ * kfstest.cpp:
+ - added test for KFileWidget (widget -> KFileWidget,
+ diroperator -> KDirOperator)
+
+Sun Oct 31 00:56:23 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileinfo.cpp (readUserInfo): Don't call getpwnam() and getgrgid()
+ all the time over and over again! This opens and parses /etc/passwd
+ or /etc/group with every call!
+ Now we load /etc/passwd and /etc/group once and store the interesting
+ stuff in static QMaps, which need to be freed with KFileInfo::cleanup()
+ cleanup() is called from KFileBaseDialog's destructor.
+
+ This speeds up KFileDialog a LOT!
+
+Sat Oct 23 01:55:00 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledetaillist.cpp (key): hopefully implemented correct mapping
+ from KFileInfo to QListViewItem and back. I had a hard time convincing
+ QListView that KFileInfoContents knows best where to insert an item
+ Now the detaillist is even usable :)
+ Fixed a problem with selection and highlighting
+ Disable clicking on listview headers that can't be used for sorting
+
+ * tdefileinfocontents.cpp (setSorting): call insertItem() with a correct
+ (is it?) index, instead of -1
+
+Thu Oct 21 23:18:54 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefiledialog.cpp (init): removed "[development only] from tooltip
+ (sorry to break the translations, but this HAD to go)
+
+ * don't update anything when leaving the configure-dialog with Cancel
+
+Wed Oct 20 15:07:16 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefileinfo.cpp,h: implemented KFileInfo::filePath() and fixed
+ KFileInfo::absURL() not being set in some cases
+
+ * kdir.cpp: fixed a buglet in the path (double slashes)
+
+ * tdefiledetaillist.cpp (KFileDetailList): improved selecting files
+ (single click, double click, Return-key)
+ but the mapping from QListViewItem to KFileInfo is still quite broken
+
+1999-06-09 Woohyun JANG <louis@mizi.co.kr>
+
+ * kdir.cpp: used QString::local8Bit() instead of QString::ascii()
+ for file names and directory names.
+
+ * tdefiledialog.cpp: used QStringList instead of QStrIList.
+
+1999-01-14 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: fixed some GUI problems and moved all default
+ configurations into config-tdefile.h.
+ Changed some default values, so that users that never looked into
+ the config dialog gets a nice suprise with 1.1 ;-)
+
+ * tdefiledialog.cpp: changed selectedFile to return decoded path instead
+ of encoded one
+
+Thu Jan 7 23:14:39 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefilesimpleview.cpp (keyPressEvent): fixed segfault on keypress,
+ when there were no files at all in the list
+
+1998-12-19 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: fixing an ugly bug when "." is used as argument
+
+Mon Dec 14 23:00:41 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefilebookmark.cpp: renamed class KBookmark to KFileBookmark to
+ avoid problems with KFM's KBookmark class. Renamed bookmark.* to
+ tdefilebookmark.*, too and changed all occurrences of bookmark.* to
+ tdefilebookmark.* (especially all the .po-files)
+
+Wed Dec 2 15:59:13 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * tdefilesimpleview.cpp: Fixed some more keyboard navigation bugs.
+ Added method isColCompletelyVisible( int col ), now you can scroll
+ perfectly to make items completely visible.
+ Moreover, in resizeEvent() the number of columns was not calculated
+ correctly in a special case.
+ And the currently selected item is rehighlighted correctly after
+ resizing, now.
+
+1998-10-12 Jochen Küpper <jochen@uni-duesseldorf.de>
+
+ * tdefiledialog.cpp (okPressed): Changed okPressed to store the correct
+ filename before leaving the dialog.
+
+1998-06-07 Stephan Kulow <coolo@kde.org>
+
+ * tdefilesimpleview.cpp: added some checks to prevent division with
+ zero using the latest qt snapshots
+
+ * tdefilesimpleview.cpp: added a repaint call after a resize
+
+ * tdefiledialog.cpp: new experimental button order
+
+ * tdefiledialog.cpp: added lastDirectory to remember the last visited
+ directory for next open
+
+1998-05-24 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: use setSelection also for the initial filename
+ given
+
+ * tdefiledialog.cpp: introduced KFileFilter to make an abstraction
+ for the used filter widget. Currently only QComboBox is supported,
+ but this may change in the future
+
+1998-05-20 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: changed the accelerator for completion
+ to CTRL-T
+
+ * tdefiledialog.cpp: fixed the setSelection() feature
+
+1998-05-19 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.h: added setSelection
+
+1998-05-18 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: bugfixes
+
+1998-05-15 Stephan Kulow <coolo@kde.org>
+
+ * tdefileinfocontents.cpp: some more changes and speed ups
+ (caching and some other little things)
+
+1998-05-14 Stephan Kulow <coolo@kde.org>
+
+ * tdefileinfocontents.cpp: added addItemList
+
+ * tdefileinfocontents.h: introduced KFileInfoContentsSignaler
+
+ * tdefileinfocontents.cpp: some more speed improvment
+
+1998-05-10 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: tried to speed up the refresh
+
+1998-04-17 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledetaillist.cpp: implemented the date field
+
+ * tdefiledetaillist.cpp: made the columns wider
+
+ * tdefileinfocontents.cpp: use the new icons by Mark
+
+Thu Apr 16 10:51:24 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * tdefiledialog.*: some small fixes concerning preview
+
+ * tdefileinfocontents.cpp: fixed sorting bug in preview
+
+ * tdefilepreview.*: small bug fixes
+
+ * kpreview.*: small bug fixes
+
+ * added some documentation
+
+1998-04-15 Stephan Kulow <coolo@kde.org>
+
+ * tdefilepreview.cpp: use a list box instead of simple view
+
+ * tdefiledialog.cpp: fixed an ugly bug
+
+1998-04-14 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialogconf.cpp: removed the width/height sliders
+
+ * tdefiledialog.cpp: save the width and height on exit
+
+ * tdefiledialogconf.cpp: added more guys to the about box
+
+ * tdefiledialog.h: removed init*Children. They were useless
+
+ * tdefiledialog.cpp: set the default size to a useful value
+
+Mon Apr 6 17:30:18 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * tdefilepreview.*: restructured previewing, one can now easily
+ use custom previewers, dynamically
+
+ * kpreview.*: changes for allowing custom previewers, two previewers
+ are hardcoded so far
+
+ * tdefiledialog.*: changes changes for allowing custom previewers
+
+ * kfstest.cpp: changes to preview mode
+
+ * xview.*: QimageIO module allowing the visual-schnauzer generated
+ images to be loaded
+
+1998-04-06 Stephan Kulow <coolo@kde.org>
+
+ * debug.h: added debugC. An empty macro to hide debug output
+
+Thu Apr 2 19:39:37 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kpreview.*: widget which for now shows some info about a
+ file/folder along with the first 20-30 lines of it
+
+ * tdefilepreview.*: added a new view which has a preview of any text
+ file in the right part
+
+ * kfstest.cpp: added the new mode "preview" which shows the above
+ view
+
+1998-03-30 Stephan Kulow <coolo@kde.org>
+
+ * tdefilesimpleview.cpp: fixed highlightning
+
+ * tdefiledialog.cpp: some fixes for the dir selection
+
+ * tdefiledialog.h: Moved KFileDialog into KFileBaseDialog and made
+ KFileDialog and KDirDialog a derived class of KFileBaseDialog to
+ make this virtual functions work
+
+Mon Mar 30 17:53:20 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * kcombiview.cpp: bug fixes for completion & corresponding
+ highlighting
+
+ * tdefiledialog.cpp: small bug fix, too much copying into location
+
+ * tdefileinfocontents.cpp: completion slightly remodeled, should
+ work in all views now
+
+ * tdefileinfocontents.h: changed nameList to case insensitive
+ list
+
+1998-03-28 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: changed the filter separator to \n.
+ This looks nicer in the source code of the call
+
+Sat Mar 28 14:49:00 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: changed the meaning of the dirName argument
+
+ * tdefiledialog.h: added getShowFilter
+
+Thu Mar 26 12:47:42 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefilesimpleview.cpp: improved scrolling in simple view
+
+ * tdefileinfocontents.cpp: add a / after a found dir
+
+ * tdefiledialog.cpp: fixed bug for !showFilter
+
+Wed Mar 25 18:39:09 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * tdefileinfocontents.cpp: completion now working
+
+ * kcombiview.cpp: changed behavior for completion, it
+ now highlights completed directory and file
+
+Tue Mar 24 16:08:46 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * tdefileinfocontents.cpp: sorting now fully working
+
+ * tdefiledialog.cpp: modifications for sorting in the on the
+ fly reconfiguration
+
+ * tdefileinfocontents.*: modification to the constructor
+ to pass along the sorting
+
+ * tdefiledetaillist.*: modification to the constructor
+ to pass along the sorting
+
+ * kcombiview.*: modification to the constructor
+ to pass along the sorting
+
+ * tdefilesimpleview.*: modification to the constructor
+ to pass along the sorting
+
+Tue Mar 24 10:45:15 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ * tdefileinfocontents.cpp: sorting fixed, the feature of keeping
+ directories grouped is still missing though
+
+Mon Mar 23 22:59:18 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledetaillist.h: added acceptsFiles() and acceptsDirs() to
+ make dirs-only views useful
+
+ * tdefileinfocontents.cpp: OK, completion is back again, but
+ currently not working, because the code is missing ;-)
+
+Mon Mar 23 00:08:02 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: moved all GM related things into initGUI() to
+ make recreation possible
+
+Sun Mar 22 00:22:46 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: use KShellProcess now
+
+ * tdefiledialog.h: added virtual function initFileList to made
+ KFileDialog customable
+
+ * tdefiledialog.cpp: show a combo box, in case more filters are given
+
+ * tdefiledialog.cpp: some bug fixes. I can't get the sorting to work
+
+ * Makefile.am: install some toolbar pixmaps
+
+ * tdefiledetailview.cpp: added pixmaps to the detail view
+
+ * Kfiledialog.cpp: made KComboView customable through virtual
+ functions
+
+ * kcombiview.cpp: took out the completion for now, added
+ kcombiview and some little changes in setCurrentItem
+
+ * kdirlistbox.cpp: fixed the use of single click
+
+ * kdir.h: moved the header files a little bit to remove
+ some dependencies
+
+ * kdirlistbox.cpp: KDirListBox is now a KFileInfoContents too
+
+ * tdefiledialog.cpp: another change in the API. It uses now QSignal.
+ I didn't liked the old way
+
+1998-03-21 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: implemented mixDirsAndFiles. Need some work and currently
+ only supported by the simple view
+
+Sat Mar 21 01:00:48 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefilesimpleview.cpp: added pixmaps to indicate access on the file
+
+ * tdefilesimpleview.cpp: improved keyboard navigation
+
+ * tdefilesimpleview.cpp: first almost working simple view
+
+ * tdefilesimpleview.cpp: started implementing a simple view. Needs
+ still some work
+
+
+Fri Mar 20 22:42:31 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefileinfocontents.h: bugfixes
+
+ * tdefileinfo.cpp: KFileInfo is no longer a derived class of
+ QFileInfo. This should reduce memory use too
+
+ * tdefileinfocontents.h: moved the actual sorting in
+ KFileInfoContents. Derived classes are for viewing only
+
+ * tdefiledialog.h: fixed some header files locations
+
+1998-03-20 Stephan Kulow <coolo@kde.org>
+
+ * tdefileinfo.cpp: show lockedfolder.xpm for folders, that are not
+ allowed to enter or read
+
+ * tdefiledialog.cpp: bug fixes
+
+Fri Mar 20 13:10:11 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * kfilgdialog.*, remodeled the configuration dialog to reflect the
+ current possible settings
+ * tdefiledetailList.cpp: added the PageUp PageDown navigation
+
+1998-03-19 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: fixed the forward/back back reported by
+ Stefan Tafener
+
+1998-03-18 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: set the initial focus to the line edit
+
+ * tdefiledialog.cpp: use kapp->invokeHTMLHelp now
+
+ * tdefiledialog.h: removed treeList, since it's not implemented
+
+Wed Mar 18 02:56:32 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledetaillist.cpp: fixed sorting again
+
+1998-03-17 Stephan Kulow <coolo@kde.org>
+
+ * added a virtual class KInfoListContent to make an abstraction
+ for the file contents. Currently there is just one implementation
+ KFileDetailList
+
+1998-03-16 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: don't accept the first entry of the combo
+ box as a file name
+
+ * tdefiledialog.cpp: added an accelerator for completion, since
+ KCombo no longer emits such a thing (currently CTRL-A)
+
+ * kdir.cpp: disable parent button in /
+
+ * tdefiledialog.cpp: fixed layout of mkdir dialog
+
+ * kdir.cpp: use currentDir instead of homeDir as default
+
+ * tdefiledialog.cpp: added member acceptOnlyExisting and set it
+ for now to always false. I guess, we need an extra parameter for this
+
+ * tdefiledialog.cpp: changed dirList and fileList to fix the
+ focus handling
+
+ * tdefileinfolistwidget.cpp: added focus handling
+
+ * tdefileinfolistwidget.cpp: added keyevent handling to handle
+ cursor and enter
+
+ * tdefiledialog.cpp: changed the filter edit to a QLineEdit, since
+ we don't need the completion, but the tabing for focus changes
+
+Mon Mar 16 11:36:07 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * added create directory, pops up a modal dialog, should add
+ a mkdir method to kdir in near future
+
+Mon Mar 16 20:04:00 1998 Martin Jones <mjones@kde.org>
+ * Added booktoken.* to remove dependancy on tdehtmlw and jscript
+
+Thu Mar 12 09:32:06 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ * worked on the dir and file completion, should do both now,
+ text in the location box will be added as much as possible
+ (right now it's the lowest denominator of dir&file&location-text)
+ * added sorting for the detailed list, so far only name and size
+ sorting implemented
+ * added single click selection for directories
+ * added a status line, which shows the number of directories and
+ files showed
+
+Thu Mar 12 00:36:05 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: made a library out of the file selector
+ * tdefiledialog.cpp: added an extra parameter acceptURLs to seperate
+ between getOpenFileName and getOpenFileURL
+
+Sun Feb 15 23:13:47 1998 Richard Moore <rich@kde.org>
+
+ * More work on the bookmarks - they should work properly now, you
+ must create the directory ~/.kde/share/apps/tdeui to store the
+ bookmarks in.
+
+ * Regenerated docs
+
+Thu Feb 12 17:27:51 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefileinfo.cpp: added determination of group and other things to
+ be display the correct values in the tdefileinfolistwidget
+
+Thu Feb 12 16:01:44 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: removed the #ifdef code. Now the combo box for
+ the path is the only option
+
+Tue Feb 10 01:09:16 1998 Richard Moore <rich@kde.org>
+
+ * Added details widget - this is currently selected by a config
+ file entry, but it there should be a toolbar button. Many changes
+ to tdefiledialog to allow the switch (need an abstract fileview class).
+
+Fri Feb 6 18:08:14 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: replaced the location lineedit with an combo
+ box. Currently configurable with a compiler define.
+
+Fri Feb 6 17:07:26 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: fixed the en- and decoding of URLs. Now it's
+ possible to move into directories called "sdasd#sdsd" for example
+
+Sat Jan 24 17:18:10 1998 Mario Weilguni <mweilguni@sime.com>
+
+ * fixed a bug in kdir.cpp/parsePermissions()
+
+ * implemented error handling for KFM URL errors
+
+Tue Jan 20 00:51:55 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: some fixes to make kfm support more robust
+
+Mon Jan 19 01:10:11 1998 Stephan Kulow <coolo@kde.org>
+
+ * kdir.cpp: re-added ftp support
+
+ * tdefiledialog.cpp: take care of the case, when the user enters a
+ complete filename
+
+ * kdir.cpp: added isReadable() to indicate, that the dir is not
+ correct
+
+ * tdefiledialog.cpp: played a little bit with the geometry management
+
+
+Sun Jan 18 15:00:06 1998 Stephan Kulow <coolo@kde.org>
+
+ * tdefiledialog.cpp: - back/forward work now as expected
+ - show the correct filter
+ - the combo box works now as expected
+
+ * kdir.cpp: check if the directory is correct (for local
+ files). If not, go back to the old value
+
+ * tdefiledialog.cpp: - disable parent button, when in root
+ - treat the case, that the URL ends with "/"
+ - strip white spaces out of the location text
+
+ * tdefileinfo.cpp: don't insert broken links
+
+ * tdefiledialog.cpp: just set the dir, if it's different
+ from the already set one
+
+Sun Jan 18 11:53:32 1998 Mario Weilguni <mweilguni@sime.com>
+
+ * symbolic links to subdirectories are now correctly reported as
+ directories
+
+ * symbolic links are show as italic text
+
+ * The toolbar button "Home" works now as expected
diff --git a/tdeio/tdefile/Makefile.am b/tdeio/tdefile/Makefile.am
new file mode 100644
index 000000000..ab8561e7c
--- /dev/null
+++ b/tdeio/tdefile/Makefile.am
@@ -0,0 +1,78 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Stephan Kulow (coolo@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 General Public License
+# along with this library; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+
+INCLUDES= -I$(srcdir)/../libltdl/ -I$(top_srcdir) -I$(top_srcdir)/tdefx \
+ -I$(top_builddir)/tdeio/tdeio -I$(top_srcdir)/tdeio/bookmarks $(all_includes) $(LIBART_CFLAGS)
+
+noinst_LTLIBRARIES = libtdefile.la
+
+METASOURCES = AUTO
+
+#SUBDIRS = . acl_prop_page
+
+include_HEADERS = tdefiledialog.h kencodingfiledialog.h\
+ kdiroperator.h tdefileview.h tdefilefiltercombo.h \
+ tdefiledetailview.h kcombiview.h kdiskfreesp.h \
+ tdefileiconview.h krecentdocument.h \
+ kurlrequester.h tdefilepreview.h tdefile.h \
+ kurlcombobox.h kurlrequesterdlg.h kopenwith.h kpropsdlg.h \
+ kicondialog.h kdirsize.h kpreviewwidgetbase.h kimagefilepreview.h tdefilesharedlg.h \
+ tdefiletreeview.h tdefiletreeviewitem.h tdefiletreebranch.h \
+ kdirselectdialog.h kurlbar.h kpropertiesdialog.h knotifydialog.h \
+ kcustommenueditor.h knotifywidgetbase.h
+
+noinst_HEADERS = config-tdefile.h krecentdirs.h kmetaprops.h \
+ tdefilebookmarkhandler.h tdefilemetainfowidget.h kopenwith_p.h \
+ tdefilespeedbar.h kpreviewprops.h kacleditwidget.h kacleditwidget_p.h images.h
+
+libtdefile_la_SOURCES = \
+ tdefilefiltercombo.cpp \
+ tdefileview.cpp tdefileiconview.cpp \
+ krecentdocument.cpp tdefiledialog.cpp kdiroperator.cpp \
+ tdefiledetailview.cpp kcombiview.cpp kurlrequester.cpp \
+ tdefilepreview.cpp kurlcombobox.cpp kurlrequesterdlg.cpp \
+ kopenwith.cpp kpropertiesdialog.cpp kicondialog.cpp kdirsize.cpp \
+ krecentdirs.cpp kdiskfreesp.cpp kimagefilepreview.cpp tdefilesharedlg.cpp \
+ kurlbar.cpp kmetaprops.cpp kpreviewprops.cpp \
+ tdefiletreeview.cpp tdefiletreeviewitem.cpp tdefiletreebranch.cpp \
+ kdirselectdialog.cpp tdefilebookmarkhandler.cpp \
+ tdefilemetainfowidget.cpp kcustommenueditor.cpp knotifywidgetbase.ui \
+ knotifydialog.cpp tdefilespeedbar.cpp kpreviewwidgetbase.cpp \
+ tdefilemetapreview.cpp kpropertiesdesktopbase.ui \
+ kpropertiesdesktopadvbase.ui kpropertiesmimetypebase.ui \
+ kencodingfiledialog.cpp kacleditwidget.cpp
+
+libtdefile_la_COMPILE_FIRST = $(srcdir)/../tdeio/kdirnotify_stub.h
+
+EXTRA_DIST = NOTES
+
+# convenience lib - no _LDFLAGS or _LIBADD !
+
+servicetype_DATA = kpropsdlgplugin.desktop
+servicetypedir = $(kde_servicetypesdir)
+
+
+#Can't be a module, we need to link to it for readConfig
+#kde_module_LTLIBRARIES = libtdefileshare.la
+#libtdefileshare_la_SOURCES = tdefileshare.cpp
+#libtdefileshare_la_LIBADD = libtdefile.la
+#libtdefileshare_la_LDFLAGS = -module $(KDE_PLUGIN)
+#kde_services_DATA = tdefilesharepropsplugin.desktop
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/tdefile/NOTES b/tdeio/tdefile/NOTES
new file mode 100644
index 000000000..ad99065be
--- /dev/null
+++ b/tdeio/tdefile/NOTES
@@ -0,0 +1,100 @@
+Rewrite
+=======
+
+Here is the result of a long discussion between the tdefile developers
+(Carsten) and the konqueror developers (Simon and David), about the plans
+for more integration between tdefile and konqueror. 16/08/2000.
+
+
+
+ KDirLister -----(1)---------------------> KFileView (3)
+ <----(2)------ [Signaller] --- | |
+ | |
+ | |
+ | |
+ | |
+ KFileIconView KFileListView
+ (4) (5)
+
+
+(1) Gives items found when listing, and the key for each item
+ (KDirLister has all the sorting code)
+(2) KFileView inherited classes emit requests for listing a new
+ directory (with a bool for treeviews), and emit requests for
+ the mimetype of a given item. If all KFileView inherited classes
+ are QScrollViews, then it could even implement the "ask for mimetype
+ of the visible icons first" algorithm, currently in KonqIconView.
+(3) KFileView, the base class for any view, knows about KFileItem, has
+ signals for dropped(), popupMenu(list of actions provided by the view),
+ has a QWidget * canvas() method, xOffset() and yOffset()
+(4) KFileIconView holds a QPtrDict to look up a QIconViewItem quickly from a
+ given KFileItem. This will help for e.g. deleteItems and refreshItems.
+(5) KFileListView holds a QPtrDict to find the QListViewItem for a
+ KFileItem. It implements different modes if we want the tree view in
+ tdefile ?
+
+
+ KFileChooserWidget
+
+This (base) class is the container widget that can contain any tdefileview and
+switch between them. It is embeddable into an application that wants a widget
+for choosing a file or directory. Features listing, selecting, popupmenu for
+switching modes, and a virtual createView( viewmode ) method, which
+only knows about the builtin views, in this class.
+It knows the current URL, has setURL(), and triggers the listing, connecting
+KFileView's requests to KDirLister's methods.
+
+ KFileManagerWidget
+
+This class inherits from KFileChooserWidget and adds the file management
+operations. It uses a KFileOperations class (taken from the current
+KonqOperations) for all KIO operations, and it uses KFileUndo, taken from
+the KonqUndo stuff. The popupMenu method is reimplemented to add those
+operations to it.
+
+ KFileWidget
+
+This class is the full widget that can be seen in the dialog. It has the
+toolbar buttons, the combo, etc. It embeds a KFileChooserWidget or a
+KFileManagerWidget, the latter being a specialisation of the former.
+
+The Konqueror side of things
+============================
+
+ KonqFileIconView
+
+Inherits KFileIconView and adds image preview - unless we want it in
+KFileIconView, and the line-up-icons algorithm, etc.
+
+ KonqFileListView
+
+Inherits KFileListView to add more stuff if needed. The mc-like text view
+could be implemented here as well, unless we want it in tdefile. Same for the
+tree view.
+
+ KonqFileManagerWidget
+
+This class inherits KFileManagerWidget and adds the konqueror stuff, like
+the enableAction signal. It also reimplements createView to create the
+konqueror versions of the views.
+
+ KonqDirPart
+
+This class inherits KParts::ReadOnlyPart, and provides a BrowserExtension.
+It integrates KonqFileManagerWidget as its KParts widget, and provides
+KActions for it.
+
+Important :
+
+Make sure to take kfind into account. It would be nice if it could use the
+same views as konqueror, to have access to all the view modes, as well as
+image preview, etc.
+
+Unrelated:
+To Add
+======
+
+Mime Mappings?
+
+Filter= ( Mime Type | shell glob list )
+Mime Type -> shell glob list
diff --git a/tdeio/tdefile/TODO b/tdeio/tdefile/TODO
new file mode 100644
index 000000000..b7bf74ea5
--- /dev/null
+++ b/tdeio/tdefile/TODO
@@ -0,0 +1,17 @@
+TODO-List for the KFileDialog and associated classes (in order of importance)
+
+- are more messageboxes necessary?
+- KFD's default dirs configurable
+- drag&drop support for the views (somehow into baseclass KFileView?
+- KFileView::setSelected( const QRegExp& )
+- separate KDirOperator, location-combo, filter-combo etc. from KFileDialog
+ to another widget (everything besides OK/Cancel buttons).
+- implement in-place editing (rename) + make it configurable in all views
+- make a simple fileview based on QListBox
+- implement KFile::PreviewInfo
+- signal KFileView::selectionCleared()
+
+If anyone wants to implement some of those, please do. In case of questions,
+don't hesitate to ask me.
+
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/tdeio/tdefile/config-tdefile.h b/tdeio/tdefile/config-tdefile.h
new file mode 100644
index 000000000..26a9ddb55
--- /dev/null
+++ b/tdeio/tdefile/config-tdefile.h
@@ -0,0 +1,32 @@
+#ifndef CONFIG_KFILE_H
+#define CONFIG_KFILE_H
+
+const int tdefile_area = 250;
+
+#define DefaultViewStyle TQString::fromLatin1("SimpleView")
+#define DefaultPannerPosition 40
+#define DefaultMixDirsAndFiles false
+#define DefaultShowStatusLine false
+#define DefaultShowHidden false
+#define DefaultCaseInsensitive true
+#define DefaultDirsFirst true
+#define DefaultSortReversed false
+#define DefaultRecentURLsNumber 15
+#define DefaultDirectoryFollowing true
+#define DefaultAutoSelectExtChecked true
+#define ConfigGroup TQString::fromLatin1("KFileDialog Settings")
+#define RecentURLs TQString::fromLatin1("Recent URLs")
+#define RecentFiles TQString::fromLatin1("Recent Files")
+#define RecentURLsNumber TQString::fromLatin1("Maximum of recent URLs")
+#define RecentFilesNumber TQString::fromLatin1("Maximum of recent files")
+#define DialogWidth TQString::fromLatin1("Width (%1)")
+#define DialogHeight TQString::fromLatin1("Height (%1)")
+#define ConfigShowStatusLine TQString::fromLatin1("ShowStatusLine")
+#define AutoDirectoryFollowing TQString::fromLatin1("Automatic directory following")
+#define PathComboCompletionMode TQString::fromLatin1("PathCombo Completionmode")
+#define LocationComboCompletionMode TQString::fromLatin1("LocationCombo Completionmode")
+#define ShowSpeedbar TQString::fromLatin1("Show Speedbar")
+#define ShowBookmarks TQString::fromLatin1("Show Bookmarks")
+#define AutoSelectExtChecked TQString::fromLatin1("Automatically select filename extension")
+
+#endif
diff --git a/tdeio/tdefile/images.h b/tdeio/tdefile/images.h
new file mode 100644
index 000000000..f544e2f0a
--- /dev/null
+++ b/tdeio/tdefile/images.h
@@ -0,0 +1,277 @@
+#ifdef USE_POSIX_ACL
+#ifndef _QEMBED_1804289383
+#define _QEMBED_1804289383
+#include <tqimage.h>
+#include <tqdict.h>
+static const QRgb group_grey_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x42484848,0xc39b9b9b,0xeab1b1b1,0xce9d9d9d,0x5a4d4d4d,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x563b3b3b,0xfdaeaeae,0xffcfcfcf,0xffcccccc,0xffcecece,
+ 0xffbababa,0x62393939,0x0,0x0,0x0,0x0,0x0,0x0,0x4525252,0x9383838,0x0,0xd0515151,0xff969696,0xff959595,
+ 0xff969696,0xff959595,0xff969696,0xdd505050,0x6000000,0x0,0x0,0x0,0xa191919,0x908f8f8f,0xebc1c1c1,0xf6c6c6c6,0xc0a1a1a1,0xf74f4f4f,
+ 0xff626262,0xff6a6a6a,0xff6c6c6c,0xff6a6a6a,0xff636363,0xfb4a4a4a,0x1a000000,0x0,0x0,0x0,0xa3828282,0xffdfdfdf,0xffdedede,0xffdddddd,
+ 0xffe0e0e0,0xffa4a4a4,0xff636363,0xff666666,0xff6a6a6a,0xff676767,0xff5f5f5f,0xe6494949,0xd000000,0x0,0x0,0x21232323,0xfca2a2a2,0xffc3c3c3,
+ 0xffc6c6c6,0xffc6c6c6,0xffc4c4c4,0xffbababa,0xff717171,0xff7e7e7e,0xff7e7e7e,0xff7d7d7d,0xfe6f6f6f,0x812b2b2b,0x0,0x0,0x0,0x3e303030,
+ 0xffa6a6a6,0xffb7b7b7,0xffbdbdbd,0xffbebebe,0xffb9b9b9,0xffacacac,0xff808080,0xff8f8f8f,0xff939393,0xff909090,0xf86b6b6b,0x34202020,0x0,0x0,
+ 0x0,0x1c191919,0xf8a5a5a5,0xffc2c2c2,0xffcccccc,0xffcecece,0xffc5c5c5,0xffbababa,0xff888888,0xffa5a5a5,0xffa4a4a4,0xffa5a5a5,0xffa1a1a1,0xd3515151,
+ 0x8030303,0x0,0x0,0x0,0x8f6f6f6f,0xffd3d3d3,0xffe2e2e2,0xffe3e3e3,0xffdbdbdb,0xff9b9b9b,0xff6f6f6f,0xff727272,0xff6e6e6e,0xff717171,
+ 0xff707070,0xff606060,0x62363636,0x0,0x0,0x0,0x6e5b5b5b,0xffb4b4b4,0xffd4d4d4,0xffdadada,0xffcecece,0xff737373,0xff656565,0xff676767,
+ 0xff696969,0xff676767,0xff636363,0xff5d5d5d,0xc44b4b4b,0x0,0x0,0x27343434,0xf5a5a5a5,0xffd1d1d1,0xffd2d2d2,0xffd1d1d1,0xffd1d1d1,0xffc3c3c3,
+ 0xff7b7b7b,0xff6f6f6f,0xff727272,0xff6f6f6f,0xff696969,0xff626262,0xf7606060,0x16050505,0x0,0xa07d7d7d,0xffb8b8b8,0xffc0c0c0,0xffc2c2c2,0xffc1c1c1,
+ 0xffc1c1c1,0xffbbbbbb,0xffa6a6a6,0xff868686,0xff858585,0xff838383,0xff838383,0xff878787,0xe95e5e5e,0x19050505,0xd141414,0xf0a2a2a2,0xffbdbdbd,0xffc6c6c6,
+ 0xffcbcbcb,0xffcbcbcb,0xffc8c8c8,0xffc0c0c0,0xffb8b8b8,0xef8b8b8b,0xd6707070,0xd26a6a6a,0xbb595959,0x82363636,0x24070707,0x0,0x44505050,0xffc0c0c0,
+ 0xffc7c7c7,0xffd2d2d2,0xffd9d9d9,0xffdadada,0xffd4d4d4,0xffcacaca,0xffc1c1c1,0xc8979797,0x3000000,0x4000000,0x0,0x0,0x0,0x0,
+ 0x2b393939,0xeeaaaaaa,0xffdadada,0xffe4e4e4,0xffeaeaea,0xffeaeaea,0xffe4e4e4,0xffdddddd,0xffd1d1d1,0xae797979,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1e0f0f0f,0x76575757,0xae898989,0xc49c9c9c,0xc6a0a0a0,0xbc9a9a9a,0x98808080,0x57414141,0xb000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+/* Generated by qembed */
+static const QRgb group_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4223731d,0xc37fbb7c,0xea9bca98,0xce86b982,0x5a316e2c,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x56146610,0xfd8fce8e,0xffbae4bb,0xffb7e2b7,0xffbae3ba,
+ 0xff9ed89d,0x62166112,0x0,0x0,0x0,0x0,0x0,0x0,0x4003ca5,0x9003171,0x0,0xd0198b17,0xff6ac468,0xff6ec665,
+ 0xff70c865,0xff6ec665,0xff6ac468,0xdd1a8918,0x6000000,0x0,0x0,0x0,0xa001333,0x905b8cc4,0xeb9fc0e4,0xf6a8c5e4,0xc07a9dc9,0xf7108e1e,
+ 0xff2eb113,0xff42be17,0xff49c216,0xff44be17,0xff31b214,0xfb109301,0x1a000000,0x0,0x0,0x0,0xa3497ebb,0xffc6def8,0xffc6ddf6,0xffc5ddf6,
+ 0xffc9e0f8,0xff77abd2,0xff31af18,0xff50cd00,0xff5cd400,0xff52ce00,0xff3bbe00,0xe6218f03,0xd000000,0x0,0x0,0x21042043,0xfc61a0e3,0xff97c3f0,
+ 0xff9cc7f1,0xff9cc8f1,0xff98c4f0,0xff85b8ef,0xff469d88,0xff7de517,0xff87ed10,0xff7ce417,0xfe5bca14,0x811b5304,0x0,0x0,0x0,0x3e082e58,
+ 0xff60a7ed,0xff7fbaef,0xff8ac3f1,0xff8bc4f1,0xff83beef,0xff6caeec,0xff4e98b3,0xff88d54a,0xff98e343,0xff89d64a,0xf846a630,0x340c4100,0x0,0x0,
+ 0x0,0x1c021631,0xf867a7e3,0xff90c9f4,0xffa1d6f8,0xffa4d8f8,0xff96cef5,0xff82bef2,0xff65aca9,0xff8ad576,0xff86d276,0xff88d377,0xff80d072,0xd3279310,
+ 0x8000700,0x0,0x0,0x0,0x8f3f6f9f,0xffaedcf9,0xffc7effe,0xffc9f0fe,0xffbbe5fc,0xff73b7c4,0xff45ba25,0xff51c61e,0xff50c617,0xff51c61c,
+ 0xff4bc120,0xff30b50c,0x62206705,0x0,0x0,0x0,0x6e1d5899,0xff81b2e7,0xffb4d7f4,0xffbddcf7,0xffa8cef4,0xff4698a0,0xff45c407,0xff53ce00,
+ 0xff59d200,0xff54cf00,0xff46c600,0xff34bb00,0xc42d9105,0x0,0x0,0x270a305f,0xf567a5e3,0xffaed3f4,0xffafd4f5,0xffaed4f4,0xffaed3f4,0xff94c2f3,
+ 0xff4fa782,0xff6cdf00,0xff74e400,0xff6cdf00,0xff5ad300,0xff43c401,0xf742b110,0x16060b00,0x0,0xa0407dba,0xff80bcf1,0xff8ec5f2,0xff92c8f2,0xff91c8f2,
+ 0xff90c6f2,0xff86bff0,0xff67a8e6,0xff80e02c,0xff95f615,0xff8aee18,0xff7de323,0xff76db33,0xe951a31a,0x19040a00,0xd000f28,0xf066a4de,0xff88c4f2,0xff97cef5,
+ 0xffa0d4f7,0xffa0d5f7,0xff9ad0f6,0xff8dc7f3,0xff7ebcf2,0xef6ea88b,0xd679b12f,0xd271a82d,0xbb5c9221,0x8235600c,0x24060d02,0x0,0x44184c89,0xff8cc6f4,
+ 0xff99d0f6,0xffabddfa,0xffb7e6fc,0xffb8e6fc,0xffaee0fb,0xff9ed4f7,0xff90c9f3,0xc86697c9,0x3000000,0x4000000,0x0,0x0,0x0,0x0,
+ 0x2b0e3664,0xee7caed8,0xffb9e4fc,0xffcaf1fe,0xffd5f6ff,0xffd6f7ff,0xffcbf2fe,0xffbee8fc,0xffa9d6f9,0xae5378a0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1e020c1d,0x7634547a,0xae6a88a8,0xc4849bb4,0xc689a0b8,0xbc7d9ab7,0x98627f9f,0x572c3e56,0xb000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static const QRgb mask_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x11c84a00,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x68d14e00,0xffda6400,0x72bf4700,0x3000000,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x14d04d00,0xefda6400,0xfffec300,0xf2d86300,0x24742b00,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98d14e00,0xfff3b537,0xfffffed6,
+ 0xfff3b537,0xa5c04800,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30cf4d00,0xfbe17803,
+ 0xfff1e7ad,0xffcacaba,0xfff1e7ac,0xfce07803,0x42973800,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0xc4d35300,0xfffad45c,0xffc0c0b2,0xff979797,0xffb2b2a9,0xfffad45a,0xccca5000,0xa000000,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x58d14e00,0xffe89410,0xfffffcbd,0xffc6c6af,0xff929292,0xffbdbda8,0xfffffcb9,0xffe8930e,0x69b04100,0x2000000,0x0,0x0,0x0,
+ 0x0,0x0,0x8cb4c00,0xe3d76000,0xfffeec6c,0xffffffbe,0xffe2e2b2,0xff878787,0xffd5d5a8,0xffffffb7,0xfffeeb62,0xe8d35e00,0x17491b00,0x0,
+ 0x0,0x0,0x0,0x0,0x84d14e00,0xfff0b41a,0xfffffea3,0xffffffa8,0xfffbfba7,0xff7b7b76,0xfff6f6a0,0xffffff9c,0xfffffe8e,0xfff0b414,
+ 0x92bd4600,0x4000000,0x0,0x0,0x0,0x20d04d00,0xf7dd7400,0xfffff85e,0xffffff89,0xffffff8b,0xffffff8a,0xffc3c376,0xffffff82,0xffffff7b,
+ 0xffffff71,0xfffff746,0xf9db7300,0x32873200,0x0,0x0,0x0,0xa8d25200,0xfff6d518,0xffffff61,0xffffff65,0xffffff65,0xffecec60,0xff9f9f52,
+ 0xffe6e657,0xffffff54,0xffffff4c,0xffffff44,0xfff6d50e,0xb4c54c00,0x8000000,0x0,0x40d04e00,0xffe49001,0xfffffd2b,0xffffff3a,0xffffff3d,0xffffff3d,
+ 0xff9b9b33,0xff272727,0xff84842a,0xffffff2e,0xffffff28,0xffffff22,0xfffffd18,0xffe49000,0x52a33c00,0x2000000,0xd0d55b00,0xfffcef07,0xffffff17,0xffffff1a,
+ 0xffffff1b,0xffffff1b,0xffeaea19,0xff8c8c16,0xffdbdb13,0xffffff10,0xffffff0d,0xffffff0a,0xffffff07,0xfffcef02,0xd7ce5800,0xc000000,0xe4d55d00,0xffe49204,
+ 0xffe4940a,0xffe4950c,0xffe4960d,0xffe4950c,0xffe4950c,0xffe4940a,0xffe49308,0xffe49307,0xffe49205,0xffe39204,0xffe39102,0xffe39100,0xead05b00,0x1c000000,
+ 0x13582100,0x3c702900,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,0x40692700,
+ 0x29290f00,0xc000000,0x0,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,
+ 0x2000000,0x2000000,0x2000000,0x0
+};
+
+static const QRgb others_grey_data[] = {
+ 0x0,0x0,0x0,0xa4c4c4c,0x5d676767,0x777c7c7c,0x3d555555,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x17535353,0xd2afafaf,0xffebebeb,0xffe5e5e5,0xfec2c2c2,0x906d6d6d,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0xa09c9c9c,0xfff1f1f1,0xfff5f5f5,0xffe6e6e6,0xffd4d4d4,0xffbebebe,0x4c424242,0x117b7b7b,
+ 0x357d7d7d,0x177c7c7c,0x0,0x0,0x0,0x0,0x0,0x606060,0xe4b4b4b4,0xffe1e1e1,0xffe4e4e4,0xffdcdcdc,0xffcecece,0xffc0c0c0,
+ 0xd9858585,0xf3d5d5d5,0xffe6e6e6,0xf8cdcdcd,0x8c828282,0x2030303,0x0,0x0,0x0,0x0,0xdcaaaaaa,0xffd0d0d0,0xffd2d2d2,0xffcecece,
+ 0xffc5c5c5,0xffa3a3a3,0xffe8e8e8,0xfffbfbfb,0xfff4f4f4,0xffeaeaea,0xffe0e0e0,0x6f767676,0x0,0x0,0x0,0x0,0x7e848484,0xffc3c3c3,
+ 0xffc3c3c3,0xffbfbfbf,0xffaeaeae,0xffaaaaaa,0xfff1f1f1,0xfff2f2f2,0xffefefef,0xffe6e6e6,0xffe0e0e0,0xcba6a6a6,0x0,0x0,0x0,0xc3f3f3f,
+ 0xb8858585,0xff8f8f8f,0xff969696,0xff919191,0xff787878,0xffa5a5a5,0xffe7e7e7,0xffe8e8e8,0xffe5e5e5,0xffe1e1e1,0xffdcdcdc,0xd4a6a6a6,0x0,0x0,
+ 0x0,0xa1959595,0xffdbdbdb,0xffe3e3e3,0xff999999,0xff7a7a7a,0xffb9b9b9,0xffb5b5b5,0xffdedede,0xffe0e0e0,0xffdfdfdf,0xffdbdbdb,0xffd1d1d1,0x8e898989,
+ 0x0,0x0,0x28363636,0xfcb2b2b2,0xffdadada,0xffededed,0xfff5f5f5,0xffd5d5d5,0xfff5f5f5,0xffcbcbcb,0xffb7b7b7,0xffd2d2d2,0xffd3d3d3,0xffc8c8c8,
+ 0xffb2b2b2,0x78979797,0x0,0x0,0x694b4b4b,0xffafafaf,0xffc8c8c8,0xffd1d1d1,0xffd8d8d8,0xffdbdbdb,0xffb9b9b9,0xffd7d7d7,0xffe4e4e4,0xffc3c3c3,
+ 0xffa0a0a0,0xffb9b9b9,0xffd2d2d2,0xffdbdbdb,0x5e979797,0x0,0x70434343,0xff9c9c9c,0xffadadad,0xffb6b6b6,0xffbbbbbb,0xffbbbbbb,0xffb0b0b0,0xffdfdfdf,
+ 0xfff5f5f5,0xfff8f8f8,0xfff2f2f2,0xfff8f8f8,0xfff6f6f6,0xffe3e3e3,0xe6bababa,0x90b0b0b,0x30232323,0xfb767676,0xff939393,0xff9a9a9a,0xff9f9f9f,0xff969696,
+ 0xffbbbbbb,0xffdadada,0xffe3e3e3,0xffe8e8e8,0xffeaeaea,0xffe9e9e9,0xffe5e5e5,0xffdedede,0xffc8c8c8,0x41363636,0x0,0x5a2e2e2e,0xde5b5b5b,0xfe707070,
+ 0xff7a7a7a,0xff727272,0xffb3b3b3,0xffcbcbcb,0xffd1d1d1,0xffd6d6d6,0xffd8d8d8,0xffd7d7d7,0xffd3d3d3,0xffcecece,0xffbfbfbf,0x57424242,0x0,0x0,
+ 0x4000000,0x20050505,0x33070707,0x3b181818,0xf2959595,0xffbababa,0xffbfbfbf,0xffc3c3c3,0xffc5c5c5,0xffc4c4c4,0xffc1c1c1,0xffbcbcbc,0xfe9f9f9f,0x321d1d1d,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x5c5f5f5f,0xf08a8a8a,0xffa7a7a7,0xffb0b0b0,0xffb2b2b2,0xffb0b0b0,0xffa9a9a9,0xf98e8e8e,
+ 0x874c4c4c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf101010,0x4a2b2b2b,0x65424242,0x6c4a4a4a,0x67444444,
+ 0x542e2e2e,0x200f0f0f,0x0,0x0
+};
+
+static const QRgb others_data[] = {
+ 0x0,0x0,0x0,0xa804618,0x5d95643a,0x77a77c52,0x3d855126,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x17964f11,0xd2cfb190,0xfff8efdf,0xffffeccb,0xfeedce98,0x909b703f,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0xa0d29e66,0xfffff7e3,0xfffff8ec,0xffffedce,0xffffe0a9,0xfff5cd88,0x4c6f4316,0x11f72300,
+ 0x35fb2b00,0x17f82200,0x0,0x0,0x0,0x0,0x0,0xc15b00,0xe4ebbc7d,0xffffeac4,0xffffecca,0xffffe5b9,0xfffedb9e,0xfff4d38d,
+ 0xd9c76844,0xf3f6b8b4,0xfffcdad0,0xf8f5b3a6,0x8cba524a,0x2070000,0x0,0x0,0x0,0x0,0xdce9b56b,0xfffedda3,0xffffdea6,0xfffedb9e,
+ 0xfff8d592,0xffdf9f67,0xfffadad6,0xfffffaf8,0xfffef0ea,0xfffee2d6,0xfffed4c3,0x6fac4f41,0x0,0x0,0x0,0x0,0x7ecd933c,0xfff7d390,
+ 0xfff6d390,0xfff3d08b,0xffe6c377,0xffe29c73,0xfffeece4,0xfffeeee7,0xfffee9e0,0xfffddecf,0xfff9d8c8,0xcbd0927d,0x0,0x0,0x0,0xc007f00,
+ 0xb85db05a,0xffbbae64,0xffd4ab58,0xffd0a952,0xffba9636,0xffd9a571,0xfffddfd2,0xfffee0d3,0xfffdddce,0xfffbd8c8,0xfff6d2c2,0xd4d3927a,0x0,0x0,
+ 0x0,0xa171b973,0xffd4e9ce,0xffd4f2d5,0xffb2a680,0xffdb301a,0xff9cde94,0xffd3c097,0xfffbd4c2,0xfffad7c6,0xfff9d6c6,0xfff6d2c0,0xfff8c2ab,0x8ec26d51,
+ 0x0,0x0,0x28026b11,0xfc9ed391,0xffd4efc6,0xffeaf8e2,0xfff2fcee,0xffe5cdc6,0xfff4fcee,0xffb5cbe1,0xffd19da5,0xfff9c2ab,0xfff8c5ae,0xfff9b398,
+ 0xffd6918f,0x785982d5,0x0,0x0,0x691d792e,0xff9edc82,0xffbdeaa7,0xffc8edb6,0xffd0f0c0,0xffd4f2c4,0xffa8cac2,0xffbdccf2,0xffcfdefa,0xffbcb5d2,
+ 0xff9a91b0,0xffaba8ca,0xffaaccfb,0xffc4d1f2,0x5e6184ce,0x0,0x70196d2d,0xff88d663,0xff9dde7c,0xffa8e28a,0xffaee493,0xffb0e493,0xff89add8,0xffc6dbf8,
+ 0xffebf5ff,0xfff1f7ff,0xffe6f3ff,0xfff2f8ff,0xffeef6ff,0xffcfe0f8,0xe694b1e1,0x9000317,0x30004626,0xfb57b03d,0xff7ed651,0xff86d75e,0xff8cd966,0xff7cc16b,
+ 0xff84aff2,0xffb6dafe,0xffc8e4ff,0xffd2eaff,0xffd6ebff,0xffd4eaff,0xffcce6ff,0xffbee0ff,0xff96c2fb,0x410e1f5e,0x0,0x5a104c2a,0xde3b882f,0xfe51aa37,
+ 0xff5cb83c,0xff4e9c49,0xff70a8f6,0xff98cdff,0xffa4d3ff,0xffaed7ff,0xffb1d8ff,0xffb0d8ff,0xffa8d4ff,0xff9dcfff,0xff81bcfe,0x57132571,0x0,0x0,
+ 0x4000001,0x2000020a,0x3300080f,0x3b000d31,0xf24a83e0,0xff76bdff,0xff80c2ff,0xff88c5ff,0xff8cc6ff,0xff8ac6ff,0xff84c2ff,0xff7abeff,0xfe5694e9,0x32030738,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x5c1429ab,0xf03d77d8,0xff57a3f7,0xff62b0fe,0xff65b2ff,0xff63b1fe,0xff5aa6f9,0xf9427edb,
+ 0x87152a83,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000021,0x4a020554,0x650b167a,0x6c0e1d86,0x670c187d,
+ 0x5403065a,0x2000001e,0x0,0x0
+};
+
+static const QRgb user_green_data[] = {
+ 0x0,0x0,0x0,0x0,0x5029,0x6c1c6e21,0xe332aa3b,0xf83ac841,0xf838c83f,0xda369a3b,0x5a145819,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e1a6c1e,0xff32da39,0xff3de341,0xff3ee045,0xff3ee042,0xff3de345,0xff27d930,0x68125817,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f013105,0xf721a328,0xff22de27,0xff23dd27,0xff26dc26,0xff26dc2a,0xff22de27,
+ 0xff22de27,0xee268c2b,0x12001402,0x0,0x0,0x0,0x0,0x0,0x0,0x5c0b590f,0xff19b51d,0xff1ecc1e,0xff1dd31d,0xff22d41e,
+ 0xff1ed41e,0xff1cd21c,0xff1dcb21,0xff18b01b,0x4d093d0d,0x0,0x0,0x0,0x0,0x0,0x0,0x640f5f13,0xff18bc18,0xff1ec61a,
+ 0xff1ed119,0xff22d519,0xff22d519,0xff22ce1a,0xff1fc31b,0xff16be1a,0x5a0e4211,0x0,0x0,0x0,0x0,0x0,0x0,0x38033507,
+ 0xff1db91d,0xff21d818,0xff24e616,0xff2aec16,0xff2aec16,0xff24e416,0xff21d418,0xfd20b020,0x35031b05,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb2a702c,0xff2df018,0xff3af41c,0xff48f620,0xff46fa1c,0xff39f21a,0xff23ef13,0xb929632c,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e012703,0xfc279129,0xff3fe729,0xff5ff537,0xff5bf632,0xff2ef11f,0xf6298f2e,0x29010d02,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x6000e07,0xc41f7721,0xff1ee01e,0xff29dd2d,0xff22de27,0xff22de27,0xff2bdf34,0xff1ddf21,0xab227226,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d136117,0xff1bc31b,0xff1ee01e,0xff24e020,0xff25e220,0xff25e220,0xff20e020,
+ 0xff20dc20,0xff1bbf1e,0x561b571f,0x0,0x0,0x0,0x0,0x0,0x8001205,0xe2268e29,0xff1eca1a,0xff23d41a,0xff23d81a,0xff23d81a,
+ 0xff23d81a,0xff23d81a,0xff24d11b,0xff1fc71b,0xd12a882c,0x4000000,0x0,0x0,0x0,0x0,0x4a0e5012,0xff1cc818,0xff21d119,0xff25db17,
+ 0xff25e117,0xff24e616,0xff24e616,0xff27df19,0xff21da18,0xff22cf19,0xff18c418,0x3a173d19,0x0,0x0,0x0,0x0,0x982b732c,0xff1ed915,
+ 0xff25dd17,0xff28ec14,0xff32f018,0xff34f21a,0xff32f218,0xff2af016,0xff28ea14,0xff20db17,0xff1bd317,0x85316f34,0x0,0x0,0x0,0x0,
+ 0xbf318131,0xff22e818,0xff2aea16,0xff39ef1b,0xff44fa1a,0xff4dfa1e,0xff4dfa1e,0xff3ff71b,0xff30f016,0xff2ae616,0xff20e616,0xb3337936,0x0,0x0,
+ 0x0,0x0,0x51134b16,0xed369834,0xff2ef11f,0xff54f828,0xff67fc2c,0xff6bfb33,0xff6ffc30,0xff5ffc28,0xff48f925,0xff30f41c,0xec33a135,0x561b3d1e,
+ 0x0,0x0,0x0,0x0,0x0,0x18000802,0x60113b14,0x9d315f33,0xbb417143,0xc6467848,0xc6467a48,0xbc417942,0x9e3c663e,0x64224225,
+ 0x1c020604,0x0,0x0,0x0
+};
+
+static const QRgb user_grey_data[] = {
+ 0x0,0x0,0x0,0x0,0x404040,0x6c6e6e6e,0xe3b0b0b0,0xf8cecece,0xf8cccccc,0xdaa6a6a6,0x5a575757,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e6b6b6b,0xffd6d6d6,0xffe6e6e6,0xffe4e4e4,0xffe4e4e4,0xffe6e6e6,0xffcccccc,0x68555555,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f282828,0xf79d9d9d,0xffcccccc,0xffcdcdcd,0xffcecece,0xffcecece,0xffcccccc,
+ 0xffcccccc,0xee8f8f8f,0x12101010,0x0,0x0,0x0,0x0,0x0,0x0,0x5c515151,0xffa5a5a5,0xffbbbbbb,0xffc0c0c0,0xffc1c1c1,
+ 0xffc1c1c1,0xffbfbfbf,0xffbababa,0xffa0a0a0,0x4d383838,0x0,0x0,0x0,0x0,0x0,0x0,0x64585858,0xffaaaaaa,0xffb4b4b4,
+ 0xffbcbcbc,0xffbfbfbf,0xffbfbfbf,0xffbababa,0xffb2b2b2,0xffa9a9a9,0x5a404040,0x0,0x0,0x0,0x0,0x0,0x0,0x382e2e2e,
+ 0xffababab,0xffc0c0c0,0xffc9c9c9,0xffcfcfcf,0xffcecece,0xffc8c8c8,0xffbdbdbd,0xfda6a6a6,0x35181818,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb7c7c7c,0xffd3d3d3,0xffd9d9d9,0xffdfdfdf,0xffdedede,0xffd7d7d7,0xffcecece,0xb9717171,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e202020,0xfc939393,0xffdadada,0xfff0f0f0,0xffededed,0xffdadada,0xf6949494,0x290c0c0c,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x60c0c0c,0xc4787878,0xffcbcbcb,0xffd2d2d2,0xffcccccc,0xffcccccc,0xffd4d4d4,0xffc9c9c9,0xab777777,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d5d5d5d,0xffb2b2b2,0xffcbcbcb,0xffcccccc,0xffcecece,0xffcecece,0xffcccccc,
+ 0xffcacaca,0xffafafaf,0x565c5c5c,0x0,0x0,0x0,0x0,0x0,0x80f0f0f,0xe2909090,0xffb7b7b7,0xffbebebe,0xffc1c1c1,0xffc1c1c1,
+ 0xffc1c1c1,0xffc1c1c1,0xffbdbdbd,0xffb5b5b5,0xd18f8f8f,0x4000000,0x0,0x0,0x0,0x0,0x4a4c4c4c,0xffb3b3b3,0xffbbbbbb,0xffc2c2c2,
+ 0xffc7c7c7,0xffc9c9c9,0xffc9c9c9,0xffc6c6c6,0xffc1c1c1,0xffb9b9b9,0xffb0b0b0,0x3a434343,0x0,0x0,0x0,0x0,0x987e7e7e,0xffbfbfbf,
+ 0xffc4c4c4,0xffcdcdcd,0xffd3d3d3,0xffd6d6d6,0xffd5d5d5,0xffd1d1d1,0xffcbcbcb,0xffc2c2c2,0xffbbbbbb,0x85808080,0x0,0x0,0x0,0x0,
+ 0xbf8e8e8e,0xffcccccc,0xffcccccc,0xffd5d5d5,0xffdddddd,0xffe0e0e0,0xffe0e0e0,0xffdbdbdb,0xffd2d2d2,0xffcacaca,0xffcacaca,0xb38a8a8a,0x0,0x0,
+ 0x0,0x0,0x514b4b4b,0xeda4a4a4,0xffdadada,0xffe7e7e7,0xffededed,0xfff1f1f1,0xfff0f0f0,0xffeaeaea,0xffe4e4e4,0xffdadada,0xeca9a9a9,0x56474747,
+ 0x0,0x0,0x0,0x0,0x0,0x18070707,0x603e3e3e,0x9d747474,0xbb8e8e8e,0xc6989898,0xc69a9a9a,0xbc959595,0x9e828282,0x64505050,
+ 0x1c070707,0x0,0x0,0x0
+};
+
+static const QRgb user_data[] = {
+ 0x0,0x0,0x0,0x0,0x7f,0x6c2c68af,0xe384abdb,0xf8b2ccea,0xf8aecae9,0xda7ba3d1,0x5a20508d,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x7e2a66ac,0xffb8d4f3,0xffd2e5f9,0xffd0e3f8,0xffcfe3f8,0xffd3e5f9,0xffa7c9f0,0x681d4e8c,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f02244d,0xf75c9ade,0xffa6cbf2,0xffa7ccf2,0xffa9cef2,0xffa9cdf2,0xffa6ccf2,
+ 0xffa6ccf2,0xee4d8bd0,0x12000d1f,0x0,0x0,0x0,0x0,0x0,0x0,0x5c124c8f,0xff60a4ea,0xff88bcee,0xff8fc1f0,0xff92c4f0,
+ 0xff92c3f0,0xff8ec0f0,0xff85baee,0xff579fe9,0x4d0f3460,0x0,0x0,0x0,0x0,0x0,0x0,0x64185598,0xff67acec,0xff7ab8ee,
+ 0xff87c1f1,0xff8cc5f2,0xff8cc5f2,0xff84c0f0,0xff76b6ed,0xff63a9ee,0x5a173d69,0x0,0x0,0x0,0x0,0x0,0x0,0x38052a56,
+ 0xff6caee9,0xff8cc6f3,0xff9cd2f6,0xffa5d8f8,0xffa4d7f8,0xff99d0f6,0xff88c3f2,0xfd68a7e4,0x3505152b,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x2000000,0xbb447bb3,0xffabdbfa,0xffb6e4fc,0xffc0ecfe,0xffbeebfe,0xffb3e2fb,0xffa2d6f9,0xb9426e9f,0x4000000,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x2e011c3e,0xfc5491d2,0xffbce2f8,0xffe1f6fe,0xffdcf5fe,0xffb9e0fb,0xf65790d0,0x29010b17,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x6000017,0xc43276be,0xffa2cbf3,0xffb0d1f3,0xffa6cbf2,0xffa6cbf2,0xffb4d2f4,0xff9ec9f3,0xab3774b7,
+ 0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x6d1f599b,0xff76b3ed,0xffa3ccf3,0xffa5cff3,0xffa7d0f4,0xffa7d0f4,0xffa5cef3,
+ 0xffa2ccf2,0xff71afed,0x562c578c,0x0,0x0,0x0,0x0,0x0,0x800071e,0xe24f8fd0,0xff7ebaef,0xff8bc4f1,0xff90c7f2,0xff8fc7f2,
+ 0xff8fc6f2,0xff8fc6f2,0xff89c2f0,0xff7bb8ee,0xd1538dca,0x4000000,0x0,0x0,0x0,0x0,0x4a164781,0xff77b8ef,0xff85c2f1,0xff90caf4,
+ 0xff98cff5,0xff9cd2f6,0xff9bd1f6,0xff97cef5,0xff8ec8f3,0xff82bff0,0xff72b2ee,0x3a244062,0x0,0x0,0x0,0x0,0x98447db7,0xff8ac5f4,
+ 0xff94ccf4,0xffa1d6f8,0xffabddfa,0xffb0e0fb,0xffafe0fb,0xffa8dbfa,0xff9ed4f7,0xff90c9f4,0xff83c0f3,0x854d7cb2,0x0,0x0,0x0,0x0,
+ 0xbf5a8fc1,0xffa1d2f6,0xffa0d6f7,0xffafe0fa,0xffbceafe,0xffc2eefe,0xffc2eefe,0xffb9e8fd,0xffaaddfa,0xff9ed3f6,0xff9dd0f6,0xb35a88ba,0x0,0x0,
+ 0x0,0x0,0x511f4776,0xed77a7d1,0xffb8e0fb,0xffcff1fe,0xffdaf8ff,0xffe2f9ff,0xffe0f9ff,0xffd5f6ff,0xffcaeefe,0xffb8e1fc,0xec7ca9d6,0x562c4462,
+ 0x0,0x0,0x0,0x0,0x0,0x1800030d,0x601b3a61,0x9d4f7198,0xbb6e8cad,0xc67d96b3,0xc67d98b6,0xbc7494b5,0x9e6180a3,0x64364c69,
+ 0x1c040409,0x0,0x0,0x0
+};
+
+static const QRgb yes_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x11049c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x1005a200,0x800ba600,0xd512a700,0xe1009d00,0x34007700,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x8009500,0x78009b00,0xf0039f03,0xe2009800,0x46003700,0xbb009300,0xeb11a111,0x35006f00,0x1000000,0x0,0x0,
+ 0x0,0x0,0x0,0x8008d00,0x70009300,0xe819ab19,0xff3ec63e,0xd4099109,0x45002c00,0xf000000,0x6f008900,0xff33d633,0xeb0a9e0a,0x35006800,
+ 0x1000000,0x0,0x0,0x4008900,0x6c008a00,0xe8099e09,0xff2cd52c,0xff3bd93b,0xcb048404,0x3c001c00,0xc000000,0x0,0x28007a00,0xff0abc0a,
+ 0xff10f410,0xeb019701,0x35006100,0x5006d00,0x60008100,0xdc009800,0xff06d206,0xff13fd13,0xff11ce11,0xc2017801,0x32000b00,0xa000000,0x0,0x0,
+ 0x1000000,0xde009100,0xff00f700,0xff00eb00,0xeb008e00,0xde008700,0xff00c400,0xff00f500,0xff00f700,0xff00c100,0xae006700,0x30000b00,0x8000000,0x0,
+ 0x0,0x0,0x0,0x97007100,0xff00dc00,0xff00eb00,0xff00e500,0xff00e700,0xff00eb00,0xff00eb00,0xff00a800,0xa2005c00,0x29000000,0x6000000,
+ 0x0,0x0,0x0,0x0,0x0,0x4c006600,0xff00af00,0xff00de00,0xff00de00,0xff00de00,0xff00dc00,0xff009600,0x96005100,0x24000000,
+ 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa004e00,0xf8008200,0xff00d200,0xff00d200,0xff00ce00,0xfc008700,0x80004100,
+ 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb005f00,0xff00c300,0xff00c100,0xf6007500,
+ 0x76003800,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6f005800,0xff009700,
+ 0xf4006d00,0x6c003200,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x28005300,0xed005900,0x5a002800,0x16000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static const QRgb yespartial_data[] = {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x114e4e4e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x10515151,0x80535353,0xd5535353,0xe14e4e4e,0x343b3b3b,0x1000000,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x84a4a4a,0x784d4d4d,0x9e515151,0xe24c4c4c,0x461b1b1b,0xbb494949,0xeb595959,0x35373737,0x1000000,0x0,0x0,
+ 0x0,0x0,0x0,0x8464646,0x70494949,0xe8626262,0x93828282,0xc34d4d4d,0x45161616,0xf000000,0x6f444444,0x8c848484,0xcf545454,0x35343434,
+ 0x1000000,0x0,0x0,0x4444444,0x6c454545,0xe5535353,0x57808080,0x5e8a8a8a,0xcb444444,0x3c0e0e0e,0xc000000,0x0,0x283d3d3d,0xa7636363,
+ 0x32828282,0xeb4c4c4c,0x35303030,0x5363636,0x60404040,0xdc4c4c4c,0x756c6c6c,0x2b888888,0x7b6f6f6f,0xc23c3c3c,0x32050505,0xa000000,0x0,0x0,
+ 0x1000000,0xde484848,0x3c7b7b7b,0x1f757575,0xeb474747,0xde434343,0x80626262,0x3c7a7a7a,0x337b7b7b,0x56606060,0xae333333,0x30050505,0x8000000,0x0,
+ 0x0,0x0,0x0,0x97383838,0x4c6e6e6e,0xa757575,0x3727272,0x24737373,0x2b757575,0x27757575,0x75545454,0x952e2e2e,0x29000000,0x6000000,
+ 0x0,0x0,0x0,0x0,0x0,0x4c333333,0x8e575757,0x1c6f6f6f,0x46f6f6f,0xb6f6f6f,0x2b6e6e6e,0x994b4b4b,0x85282828,0x24000000,
+ 0x5000000,0x0,0x0,0x0,0x0,0x0,0x0,0xa272727,0xdc414141,0x3d696969,0x11696969,0x1e676767,0x91434343,0x77202020,
+ 0x21000000,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbb2f2f2f,0x5d616161,0x36606060,0x893a3a3a,
+ 0x761c1c1c,0x1d000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6f2c2c2c,0x9a4b4b4b,
+ 0x9b363636,0x6c191919,0x19000000,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x28292929,0xed2c2c2c,0x5a141414,0x16000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x1000000,0x15000000,0x12000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0
+};
+
+static struct EmbedImage {
+ int width, height, depth;
+ const unsigned char *data;
+ int numColors;
+ const QRgb *colorTable;
+ bool alpha;
+ const char *name;
+} embed_image_vec[] = {
+ { 16, 16, 32, (const unsigned char*)group_grey_data, 0, 0, TRUE, "group-grey" },
+ { 16, 16, 32, (const unsigned char*)group_data, 0, 0, TRUE, "group" },
+ { 16, 16, 32, (const unsigned char*)mask_data, 0, 0, TRUE, "mask" },
+ { 16, 16, 32, (const unsigned char*)others_grey_data, 0, 0, TRUE, "others-grey" },
+ { 16, 16, 32, (const unsigned char*)others_data, 0, 0, TRUE, "others" },
+ { 16, 16, 32, (const unsigned char*)user_green_data, 0, 0, TRUE, "user-green" },
+ { 16, 16, 32, (const unsigned char*)user_grey_data, 0, 0, TRUE, "user-grey" },
+ { 16, 16, 32, (const unsigned char*)user_data, 0, 0, TRUE, "user" },
+ { 16, 16, 32, (const unsigned char*)yes_data, 0, 0, TRUE, "yes" },
+ { 16, 16, 32, (const unsigned char*)yespartial_data, 0, 0, TRUE, "yespartial" },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const TQImage& qembed_findImage( const TQString& name )
+{
+ static TQDict<TQImage> dict;
+ TQImage* img = dict.find( name );
+ if ( !img ) {
+ for ( int i = 0; embed_image_vec[i].data; i++ ) {
+ if ( strcmp(embed_image_vec[i].name, name.latin1()) == 0 ) {
+ img = new TQImage((uchar*)embed_image_vec[i].data,
+ embed_image_vec[i].width,
+ embed_image_vec[i].height,
+ embed_image_vec[i].depth,
+ (QRgb*)embed_image_vec[i].colorTable,
+ embed_image_vec[i].numColors,
+ TQImage::BigEndian );
+ if ( embed_image_vec[i].alpha )
+ img->setAlphaBuffer( TRUE );
+ dict.insert( name, img );
+ break;
+ }
+ }
+ if ( !img ) {
+ static TQImage dummy;
+ return dummy;
+ }
+ }
+ return *img;
+}
+
+#endif
+#endif
diff --git a/tdeio/tdefile/kacleditwidget.cpp b/tdeio/tdefile/kacleditwidget.cpp
new file mode 100644
index 000000000..94ee0d4c4
--- /dev/null
+++ b/tdeio/tdefile/kacleditwidget.cpp
@@ -0,0 +1,1054 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+
+#include "kacleditwidget.h"
+#include "kacleditwidget_p.h"
+
+#ifdef USE_POSIX_ACL
+
+#include <tqpainter.h>
+#include <tqptrlist.h>
+#include <tqvbox.h>
+#include <tqhbox.h>
+#include <tqpushbutton.h>
+#include <tqvbuttongroup.h>
+#include <tqradiobutton.h>
+#include <tqcombobox.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <tqlayout.h>
+#include <tqwidgetstack.h>
+#include <tqheader.h>
+
+#include <klocale.h>
+#include <tdefileitem.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+}
+#include <assert.h>
+
+#include "images.h"
+
+static struct {
+ const char* label;
+ const char* pixmapName;
+ TQPixmap* pixmap;
+} s_itemAttributes[] = {
+ { I18N_NOOP( "Owner" ), "user-grey", 0 },
+ { I18N_NOOP( "Owning Group" ), "group-grey", 0 },
+ { I18N_NOOP( "Others" ), "others-grey", 0 },
+ { I18N_NOOP( "Mask" ), "mask", 0 },
+ { I18N_NOOP( "Named User" ), "user", 0 },
+ { I18N_NOOP( "Named Group" ), "group", 0 },
+};
+
+KACLEditWidget::KACLEditWidget( TQWidget *parent, const char *name )
+ :TQWidget( parent, name )
+{
+ TQHBox *hbox = new TQHBox( parent );
+ hbox->setSpacing( KDialog::spacingHint() );
+ m_listView = new KACLListView( hbox, "acl_listview" );
+ connect( m_listView, TQT_SIGNAL( selectionChanged() ),
+ this, TQT_SLOT( slotUpdateButtons() ) );
+ TQVBox *vbox = new TQVBox( hbox );
+ vbox->setSpacing( KDialog::spacingHint() );
+ m_AddBtn = new TQPushButton( i18n( "Add Entry..." ), vbox, "add_entry_button" );
+ connect( m_AddBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotAddEntry() ) );
+ m_EditBtn = new TQPushButton( i18n( "Edit Entry..." ), vbox, "edit_entry_button" );
+ connect( m_EditBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotEditEntry() ) );
+ m_DelBtn = new TQPushButton( i18n( "Delete Entry" ), vbox, "delete_entry_button" );
+ connect( m_DelBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotRemoveEntry() ) );
+ TQWidget *spacer = new TQWidget( vbox );
+ spacer->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+ slotUpdateButtons();
+}
+
+void KACLEditWidget::slotUpdateButtons()
+{
+ bool atLeastOneIsNotDeletable = false;
+ bool atLeastOneIsNotAllowedToChangeType = false;
+ int selectedCount = 0;
+ TQListViewItemIterator it( m_listView, TQListViewItemIterator::Selected );
+ while ( KACLListViewItem *item = dynamic_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it; ++selectedCount;
+ if ( !item->isDeletable() )
+ atLeastOneIsNotDeletable = true;
+ if ( !item->isAllowedToChangeType() )
+ atLeastOneIsNotAllowedToChangeType = true;
+ }
+ m_EditBtn->setEnabled( selectedCount && !atLeastOneIsNotAllowedToChangeType );
+ m_DelBtn->setEnabled( selectedCount && !atLeastOneIsNotDeletable );
+}
+
+KACL KACLEditWidget::getACL() const
+{
+ return m_listView->getACL();
+}
+
+KACL KACLEditWidget::getDefaultACL() const
+{
+ return m_listView->getDefaultACL();
+}
+
+void KACLEditWidget::setACL( const KACL &acl )
+{
+ return m_listView->setACL( acl );
+}
+
+void KACLEditWidget::setDefaultACL( const KACL &acl )
+{
+ return m_listView->setDefaultACL( acl );
+}
+
+void KACLEditWidget::setAllowDefaults( bool value )
+{
+ m_listView->setAllowDefaults( value );
+}
+
+void KACLEditWidget::setReadOnly( bool on )
+{
+ m_listView->setEnabled( !on );
+ m_AddBtn->setEnabled( !on );
+ if ( !on )
+ slotUpdateButtons();
+}
+
+KACLListViewItem::KACLListViewItem( TQListView* parent,
+ KACLListView::EntryType _type,
+ unsigned short _value, bool defaults,
+ const TQString& _qualifier )
+ : KListViewItem( parent, parent->lastItem() ), // we want to append
+ type( _type ), value( _value ), isDefault( defaults ),
+ qualifier( _qualifier ), isPartial( false )
+{
+ m_pACLListView = dynamic_cast<KACLListView*>( parent );
+ repaint();
+}
+
+
+KACLListViewItem::~ KACLListViewItem()
+{
+
+}
+
+TQString KACLListViewItem::key( int, bool ) const
+{
+ TQString key;
+ if ( !isDefault )
+ key = "A";
+ else
+ key = "B";
+ switch ( type )
+ {
+ case KACLListView::User:
+ key += "A";
+ break;
+ case KACLListView::Group:
+ key += "B";
+ break;
+ case KACLListView::Others:
+ key += "C";
+ break;
+ case KACLListView::Mask:
+ key += "D";
+ break;
+ case KACLListView::NamedUser:
+ key += "E" + text( 1 );
+ break;
+ case KACLListView::NamedGroup:
+ key += "F" + text( 1 );
+ break;
+ default:
+ key += text( 0 );
+ break;
+ }
+ return key;
+}
+
+void KACLListViewItem::paintCell( TQPainter* p, const TQColorGroup &cg,
+ int column, int width, int alignment )
+{
+ TQColorGroup mycg = cg;
+ if ( isDefault ) {
+ mycg.setColor( TQColorGroup::Text, TQColor( 0, 0, 255 ) );
+ }
+ if ( isPartial ) {
+ TQFont font = p->font();
+ font.setItalic( true );
+ mycg.setColor( TQColorGroup::Text, TQColor( 100, 100, 100 ) );
+ p->setFont( font );
+ }
+ KListViewItem::paintCell( p, mycg, column, width, alignment );
+
+ KACLListViewItem *below =0;
+ if ( itemBelow() )
+ below = static_cast<KACLListViewItem*>( itemBelow() );
+ const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup;
+ const bool lastNonDefault = !isDefault && below && below->isDefault;
+ if ( type == KACLListView::Mask || lastUser || lastNonDefault )
+ {
+ p->setPen( TQPen( Qt::gray, 0, TQPen::DotLine ) );
+ if ( type == KACLListView::Mask )
+ p->drawLine( 0, 0, width - 1, 0 );
+ p->drawLine( 0, height() - 1, width - 1, height() - 1 );
+ }
+}
+
+
+void KACLListViewItem::updatePermPixmaps()
+{
+ unsigned int partialPerms = value;
+
+ if ( value & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 2, TQPixmap() );
+
+ if ( value & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 3, TQPixmap() );
+
+ if ( value & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 4, TQPixmap() );
+}
+
+void KACLListViewItem::repaint()
+{
+ int idx = 0;
+ switch ( type )
+ {
+ case KACLListView::User:
+ idx = KACLListView::OWNER_IDX;
+ break;
+ case KACLListView::Group:
+ idx = KACLListView::GROUP_IDX;
+ break;
+ case KACLListView::Others:
+ idx = KACLListView::OTHERS_IDX;
+ break;
+ case KACLListView::Mask:
+ idx = KACLListView::MASK_IDX;
+ break;
+ case KACLListView::NamedUser:
+ idx = KACLListView::NAMED_USER_IDX;
+ break;
+ case KACLListView::NamedGroup:
+ idx = KACLListView::NAMED_GROUP_IDX;
+ break;
+ default:
+ idx = KACLListView::OWNER_IDX;
+ break;
+ }
+ setText( 0, i18n(s_itemAttributes[idx].label) );
+ setPixmap( 0, *s_itemAttributes[idx].pixmap );
+ if ( isDefault )
+ setText( 0, text( 0 ) + i18n( " (Default)" ) );
+ setText( 1, qualifier );
+ // Set the pixmaps for which of the perms are set
+ updatePermPixmaps();
+}
+
+void KACLListViewItem::calcEffectiveRights()
+{
+ TQString strEffective = TQString( "---" );
+
+ // Do we need to worry about the mask entry? It applies to named users,
+ // owning group, and named groups
+ if ( m_pACLListView->hasMaskEntry()
+ && ( type == KACLListView::NamedUser
+ || type == KACLListView::Group
+ || type == KACLListView::NamedGroup )
+ && !isDefault )
+ {
+
+ strEffective[0] = ( m_pACLListView->maskPermissions() & value & ACL_READ ) ? 'r' : '-';
+ strEffective[1] = ( m_pACLListView->maskPermissions() & value & ACL_WRITE ) ? 'w' : '-';
+ strEffective[2] = ( m_pACLListView->maskPermissions() & value & ACL_EXECUTE ) ? 'x' : '-';
+/*
+ // What about any partial perms?
+ if ( maskPerms & partialPerms & ACL_READ || // Partial perms on entry
+ maskPartialPerms & perms & ACL_READ || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_READ ) // Partial perms on mask and entry
+ strEffective[0] = 'R';
+ if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry
+ maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perms on mask and entry
+ strEffective[1] = 'W';
+ if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry
+ maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask
+ maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial perms on mask and entry
+ strEffective[2] = 'X';
+*/
+ }
+ else
+ {
+ // No, the effective value are just the value in this entry
+ strEffective[0] = ( value & ACL_READ ) ? 'r' : '-';
+ strEffective[1] = ( value & ACL_WRITE ) ? 'w' : '-';
+ strEffective[2] = ( value & ACL_EXECUTE ) ? 'x' : '-';
+
+ /*
+ // What about any partial perms?
+ if ( partialPerms & ACL_READ )
+ strEffective[0] = 'R';
+ if ( partialPerms & ACL_WRITE )
+ strEffective[1] = 'W';
+ if ( partialPerms & ACL_EXECUTE )
+ strEffective[2] = 'X';
+ */
+ }
+ setText( 5, strEffective );
+}
+
+bool KACLListViewItem::isDeletable() const
+{
+ bool isMaskAndDeletable = false;
+ if (type == KACLListView::Mask ) {
+ if ( !isDefault && m_pACLListView->maskCanBeDeleted() )
+ isMaskAndDeletable = true;
+ else if ( isDefault && m_pACLListView->defaultMaskCanBeDeleted() )
+ isMaskAndDeletable = true;
+ }
+ return type != KACLListView::User &&
+ type != KACLListView::Group &&
+ type != KACLListView::Others &&
+ ( type != KACLListView::Mask || isMaskAndDeletable );
+}
+
+bool KACLListViewItem::isAllowedToChangeType() const
+{
+ return type != KACLListView::User &&
+ type != KACLListView::Group &&
+ type != KACLListView::Others &&
+ type != KACLListView::Mask;
+}
+
+void KACLListViewItem::togglePerm( acl_perm_t perm )
+{
+ value ^= perm; // Toggle the perm
+ if ( type == KACLListView::Mask && !isDefault ) {
+ m_pACLListView->setMaskPermissions( value );
+ }
+ calcEffectiveRights();
+ updatePermPixmaps();
+/*
+ // If the perm is in the partial perms then remove it. i.e. Once
+ // a user changes a partial perm it then applies to all selected files.
+ if ( m_pEntry->m_partialPerms & perm )
+ m_pEntry->m_partialPerms ^= perm;
+
+ m_pEntry->setPartialEntry( false );
+ // Make sure that all entries have their effective rights calculated if
+ // we are changing the ACL_MASK entry.
+ if ( type == Mask )
+ {
+ m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms );
+ m_pACLListView->setMaskPermissions( value );
+ m_pACLListView->calculateEffectiveRights();
+ }
+*/
+}
+
+
+
+EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item,
+ const TQStringList &users,
+ const TQStringList &groups,
+ const TQStringList &defaultUsers,
+ const TQStringList &defaultGroups,
+ int allowedTypes, int allowedDefaultTypes,
+ bool allowDefaults )
+ : KDialogBase( listView, "edit_entry_dialog", true,
+ i18n( "Edit ACL Entry" ), KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok, false ),
+ m_listView( listView ), m_item( item ), m_users( users ), m_groups( groups ),
+ m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ),
+ m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefaultTypes ),
+ m_defaultCB( 0 )
+{
+ TQWidget *page = new TQWidget( this );
+ setMainWidget( page );
+ TQVBoxLayout *mainLayout = new TQVBoxLayout( page, 0, spacingHint(), "mainLayout" );
+ m_buttonGroup = new TQVButtonGroup( i18n("Entry Type"), page, "bg" );
+
+ if ( allowDefaults ) {
+ m_defaultCB = new TQCheckBox( i18n("Default for new files in this folder"), page, "defaultCB" );
+ mainLayout->addWidget( m_defaultCB );
+ connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SLOT( slotUpdateAllowedUsersAndGroups() ) );
+ connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SLOT( slotUpdateAllowedTypes() ) );
+
+ }
+
+ mainLayout->addWidget( m_buttonGroup );
+
+ TQRadioButton *ownerType = new TQRadioButton( i18n("Owner"), m_buttonGroup, "ownerType" );
+ m_buttonGroup->insert( ownerType, KACLListView::User );
+ TQRadioButton *owningGroupType = new TQRadioButton( i18n("Owning Group"), m_buttonGroup, "owningGroupType" );
+ m_buttonGroup->insert( owningGroupType, KACLListView::Group );
+ TQRadioButton *othersType = new TQRadioButton( i18n("Others"), m_buttonGroup, "othersType" );
+ m_buttonGroup->insert( othersType, KACLListView::Others );
+ TQRadioButton *maskType = new TQRadioButton( i18n("Mask"), m_buttonGroup, "maskType" );
+ m_buttonGroup->insert( maskType, KACLListView::Mask );
+ TQRadioButton *namedUserType = new TQRadioButton( i18n("Named User"), m_buttonGroup, "namesUserType" );
+ m_buttonGroup->insert( namedUserType, KACLListView::NamedUser );
+ TQRadioButton *namedGroupType = new TQRadioButton( i18n("Named Group"), m_buttonGroup, "namedGroupType" );
+ m_buttonGroup->insert( namedGroupType, KACLListView::NamedGroup );
+
+ connect( m_buttonGroup, TQT_SIGNAL( clicked( int ) ),
+ this, TQT_SLOT( slotSelectionChanged( int ) ) );
+
+ m_widgetStack = new TQWidgetStack( page );
+ mainLayout->addWidget( m_widgetStack );
+
+ TQHBox *usersBox = new TQHBox( m_widgetStack );
+ m_widgetStack->addWidget( usersBox, KACLListView::NamedUser );
+
+ TQHBox *groupsBox = new TQHBox( m_widgetStack );
+ m_widgetStack->addWidget( groupsBox, KACLListView::NamedGroup );
+
+ TQLabel *usersLabel = new TQLabel( i18n( "User: " ), usersBox );
+ m_usersCombo = new TQComboBox( false, usersBox, "users" );
+ usersLabel->setBuddy( m_usersCombo );
+
+ TQLabel *groupsLabel = new TQLabel( i18n( "Group: " ), groupsBox );
+ m_groupsCombo = new TQComboBox( false, groupsBox, "groups" );
+ groupsLabel->setBuddy( m_groupsCombo );
+
+ if ( m_item ) {
+ m_buttonGroup->setButton( m_item->type );
+ if ( m_defaultCB )
+ m_defaultCB->setChecked( m_item->isDefault );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( m_item->type );
+ slotUpdateAllowedUsersAndGroups();
+ if ( m_item->type == KACLListView::NamedUser ) {
+ m_usersCombo->setCurrentText( m_item->qualifier );
+ } else if ( m_item->type == KACLListView::NamedGroup ) {
+ m_groupsCombo->setCurrentText( m_item->qualifier );
+ }
+ } else {
+ // new entry, preselect "named user", arguably the most common one
+ m_buttonGroup->setButton( KACLListView::NamedUser );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( KACLListView::NamedUser );
+ slotUpdateAllowedUsersAndGroups();
+ }
+ incInitialSize( TQSize( 100, 0 ) );
+}
+
+void EditACLEntryDialog::slotUpdateAllowedTypes()
+{
+ int allowedTypes = m_allowedTypes;
+ if ( m_defaultCB && m_defaultCB->isChecked() ) {
+ allowedTypes = m_allowedDefaultTypes;
+ }
+ for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) {
+ if ( allowedTypes & i )
+ m_buttonGroup->find( i )->show();
+ else
+ m_buttonGroup->find( i )->hide();
+ }
+}
+
+void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
+{
+ const TQString oldUser = m_usersCombo->currentText();
+ const TQString oldGroup = m_groupsCombo->currentText();
+ m_usersCombo->clear();
+ m_groupsCombo->clear();
+ if ( m_defaultCB && m_defaultCB->isChecked() ) {
+ m_usersCombo->insertStringList( m_defaultUsers );
+ if ( m_defaultUsers.find( oldUser ) != m_defaultUsers.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_defaultGroups );
+ if ( m_defaultGroups.find( oldGroup ) != m_defaultGroups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ } else {
+ m_usersCombo->insertStringList( m_users );
+ if ( m_users.find( oldUser ) != m_users.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_groups );
+ if ( m_groups.find( oldGroup ) != m_groups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ }
+}
+void EditACLEntryDialog::slotOk()
+{
+ KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonGroup->selectedId() );
+
+ TQString qualifier;
+ if ( type == KACLListView::NamedUser )
+ qualifier = m_usersCombo->currentText();
+ if ( type == KACLListView::NamedGroup )
+ qualifier = m_groupsCombo->currentText();
+
+ if ( !m_item ) {
+ m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier );
+ } else {
+ m_item->type = type;
+ m_item->qualifier = qualifier;
+ }
+ if ( m_defaultCB )
+ m_item->isDefault = m_defaultCB->isChecked();
+ m_item->repaint();
+
+ KDialogBase::slotOk();
+}
+
+void EditACLEntryDialog::slotSelectionChanged( int id )
+{
+ switch ( id ) {
+ case KACLListView::User:
+ case KACLListView::Group:
+ case KACLListView::Others:
+ case KACLListView::Mask:
+ m_widgetStack->setEnabled( false );
+ break;
+ case KACLListView::NamedUser:
+ m_widgetStack->setEnabled( true );
+ m_widgetStack->raiseWidget( KACLListView::NamedUser );
+ break;
+ case KACLListView::NamedGroup:
+ m_widgetStack->setEnabled( true );
+ m_widgetStack->raiseWidget( KACLListView::NamedGroup );
+ break;
+ default:
+ break;
+ }
+}
+
+
+KACLListView::KACLListView( TQWidget* parent, const char* name )
+ : KListView( parent, name ),
+ m_hasMask( false ), m_allowDefaults( false )
+{
+ // Add the columns
+ addColumn( i18n( "Type" ) );
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "read permission", "r" ) );
+ addColumn( i18n( "write permission", "w" ) );
+ addColumn( i18n( "execute permission", "x" ) );
+ addColumn( i18n( "Effective" ) );
+
+ header()->setClickEnabled( false );
+
+ // Load the avatars
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ s_itemAttributes[i].pixmap = new TQPixmap( qembed_findImage( s_itemAttributes[i].pixmapName ) );
+ }
+ m_yesPixmap = new TQPixmap( qembed_findImage( "yes" ) );
+ m_yesPartialPixmap = new TQPixmap( qembed_findImage( "yespartial" ) );
+
+ setSelectionMode( TQListView::Extended );
+
+ // fill the lists of all legal users and groups
+ struct passwd *user = 0;
+ setpwent();
+ while ( ( user = getpwent() ) != 0 ) {
+ m_allUsers << TQString::fromLatin1( user->pw_name );
+ }
+ endpwent();
+
+ struct group *gr = 0;
+ setgrent();
+ while ( ( gr = getgrent() ) != 0 ) {
+ m_allGroups << TQString::fromLatin1( gr->gr_name );
+ }
+ endgrent();
+ m_allUsers.sort();
+ m_allGroups.sort();
+}
+
+
+KACLListView::~KACLListView()
+{
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ delete s_itemAttributes[i].pixmap;
+ }
+ delete m_yesPixmap;
+ delete m_yesPartialPixmap;
+}
+
+TQStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem )
+{
+ TQStringList allowedUsers = m_allUsers;
+ TQListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedUser || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedUsers.remove( item->qualifier );
+ }
+ return allowedUsers;
+}
+
+TQStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem )
+{
+ TQStringList allowedGroups = m_allGroups;
+ TQListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedGroup || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedGroups.remove( item->qualifier );
+ }
+ return allowedGroups;
+}
+
+void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults )
+{
+ // clear out old entries of that ilk
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( item->isDefault == defaults )
+ delete item;
+ }
+ KACLListViewItem *item =
+ new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults );
+
+ bool hasMask = false;
+ unsigned short mask = pACL.maskPermissions( hasMask );
+ if ( hasMask ) {
+ item = new KACLListViewItem( this, Mask, mask, defaults );
+ }
+
+ // read all named user entries
+ const ACLUserPermissionsList &userList = pACL.allUserPermissions();
+ ACLUserPermissionsConstIterator itu = userList.begin();
+ while ( itu != userList.end() ) {
+ new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first );
+ ++itu;
+ }
+
+ // and now all named groups
+ const ACLUserPermissionsList &groupList = pACL.allGroupPermissions();
+ ACLUserPermissionsConstIterator itg = groupList.begin();
+ while ( itg != groupList.end() ) {
+ new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first );
+ ++itg;
+ }
+}
+
+void KACLListView::setACL( const KACL &acl )
+{
+ if ( !acl.isValid() ) return;
+ // Remove any entries left over from displaying a previous ACL
+ m_ACL = acl;
+ fillItemsFromACL( m_ACL );
+
+ m_mask = acl.maskPermissions( m_hasMask );
+ calculateEffectiveRights();
+}
+
+void KACLListView::setDefaultACL( const KACL &acl )
+{
+ if ( !acl.isValid() ) return;
+ m_defaultACL = acl;
+ fillItemsFromACL( m_defaultACL, true );
+ calculateEffectiveRights();
+}
+
+KACL KACLListView::itemsToACL( bool defaults ) const
+{
+ KACL newACL( 0 );
+ bool atLeastOneEntry = false;
+ ACLUserPermissionsList users;
+ ACLGroupPermissionsList groups;
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( TQListViewItem* qlvi = it.current() ) {
+ ++it;
+ const KACLListViewItem* item = static_cast<KACLListViewItem*>( qlvi );
+ if ( item->isDefault != defaults ) continue;
+ atLeastOneEntry = true;
+ switch ( item->type ) {
+ case User:
+ newACL.setOwnerPermissions( item->value );
+ break;
+ case Group:
+ newACL.setOwningGroupPermissions( item->value );
+ break;
+ case Others:
+ newACL.setOthersPermissions( item->value );
+ break;
+ case Mask:
+ newACL.setMaskPermissions( item->value );
+ break;
+ case NamedUser:
+ users.append( qMakePair( item->text( 1 ), item->value ) );
+ break;
+ case NamedGroup:
+ groups.append( qMakePair( item->text( 1 ), item->value ) );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( atLeastOneEntry ) {
+ newACL.setAllUserPermissions( users );
+ newACL.setAllGroupPermissions( groups );
+ if ( newACL.isValid() )
+ return newACL;
+ }
+ return KACL();
+}
+
+KACL KACLListView::getACL()
+{
+ return itemsToACL( false );
+}
+
+
+KACL KACLListView::getDefaultACL()
+{
+ return itemsToACL( true );
+}
+
+void KACLListView::contentsMousePressEvent( TQMouseEvent * e )
+{
+ TQListViewItem *clickedItem = itemAt( contentsToViewport( e->pos() ) );
+ if ( !clickedItem ) return;
+ // if the click is on an as yet unselected item, select it first
+ if ( !clickedItem->isSelected() )
+ KListView::contentsMousePressEvent( e );
+
+ if ( !currentItem() ) return;
+ int column = header()->sectionAt( e->x() );
+ acl_perm_t perm;
+ switch ( column )
+ {
+ case 2:
+ perm = ACL_READ;
+ break;
+ case 3:
+ perm = ACL_WRITE;
+ break;
+ case 4:
+ perm = ACL_EXECUTE;
+ break;
+ default:
+ return KListView::contentsMousePressEvent( e );
+ }
+ KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem );
+ unsigned short referenceHadItSet = referenceItem->value & perm;
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( !item->isSelected() ) continue;
+ // toggle those with the same value as the clicked item, leave the others
+ if ( referenceHadItSet == ( item->value & perm ) )
+ item->togglePerm( perm );
+ }
+}
+
+void KACLListView::entryClicked( TQListViewItem* pItem, const TQPoint& /*pt*/, int col )
+{
+ if ( !pItem ) return;
+
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( !item->isSelected() ) continue;
+ switch ( col )
+ {
+ case 2:
+ item->togglePerm( ACL_READ );
+ break;
+ case 3:
+ item->togglePerm( ACL_WRITE );
+ break;
+ case 4:
+ item->togglePerm( ACL_EXECUTE );
+ break;
+
+ default:
+ ; // Do nothing
+ }
+ }
+ /*
+ // Has the user changed one of the required entries in a default ACL?
+ if ( m_pACL->aclType() == ACL_TYPE_DEFAULT &&
+ ( col == 2 || col == 3 || col == 4 ) &&
+ ( pACLItem->entryType() == ACL_USER_OBJ ||
+ pACLItem->entryType() == ACL_GROUP_OBJ ||
+ pACLItem->entryType() == ACL_OTHER ) )
+ {
+ // Mark the required entries as no longer being partial entries.
+ // That is, they will get applied to all selected directories.
+ KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ );
+ pUserObj->entry()->setPartialEntry( false );
+
+ KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ );
+ pGroupObj->entry()->setPartialEntry( false );
+
+ KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER );
+ pOther->entry()->setPartialEntry( false );
+
+ update();
+ }
+ */
+}
+
+
+void KACLListView::calculateEffectiveRights()
+{
+ TQListViewItemIterator it( this );
+ KACLListViewItem* pItem;
+ while ( ( pItem = dynamic_cast<KACLListViewItem*>( it.current() ) ) != 0 )
+ {
+ ++it;
+ pItem->calcEffectiveRights();
+ }
+}
+
+
+unsigned short KACLListView::maskPermissions() const
+{
+ return m_mask;
+}
+
+
+void KACLListView::setMaskPermissions( unsigned short maskPerms )
+{
+ m_mask = maskPerms;
+ calculateEffectiveRights();
+}
+
+
+acl_perm_t KACLListView::maskPartialPermissions() const
+{
+ // return m_pMaskEntry->m_partialPerms;
+ return 0;
+}
+
+
+void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ )
+{
+ //m_pMaskEntry->m_partialPerms = maskPartialPerms;
+ calculateEffectiveRights();
+}
+
+bool KACLListView::hasDefaultEntries() const
+{
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++it;
+ if ( item->isDefault ) return true;
+ }
+ return false;
+}
+
+const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const
+{
+ return findItemByType( type, true );
+}
+
+const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const
+{
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++it;
+ if ( item->isDefault == defaults && item->type == type ) {
+ return item;
+ }
+ }
+ return 0;
+}
+
+
+unsigned short KACLListView::calculateMaskValue( bool defaults ) const
+{
+ // KACL auto-adds the relevant maks entries, so we can simply query
+ bool dummy;
+ return itemsToACL( defaults ).maskPermissions( dummy );
+}
+
+void KACLListView::slotAddEntry()
+{
+ int allowedTypes = NamedUser | NamedGroup;
+ if ( !m_hasMask )
+ allowedTypes |= Mask;
+ int allowedDefaultTypes = NamedUser | NamedGroup;
+ if ( !findDefaultItemByType( Mask ) )
+ allowedDefaultTypes |= Mask;
+ if ( !hasDefaultEntries() )
+ allowedDefaultTypes |= User | Group;
+ EditACLEntryDialog dlg( this, 0,
+ allowedUsers( false ), allowedGroups( false ),
+ allowedUsers( true ), allowedGroups( true ),
+ allowedTypes, allowedDefaultTypes, m_allowDefaults );
+ dlg.exec();
+ KACLListViewItem *item = dlg.item();
+ if ( !item ) return; // canceled
+ if ( item->type == Mask && !item->isDefault ) {
+ m_hasMask = true;
+ m_mask = item->value;
+ }
+ if ( item->isDefault && !hasDefaultEntries() ) {
+ // first default entry, fill in what is needed
+ if ( item->type != User ) {
+ unsigned short v = findDefaultItemByType( User )->value;
+ new KACLListViewItem( this, User, v, true );
+ }
+ if ( item->type != Group ) {
+ unsigned short v = findDefaultItemByType( Group )->value;
+ new KACLListViewItem( this, Group, v, true );
+ }
+ if ( item->type != Others ) {
+ unsigned short v = findDefaultItemByType( Others )->value;
+ new KACLListViewItem( this, Others, v, true );
+ }
+ }
+ const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask );
+ if ( item->isDefault && !defaultMaskItem ) {
+ unsigned short v = calculateMaskValue( true );
+ new KACLListViewItem( this, Mask, v, true );
+ }
+ if ( !item->isDefault && !m_hasMask &&
+ ( item->type == Group
+ || item->type == NamedUser
+ || item->type == NamedGroup ) ) {
+ // auto-add a mask entry
+ unsigned short v = calculateMaskValue( false );
+ new KACLListViewItem( this, Mask, v, false );
+ m_hasMask = true;
+ m_mask = v;
+ }
+ calculateEffectiveRights();
+ sort();
+ setCurrentItem( item );
+ // TQListView doesn't seem to emit, in this case, and we need to update
+ // the buttons...
+ if ( childCount() == 1 )
+ emit currentChanged( item );
+}
+
+void KACLListView::slotEditEntry()
+{
+ TQListViewItem * current = currentItem();
+ if ( !current ) return;
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( current );
+ int allowedTypes = item->type | NamedUser | NamedGroup;
+ bool itemWasMask = item->type == Mask;
+ if ( !m_hasMask || itemWasMask )
+ allowedTypes |= Mask;
+ int allowedDefaultTypes = item->type | NamedUser | NamedGroup;
+ if ( !findDefaultItemByType( Mask ) )
+ allowedDefaultTypes |= Mask;
+ if ( !hasDefaultEntries() )
+ allowedDefaultTypes |= User | Group;
+
+ EditACLEntryDialog dlg( this, item,
+ allowedUsers( false, item ), allowedGroups( false, item ),
+ allowedUsers( true, item ), allowedGroups( true, item ),
+ allowedTypes, allowedDefaultTypes, m_allowDefaults );
+ dlg.exec();
+ if ( itemWasMask && item->type != Mask ) {
+ m_hasMask = false;
+ m_mask = 0;
+ }
+ if ( !itemWasMask && item->type == Mask ) {
+ m_mask = item->value;
+ m_hasMask = true;
+ }
+ calculateEffectiveRights();
+ sort();
+}
+
+void KACLListView::slotRemoveEntry()
+{
+ TQListViewItemIterator it( this, TQListViewItemIterator::Selected );
+ while ( it.current() ) {
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() );
+ ++it;
+ /* First check if it's a mask entry and if so, make sure that there is
+ * either no name user or group entry, which means the mask can be
+ * removed, or don't remove it, but reset it. That is allowed. */
+ if ( item->type == Mask ) {
+ bool itemWasDefault = item->isDefault;
+ if ( !itemWasDefault && maskCanBeDeleted() ) {
+ m_hasMask= false;
+ m_mask = 0;
+ delete item;
+ } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) {
+ delete item;
+ } else {
+ item->value = 0;
+ item->repaint();
+ }
+ if ( !itemWasDefault )
+ calculateEffectiveRights();
+ } else {
+ // for the base permissions, disable them, which is what libacl does
+ if ( !item->isDefault &&
+ ( item->type == User
+ || item->type == Group
+ || item->type == Others ) ) {
+ item->value = 0;
+ item->repaint();
+ } else {
+ delete item;
+ }
+ }
+ }
+}
+
+bool KACLListView::maskCanBeDeleted() const
+{
+ return !findItemByType( NamedUser ) && !findItemByType( NamedGroup );
+}
+
+bool KACLListView::defaultMaskCanBeDeleted() const
+{
+ return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup );
+}
+
+#include "kacleditwidget.moc"
+#include "kacleditwidget_p.moc"
+#endif
+// vim:set ts=8 sw=4:
diff --git a/tdeio/tdefile/kacleditwidget.h b/tdeio/tdefile/kacleditwidget.h
new file mode 100644
index 000000000..c51cb94fc
--- /dev/null
+++ b/tdeio/tdefile/kacleditwidget.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public 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 KACLEDITWIDGET_H
+#define KACLEDITWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef Q_MOC_RUN
+#define USE_POSIX_ACL
+#endif // Q_MOC_RUN
+
+#ifdef USE_POSIX_ACL
+
+#include <klistview.h>
+#include <kacl.h>
+#include <tdefileitem.h>
+
+class KACLListViewItem;
+class KACLListView;
+class TQPushButton;
+
+class KACLEditWidget : TQWidget
+{
+ Q_OBJECT
+
+public:
+ KACLEditWidget( TQWidget *parent = 0, const char *name = 0 );
+ KACL getACL() const;
+ KACL getDefaultACL() const;
+ void setACL( const KACL & );
+ void setDefaultACL( const KACL & );
+ void setAllowDefaults( bool value );
+ void setReadOnly( bool value );
+private slots:
+ void slotUpdateButtons();
+
+private:
+ KACLListView* m_listView;
+ TQPushButton *m_AddBtn;
+ TQPushButton *m_EditBtn;
+ TQPushButton *m_DelBtn;
+};
+
+
+#endif
+#endif
diff --git a/tdeio/tdefile/kacleditwidget_p.h b/tdeio/tdefile/kacleditwidget_p.h
new file mode 100644
index 000000000..dc7e4c811
--- /dev/null
+++ b/tdeio/tdefile/kacleditwidget_p.h
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public 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 KACLEDITWIDGET_P_H
+#define KACLEDITWIDGET_P_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef Q_MOC_RUN
+#define USE_POSIX_ACL
+#endif // Q_MOC_RUN
+
+#ifdef USE_POSIX_ACL
+#include <klistview.h>
+#include <sys/acl.h>
+#include <kacl.h>
+#include <tdefileitem.h>
+#include <kdialogbase.h>
+#include <tqpixmap.h>
+#include <tqcombobox.h>
+
+class KACLListViewItem;
+class TQPushButton;
+class TQVButtonGroup;
+class KACLListView;
+class TQWidgetStack;
+class TQCheckBox;
+
+/**
+@author Sean Harmer
+*/
+class KACLListView : public KListView
+{
+ Q_OBJECT
+
+ friend class KACLListViewItem;
+public:
+ enum Types
+ {
+ OWNER_IDX = 0,
+ GROUP_IDX,
+ OTHERS_IDX,
+ MASK_IDX,
+ NAMED_USER_IDX,
+ NAMED_GROUP_IDX,
+ LAST_IDX
+ };
+ enum EntryType { User = 1,
+ Group = 2,
+ Others = 4,
+ Mask = 8,
+ NamedUser = 16,
+ NamedGroup = 32,
+ AllTypes = 63 };
+
+ KACLListView( TQWidget* parent = 0, const char* name = 0 );
+ ~KACLListView();
+
+ bool hasMaskEntry() const { return m_hasMask; }
+ bool hasDefaultEntries() const;
+ bool allowDefaults() const { return m_allowDefaults; }
+ void setAllowDefaults( bool v ) { m_allowDefaults = v; }
+ unsigned short maskPermissions() const;
+ void setMaskPermissions( unsigned short maskPerms );
+ acl_perm_t maskPartialPermissions() const;
+ void setMaskPartialPermissions( acl_perm_t maskPerms );
+
+ bool maskCanBeDeleted() const;
+ bool defaultMaskCanBeDeleted() const;
+
+ const KACLListViewItem* findDefaultItemByType( EntryType type ) const;
+ const KACLListViewItem* findItemByType( EntryType type,
+ bool defaults = false ) const;
+ unsigned short calculateMaskValue( bool defaults ) const;
+ void calculateEffectiveRights();
+
+ TQStringList allowedUsers( bool defaults, KACLListViewItem *allowedItem = 0 );
+ TQStringList allowedGroups( bool defaults, KACLListViewItem *allowedItem = 0 );
+
+ const KACL getACL() const { return getACL(); }
+ KACL getACL();
+
+ const KACL getDefaultACL() const { return getDefaultACL(); }
+ KACL getDefaultACL();
+
+ TQPixmap getYesPixmap() const { return *m_yesPixmap; }
+ TQPixmap getYesPartialPixmap() const { return *m_yesPartialPixmap; }
+
+public slots:
+ void slotAddEntry();
+ void slotEditEntry();
+ void slotRemoveEntry();
+ void setACL( const KACL &anACL );
+ void setDefaultACL( const KACL &anACL );
+
+protected slots:
+ void entryClicked( TQListViewItem* pItem, const TQPoint& pt, int col );
+protected:
+ void contentsMousePressEvent( TQMouseEvent * e );
+
+private:
+ void fillItemsFromACL( const KACL &pACL, bool defaults = false );
+ KACL itemsToACL( bool defaults ) const;
+
+ KACL m_ACL;
+ KACL m_defaultACL;
+ unsigned short m_mask;
+ bool m_hasMask;
+ bool m_allowDefaults;
+ TQStringList m_allUsers;
+ TQStringList m_allGroups;
+ TQPixmap* m_yesPixmap;
+ TQPixmap* m_yesPartialPixmap;
+};
+
+class EditACLEntryDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item,
+ const TQStringList &users,
+ const TQStringList &groups,
+ const TQStringList &defaultUsers,
+ const TQStringList &defaultGroups,
+ int allowedTypes = KACLListView::AllTypes,
+ int allowedDefaultTypes = KACLListView::AllTypes,
+ bool allowDefault = false );
+ KACLListViewItem* item() const { return m_item; }
+public slots:
+ void slotOk();
+ void slotSelectionChanged( int id );
+private slots:
+ void slotUpdateAllowedUsersAndGroups();
+ void slotUpdateAllowedTypes();
+private:
+ KACLListView *m_listView;
+ KACLListViewItem *m_item;
+ TQStringList m_users;
+ TQStringList m_groups;
+ TQStringList m_defaultUsers;
+ TQStringList m_defaultGroups;
+ int m_allowedTypes;
+ int m_allowedDefaultTypes;
+ TQVButtonGroup *m_buttonGroup;
+ TQComboBox *m_usersCombo;
+ TQComboBox *m_groupsCombo;
+ TQWidgetStack *m_widgetStack;
+ TQCheckBox *m_defaultCB;
+};
+
+
+class KACLListViewItem : public KListViewItem
+{
+public:
+ KACLListViewItem( TQListView* parent, KACLListView::EntryType type,
+ unsigned short value,
+ bool defaultEntry,
+ const TQString& qualifier = TQString::null );
+ virtual ~KACLListViewItem();
+ virtual TQString key( int column, bool ascending ) const;
+
+ void calcEffectiveRights();
+
+ bool isDeletable() const;
+ bool isAllowedToChangeType() const;
+
+ void togglePerm( acl_perm_t perm );
+
+ virtual void paintCell( TQPainter *p, const TQColorGroup &cg,
+ int column, int width, int alignment );
+
+ void updatePermPixmaps();
+ void repaint();
+
+ KACLListView::EntryType type;
+ unsigned short value;
+ bool isDefault;
+ TQString qualifier;
+ bool isPartial;
+
+private:
+ KACLListView* m_pACLListView;
+};
+
+
+#endif
+#endif
diff --git a/tdeio/tdefile/kcombiview.cpp b/tdeio/tdefile/kcombiview.cpp
new file mode 100644
index 000000000..bc3d43384
--- /dev/null
+++ b/tdeio/tdefile/kcombiview.cpp
@@ -0,0 +1,371 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ 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.
+*/
+
+// $Id$
+
+#include <assert.h>
+
+#include "tdefileitem.h"
+#include "kcombiview.h"
+#include "tdefileiconview.h"
+#include "tdefiledetailview.h"
+#include "config-tdefile.h"
+
+#include <tqevent.h>
+
+#include <tqdir.h>
+
+#include <kapplication.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <tqvaluelist.h>
+
+KCombiView::KCombiView( TQWidget *parent, const char *name)
+ : TQSplitter( parent, name),
+ KFileView(),
+ right(0),
+ m_lastViewForNextItem(0),
+ m_lastViewForPrevItem(0)
+{
+ left = new KFileIconView( this, "left" );
+ left->setAcceptDrops(false);
+ left->viewport()->setAcceptDrops(false);
+ left->setGridX( 160 );
+ left->KFileView::setViewMode( Directories );
+ left->setArrangement( TQIconView::LeftToRight );
+ left->setParentView( this );
+ left->setAcceptDrops(false);
+ left->installEventFilter( this );
+
+ connect( sig, TQT_SIGNAL( sortingChanged( TQDir::SortSpec ) ),
+ TQT_SLOT( slotSortingChanged( TQDir::SortSpec ) ));
+}
+
+KCombiView::~KCombiView()
+{
+ delete right;
+}
+
+void KCombiView::setRight(KFileView *view)
+{
+ delete right;
+ right = view;
+ right->KFileView::setViewMode( Files );
+ setViewName( right->viewName() );
+
+ TQValueList<int> lst;
+ lst << left->gridX() + 2 * left->spacing();
+ setSizes( lst );
+ setResizeMode( left, TQSplitter::KeepSize );
+
+ right->setParentView( this );
+ right->widget()->setAcceptDrops(acceptDrops());
+ right->setDropOptions(dropOptions());
+ right->widget()->installEventFilter( this );
+}
+
+
+void KCombiView::insertItem( KFileItem *item )
+{
+ KFileView::insertItem( item );
+
+ if ( item->isDir() ) {
+ left->updateNumbers( item );
+ left->insertItem( item );
+ }
+ else {
+ right->updateNumbers( item );
+ right->insertItem( item );
+ }
+}
+
+void KCombiView::setSorting( TQDir::SortSpec sort )
+{
+ if ( !right )
+ kdFatal() << "You need to call setRight( someview ) before!" << endl;
+ right->setSorting( sort );
+ left->setSorting( sort );
+
+ KFileView::setSorting( right->sorting() );
+}
+
+void KCombiView::clearView()
+{
+ left->clearView();
+ if ( right )
+ right->clearView();
+}
+
+void KCombiView::updateView( bool b )
+{
+ left->updateView( b );
+ if ( right )
+ right->updateView( b );
+}
+
+void KCombiView::updateView( const KFileItem *i )
+{
+ left->updateView( i );
+ if ( right )
+ right->updateView( i );
+}
+
+void KCombiView::removeItem( const KFileItem *i )
+{
+ left->removeItem( i );
+ if ( right )
+ right->removeItem( i );
+ KFileView::removeItem( i );
+}
+
+void KCombiView::listingCompleted()
+{
+ left->listingCompleted();
+ if ( right )
+ right->listingCompleted();
+}
+
+void KCombiView::clear()
+{
+ KFileView::clear();
+ left->KFileView::clear();
+ if ( right )
+ right->clear();
+}
+
+void KCombiView::clearSelection()
+{
+ left->clearSelection();
+ if ( right )
+ right->clearSelection();
+}
+
+void KCombiView::selectAll()
+{
+ left->selectAll();
+ if ( right )
+ right->selectAll();
+}
+
+void KCombiView::invertSelection()
+{
+ left->invertSelection();
+ if ( right )
+ right->invertSelection();
+}
+
+bool KCombiView::isSelected( const KFileItem *item ) const
+{
+ assert( right ); // for performance reasons no if ( right ) check.
+ return (right->isSelected( item ) || left->isSelected( item ));
+}
+
+void KCombiView::setSelectionMode( KFile::SelectionMode sm )
+{
+ // I think the left view (directories should always be in
+ // Single-Mode, right?
+ // left->setSelectionMode( sm );
+ if ( !right )
+ kdFatal() << "You need to call setRight( someview ) before!" << endl;
+ right->setSelectionMode( sm );
+}
+
+void KCombiView::setSelected( const KFileItem *item, bool enable )
+{
+ left->setSelected( item, enable );
+ if ( right )
+ right->setSelected( item, enable );
+}
+
+void KCombiView::setCurrentItem( const KFileItem *item )
+{
+ left->setCurrentItem( item );
+ if ( right )
+ right->setCurrentItem( item );
+}
+
+KFileItem * KCombiView::currentFileItem() const
+{
+ // we can actually have two current items, one in each view. So we simply
+ // prefer the fileview's item over the directory's.
+ // Smarter: if the right view has focus, prefer that over the left.
+ if ( !right )
+ return left->currentFileItem();
+
+ KFileView *preferredView = focusView( right );
+ KFileItem *item = preferredView->currentFileItem();
+ if ( !item && preferredView != left )
+ item = left->currentFileItem();
+
+ return item;
+}
+
+void KCombiView::ensureItemVisible(const KFileItem *item)
+{
+ left->ensureItemVisible( item );
+ if ( right )
+ right->ensureItemVisible( item );
+}
+
+KFileItem * KCombiView::firstFileItem() const
+{
+ if ( !right )
+ return left->firstFileItem();
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->firstFileItem();
+ if ( !item )
+ item = otherView->firstFileItem();
+
+ return item;
+}
+
+KFileItem * KCombiView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( !right )
+ return left->nextItem( fileItem );
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->nextItem( fileItem );
+
+ if ( item )
+ m_lastViewForNextItem = preferredView;
+ else { // no item, check other view
+ // when changing from one to another view, we need to continue
+ // with the next view's first item!
+ if ( m_lastViewForNextItem != otherView ) {
+ m_lastViewForNextItem = otherView;
+ return otherView->firstFileItem();
+ }
+
+ item = otherView->nextItem( fileItem );
+ m_lastViewForNextItem = otherView;
+ }
+
+ return item;
+}
+
+KFileItem * KCombiView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( !right )
+ return left->nextItem( fileItem );
+
+ KFileView *preferredView = focusView( left );
+ KFileView *otherView = (preferredView == left) ? right : left;
+ KFileItem *item = preferredView->prevItem( fileItem );
+ if ( item )
+ m_lastViewForPrevItem = preferredView;
+
+ else { // no item, check other view
+ // when changing from one to another view, we need to continue
+ // with the next view's last item!
+ if ( m_lastViewForPrevItem != otherView ) {
+ fileItem = otherView->firstFileItem();
+ while ( otherView->nextItem( fileItem ) ) // find the last item
+ fileItem = otherView->nextItem( fileItem );
+ }
+
+ item = otherView->prevItem( fileItem );
+ m_lastViewForPrevItem = otherView;
+ }
+
+ return item;
+}
+
+void KCombiView::slotSortingChanged( TQDir::SortSpec sorting )
+{
+ KFileView::setSorting( sorting );
+}
+
+KFileView *KCombiView::focusView( KFileView *preferred ) const
+{
+ TQWidget *w = focusWidget();
+ KFileView *other = (right == preferred) ? left : right;
+ return (preferred && w == preferred->widget()) ? preferred : other;
+}
+
+void KCombiView::readConfig( TDEConfig *config, const TQString& group )
+{
+ left->readConfig( config, group );
+ if ( right )
+ right->readConfig( config, group );
+}
+
+void KCombiView::writeConfig( TDEConfig *config, const TQString& group )
+{
+ left->writeConfig( config, group );
+ if ( right )
+ right->writeConfig( config, group );
+}
+
+KActionCollection * KCombiView::actionCollection() const
+{
+ return focusView( right )->actionCollection();
+}
+
+void KCombiView::setAcceptDrops(bool b)
+{
+ left->setAcceptDrops(b);
+ if (right)
+ right->widget()->setAcceptDrops(b);
+ TQSplitter::setAcceptDrops(b);
+}
+
+void KCombiView::setDropOptions_impl(int options)
+{
+ KFileView::setDropOptions_impl(options);
+ left->setDropOptions(options);
+ if (right)
+ right->setDropOptions(options);
+}
+
+void KCombiView::virtual_hook( int id, void* data )
+{
+ switch(id) {
+ case VIRTUAL_SET_DROP_OPTIONS:
+ setDropOptions_impl(*(int *)data);
+ break;
+ default:
+ KFileView::virtual_hook( id, data );
+ }
+}
+
+bool KCombiView::eventFilter( TQObject *o, TQEvent *e )
+{
+ int type = e->type();
+
+ // only the focused view may have a selection
+ if ( type == TQEvent::FocusIn )
+ {
+ if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(left) )
+ right->clearSelection();
+ else if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(right->widget()) )
+ left->clearSelection();
+ }
+
+ return TQSplitter::eventFilter( o, e );
+}
+
+#include "kcombiview.moc"
+
diff --git a/tdeio/tdefile/kcombiview.h b/tdeio/tdefile/kcombiview.h
new file mode 100644
index 000000000..8da3da3fb
--- /dev/null
+++ b/tdeio/tdefile/kcombiview.h
@@ -0,0 +1,133 @@
+/* -*- c++ -*-
+ This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+
+ 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 _KCOMBIVIEW_H
+#define _KCOMBIVIEW_H
+
+#include <tqsplitter.h>
+#include <klocale.h>
+
+#include <tdefile.h>
+#include <tdefileview.h>
+
+class KFileIconView;
+class TQEvent;
+class TQIconViewItem;
+
+/**
+ * This view is designed to combine two KFileViews into one widget, to show
+ * directories on the left side and files on the right side.
+ *
+ * Methods like selectedItems() to query status _only_ work on the right side,
+ * i.e. on the files.
+ *
+ * After creating the KCombiView, you need to supply the view shown in the
+ * right, (see setRight()). Available KFileView implementations are
+ * KFileIconView and KFileDetailView.
+ *
+ * Most of the below methods are just implementations of the baseclass
+ * KFileView, so look there for documentation.
+ *
+ * @see KFileView
+ * @see KFileIconView
+ * @see KFileDetailView
+ * @see KDirOperator
+ */
+class TDEIO_EXPORT KCombiView : public TQSplitter,
+ public KFileView
+{
+ Q_OBJECT
+
+public:
+ KCombiView( TQWidget *parent, const char *name);
+ virtual ~KCombiView();
+
+ virtual TQWidget *widget() { return this; }
+ virtual void clearView();
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem( const KFileItem * );
+ virtual void listingCompleted();
+
+ /**
+ * Sets the view to be shown in the right. You need to call this before
+ * doing anything else with this widget.
+ */
+ void setRight(KFileView *view);
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected( const KFileItem * ) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void insertItem( KFileItem *i );
+ virtual void clear();
+
+ virtual void setSorting( TQDir::SortSpec sort );
+
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null);
+
+ void ensureItemVisible( const KFileItem * );
+
+ virtual KActionCollection * actionCollection() const;
+
+ virtual void setAcceptDrops(bool b);
+
+protected:
+ KFileIconView *left;
+ KFileView *right;
+
+protected slots:
+ void slotSortingChanged( TQDir::SortSpec );
+
+private:
+ KFileView *focusView( KFileView *preferred ) const;
+
+ // in nextItem() and prevItem(), we have to switch views, when the first
+ // view returns 0L. So we need to remember which view was used in the
+ // previous call to next/prevItem(). Yes, it's a hack, but it works for
+ // some cases at least.
+ mutable KFileView *m_lastViewForNextItem;
+ mutable KFileView *m_lastViewForPrevItem;
+
+protected:
+ virtual bool eventFilter( TQObject *o, TQEvent *e );
+ void setDropOptions_impl(int options);
+
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KCombiViewPrivate;
+ KCombiViewPrivate *d;
+
+};
+
+#endif
diff --git a/tdeio/tdefile/kcustommenueditor.cpp b/tdeio/tdefile/kcustommenueditor.cpp
new file mode 100644
index 000000000..48c911e30
--- /dev/null
+++ b/tdeio/tdefile/kcustommenueditor.cpp
@@ -0,0 +1,242 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 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; version 2
+ of the License.
+
+ 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 <tqhbox.h>
+#include <tqregexp.h>
+#include <tqimage.h>
+#include <tqpushbutton.h>
+#include <tqdir.h>
+
+#include <kbuttonbox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klistview.h>
+#include <kservice.h>
+#include <kstandarddirs.h>
+#include <tdeconfigbase.h>
+#include <kopenwith.h>
+
+#include "kcustommenueditor.h"
+
+class KCustomMenuEditor::Item : public TQListViewItem
+{
+public:
+ Item(TQListView *parent, KService::Ptr service)
+ : TQListViewItem(parent),
+ s(service)
+ {
+ init();
+ }
+
+ Item(TQListViewItem *parent, KService::Ptr service)
+ : TQListViewItem(parent),
+ s(service)
+ {
+ init();
+ }
+
+ void init()
+ {
+ TQString serviceName = s->name();
+
+ // item names may contain ampersands. To avoid them being converted
+ // to accelators, replace them with two ampersands.
+ serviceName.replace("&", "&&");
+
+ TQPixmap normal = TDEGlobal::instance()->iconLoader()->loadIcon(s->icon(), KIcon::Small,
+ 0, KIcon::DefaultState, 0L, true);
+
+ // make sure they are not larger than 16x16
+ if (normal.width() > 16 || normal.height() > 16) {
+ TQImage tmp = normal.convertToImage();
+ tmp = tmp.smoothScale(16, 16);
+ normal.convertFromImage(tmp);
+ }
+ setText(0, serviceName);
+ setPixmap(0, normal);
+ }
+
+ KService::Ptr s;
+};
+
+class KCustomMenuEditor::KCustomMenuEditorPrivate
+{
+public:
+ TQPushButton * pbRemove;
+ TQPushButton * pbMoveUp;
+ TQPushButton * pbMoveDown;
+};
+
+KCustomMenuEditor::KCustomMenuEditor(TQWidget *parent)
+ : KDialogBase(parent, "custommenueditor", true, i18n("Menu Editor"), Ok|Cancel, Ok, true),
+ m_listView(0)
+{
+ d = new KCustomMenuEditorPrivate;
+ TQHBox *page = makeHBoxMainWidget();
+ m_listView = new KListView(page);
+ m_listView->addColumn(i18n("Menu"));
+ m_listView->setFullWidth(true);
+ m_listView->setSorting(-1);
+ KButtonBox *buttonBox = new KButtonBox(page, Qt::Vertical);
+ buttonBox->addButton(i18n("New..."), TQT_TQOBJECT(this), TQT_SLOT(slotNewItem()));
+ d->pbRemove=buttonBox->addButton(i18n("Remove"), TQT_TQOBJECT(this), TQT_SLOT(slotRemoveItem()));
+ d->pbMoveUp=buttonBox->addButton(i18n("Move Up"), TQT_TQOBJECT(this), TQT_SLOT(slotMoveUp()));
+ d->pbMoveDown=buttonBox->addButton(i18n("Move Down"), TQT_TQOBJECT(this), TQT_SLOT(slotMoveDown()));
+ buttonBox->layout();
+ connect( m_listView, TQT_SIGNAL( selectionChanged () ), this, TQT_SLOT( refreshButton() ) );
+ refreshButton();
+}
+
+KCustomMenuEditor::~KCustomMenuEditor()
+{
+ delete d;
+ d=0;
+}
+
+void KCustomMenuEditor::refreshButton()
+{
+ TQListViewItem *item = m_listView->currentItem();
+ d->pbRemove->setEnabled( item );
+ d->pbMoveUp->setEnabled( item && item->itemAbove() );
+ d->pbMoveDown->setEnabled( item && item->itemBelow() );
+}
+
+void
+KCustomMenuEditor::load(TDEConfigBase *cfg)
+{
+ cfg->setGroup(TQString::null);
+ int count = cfg->readNumEntry("NrOfItems");
+ TQListViewItem *last = 0;
+ for(int i = 0; i < count; i++)
+ {
+ TQString entry = cfg->readPathEntry(TQString("Item%1").arg(i+1));
+ if (entry.isEmpty())
+ continue;
+
+ // Try KSycoca first.
+ KService::Ptr menuItem = KService::serviceByDesktopPath( entry );
+ if (!menuItem)
+ menuItem = KService::serviceByDesktopName( entry );
+ if (!menuItem)
+ menuItem = new KService( entry );
+
+ if (!menuItem->isValid())
+ continue;
+
+ TQListViewItem *item = new Item(m_listView, menuItem);
+ item->moveItem(last);
+ last = item;
+ }
+}
+
+void
+KCustomMenuEditor::save(TDEConfigBase *cfg)
+{
+ // First clear the whole config file.
+ TQStringList groups = cfg->groupList();
+ for(TQStringList::ConstIterator it = groups.begin();
+ it != groups.end(); ++it)
+ {
+ cfg->deleteGroup(*it);
+ }
+
+ cfg->setGroup(TQString::null);
+ Item * item = (Item *) m_listView->firstChild();
+ int i = 0;
+ while(item)
+ {
+ i++;
+ TQString path = item->s->desktopEntryPath();
+ if (TQDir::isRelativePath(path) || TQDir::isRelativePath(TDEGlobal::dirs()->relativeLocation("xdgdata-apps", path)))
+ path = item->s->desktopEntryName();
+ cfg->writePathEntry(TQString("Item%1").arg(i), path);
+ item = (Item *) item->nextSibling();
+ }
+ cfg->writeEntry("NrOfItems", i);
+}
+
+void
+KCustomMenuEditor::slotNewItem()
+{
+ TQListViewItem *item = m_listView->currentItem();
+
+ KOpenWithDlg dlg(this);
+ dlg.setSaveNewApplications(true);
+
+ if (dlg.exec())
+ {
+ KService::Ptr s = dlg.service();
+ if (s && s->isValid())
+ {
+ Item *newItem = new Item(m_listView, s);
+ newItem->moveItem(item);
+ }
+ refreshButton();
+ }
+}
+
+void
+KCustomMenuEditor::slotRemoveItem()
+{
+ TQListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ delete item;
+ refreshButton();
+}
+
+void
+KCustomMenuEditor::slotMoveUp()
+{
+ TQListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ TQListViewItem *searchItem = m_listView->firstChild();
+ while(searchItem)
+ {
+ TQListViewItem *next = searchItem->nextSibling();
+ if (next == item)
+ {
+ searchItem->moveItem(item);
+ break;
+ }
+ searchItem = next;
+ }
+ refreshButton();
+}
+
+void
+KCustomMenuEditor::slotMoveDown()
+{
+ TQListViewItem *item = m_listView->currentItem();
+ if (!item)
+ return;
+
+ TQListViewItem *after = item->nextSibling();
+ if (!after)
+ return;
+
+ item->moveItem( after );
+ refreshButton();
+}
+
+#include "kcustommenueditor.moc"
diff --git a/tdeio/tdefile/kcustommenueditor.h b/tdeio/tdefile/kcustommenueditor.h
new file mode 100644
index 000000000..108e9c477
--- /dev/null
+++ b/tdeio/tdefile/kcustommenueditor.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 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; version 2
+ of the License.
+
+ 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 _KCUSTOMMENUEDITOR_H_
+#define _KCUSTOMMENUEDITOR_H_
+
+#include <kdialogbase.h>
+
+class KListView;
+class TDEConfigBase;
+
+ /*
+ * Dialog for editing custom menus.
+ *
+ * @author Waldo Bastian (bastian@kde.org)
+ * @since 3.1
+ */
+class TDEIO_EXPORT KCustomMenuEditor : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a dialog for editing a custom menu
+ */
+ KCustomMenuEditor(TQWidget *parent);
+ ~KCustomMenuEditor();
+ /**
+ * load the custom menu
+ */
+ void load(TDEConfigBase *);
+
+ /**
+ * save the custom menu
+ */
+ void save(TDEConfigBase *);
+
+public slots:
+ void slotNewItem();
+ void slotRemoveItem();
+ void slotMoveUp();
+ void slotMoveDown();
+ void refreshButton();
+
+protected:
+ class Item;
+ KListView *m_listView;
+
+ class KCustomMenuEditorPrivate;
+ KCustomMenuEditorPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kdiroperator.cpp b/tdeio/tdefile/kdiroperator.cpp
new file mode 100644
index 000000000..ea3183f78
--- /dev/null
+++ b/tdeio/tdefile/kdiroperator.cpp
@@ -0,0 +1,1740 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000 Stephan Kulow <coolo@kde.org>
+ 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@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 <unistd.h>
+
+#include <tqdir.h>
+#include <tqapplication.h>
+#include <tqdialog.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+#include <tqpopupmenu.h>
+#include <tqregexp.h>
+#include <tqtimer.h>
+#include <tqvbox.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kdirlister.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kprogress.h>
+#include <kstdaction.h>
+#include <tdeio/job.h>
+#include <tdeio/jobclasses.h>
+#include <tdeio/netaccess.h>
+#include <tdeio/previewjob.h>
+#include <tdeio/renamedlg.h>
+#include <kpropertiesdialog.h>
+#include <kservicetypefactory.h>
+#include <kstdaccel.h>
+#include <kde_file.h>
+
+#include "config-tdefile.h"
+#include "kcombiview.h"
+#include "kdiroperator.h"
+#include "tdefiledetailview.h"
+#include "tdefileiconview.h"
+#include "tdefilepreview.h"
+#include "tdefileview.h"
+#include "tdefileitem.h"
+#include "tdefilemetapreview.h"
+
+
+template class TQPtrStack<KURL>;
+template class TQDict<KFileItem>;
+
+
+class KDirOperator::KDirOperatorPrivate
+{
+public:
+ KDirOperatorPrivate() {
+ onlyDoubleClickSelectsFiles = false;
+ progressDelayTimer = 0L;
+ dirHighlighting = false;
+ config = 0L;
+ dropOptions = 0;
+ }
+
+ ~KDirOperatorPrivate() {
+ delete progressDelayTimer;
+ }
+
+ bool dirHighlighting;
+ TQString lastURL; // used for highlighting a directory on cdUp
+ bool onlyDoubleClickSelectsFiles;
+ TQTimer *progressDelayTimer;
+ KActionSeparator *viewActionSeparator;
+ int dropOptions;
+
+ TDEConfig *config;
+ TQString configGroup;
+};
+
+KDirOperator::KDirOperator(const KURL& _url,
+ TQWidget *parent, const char* _name)
+ : TQWidget(parent, _name),
+ dir(0),
+ m_fileView(0),
+ progress(0)
+{
+ myPreview = 0L;
+ myMode = KFile::File;
+ m_viewKind = KFile::Simple;
+ mySorting = static_cast<TQDir::SortSpec>(TQDir::Name | TQDir::DirsFirst);
+ d = new KDirOperatorPrivate;
+
+ if (_url.isEmpty()) { // no dir specified -> current dir
+ TQString strPath = TQDir::currentDirPath();
+ strPath.append('/');
+ currUrl = KURL();
+ currUrl.setProtocol(TQString::fromLatin1("file"));
+ currUrl.setPath(strPath);
+ }
+ else {
+ currUrl = _url;
+ if ( currUrl.protocol().isEmpty() )
+ currUrl.setProtocol(TQString::fromLatin1("file"));
+
+ currUrl.addPath("/"); // make sure we have a trailing slash!
+ }
+
+ setDirLister( new KDirLister( true ) );
+
+ connect(&myCompletion, TQT_SIGNAL(match(const TQString&)),
+ TQT_SLOT(slotCompletionMatch(const TQString&)));
+
+ progress = new KProgress(this, "progress");
+ progress->adjustSize();
+ progress->move(2, height() - progress->height() -2);
+
+ d->progressDelayTimer = new TQTimer( this, "progress delay timer" );
+ connect( d->progressDelayTimer, TQT_SIGNAL( timeout() ),
+ TQT_SLOT( slotShowProgress() ));
+
+ myCompleteListDirty = false;
+
+ backStack.setAutoDelete( true );
+ forwardStack.setAutoDelete( true );
+
+ // action stuff
+ setupActions();
+ setupMenu();
+
+ setFocusPolicy(TQ_WheelFocus);
+}
+
+KDirOperator::~KDirOperator()
+{
+ resetCursor();
+ if ( m_fileView )
+ {
+ if ( d->config )
+ m_fileView->writeConfig( d->config, d->configGroup );
+
+ delete m_fileView;
+ m_fileView = 0L;
+ }
+
+ delete myPreview;
+ delete dir;
+ delete d;
+}
+
+
+void KDirOperator::setSorting( TQDir::SortSpec spec )
+{
+ if ( m_fileView )
+ m_fileView->setSorting( spec );
+ mySorting = spec;
+ updateSortActions();
+}
+
+void KDirOperator::resetCursor()
+{
+ TQApplication::restoreOverrideCursor();
+ progress->hide();
+}
+
+void KDirOperator::insertViewDependentActions()
+{
+ // If we have a new view actionCollection(), insert its actions
+ // into viewActionMenu.
+
+ if( !m_fileView )
+ return;
+
+ if ( (viewActionMenu->popupMenu()->count() == 0) || // Not yet initialized or...
+ (viewActionCollection != m_fileView->actionCollection()) ) // ...changed since.
+ {
+ if (viewActionCollection)
+ {
+ disconnect( viewActionCollection, TQT_SIGNAL( inserted( KAction * )),
+ this, TQT_SLOT( slotViewActionAdded( KAction * )));
+ disconnect( viewActionCollection, TQT_SIGNAL( removed( KAction * )),
+ this, TQT_SLOT( slotViewActionRemoved( KAction * )));
+ }
+
+ viewActionMenu->popupMenu()->clear();
+// viewActionMenu->insert( shortAction );
+// viewActionMenu->insert( detailedAction );
+// viewActionMenu->insert( actionSeparator );
+ viewActionMenu->insert( myActionCollection->action( "short view" ) );
+ viewActionMenu->insert( myActionCollection->action( "detailed view" ) );
+ viewActionMenu->insert( actionSeparator );
+ viewActionMenu->insert( showHiddenAction );
+// viewActionMenu->insert( myActionCollection->action( "single" ));
+ viewActionMenu->insert( separateDirsAction );
+ // Warning: adjust slotViewActionAdded() and slotViewActionRemoved()
+ // when you add/remove actions here!
+
+ viewActionCollection = m_fileView->actionCollection();
+ if (!viewActionCollection)
+ return;
+
+ if ( !viewActionCollection->isEmpty() )
+ {
+ viewActionMenu->insert( d->viewActionSeparator );
+
+ // first insert the normal actions, then the grouped ones
+ TQStringList groups = viewActionCollection->groups();
+ groups.prepend( TQString::null ); // actions without group
+ TQStringList::ConstIterator git = groups.begin();
+ KActionPtrList list;
+ KAction *sep = actionCollection()->action("separator");
+ for ( ; git != groups.end(); ++git )
+ {
+ if ( git != groups.begin() )
+ viewActionMenu->insert( sep );
+
+ list = viewActionCollection->actions( *git );
+ KActionPtrList::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it )
+ viewActionMenu->insert( *it );
+ }
+ }
+
+ connect( viewActionCollection, TQT_SIGNAL( inserted( KAction * )),
+ TQT_SLOT( slotViewActionAdded( KAction * )));
+ connect( viewActionCollection, TQT_SIGNAL( removed( KAction * )),
+ TQT_SLOT( slotViewActionRemoved( KAction * )));
+ }
+}
+
+void KDirOperator::activatedMenu( const KFileItem *, const TQPoint& pos )
+{
+ setupMenu();
+ updateSelectionDependentActions();
+
+ actionMenu->popup( pos );
+}
+
+void KDirOperator::updateSelectionDependentActions()
+{
+ bool hasSelection = m_fileView && m_fileView->selectedItems() &&
+ !m_fileView->selectedItems()->isEmpty();
+ myActionCollection->action( "trash" )->setEnabled( hasSelection );
+ myActionCollection->action( "delete" )->setEnabled( hasSelection );
+ myActionCollection->action( "properties" )->setEnabled( hasSelection );
+}
+
+void KDirOperator::setPreviewWidget(const TQWidget *w)
+{
+ if(w != 0L)
+ m_viewKind = (m_viewKind | KFile::PreviewContents);
+ else
+ m_viewKind = (m_viewKind & ~KFile::PreviewContents);
+
+ delete myPreview;
+ myPreview = w;
+
+ KToggleAction *preview = static_cast<KToggleAction*>(myActionCollection->action("preview"));
+ preview->setEnabled( w != 0L );
+ preview->setChecked( w != 0L );
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+int KDirOperator::numDirs() const
+{
+ return m_fileView ? m_fileView->numDirs() : 0;
+}
+
+int KDirOperator::numFiles() const
+{
+ return m_fileView ? m_fileView->numFiles() : 0;
+}
+
+void KDirOperator::slotDetailedView()
+{
+ KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Simple) | KFile::Detail );
+ setView( view );
+}
+
+void KDirOperator::slotSimpleView()
+{
+ KFile::FileView view = static_cast<KFile::FileView>( (m_viewKind & ~KFile::Detail) | KFile::Simple );
+ setView( view );
+}
+
+void KDirOperator::slotToggleHidden( bool show )
+{
+ dir->setShowingDotFiles( show );
+ updateDir();
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::slotSeparateDirs()
+{
+ if (separateDirsAction->isChecked())
+ {
+ KFile::FileView view = static_cast<KFile::FileView>( m_viewKind | KFile::SeparateDirs );
+ setView( view );
+ }
+ else
+ {
+ KFile::FileView view = static_cast<KFile::FileView>( m_viewKind & ~KFile::SeparateDirs );
+ setView( view );
+ }
+}
+
+void KDirOperator::slotDefaultPreview()
+{
+ m_viewKind = m_viewKind | KFile::PreviewContents;
+ if ( !myPreview ) {
+ myPreview = new KFileMetaPreview( this );
+ (static_cast<KToggleAction*>( myActionCollection->action("preview") ))->setChecked(true);
+ }
+
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+void KDirOperator::slotSortByName()
+{
+ int sorting = (m_fileView->sorting()) & ~TQDir::SortByMask;
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting | TQDir::Name ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( true );
+}
+
+void KDirOperator::slotSortBySize()
+{
+ int sorting = (m_fileView->sorting()) & ~TQDir::SortByMask;
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting | TQDir::Size ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( false );
+}
+
+void KDirOperator::slotSortByDate()
+{
+ int sorting = (m_fileView->sorting()) & ~TQDir::SortByMask;
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting | TQDir::Time ));
+ mySorting = m_fileView->sorting();
+ caseInsensitiveAction->setEnabled( false );
+}
+
+void KDirOperator::slotSortReversed()
+{
+ if ( m_fileView )
+ m_fileView->sortReversed();
+}
+
+void KDirOperator::slotToggleDirsFirst()
+{
+ TQDir::SortSpec sorting = m_fileView->sorting();
+ if ( !KFile::isSortDirsFirst( sorting ) )
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting | TQDir::DirsFirst ));
+ else
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting & ~TQDir::DirsFirst));
+ mySorting = m_fileView->sorting();
+}
+
+void KDirOperator::slotToggleIgnoreCase()
+{
+ TQDir::SortSpec sorting = m_fileView->sorting();
+ if ( !KFile::isSortCaseInsensitive( sorting ) )
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting | TQDir::IgnoreCase ));
+ else
+ m_fileView->setSorting( static_cast<TQDir::SortSpec>( sorting & ~TQDir::IgnoreCase));
+ mySorting = m_fileView->sorting();
+}
+
+void KDirOperator::mkdir()
+{
+ bool ok;
+ TQString where = url().pathOrURL();
+ TQString name = i18n( "New Folder" );
+ if ( url().isLocalFile() && TQFileInfo( url().path(+1) + name ).exists() )
+ name = TDEIO::RenameDlg::suggestName( url(), name );
+
+ TQString dir = KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Create new folder in:\n%1" ).arg( where ),
+ name, &ok, this);
+ if (ok)
+ mkdir( TDEIO::encodeFileName( dir ), true );
+}
+
+bool KDirOperator::mkdir( const TQString& directory, bool enterDirectory )
+{
+ // Creates "directory", relative to the current directory (currUrl).
+ // The given path may contain any number directories, existant or not.
+ // They will all be created, if possible.
+
+ bool writeOk = false;
+ bool exists = false;
+ KURL url( currUrl );
+
+ TQStringList dirs = TQStringList::split( TQDir::separator(), directory );
+ TQStringList::ConstIterator it = dirs.begin();
+
+ for ( ; it != dirs.end(); ++it )
+ {
+ url.addPath( *it );
+ exists = TDEIO::NetAccess::exists( url, false, 0 );
+ writeOk = !exists && TDEIO::NetAccess::mkdir( url, topLevelWidget() );
+ }
+
+ if ( exists ) // url was already existant
+ {
+ KMessageBox::sorry(viewWidget(), i18n("A file or folder named %1 already exists.").arg(url.pathOrURL()));
+ enterDirectory = false;
+ }
+ else if ( !writeOk ) {
+ KMessageBox::sorry(viewWidget(), i18n("You do not have permission to "
+ "create that folder." ));
+ }
+ else if ( enterDirectory ) {
+ setURL( url, true );
+ }
+
+ return writeOk;
+}
+
+TDEIO::DeleteJob * KDirOperator::del( const KFileItemList& items,
+ bool ask, bool showProgress )
+{
+ return del( items, this, ask, showProgress );
+}
+
+TDEIO::DeleteJob * KDirOperator::del( const KFileItemList& items,
+ TQWidget *parent,
+ bool ask, bool showProgress )
+{
+ if ( items.isEmpty() ) {
+ KMessageBox::information( parent,
+ i18n("You did not select a file to delete."),
+ i18n("Nothing to Delete") );
+ return 0L;
+ }
+
+ KURL::List urls;
+ TQStringList files;
+ KFileItemListIterator it( items );
+
+ for ( ; it.current(); ++it ) {
+ KURL url = (*it)->url();
+ urls.append( url );
+ if ( url.isLocalFile() )
+ files.append( url.path() );
+ else
+ files.append( url.prettyURL() );
+ }
+
+ bool doIt = !ask;
+ if ( ask ) {
+ int ret;
+ if ( items.count() == 1 ) {
+ ret = KMessageBox::warningContinueCancel( parent,
+ i18n( "<qt>Do you really want to delete\n <b>'%1'</b>?</qt>" )
+ .arg( files.first() ),
+ i18n("Delete File"),
+ KStdGuiItem::del(), "AskForDelete" );
+ }
+ else
+ ret = KMessageBox::warningContinueCancelList( parent,
+ i18n("Do you really want to delete this item?", "Do you really want to delete these %n items?", items.count() ),
+ files,
+ i18n("Delete Files"),
+ KStdGuiItem::del(), "AskForDelete" );
+ doIt = (ret == KMessageBox::Continue);
+ }
+
+ if ( doIt ) {
+ TDEIO::DeleteJob *job = TDEIO::del( urls, false, showProgress );
+ job->setWindow (topLevelWidget());
+ job->setAutoErrorHandlingEnabled( true, parent );
+ return job;
+ }
+
+ return 0L;
+}
+
+void KDirOperator::deleteSelected()
+{
+ if ( !m_fileView )
+ return;
+
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( list )
+ del( *list );
+}
+
+TDEIO::CopyJob * KDirOperator::trash( const KFileItemList& items,
+ TQWidget *parent,
+ bool ask, bool showProgress )
+{
+ if ( items.isEmpty() ) {
+ KMessageBox::information( parent,
+ i18n("You did not select a file to trash."),
+ i18n("Nothing to Trash") );
+ return 0L;
+ }
+
+ KURL::List urls;
+ TQStringList files;
+ KFileItemListIterator it( items );
+
+ for ( ; it.current(); ++it ) {
+ KURL url = (*it)->url();
+ urls.append( url );
+ if ( url.isLocalFile() )
+ files.append( url.path() );
+ else
+ files.append( url.prettyURL() );
+ }
+
+ bool doIt = !ask;
+ if ( ask ) {
+ int ret;
+ if ( items.count() == 1 ) {
+ ret = KMessageBox::warningContinueCancel( parent,
+ i18n( "<qt>Do you really want to trash\n <b>'%1'</b>?</qt>" )
+ .arg( files.first() ),
+ i18n("Trash File"),
+ KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" );
+ }
+ else
+ ret = KMessageBox::warningContinueCancelList( parent,
+ i18n("translators: not called for n == 1", "Do you really want to trash these %n items?", items.count() ),
+ files,
+ i18n("Trash Files"),
+ KGuiItem(i18n("to trash", "&Trash"),"edittrash"), "AskForTrash" );
+ doIt = (ret == KMessageBox::Continue);
+ }
+
+ if ( doIt ) {
+ TDEIO::CopyJob *job = TDEIO::trash( urls, showProgress );
+ job->setWindow (topLevelWidget());
+ job->setAutoErrorHandlingEnabled( true, parent );
+ return job;
+ }
+
+ return 0L;
+}
+
+void KDirOperator::trashSelected(KAction::ActivationReason reason, TQt::ButtonState state)
+{
+ if ( !m_fileView )
+ return;
+
+ if ( reason == KAction::PopupMenuActivation && ( state & ShiftButton ) ) {
+ deleteSelected();
+ return;
+ }
+
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( list )
+ trash( *list, this );
+}
+
+void KDirOperator::close()
+{
+ resetCursor();
+ pendingMimeTypes.clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+ myCompleteListDirty = true;
+ dir->stop();
+}
+
+void KDirOperator::checkPath(const TQString &, bool /*takeFiles*/) // SLOT
+{
+#if 0
+ // copy the argument in a temporary string
+ TQString text = _txt;
+ // it's unlikely to happen, that at the beginning are spaces, but
+ // for the end, it happens quite often, I guess.
+ text = text.stripWhiteSpace();
+ // if the argument is no URL (the check is quite fragil) and it's
+ // no absolute path, we add the current directory to get a correct url
+ if (text.find(':') < 0 && text[0] != '/')
+ text.insert(0, currUrl);
+
+ // in case we have a selection defined and someone patched the file-
+ // name, we check, if the end of the new name is changed.
+ if (!selection.isNull()) {
+ int position = text.findRev('/');
+ ASSERT(position >= 0); // we already inserted the current dir in case
+ TQString filename = text.mid(position + 1, text.length());
+ if (filename != selection)
+ selection = TQString::null;
+ }
+
+ KURL u(text); // I have to take care of entered URLs
+ bool filenameEntered = false;
+
+ if (u.isLocalFile()) {
+ // the empty path is kind of a hack
+ KFileItem i("", u.path());
+ if (i.isDir())
+ setURL(text, true);
+ else {
+ if (takeFiles)
+ if (acceptOnlyExisting && !i.isFile())
+ warning("you entered an invalid URL");
+ else
+ filenameEntered = true;
+ }
+ } else
+ setURL(text, true);
+
+ if (filenameEntered) {
+ filename_ = u.url();
+ emit fileSelected(filename_);
+
+ TQApplication::restoreOverrideCursor();
+
+ accept();
+ }
+#endif
+ kdDebug(tdefile_area) << "TODO KDirOperator::checkPath()" << endl;
+}
+
+void KDirOperator::setURL(const KURL& _newurl, bool clearforward)
+{
+ KURL newurl;
+
+ if ( !_newurl.isValid() )
+ newurl.setPath( TQDir::homeDirPath() );
+ else
+ newurl = _newurl;
+
+ TQString pathstr = newurl.path(+1);
+ newurl.setPath(pathstr);
+
+ // already set
+ if ( newurl.equals( currUrl, true ) )
+ return;
+
+ if ( !isReadable( newurl ) ) {
+ // maybe newurl is a file? check its parent directory
+ newurl.cd(TQString::fromLatin1(".."));
+ if ( !isReadable( newurl ) ) {
+ resetCursor();
+ KMessageBox::error(viewWidget(),
+ i18n("The specified folder does not exist "
+ "or was not readable."));
+ return;
+ }
+ }
+
+ if (clearforward) {
+ // autodelete should remove this one
+ backStack.push(new KURL(currUrl));
+ forwardStack.clear();
+ }
+
+ d->lastURL = currUrl.url(-1);
+ currUrl = newurl;
+
+ pathChanged();
+ emit urlEntered(newurl);
+
+ // enable/disable actions
+ forwardAction->setEnabled( !forwardStack.isEmpty() );
+ backAction->setEnabled( !backStack.isEmpty() );
+ upAction->setEnabled( !isRoot() );
+
+ openURL( newurl );
+}
+
+void KDirOperator::updateDir()
+{
+ dir->emitChanges();
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::rereadDir()
+{
+ pathChanged();
+ openURL( currUrl, false, true );
+}
+
+
+bool KDirOperator::openURL( const KURL& url, bool keep, bool reload )
+{
+ bool result = dir->openURL( url, keep, reload );
+ if ( !result ) // in that case, neither completed() nor canceled() will be emitted by KDL
+ slotCanceled();
+
+ return result;
+}
+
+// Protected
+void KDirOperator::pathChanged()
+{
+ if (!m_fileView)
+ return;
+
+ pendingMimeTypes.clear();
+ m_fileView->clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+
+ // it may be, that we weren't ready at this time
+ TQApplication::restoreOverrideCursor();
+
+ // when TDEIO::Job emits finished, the slot will restore the cursor
+ TQApplication::setOverrideCursor( tqwaitCursor );
+
+ if ( !isReadable( currUrl )) {
+ KMessageBox::error(viewWidget(),
+ i18n("The specified folder does not exist "
+ "or was not readable."));
+ if (backStack.isEmpty())
+ home();
+ else
+ back();
+ }
+}
+
+void KDirOperator::slotRedirected( const KURL& newURL )
+{
+ currUrl = newURL;
+ pendingMimeTypes.clear();
+ myCompletion.clear();
+ myDirCompletion.clear();
+ myCompleteListDirty = true;
+ emit urlEntered( newURL );
+}
+
+// Code pinched from kfm then hacked
+void KDirOperator::back()
+{
+ if ( backStack.isEmpty() )
+ return;
+
+ forwardStack.push( new KURL(currUrl) );
+
+ KURL *s = backStack.pop();
+
+ setURL(*s, false);
+ delete s;
+}
+
+// Code pinched from kfm then hacked
+void KDirOperator::forward()
+{
+ if ( forwardStack.isEmpty() )
+ return;
+
+ backStack.push(new KURL(currUrl));
+
+ KURL *s = forwardStack.pop();
+ setURL(*s, false);
+ delete s;
+}
+
+KURL KDirOperator::url() const
+{
+ return currUrl;
+}
+
+void KDirOperator::cdUp()
+{
+ KURL tmp(currUrl);
+ tmp.cd(TQString::fromLatin1(".."));
+ setURL(tmp, true);
+}
+
+void KDirOperator::home()
+{
+ KURL u;
+ u.setPath( TQDir::homeDirPath() );
+ setURL(u, true);
+}
+
+void KDirOperator::clearFilter()
+{
+ dir->setNameFilter( TQString::null );
+ dir->clearMimeFilter();
+ checkPreviewSupport();
+}
+
+void KDirOperator::setNameFilter(const TQString& filter)
+{
+ dir->setNameFilter(filter);
+ checkPreviewSupport();
+}
+
+void KDirOperator::setMimeFilter( const TQStringList& mimetypes )
+{
+ dir->setMimeFilter( mimetypes );
+ checkPreviewSupport();
+}
+
+bool KDirOperator::checkPreviewSupport()
+{
+ KToggleAction *previewAction = static_cast<KToggleAction*>( myActionCollection->action( "preview" ));
+
+ bool hasPreviewSupport = false;
+ TDEConfig *kc = TDEGlobal::config();
+ TDEConfigGroupSaver cs( kc, ConfigGroup );
+ if ( kc->readBoolEntry( "Show Default Preview", true ) )
+ hasPreviewSupport = checkPreviewInternal();
+
+ previewAction->setEnabled( hasPreviewSupport );
+ return hasPreviewSupport;
+}
+
+bool KDirOperator::checkPreviewInternal() const
+{
+ TQStringList supported = TDEIO::PreviewJob::supportedMimeTypes();
+ // no preview support for directories?
+ if ( dirOnlyMode() && supported.findIndex( "inode/directory" ) == -1 )
+ return false;
+
+ TQStringList mimeTypes = dir->mimeFilters();
+ TQStringList nameFilter = TQStringList::split( " ", dir->nameFilter() );
+
+ if ( mimeTypes.isEmpty() && nameFilter.isEmpty() && !supported.isEmpty() )
+ return true;
+ else {
+ TQRegExp r;
+ r.setWildcard( true ); // the "mimetype" can be "image/*"
+
+ if ( !mimeTypes.isEmpty() ) {
+ TQStringList::Iterator it = supported.begin();
+
+ for ( ; it != supported.end(); ++it ) {
+ r.setPattern( *it );
+
+ TQStringList result = mimeTypes.grep( r );
+ if ( !result.isEmpty() ) { // matches! -> we want previews
+ return true;
+ }
+ }
+ }
+
+ if ( !nameFilter.isEmpty() ) {
+ // find the mimetypes of all the filter-patterns and
+ KServiceTypeFactory *fac = KServiceTypeFactory::self();
+ TQStringList::Iterator it1 = nameFilter.begin();
+ for ( ; it1 != nameFilter.end(); ++it1 ) {
+ if ( (*it1) == "*" ) {
+ return true;
+ }
+
+ KMimeType *mt = fac->findFromPattern( *it1 );
+ if ( !mt )
+ continue;
+ TQString mime = mt->name();
+ delete mt;
+
+ // the "mimetypes" we get from the PreviewJob can be "image/*"
+ // so we need to check in wildcard mode
+ TQStringList::Iterator it2 = supported.begin();
+ for ( ; it2 != supported.end(); ++it2 ) {
+ r.setPattern( *it2 );
+ if ( r.search( mime ) != -1 ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+KFileView* KDirOperator::createView( TQWidget* parent, KFile::FileView view )
+{
+ KFileView* new_view = 0L;
+ bool separateDirs = KFile::isSeparateDirs( view );
+ bool preview = ( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) );
+
+ if ( separateDirs || preview ) {
+ KCombiView *combi = 0L;
+ if (separateDirs)
+ {
+ combi = new KCombiView( parent, "combi view" );
+ combi->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+ }
+
+ KFileView* v = 0L;
+ if ( KFile::isSimpleView( view ) )
+ v = createView( combi, KFile::Simple );
+ else
+ v = createView( combi, KFile::Detail );
+
+ v->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+
+ if (combi)
+ combi->setRight( v );
+
+ if (preview)
+ {
+ KFilePreview* pView = new KFilePreview( combi ? combi : v, parent, "preview" );
+ pView->setOnlyDoubleClickSelectsFiles(d->onlyDoubleClickSelectsFiles);
+ new_view = pView;
+ }
+ else
+ new_view = combi;
+ }
+ else if ( KFile::isDetailView( view ) && !preview ) {
+ new_view = new KFileDetailView( parent, "detail view");
+ new_view->setViewName( i18n("Detailed View") );
+ }
+ else /* if ( KFile::isSimpleView( view ) && !preview ) */ {
+ KFileIconView *iconView = new KFileIconView( parent, "simple view");
+ new_view = iconView;
+ new_view->setViewName( i18n("Short View") );
+ }
+
+ new_view->widget()->setAcceptDrops(acceptDrops());
+ return new_view;
+}
+
+void KDirOperator::setAcceptDrops(bool b)
+{
+ if (m_fileView)
+ m_fileView->widget()->setAcceptDrops(b);
+ TQWidget::setAcceptDrops(b);
+}
+
+void KDirOperator::setDropOptions(int options)
+{
+ d->dropOptions = options;
+ if (m_fileView)
+ m_fileView->setDropOptions(options);
+}
+
+void KDirOperator::setView( KFile::FileView view )
+{
+ bool separateDirs = KFile::isSeparateDirs( view );
+ bool preview=( KFile::isPreviewInfo(view) || KFile::isPreviewContents( view ) );
+
+ if (view == KFile::Default) {
+ if ( KFile::isDetailView( (KFile::FileView) defaultView ) )
+ view = KFile::Detail;
+ else
+ view = KFile::Simple;
+
+ separateDirs = KFile::isSeparateDirs( static_cast<KFile::FileView>(defaultView) );
+ preview = ( KFile::isPreviewInfo( static_cast<KFile::FileView>(defaultView) ) ||
+ KFile::isPreviewContents( static_cast<KFile::FileView>(defaultView) ) )
+ && myActionCollection->action("preview")->isEnabled();
+
+ if ( preview ) { // instantiates KFileMetaPreview and calls setView()
+ m_viewKind = defaultView;
+ slotDefaultPreview();
+ return;
+ }
+ else if ( !separateDirs )
+ separateDirsAction->setChecked(true);
+ }
+
+ // if we don't have any files, we can't separate dirs from files :)
+ if ( (mode() & KFile::File) == 0 &&
+ (mode() & KFile::Files) == 0 ) {
+ separateDirs = false;
+ separateDirsAction->setEnabled( false );
+ }
+
+ m_viewKind = static_cast<int>(view) | (separateDirs ? KFile::SeparateDirs : 0);
+ view = static_cast<KFile::FileView>(m_viewKind);
+
+ KFileView *new_view = createView( this, view );
+ if ( preview ) {
+ // we keep the preview-_widget_ around, but not the KFilePreview.
+ // KFilePreview::setPreviewWidget handles the reparenting for us
+ static_cast<KFilePreview*>(new_view)->setPreviewWidget(myPreview, url());
+ }
+
+ setView( new_view );
+}
+
+
+void KDirOperator::connectView(KFileView *view)
+{
+ // TODO: do a real timer and restart it after that
+ pendingMimeTypes.clear();
+ bool listDir = true;
+
+ if ( dirOnlyMode() )
+ view->setViewMode(KFileView::Directories);
+ else
+ view->setViewMode(KFileView::All);
+
+ if ( myMode & KFile::Files )
+ view->setSelectionMode( KFile::Extended );
+ else
+ view->setSelectionMode( KFile::Single );
+
+ if (m_fileView)
+ {
+ if ( d->config ) // save and restore the views' configuration
+ {
+ m_fileView->writeConfig( d->config, d->configGroup );
+ view->readConfig( d->config, d->configGroup );
+ }
+
+ // transfer the state from old view to new view
+ view->clear();
+ view->addItemList( *m_fileView->items() );
+ listDir = false;
+
+ if ( m_fileView->widget()->hasFocus() )
+ view->widget()->setFocus();
+
+ KFileItem *oldCurrentItem = m_fileView->currentFileItem();
+ if ( oldCurrentItem ) {
+ view->setCurrentItem( oldCurrentItem );
+ view->setSelected( oldCurrentItem, false );
+ view->ensureItemVisible( oldCurrentItem );
+ }
+
+ const KFileItemList *oldSelected = m_fileView->selectedItems();
+ if ( !oldSelected->isEmpty() ) {
+ KFileItemListIterator it( *oldSelected );
+ for ( ; it.current(); ++it )
+ view->setSelected( it.current(), true );
+ }
+
+ m_fileView->widget()->hide();
+ delete m_fileView;
+ }
+
+ else
+ {
+ if ( d->config )
+ view->readConfig( d->config, d->configGroup );
+ }
+
+ m_fileView = view;
+ m_fileView->setDropOptions(d->dropOptions);
+ viewActionCollection = 0L;
+ KFileViewSignaler *sig = view->signaler();
+
+ connect(sig, TQT_SIGNAL( activatedMenu(const KFileItem *, const TQPoint& ) ),
+ this, TQT_SLOT( activatedMenu(const KFileItem *, const TQPoint& )));
+ connect(sig, TQT_SIGNAL( dirActivated(const KFileItem *) ),
+ this, TQT_SLOT( selectDir(const KFileItem*) ) );
+ connect(sig, TQT_SIGNAL( fileSelected(const KFileItem *) ),
+ this, TQT_SLOT( selectFile(const KFileItem*) ) );
+ connect(sig, TQT_SIGNAL( fileHighlighted(const KFileItem *) ),
+ this, TQT_SLOT( highlightFile(const KFileItem*) ));
+ connect(sig, TQT_SIGNAL( sortingChanged( TQDir::SortSpec ) ),
+ this, TQT_SLOT( slotViewSortingChanged( TQDir::SortSpec )));
+ connect(sig, TQT_SIGNAL( dropped(const KFileItem *, TQDropEvent*, const KURL::List&) ),
+ this, TQT_SIGNAL( dropped(const KFileItem *, TQDropEvent*, const KURL::List&)) );
+
+ if ( reverseAction->isChecked() != m_fileView->isReversed() )
+ slotSortReversed();
+
+ updateViewActions();
+ m_fileView->widget()->resize(size());
+ m_fileView->widget()->show();
+
+ if ( listDir ) {
+ TQApplication::setOverrideCursor( tqwaitCursor );
+ openURL( currUrl );
+ }
+ else
+ view->listingCompleted();
+}
+
+KFile::Mode KDirOperator::mode() const
+{
+ return myMode;
+}
+
+void KDirOperator::setMode(KFile::Mode m)
+{
+ if (myMode == m)
+ return;
+
+ myMode = m;
+
+ dir->setDirOnlyMode( dirOnlyMode() );
+
+ // reset the view with the different mode
+ setView( static_cast<KFile::FileView>(m_viewKind) );
+}
+
+void KDirOperator::setView(KFileView *view)
+{
+ if ( view == m_fileView ) {
+ return;
+ }
+
+ setFocusProxy(view->widget());
+ view->setSorting( mySorting );
+ view->setOnlyDoubleClickSelectsFiles( d->onlyDoubleClickSelectsFiles );
+ connectView(view); // also deletes the old view
+
+ emit viewChanged( view );
+}
+
+void KDirOperator::setDirLister( KDirLister *lister )
+{
+ if ( lister == dir ) // sanity check
+ return;
+
+ delete dir;
+ dir = lister;
+
+ dir->setAutoUpdate( true );
+
+ TQWidget* mainWidget = topLevelWidget();
+ dir->setMainWindow (mainWidget);
+ kdDebug (tdefile_area) << "mainWidget=" << mainWidget << endl;
+
+ connect( dir, TQT_SIGNAL( percent( int )),
+ TQT_SLOT( slotProgress( int ) ));
+ connect( dir, TQT_SIGNAL(started( const KURL& )), TQT_SLOT(slotStarted()));
+ connect( dir, TQT_SIGNAL(newItems(const KFileItemList &)),
+ TQT_SLOT(insertNewFiles(const KFileItemList &)));
+ connect( dir, TQT_SIGNAL(completed()), TQT_SLOT(slotIOFinished()));
+ connect( dir, TQT_SIGNAL(canceled()), TQT_SLOT(slotCanceled()));
+ connect( dir, TQT_SIGNAL(deleteItem(KFileItem *)),
+ TQT_SLOT(itemDeleted(KFileItem *)));
+ connect( dir, TQT_SIGNAL(redirection( const KURL& )),
+ TQT_SLOT( slotRedirected( const KURL& )));
+ connect( dir, TQT_SIGNAL( clear() ), TQT_SLOT( slotClearView() ));
+ connect( dir, TQT_SIGNAL( refreshItems( const KFileItemList& ) ),
+ TQT_SLOT( slotRefreshItems( const KFileItemList& ) ) );
+}
+
+void KDirOperator::insertNewFiles(const KFileItemList &newone)
+{
+ if ( newone.isEmpty() || !m_fileView )
+ return;
+
+ myCompleteListDirty = true;
+ m_fileView->addItemList( newone );
+ emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles());
+
+ KFileItem *item;
+ KFileItemListIterator it( newone );
+
+ while ( (item = it.current()) ) {
+ // highlight the dir we come from, if possible
+ if ( d->dirHighlighting && item->isDir() &&
+ item->url().url(-1) == d->lastURL ) {
+ m_fileView->setCurrentItem( item );
+ m_fileView->ensureItemVisible( item );
+ }
+
+ ++it;
+ }
+
+ TQTimer::singleShot(200, this, TQT_SLOT(resetCursor()));
+}
+
+void KDirOperator::selectDir(const KFileItem *item)
+{
+ setURL(item->url(), true);
+}
+
+void KDirOperator::itemDeleted(KFileItem *item)
+{
+ pendingMimeTypes.removeRef( item );
+ if ( m_fileView )
+ {
+ m_fileView->removeItem( static_cast<KFileItem *>( item ));
+ emit updateInformation(m_fileView->numDirs(), m_fileView->numFiles());
+ }
+}
+
+void KDirOperator::selectFile(const KFileItem *item)
+{
+ TQApplication::restoreOverrideCursor();
+
+ emit fileSelected( item );
+}
+
+void KDirOperator::setCurrentItem( const TQString& filename )
+{
+ if ( m_fileView ) {
+ const KFileItem *item = 0L;
+
+ if ( !filename.isNull() )
+ item = static_cast<KFileItem *>(dir->findByName( filename ));
+
+ m_fileView->clearSelection();
+ if ( item ) {
+ m_fileView->setCurrentItem( item );
+ m_fileView->setSelected( item, true );
+ m_fileView->ensureItemVisible( item );
+ }
+ }
+}
+
+TQString KDirOperator::makeCompletion(const TQString& string)
+{
+ if ( string.isEmpty() ) {
+ m_fileView->clearSelection();
+ return TQString::null;
+ }
+
+ prepareCompletionObjects();
+ return myCompletion.makeCompletion( string );
+}
+
+TQString KDirOperator::makeDirCompletion(const TQString& string)
+{
+ if ( string.isEmpty() ) {
+ m_fileView->clearSelection();
+ return TQString::null;
+ }
+
+ prepareCompletionObjects();
+ return myDirCompletion.makeCompletion( string );
+}
+
+void KDirOperator::prepareCompletionObjects()
+{
+ if ( !m_fileView )
+ return;
+
+ if ( myCompleteListDirty ) { // create the list of all possible completions
+ KFileItemListIterator it( *(m_fileView->items()) );
+ for( ; it.current(); ++it ) {
+ KFileItem *item = it.current();
+
+ myCompletion.addItem( item->name() );
+ if ( item->isDir() )
+ myDirCompletion.addItem( item->name() );
+ }
+ myCompleteListDirty = false;
+ }
+}
+
+void KDirOperator::slotCompletionMatch(const TQString& match)
+{
+ setCurrentItem( match );
+ emit completion( match );
+}
+
+void KDirOperator::setupActions()
+{
+ myActionCollection = new KActionCollection( topLevelWidget(), TQT_TQOBJECT(this), "KDirOperator::myActionCollection" );
+
+ actionMenu = new KActionMenu( i18n("Menu"), myActionCollection, "popupMenu" );
+ upAction = KStdAction::up( TQT_TQOBJECT(this), TQT_SLOT( cdUp() ), myActionCollection, "up" );
+ upAction->setText( i18n("Parent Folder") );
+ backAction = KStdAction::back( TQT_TQOBJECT(this), TQT_SLOT( back() ), myActionCollection, "back" );
+ forwardAction = KStdAction::forward( TQT_TQOBJECT(this), TQT_SLOT(forward()), myActionCollection, "forward" );
+ homeAction = KStdAction::home( TQT_TQOBJECT(this), TQT_SLOT( home() ), myActionCollection, "home" );
+ homeAction->setText(i18n("Home Folder"));
+ reloadAction = KStdAction::redisplay( TQT_TQOBJECT(this), TQT_SLOT(rereadDir()), myActionCollection, "reload" );
+ actionSeparator = new KActionSeparator( myActionCollection, "separator" );
+ d->viewActionSeparator = new KActionSeparator( myActionCollection,
+ "viewActionSeparator" );
+ mkdirAction = new KAction( i18n("New Folder..."), 0,
+ TQT_TQOBJECT(this), TQT_SLOT( mkdir() ), myActionCollection, "mkdir" );
+ KAction* trash = new KAction( i18n( "Move to Trash" ), "edittrash", Key_Delete, myActionCollection, "trash" );
+ connect( trash, TQT_SIGNAL( activated( KAction::ActivationReason, TQt::ButtonState ) ),
+ this, TQT_SLOT( trashSelected( KAction::ActivationReason, TQt::ButtonState ) ) );
+ new KAction( i18n( "Delete" ), "editdelete", SHIFT+Key_Delete, TQT_TQOBJECT(this),
+ TQT_SLOT( deleteSelected() ), myActionCollection, "delete" );
+ mkdirAction->setIcon( TQString::fromLatin1("folder_new") );
+ reloadAction->setText( i18n("Reload") );
+ reloadAction->setShortcut( KStdAccel::shortcut( KStdAccel::Reload ));
+
+
+ // the sort menu actions
+ sortActionMenu = new KActionMenu( i18n("Sorting"), myActionCollection, "sorting menu");
+ byNameAction = new KRadioAction( i18n("By Name"), 0,
+ TQT_TQOBJECT(this), TQT_SLOT( slotSortByName() ),
+ myActionCollection, "by name" );
+ byDateAction = new KRadioAction( i18n("By Date"), 0,
+ TQT_TQOBJECT(this), TQT_SLOT( slotSortByDate() ),
+ myActionCollection, "by date" );
+ bySizeAction = new KRadioAction( i18n("By Size"), 0,
+ TQT_TQOBJECT(this), TQT_SLOT( slotSortBySize() ),
+ myActionCollection, "by size" );
+ reverseAction = new KToggleAction( i18n("Reverse"), 0,
+ TQT_TQOBJECT(this), TQT_SLOT( slotSortReversed() ),
+ myActionCollection, "reversed" );
+
+ TQString sortGroup = TQString::fromLatin1("sort");
+ byNameAction->setExclusiveGroup( sortGroup );
+ byDateAction->setExclusiveGroup( sortGroup );
+ bySizeAction->setExclusiveGroup( sortGroup );
+
+
+ dirsFirstAction = new KToggleAction( i18n("Folders First"), 0,
+ myActionCollection, "dirs first");
+ caseInsensitiveAction = new KToggleAction(i18n("Case Insensitive"), 0,
+ myActionCollection, "case insensitive" );
+
+ connect( dirsFirstAction, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( slotToggleDirsFirst() ));
+ connect( caseInsensitiveAction, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( slotToggleIgnoreCase() ));
+
+
+
+ // the view menu actions
+ viewActionMenu = new KActionMenu( i18n("&View"), myActionCollection, "view menu" );
+ connect( viewActionMenu->popupMenu(), TQT_SIGNAL( aboutToShow() ),
+ TQT_SLOT( insertViewDependentActions() ));
+
+ shortAction = new KRadioAction( i18n("Short View"), "view_multicolumn",
+ KShortcut(), myActionCollection, "short view" );
+ detailedAction = new KRadioAction( i18n("Detailed View"), "view_detailed",
+ KShortcut(), myActionCollection, "detailed view" );
+
+ showHiddenAction = new KToggleAction( i18n("Show Hidden Files"), KShortcut(),
+ myActionCollection, "show hidden" );
+// showHiddenAction->setCheckedState( i18n("Hide Hidden Files") );
+ separateDirsAction = new KToggleAction( i18n("Separate Folders"), KShortcut(),
+ TQT_TQOBJECT(this),
+ TQT_SLOT(slotSeparateDirs()),
+ myActionCollection, "separate dirs" );
+ KToggleAction *previewAction = new KToggleAction(i18n("Show Preview"),
+ "thumbnail", KShortcut(),
+ myActionCollection,
+ "preview" );
+ previewAction->setCheckedState(i18n("Hide Preview"));
+ connect( previewAction, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( togglePreview( bool )));
+
+
+ TQString viewGroup = TQString::fromLatin1("view");
+ shortAction->setExclusiveGroup( viewGroup );
+ detailedAction->setExclusiveGroup( viewGroup );
+
+ connect( shortAction, TQT_SIGNAL( activated() ),
+ TQT_SLOT( slotSimpleView() ));
+ connect( detailedAction, TQT_SIGNAL( activated() ),
+ TQT_SLOT( slotDetailedView() ));
+ connect( showHiddenAction, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( slotToggleHidden( bool ) ));
+
+ new KAction( i18n("Properties"), KShortcut(ALT+Key_Return), TQT_TQOBJECT(this),
+ TQT_SLOT(slotProperties()), myActionCollection, "properties" );
+}
+
+void KDirOperator::setupMenu()
+{
+ setupMenu(AllActions);
+}
+
+void KDirOperator::setupMenu(int whichActions)
+{
+ // first fill the submenus (sort and view)
+ sortActionMenu->popupMenu()->clear();
+ sortActionMenu->insert( byNameAction );
+ sortActionMenu->insert( byDateAction );
+ sortActionMenu->insert( bySizeAction );
+ sortActionMenu->insert( actionSeparator );
+ sortActionMenu->insert( reverseAction );
+ sortActionMenu->insert( dirsFirstAction );
+ sortActionMenu->insert( caseInsensitiveAction );
+
+ // now plug everything into the popupmenu
+ actionMenu->popupMenu()->clear();
+ if (whichActions & NavActions)
+ {
+ actionMenu->insert( upAction );
+ actionMenu->insert( backAction );
+ actionMenu->insert( forwardAction );
+ actionMenu->insert( homeAction );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & FileActions)
+ {
+ actionMenu->insert( mkdirAction );
+ if (currUrl.isLocalFile() && !(TDEApplication::keyboardMouseState() & TQt::ShiftButton))
+ actionMenu->insert( myActionCollection->action( "trash" ) );
+ TDEConfig *globalconfig = TDEGlobal::config();
+ TDEConfigGroupSaver cs( globalconfig, TQString::fromLatin1("KDE") );
+ if (!currUrl.isLocalFile() || (TDEApplication::keyboardMouseState() & TQt::ShiftButton) ||
+ globalconfig->readBoolEntry("ShowDeleteCommand", false))
+ actionMenu->insert( myActionCollection->action( "delete" ) );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & SortActions)
+ {
+ actionMenu->insert( sortActionMenu );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & ViewActions)
+ {
+ actionMenu->insert( viewActionMenu );
+ actionMenu->insert( actionSeparator );
+ }
+
+ if (whichActions & FileActions)
+ {
+ actionMenu->insert( myActionCollection->action( "properties" ) );
+ }
+}
+
+void KDirOperator::updateSortActions()
+{
+ if ( KFile::isSortByName( mySorting ) )
+ byNameAction->setChecked( true );
+ else if ( KFile::isSortByDate( mySorting ) )
+ byDateAction->setChecked( true );
+ else if ( KFile::isSortBySize( mySorting ) )
+ bySizeAction->setChecked( true );
+
+ dirsFirstAction->setChecked( KFile::isSortDirsFirst( mySorting ) );
+ caseInsensitiveAction->setChecked( KFile::isSortCaseInsensitive(mySorting) );
+ caseInsensitiveAction->setEnabled( KFile::isSortByName( mySorting ) );
+
+ if ( m_fileView )
+ reverseAction->setChecked( m_fileView->isReversed() );
+}
+
+void KDirOperator::updateViewActions()
+{
+ KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind );
+
+ separateDirsAction->setChecked( KFile::isSeparateDirs( fv ) &&
+ separateDirsAction->isEnabled() );
+
+ shortAction->setChecked( KFile::isSimpleView( fv ));
+ detailedAction->setChecked( KFile::isDetailView( fv ));
+}
+
+void KDirOperator::readConfig( TDEConfig *kc, const TQString& group )
+{
+ if ( !kc )
+ return;
+ TQString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ defaultView = 0;
+ int sorting = 0;
+
+ TQString viewStyle = kc->readEntry( TQString::fromLatin1("View Style"),
+ TQString::fromLatin1("Simple") );
+ if ( viewStyle == TQString::fromLatin1("Detail") )
+ defaultView |= KFile::Detail;
+ else
+ defaultView |= KFile::Simple;
+ if ( kc->readBoolEntry( TQString::fromLatin1("Separate Directories"),
+ DefaultMixDirsAndFiles ) )
+ defaultView |= KFile::SeparateDirs;
+ if ( kc->readBoolEntry(TQString::fromLatin1("Show Preview"), false))
+ defaultView |= KFile::PreviewContents;
+
+ if ( kc->readBoolEntry( TQString::fromLatin1("Sort case insensitively"),
+ DefaultCaseInsensitive ) )
+ sorting |= TQDir::IgnoreCase;
+ if ( kc->readBoolEntry( TQString::fromLatin1("Sort directories first"),
+ DefaultDirsFirst ) )
+ sorting |= TQDir::DirsFirst;
+
+
+ TQString name = TQString::fromLatin1("Name");
+ TQString sortBy = kc->readEntry( TQString::fromLatin1("Sort by"), name );
+ if ( sortBy == name )
+ sorting |= TQDir::Name;
+ else if ( sortBy == TQString::fromLatin1("Size") )
+ sorting |= TQDir::Size;
+ else if ( sortBy == TQString::fromLatin1("Date") )
+ sorting |= TQDir::Time;
+
+ mySorting = static_cast<TQDir::SortSpec>( sorting );
+ setSorting( mySorting );
+
+
+ if ( kc->readBoolEntry( TQString::fromLatin1("Show hidden files"),
+ DefaultShowHidden ) ) {
+ showHiddenAction->setChecked( true );
+ dir->setShowingDotFiles( true );
+ }
+ if ( kc->readBoolEntry( TQString::fromLatin1("Sort reversed"),
+ DefaultSortReversed ) )
+ reverseAction->setChecked( true );
+
+ kc->setGroup( oldGroup );
+}
+
+void KDirOperator::writeConfig( TDEConfig *kc, const TQString& group )
+{
+ if ( !kc )
+ return;
+
+ const TQString oldGroup = kc->group();
+
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ TQString sortBy = TQString::fromLatin1("Name");
+ if ( KFile::isSortBySize( mySorting ) )
+ sortBy = TQString::fromLatin1("Size");
+ else if ( KFile::isSortByDate( mySorting ) )
+ sortBy = TQString::fromLatin1("Date");
+ kc->writeEntry( TQString::fromLatin1("Sort by"), sortBy );
+
+ kc->writeEntry( TQString::fromLatin1("Sort reversed"),
+ reverseAction->isChecked() );
+ kc->writeEntry( TQString::fromLatin1("Sort case insensitively"),
+ caseInsensitiveAction->isChecked() );
+ kc->writeEntry( TQString::fromLatin1("Sort directories first"),
+ dirsFirstAction->isChecked() );
+
+ // don't save the separate dirs or preview when an application specific
+ // preview is in use.
+ bool appSpecificPreview = false;
+ if ( myPreview ) {
+ TQWidget *preview = const_cast<TQWidget*>( myPreview ); // grmbl
+ KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview*>( preview );
+ appSpecificPreview = (tmp == 0L);
+ }
+
+ if ( !appSpecificPreview ) {
+ if ( separateDirsAction->isEnabled() )
+ kc->writeEntry( TQString::fromLatin1("Separate Directories"),
+ separateDirsAction->isChecked() );
+
+ KToggleAction *previewAction = static_cast<KToggleAction*>(myActionCollection->action("preview"));
+ if ( previewAction->isEnabled() ) {
+ bool hasPreview = previewAction->isChecked();
+ kc->writeEntry( TQString::fromLatin1("Show Preview"), hasPreview );
+ }
+ }
+
+ kc->writeEntry( TQString::fromLatin1("Show hidden files"),
+ showHiddenAction->isChecked() );
+
+ KFile::FileView fv = static_cast<KFile::FileView>( m_viewKind );
+ TQString style;
+ if ( KFile::isDetailView( fv ) )
+ style = TQString::fromLatin1("Detail");
+ else if ( KFile::isSimpleView( fv ) )
+ style = TQString::fromLatin1("Simple");
+ kc->writeEntry( TQString::fromLatin1("View Style"), style );
+
+ kc->setGroup( oldGroup );
+}
+
+
+void KDirOperator::resizeEvent( TQResizeEvent * )
+{
+ if (m_fileView)
+ m_fileView->widget()->resize( size() );
+
+ if ( TQT_BASE_OBJECT(progress->parent()) == TQT_BASE_OBJECT(this) ) // might be reparented into a statusbar
+ progress->move(2, height() - progress->height() -2);
+}
+
+void KDirOperator::setOnlyDoubleClickSelectsFiles( bool enable )
+{
+ d->onlyDoubleClickSelectsFiles = enable;
+ if ( m_fileView )
+ m_fileView->setOnlyDoubleClickSelectsFiles( enable );
+}
+
+bool KDirOperator::onlyDoubleClickSelectsFiles() const
+{
+ return d->onlyDoubleClickSelectsFiles;
+}
+
+void KDirOperator::slotStarted()
+{
+ progress->setProgress( 0 );
+ // delay showing the progressbar for one second
+ d->progressDelayTimer->start( 1000, true );
+}
+
+void KDirOperator::slotShowProgress()
+{
+ progress->raise();
+ progress->show();
+ TQApplication::flushX();
+}
+
+void KDirOperator::slotProgress( int percent )
+{
+ progress->setProgress( percent );
+ // we have to redraw this as fast as possible
+ if ( progress->isVisible() )
+ TQApplication::flushX();
+}
+
+
+void KDirOperator::slotIOFinished()
+{
+ d->progressDelayTimer->stop();
+ slotProgress( 100 );
+ progress->hide();
+ emit finishedLoading();
+ resetCursor();
+
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+void KDirOperator::slotCanceled()
+{
+ emit finishedLoading();
+ resetCursor();
+
+ if ( m_fileView )
+ m_fileView->listingCompleted();
+}
+
+KProgress * KDirOperator::progressBar() const
+{
+ return progress;
+}
+
+void KDirOperator::clearHistory()
+{
+ backStack.clear();
+ backAction->setEnabled( false );
+ forwardStack.clear();
+ forwardAction->setEnabled( false );
+}
+
+void KDirOperator::slotViewActionAdded( KAction *action )
+{
+ if ( viewActionMenu->popupMenu()->count() == 5 ) // need to add a separator
+ viewActionMenu->insert( d->viewActionSeparator );
+
+ viewActionMenu->insert( action );
+}
+
+void KDirOperator::slotViewActionRemoved( KAction *action )
+{
+ viewActionMenu->remove( action );
+
+ if ( viewActionMenu->popupMenu()->count() == 6 ) // remove the separator
+ viewActionMenu->remove( d->viewActionSeparator );
+}
+
+void KDirOperator::slotViewSortingChanged( TQDir::SortSpec sort )
+{
+ mySorting = sort;
+ updateSortActions();
+}
+
+void KDirOperator::setEnableDirHighlighting( bool enable )
+{
+ d->dirHighlighting = enable;
+}
+
+bool KDirOperator::dirHighlighting() const
+{
+ return d->dirHighlighting;
+}
+
+void KDirOperator::slotProperties()
+{
+ if ( m_fileView ) {
+ const KFileItemList *list = m_fileView->selectedItems();
+ if ( !list->isEmpty() )
+ (void) new KPropertiesDialog( *list, this, "props dlg", true);
+ }
+}
+
+void KDirOperator::slotClearView()
+{
+ if ( m_fileView )
+ m_fileView->clearView();
+}
+
+// ### temporary code
+#include <dirent.h>
+bool KDirOperator::isReadable( const KURL& url )
+{
+ if ( !url.isLocalFile() )
+ return true; // what else can we say?
+
+ KDE_struct_stat buf;
+ TQString ts = url.path(+1);
+ bool readable = ( KDE_stat( TQFile::encodeName( ts ), &buf) == 0 );
+ if (readable) { // further checks
+ DIR *test;
+ test = opendir( TQFile::encodeName( ts )); // we do it just to test here
+ readable = (test != 0);
+ if (test)
+ closedir(test);
+ }
+ return readable;
+}
+
+void KDirOperator::togglePreview( bool on )
+{
+ if ( on )
+ slotDefaultPreview();
+ else
+ setView( (KFile::FileView) (m_viewKind & ~(KFile::PreviewContents|KFile::PreviewInfo)) );
+}
+
+void KDirOperator::slotRefreshItems( const KFileItemList& items )
+{
+ if ( !m_fileView )
+ return;
+
+ KFileItemListIterator it( items );
+ for ( ; it.current(); ++it )
+ m_fileView->updateView( it.current() );
+}
+
+void KDirOperator::setViewConfig( TDEConfig *config, const TQString& group )
+{
+ d->config = config;
+ d->configGroup = group;
+}
+
+TDEConfig * KDirOperator::viewConfig()
+{
+ return d->config;
+}
+
+TQString KDirOperator::viewConfigGroup() const
+{
+ return d->configGroup;
+}
+
+void KDirOperator::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kdiroperator.moc"
diff --git a/tdeio/tdefile/kdiroperator.h b/tdeio/tdefile/kdiroperator.h
new file mode 100644
index 000000000..418bb20c8
--- /dev/null
+++ b/tdeio/tdefile/kdiroperator.h
@@ -0,0 +1,950 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
+ 2000,2001 Carsten Pfeiffer <pfeiffer@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 KDIROPERATOR_H_
+#define KDIROPERATOR_H_
+
+#include <tqwidget.h>
+#include <tqptrstack.h>
+
+#include <kaction.h>
+#include <kcompletion.h>
+#include <kdirlister.h>
+#include <tdefileview.h>
+#include <tdefileitem.h>
+#include <tdefile.h>
+
+class TQPopupMenu;
+class TQTimer;
+
+class KAction;
+class KDirLister;
+class KToggleAction;
+class KActionSeparator;
+class KActionMenu;
+class TQWidgetStack;
+class KProgress;
+namespace TDEIO {
+ class CopyJob;
+ class DeleteJob;
+}
+
+/**
+ * This widget works as a network transparent filebrowser. You specify a URL
+ * to display and this url will be loaded via KDirLister. The user can
+ * browse through directories, highlight and select files, delete or rename
+ * files.
+ *
+ * It supports different views, e.g. a detailed view (see KFileDetailView),
+ * a simple icon view (see KFileIconView), a combination of two views,
+ * separating directories and files ( KCombiView).
+ *
+ * Additionally, a preview view is available (see KFilePreview), which can
+ * show either a simple or detailed view and additionally a preview widget
+ * (see setPreviewWidget()). KImageFilePreview is one implementation
+ * of a preview widget, that displays previews for all supported filetypes
+ * utilizing TDEIO::PreviewJob.
+ *
+ * Currently, those classes don't support Drag&Drop out of the box -- there
+ * you have to use your own view-classes. You can use some DnD-aware views
+ * from Bj�n Sahlstr� <bjorn@kbear.org> until they will be integrated
+ * into this library. See http://devel-home.kde.org/~pfeiffer/DnD-classes.tar.gz
+ *
+ * This widget is the one used in the KFileDialog.
+ *
+ * Basic usage is like this:
+ * \code
+ * KDirOperator *op = new KDirOperator( KURL( "file:/home/gis" ), this );
+ * // some signals you might be interested in
+ * connect(op, TQT_SIGNAL(urlEntered(const KURL&)),
+ * TQT_SLOT(urlEntered(const KURL&)));
+ * connect(op, TQT_SIGNAL(fileHighlighted(const KFileItem *)),
+ * TQT_SLOT(fileHighlighted(const KFileItem *)));
+ * connect(op, TQT_SIGNAL(fileSelected(const KFileItem *)),
+ * TQT_SLOT(fileSelected(const KFileItem *)));
+ * connect(op, TQT_SIGNAL(finishedLoading()),
+ * TQT_SLOT(slotLoadingFinished()));
+ *
+ * op->readConfig( TDEGlobal::config(), "Your KDiroperator ConfigGroup" );
+ * op->setView(KFile::Default);
+ * \endcode
+ *
+ * This will create a childwidget of 'this' showing the directory contents
+ * of /home/gis in the default-view. The view is determined by the readConfig()
+ * call, which will read the KDirOperator settings, the user left your program
+ * with (and which you saved with op->writeConfig()).
+ *
+ * @short A widget for displaying files and browsing directories.
+ * @author Stephan Kulow <coolo@kde.org>, Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KDirOperator : public TQWidget
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * The various action types. These values can be or'd together
+ * @since 3.1
+ */
+ enum ActionTypes { SortActions = 1,
+ ViewActions = 2,
+ NavActions = 4,
+ FileActions = 8,
+ AllActions = 15 };
+ /**
+ * Constructs the KDirOperator with no initial view. As the views are
+ * configurable, call readConfig() to load the user's configuration
+ * and then setView to explicitly set a view.
+ *
+ * This constructor doesn't start loading the url, setView will do it.
+ */
+ KDirOperator(const KURL& urlName = KURL(),
+ TQWidget *parent = 0, const char* name = 0);
+ /**
+ * Destroys the KDirOperator.
+ */
+ virtual ~KDirOperator();
+
+ /**
+ * Enables/disables showing hidden files.
+ */
+ // ### KDE4: make virtual
+ void setShowHiddenFiles ( bool s ) { showHiddenAction->setChecked( s ); }
+
+ /**
+ * @returns true when hidden files are shown or false otherwise.
+ */
+ bool showHiddenFiles () const { return showHiddenAction->isChecked(); }
+
+ /**
+ * Stops loading immediately. You don't need to call this, usually.
+ */
+ void close();
+ /// Reimplemented to avoid "hidden virtual" warnings
+ virtual bool close( bool alsoDelete ) { return TQWidget::close( alsoDelete ); }
+
+ /**
+ * Sets a filter like "*.cpp *.h *.o". Only files matching that filter
+ * will be shown. Call updateDir() to apply it.
+ *
+ * @see KDirLister::setNameFilter
+ * @see nameFilter
+ */
+ void setNameFilter(const TQString& filter);
+
+ /**
+ * @returns the current namefilter.
+ * @see setNameFilter
+ */
+ const TQString& nameFilter() const { return dir->nameFilter(); }
+
+ /**
+ * Sets a list of mimetypes as filter. Only files of those mimetypes
+ * will be shown.
+ *
+ * Example:
+ * \code
+ * TQStringList filter;
+ * filter << "text/html" << "image/png" << "inode/directory";
+ * dirOperator->setMimefilter( filter );
+ * \endcode
+ *
+ * Node: Without the mimetype inode/directory, only files would be shown.
+ * Call updateDir() to apply it.
+ *
+ * @see KDirLister::setMimeFilter
+ * @see mimeFilter
+ */
+ void setMimeFilter( const TQStringList& mimetypes );
+
+ /**
+ * @returns the current mime filter.
+ */
+ TQStringList mimeFilter() const { return dir->mimeFilters(); }
+
+ /**
+ * Clears both the namefilter and mimetype filter, so that all files and
+ * directories will be shown. Call updateDir() to apply it.
+ *
+ * @see setMimeFilter
+ * @see setNameFilter
+ */
+ void clearFilter();
+
+ /**
+ * @returns the current url
+ */
+ KURL url() const;
+
+ /**
+ * Sets a new url to list.
+ * @param clearforward specifies whether the "forward" history should be cleared.
+ * @param url the URL to set
+ */
+ // ### KDE4: make virtual
+ void setURL(const KURL& url, bool clearforward);
+
+ /**
+ * Clears the current selection and attempts to set @p filename
+ * the current file. filename is just the name, no path or url.
+ */
+ void setCurrentItem( const TQString& filename );
+
+ /**
+ * Sets a new KFileView to be used for showing and browsing files.
+ * Note: this will read the current url() to fill the view.
+ *
+ * @see KFileView
+ * @see KFileIconView
+ * @see KFileDetailView
+ * @see KCombiView
+ * @see view
+ */
+ // ### KDE4: make virtual
+ void setView(KFileView *view);
+
+ /**
+ * @returns the currently used view.
+ * @see setView
+ */
+ KFileView * view() const { return m_fileView; }
+
+ /**
+ * Returns the widget of the current view. 0L if there is no view/widget.
+ * (KFileView itself is not a widget.)
+ */
+ TQWidget * viewWidget() const { return m_fileView ? m_fileView->widget() : 0L; }
+
+ /**
+ * Sets one of the predefined fileviews
+ * @see KFile::FileView
+ */
+ // ### KDE4: make virtual
+ void setView(KFile::FileView view);
+
+ /**
+ * Sets the way to sort files and directories.
+ */
+ void setSorting( TQDir::SortSpec );
+
+ /**
+ * @returns the current way of sorting files and directories
+ */
+ TQDir::SortSpec sorting() const { return mySorting; }
+
+ /**
+ * @returns true if we are displaying the root directory of the current url
+ */
+ bool isRoot() const { return url().path() == TQChar('/'); }
+
+ /**
+ * @returns the object listing the directory
+ */
+ KDirLister *dirLister() const { return dir; }
+
+ /**
+ * @returns the progress widget, that is shown during directory listing.
+ * You can for example reparent() it to put it into a statusbar.
+ */
+ KProgress * progressBar() const;
+
+ /**
+ * Sets the listing/selection mode for the views, an OR'ed combination of
+ * @li File
+ * @li Directory
+ * @li Files
+ * @li ExistingOnly
+ * @li LocalOnly
+ *
+ * You cannot mix File and Files of course, as the former means
+ * single-selection mode, the latter multi-selection.
+ */
+ // ### KDE4: make virtual
+ void setMode( KFile::Mode m );
+ /**
+ * @returns the listing/selection mode.
+ */
+ KFile::Mode mode() const;
+
+ /**
+ * Sets a preview-widget to be shown next to the file-view.
+ * The ownership of @p w is transferred to KDirOperator, so don't
+ * delete it yourself!
+ */
+ // ### KDE4: make virtual
+ void setPreviewWidget(const TQWidget *w);
+
+ /**
+ * @returns a list of all currently selected items. If there is no view,
+ * then 0L is returned.
+ */
+ const KFileItemList * selectedItems() const {
+ return ( m_fileView ? m_fileView->selectedItems() : 0L );
+ }
+
+ /**
+ * @returns true if @p item is currently selected, or false otherwise.
+ */
+ inline bool isSelected( const KFileItem *item ) const {
+ return ( m_fileView ? m_fileView->isSelected( item ) : false );
+ }
+
+ /**
+ * @returns the number of directories in the currently listed url.
+ * Returns 0 if there is no view.
+ */
+ int numDirs() const;
+
+ /**
+ * @returns the number of files in the currently listed url.
+ * Returns 0 if there is no view.
+ */
+ int numFiles() const;
+
+ /**
+ * @returns a KCompletion object, containing all filenames and
+ * directories of the current directory/URL.
+ * You can use it to insert it into a KLineEdit or KComboBox
+ * Note: it will only contain files, after prepareCompletionObjects()
+ * has been called. It will be implicitly called from makeCompletion()
+ * or makeDirCompletion()
+ */
+ KCompletion * completionObject() const {
+ return const_cast<KCompletion *>( &myCompletion );
+ }
+
+ /**
+ * @returns a KCompletion object, containing only all directories of the
+ * current directory/URL.
+ * You can use it to insert it into a KLineEdit or KComboBox
+ * Note: it will only contain directories, after
+ * prepareCompletionObjects() has been called. It will be implicitly
+ * called from makeCompletion() or makeDirCompletion()
+ */
+ KCompletion *dirCompletionObject() const {
+ return const_cast<KCompletion *>( &myDirCompletion );
+ }
+
+ /**
+ * an accessor to a collection of all available Actions. The actions
+ * are static, they will be there all the time (no need to connect to
+ * the signals KActionCollection::inserted() or removed().
+ *
+ * There are the following actions:
+ *
+ * @li popupMenu : an ActionMenu presenting a popupmenu with all actions
+ * @li up : changes to the parent directory
+ * @li back : goes back to the previous directory
+ * @li forward : goes forward in the history
+ * @li home : changes to the user's home directory
+ * @li reload : reloads the current directory
+ * @li separator : a separator
+ * @li mkdir : opens a dialog box to create a directory
+ * @li delete : deletes the selected files/directories
+ * @li sorting menu : an ActionMenu containing all sort-options
+ * @li by name : sorts by name
+ * @li by date : sorts by date
+ * @li by size : sorts by size
+ * @li reversed : reverses the sort order
+ * @li dirs first : sorts directories before files
+ * @li case insensitive : sorts case insensitively
+ * @li view menu : an ActionMenu containing all actions concerning the view
+ * @li short view : shows a simple fileview
+ * @li detailed view : shows a detailed fileview (dates, permissions ,...)
+ * @li show hidden : shows hidden files
+ * @li separate dirs : shows directories in a separate pane
+ * @li preview : shows a preview next to the fileview
+ * @li single : hides the separate view for directories or the preview
+ * @li properties : shows a KPropertiesDialog for the selected files
+ *
+ * The short and detailed view are in an exclusive group. The sort-by
+ * actions are in an exclusive group as well. Also the "separate dirs",
+ * "preview" and "single" actions are in an exclusive group.
+ *
+ * You can e.g. use
+ * \code
+ * actionCollection()->action( "up" )->plug( someToolBar );
+ * \endcode
+ * to add a button into a toolbar, which makes the dirOperator change to
+ * its parent directory.
+ *
+ * @returns all available Actions
+ */
+ KActionCollection * actionCollection() const { return myActionCollection; }
+
+ /**
+ * Sets the config object and the to be used group in KDirOperator. This
+ * will be used to store the view's configuration via
+ * KFileView::writeConfig() (and for KFileView::readConfig()).
+ * If you don't set this, the views cannot save and restore their
+ * configuration.
+ *
+ * Usually you call this right after KDirOperator creation so that the view
+ * instantiation can make use of it already.
+ *
+ * Note that KDirOperator does NOT take ownership of that object (typically
+ * it's TDEGlobal::config() anyway.
+ *
+ * @see viewConfig
+ * @see viewConfigGroup
+ * @since 3.1
+ */
+ // ### KDE4: make virtual
+ void setViewConfig( TDEConfig *config, const TQString& group );
+
+ /**
+ * Returns the TDEConfig object used for saving and restoring view's
+ * configuration.
+ * @returns the TDEConfig object used for saving and restoring view's
+ * configuration.
+ * @since 3.1
+ */
+ TDEConfig *viewConfig();
+
+ /**
+ * Returns the group name used for saving and restoring view's
+ * configuration.
+ * @returns the group name used for saving and restoring view's
+ * configuration.
+ * @since 3.1
+ */
+ TQString viewConfigGroup() const;
+
+ /**
+ * Reads the default settings for a view, i.e. the default KFile::FileView.
+ * Also reads the sorting and whether hidden files should be shown.
+ * Note: the default view will not be set - you have to call
+ * \code
+ * setView( KFile::Default )
+ * \endcode
+ * to apply it.
+ *
+ * @see setView
+ * @see setViewConfig
+ * @see writeConfig
+ */
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+
+ /**
+ * Saves the current settings like sorting, simple or detailed view.
+ *
+ * @see readConfig
+ * @see setViewConfig
+ */
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null );
+
+
+ /**
+ * This is a KFileDialog specific hack: we want to select directories with
+ * single click, but not files. But as a generic class, we have to be able
+ * to select files on single click as well.
+ *
+ * This gives us the opportunity to do both.
+ *
+ * The default is false, set it to true if you don't want files selected
+ * with single click.
+ */
+ void setOnlyDoubleClickSelectsFiles( bool enable );
+
+ /**
+ * @returns whether files (not directories) should only be select()ed by
+ * double-clicks.
+ * @see setOnlyDoubleClickSelectsFiles
+ */
+ bool onlyDoubleClickSelectsFiles() const;
+
+ /**
+ * Creates the given directory/url. If it is a relative path,
+ * it will be completed with the current directory.
+ * If enterDirectory is true, the directory will be entered after a
+ * successful operation. If unsuccessful, a messagebox will be presented
+ * to the user.
+ * @returns true if the directory could be created.
+ */
+ // ### KDE4: make virtual and turn TQString into KURL
+ bool mkdir( const TQString& directory, bool enterDirectory = true );
+
+ /**
+ * Starts and returns a TDEIO::DeleteJob to delete the given @p items.
+ *
+ * @param items the list of items to be deleted
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the DeleteJob to show a progress dialog
+ */
+ // ### KDE4: make virtual
+ TDEIO::DeleteJob * del( const KFileItemList& items,
+ bool ask = true, bool showProgress = true );
+
+ /**
+ * Starts and returns a TDEIO::DeleteJob to delete the given @p items.
+ *
+ * @param items the list of items to be deleted
+ * @param parent the parent widget used for the confirmation dialog
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the DeleteJob to show a progress dialog
+ * @since 3.1
+ */
+ // ### KDE4: make virtual
+ TDEIO::DeleteJob * del( const KFileItemList& items, TQWidget *parent,
+ bool ask = true, bool showProgress = true );
+
+ /**
+ * Clears the forward and backward history.
+ */
+ void clearHistory();
+
+ /**
+ * When going up in the directory hierarchy, KDirOperator can highlight
+ * the directory that was just left.
+ *
+ * I.e. when you go from /home/gis/src to /home/gis, the item "src" will
+ * be made the current item.
+ *
+ * Default is off, because this behavior introduces bug #136630.
+ * Don't enable until this bug is fixed.
+ */
+ // ### KDE4: make virtual
+ void setEnableDirHighlighting( bool enable );
+
+ /**
+ * @returns whether the last directory will be made the current item
+ * when going up in the directory hierarchy.
+ *
+ * Default is false.
+ */
+ bool dirHighlighting() const;
+
+ /**
+ * @returns true if we are in directory-only mode, that is, no files are
+ * shown.
+ */
+ bool dirOnlyMode() const { return dirOnlyMode( myMode ); }
+
+ static bool dirOnlyMode( uint mode ) {
+ return ( (mode & KFile::Directory) &&
+ (mode & (KFile::File | KFile::Files)) == 0 );
+ }
+
+ /**
+ * Sets up the action menu.
+ * @param whichActions is an value of OR'd ActionTypes that controls which actions to show in the action menu
+ */
+ void setupMenu(int whichActions);
+
+ /**
+ * Reimplemented - allow dropping of files if @p b is true
+ * @param b true if the widget should allow dropping of files
+ */
+ virtual void setAcceptDrops(bool b);
+
+ /**
+ * Sets the options for dropping files.
+ * @see KFileView::DropOptions
+ * @since 3.2
+ */
+ // ### KDE4: make virtual
+ void setDropOptions(int options);
+
+ /**
+ * Starts and returns a TDEIO::CopyJob to trash the given @p items.
+ *
+ * @param items the list of items to be trashed
+ * @param parent the parent widget used for the confirmation dialog
+ * @param ask specifies whether a confirmation dialog should be shown
+ * @param showProgress passed to the CopyJob to show a progress dialog
+ * @since 3.4
+ */
+ // ### KDE4: make virtual
+ TDEIO::CopyJob * trash( const KFileItemList& items, TQWidget *parent,
+ bool ask = true, bool showProgress = true );
+
+protected:
+ /**
+ * A view factory for creating predefined fileviews. Called internally by setView
+ * , but you can also call it directly. Reimplement this if you depend on self defined fileviews.
+ * @param parent is the TQWidget to be set as parent
+ * @param view is the predefined view to be set, note: this can be several ones OR:ed together.
+ * @returns the created KFileView
+ * @see KFileView
+ * @see KCombiView
+ * @see KFileDetailView
+ * @see KFileIconView
+ * @see KFilePreview
+ * @see KFile::FileView
+ * @see setView
+ */
+ virtual KFileView* createView( TQWidget* parent, KFile::FileView view );
+ /**
+ * Sets a custom KDirLister to list directories.
+ */
+ // ### KDE4: make virtual
+ void setDirLister( KDirLister *lister );
+
+ virtual void resizeEvent( TQResizeEvent * );
+
+ /**
+ * Sets up all the actions. Called from the constructor, you usually
+ * better not call this.
+ */
+ void setupActions();
+
+ /**
+ * Updates the sorting-related actions to comply with the current sorting
+ * @see sorting
+ */
+ void updateSortActions();
+
+ /**
+ * Updates the view-related actions to comply with the current
+ * KFile::FileView
+ */
+ void updateViewActions();
+
+ /**
+ * Sets up the context-menu with all the necessary actions. Called from the
+ * constructor, you usually don't need to call this.
+ * @since 3.1
+ */
+ void setupMenu();
+
+ /**
+ * Synchronizes the completion objects with the entries of the
+ * currently listed url.
+ *
+ * Automatically called from makeCompletion() and
+ * makeDirCompletion()
+ */
+ void prepareCompletionObjects();
+
+ /**
+ * Checks if there support from TDEIO::PreviewJob for the currently
+ * shown files, taking mimeFilter() and nameFilter() into account
+ * Enables/disables the preview-action accordingly.
+ */
+ bool checkPreviewSupport();
+
+public slots:
+ /**
+ * Goes one step back in the history and opens that url.
+ */
+ // ### KDE4: make virtual
+ void back();
+
+ /**
+ * Goes one step forward in the history and opens that url.
+ */
+ // ### KDE4: make virtual
+ void forward();
+
+ /**
+ * Enters the home directory.
+ */
+ // ### KDE4: make virtual
+ void home();
+
+ /**
+ * Goes one directory up from the current url.
+ */
+ // ### KDE4: make virtual
+ void cdUp();
+
+ /**
+ * to update the view after changing the settings
+ */
+ void updateDir();
+
+ /**
+ * Re-reads the current url.
+ */
+ // ### KDE4: make virtual
+ void rereadDir();
+
+ /**
+ * Opens a dialog to create a new directory.
+ */
+ // ### KDE4: make virtual
+ void mkdir();
+
+ /**
+ * Deletes the currently selected files/directories.
+ */
+ // ### KDE4: make virtual
+ void deleteSelected();
+
+ /**
+ * Enables/disables actions that are selection dependent. Call this e.g.
+ * when you are about to show a popup menu using some of KDirOperators
+ * actions.
+ */
+ void updateSelectionDependentActions();
+
+ /**
+ * Tries to complete the given string (only completes files).
+ */
+ TQString makeCompletion(const TQString&);
+
+ /**
+ * Tries to complete the given string (only completes directores).
+ */
+ TQString makeDirCompletion(const TQString&);
+
+ /**
+ * Trashes the currently selected files/directories.
+ * @since 3.4
+ */
+ // ### KDE4: make virtual
+ void trashSelected(KAction::ActivationReason, TQt::ButtonState);
+
+protected slots:
+ /**
+ * Restores the normal cursor after showing the busy-cursor. Also hides
+ * the progressbar.
+ */
+ void resetCursor();
+
+ /**
+ * Called after setURL() to load the directory, update the history,
+ * etc.
+ */
+ void pathChanged();
+
+ /**
+ * Adds a new list of KFileItems to the view
+ * (coming from KDirLister)
+ */
+ void insertNewFiles(const KFileItemList &newone);
+
+ /**
+ * Removes the given KFileItem item from the view (usually called from
+ * KDirLister).
+ */
+ void itemDeleted(KFileItem *);
+
+ /**
+ * Enters the directory specified by the given @p item.
+ */
+ // ### KDE4: make virtual
+ void selectDir(const KFileItem *item );
+
+ /**
+ * Emits fileSelected( item )
+ */
+ void selectFile(const KFileItem *item);
+
+ /**
+ * Emits fileHighlighted( i )
+ */
+ void highlightFile(const KFileItem* i) { emit fileHighlighted( i ); }
+
+ /**
+ * Called upon right-click to activate the popupmenu.
+ */
+ virtual void activatedMenu( const KFileItem *, const TQPoint& pos );
+
+ /**
+ * Changes sorting to sort by name
+ */
+ void sortByName() { byNameAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to sort by size
+ */
+ void sortBySize() { bySizeAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to sort by date
+ */
+ void sortByDate() { byDateAction->setChecked( true ); }
+
+ /**
+ * Changes sorting to reverse sorting
+ */
+ void sortReversed() { reverseAction->setChecked( !reverseAction->isChecked() ); }
+
+ /**
+ * Toggles showing directories first / having them sorted like files.
+ */
+ void toggleDirsFirst() { dirsFirstAction->setChecked( !dirsFirstAction->isChecked() ); }
+
+ /**
+ * Toggles case sensitive / case insensitive sorting
+ */
+ void toggleIgnoreCase() { caseInsensitiveAction->setChecked( !caseInsensitiveAction->isChecked() ); }
+
+ /**
+ * Tries to make the given @p match as current item in the view and emits
+ * completion( match )
+ */
+ void slotCompletionMatch(const TQString& match);
+
+signals:
+ void urlEntered(const KURL& );
+ void updateInformation(int files, int dirs);
+ void completion(const TQString&);
+ void finishedLoading();
+
+ /**
+ * Emitted whenever the current fileview is changed, either by an explicit
+ * call to setView() or by the user selecting a different view thru
+ * the GUI.
+ */
+ void viewChanged( KFileView * newView );
+
+ /**
+ * Emitted when a file is highlighted or generally the selection changes in
+ * multiselection mode. In the latter case, @p item is 0L. You can access
+ * the selected items with selectedItems().
+ */
+ void fileHighlighted( const KFileItem *item );
+ void dirActivated( const KFileItem *item );
+ void fileSelected( const KFileItem *item );
+ /**
+ * Emitted when files are dropped. Dropping files is disabled by
+ * default. You need to enable it with setAcceptDrops()
+ * @param item the item on which the drop occurred or 0.
+ * @param event the drop event itself.
+ * @param urls the urls that where dropped.
+ * @since 3.2
+ */
+ void dropped(const KFileItem *item, TQDropEvent*event, const KURL::List&urls);
+private:
+ /**
+ * Contains all URLs you can reach with the back button.
+ */
+ TQPtrStack<KURL> backStack;
+
+ /**
+ * Contains all URLs you can reach with the forward button.
+ */
+ TQPtrStack<KURL> forwardStack;
+
+ KDirLister *dir;
+ KURL currUrl;
+
+ KCompletion myCompletion;
+ KCompletion myDirCompletion;
+ bool myCompleteListDirty;
+ TQDir::SortSpec mySorting;
+
+ /**
+ * Checks whether we preview support is available for the current
+ * mimetype/namefilter
+ */
+ bool checkPreviewInternal() const;
+
+ /**
+ * takes action on the new location. If it's a directory, change
+ * into it, if it's a file, correct the name, etc.
+ */
+ void checkPath(const TQString& txt, bool takeFiles = false);
+
+ void connectView(KFileView *);
+
+ bool openURL( const KURL& url, bool keep = false, bool reload = false );
+
+ KFileView *m_fileView;
+ KFileItemList pendingMimeTypes;
+
+ // the enum KFile::FileView as an int
+ int m_viewKind;
+ int defaultView;
+
+ KFile::Mode myMode;
+ KProgress *progress;
+
+ const TQWidget *myPreview; // temporary pointer for the preview widget
+
+ // actions for the popupmenus
+ // ### clean up all those -- we have them all in the actionMenu!
+ KActionMenu *actionMenu;
+
+ KAction *backAction;
+ KAction *forwardAction;
+ KAction *homeAction;
+ KAction *upAction;
+ KAction *reloadAction;
+ KActionSeparator *actionSeparator;
+ KAction *mkdirAction;
+
+ KActionMenu *sortActionMenu;
+ KRadioAction *byNameAction;
+ KRadioAction *byDateAction;
+ KRadioAction *bySizeAction;
+ KToggleAction *reverseAction;
+ KToggleAction *dirsFirstAction;
+ KToggleAction *caseInsensitiveAction;
+
+ KActionMenu *viewActionMenu;
+ KRadioAction *shortAction;
+ KRadioAction *detailedAction;
+ KToggleAction *showHiddenAction;
+ KToggleAction *separateDirsAction;
+
+ KActionCollection *myActionCollection;
+ KActionCollection *viewActionCollection;
+
+private slots:
+ /**
+ * @internal
+ */
+ void slotDetailedView();
+ void slotSimpleView();
+ void slotToggleHidden( bool );
+
+ void slotSeparateDirs();
+ void slotDefaultPreview();
+ void togglePreview( bool );
+
+ void slotSortByName();
+ void slotSortBySize();
+ void slotSortByDate();
+ void slotSortReversed();
+ void slotToggleDirsFirst();
+ void slotToggleIgnoreCase();
+
+ void slotStarted();
+ void slotProgress( int );
+ void slotShowProgress();
+ void slotIOFinished();
+ void slotCanceled();
+ void slotRedirected( const KURL& );
+
+ void slotViewActionAdded( KAction * );
+ void slotViewActionRemoved( KAction * );
+ void slotViewSortingChanged( TQDir::SortSpec );
+
+ void slotClearView();
+ void slotRefreshItems( const KFileItemList& items );
+
+ void slotProperties();
+
+ void insertViewDependentActions();
+
+private:
+ static bool isReadable( const KURL& url );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirOperatorPrivate;
+ KDirOperatorPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kdirselectdialog.cpp b/tdeio/tdefile/kdirselectdialog.cpp
new file mode 100644
index 000000000..6a13920fd
--- /dev/null
+++ b/tdeio/tdefile/kdirselectdialog.cpp
@@ -0,0 +1,481 @@
+/*
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2001 Michael Jarrett <michaelj@corel.com>
+
+ 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 <tqdir.h>
+#include <tqlayout.h>
+#include <tqpopupmenu.h>
+#include <tqstringlist.h>
+#include <tqvaluestack.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <tdeconfig.h>
+#include <tdefiledialog.h>
+#include <tdefilespeedbar.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <krecentdirs.h>
+#include <kshell.h>
+#include <kurl.h>
+#include <kurlcompletion.h>
+#include <kurlpixmapprovider.h>
+#include <kinputdialog.h>
+#include <tdeio/netaccess.h>
+#include <tdeio/renamedlg.h>
+#include <kmessagebox.h>
+
+#include "tdefiletreeview.h"
+#include "kdirselectdialog.h"
+
+// ### add mutator for treeview!
+
+class KDirSelectDialog::KDirSelectDialogPrivate
+{
+public:
+ KDirSelectDialogPrivate()
+ {
+ urlCombo = 0L;
+ branch = 0L;
+ comboLocked = false;
+ }
+
+ KFileSpeedBar *speedBar;
+ KHistoryCombo *urlCombo;
+ KFileTreeBranch *branch;
+ TQString recentDirClass;
+ KURL startURL;
+ TQValueStack<KURL> dirsToList;
+
+ bool comboLocked : 1;
+};
+
+static KURL rootUrl(const KURL &url)
+{
+ KURL root = url;
+ root.setPath( "/" );
+
+ if (!kapp->authorizeURLAction("list", KURL(), root))
+ {
+ root = KURL::fromPathOrURL( TQDir::homeDirPath() );
+ if (!kapp->authorizeURLAction("list", KURL(), root))
+ {
+ root = url;
+ }
+ }
+ return root;
+}
+
+KDirSelectDialog::KDirSelectDialog(const TQString &startDir, bool localOnly,
+ TQWidget *parent, const char *name,
+ bool modal)
+ : KDialogBase( parent, name, modal, i18n("Select Folder"),
+ Ok|Cancel|User1, Ok, false,
+ KGuiItem( i18n("New Folder..."), "folder_new" ) ),
+ m_localOnly( localOnly )
+{
+ d = new KDirSelectDialogPrivate;
+ d->branch = 0L;
+
+ TQFrame *page = makeMainWidget();
+ TQHBoxLayout *hlay = new TQHBoxLayout( page, 0, spacingHint() );
+ m_mainLayout = new TQVBoxLayout();
+ d->speedBar = new KFileSpeedBar( page, "speedbar" );
+ connect( d->speedBar, TQT_SIGNAL( activated( const KURL& )),
+ TQT_SLOT( setCurrentURL( const KURL& )) );
+ hlay->addWidget( d->speedBar, 0 );
+ hlay->addLayout( m_mainLayout, 1 );
+
+ // Create dir list
+ m_treeView = new KFileTreeView( page );
+ m_treeView->addColumn( i18n("Folders") );
+ m_treeView->setColumnWidthMode( 0, TQListView::Maximum );
+ m_treeView->setResizeMode( TQListView::AllColumns );
+
+ d->urlCombo = new KHistoryCombo( page, "url combo" );
+ d->urlCombo->setTrapReturnKey( true );
+ d->urlCombo->setPixmapProvider( new KURLPixmapProvider() );
+ KURLCompletion *comp = new KURLCompletion();
+ comp->setMode( KURLCompletion::DirCompletion );
+ d->urlCombo->setCompletionObject( comp, true );
+ d->urlCombo->setAutoDeleteCompletionObject( true );
+ d->urlCombo->setDuplicatesEnabled( false );
+ connect( d->urlCombo, TQT_SIGNAL( textChanged( const TQString& ) ),
+ TQT_SLOT( slotComboTextChanged( const TQString& ) ));
+
+ m_contextMenu = new TQPopupMenu( this );
+ KAction* newFolder = new KAction( i18n("New Folder..."), "folder_new", 0, TQT_TQOBJECT(this), TQT_SLOT( slotMkdir() ), TQT_TQOBJECT(this));
+ newFolder->plug(m_contextMenu);
+ m_contextMenu->insertSeparator();
+ m_showHiddenFolders = new KToggleAction ( i18n( "Show Hidden Folders" ), 0, TQT_TQOBJECT(this),
+ TQT_SLOT( slotShowHiddenFoldersToggled() ), TQT_TQOBJECT(this));
+ m_showHiddenFolders->plug(m_contextMenu);
+
+ d->startURL = KFileDialog::getStartURL( startDir, d->recentDirClass );
+ if ( localOnly && !d->startURL.isLocalFile() )
+ {
+ d->startURL = KURL();
+ TQString docPath = TDEGlobalSettings::documentPath();
+ if (TQDir(docPath).exists())
+ d->startURL.setPath( docPath );
+ else
+ d->startURL.setPath( TQDir::homeDirPath() );
+ }
+
+ KURL root = rootUrl(d->startURL);
+
+ m_startDir = d->startURL.url();
+
+ d->branch = createBranch( root );
+
+ readConfig( TDEGlobal::config(), "DirSelect Dialog" );
+
+ m_mainLayout->addWidget( m_treeView, 1 );
+ m_mainLayout->addWidget( d->urlCombo, 0 );
+
+ connect( m_treeView, TQT_SIGNAL( currentChanged( TQListViewItem * )),
+ TQT_SLOT( slotCurrentChanged() ));
+ connect( m_treeView, TQT_SIGNAL( contextMenu( KListView *, TQListViewItem *, const TQPoint & )),
+ TQT_SLOT( slotContextMenu( KListView *, TQListViewItem *, const TQPoint & )));
+
+ connect( d->urlCombo, TQT_SIGNAL( activated( const TQString& )),
+ TQT_SLOT( slotURLActivated( const TQString& )));
+ connect( d->urlCombo, TQT_SIGNAL( returnPressed( const TQString& )),
+ TQT_SLOT( slotURLActivated( const TQString& )));
+
+ setCurrentURL( d->startURL );
+}
+
+
+KDirSelectDialog::~KDirSelectDialog()
+{
+ delete d;
+}
+
+void KDirSelectDialog::setCurrentURL( const KURL& url )
+{
+ if ( !url.isValid() )
+ return;
+
+ KURL root = rootUrl(url);
+
+ d->startURL = url;
+ if ( !d->branch ||
+ url.protocol() != d->branch->url().protocol() ||
+ url.host() != d->branch->url().host() )
+ {
+ if ( d->branch )
+ {
+ // removing the root-item causes the currentChanged() signal to be
+ // emitted, but we don't want to update the location-combo yet.
+ d->comboLocked = true;
+ view()->removeBranch( d->branch );
+ d->comboLocked = false;
+ }
+
+ d->branch = createBranch( root );
+ }
+
+ d->branch->disconnect( TQT_SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, TQT_SLOT( slotNextDirToList( KFileTreeViewItem *)));
+ connect( d->branch, TQT_SIGNAL( populateFinished( KFileTreeViewItem * )),
+ TQT_SLOT( slotNextDirToList( KFileTreeViewItem * ) ));
+
+ KURL dirToList = root;
+ d->dirsToList.clear();
+ TQString path = url.path(+1);
+ int pos = path.length();
+
+ if ( path.isEmpty() ) // e.g. ftp://host.com/ -> just list the root dir
+ d->dirsToList.push( root );
+
+ else
+ {
+ while ( pos > 0 )
+ {
+ pos = path.findRev( '/', pos -1 );
+ if ( pos >= 0 )
+ {
+ dirToList.setPath( path.left( pos +1 ) );
+ d->dirsToList.push( dirToList );
+// tqDebug( "List: %s", dirToList.url().latin1());
+ }
+ }
+ }
+
+ if ( !d->dirsToList.isEmpty() )
+ openNextDir( d->branch->root() );
+}
+
+void KDirSelectDialog::openNextDir( KFileTreeViewItem * /*parent*/ )
+{
+ if ( !d->branch )
+ return;
+
+ KURL url = d->dirsToList.pop();
+
+ KFileTreeViewItem *item = view()->findItem( d->branch, url.path().mid(1));
+ if ( item )
+ {
+ if ( !item->isOpen() )
+ item->setOpen( true );
+ else // already open -> go to next one
+ slotNextDirToList( item );
+ }
+// else
+// tqDebug("###### openNextDir: item not found!");
+}
+
+void KDirSelectDialog::slotNextDirToList( KFileTreeViewItem *item )
+{
+ // scroll to make item the topmost item
+ view()->ensureItemVisible( item );
+ TQRect r = view()->itemRect( item );
+ if ( r.isValid() )
+ {
+ int x, y;
+ view()->viewportToContents( view()->contentsX(), r.y(), x, y );
+ view()->setContentsPos( x, y );
+ }
+
+ if ( !d->dirsToList.isEmpty() )
+ openNextDir( item );
+ else
+ {
+ d->branch->disconnect( TQT_SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, TQT_SLOT( slotNextDirToList( KFileTreeViewItem *)));
+ view()->setCurrentItem( item );
+ item->setSelected( true );
+ }
+}
+
+void KDirSelectDialog::readConfig( TDEConfig *config, const TQString& group )
+{
+ d->urlCombo->clear();
+
+ TDEConfigGroup conf( config, group );
+ d->urlCombo->setHistoryItems( conf.readPathListEntry( "History Items" ));
+
+ TQSize defaultSize( 400, 450 );
+ resize( conf.readSizeEntry( "DirSelectDialog Size", &defaultSize ));
+}
+
+void KDirSelectDialog::saveConfig( TDEConfig *config, const TQString& group )
+{
+ TDEConfigGroup conf( config, group );
+ conf.writePathEntry( "History Items", d->urlCombo->historyItems(), ',',
+ true, true);
+ conf.writeEntry( "DirSelectDialog Size", size(), true, true );
+
+ d->speedBar->save( config );
+
+ config->sync();
+}
+
+void KDirSelectDialog::slotUser1()
+{
+ slotMkdir();
+}
+
+void KDirSelectDialog::accept()
+{
+ KFileTreeViewItem *item = m_treeView->currentKFileTreeViewItem();
+ if ( !item )
+ return;
+
+ if ( !d->recentDirClass.isEmpty() )
+ {
+ KURL dir = item->url();
+ if ( !item->isDir() )
+ dir = dir.upURL();
+
+ KRecentDirs::add(d->recentDirClass, dir.url());
+ }
+
+ d->urlCombo->addToHistory( item->url().prettyURL() );
+ KFileDialog::setStartDir( url() );
+
+ KDialogBase::accept();
+ saveConfig( TDEGlobal::config(), "DirSelect Dialog" );
+}
+
+
+KURL KDirSelectDialog::url() const
+{
+ return m_treeView->currentURL();
+}
+
+void KDirSelectDialog::slotCurrentChanged()
+{
+ if ( d->comboLocked )
+ return;
+
+ KFileTreeViewItem *current = view()->currentKFileTreeViewItem();
+ KURL u = current ? current->url() : (d->branch ? d->branch->rootUrl() : KURL());
+
+ if ( u.isValid() )
+ {
+ if ( u.isLocalFile() )
+ d->urlCombo->setEditText( u.path() );
+
+ else // remote url
+ d->urlCombo->setEditText( u.prettyURL() );
+ }
+ else
+ d->urlCombo->setEditText( TQString::null );
+}
+
+void KDirSelectDialog::slotURLActivated( const TQString& text )
+{
+ if ( text.isEmpty() )
+ return;
+
+ KURL url = KURL::fromPathOrURL( text );
+ d->urlCombo->addToHistory( url.prettyURL() );
+
+ if ( localOnly() && !url.isLocalFile() )
+ return; // ### messagebox
+
+ KURL oldURL = m_treeView->currentURL();
+ if ( oldURL.isEmpty() )
+ oldURL = KURL::fromPathOrURL( m_startDir );
+
+ setCurrentURL( url );
+}
+
+KFileTreeBranch * KDirSelectDialog::createBranch( const KURL& url )
+{
+ TQString title = url.isLocalFile() ? url.path() : url.prettyURL();
+ KFileTreeBranch *branch = view()->addBranch( url, title, m_showHiddenFolders->isChecked() );
+ branch->setChildRecurse( false );
+ view()->setDirOnlyMode( branch, true );
+
+ return branch;
+}
+
+void KDirSelectDialog::slotComboTextChanged( const TQString& text )
+{
+ if ( d->branch )
+ {
+ KURL url = KURL::fromPathOrURL( KShell::tildeExpand( text ) );
+ KFileTreeViewItem *item = d->branch->findTVIByURL( url );
+ if ( item )
+ {
+ view()->setCurrentItem( item );
+ view()->setSelected( item, true );
+ view()->ensureItemVisible( item );
+ return;
+ }
+ }
+
+ TQListViewItem *item = view()->currentItem();
+ if ( item )
+ {
+ item->setSelected( false );
+ // 2002/12/27, deselected item is not repainted, so force it
+ item->repaint();
+ }
+}
+
+void KDirSelectDialog::slotContextMenu( KListView *, TQListViewItem *, const TQPoint& pos )
+{
+ m_contextMenu->popup( pos );
+}
+
+void KDirSelectDialog::slotMkdir()
+{
+ bool ok;
+ TQString where = url().pathOrURL();
+ TQString name = i18n( "New Folder" );
+ if ( url().isLocalFile() && TQFileInfo( url().path(+1) + name ).exists() )
+ name = TDEIO::RenameDlg::suggestName( url(), name );
+
+ TQString directory = TDEIO::encodeFileName( KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Create new folder in:\n%1" ).arg( where ),
+ name, &ok, this));
+ if (!ok)
+ return;
+
+ bool selectDirectory = true;
+ bool writeOk = false;
+ bool exists = false;
+ KURL folderurl( url() );
+
+ TQStringList dirs = TQStringList::split( TQDir::separator(), directory );
+ TQStringList::ConstIterator it = dirs.begin();
+
+ for ( ; it != dirs.end(); ++it )
+ {
+ folderurl.addPath( *it );
+ exists = TDEIO::NetAccess::exists( folderurl, false, 0 );
+ writeOk = !exists && TDEIO::NetAccess::mkdir( folderurl, topLevelWidget() );
+ }
+
+ if ( exists ) // url was already existant
+ {
+ TQString which = folderurl.isLocalFile() ? folderurl.path() : folderurl.prettyURL();
+ KMessageBox::sorry(this, i18n("A file or folder named %1 already exists.").arg(which));
+ selectDirectory = false;
+ }
+ else if ( !writeOk ) {
+ KMessageBox::sorry(this, i18n("You do not have permission to create that folder." ));
+ }
+ else if ( selectDirectory ) {
+ setCurrentURL( folderurl );
+ }
+}
+
+void KDirSelectDialog::slotShowHiddenFoldersToggled()
+{
+ KURL currentURL = url();
+
+ d->comboLocked = true;
+ view()->removeBranch( d->branch );
+ d->comboLocked = false;
+
+ KURL root = rootUrl(d->startURL);
+ d->branch = createBranch( root );
+
+ setCurrentURL( currentURL );
+}
+
+// static
+KURL KDirSelectDialog::selectDirectory( const TQString& startDir,
+ bool localOnly,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ KDirSelectDialog myDialog( startDir, localOnly, parent,
+ "kdirselect dialog", true );
+
+ if ( !caption.isNull() )
+ myDialog.setCaption( caption );
+
+ if ( myDialog.exec() == TQDialog::Accepted )
+ return TDEIO::NetAccess::mostLocalURL(myDialog.url(),parent);
+ else
+ return KURL();
+}
+
+void KDirSelectDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+#include "kdirselectdialog.moc"
diff --git a/tdeio/tdefile/kdirselectdialog.h b/tdeio/tdefile/kdirselectdialog.h
new file mode 100644
index 000000000..746064c68
--- /dev/null
+++ b/tdeio/tdefile/kdirselectdialog.h
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2001 Michael Jarrett <michaelj@corel.com>
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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 KDIRSELECTDIALOG_H
+#define KDIRSELECTDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class TQPopupMenu;
+class TQVBoxLayout;
+class TDEConfig;
+class KFileTreeBranch;
+class KFileTreeView;
+class KFileTreeViewItem;
+class KToggleAction;
+
+/**
+ * A pretty dialog for a KDirSelect control for selecting directories.
+ * @author Michael Jarrett <michaelj@corel.com>
+ * @see KFileDialog
+ */
+class TDEIO_EXPORT KDirSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * The constructor. Creates a dialog to select a directory (url).
+ * @internal use the static selectDirectory function
+ * @param startDir the directory, initially shown
+ * @param localOnly unused. You can only select paths below the startDir
+ * @param parent the parent for the dialog, usually 0L
+ * @param name the TQObject::name
+ * @param modal if the dialog is modal or not
+ */
+ KDirSelectDialog(const TQString& startDir = TQString::null,
+ bool localOnly = false,
+ TQWidget *parent = 0L,
+ const char *name = 0, bool modal = false);
+
+ /**
+ */
+ ~KDirSelectDialog();
+
+ /**
+ * Returns the currently-selected URL, or a blank URL if none is selected.
+ * @return The currently-selected URL, if one was selected.
+ */
+ KURL url() const;
+
+ KFileTreeView * view() const { return m_treeView; }
+
+ bool localOnly() const { return m_localOnly; }
+
+ /**
+ * Creates a KDirSelectDialog, and returns the result.
+ * @param startDir the directory, initially shown
+ * The tree will display this directory and subdirectories of it.
+ * @param localOnly unused. You can only select paths below the startDir
+ * @param parent the parent widget to use for the dialog, or NULL to create a parent-less dialog
+ * @param caption the caption to use for the dialog, or TQString::null for the default caption
+ * @return The URL selected, or an empty URL if the user canceled
+ * or no URL was selected.
+ */
+ static KURL selectDirectory( const TQString& startDir = TQString::null,
+ bool localOnly = false, TQWidget *parent = 0L,
+ const TQString& caption = TQString::null);
+
+ /**
+ * @return The path for the root node
+ */
+ TQString startDir() const { return m_startDir; }
+
+public slots:
+ void setCurrentURL( const KURL& url );
+
+protected slots:
+ virtual void slotUser1();
+
+protected:
+ virtual void accept();
+
+ // Layouts protected so that subclassing is easy
+ TQVBoxLayout *m_mainLayout;
+ TQString m_startDir;
+
+private slots:
+ void slotCurrentChanged();
+ void slotURLActivated( const TQString& );
+ void slotNextDirToList( KFileTreeViewItem *dirItem );
+ void slotComboTextChanged( const TQString& text );
+ void slotContextMenu( KListView *, TQListViewItem *, const TQPoint & );
+ void slotShowHiddenFoldersToggled();
+ void slotMkdir();
+
+private:
+ void readConfig( TDEConfig *config, const TQString& group );
+ void saveConfig( TDEConfig *config, const TQString& group );
+ void openNextDir( KFileTreeViewItem *parent );
+ KFileTreeBranch * createBranch( const KURL& url );
+
+ KFileTreeView *m_treeView;
+ TQPopupMenu *m_contextMenu;
+ KToggleAction *m_showHiddenFolders;
+ bool m_localOnly;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirSelectDialogPrivate;
+ KDirSelectDialogPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kdirsize.cpp b/tdeio/tdefile/kdirsize.cpp
new file mode 100644
index 000000000..c2ea4079a
--- /dev/null
+++ b/tdeio/tdefile/kdirsize.cpp
@@ -0,0 +1,166 @@
+/* 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.
+*/
+
+#include "kdirsize.h"
+#include <kdebug.h>
+#include <kglobal.h>
+#include <tqapplication.h>
+#include <tqtimer.h>
+#include <config-tdefile.h>
+
+using namespace TDEIO;
+
+KDirSize::KDirSize( const KURL & directory )
+ : TDEIO::Job(false /*No GUI*/), m_bAsync(true), m_totalSize(0L), m_totalFiles(0L), m_totalSubdirs(0L)
+{
+ startNextJob( directory );
+}
+
+KDirSize::KDirSize( const KFileItemList & lstItems )
+ : TDEIO::Job(false /*No GUI*/), m_bAsync(true), m_totalSize(0L), m_totalFiles(0L), m_totalSubdirs(0L), m_lstItems(lstItems)
+{
+ TQTimer::singleShot( 0, this, TQT_SLOT(processList()) );
+}
+
+void KDirSize::processList()
+{
+ while (!m_lstItems.isEmpty())
+ {
+ KFileItem * item = m_lstItems.first();
+ m_lstItems.removeFirst();
+ if ( !item->isLink() )
+ {
+ if ( item->isDir() )
+ {
+ kdDebug(tdefile_area) << "KDirSize::processList dir -> listing" << endl;
+ KURL url = item->url();
+ startNextJob( url );
+ return; // we'll come back later, when this one's finished
+ }
+ else
+ {
+ m_totalSize += item->size();
+// no long long with kdDebug()
+// kdDebug(tdefile_area) << "KDirSize::processList file -> " << m_totalSize << endl;
+ }
+ }
+ }
+ kdDebug(tdefile_area) << "KDirSize::processList finished" << endl;
+ if ( !m_bAsync )
+ tqApp->exit_loop();
+ emitResult();
+}
+
+void KDirSize::startNextJob( const KURL & url )
+{
+ TDEIO::ListJob * listJob = TDEIO::listRecursive( url, false /* no GUI */ );
+ connect( listJob, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob( listJob );
+}
+
+void KDirSize::slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList & list )
+{
+ static const TQString& dot = TDEGlobal::staticQString( "." );
+ static const TQString& dotdot = TDEGlobal::staticQString( ".." );
+ TDEIO::UDSEntryListConstIterator it = list.begin();
+ TDEIO::UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+ TDEIO::UDSEntry::ConstIterator it2 = (*it).begin();
+ TDEIO::filesize_t size = 0;
+ bool isLink = false;
+ bool isDir = false;
+ TQString name;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch( (*it2).m_uds ) {
+ case TDEIO::UDS_NAME:
+ name = (*it2).m_str;
+ break;
+ case TDEIO::UDS_LINK_DEST:
+ isLink = !(*it2).m_str.isEmpty();
+ break;
+ case TDEIO::UDS_SIZE:
+ size = ((*it2).m_long);
+ break;
+ case TDEIO::UDS_FILE_TYPE:
+ isDir = S_ISDIR((*it2).m_long);
+ break;
+ default:
+ break;
+ }
+ }
+ if ( name == dot )
+ m_totalSize += size;
+ else if ( name != dotdot )
+ {
+ if (!isLink)
+ m_totalSize += size;
+ if (!isDir)
+ m_totalFiles++;
+ else
+ m_totalSubdirs++;
+ //kdDebug(tdefile_area) << name << ":" << size << endl;
+ }
+ }
+}
+
+//static
+KDirSize * KDirSize::dirSizeJob( const KURL & directory )
+{
+ return new KDirSize( directory ); // useless - but consistent with other jobs
+}
+
+//static
+KDirSize * KDirSize::dirSizeJob( const KFileItemList & lstItems )
+{
+ return new KDirSize( lstItems );
+}
+
+//static
+TDEIO::filesize_t KDirSize::dirSize( const KURL & directory )
+{
+ KDirSize * dirSize = dirSizeJob( directory );
+ dirSize->setSync();
+ tqApp->enter_loop();
+ return dirSize->totalSize();
+}
+
+
+void KDirSize::slotResult( TDEIO::Job * job )
+{
+ kdDebug(tdefile_area) << " KDirSize::slotResult( TDEIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
+ if ( !m_lstItems.isEmpty() )
+ {
+ subjobs.remove(job); // Remove job, but don't kill this job.
+ processList();
+ }
+ else
+ {
+ if ( !m_bAsync )
+ tqApp->exit_loop();
+ TDEIO::Job::slotResult( job );
+ }
+}
+
+void KDirSize::virtual_hook( int id, void* data )
+{ TDEIO::Job::virtual_hook( id, data ); }
+
+#include "kdirsize.moc"
diff --git a/tdeio/tdefile/kdirsize.h b/tdeio/tdefile/kdirsize.h
new file mode 100644
index 000000000..210080950
--- /dev/null
+++ b/tdeio/tdefile/kdirsize.h
@@ -0,0 +1,106 @@
+/* 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 __KDIRSIZE_H
+#define __KDIRSIZE_H
+
+#include <tdeio/job.h>
+#include <tdefileitem.h>
+
+/**
+ * Computes a directory size (similar to "du", but doesn't give the same results
+ * since we simply sum up the dir and file sizes, whereas du speaks disk blocks)
+ */
+class TDEIO_EXPORT KDirSize : public TDEIO::Job
+{
+ Q_OBJECT
+protected:
+ KDirSize( const KURL & directory );
+ KDirSize( const KFileItemList & lstItems );
+ ~KDirSize() {}
+
+public:
+ /**
+ * @return the size we found
+ */
+ TDEIO::filesize_t totalSize() const { return m_totalSize; }
+
+ /**
+ * @return the total number of files (counting symlinks to files, sockets
+ * and character devices as files) in this directory and all sub-directories
+ * @since 3.3
+ */
+ TDEIO::filesize_t totalFiles() const { return m_totalFiles; }
+
+ /**
+ * @return the total number of sub-directories found (not including the
+ * directory the search started from and treating symlinks to directories
+ * as directories)
+ * @since 3.3
+ */
+ TDEIO::filesize_t totalSubdirs() const { return m_totalSubdirs; }
+
+ /**
+ * Asynchronous method. Connect to the result signal.
+ * This one lists a single directory.
+ */
+ static KDirSize * dirSizeJob( const KURL & directory );
+
+ /**
+ * Asynchronous method. Connect to the result signal.
+ * This one lists the items from @p lstItems.
+ * The reason we asks for items instead of just urls, is so that
+ * we directly know if the item is a file or a directory,
+ * and in case of a file, we already have its size.
+ */
+ static KDirSize * dirSizeJob( const KFileItemList & lstItems );
+
+ /**
+ * Synchronous method - you get the result as soon as
+ * the call returns.
+ */
+ static TDEIO::filesize_t dirSize( const KURL & directory );
+
+protected:
+ /**
+ * @internal
+ */
+ void setSync() { m_bAsync = false; }
+
+ void startNextJob( const KURL & url );
+
+protected slots:
+
+ virtual void slotResult( TDEIO::Job *job );
+ void slotEntries( TDEIO::Job * , const TDEIO::UDSEntryList &);
+ void processList();
+
+private:
+ bool m_bAsync;
+ TDEIO::filesize_t m_totalSize;
+ TDEIO::filesize_t m_totalFiles;
+ TDEIO::filesize_t m_totalSubdirs;
+ KFileItemList m_lstItems;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDirSize* d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kdiskfreesp.cpp b/tdeio/tdefile/kdiskfreesp.cpp
new file mode 100644
index 000000000..9a6959fdd
--- /dev/null
+++ b/tdeio/tdefile/kdiskfreesp.cpp
@@ -0,0 +1,169 @@
+/*
+ * kdiskfreesp.cpp
+ *
+ * Copyright (c) 1999 Michael Kropfberger <michael.kropfberger@gmx.net>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ *
+ * 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 "kdiskfreesp.h"
+#include <tqfile.h>
+#include <tqtextstream.h>
+
+#include <kdebug.h>
+#include <kprocess.h>
+#include <tdeio/global.h>
+#include <config-tdefile.h>
+
+#include "kdiskfreesp.moc"
+
+#define DF_COMMAND "df"
+#define DF_ARGS "-k"
+#define NO_FS_TYPE true
+
+#define BLANK ' '
+#define FULL_PERCENT 95.0
+
+/***************************************************************************
+ * constructor
+**/
+KDiskFreeSp::KDiskFreeSp(TQObject *parent, const char *name)
+ : TQObject(parent,name)
+{
+ dfProc = new TDEProcess(); TQ_CHECK_PTR(dfProc);
+ dfProc->setEnvironment("LANGUAGE", "C");
+ connect( dfProc, TQT_SIGNAL(receivedStdout(TDEProcess *, char *, int) ),
+ this, TQT_SLOT (receivedDFStdErrOut(TDEProcess *, char *, int)) );
+ connect(dfProc,TQT_SIGNAL(processExited(TDEProcess *) ),
+ this, TQT_SLOT(dfDone() ) );
+
+ readingDFStdErrOut=false;
+}
+
+
+/***************************************************************************
+ * destructor
+**/
+KDiskFreeSp::~KDiskFreeSp()
+{
+ delete dfProc;
+}
+
+/***************************************************************************
+ * is called, when the df-command writes on StdOut
+**/
+void KDiskFreeSp::receivedDFStdErrOut(TDEProcess *, char *data, int len)
+{
+ TQCString tmp(data,len+1); // adds a zero-byte
+ dfStringErrOut.append(tmp);
+}
+
+/***************************************************************************
+ * reads the df-commands results
+**/
+int KDiskFreeSp::readDF( const TQString & mountPoint )
+{
+ if (readingDFStdErrOut || dfProc->isRunning())
+ return -1;
+ m_mountPoint = mountPoint;
+ dfStringErrOut=""; // yet no data received
+ dfProc->clearArguments();
+ (*dfProc) << TQString::fromLocal8Bit(DF_COMMAND) << TQString::fromLocal8Bit(DF_ARGS);
+ if (!dfProc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ))
+ kdError() << "could not execute ["<< DF_COMMAND << "]" << endl;
+ return 1;
+}
+
+
+/***************************************************************************
+ * is called, when the df-command has finished
+**/
+void KDiskFreeSp::dfDone()
+{
+ readingDFStdErrOut=true;
+
+ TQTextStream t (dfStringErrOut, IO_ReadOnly);
+ TQString s=t.readLine();
+ if ( (s.isEmpty()) || ( s.left(10) != TQString::fromLatin1("Filesystem") ) )
+ kdError() << "Error running df command... got [" << s << "]" << endl;
+ while ( !t.eof() ) {
+ TQString u,v;
+ s=t.readLine();
+ s=s.simplifyWhiteSpace();
+ if ( !s.isEmpty() ) {
+ //kdDebug(tdefile_area) << "GOT: [" << s << "]" << endl;
+
+ if (s.find(BLANK)<0) // devicename was too long, rest in next line
+ if ( !t.eof() ) { // just appends the next line
+ v=t.readLine();
+ s=s.append(v);
+ s=s.simplifyWhiteSpace();
+ //kdDebug(tdefile_area) << "SPECIAL GOT: [" << s << "]" << endl;
+ }//if silly linefeed
+
+ //kdDebug(tdefile_area) << "[" << s << "]" << endl;
+
+ //TQString deviceName = s.left(s.find(BLANK));
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(tdefile_area) << " DeviceName: [" << deviceName << "]" << endl;
+
+ if (!NO_FS_TYPE)
+ s=s.remove(0,s.find(BLANK)+1 ); // eat fs type
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBSize = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(tdefile_area) << " Size: [" << kBSize << "]" << endl;
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBUsed = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(tdefile_area) << " Used: [" << kBUsed << "]" << endl;
+
+ u=s.left(s.find(BLANK));
+ unsigned long kBAvail = u.toULong();
+ s=s.remove(0,s.find(BLANK)+1 );
+ //kdDebug(tdefile_area) << " Avail: [" << kBAvail << "]" << endl;
+
+
+ s=s.remove(0,s.find(BLANK)+1 ); // delete the capacity 94%
+ TQString mountPoint = s.stripWhiteSpace();
+ //kdDebug(tdefile_area) << " MountPoint: [" << mountPoint << "]" << endl;
+
+ if ( mountPoint == m_mountPoint )
+ {
+ //kdDebug(tdefile_area) << "Found mount point. Emitting" << endl;
+ emit foundMountPoint( mountPoint, kBSize, kBUsed, kBAvail );
+ emit foundMountPoint( kBSize, kBUsed, kBAvail, mountPoint ); // sic!
+ }
+ }//if not header
+ }//while further lines available
+
+ readingDFStdErrOut=false;
+ emit done();
+ delete this;
+}
+
+KDiskFreeSp * KDiskFreeSp::findUsageInfo( const TQString & path )
+{
+ KDiskFreeSp * job = new KDiskFreeSp;
+ TQString mountPoint = TDEIO::findPathMountPoint( path );
+ job->readDF( mountPoint );
+ return job;
+}
diff --git a/tdeio/tdefile/kdiskfreesp.h b/tdeio/tdefile/kdiskfreesp.h
new file mode 100644
index 000000000..5ffa47d9a
--- /dev/null
+++ b/tdeio/tdefile/kdiskfreesp.h
@@ -0,0 +1,89 @@
+/*
+ * kdiskfreesp.h
+ *
+ * Copyright (c) 1999 Michael Kropfberger <michael.kropfberger@gmx.net>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ *
+ * 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 __KDISKFREESP_H__
+#define __KDISKFREESP_H__
+
+#include <tqobject.h>
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+class TDEProcess;
+
+/**
+ * This class parses the output of "df" to find the disk usage
+ * information for a given partition (mount point).
+ */
+class TDEIO_EXPORT KDiskFreeSp : public TQObject
+{ Q_OBJECT
+public:
+ KDiskFreeSp( TQObject *parent=0, const char *name=0 );
+ /**
+ * Destructor - this object autodeletes itself when it's done
+ */
+ ~KDiskFreeSp();
+ /**
+ * Call this to fire a search on the disk usage information
+ * for @p mountPoint. foundMountPoint will be emitted
+ * if this mount point is found, with the info requested.
+ * done is emitted in any case.
+ */
+ int readDF( const TQString & mountPoint );
+
+ /**
+ * Call this to fire a search on the disk usage information
+ * for the mount point containing @p path.
+ * foundMountPoint will be emitted
+ * if this mount point is found, with the info requested.
+ * done is emitted in any case.
+ */
+ static KDiskFreeSp * findUsageInfo( const TQString & path );
+
+signals:
+ void foundMountPoint( const TQString & mountPoint, unsigned long kBSize, unsigned long kBUsed, unsigned long kBAvail );
+
+ // This one is a hack around a weird (compiler?) bug. In the former signal,
+ // the slot in KPropsDlg would get 0L, 0L as the last two parameters.
+ // When using const ulong& instead, all is ok.
+ void foundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const TQString& );
+ void done();
+
+private slots:
+ void receivedDFStdErrOut(TDEProcess *, char *data, int len);
+ void dfDone();
+
+private:
+ TDEProcess *dfProc;
+ TQCString dfStringErrOut;
+ TQString m_mountPoint;
+ bool readingDFStdErrOut;
+ class KDiskFreeSpPrivate;
+ KDiskFreeSpPrivate * d;
+};
+/***************************************************************************/
+
+
+#endif
diff --git a/tdeio/tdefile/kencodingfiledialog.cpp b/tdeio/tdefile/kencodingfiledialog.cpp
new file mode 100644
index 000000000..b8c90f6ff
--- /dev/null
+++ b/tdeio/tdefile/kencodingfiledialog.cpp
@@ -0,0 +1,223 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ 2003 Andras Mantia <amantia@freemail.hu>
+
+ 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 "config-tdefile.h"
+
+#include "kencodingfiledialog.h"
+#include <kcombobox.h>
+#include <ktoolbar.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <tqtextcodec.h>
+#include <kdiroperator.h>
+#include <krecentdocument.h>
+
+struct KEncodingFileDialogPrivate
+{
+ KComboBox *encoding;
+};
+
+KEncodingFileDialog::KEncodingFileDialog(const TQString& startDir, const TQString& encoding , const TQString& filter,
+ const TQString& caption, KFileDialog::OperationMode type, TQWidget *parent, const char* name, bool modal)
+ : KFileDialog(startDir,filter,parent,name,modal), d(new KEncodingFileDialogPrivate)
+{
+ setCaption(caption);
+
+ setOperationMode( type );
+
+ KToolBar *tb = toolBar();
+ tb->insertSeparator();
+ int index = tb->insertCombo(TQStringList(), -1 /*id*/, false /*writable*/, 0 /*signal*/, 0 /*receiver*/, 0 /*slot*/ );
+ d->encoding = tb->getCombo( tb->idAt( index ) );
+ if ( !d->encoding )
+ return;
+
+ d->encoding->clear ();
+ TQString sEncoding = encoding;
+ if (sEncoding.isEmpty())
+ sEncoding = TQString::fromLatin1(TDEGlobal::locale()->encoding());
+
+ TQStringList encodings (TDEGlobal::charsets()->availableEncodingNames());
+ int insert = 0;
+ for (uint i=0; i < encodings.count(); i++)
+ {
+ bool found = false;
+ TQTextCodec *codecForEnc = TDEGlobal::charsets()->codecForName(encodings[i], found);
+
+ if (found)
+ {
+ d->encoding->insertItem (encodings[i]);
+ if ( (codecForEnc->name() == sEncoding) || (encodings[i] == sEncoding) )
+ {
+ d->encoding->setCurrentItem(insert);
+ }
+
+ insert++;
+ }
+ }
+
+
+}
+
+KEncodingFileDialog::~KEncodingFileDialog()
+{
+ delete d;
+}
+
+
+TQString KEncodingFileDialog::selectedEncoding() const
+{
+ if (d->encoding)
+ return d->encoding->currentText();
+ else
+ return TQString::null;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenFileNameAndEncoding(const TQString& encoding,
+ const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent, const TQString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.fileNames<<dlg.selectedFile();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenFileNamesAndEncoding(const TQString& encoding,
+ const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+ dlg.setMode(KFile::Files | KFile::LocalOnly);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.fileNames=dlg.selectedFiles();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenURLAndEncoding(const TQString& encoding, const TQString& startDir,
+ const TQString& filter, TQWidget *parent, const TQString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode( KFile::File );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.URLs<<dlg.selectedURL();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+KEncodingFileDialog::Result KEncodingFileDialog::getOpenURLsAndEncoding(const TQString& encoding, const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ KEncodingFileDialog dlg(startDir, encoding,filter,caption.isNull() ? i18n("Open") : caption,Opening,parent,
+ "filedialog", true);
+
+ dlg.setMode(KFile::Files);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ Result res;
+ res.URLs=dlg.selectedURLs();
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getSaveFileNameAndEncoding(const TQString& encoding,
+ const TQString& dir,
+ const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KEncodingFileDialog dlg(specialDir?dir:TQString::null, encoding,filter,caption.isNull() ? i18n("Save As") : caption,
+ Saving,parent, "filedialog", true);
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+ dlg.exec();
+
+ TQString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ Result res;
+ res.fileNames<<filename;
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+KEncodingFileDialog::Result KEncodingFileDialog::getSaveURLAndEncoding(const TQString& encoding,
+ const TQString& dir, const TQString& filter,
+ TQWidget *parent, const TQString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KEncodingFileDialog dlg(specialDir?dir:TQString::null, encoding,filter,caption.isNull() ? i18n("Save As") :
+ caption, Saving,parent, "filedialog", true);
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.exec();
+
+ KURL url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add( url );
+
+ Result res;
+ res.URLs<<url;
+ res.encoding=dlg.selectedEncoding();
+ return res;
+}
+
+
+
+void KEncodingFileDialog::virtual_hook( int id, void* data )
+{
+ KFileDialog::virtual_hook( id, data );
+}
+
+
+#include "kencodingfiledialog.moc"
diff --git a/tdeio/tdefile/kencodingfiledialog.h b/tdeio/tdefile/kencodingfiledialog.h
new file mode 100644
index 000000000..8659122fb
--- /dev/null
+++ b/tdeio/tdefile/kencodingfiledialog.h
@@ -0,0 +1,313 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ 2003 Andras Mantia <amantia@freemail.hu>
+
+ 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 __KENCODINGFILEDIALOG_H__
+#define __KENCODINGFILEDIALOG_H__
+
+#include <tdefiledialog.h>
+
+struct KEncodingFileDialogPrivate;
+
+/**
+ * Provides a user (and developer) friendly way to
+ * select files with support for choosing encoding
+ *
+ *
+ * The dialog has been designed to allow applications to customise it
+ * by subclassing. It uses geometry management to ensure that subclasses
+ * can easily add children that will be incorporated into the layout.
+ */
+
+class TDEIO_EXPORT KEncodingFileDialog : public KFileDialog
+{
+ Q_OBJECT
+
+public:
+ class Result {
+ public:
+ TQStringList fileNames;
+ KURL::List URLs;
+ TQString encoding;
+ };
+
+ /**
+ * Constructs a file dialog for text files with encoding selection possibility.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param encoding The encoding shown in the encoding combo. If it's
+ * TQString::null, the global default encoding will be shown.
+ *
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ *
+ * @param caption The caption of the dialog
+ *
+ * @param type This can either be
+ * @li Opening (open dialog, the default setting)
+ * @li Saving
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ *
+ * @since 3.2
+ */
+ KEncodingFileDialog (const TQString& startDir = TQString::null,
+ const TQString& encoding = TQString::null,
+ const TQString& filter = TQString::null,
+ const TQString& caption = TQString::null, KFileDialog::OperationMode type = KFileDialog::Opening,
+ TQWidget *parent= 0, const char *name="", bool modal = true);
+ /**
+ * Destructs the file dialog.
+ */
+ ~KEncodingFileDialog();
+
+
+ /**
+ * @returns The selected encoding if the constructor with the encoding parameter was used, otherwise TQString::null.
+ */
+ TQString selectedEncoding() const;
+
+
+ /**
+ * Creates a modal file dialog and return the selected
+ * filename or an empty string if none was chosen additionally a chosen
+ * encoding value is returned.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenFileNameAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and the selected
+ * filenames or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenFileNamesAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent = 0,
+ const TQString& caption= TQString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * URL or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing URL.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenURLAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir = TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding
+ * URLs or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getOpenURLsAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent = 0,
+ const TQString& caption= TQString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getSaveFileNameAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir=TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+ /**
+ * Creates a modal file dialog and returns the selected encoding and
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param encoding The encoding shown in the encoding combo.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static Result getSaveURLAndEncoding(const TQString& encoding=TQString::null,
+ const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KEncodingFileDialogPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kicondialog.cpp b/tdeio/tdefile/kicondialog.cpp
new file mode 100644
index 000000000..da8745507
--- /dev/null
+++ b/tdeio/tdefile/kicondialog.cpp
@@ -0,0 +1,772 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module tdefile.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * (C) 2000 Kurt Granroth <granroth@kde.org>
+ * (C) 1997 Christoph Neerfeld <chris@kde.org>
+ * (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#include "kicondialog.h"
+
+#include <config.h>
+
+#include <assert.h>
+
+#include <kiconviewsearchline.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kprogress.h>
+#include <kiconview.h>
+#include <tdefiledialog.h>
+#include <kimagefilepreview.h>
+
+#include <tqlayout.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqsortedlist.h>
+#include <tqimage.h>
+#include <tqpixmap.h>
+#include <tqlabel.h>
+#include <tqcombobox.h>
+#include <tqtimer.h>
+#include <tqbuttongroup.h>
+#include <tqradiobutton.h>
+#include <tqfileinfo.h>
+#include <tqtoolbutton.h>
+#include <tqwhatsthis.h>
+
+#ifdef HAVE_LIBART
+#include <svgicons/ksvgiconengine.h>
+#include <svgicons/ksvgiconpainter.h>
+#endif
+
+class KIconCanvas::KIconCanvasPrivate
+{
+ public:
+ KIconCanvasPrivate() { m_bLoading = false; }
+ ~KIconCanvasPrivate() {}
+ bool m_bLoading;
+};
+
+/**
+ * Helper class for sorting icon paths by icon name
+ */
+class IconPath : public TQString
+{
+protected:
+ TQString m_iconName;
+
+public:
+ IconPath(const TQString &ip) : TQString (ip)
+ {
+ int n = findRev('/');
+ m_iconName = (n==-1) ? static_cast<TQString>(*this) : mid(n+1);
+ }
+
+
+ IconPath() : TQString ()
+ { }
+
+ bool operator== (const IconPath &ip) const
+ { return m_iconName == ip.m_iconName; }
+
+ bool operator< (const IconPath &ip) const
+ { return m_iconName < ip.m_iconName; }
+
+};
+
+/*
+ * KIconCanvas: Iconview for the iconloader dialog.
+ */
+
+KIconCanvas::KIconCanvas(TQWidget *parent, const char *name)
+ : KIconView(parent, name)
+{
+ d = new KIconCanvasPrivate;
+ mpTimer = new TQTimer(this);
+ connect(mpTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotLoadFiles()));
+ connect(this, TQT_SIGNAL(currentChanged(TQIconViewItem *)),
+ TQT_SLOT(slotCurrentChanged(TQIconViewItem *)));
+ setGridX(80);
+ setWordWrapIconText(false);
+ setShowToolTips(true);
+}
+
+KIconCanvas::~KIconCanvas()
+{
+ delete mpTimer;
+ delete d;
+}
+
+void KIconCanvas::loadFiles(const TQStringList& files)
+{
+ clear();
+ mFiles = files;
+ emit startLoading(mFiles.count());
+ mpTimer->start(10, true); // #86680
+ d->m_bLoading = false;
+}
+
+void KIconCanvas::slotLoadFiles()
+{
+ setResizeMode(Fixed);
+ TQApplication::setOverrideCursor(tqwaitCursor);
+
+ // disable updates to not trigger paint events when adding child items
+ setUpdatesEnabled( false );
+
+#ifdef HAVE_LIBART
+ KSVGIconEngine *svgEngine = new KSVGIconEngine();
+#endif
+
+ d->m_bLoading = true;
+ int i;
+ TQStringList::ConstIterator it;
+ uint emitProgress = 10; // so we will emit it once in the beginning
+ TQStringList::ConstIterator end(mFiles.end());
+ for (it=mFiles.begin(), i=0; it!=end; ++it, i++)
+ {
+ // Calling kapp->processEvents() makes the iconview flicker like hell
+ // (it's being repainted once for every new item), so we don't do this.
+ // Instead, we directly repaint the progress bar without going through
+ // the event-loop. We do that just once for every 10th item so that
+ // the progress bar doesn't flicker in turn. (pfeiffer)
+ if ( emitProgress >= 10 ) {
+ emit progress(i);
+ emitProgress = 0;
+ }
+
+ emitProgress++;
+// kapp->processEvents();
+ if ( !d->m_bLoading ) // user clicked on a button that will load another set of icons
+ break;
+ TQImage img;
+
+ // Use the extension as the format. Works for XPM and PNG, but not for SVG
+ TQString path= *it;
+ TQString ext = path.right(3).upper();
+
+ if (ext != "SVG" && ext != "VGZ")
+ img.load(*it);
+#ifdef HAVE_LIBART
+ else
+ if (svgEngine->load(60, 60, *it))
+ img = *svgEngine->painter()->image();
+#endif
+
+ if (img.isNull())
+ continue;
+ if (img.width() > 60 || img.height() > 60)
+ {
+ if (img.width() > img.height())
+ {
+ int height = (int) ((60.0 / img.width()) * img.height());
+ img = img.smoothScale(60, height);
+ } else
+ {
+ int width = (int) ((60.0 / img.height()) * img.width());
+ img = img.smoothScale(width, 60);
+ }
+ }
+ TQPixmap pm;
+ pm.convertFromImage(img);
+ TQFileInfo fi(*it);
+ TQIconViewItem *item = new TQIconViewItem(this, fi.baseName(), pm);
+ item->setKey(*it);
+ item->setDragEnabled(false);
+ item->setDropEnabled(false);
+ }
+
+#ifdef HAVE_LIBART
+ delete svgEngine;
+#endif
+
+ // enable updates since we have to draw the whole view now
+ setUpdatesEnabled( true );
+
+ TQApplication::restoreOverrideCursor();
+ d->m_bLoading = false;
+ emit finished();
+ setResizeMode(Adjust);
+}
+
+TQString KIconCanvas::getCurrent() const
+{
+ if (!currentItem())
+ return TQString::null;
+ return currentItem()->key();
+}
+
+void KIconCanvas::stopLoading()
+{
+ d->m_bLoading = false;
+}
+
+void KIconCanvas::slotCurrentChanged(TQIconViewItem *item)
+{
+ emit nameChanged((item != 0L) ? item->text() : TQString::null);
+}
+
+class KIconDialog::KIconDialogPrivate
+{
+ public:
+ KIconDialogPrivate() {
+ m_bStrictIconSize = true;
+ m_bLockUser = false;
+ m_bLockCustomDir = false;
+ searchLine = 0;
+ }
+ ~KIconDialogPrivate() {}
+ bool m_bStrictIconSize, m_bLockUser, m_bLockCustomDir;
+ TQString custom;
+ TQString customLocation;
+ KIconViewSearchLine *searchLine;
+};
+
+/*
+ * KIconDialog: Dialog for selecting icons. Both system and user
+ * specified icons can be chosen.
+ */
+
+KIconDialog::KIconDialog(TQWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
+{
+ d = new KIconDialogPrivate;
+ mpLoader = TDEGlobal::iconLoader();
+ init();
+}
+
+KIconDialog::KIconDialog(KIconLoader *loader, TQWidget *parent,
+ const char *name)
+ : KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
+{
+ d = new KIconDialogPrivate;
+ mpLoader = loader;
+ init();
+}
+
+void KIconDialog::init()
+{
+ mGroupOrSize = KIcon::Desktop;
+ mContext = KIcon::Any;
+ mType = 0;
+ mFileList = TDEGlobal::dirs()->findAllResources("appicon", TQString::fromLatin1("*.png"));
+
+ TQWidget *main = new TQWidget( this );
+ setMainWidget(main);
+
+ TQVBoxLayout *top = new TQVBoxLayout(main);
+ top->setSpacing( spacingHint() );
+
+ TQButtonGroup *bgroup = new TQButtonGroup(0, Qt::Vertical, i18n("Icon Source"), main);
+ bgroup->layout()->setSpacing(KDialog::spacingHint());
+ bgroup->layout()->setMargin(KDialog::marginHint());
+ top->addWidget(bgroup);
+ connect(bgroup, TQT_SIGNAL(clicked(int)), TQT_SLOT(slotButtonClicked(int)));
+ TQGridLayout *grid = new TQGridLayout(bgroup->layout(), 3, 2);
+ mpRb1 = new TQRadioButton(i18n("S&ystem icons:"), bgroup);
+ grid->addWidget(mpRb1, 1, 0);
+ mpCombo = new TQComboBox(bgroup);
+ connect(mpCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotContext(int)));
+ grid->addWidget(mpCombo, 1, 1);
+ mpRb2 = new TQRadioButton(i18n("O&ther icons:"), bgroup);
+ grid->addWidget(mpRb2, 2, 0);
+ mpBrowseBut = new TQPushButton(i18n("&Browse..."), bgroup);
+ grid->addWidget(mpBrowseBut, 2, 1);
+
+ //
+ // ADD SEARCHLINE
+ //
+ TQHBoxLayout *searchLayout = new TQHBoxLayout(0, 0, KDialog::spacingHint());
+ top->addLayout(searchLayout);
+
+ TQToolButton *clearSearch = new TQToolButton(main);
+ clearSearch->setTextLabel(i18n("Clear Search"), true);
+ clearSearch->setIconSet(SmallIconSet(TQApplication::reverseLayout() ? "clear_left" :"locationbar_erase"));
+ searchLayout->addWidget(clearSearch);
+
+ TQLabel *searchLabel = new TQLabel(i18n("&Search:"), main);
+ searchLayout->addWidget(searchLabel);
+
+ d->searchLine = new KIconViewSearchLine(main, "searchLine");
+ searchLayout->addWidget(d->searchLine);
+ searchLabel->setBuddy(d->searchLine);
+
+
+ // signals and slots connections
+ connect(clearSearch, TQT_SIGNAL(clicked()), d->searchLine, TQT_SLOT(clear()));
+
+ TQString wtstr = i18n("Search interactively for icon names (e.g. folder).");
+ TQWhatsThis::add(searchLabel, wtstr);
+ TQWhatsThis::add(d->searchLine, wtstr);
+
+
+ mpCanvas = new KIconCanvas(main);
+ connect(mpCanvas, TQT_SIGNAL(executed(TQIconViewItem *)), TQT_SLOT(slotAcceptIcons()));
+ connect(mpCanvas, TQT_SIGNAL(returnPressed(TQIconViewItem *)), TQT_SLOT(slotAcceptIcons()));
+ mpCanvas->setMinimumSize(400, 125);
+ top->addWidget(mpCanvas);
+ d->searchLine->setIconView(mpCanvas);
+
+ mpProgress = new KProgress(main);
+ top->addWidget(mpProgress);
+ connect(mpCanvas, TQT_SIGNAL(startLoading(int)), TQT_SLOT(slotStartLoading(int)));
+ connect(mpCanvas, TQT_SIGNAL(progress(int)), TQT_SLOT(slotProgress(int)));
+ connect(mpCanvas, TQT_SIGNAL(finished()), TQT_SLOT(slotFinished()));
+
+ // When pressing Ok or Cancel, stop loading icons
+ connect(this, TQT_SIGNAL(hidden()), mpCanvas, TQT_SLOT(stopLoading()));
+
+ static const char* const context_text[] = {
+ I18N_NOOP( "Actions" ),
+ I18N_NOOP( "Animations" ),
+ I18N_NOOP( "Applications" ),
+ I18N_NOOP( "Categories" ),
+ I18N_NOOP( "Devices" ),
+ I18N_NOOP( "Emblems" ),
+ I18N_NOOP( "Emotes" ),
+ I18N_NOOP( "Filesystems" ),
+ I18N_NOOP( "International" ),
+ I18N_NOOP( "Mimetypes" ),
+ I18N_NOOP( "Places" ),
+ I18N_NOOP( "Status" ) };
+ static const KIcon::Context context_id[] = {
+ KIcon::Action,
+ KIcon::Animation,
+ KIcon::Application,
+ KIcon::Category,
+ KIcon::Device,
+ KIcon::Emblem,
+ KIcon::Emote,
+ KIcon::FileSystem,
+ KIcon::International,
+ KIcon::MimeType,
+ KIcon::Place,
+ KIcon::StatusIcon };
+ mNumContext = 0;
+ int cnt = sizeof( context_text ) / sizeof( context_text[ 0 ] );
+ // check all 3 arrays have same sizes
+ assert( cnt == sizeof( context_id ) / sizeof( context_id[ 0 ] )
+ && cnt == sizeof( mContextMap ) / sizeof( mContextMap[ 0 ] ));
+ for( int i = 0;
+ i < cnt;
+ ++i )
+ {
+ if( mpLoader->hasContext( context_id[ i ] ))
+ {
+ mpCombo->insertItem(i18n( context_text[ i ] ));
+ mContextMap[ mNumContext++ ] = context_id[ i ];
+ }
+ }
+ mpCombo->setFixedSize(mpCombo->sizeHint());
+
+ mpBrowseBut->setFixedWidth(mpCombo->width());
+
+ // Make the dialog a little taller
+ incInitialSize(TQSize(0,100));
+}
+
+
+KIconDialog::~KIconDialog()
+{
+ delete d;
+}
+
+void KIconDialog::slotAcceptIcons()
+{
+ d->custom=TQString::null;
+ slotOk();
+}
+
+void KIconDialog::showIcons()
+{
+ mpCanvas->clear();
+ TQStringList filelist;
+ if (mType == 0)
+ if (d->m_bStrictIconSize)
+ filelist=mpLoader->queryIcons(mGroupOrSize, mContext);
+ else
+ filelist=mpLoader->queryIconsByContext(mGroupOrSize, mContext);
+ else if ( !d->customLocation.isNull() )
+ filelist=mpLoader->queryIconsByDir( d->customLocation );
+ else
+ filelist=mFileList;
+
+ TQSortedList <IconPath>iconlist;
+ iconlist.setAutoDelete(true);
+ TQStringList::Iterator it;
+ for( it = filelist.begin(); it != filelist.end(); ++it )
+ iconlist.append(new IconPath(*it));
+
+ iconlist.sort();
+ filelist.clear();
+
+ for ( IconPath *ip=iconlist.first(); ip != 0; ip=iconlist.next() )
+ filelist.append(*ip);
+
+ d->searchLine->clear();
+ mpCanvas->loadFiles(filelist);
+}
+
+void KIconDialog::setStrictIconSize(bool b)
+{
+ d->m_bStrictIconSize=b;
+}
+
+bool KIconDialog::strictIconSize() const
+{
+ return d->m_bStrictIconSize;
+}
+
+void KIconDialog::setIconSize( int size )
+{
+ // see KIconLoader, if you think this is weird
+ if ( size == 0 )
+ mGroupOrSize = KIcon::Desktop; // default Group
+ else
+ mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird
+}
+
+int KIconDialog::iconSize() const
+{
+ // 0 or any other value ==> mGroupOrSize is a group, so we return 0
+ return (mGroupOrSize < 0) ? -mGroupOrSize : 0;
+}
+
+#ifndef KDE_NO_COMPAT
+TQString KIconDialog::selectIcon(KIcon::Group group, KIcon::Context context, bool user)
+{
+ setup( group, context, false, 0, user );
+ return openDialog();
+}
+#endif
+
+void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user )
+{
+ d->m_bStrictIconSize = strictIconSize;
+ mGroupOrSize = (iconSize == 0) ? group : -iconSize;
+ mType = user ? 1 : 0;
+ mpRb1->setChecked(!user);
+ mpRb2->setChecked(user);
+ mpCombo->setEnabled(!user);
+ mpBrowseBut->setEnabled(user);
+ setContext( context );
+}
+
+void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user,
+ bool lockUser, bool lockCustomDir )
+{
+ d->m_bStrictIconSize = strictIconSize;
+ d->m_bLockUser = lockUser;
+ d->m_bLockCustomDir = lockCustomDir;
+ mGroupOrSize = (iconSize == 0) ? group : -iconSize;
+ mType = user ? 1 : 0;
+ mpRb1->setChecked(!user);
+ mpRb1->setEnabled( !lockUser || !user );
+ mpRb2->setChecked(user);
+ mpRb2->setEnabled( !lockUser || user );
+ mpCombo->setEnabled(!user);
+ mpBrowseBut->setEnabled( user && !lockCustomDir );
+ setContext( context );
+}
+
+void KIconDialog::setContext( KIcon::Context context )
+{
+ mContext = context;
+ for( int i = 0;
+ i < mNumContext;
+ ++i )
+ if( mContextMap[ i ] == context )
+ {
+ mpCombo->setCurrentItem( i );
+ return;
+ }
+}
+
+void KIconDialog::setCustomLocation( const TQString& location )
+{
+ d->customLocation = location;
+}
+
+TQString KIconDialog::openDialog()
+{
+ showIcons();
+
+ if ( exec() == Accepted )
+ {
+ if (!d->custom.isNull())
+ return d->custom;
+ TQString name = mpCanvas->getCurrent();
+ if (name.isEmpty() || (mType == 1))
+ return name;
+ TQFileInfo fi(name);
+ return fi.baseName();
+ }
+ return TQString::null;
+}
+
+void KIconDialog::showDialog()
+{
+ setModal(false);
+ showIcons();
+ show();
+}
+
+void KIconDialog::slotOk()
+{
+ TQString name;
+ if (!d->custom.isNull())
+ {
+ name = d->custom;
+ }
+ else
+ {
+ name = mpCanvas->getCurrent();
+ if (!name.isEmpty() && (mType != 1))
+ {
+ TQFileInfo fi(name);
+ name = fi.baseName();
+ }
+ }
+
+ emit newIconName(name);
+ KDialogBase::slotOk();
+}
+
+TQString KIconDialog::getIcon(KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user,
+ TQWidget *parent, const TQString &caption)
+{
+ KIconDialog dlg(parent, "icon dialog");
+ dlg.setup( group, context, strictIconSize, iconSize, user );
+ if (!caption.isNull())
+ dlg.setCaption(caption);
+
+ return dlg.openDialog();
+}
+
+void KIconDialog::slotButtonClicked(int id)
+{
+ TQString file;
+
+ switch (id)
+ {
+ case 0:
+ if(mType!=0)
+ {
+ mType = 0;
+ mpBrowseBut->setEnabled(false);
+ mpCombo->setEnabled(true);
+ showIcons();
+ }
+ break;
+
+ case 1:
+ if(mType!=1)
+ {
+ mType = 1;
+ mpBrowseBut->setEnabled( !d->m_bLockCustomDir );
+ mpCombo->setEnabled(false);
+ showIcons();
+ }
+ break;
+ case 2:
+ {
+ // Create a file dialog to select a PNG, XPM or SVG file,
+ // with the image previewer shown.
+ // KFileDialog::getImageOpenURL doesn't allow svg.
+ KFileDialog dlg(TQString::null, i18n("*.png *.xpm *.svg *.svgz|Icon Files (*.png *.xpm *.svg *.svgz)"),
+ this, "filedialog", true);
+ dlg.setOperationMode( KFileDialog::Opening );
+ dlg.setCaption( i18n("Open") );
+ dlg.setMode( KFile::File );
+
+ KImageFilePreview *ip = new KImageFilePreview( &dlg );
+ dlg.setPreviewWidget( ip );
+ dlg.exec();
+
+ file = dlg.selectedFile();
+ if (!file.isEmpty())
+ {
+ d->custom = file;
+ if ( mType == 1 )
+ d->customLocation = TQFileInfo( file ).dirPath( true );
+ slotOk();
+ }
+ }
+ break;
+ }
+}
+
+void KIconDialog::slotContext(int id)
+{
+ mContext = static_cast<KIcon::Context>( mContextMap[ id ] );
+ showIcons();
+}
+
+void KIconDialog::slotStartLoading(int steps)
+{
+ if (steps < 10)
+ mpProgress->hide();
+ else
+ {
+ mpProgress->setTotalSteps(steps);
+ mpProgress->setProgress(0);
+ mpProgress->show();
+ }
+}
+
+void KIconDialog::slotProgress(int p)
+{
+ mpProgress->setProgress(p);
+ // commented out the following since setProgress already paints ther
+ // progress bar. ->repaint() only makes it flicker
+ //mpProgress->repaint();
+}
+
+void KIconDialog::slotFinished()
+{
+ mpProgress->hide();
+}
+
+class KIconButton::KIconButtonPrivate
+{
+ public:
+ KIconButtonPrivate() {
+ m_bStrictIconSize = false;
+ iconSize = 0; // let KIconLoader choose the default
+ }
+ ~KIconButtonPrivate() {}
+ bool m_bStrictIconSize;
+ int iconSize;
+};
+
+
+/*
+ * KIconButton: A "choose icon" pushbutton.
+ */
+
+KIconButton::KIconButton(TQWidget *parent, const char *name)
+ : TQPushButton(parent, name)
+{
+ init( TDEGlobal::iconLoader() );
+}
+
+KIconButton::KIconButton(KIconLoader *loader,
+ TQWidget *parent, const char *name)
+ : TQPushButton(parent, name)
+{
+ init( loader );
+}
+
+void KIconButton::init( KIconLoader *loader )
+{
+ d = new KIconButtonPrivate;
+ mGroup = KIcon::Desktop;
+ mContext = KIcon::Application;
+ mbUser = false;
+
+ mpLoader = loader;
+ mpDialog = 0L;
+ connect(this, TQT_SIGNAL(clicked()), TQT_SLOT(slotChangeIcon()));
+}
+
+KIconButton::~KIconButton()
+{
+ delete mpDialog;
+ delete d;
+}
+
+void KIconButton::setStrictIconSize(bool b)
+{
+ d->m_bStrictIconSize=b;
+}
+
+bool KIconButton::strictIconSize() const
+{
+ return d->m_bStrictIconSize;
+}
+
+void KIconButton::setIconSize( int size )
+{
+ d->iconSize = size;
+}
+
+int KIconButton::iconSize() const
+{
+ return d->iconSize;
+}
+
+void KIconButton::setIconType(KIcon::Group group, KIcon::Context context, bool user)
+{
+ mGroup = group;
+ mContext = context;
+ mbUser = user;
+}
+
+void KIconButton::setIcon(const TQString& icon)
+{
+ mIcon = icon;
+ setIconSet(mpLoader->loadIconSet(mIcon, mGroup, d->iconSize));
+
+ if (!mpDialog)
+ {
+ mpDialog = new KIconDialog(mpLoader, this);
+ connect(mpDialog, TQT_SIGNAL(newIconName(const TQString&)), TQT_SLOT(newIconName(const TQString&)));
+ }
+
+ if ( mbUser )
+ mpDialog->setCustomLocation( TQFileInfo( mpLoader->iconPath(mIcon, mGroup, true) ).dirPath( true ) );
+}
+
+void KIconButton::resetIcon()
+{
+ mIcon = TQString::null;
+ setIconSet(TQIconSet());
+}
+
+void KIconButton::slotChangeIcon()
+{
+ if (!mpDialog)
+ {
+ mpDialog = new KIconDialog(mpLoader, this);
+ connect(mpDialog, TQT_SIGNAL(newIconName(const TQString&)), TQT_SLOT(newIconName(const TQString&)));
+ }
+
+ mpDialog->setup( mGroup, mContext, d->m_bStrictIconSize, d->iconSize, mbUser );
+ mpDialog->showDialog();
+}
+
+void KIconButton::newIconName(const TQString& name)
+{
+ if (name.isEmpty())
+ return;
+
+ TQIconSet iconset = mpLoader->loadIconSet(name, mGroup, d->iconSize);
+ setIconSet(iconset);
+ mIcon = name;
+
+ if ( mbUser )
+ mpDialog->setCustomLocation( TQFileInfo( mpLoader->iconPath(mIcon, mGroup, true) ).dirPath( true ) );
+
+ emit iconChanged(name);
+}
+
+void KIconCanvas::virtual_hook( int id, void* data )
+{ KIconView::virtual_hook( id, data ); }
+
+void KIconDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+#include "kicondialog.moc"
diff --git a/tdeio/tdefile/kicondialog.h b/tdeio/tdefile/kicondialog.h
new file mode 100644
index 000000000..d7cb48f1c
--- /dev/null
+++ b/tdeio/tdefile/kicondialog.h
@@ -0,0 +1,350 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module tdefile.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ * (C) 2000 Kurt Granroth <granroth@kde.org>
+ * (C) 1997 Christoph Neerfeld <chris@kde.org>
+ * (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * This is free software; it comes under the GNU Library General
+ * Public License, version 2. See the file "COPYING.LIB" for the
+ * exact licensing terms.
+ */
+
+#ifndef __KIconDialog_h__
+#define __KIconDialog_h__
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqpushbutton.h>
+
+#include <kicontheme.h>
+#include <kdialogbase.h>
+#include <kiconview.h>
+
+class TQComboBox;
+class TQTimer;
+class TQKeyEvent;
+class TQRadioButton;
+class KProgress;
+class KIconLoader;
+
+/**
+ * Icon canvas for KIconDialog.
+ */
+class TDEIO_EXPORT KIconCanvas: public KIconView
+{
+ Q_OBJECT
+
+public:
+ KIconCanvas(TQWidget *parent=0L, const char *name=0L);
+ ~KIconCanvas();
+
+ /**
+ * Load icons into the canvas.
+ */
+ void loadFiles(const TQStringList& files);
+
+ /**
+ * Returns the current icon.
+ */
+ TQString getCurrent() const;
+
+public slots:
+ void stopLoading();
+
+signals:
+ /**
+ * Emitted when the current icon has changed.
+ */
+ void nameChanged(TQString);
+ /* KDE 4: Make it const TQString & */
+
+ void startLoading(int);
+ void progress(int);
+ void finished();
+
+private slots:
+ void slotLoadFiles();
+ void slotCurrentChanged(TQIconViewItem *item);
+
+private:
+ TQStringList mFiles;
+ TQTimer *mpTimer;
+ KIconLoader *mpLoader; // unused
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ class KIconCanvasPrivate;
+ KIconCanvasPrivate *d;
+};
+
+
+/**
+ * Dialog for interactive selection of icons. Use the function
+ * getIcon() let the user select an icon.
+ *
+ * @short An icon selection dialog.
+ */
+class TDEIO_EXPORT KIconDialog: public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs an icon selection dialog using the global iconloader.
+ */
+ KIconDialog(TQWidget *parent=0L, const char *name=0L);
+ /**
+ * Constructs an icon selection dialog using a specific iconloader.
+ */
+ KIconDialog(KIconLoader *loader, TQWidget *parent=0,
+ const char *name=0);
+ /**
+ * Destructs the dialog.
+ */
+ ~KIconDialog();
+
+ /**
+ * Sets a strict icon size policy for allowed icons. When true,
+ * only icons of the specified group's size in getIcon() are shown.
+ * When false, icons not available at the desired group's size will
+ * also be selectable.
+ */
+ void setStrictIconSize(bool b);
+ /**
+ * Returns true if a strict icon size policy is set.
+ */
+ bool strictIconSize() const;
+ /**
+ * sets a custom icon directory
+ * @since 3.1
+ */
+ void setCustomLocation( const TQString& location );
+
+ /**
+ * Sets the size of the icons to be shown / selected.
+ * @see KIcon::StdSizes
+ * @see iconSize
+ */
+ void setIconSize(int size);
+
+ /**
+ * Returns the iconsize set via setIconSize() or 0, if the default
+ * iconsize will be used.
+ */
+ int iconSize() const;
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated in KDE 3.0, use the static method getIcon instead.
+ */
+ TQString selectIcon(KIcon::Group group=KIcon::Desktop, KIcon::Context
+ context=KIcon::Application, bool user=false);
+#endif
+
+ /**
+ * Allows you to set the same parameters as in the class method
+ * getIcon().
+ */
+ void setup( KIcon::Group group,
+ KIcon::Context context = KIcon::Application,
+ bool strictIconSize = false, int iconSize = 0,
+ bool user = false );
+
+ /**
+ * Allows you to set the same parameters as in the class method
+ * getIcon(), as well as two additional parameters to lock
+ * the choice between system and user dirs and to lock the custom user
+ * dir itself.
+ *
+ * @since 3.3
+ */
+
+ void setup( KIcon::Group group, KIcon::Context context,
+ bool strictIconSize, int iconSize, bool user, bool lockUser,
+ bool lockCustomDir );
+
+ /**
+ * exec()utes this modal dialog and returns the name of the selected icon,
+ * or TQString::null if the dialog was aborted.
+ * @returns the name of the icon, suitable for loading with KIconLoader.
+ * @see getIcon
+ */
+ TQString openDialog();
+
+ /**
+ * show()es this dialog and emits a newIcon(const TQString&) signal when
+ * successful. TQString::null will be emitted if the dialog was aborted.
+ */
+ void showDialog();
+
+ /**
+ * Pops up the dialog an lets the user select an icon.
+ *
+ * @param group The icon group this icon is intended for. Providing the
+ * group shows the icons in the dialog with the same appearance as when
+ * used outside the dialog.
+ * @param context The initial icon context. Initially, the icons having
+ * this context are shown in the dialog. The user can change this.
+ * @param strictIconSize When true, only icons of the specified group's size
+ * are shown, otherwise icon not available in the desired group's size
+ * will also be selectable.
+ * @param iconSize the size of the icons -- the default of the icongroup
+ * if set to 0
+ * @param user Begin with the "user icons" instead of "system icons".
+ * @param parent The parent widget of the dialog.
+ * @param caption The caption to use for the dialog.
+ * @return The name of the icon, suitable for loading with KIconLoader.
+ * @version New in 3.0
+ */
+ static TQString getIcon(KIcon::Group group=KIcon::Desktop,
+ KIcon::Context context=KIcon::Application,
+ bool strictIconSize=false, int iconSize = 0,
+ bool user=false, TQWidget *parent=0,
+ const TQString &caption=TQString::null);
+
+signals:
+ void newIconName(const TQString&);
+
+protected slots:
+ void slotOk();
+
+private slots:
+ void slotButtonClicked(int);
+ void slotContext(int);
+ void slotStartLoading(int);
+ void slotProgress(int);
+ void slotFinished();
+ void slotAcceptIcons();
+private:
+ void init();
+ void showIcons();
+ void setContext( KIcon::Context context );
+
+ int mGroupOrSize;
+ KIcon::Context mContext;
+ int mType;
+
+ TQStringList mFileList;
+ TQComboBox *mpCombo;
+ TQPushButton *mpBrowseBut;
+ TQRadioButton *mpRb1, *mpRb2;
+ KProgress *mpProgress;
+ KIconLoader *mpLoader;
+ KIconCanvas *mpCanvas;
+ int mNumContext;
+ KIcon::Context mContextMap[ 12 ]; // must match KIcon::Context size, code has assert
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KIconDialogPrivate;
+ KIconDialogPrivate *d;
+};
+
+
+/**
+ * A pushbutton for choosing an icon. Pressing on the button will open a
+ * KIconDialog for the user to select an icon. The current icon will be
+ * displayed on the button.
+ *
+ * @see KIconDialog
+ * @short A push button that allows selection of an icon.
+ */
+class TDEIO_EXPORT KIconButton: public TQPushButton
+{
+ Q_OBJECT
+ TQ_PROPERTY( TQString icon READ icon WRITE setIcon RESET resetIcon )
+ TQ_PROPERTY( int iconSize READ iconSize WRITE setIconSize)
+ TQ_PROPERTY( bool strictIconSize READ strictIconSize WRITE setStrictIconSize )
+
+public:
+ /**
+ * Constructs a KIconButton using the global iconloader.
+ */
+ KIconButton(TQWidget *parent=0L, const char *name=0L);
+
+ /**
+ * Constructs a KIconButton using a specific KIconLoader.
+ */
+ KIconButton(KIconLoader *loader, TQWidget *parent, const char *name=0L);
+ /**
+ * Destructs the button.
+ */
+ ~KIconButton();
+
+ /**
+ * Sets a strict icon size policy for allowed icons. When true,
+ * only icons of the specified group's size in setIconType are allowed,
+ * and only icons of that size will be shown in the icon dialog.
+ */
+ void setStrictIconSize(bool b);
+ /**
+ * Returns true if a strict icon size policy is set.
+ */
+ bool strictIconSize() const;
+
+ /**
+ * Sets the icon group and context. Use KIcon::NoGroup if you want to
+ * allow icons for any group in the given context.
+ */
+ void setIconType(KIcon::Group group, KIcon::Context context, bool user=false);
+
+ /**
+ * Sets the button's initial icon.
+ */
+ void setIcon(const TQString& icon);
+
+ /**
+ * Resets the icon (reverts to an empty button).
+ */
+ void resetIcon();
+
+ /**
+ * Returns the name of the selected icon.
+ */
+ TQString icon() const { return mIcon; }
+
+ /**
+ * Sets the size of the icon to be shown / selected.
+ * @see KIcon::StdSizes
+ * @see iconSize
+ */
+ void setIconSize( int size );
+
+ /**
+ * Returns the iconsize set via setIconSize() or 0, if the default
+ * iconsize will be used.
+ */
+ int iconSize() const;
+
+signals:
+ /**
+ * Emitted when the icon has changed.
+ */
+ void iconChanged(TQString icon);
+ /* KDE 4: Make it const TQString & */
+
+private slots:
+ void slotChangeIcon();
+ void newIconName(const TQString& name);
+
+private:
+ void init( KIconLoader *loader );
+
+ bool mbUser;
+ KIcon::Group mGroup;
+ KIcon::Context mContext;
+
+ TQString mIcon;
+ KIconDialog *mpDialog;
+ KIconLoader *mpLoader;
+ class KIconButtonPrivate;
+ KIconButtonPrivate *d;
+};
+
+
+#endif // __KIconDialog_h__
diff --git a/tdeio/tdefile/kimagefilepreview.cpp b/tdeio/tdefile/kimagefilepreview.cpp
new file mode 100644
index 000000000..f499f4580
--- /dev/null
+++ b/tdeio/tdefile/kimagefilepreview.cpp
@@ -0,0 +1,187 @@
+/*
+ * This file is part of the KDE project
+ * Copyright (C) 2001 Martin R. Jones <mjones@kde.org>
+ * 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <tqlayout.h>
+#include <tqlabel.h>
+#include <tqcombobox.h>
+#include <tqcheckbox.h>
+#include <tqwhatsthis.h>
+#include <tqtimer.h>
+
+#include <kapplication.h>
+#include <tdeconfig.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <tdefiledialog.h>
+#include <tdefileitem.h>
+#include <tdeio/previewjob.h>
+
+#include "kimagefilepreview.h"
+#include "config-tdefile.h"
+
+/**** KImageFilePreview ****/
+
+KImageFilePreview::KImageFilePreview( TQWidget *parent )
+ : KPreviewWidgetBase( parent ),
+ m_job( 0L )
+{
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver cs( config, ConfigGroup );
+ autoMode = config->readBoolEntry( "Automatic Preview", true );
+
+ TQVBoxLayout *vb = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
+
+ imageLabel = new TQLabel( this );
+ imageLabel->setFrameStyle( TQFrame::NoFrame );
+ imageLabel->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
+ imageLabel->setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding) );
+ vb->addWidget( imageLabel );
+
+ TQHBoxLayout *hb = new TQHBoxLayout( 0 );
+ vb->addLayout( hb );
+
+ autoPreview = new TQCheckBox( i18n("&Automatic preview"), this );
+ autoPreview->setChecked( autoMode );
+ hb->addWidget( autoPreview );
+ connect( autoPreview, TQT_SIGNAL(toggled(bool)), TQT_SLOT(toggleAuto(bool)) );
+
+ previewButton = new KPushButton( SmallIconSet("thumbnail"), i18n("&Preview"), this );
+ hb->addWidget( previewButton );
+ connect( previewButton, TQT_SIGNAL(clicked()), TQT_SLOT(showPreview()) );
+
+ timer = new TQTimer( this );
+ connect( timer, TQT_SIGNAL(timeout()), TQT_SLOT(showPreview()) );
+
+ setSupportedMimeTypes( TDEIO::PreviewJob::supportedMimeTypes() );
+}
+
+KImageFilePreview::~KImageFilePreview()
+{
+ if ( m_job )
+ m_job->kill();
+
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver cs( config, ConfigGroup );
+ config->writeEntry( "Automatic Preview", autoPreview->isChecked() );
+}
+
+void KImageFilePreview::showPreview()
+{
+ // Pass a copy since clearPreview() will clear currentURL
+ KURL url = currentURL;
+ showPreview( url, true );
+}
+
+// called via KPreviewWidgetBase interface
+void KImageFilePreview::showPreview( const KURL& url )
+{
+ showPreview( url, false );
+}
+
+void KImageFilePreview::showPreview( const KURL &url, bool force )
+{
+ if ( !url.isValid() ) {
+ clearPreview();
+ return;
+ }
+
+ if ( url != currentURL || force )
+ {
+ clearPreview();
+ currentURL = url;
+
+ if ( autoMode || force )
+ {
+ int w = imageLabel->contentsRect().width() - 4;
+ int h = imageLabel->contentsRect().height() - 4;
+
+ m_job = createJob( url, w, h );
+ if ( force ) // explicitly requested previews shall always be generated!
+ m_job->setIgnoreMaximumSize( true );
+
+ connect( m_job, TQT_SIGNAL( result( TDEIO::Job * )),
+ this, TQT_SLOT( slotResult( TDEIO::Job * )));
+ connect( m_job, TQT_SIGNAL( gotPreview( const KFileItem*,
+ const TQPixmap& )),
+ TQT_SLOT( gotPreview( const KFileItem*, const TQPixmap& ) ));
+
+ connect( m_job, TQT_SIGNAL( failed( const KFileItem* )),
+ this, TQT_SLOT( slotFailed( const KFileItem* ) ));
+ }
+ }
+}
+
+void KImageFilePreview::toggleAuto( bool a )
+{
+ autoMode = a;
+ if ( autoMode )
+ {
+ // Pass a copy since clearPreview() will clear currentURL
+ KURL url = currentURL;
+ showPreview( url, true );
+ }
+}
+
+void KImageFilePreview::resizeEvent( TQResizeEvent * )
+{
+ timer->start( 100, true ); // forces a new preview
+}
+
+TQSize KImageFilePreview::sizeHint() const
+{
+ return TQSize( 20, 200 ); // otherwise it ends up huge???
+}
+
+TDEIO::PreviewJob * KImageFilePreview::createJob( const KURL& url, int w, int h )
+{
+ KURL::List urls;
+ urls.append( url );
+ return TDEIO::filePreview( urls, w, h, 0, 0, true, false );
+}
+
+void KImageFilePreview::gotPreview( const KFileItem* item, const TQPixmap& pm )
+{
+ if ( item->url() == currentURL ) // should always be the case
+ imageLabel->setPixmap( pm );
+}
+
+void KImageFilePreview::slotFailed( const KFileItem* item )
+{
+ if ( item->isDir() )
+ imageLabel->clear();
+ else if ( item->url() == currentURL ) // should always be the case
+ imageLabel->setPixmap( SmallIcon( "file_broken", KIcon::SizeLarge,
+ KIcon::DisabledState ));
+}
+
+void KImageFilePreview::slotResult( TDEIO::Job *job )
+{
+ if ( job == m_job )
+ m_job = 0L;
+}
+
+void KImageFilePreview::clearPreview()
+{
+ if ( m_job ) {
+ m_job->kill();
+ m_job = 0L;
+ }
+
+ imageLabel->clear();
+ currentURL = KURL();
+}
+
+void KImageFilePreview::virtual_hook( int id, void* data )
+{ KPreviewWidgetBase::virtual_hook( id, data ); }
+
+#include "kimagefilepreview.moc"
diff --git a/tdeio/tdefile/kimagefilepreview.h b/tdeio/tdefile/kimagefilepreview.h
new file mode 100644
index 000000000..0604e08f0
--- /dev/null
+++ b/tdeio/tdefile/kimagefilepreview.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * This file is part of the KDE project.
+ * Copyright (C) 2001 Martin R. Jones <mjones@kde.org>
+ * 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef KIMAGEFILEPREVIEW_H
+#define KIMAGEFILEPREVIEW_H
+
+#include <tqpixmap.h>
+
+#include <kurl.h>
+#include <kpreviewwidgetbase.h>
+
+class TQCheckBox;
+class TQPushButton;
+class TQLabel;
+class TQTimer;
+
+class KFileDialog;
+class KFileItem;
+namespace TDEIO { class Job; class PreviewJob; }
+
+/**
+ * Image preview widget for the file dialog.
+ */
+class TDEIO_EXPORT KImageFilePreview : public KPreviewWidgetBase
+{
+ Q_OBJECT
+
+ public:
+ KImageFilePreview(TQWidget *parent);
+ ~KImageFilePreview();
+
+ virtual TQSize sizeHint() const;
+
+ public slots:
+ virtual void showPreview(const KURL &url);
+ virtual void clearPreview();
+
+ protected slots:
+ void showPreview();
+ void showPreview( const KURL& url, bool force );
+
+ void toggleAuto(bool);
+ virtual void gotPreview( const KFileItem*, const TQPixmap& );
+
+ protected:
+ virtual void resizeEvent(TQResizeEvent *e);
+ virtual TDEIO::PreviewJob * createJob( const KURL& url,
+ int w, int h );
+
+ private slots:
+ void slotResult( TDEIO::Job * );
+ virtual void slotFailed( const KFileItem* );
+
+ private:
+ bool autoMode;
+ KURL currentURL;
+ TQTimer *timer;
+ TQLabel *imageLabel;
+ TQLabel *infoLabel;
+ TQCheckBox *autoPreview;
+ TQPushButton *previewButton;
+ TDEIO::PreviewJob *m_job;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class KImageFilePreviewPrivate;
+ KImageFilePreviewPrivate *d;
+};
+
+#endif // KIMAGEFILEPREVIEW_H
diff --git a/tdeio/tdefile/kmetaprops.cpp b/tdeio/tdefile/kmetaprops.cpp
new file mode 100644
index 000000000..ce6201177
--- /dev/null
+++ b/tdeio/tdefile/kmetaprops.cpp
@@ -0,0 +1,268 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ 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.
+
+ $Id$
+ */
+
+#include "kmetaprops.h"
+
+#include <kdebug.h>
+#include <tdefilemetainfowidget.h>
+#include <tdefilemetainfo.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+
+#include <tqvalidator.h>
+#include <tqlayout.h>
+#include <tqlabel.h>
+#include <tqfileinfo.h>
+#include <tqdatetime.h>
+#include <tqstylesheet.h>
+#include <tqvgroupbox.h>
+
+#undef Bool
+
+class MetaPropsScrollView : public TQScrollView
+{
+public:
+ MetaPropsScrollView(TQWidget* parent = 0, const char* name = 0)
+ : TQScrollView(parent, name)
+ {
+ setFrameStyle(TQFrame::NoFrame);
+ m_frame = new TQFrame(viewport(), "MetaPropsScrollView::m_frame");
+ m_frame->setFrameStyle(TQFrame::NoFrame);
+ addChild(m_frame, 0, 0);
+ };
+
+ TQFrame* frame() {return m_frame;};
+
+protected:
+ virtual void viewportResizeEvent(TQResizeEvent* ev)
+ {
+ TQScrollView::viewportResizeEvent(ev);
+ m_frame->resize( kMax(m_frame->sizeHint().width(), ev->size().width()),
+ kMax(m_frame->sizeHint().height(), ev->size().height()));
+ };
+
+private:
+ TQFrame* m_frame;
+};
+
+class KFileMetaPropsPlugin::KFileMetaPropsPluginPrivate
+{
+public:
+ KFileMetaPropsPluginPrivate() {}
+ ~KFileMetaPropsPluginPrivate() {}
+
+ TQFrame* m_frame;
+ TQGridLayout* m_framelayout;
+ KFileMetaInfo m_info;
+// TQPushButton* m_add;
+ TQPtrList<KFileMetaInfoWidget> m_editWidgets;
+};
+
+KFileMetaPropsPlugin::KFileMetaPropsPlugin(KPropertiesDialog* props)
+ : KPropsDlgPlugin(props)
+{
+ d = new KFileMetaPropsPluginPrivate;
+
+ KFileItem * fileitem = properties->item();
+ kdDebug(250) << "KFileMetaPropsPlugin constructor" << endl;
+
+ d->m_info = fileitem->metaInfo();
+ if (!d->m_info.isValid())
+ {
+ d->m_info = KFileMetaInfo(properties->kurl().path(-1));
+ fileitem->setMetaInfo(d->m_info);
+ }
+
+ if ( properties->items().count() > 1 )
+ {
+ // not yet supported
+ // we should allow setting values for a list of files. Itt makes sense
+ // in some cases, like the album of a list of mp3s
+ return;
+ }
+
+ createLayout();
+
+ setDirty(true);
+}
+
+void KFileMetaPropsPlugin::createLayout()
+{
+ TQFileInfo file_info(properties->item()->url().path());
+
+ kdDebug(250) << "KFileMetaPropsPlugin::createLayout" << endl;
+
+ // is there any valid and non-empty info at all?
+ if ( !d->m_info.isValid() || (d->m_info.preferredKeys()).isEmpty() )
+ return;
+
+ // now get a list of groups
+ KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
+ TQStringList groupList = d->m_info.preferredGroups();
+
+ const KFileMimeTypeInfo* mtinfo = prov->mimeTypeInfo(d->m_info.mimeType());
+ if (!mtinfo)
+ {
+ kdDebug(7034) << "no mimetype info there\n";
+ return;
+ }
+
+ // let the dialog create the page frame
+ TQFrame* topframe = properties->addPage(i18n("&Meta Info"));
+ topframe->setFrameStyle(TQFrame::NoFrame);
+ TQVBoxLayout* tmp = new TQVBoxLayout(topframe);
+
+ // create a scroll view in the page
+ MetaPropsScrollView* view = new MetaPropsScrollView(topframe);
+
+ tmp->addWidget(view);
+
+ d->m_frame = view->frame();
+
+ TQVBoxLayout *toplayout = new TQVBoxLayout(d->m_frame);
+ toplayout->setSpacing(KDialog::spacingHint());
+
+ for (TQStringList::Iterator git=groupList.begin();
+ git!=groupList.end(); ++git)
+ {
+ kdDebug(7033) << *git << endl;
+
+ TQStringList itemList = d->m_info.group(*git).preferredKeys();
+ if (itemList.isEmpty())
+ continue;
+
+ TQGroupBox *groupBox = new TQGroupBox(2, Qt::Horizontal,
+ TQStyleSheet::escape(mtinfo->groupInfo(*git)->translatedName()),
+ d->m_frame);
+
+ toplayout->addWidget(groupBox);
+
+ TQValueList<KFileMetaInfoItem> readItems;
+ TQValueList<KFileMetaInfoItem> editItems;
+
+ for (TQStringList::Iterator iit = itemList.begin();
+ iit!=itemList.end(); ++iit)
+ {
+ KFileMetaInfoItem item = d->m_info[*git][*iit];
+ if ( !item.isValid() ) continue;
+
+ bool editable = file_info.isWritable() && item.isEditable();
+
+ if (editable)
+ editItems.append( item );
+ else
+ readItems.append( item );
+ }
+
+ KFileMetaInfoWidget* w = 0L;
+ // then first add the editable items to the layout
+ for (TQValueList<KFileMetaInfoItem>::Iterator iit= editItems.begin();
+ iit!=editItems.end(); ++iit)
+ {
+ TQLabel* l = new TQLabel((*iit).translatedKey() + ":", groupBox);
+ l->setAlignment( AlignAuto | AlignTop | ExpandTabs );
+ TQValidator* val = mtinfo->createValidator(*git, (*iit).key());
+ if (!val) kdDebug(7033) << "didn't get a validator for " << *git << "/" << (*iit).key() << endl;
+ w = new KFileMetaInfoWidget(*iit, val, groupBox);
+ d->m_editWidgets.append( w );
+ connect(w, TQT_SIGNAL(valueChanged(const TQVariant&)), this, TQT_SIGNAL(changed()));
+ }
+
+ // and then the read only items
+ for (TQValueList<KFileMetaInfoItem>::Iterator iit= readItems.begin();
+ iit!=readItems.end(); ++iit)
+ {
+ TQLabel* l = new TQLabel((*iit).translatedKey() + ":", groupBox);
+ l->setAlignment( AlignAuto | AlignTop | ExpandTabs );
+ (new KFileMetaInfoWidget(*iit, KFileMetaInfoWidget::ReadOnly, 0L, groupBox));
+ }
+ }
+
+ toplayout->addStretch(1);
+
+ // the add key (disabled until fully implemented)
+/* d->m_add = new TQPushButton(i18n("&Add"), topframe);
+ d->m_add->setSizePolicy(TQSizePolicy(TQSizePolicy::Fixed,
+ TQSizePolicy::Fixed));
+ connect(d->m_add, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotAdd()));
+ tmp->addWidget(d->m_add);
+
+ // if nothing can be added, deactivate it
+ if ( !d->m_info.supportsVariableKeys() )
+ {
+ // if supportedKeys() does contain anything not in preferredKeys,
+ // we have something addable
+
+ TQStringList sk = d->m_info.supportedKeys();
+ d->m_add->setEnabled(false);
+ for (TQStringList::Iterator it = sk.begin(); it!=sk.end(); ++it)
+ {
+ if ( l.find(*it)==l.end() )
+ {
+ d->m_add->setEnabled(true);
+ kdDebug(250) << "**first addable key is " << (*it).latin1() << "**" <<endl;
+ break;
+ }
+ kdDebug(250) << "**already existing key is " << (*it).latin1() << "**" <<endl;
+ }
+ } */
+}
+
+/*void KFileMetaPropsPlugin::slotAdd()
+{
+ // add a lineedit for the name
+
+
+
+ // insert the item in the list
+
+}*/
+
+KFileMetaPropsPlugin::~KFileMetaPropsPlugin()
+{
+ delete d;
+}
+
+bool KFileMetaPropsPlugin::supports( KFileItemList _items )
+{
+#ifdef _GNUC
+#warning TODO: Add support for more than one item
+#endif
+ if (KExecPropsPlugin::supports(_items) || KURLPropsPlugin::supports(_items))
+ return false; // Having both is redundant.
+
+ bool metaDataEnabled = TDEGlobalSettings::showFilePreview(_items.first()->url());
+ return _items.count() == 1 && metaDataEnabled;
+}
+
+void KFileMetaPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "applying changes" << endl;
+ // insert the fields that changed into the info object
+
+ TQPtrListIterator<KFileMetaInfoWidget> it( d->m_editWidgets );
+ KFileMetaInfoWidget* w;
+ for (; (w = it.current()); ++it) w->apply();
+ d->m_info.applyChanges(properties->kurl().path());
+}
+
+#include "kmetaprops.moc"
diff --git a/tdeio/tdefile/kmetaprops.h b/tdeio/tdefile/kmetaprops.h
new file mode 100644
index 000000000..c842499dd
--- /dev/null
+++ b/tdeio/tdefile/kmetaprops.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ 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 __KMETAPROPS_H__
+#define __KMETAPROPS_H__
+#include <kpropertiesdialog.h>
+
+
+class KFileMetaInfoItem;
+
+/*!
+ * 'MetaProps plugin
+ * In this plugin you can modify meta information like id3 tags of mp3 files
+ */
+class TDEIO_EXPORT KFileMetaPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KFileMetaPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFileMetaPropsPlugin();
+
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the file specified by _items has a 'MetaInfo' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+private:
+ void createLayout();
+
+ TQWidget* makeBoolWidget(const KFileMetaInfoItem& item, TQWidget* parent);
+ TQWidget* makeIntWidget(const KFileMetaInfoItem& item, TQWidget* parent,
+ TQString& valClass);
+ TQWidget* makeStringWidget(const KFileMetaInfoItem& item, TQWidget* parent,
+ TQString& valClass);
+ TQWidget* makeDateTimeWidget(const KFileMetaInfoItem& item, TQWidget* parent,
+ TQString& valClass);
+
+private slots:
+ // Code disabled until the "Add" button is implemented
+// void slotAdd();
+
+private:
+
+ class KFileMetaPropsPluginPrivate;
+ KFileMetaPropsPluginPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/knotifydialog.cpp b/tdeio/tdefile/knotifydialog.cpp
new file mode 100644
index 000000000..a9639ae3d
--- /dev/null
+++ b/tdeio/tdefile/knotifydialog.cpp
@@ -0,0 +1,1191 @@
+/*
+ Copyright (C) 2000,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com>
+
+ This program 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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library, If not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kaudioplayer.h>
+#include <kcombobox.h>
+#include <tdeconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <tdefiledialog.h>
+#include <kiconloader.h>
+#include <kicontheme.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <knotifydialog.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+#include <tdeio/netaccess.h>
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tqheader.h>
+#include <tqlabel.h>
+#include <tqlistview.h>
+#include <tqlayout.h>
+#include <tqptrlist.h>
+#include <tqpushbutton.h>
+#include <tqstring.h>
+#include <tqtooltip.h>
+#include <tqtimer.h>
+#include <tqvbox.h>
+#include <tqwhatsthis.h>
+
+using namespace KNotify;
+
+enum
+{
+ COL_EXECUTE = 0,
+ COL_STDERR = 1,
+ COL_MESSAGE = 2,
+ COL_LOGFILE = 3,
+ COL_SOUND = 4,
+ COL_TASKBAR = 5,
+ COL_EVENT = 6
+};
+
+//
+// I don't feel like subclassing KComboBox and find ways to insert that into
+// the .ui file...
+//
+namespace KNotify
+{
+ class SelectionCombo
+ {
+ public:
+ //
+ // Mind the order in fill() and type()
+ //
+ static void fill( KComboBox *combo )
+ {
+ combo->insertItem( i18n("Sounds") );
+ combo->insertItem( i18n("Logging") );
+ combo->insertItem( i18n("Program Execution") );
+ combo->insertItem( i18n("Message Windows") );
+ combo->insertItem( i18n("Passive Windows") );
+ combo->insertItem( i18n("Standard Error Output") );
+ combo->insertItem( i18n("Taskbar") );
+ }
+
+ static int type( KComboBox *combo )
+ {
+ switch( combo->currentItem() )
+ {
+ case 0:
+ return KNotifyClient::Sound;
+ case 1:
+ return KNotifyClient::Logfile;
+ case 2:
+ return KNotifyClient::Execute;
+ case 3:
+ return KNotifyClient::Messagebox;
+ case 4:
+ return KNotifyClient::PassivePopup;
+ case 5:
+ return KNotifyClient::Stderr;
+ case 6:
+ return KNotifyClient::Taskbar;
+ }
+
+ return KNotifyClient::None;
+ }
+ };
+
+ // Needed for displaying tooltips in the listview's QHeader
+ class KNotifyToolTip : public TQToolTip
+ {
+ public:
+ KNotifyToolTip( TQHeader *header )
+ : TQToolTip( header )
+ {
+ m_tips[COL_EXECUTE] = i18n("Execute a program");
+ m_tips[COL_STDERR] = i18n("Print to Standard error output");
+ m_tips[COL_MESSAGE] = i18n("Display a messagebox");
+ m_tips[COL_LOGFILE] = i18n("Log to a file");
+ m_tips[COL_SOUND] = i18n("Play a sound");
+ m_tips[COL_TASKBAR] = i18n("Flash the taskbar entry");
+ }
+ virtual ~KNotifyToolTip() {}
+
+ protected:
+ virtual void maybeTip ( const TQPoint& p )
+ {
+ TQHeader *header = static_cast<TQHeader*>( parentWidget() );
+ int section = 0;
+
+ if ( header->orientation() == Qt::Horizontal )
+ section= header->sectionAt( p.x() );
+ else
+ section= header->sectionAt( p.y() );
+
+ if ( ( section < 0 ) || ( static_cast<uint>( section ) >= (sizeof(m_tips) / sizeof(TQString)) ) )
+ return;
+
+ tip( header->sectionRect( section ), m_tips[section] );
+ }
+
+ private:
+ TQString m_tips[6];
+ };
+
+}
+
+
+int KNotifyDialog::configure( TQWidget *parent, const char *name,
+ const TDEAboutData *aboutData )
+{
+ KNotifyDialog dialog( parent, name, true, aboutData );
+ return dialog.exec();
+}
+
+KNotifyDialog::KNotifyDialog( TQWidget *parent, const char *name, bool modal,
+ const TDEAboutData *aboutData )
+ : KDialogBase(parent, name, modal, i18n("Notification Settings"),
+ Ok | Apply | Cancel | Default, Ok, true )
+{
+ TQVBox *box = makeVBoxMainWidget();
+
+ m_notifyWidget = new KNotifyWidget( box, "knotify widget" );
+
+ if ( aboutData )
+ addApplicationEvents( aboutData->appName() );
+
+ connect( this, TQT_SIGNAL( okClicked() ), m_notifyWidget, TQT_SLOT( save() ));
+ connect( this, TQT_SIGNAL( applyClicked() ), m_notifyWidget, TQT_SLOT( save() ));
+}
+
+KNotifyDialog::~KNotifyDialog()
+{
+}
+
+void KNotifyDialog::addApplicationEvents( const char *appName )
+{
+ addApplicationEvents( TQString::fromUtf8( appName ) +
+ TQString::fromLatin1( "/eventsrc" ) );
+}
+
+void KNotifyDialog::addApplicationEvents( const TQString& path )
+{
+ Application *app = m_notifyWidget->addApplicationEvents( path );
+ if ( app )
+ {
+ m_notifyWidget->addVisibleApp( app );
+ m_notifyWidget->sort();
+ }
+}
+
+void KNotifyDialog::clearApplicationEvents()
+{
+ m_notifyWidget->clear();
+}
+
+void KNotifyDialog::slotDefault()
+{
+ m_notifyWidget->resetDefaults( true ); // ask user
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+class KNotifyWidget::Private
+{
+public:
+ TQPixmap pixmaps[6];
+ KNotifyToolTip *toolTip;
+};
+
+// simple access to all knotify-handled applications
+KNotifyWidget::KNotifyWidget( TQWidget *parent, const char *name,
+ bool handleAllApps )
+ : KNotifyWidgetBase( parent, name ? name : "KNotifyWidget" )
+{
+ d = new Private;
+
+ m_allApps.setAutoDelete( true );
+
+ if ( !handleAllApps )
+ {
+ m_affectAllApps->hide();
+ m_playerButton->hide();
+ }
+
+ SelectionCombo::fill( m_comboEnable );
+ SelectionCombo::fill( m_comboDisable );
+
+ m_listview->setFullWidth( true );
+ m_listview->setAllColumnsShowFocus( true );
+
+ TQPixmap pexec = SmallIcon("exec");
+ TQPixmap pstderr = SmallIcon("terminal");
+ TQPixmap pmessage = SmallIcon("info");
+ TQPixmap plogfile = SmallIcon("log");
+ TQPixmap psound = SmallIcon("sound");
+ TQPixmap ptaskbar = SmallIcon("kicker");
+
+ d->pixmaps[COL_EXECUTE] = pexec;
+ d->pixmaps[COL_STDERR] = pstderr;
+ d->pixmaps[COL_MESSAGE] = pmessage;
+ d->pixmaps[COL_LOGFILE] = plogfile;
+ d->pixmaps[COL_SOUND] = psound;
+ d->pixmaps[COL_TASKBAR] = ptaskbar;
+
+ int w = KIcon::SizeSmall + 6;
+
+ TQHeader *header = m_listview->header();
+ header->setLabel( COL_EXECUTE, pexec, TQString::null, w );
+ header->setLabel( COL_STDERR, pstderr, TQString::null, w );
+ header->setLabel( COL_MESSAGE, pmessage, TQString::null, w );
+ header->setLabel( COL_LOGFILE, plogfile, TQString::null, w );
+ header->setLabel( COL_SOUND, psound, TQString::null, w );
+ header->setLabel( COL_TASKBAR, ptaskbar, TQString::null, w );
+
+ d->toolTip = new KNotifyToolTip( header );
+
+ m_playButton->setIconSet( SmallIconSet( "player_play" ) );
+ connect( m_playButton, TQT_SIGNAL( clicked() ), TQT_SLOT( playSound() ));
+
+ connect( m_listview, TQT_SIGNAL( currentChanged( TQListViewItem * ) ),
+ TQT_SLOT( slotEventChanged( TQListViewItem * ) ));
+ connect( m_listview, TQT_SIGNAL(clicked( TQListViewItem *, const TQPoint&, int)),
+ TQT_SLOT( slotItemClicked( TQListViewItem *, const TQPoint&, int )));
+
+ connect( m_playSound, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( soundToggled( bool )) );
+ connect( m_logToFile, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( loggingToggled( bool )) );
+ connect( m_execute, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( executeToggled( bool )) );
+ connect( m_messageBox, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( messageBoxChanged() ) );
+ connect( m_passivePopup, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( messageBoxChanged() ) );
+ connect( m_stderr, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( stderrToggled( bool ) ) );
+ connect( m_taskbar, TQT_SIGNAL( toggled( bool )),
+ TQT_SLOT( taskbarToggled( bool ) ) );
+
+ connect( m_soundPath, TQT_SIGNAL( textChanged( const TQString& )),
+ TQT_SLOT( soundFileChanged( const TQString& )));
+ connect( m_logfilePath, TQT_SIGNAL( textChanged( const TQString& )),
+ TQT_SLOT( logfileChanged( const TQString& ) ));
+ connect( m_executePath, TQT_SIGNAL( textChanged( const TQString& )),
+ TQT_SLOT( commandlineChanged( const TQString& ) ));
+
+ connect( m_soundPath, TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ TQT_SLOT( openSoundDialog( KURLRequester * )));
+ connect( m_logfilePath, TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ TQT_SLOT( openLogDialog( KURLRequester * )));
+ connect( m_executePath, TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ TQT_SLOT( openExecDialog( KURLRequester * )));
+
+ connect( m_extension, TQT_SIGNAL( clicked() ),
+ TQT_SLOT( toggleAdvanced()) );
+
+ connect( m_buttonEnable, TQT_SIGNAL( clicked() ), TQT_SLOT( enableAll() ));
+ connect( m_buttonDisable, TQT_SIGNAL( clicked() ), TQT_SLOT( enableAll() ));
+
+ TQString whatsThis = i18n("<qt>You may use the following macros<br>"
+ "in the commandline:<br>"
+ "<b>%e</b>: for the event name,<br>"
+ "<b>%a</b>: for the name of the application that sent the event,<br>"
+ "<b>%s</b>: for the notification message,<br>"
+ "<b>%w</b>: for the numeric window ID where the event originated,<br>"
+ "<b>%i</b>: for the numeric event ID.");
+ TQWhatsThis::add( m_execute, whatsThis );
+ TQWhatsThis::add( m_executePath, whatsThis );
+
+ showAdvanced( false );
+
+ slotEventChanged( 0L ); // disable widgets by default
+}
+
+KNotifyWidget::~KNotifyWidget()
+{
+ delete d->toolTip;
+ delete d;
+}
+
+void KNotifyWidget::toggleAdvanced()
+{
+ showAdvanced( m_logToFile->isHidden() );
+}
+
+void KNotifyWidget::showAdvanced( bool show )
+{
+ if ( show )
+ {
+ m_extension->setText( i18n("Advanced <<") );
+ TQToolTip::add( m_extension, i18n("Hide advanced options") );
+
+ m_logToFile->show();
+ m_logfilePath->show();
+ m_execute->show();
+ m_executePath->show();
+ m_messageBox->show();
+ m_passivePopup->show();
+ m_stderr->show();
+ m_taskbar->show();
+
+ m_passivePopup->setEnabled( m_messageBox->isChecked() );
+ m_actionsBoxLayout->setSpacing( KDialog::spacingHint() );
+ }
+ else
+ {
+ m_extension->setText( i18n("Advanced >>") );
+ TQToolTip::add( m_extension, i18n("Show advanced options") );
+
+ m_logToFile->hide();
+ m_logfilePath->hide();
+ m_execute->hide();
+ m_executePath->hide();
+ m_messageBox->hide();
+ m_passivePopup->hide();
+ m_stderr->hide();
+ m_taskbar->hide();
+
+ m_actionsBoxLayout->setSpacing( 0 );
+ }
+}
+
+Application * KNotifyWidget::addApplicationEvents( const TQString& path )
+{
+ kdDebug() << "**** knotify: adding path: " << path << endl;
+ TQString relativePath = path;
+
+ if ( path.at(0) == '/' && KStandardDirs::exists( path ) )
+ relativePath = makeRelative( path );
+
+ if ( !relativePath.isEmpty() )
+ {
+ Application *app = new Application( relativePath );
+ m_allApps.append( app );
+ return app;
+ }
+
+ return 0L;
+}
+
+void KNotifyWidget::clear()
+{
+ clearVisible();
+ m_allApps.clear();
+}
+
+void KNotifyWidget::clearVisible()
+{
+ m_visibleApps.clear();
+ m_listview->clear();
+ slotEventChanged( 0L ); // disable widgets
+}
+
+void KNotifyWidget::showEvent( TQShowEvent *e )
+{
+ selectItem( m_listview->firstChild() );
+ KNotifyWidgetBase::showEvent( e );
+}
+
+void KNotifyWidget::slotEventChanged( TQListViewItem *item )
+{
+ bool on = (item != 0L);
+
+ m_actionsBox->setEnabled( on );
+ m_controlsBox->setEnabled( on );
+
+ if ( !on )
+ return;
+
+ ListViewItem *lit = static_cast<ListViewItem*>( item );
+ updateWidgets( lit );
+}
+
+void KNotifyWidget::updateWidgets( ListViewItem *item )
+{
+ bool enable;
+ bool checked;
+
+ blockSignals( true ); // don't emit changed() signals
+
+ const Event& event = item->event();
+
+ // sound settings
+ m_playButton->setEnabled( !event.soundfile.isEmpty() );
+ m_soundPath->setURL( event.soundfile );
+ enable = (event.dontShow & KNotifyClient::Sound) == 0;
+ checked = enable && !event.soundfile.isEmpty() &&
+ (event.presentation & KNotifyClient::Sound);
+ m_playSound->setEnabled( enable );
+ m_playSound->setChecked( checked );
+ m_soundPath->setEnabled( checked );
+
+
+ // logfile settings
+ m_logfilePath->setURL( event.logfile );
+ enable = (event.dontShow & KNotifyClient::Logfile) == 0;
+ checked = enable && !event.logfile.isEmpty() &&
+ (event.presentation & KNotifyClient::Logfile);
+ m_logToFile->setEnabled( enable );
+ m_logToFile->setChecked( checked );
+ m_logfilePath->setEnabled( checked );
+
+
+ // execute program settings
+ m_executePath->setURL( event.commandline );
+ enable = (event.dontShow & KNotifyClient::Execute) == 0;
+ checked = enable && !event.commandline.isEmpty() &&
+ (event.presentation & KNotifyClient::Execute);
+ m_execute->setEnabled( enable );
+ m_execute->setChecked( checked );
+ m_executePath->setEnabled( checked );
+
+
+ // other settings
+ m_messageBox->setChecked(event.presentation & (KNotifyClient::Messagebox | KNotifyClient::PassivePopup));
+ enable = (event.dontShow & KNotifyClient::Messagebox) == 0;
+ m_messageBox->setEnabled( enable );
+
+ m_passivePopup->setChecked(event.presentation & KNotifyClient::PassivePopup);
+ enable = (event.dontShow & KNotifyClient::PassivePopup) == 0;
+ m_passivePopup->setEnabled( enable );
+
+ m_stderr->setChecked( event.presentation & KNotifyClient::Stderr );
+ enable = (event.dontShow & KNotifyClient::Stderr) == 0;
+ m_stderr->setEnabled( enable );
+
+ m_taskbar->setChecked(event.presentation & KNotifyClient::Taskbar);
+ enable = (event.dontShow & KNotifyClient::Taskbar) == 0;
+ m_taskbar->setEnabled( enable );
+
+ updatePixmaps( item );
+
+ blockSignals( false );
+}
+
+void KNotifyWidget::updatePixmaps( ListViewItem *item )
+{
+ TQPixmap emptyPix;
+ Event &event = item->event();
+
+ bool doIt = (event.presentation & KNotifyClient::Execute) &&
+ !event.commandline.isEmpty();
+ item->setPixmap( COL_EXECUTE, doIt ? d->pixmaps[COL_EXECUTE] : emptyPix );
+
+ doIt = (event.presentation & KNotifyClient::Sound) &&
+ !event.soundfile.isEmpty();
+ item->setPixmap( COL_SOUND, doIt ? d->pixmaps[COL_SOUND] : emptyPix );
+
+ doIt = (event.presentation & KNotifyClient::Logfile) &&
+ !event.logfile.isEmpty();
+ item->setPixmap( COL_LOGFILE, doIt ? d->pixmaps[COL_LOGFILE] : emptyPix );
+
+ item->setPixmap( COL_MESSAGE,
+ (event.presentation &
+ (KNotifyClient::Messagebox | KNotifyClient::PassivePopup)) ?
+ d->pixmaps[COL_MESSAGE] : emptyPix );
+
+ item->setPixmap( COL_STDERR,
+ (event.presentation & KNotifyClient::Stderr) ?
+ d->pixmaps[COL_STDERR] : emptyPix );
+ item->setPixmap( COL_TASKBAR,
+ (event.presentation & KNotifyClient::Taskbar) ?
+ d->pixmaps[COL_TASKBAR] : emptyPix );
+}
+
+void KNotifyWidget::addVisibleApp( Application *app )
+{
+ if ( !app || (m_visibleApps.findRef( app ) != -1) )
+ return;
+
+ m_visibleApps.append( app );
+ addToView( app->eventList() );
+
+ TQListViewItem *item = m_listview->selectedItem();
+ if ( !item )
+ item = m_listview->firstChild();
+
+ selectItem( item );
+}
+
+void KNotifyWidget::addToView( const EventList& events )
+{
+ ListViewItem *item = 0L;
+
+ EventListIterator it( events );
+
+ for ( ; it.current(); ++it )
+ {
+ Event *event = it.current();
+ item = new ListViewItem( m_listview, event );
+
+ if ( (event->presentation & KNotifyClient::Execute) &&
+ !event->commandline.isEmpty() )
+ item->setPixmap( COL_EXECUTE, d->pixmaps[COL_EXECUTE] );
+ if ( (event->presentation & KNotifyClient::Sound) &&
+ !event->soundfile.isEmpty() )
+ item->setPixmap( COL_SOUND, d->pixmaps[COL_SOUND] );
+ if ( (event->presentation & KNotifyClient::Logfile) &&
+ !event->logfile.isEmpty() )
+ item->setPixmap( COL_LOGFILE, d->pixmaps[COL_LOGFILE] );
+ if ( event->presentation & (KNotifyClient::Messagebox|KNotifyClient::PassivePopup) )
+ item->setPixmap( COL_MESSAGE, d->pixmaps[COL_MESSAGE] );
+ if ( event->presentation & KNotifyClient::Stderr )
+ item->setPixmap( COL_STDERR, d->pixmaps[COL_STDERR] );
+ if ( event->presentation & KNotifyClient::Taskbar )
+ item->setPixmap( COL_TASKBAR, d->pixmaps[COL_TASKBAR] );
+ }
+}
+
+void KNotifyWidget::widgetChanged( TQListViewItem *item,
+ int what, bool on, TQWidget *buddy )
+{
+ if ( signalsBlocked() )
+ return;
+
+ if ( buddy )
+ buddy->setEnabled( on );
+
+ Event &e = static_cast<ListViewItem*>( item )->event();
+ if ( on )
+ {
+ e.presentation |= what;
+ if ( buddy )
+ buddy->setFocus();
+ }
+ else
+ e.presentation &= ~what;
+
+ emit changed( true );
+}
+
+void KNotifyWidget::soundToggled( bool on )
+{
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_soundPath->url().isEmpty();
+ item->setPixmap( COL_SOUND, doIcon ? d->pixmaps[COL_SOUND] : TQPixmap() );
+ widgetChanged( item, KNotifyClient::Sound, on, m_soundPath );
+}
+
+void KNotifyWidget::loggingToggled( bool on )
+{
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_logfilePath->url().isEmpty();
+ item->setPixmap(COL_LOGFILE, doIcon ? d->pixmaps[COL_LOGFILE] : TQPixmap());
+ widgetChanged( item, KNotifyClient::Logfile, on, m_logfilePath );
+}
+
+void KNotifyWidget::executeToggled( bool on )
+{
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ bool doIcon = on && !m_executePath->url().isEmpty();
+ item->setPixmap(COL_EXECUTE, doIcon ? d->pixmaps[COL_EXECUTE] : TQPixmap());
+ widgetChanged( item, KNotifyClient::Execute, on, m_executePath );
+}
+
+void KNotifyWidget::messageBoxChanged()
+{
+ if ( signalsBlocked() )
+ return;
+
+ m_passivePopup->setEnabled( m_messageBox->isChecked() );
+
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ bool on = m_passivePopup->isEnabled();
+ item->setPixmap( COL_MESSAGE, on ? d->pixmaps[COL_MESSAGE] : TQPixmap() );
+
+ Event &e = static_cast<ListViewItem*>( item )->event();
+
+ if ( m_messageBox->isChecked() ) {
+ if ( m_passivePopup->isChecked() ) {
+ e.presentation |= KNotifyClient::PassivePopup;
+ e.presentation &= ~KNotifyClient::Messagebox;
+ }
+ else {
+ e.presentation &= ~KNotifyClient::PassivePopup;
+ e.presentation |= KNotifyClient::Messagebox;
+ }
+ }
+ else {
+ e.presentation &= ~KNotifyClient::Messagebox;
+ e.presentation &= ~KNotifyClient::PassivePopup;
+ }
+
+ emit changed( true );
+}
+
+void KNotifyWidget::stderrToggled( bool on )
+{
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ item->setPixmap( COL_STDERR, on ? d->pixmaps[COL_STDERR] : TQPixmap() );
+ widgetChanged( item, KNotifyClient::Stderr, on );
+}
+
+void KNotifyWidget::taskbarToggled( bool on )
+{
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+ item->setPixmap( COL_TASKBAR, on ? d->pixmaps[COL_TASKBAR] : TQPixmap() );
+ widgetChanged( item, KNotifyClient::Taskbar, on );
+}
+
+void KNotifyWidget::soundFileChanged( const TQString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ m_playButton->setEnabled( !text.isEmpty() );
+
+ currentEvent()->soundfile = text;
+ bool ok = !text.isEmpty() && m_playSound->isChecked();
+ item->setPixmap( COL_SOUND, ok ? d->pixmaps[COL_SOUND] : TQPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::logfileChanged( const TQString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ currentEvent()->logfile = text;
+ bool ok = !text.isEmpty() && m_logToFile->isChecked();
+ item->setPixmap( COL_LOGFILE, ok ? d->pixmaps[COL_LOGFILE] : TQPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::commandlineChanged( const TQString& text )
+{
+ if ( signalsBlocked() )
+ return;
+
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ return;
+
+ currentEvent()->commandline = text;
+ bool ok = !text.isEmpty() && m_execute->isChecked();
+ item->setPixmap( COL_EXECUTE, ok ? d->pixmaps[COL_EXECUTE] : TQPixmap() );
+
+ emit changed( true );
+}
+
+void KNotifyWidget::slotItemClicked( TQListViewItem *item, const TQPoint&,
+ int col )
+{
+ if ( !item || !item->isSelected() )
+ return;
+
+ Event *event = currentEvent();
+ if ( !event )
+ return; // very unlikely, but safety first
+
+ bool doShowAdvanced = false;
+
+ switch( col )
+ {
+ case COL_EXECUTE:
+ m_execute->toggle();
+ m_executePath->setFocus();
+ doShowAdvanced = true;
+ break;
+ case COL_STDERR:
+ m_stderr->toggle();
+ break;
+ case COL_TASKBAR:
+ m_taskbar->toggle();
+ break;
+ case COL_MESSAGE:
+ m_passivePopup->setChecked( true ); // default to passive popups
+ m_messageBox->toggle();
+ break;
+ case COL_LOGFILE:
+ m_logToFile->toggle();
+ m_logfilePath->setFocus();
+ doShowAdvanced = true;
+ break;
+ case COL_SOUND:
+ m_playSound->toggle();
+ break;
+ default: // do nothing
+ break;
+ }
+
+ if ( doShowAdvanced && !m_logToFile->isVisible() )
+ {
+ showAdvanced( true );
+ m_listview->ensureItemVisible( m_listview->currentItem() );
+ }
+}
+
+void KNotifyWidget::sort( bool ascending )
+{
+ m_listview->setSorting( COL_EVENT, ascending );
+ m_listview->sort();
+}
+
+void KNotifyWidget::selectItem( TQListViewItem *item )
+{
+ if ( item )
+ {
+ m_listview->setCurrentItem( item );
+ item->setSelected( true );
+ slotEventChanged( item );
+ }
+}
+
+void KNotifyWidget::resetDefaults( bool ask )
+{
+ if ( ask )
+ {
+ if ( KMessageBox::warningContinueCancel(this,
+ i18n("This will cause the notifications "
+ "to be reset to their defaults."),
+ i18n("Are You Sure?"),
+ i18n("&Reset"))
+ != KMessageBox::Continue)
+ return;
+ }
+
+ reload( true ); // defaults
+ emit changed( true );
+}
+
+void KNotifyWidget::reload( bool revertToDefaults )
+{
+ m_listview->clear();
+ ApplicationListIterator it( m_visibleApps );
+ for ( ; it.current(); ++it )
+ {
+ it.current()->reloadEvents( revertToDefaults );
+ addToView( it.current()->eventList() );
+ }
+
+ m_listview->sort();
+ selectItem( m_listview->firstChild() );
+}
+
+void KNotifyWidget::save()
+{
+ kdDebug() << "save\n";
+
+ ApplicationListIterator it( m_allApps );
+ while ( it.current() )
+ {
+ (*it)->save();
+ ++it;
+ }
+
+ if ( kapp )
+ {
+ if ( !kapp->dcopClient()->isAttached() )
+ kapp->dcopClient()->attach();
+ kapp->dcopClient()->send("knotify", "", "reconfigure()", TQString(""));
+ }
+
+ emit changed( false );
+}
+
+// returns e.g. "twin/eventsrc" from a given path
+// "/opt/trinity/share/apps/twin/eventsrc"
+TQString KNotifyWidget::makeRelative( const TQString& fullPath )
+{
+ int slash = fullPath.findRev( '/' ) - 1;
+ slash = fullPath.findRev( '/', slash );
+
+ if ( slash < 0 )
+ return TQString::null;
+
+ return fullPath.mid( slash+1 );
+}
+
+Event * KNotifyWidget::currentEvent()
+{
+ TQListViewItem *current = m_listview->currentItem();
+ if ( !current )
+ return 0L;
+
+ return &static_cast<ListViewItem*>( current )->event();
+}
+
+void KNotifyWidget::openSoundDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ this, TQT_SLOT( openSoundDialog( KURLRequester * )));
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select Sound File") );
+ TQStringList filters;
+ filters << "audio/x-wav" << "audio/x-mp3" << "application/ogg"
+ << "audio/x-adpcm";
+ fileDialog->setMimeFilter( filters );
+
+ // find the first "sound"-resource that contains files
+ const Application *app = currentEvent()->application();
+ TQStringList soundDirs =
+ TDEGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
+ soundDirs += TDEGlobal::dirs()->resourceDirs( "sound" );
+
+ if ( !soundDirs.isEmpty() ) {
+ KURL soundURL;
+ TQDir dir;
+ dir.setFilter( TQDir::Files | TQDir::Readable );
+ TQStringList::ConstIterator it = soundDirs.begin();
+ while ( it != soundDirs.end() ) {
+ dir = *it;
+ if ( dir.isReadable() && dir.count() > 2 ) {
+ soundURL.setPath( *it );
+ fileDialog->setURL( soundURL );
+ break;
+ }
+ ++it;
+ }
+ }
+}
+
+void KNotifyWidget::openLogDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ this, TQT_SLOT( openLogDialog( KURLRequester * )));
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select Log File") );
+ TQStringList filters;
+ filters << "text/x-log" << "text/plain";
+ fileDialog->setMimeFilter( filters );
+}
+
+void KNotifyWidget::openExecDialog( KURLRequester *requester )
+{
+ // only need to init this once
+ requester->disconnect( TQT_SIGNAL( openFileDialog( KURLRequester * )),
+ this, TQT_SLOT( openExecDialog( KURLRequester * )));
+
+
+ KFileDialog *fileDialog = requester->fileDialog();
+ fileDialog->setCaption( i18n("Select File to Execute") );
+ TQStringList filters;
+ filters << "application/x-executable" << "application/x-shellscript"
+ << "application/x-perl" << "application/x-python";
+ fileDialog->setMimeFilter( filters );
+}
+
+void KNotifyWidget::playSound()
+{
+ TQString soundPath = m_soundPath->url();
+ if (!TDEIO::NetAccess::exists( m_soundPath->url(), true, 0 )) {
+ bool foundSound=false;
+
+ // find the first "sound"-resource that contains files
+ const Application *app = currentEvent()->application();
+ TQStringList soundDirs = TDEGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
+ soundDirs += TDEGlobal::dirs()->resourceDirs( "sound" );
+
+ if ( !soundDirs.isEmpty() ) {
+ TQDir dir;
+ dir.setFilter( TQDir::Files | TQDir::Readable );
+ TQStringList::ConstIterator it = soundDirs.begin();
+ while ( it != soundDirs.end() ) {
+ dir = *it;
+ if ( dir.isReadable() && dir.count() > 2 &&
+ TDEIO::NetAccess::exists( *it + m_soundPath->url(), true, 0 )) {
+ foundSound=true;
+ soundPath = *it + m_soundPath->url();
+ break;
+ }
+ ++it;
+ }
+ }
+ if ( !foundSound ) {
+ KMessageBox::sorry(this, i18n("The specified file does not exist." ));
+ return;
+ }
+ }
+ KAudioPlayer::play( soundPath );
+}
+
+void KNotifyWidget::enableAll()
+{
+ bool enable = (sender() == m_buttonEnable);
+ enableAll( SelectionCombo::type(enable ? m_comboEnable : m_comboDisable),
+ enable );
+}
+
+void KNotifyWidget::enableAll( int what, bool enable )
+{
+ if ( m_listview->childCount() == 0 )
+ return;
+
+ bool affectAll = m_affectAllApps->isChecked(); // multi-apps mode
+
+ ApplicationListIterator appIt( affectAll ? m_allApps : m_visibleApps );
+ for ( ; appIt.current(); ++appIt )
+ {
+ const EventList& events = appIt.current()->eventList();
+ EventListIterator it( events );
+ for ( ; it.current(); ++it )
+ {
+ if ( enable )
+ it.current()->presentation |= what;
+ else
+ it.current()->presentation &= ~what;
+ }
+ }
+
+ // now make the listview reflect the changes
+ TQListViewItemIterator it( m_listview->firstChild() );
+ for ( ; it.current(); ++it )
+ {
+ ListViewItem *item = static_cast<ListViewItem*>( it.current() );
+ updatePixmaps( item );
+ }
+
+ TQListViewItem *item = m_listview->currentItem();
+ if ( !item )
+ item = m_listview->firstChild();
+ selectItem( item );
+
+ emit changed( true );
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+//
+// path must be "appname/eventsrc", i.e. a relative path
+//
+Application::Application( const TQString &path )
+{
+ TQString config_file = path;
+ config_file[config_file.find('/')] = '.';
+ m_events = 0L;
+ config = new TDEConfig(config_file, false, false);
+ kc = new TDEConfig(path, true, false, "data");
+ kc->setGroup( TQString::fromLatin1("!Global!") );
+ m_icon = kc->readEntry(TQString::fromLatin1("IconName"),
+ TQString::fromLatin1("misc"));
+ m_description = kc->readEntry( TQString::fromLatin1("Comment"),
+ i18n("No description available") );
+
+ int index = path.find( '/' );
+ if ( index >= 0 )
+ m_appname = path.left( index );
+ else
+ kdDebug() << "Cannot determine application name from path: " << path << endl;
+}
+
+Application::~Application()
+{
+ delete config;
+ delete kc;
+ delete m_events;
+}
+
+
+const EventList& Application::eventList()
+{
+ if ( !m_events ) {
+ m_events = new EventList;
+ m_events->setAutoDelete( true );
+ reloadEvents();
+ }
+
+ return *m_events;
+}
+
+
+void Application::save()
+{
+ if ( !m_events )
+ return;
+
+ EventListIterator it( *m_events );
+ Event *e;
+ while ( (e = it.current()) ) {
+ config->setGroup( e->configGroup );
+ config->writeEntry( "presentation", e->presentation );
+ config->writePathEntry( "soundfile", e->soundfile );
+ config->writePathEntry( "logfile", e->logfile );
+ config->writePathEntry( "commandline", e->commandline );
+
+ ++it;
+ }
+ config->sync();
+}
+
+
+void Application::reloadEvents( bool revertToDefaults )
+{
+ if ( m_events )
+ m_events->clear();
+ else
+ {
+ m_events = new EventList;
+ m_events->setAutoDelete( true );
+ }
+
+ Event *e = 0L;
+
+ TQString global = TQString::fromLatin1("!Global!");
+ TQString default_group = TQString::fromLatin1("<default>");
+ TQString name = TQString::fromLatin1("Name");
+ TQString comment = TQString::fromLatin1("Comment");
+
+ TQStringList conflist = kc->groupList();
+ TQStringList::ConstIterator it = conflist.begin();
+
+ while ( it != conflist.end() ) {
+ if ( (*it) != global && (*it) != default_group ) { // event group
+ kc->setGroup( *it );
+
+ e = new Event( this );
+ e->name = kc->readEntry( name );
+ e->description = kc->readEntry( comment );
+ e->dontShow = kc->readNumEntry("nopresentation", 0 );
+ e->configGroup = *it;
+ if ( e->name.isEmpty() && e->description.isEmpty() )
+ delete e;
+ else { // load the event
+ if( !e->name.isEmpty() && e->description.isEmpty() )
+ e->description = e->name;
+ // default to passive popups over plain messageboxes
+ int default_rep = kc->readNumEntry("default_presentation",
+ 0 | KNotifyClient::PassivePopup);
+ TQString default_logfile = kc->readPathEntry("default_logfile");
+ TQString default_soundfile = kc->readPathEntry("default_sound");
+ TQString default_commandline = kc->readPathEntry("default_commandline");
+
+ config->setGroup(*it);
+
+ if ( revertToDefaults )
+ {
+ e->presentation = default_rep;
+ e->logfile = default_logfile;
+ e->soundfile = default_soundfile;
+ e->commandline = default_commandline;
+ }
+
+ else
+ {
+ e->presentation = config->readNumEntry("presentation",
+ default_rep);
+ e->logfile = config->readPathEntry("logfile",
+ default_logfile);
+ e->soundfile = config->readPathEntry("soundfile",
+ default_soundfile);
+ e->commandline = config->readPathEntry("commandline",
+ default_commandline);
+ }
+
+ m_events->append( e );
+ }
+ }
+
+ ++it;
+ }
+
+ return;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ListViewItem::ListViewItem( TQListView *view, Event *event )
+ : TQListViewItem( view ),
+ m_event( event )
+{
+ setText( COL_EVENT, event->text() );
+}
+
+int ListViewItem::compare ( TQListViewItem * i, int col, bool ascending ) const
+{
+ ListViewItem *item = static_cast<ListViewItem*>( i );
+ int myPres = m_event->presentation;
+ int otherPres = item->event().presentation;
+
+ int action = 0;
+
+ switch ( col )
+ {
+ case COL_EVENT: // use default sorting
+ return TQListViewItem::compare( i, col, ascending );
+
+ case COL_EXECUTE:
+ action = KNotifyClient::Execute;
+ break;
+ case COL_LOGFILE:
+ action = KNotifyClient::Logfile;
+ break;
+ case COL_MESSAGE:
+ action = (KNotifyClient::Messagebox | KNotifyClient::PassivePopup);
+ break;
+ case COL_SOUND:
+ action = KNotifyClient::Sound;
+ break;
+ case COL_STDERR:
+ action = KNotifyClient::Stderr;
+ break;
+ case COL_TASKBAR:
+ action = KNotifyClient::Taskbar;
+ break;
+ }
+
+ if ( (myPres & action) == (otherPres & action) )
+ {
+ // default sorting by event
+ return TQListViewItem::compare( i, COL_EVENT, true );
+ }
+
+ if ( myPres & action )
+ return -1;
+ if ( otherPres & action )
+ return 1;
+
+ return 0;
+}
+
+#include "knotifydialog.moc"
diff --git a/tdeio/tdefile/knotifydialog.h b/tdeio/tdefile/knotifydialog.h
new file mode 100644
index 000000000..9bb3210ea
--- /dev/null
+++ b/tdeio/tdefile/knotifydialog.h
@@ -0,0 +1,341 @@
+/*
+ Copyright (C) 2000,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com>
+
+ This program 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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library, If not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KNOTIFYDIALOG_H
+#define KNOTIFYDIALOG_H
+
+#include <klistview.h>
+#include <kdialogbase.h>
+#include <kinstance.h>
+#include <kglobal.h>
+
+#include "knotifywidgetbase.h"
+
+class TQShowEvent;
+
+namespace KNotify
+{
+ class KNotifyWidget;
+}
+
+/**
+ * KNotifyDialog presents an interface for configuring an application's
+ * KNotify events.
+ *
+ * Rather than requiring the user to wade through the entire list of
+ * applications' events in KControl, your application can make the list
+ * of its own notifications available here.
+ *
+ * Typical usage is calling the static configure() method:
+ * \code
+ * (void) KNotifyDialog::configure( someParentWidget );
+ * \endcode
+ *
+ * @since 3.1
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KNotifyDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * If you want a non-modal dialog, you need to instantiate KNotifyDialog
+ * yourself instead of using the configure() method.
+ *
+ * KDE4.0 modal default will be false.
+ *
+ * @param parent The parent widget for the dialog
+ * @param name The widget name
+ * @param modal If true, this will be a modal dialog, otherwise non-modal.
+ * @param aboutData A pointer to a TDEAboutData object. TDEAboutData::appName()
+ * will be used to find the KNotify events (in the eventsrc file).
+ * Set this to 0L if you want to add all events yourself with
+ * addApplicationEvents().
+ */
+ KNotifyDialog( TQWidget *parent = 0, const char *name = 0,
+ bool modal = true,
+ const TDEAboutData *aboutData =
+ TDEGlobal::instance()->aboutData() );
+ /**
+ * Destroys the KNotifyDialog
+ */
+ virtual ~KNotifyDialog();
+
+ /**
+ * Convenience method to create exec() a modal KNotifyDialog.
+ *
+ * @param parent The parent widget for the dialog
+ * @param name The widget name
+ * @param aboutData A pointer to a TDEAboutData object. TDEAboutData::appName()
+ * will be used to find the KNotify events (in the eventsrc file).
+ * @see exec for the return values.
+ * @return The value of TQDialog::exec()
+ */
+ static int configure( TQWidget *parent = 0, const char *name = 0,
+ const TDEAboutData *aboutData = TDEGlobal::instance()->aboutData() );
+
+ /**
+ * With this method, you can add the KNotify events of one eventsrc
+ * files to the view.
+ * KNotifyDialog can handle events for multiple applications (i.e. eventsrc files).
+ * Successive calls with a different @p appName will add them.
+ * @param appName The application's name, i.e. the name passed to the
+ * TDEApplication constructor or TDEAboutData.
+ * @see clearApplicationEvents()
+ */
+ virtual void addApplicationEvents( const char *appName );
+
+ /**
+ * With this method, you can add the KNotify events of one eventsrc
+ * files to the view.
+ * KNotifyDialog can handle events for multiple applications (i.e. eventsrc files).
+ * Successive calls with a different @p path will add them.
+ * @param path The absolute or relative path to the eventsrc file to be configured.
+ * A relative path would be e.g. "twin/eventsrc".
+ * @see clearApplicationEvents()
+ */
+ virtual void addApplicationEvents( const TQString& path );
+
+ /**
+ * Removes all the events added with addApplicationEvents()
+ * @see addApplicationEvents()
+ */
+ virtual void clearApplicationEvents();
+
+private slots:
+ void slotDefault();
+
+private:
+ enum
+ {
+ COL_FILENAME = 1
+ };
+
+ void updateView();
+
+ KNotify::KNotifyWidget * m_notifyWidget;
+
+ class Private;
+ Private *d;
+};
+
+
+namespace KNotify
+{
+ class Application;
+ class Event;
+ class ListViewItem;
+ typedef TQPtrList<Event> EventList;
+ typedef TQPtrListIterator<Application> ApplicationListIterator;
+ typedef TQPtrListIterator<Event> EventListIterator;
+
+ /**
+ * @internal
+ */
+ class TDEIO_EXPORT Application
+ {
+ public:
+ Application( const TQString &path );
+ ~Application();
+
+ TQString text() const { return m_description; }
+ TQString icon() const { return m_icon; }
+ const EventList& eventList();
+ void reloadEvents( bool revertToDefaults = false );
+ void save();
+
+ TQString appName() const { return m_appname; }
+
+ private:
+ TQString m_icon;
+ TQString m_description;
+ TQString m_appname;
+ EventList *m_events;
+
+ TDEConfig *kc; // The file that defines the events.
+ TDEConfig *config; // The file that contains the settings for the events
+ };
+
+
+ class TDEIO_EXPORT ApplicationList : public TQPtrList<Application>
+ {
+ virtual int compareItems ( TQPtrCollection::Item item1,
+ TQPtrCollection::Item item2 )
+ {
+ return (static_cast<Application*>( item1 )->text() >=
+ static_cast<Application*>( item2 )->text()) ? 1 : -1;
+ }
+ };
+
+ /**
+ * @internal
+ */
+ class TDEIO_EXPORT KNotifyWidget : public KNotifyWidgetBase
+ {
+ Q_OBJECT
+
+ public:
+ KNotifyWidget( TQWidget* parent = 0, const char* name = 0,
+ bool handleAllApps = false );
+ ~KNotifyWidget();
+
+ KListView * eventsView() {
+ return m_listview;
+ }
+
+ void addVisibleApp( Application *app );
+ ApplicationList& visibleApps() { return m_visibleApps; }
+ ApplicationList& allApps() { return m_allApps; }
+
+ /**
+ * Returns 0L if no application events could be found
+ * The returned pointer must be freed by the caller (easiest done
+ * by putting it into an ApplicationList with setAutoDelete( true )).
+ */
+ Application * addApplicationEvents( const TQString& path );
+
+ void resetDefaults( bool ask );
+ void sort( bool ascending = true );
+
+ public slots:
+ /**
+ * Clears the view and all the Application events.
+ */
+ virtual void clear();
+ /**
+ * Clears only the view and the visible Application events.
+ * E.g. useful if you want to set new visible events with
+ * addVisibleApp()
+ */
+ virtual void clearVisible();
+ virtual void save();
+ virtual void showAdvanced( bool show );
+ void toggleAdvanced();
+
+
+ signals:
+ void changed( bool hasChanges );
+
+ protected:
+ /**
+ * May return 0L, if there is no current event selected.
+ */
+ Event * currentEvent();
+ virtual void showEvent( TQShowEvent * );
+ virtual void enableAll( int what, bool enable );
+
+ void reload( bool revertToDefaults = false );
+
+ protected slots:
+ void playSound();
+
+ private slots:
+ void slotItemClicked( TQListViewItem *item, const TQPoint& point,
+ int col );
+ void slotEventChanged( TQListViewItem * );
+ void soundToggled( bool on );
+ void loggingToggled( bool on );
+ void executeToggled( bool on );
+ void messageBoxChanged();
+ void stderrToggled( bool on );
+ void taskbarToggled( bool on );
+
+ void soundFileChanged( const TQString& text );
+ void logfileChanged( const TQString& text );
+ void commandlineChanged( const TQString& text );
+
+ void openSoundDialog( KURLRequester * );
+ void openLogDialog( KURLRequester * );
+ void openExecDialog( KURLRequester * );
+
+ void enableAll();
+
+ private:
+ void updateWidgets( ListViewItem *item );
+ void updatePixmaps( ListViewItem *item );
+
+ static TQString makeRelative( const TQString& );
+ void addToView( const EventList& events );
+ void widgetChanged( TQListViewItem *item,
+ int what, bool on, TQWidget *buddy = 0L );
+ void selectItem( TQListViewItem *item );
+
+ ApplicationList m_visibleApps;
+ ApplicationList m_allApps;
+
+ class Private;
+ Private *d;
+
+ };
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+ /**
+ * @internal
+ */
+ class Event
+ {
+ friend class Application;
+
+ public:
+ TQString text() const { return description; }
+
+ int presentation;
+ int dontShow;
+ TQString logfile;
+ TQString soundfile;
+ TQString commandline;
+
+ const Application *application() const { return m_app; }
+
+ private:
+ Event( const Application *app ) {
+ presentation = 0;
+ dontShow = 0;
+ m_app = app;
+ }
+ TQString name;
+ TQString description;
+ TQString configGroup;
+
+ const Application *m_app;
+ };
+
+ /**
+ * @internal
+ */
+ class ListViewItem : public TQListViewItem
+ {
+ public:
+ ListViewItem( TQListView *view, Event *event );
+
+ Event& event() { return *m_event; }
+ virtual int compare (TQListViewItem * i, int col, bool ascending) const;
+
+ private:
+ Event * m_event;
+ };
+
+}
+
+
+#endif
diff --git a/tdeio/tdefile/knotifywidgetbase.ui b/tdeio/tdefile/knotifywidgetbase.ui
new file mode 100644
index 000000000..d3c3103ff
--- /dev/null
+++ b/tdeio/tdefile/knotifywidgetbase.ui
@@ -0,0 +1,469 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KNotifyWidgetBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KNotifyWidgetBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>487</width>
+ <height>531</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Events</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listview</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>m_controlsBox</cstring>
+ </property>
+ <property name="title">
+ <string>Quick Controls</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>m_affectAllApps</cstring>
+ </property>
+ <property name="text">
+ <string>Apply to &amp;all applications</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>Spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="3">
+ <property name="name">
+ <cstring>Spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>318</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton" row="2" column="1">
+ <property name="name">
+ <cstring>m_buttonDisable</cstring>
+ </property>
+ <property name="text">
+ <string>Turn O&amp;ff All</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Allows you to change the behavior for all events at once</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_buttonEnable</cstring>
+ </property>
+ <property name="text">
+ <string>Turn O&amp;n All</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Allows you to change the behavior for all events at once</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="2">
+ <property name="name">
+ <cstring>m_comboEnable</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="2">
+ <property name="name">
+ <cstring>m_comboDisable</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>m_actionsBox</cstring>
+ </property>
+ <property name="title">
+ <string>Actions</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_stderr</cstring>
+ </property>
+ <property name="text">
+ <string>Print a message to standard &amp;error output</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_messageBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show a &amp;message in a pop-up window</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_execute</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;xecute a program:</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>m_playSound</cstring>
+ </property>
+ <property name="text">
+ <string>Play a &amp;sound:</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>m_playButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Test the Sound</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQCheckBox" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_taskbar</cstring>
+ </property>
+ <property name="text">
+ <string>Mark &amp;taskbar entry</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_logToFile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Log to a file:</string>
+ </property>
+ </widget>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="2" column="2">
+ <property name="name">
+ <cstring>m_executePath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="2">
+ <property name="name">
+ <cstring>m_logfilePath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="2">
+ <property name="name">
+ <cstring>m_soundPath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_passivePopup</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Use a passive window that does not interrupt other work</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>Layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>m_extension</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Less Options</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>m_playerButton</cstring>
+ </property>
+ <property name="text">
+ <string>Player Settings</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_messageBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_passivePopup</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_execute</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_executePath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_playSound</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_soundPath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_logToFile</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_logfilePath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_listview</tabstop>
+ <tabstop>m_playSound</tabstop>
+ <tabstop>m_playButton</tabstop>
+ <tabstop>m_soundPath</tabstop>
+ <tabstop>m_logToFile</tabstop>
+ <tabstop>m_logfilePath</tabstop>
+ <tabstop>m_execute</tabstop>
+ <tabstop>m_executePath</tabstop>
+ <tabstop>m_messageBox</tabstop>
+ <tabstop>m_passivePopup</tabstop>
+ <tabstop>m_stderr</tabstop>
+ <tabstop>m_affectAllApps</tabstop>
+ <tabstop>m_buttonEnable</tabstop>
+ <tabstop>m_comboEnable</tabstop>
+ <tabstop>m_buttonDisable</tabstop>
+ <tabstop>m_comboDisable</tabstop>
+ <tabstop>m_extension</tabstop>
+ <tabstop>m_playerButton</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+ <include location="global" impldecl="in implementation">kcombobox.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/tdeio/tdefile/kopenwith.cpp b/tdeio/tdefile/kopenwith.cpp
new file mode 100644
index 000000000..691487730
--- /dev/null
+++ b/tdeio/tdefile/kopenwith.cpp
@@ -0,0 +1,851 @@
+/* This file is part of the KDE libraries
+
+ Copyright (C) 1997 Torben Weis <weis@stud.uni-frankfurt.de>
+ Copyright (C) 1999 Dirk Mueller <mueller@kde.org>
+ Portions copyright (C) 1999 Preston Brown <pbrown@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 <tqfile.h>
+#include <tqdir.h>
+#include <tqdialog.h>
+#include <tqimage.h>
+#include <tqpixmap.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+#include <tqtoolbutton.h>
+#include <tqcheckbox.h>
+#include <tqtooltip.h>
+#include <tqstyle.h>
+#include <tqwhatsthis.h>
+
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <kcombobox.h>
+#include <kdesktopfile.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmimemagic.h>
+#include <krun.h>
+#include <kstandarddirs.h>
+#include <kstringhandler.h>
+#include <kuserprofile.h>
+#include <kurlcompletion.h>
+#include <kurlrequester.h>
+#include <dcopclient.h>
+#include <kmimetype.h>
+#include <kservicegroup.h>
+#include <klistview.h>
+#include <tdesycoca.h>
+#include <kstdguiitem.h>
+
+#include "kopenwith.h"
+#include "kopenwith_p.h"
+
+#include <kdebug.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#define SORT_SPEC (TQDir::DirsFirst | TQDir::Name | TQDir::IgnoreCase)
+
+
+// ----------------------------------------------------------------------
+
+KAppTreeListItem::KAppTreeListItem( KListView* parent, const TQString & name,
+ const TQPixmap& pixmap, bool parse, bool dir, const TQString &p, const TQString &c )
+ : TQListViewItem( parent, name )
+{
+ init(pixmap, parse, dir, p, c);
+}
+
+
+// ----------------------------------------------------------------------
+
+KAppTreeListItem::KAppTreeListItem( TQListViewItem* parent, const TQString & name,
+ const TQPixmap& pixmap, bool parse, bool dir, const TQString &p, const TQString &c )
+ : TQListViewItem( parent, name )
+{
+ init(pixmap, parse, dir, p, c);
+}
+
+
+// ----------------------------------------------------------------------
+
+void KAppTreeListItem::init(const TQPixmap& pixmap, bool parse, bool dir, const TQString &_path, const TQString &_exec)
+{
+ setPixmap(0, pixmap);
+ parsed = parse;
+ directory = dir;
+ path = _path; // relative path
+ exec = _exec;
+}
+
+
+/* Ensures that directories sort before non-directories */
+int KAppTreeListItem::compare(TQListViewItem *i, int col, bool ascending) const
+{
+ KAppTreeListItem *other = dynamic_cast<KAppTreeListItem *>(i);
+
+ // Directories sort first
+ if (directory && !other->directory)
+ return -1;
+
+ else if (!directory && other->directory)
+ return 1;
+
+ else // both directories or both not
+ return TQListViewItem::compare(i, col, ascending);
+}
+
+// ----------------------------------------------------------------------
+// Ensure that case is ignored
+TQString KAppTreeListItem::key(int column, bool /*ascending*/) const
+{
+ return text(column).upper();
+}
+
+void KAppTreeListItem::activate()
+{
+ if ( directory )
+ setOpen(!isOpen());
+}
+
+void KAppTreeListItem::setOpen( bool o )
+{
+ if( o && !parsed ) { // fill the children before opening
+ ((TDEApplicationTree *) parent())->addDesktopGroup( path, this );
+ parsed = true;
+ }
+ TQListViewItem::setOpen( o );
+}
+
+bool KAppTreeListItem::isDirectory()
+{
+ return directory;
+}
+
+// ----------------------------------------------------------------------
+
+TDEApplicationTree::TDEApplicationTree( TQWidget *parent )
+ : KListView( parent ), currentitem(0)
+{
+ addColumn( i18n("Known Applications") );
+ setRootIsDecorated( true );
+
+ addDesktopGroup( TQString::null );
+ cleanupTree();
+
+ connect( this, TQT_SIGNAL( currentChanged(TQListViewItem*) ),
+ TQT_SLOT( slotItemHighlighted(TQListViewItem*) ) );
+ connect( this, TQT_SIGNAL( selectionChanged(TQListViewItem*) ),
+ TQT_SLOT( slotSelectionChanged(TQListViewItem*) ) );
+}
+
+// ----------------------------------------------------------------------
+
+bool TDEApplicationTree::isDirSel()
+{
+ if (!currentitem) return false; // if currentitem isn't set
+ return currentitem->isDirectory();
+}
+
+// ----------------------------------------------------------------------
+
+static TQPixmap appIcon(const TQString &iconName)
+{
+ TQPixmap normal = TDEGlobal::iconLoader()->loadIcon(iconName, KIcon::Small, 0, KIcon::DefaultState, 0L, true);
+ // make sure they are not larger than 20x20
+ if (normal.width() > 20 || normal.height() > 20)
+ {
+ TQImage tmp = normal.convertToImage();
+ tmp = tmp.smoothScale(20, 20);
+ normal.convertFromImage(tmp);
+ }
+ return normal;
+}
+
+void TDEApplicationTree::addDesktopGroup( const TQString &relPath, KAppTreeListItem *item)
+{
+ KServiceGroup::Ptr root = KServiceGroup::group(relPath);
+ if (!root || !root->isValid()) return;
+
+ KServiceGroup::List list = root->entries();
+
+ KAppTreeListItem * newItem;
+ for( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); it++)
+ {
+ TQString icon;
+ TQString text;
+ TQString relPath;
+ TQString exec;
+ bool isDir = false;
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+
+ if (service->noDisplay())
+ continue;
+
+ icon = service->icon();
+ text = service->name();
+ exec = service->exec();
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+
+ if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
+ continue;
+
+ icon = serviceGroup->icon();
+ text = serviceGroup->caption();
+ relPath = serviceGroup->relPath();
+ isDir = true;
+ }
+ else
+ {
+ kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl;
+ continue;
+ }
+
+ TQPixmap pixmap = appIcon( icon );
+
+ if (item)
+ newItem = new KAppTreeListItem( item, text, pixmap, false, isDir,
+ relPath, exec );
+ else
+ newItem = new KAppTreeListItem( this, text, pixmap, false, isDir,
+ relPath, exec );
+ if (isDir)
+ newItem->setExpandable( true );
+ }
+}
+
+
+// ----------------------------------------------------------------------
+
+void TDEApplicationTree::slotItemHighlighted(TQListViewItem* i)
+{
+ // i may be 0 (see documentation)
+ if(!i)
+ return;
+
+ KAppTreeListItem *item = (KAppTreeListItem *) i;
+
+ currentitem = item;
+
+ if( (!item->directory ) && (!item->exec.isEmpty()) )
+ emit highlighted( item->text(0), item->exec );
+}
+
+
+// ----------------------------------------------------------------------
+
+void TDEApplicationTree::slotSelectionChanged(TQListViewItem* i)
+{
+ // i may be 0 (see documentation)
+ if(!i)
+ return;
+
+ KAppTreeListItem *item = (KAppTreeListItem *) i;
+
+ currentitem = item;
+
+ if( ( !item->directory ) && (!item->exec.isEmpty() ) )
+ emit selected( item->text(0), item->exec );
+}
+
+// ----------------------------------------------------------------------
+
+void TDEApplicationTree::resizeEvent( TQResizeEvent * e)
+{
+ setColumnWidth(0, width()-TQApplication::style().pixelMetric(TQStyle::PM_ScrollBarExtent)
+ -2*TQApplication::style().pixelMetric(TQStyle::PM_DefaultFrameWidth));
+ KListView::resizeEvent(e);
+}
+
+// Prune empty directories from the tree
+void TDEApplicationTree::cleanupTree()
+{
+ TQListViewItem *item=firstChild();
+ while(item!=0)
+ {
+ if(item->isExpandable())
+ {
+ TQListViewItem *temp=item->itemBelow();
+ if(item->text(0)!=i18n("Applications"))
+ item->setOpen(false);
+ item=temp;
+ continue;
+ }
+ item=item->itemBelow();
+ }
+}
+
+/***************************************************************
+ *
+ * KOpenWithDlg
+ *
+ ***************************************************************/
+class KOpenWithDlgPrivate
+{
+public:
+ KOpenWithDlgPrivate() : saveNewApps(false) { };
+ TQPushButton* ok;
+ bool saveNewApps;
+ KService::Ptr curService;
+};
+
+KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, TQWidget* parent )
+ :TQDialog( parent, "openwith", true )
+{
+ setCaption( i18n( "Open With" ) );
+ TQString text;
+ if( _urls.count() == 1 )
+ {
+ text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>").arg( _urls.first().fileName() );
+ }
+ else
+ // Should never happen ??
+ text = i18n( "Choose the name of the program with which to open the selected files." );
+ setServiceType( _urls );
+ init( text, TQString() );
+}
+
+KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const TQString&_text,
+ const TQString& _value, TQWidget *parent)
+ :TQDialog( parent, "openwith", true )
+{
+ TQString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
+ if (_urls.count() > 1)
+ caption += TQString::fromLatin1("...");
+ setCaption(caption);
+ setServiceType( _urls );
+ init( _text, _value );
+}
+
+KOpenWithDlg::KOpenWithDlg( const TQString &serviceType, const TQString& value,
+ TQWidget *parent)
+ :TQDialog( parent, "openwith", true )
+{
+ setCaption(i18n("Choose Application for %1").arg(serviceType));
+ TQString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>").arg(serviceType);
+ qServiceType = serviceType;
+ init( text, value );
+ if (remember)
+ remember->hide();
+}
+
+KOpenWithDlg::KOpenWithDlg( TQWidget *parent)
+ :TQDialog( parent, "openwith", true )
+{
+ setCaption(i18n("Choose Application"));
+ TQString text = i18n("<qt>Select a program. "
+ "If the program is not listed, enter the name or click "
+ "the browse button.</qt>");
+ qServiceType = TQString::null;
+ init( text, TQString::null );
+}
+
+void KOpenWithDlg::setServiceType( const KURL::List& _urls )
+{
+ if ( _urls.count() == 1 )
+ {
+ qServiceType = KMimeType::findByURL( _urls.first())->name();
+ if (qServiceType == TQString::fromLatin1("application/octet-stream"))
+ qServiceType = TQString::null;
+ }
+ else
+ qServiceType = TQString::null;
+}
+
+void KOpenWithDlg::init( const TQString& _text, const TQString& _value )
+{
+ d = new KOpenWithDlgPrivate;
+ bool bReadOnly = kapp && !kapp->authorize("shell_access");
+ m_terminaldirty = false;
+ m_pTree = 0L;
+ m_pService = 0L;
+ d->curService = 0L;
+
+ TQBoxLayout *topLayout = new TQVBoxLayout( this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+ label = new TQLabel( _text, this );
+ topLayout->addWidget(label);
+
+ TQHBoxLayout* hbox = new TQHBoxLayout(topLayout);
+
+ TQToolButton *clearButton = new TQToolButton( this );
+ clearButton->setIconSet( BarIcon( "locationbar_erase" ) );
+ clearButton->setFixedSize( clearButton->sizeHint() );
+ connect( clearButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotClear() ) );
+ TQToolTip::add( clearButton, i18n( "Clear input field" ) );
+
+ hbox->addWidget( clearButton );
+
+ if (!bReadOnly)
+ {
+ // init the history combo and insert it into the URL-Requester
+ KHistoryCombo *combo = new KHistoryCombo();
+ combo->setDuplicatesEnabled( false );
+ TDEConfig *kc = TDEGlobal::config();
+ TDEConfigGroupSaver ks( kc, TQString::fromLatin1("Open-with settings") );
+ int max = kc->readNumEntry( TQString::fromLatin1("Maximum history"), 15 );
+ combo->setMaxCount( max );
+ int mode = kc->readNumEntry(TQString::fromLatin1("CompletionMode"),
+ TDEGlobalSettings::completionMode());
+ combo->setCompletionMode((TDEGlobalSettings::Completion)mode);
+ TQStringList list = kc->readListEntry( TQString::fromLatin1("History") );
+ combo->setHistoryItems( list, true );
+ edit = new KURLRequester( combo, this );
+ }
+ else
+ {
+ clearButton->hide();
+ edit = new KURLRequester( this );
+ edit->lineEdit()->setReadOnly(true);
+ edit->button()->hide();
+ }
+
+ edit->setURL( _value );
+ TQWhatsThis::add(edit,i18n(
+ "Following the command, you can have several place holders which will be replaced "
+ "with the actual values when the actual program is run:\n"
+ "%f - a single file name\n"
+ "%F - a list of files; use for applications that can open several local files at once\n"
+ "%u - a single URL\n"
+ "%U - a list of URLs\n"
+ "%d - the directory of the file to open\n"
+ "%D - a list of directories\n"
+ "%i - the icon\n"
+ "%m - the mini-icon\n"
+ "%c - the comment"));
+
+ hbox->addWidget(edit);
+
+ if ( edit->comboBox() ) {
+ KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion );
+ edit->comboBox()->setCompletionObject( comp );
+ edit->comboBox()->setAutoDeleteCompletionObject( true );
+ }
+
+ connect ( edit, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotOK()) );
+ connect ( edit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotTextChanged()) );
+
+ m_pTree = new TDEApplicationTree( this );
+ topLayout->addWidget(m_pTree);
+
+ connect( m_pTree, TQT_SIGNAL( selected( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotSelected( const TQString&, const TQString& ) ) );
+ connect( m_pTree, TQT_SIGNAL( highlighted( const TQString&, const TQString& ) ),
+ TQT_SLOT( slotHighlighted( const TQString&, const TQString& ) ) );
+ connect( m_pTree, TQT_SIGNAL( doubleClicked(TQListViewItem*) ),
+ TQT_SLOT( slotDbClick() ) );
+
+ terminal = new TQCheckBox( i18n("Run in &terminal"), this );
+ if (bReadOnly)
+ terminal->hide();
+ connect(terminal, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotTerminalToggled(bool)));
+
+ topLayout->addWidget(terminal);
+
+ TQBoxLayout* nocloseonexitLayout = new TQHBoxLayout( 0, 0, KDialog::spacingHint() );
+ TQSpacerItem* spacer = new TQSpacerItem( 20, 0, TQSizePolicy::Fixed, TQSizePolicy::Minimum );
+ nocloseonexitLayout->addItem( spacer );
+
+ nocloseonexit = new TQCheckBox( i18n("&Do not close when command exits"), this );
+ nocloseonexit->setChecked( false );
+ nocloseonexit->setDisabled( true );
+
+ // check to see if we use konsole if not disable the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") );
+ TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication", TQString::fromLatin1("konsole"));
+
+ if (bReadOnly || preferredTerminal != "konsole")
+ nocloseonexit->hide();
+
+ nocloseonexitLayout->addWidget( nocloseonexit );
+ topLayout->addLayout( nocloseonexitLayout );
+
+ if (!qServiceType.isNull())
+ {
+ remember = new TQCheckBox(i18n("&Remember application association for this type of file"), this);
+ // remember->setChecked(true);
+ topLayout->addWidget(remember);
+ }
+ else
+ remember = 0L;
+
+ // Use KButtonBox for the aligning pushbuttons nicely
+ KButtonBox* b = new KButtonBox( this );
+ b->addStretch( 2 );
+
+ d->ok = b->addButton( KStdGuiItem::ok() );
+ d->ok->setDefault( true );
+ connect( d->ok, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOK() ) );
+
+ TQPushButton* cancel = b->addButton( KStdGuiItem::cancel() );
+ connect( cancel, TQT_SIGNAL( clicked() ), TQT_SLOT( reject() ) );
+
+ b->layout();
+ topLayout->addWidget( b );
+
+ //edit->setText( _value );
+ // This is what caused "can't click on items before clicking on Name header".
+ // Probably due to the resizeEvent handler using width().
+ //resize( minimumWidth(), sizeHint().height() );
+ edit->setFocus();
+ slotTextChanged();
+}
+
+
+// ----------------------------------------------------------------------
+
+KOpenWithDlg::~KOpenWithDlg()
+{
+ delete d;
+ d = 0;
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotClear()
+{
+ edit->setURL(TQString::null);
+ edit->setFocus();
+}
+
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotSelected( const TQString& /*_name*/, const TQString& _exec )
+{
+ kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl;
+ KService::Ptr pService = d->curService;
+ edit->setURL( _exec ); // calls slotTextChanged :(
+ d->curService = pService;
+}
+
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotHighlighted( const TQString& _name, const TQString& )
+{
+ kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl;
+ qName = _name;
+ d->curService = KService::serviceByName( qName );
+ if (!m_terminaldirty)
+ {
+ // ### indicate that default value was restored
+ terminal->setChecked(d->curService->terminal());
+ TQString terminalOptions = d->curService->terminalOptions();
+ nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) );
+ m_terminaldirty = false; // slotTerminalToggled changed it
+ }
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotTextChanged()
+{
+ kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl;
+ // Forget about the service
+ d->curService = 0L;
+ d->ok->setEnabled( !edit->url().isEmpty());
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotTerminalToggled(bool)
+{
+ // ### indicate that default value was overridden
+ m_terminaldirty = true;
+ nocloseonexit->setDisabled( ! terminal->isChecked() );
+}
+
+// ----------------------------------------------------------------------
+
+void KOpenWithDlg::slotDbClick()
+{
+ if (m_pTree->isDirSel() ) return; // check if a directory is selected
+ slotOK();
+}
+
+void KOpenWithDlg::setSaveNewApplications(bool b)
+{
+ d->saveNewApps = b;
+}
+
+void KOpenWithDlg::slotOK()
+{
+ TQString typedExec(edit->url());
+ TQString fullExec(typedExec);
+
+ TQString serviceName;
+ TQString initialServiceName;
+ TQString preferredTerminal;
+ m_pService = d->curService;
+ if (!m_pService) {
+ // No service selected - check the command line
+
+ // Find out the name of the service from the command line, removing args and paths
+ serviceName = KRun::binaryName( typedExec, true );
+ if (serviceName.isEmpty())
+ {
+ // TODO add a KMessageBox::error here after the end of the message freeze
+ return;
+ }
+ initialServiceName = serviceName;
+ kdDebug(250) << "initialServiceName=" << initialServiceName << endl;
+ int i = 1; // We have app, app-2, app-3... Looks better for the user.
+ bool ok = false;
+ // Check if there's already a service by that name, with the same Exec line
+ do {
+ kdDebug(250) << "looking for service " << serviceName << endl;
+ KService::Ptr serv = KService::serviceByDesktopName( serviceName );
+ ok = !serv; // ok if no such service yet
+ // also ok if we find the exact same service (well, "kwrite" == "kwrite %U"
+ if ( serv && serv->type() == "Application")
+ {
+ TQString exec = serv->exec();
+ fullExec = exec;
+ exec.replace("%u", "", false);
+ exec.replace("%f", "", false);
+ exec.replace("-caption %c", "");
+ exec.replace("-caption \"%c\"", "");
+ exec.replace("%i", "");
+ exec.replace("%m", "");
+ exec = exec.simplifyWhiteSpace();
+ if (exec == typedExec)
+ {
+ ok = true;
+ m_pService = serv;
+ kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl;
+ }
+ }
+ if (!ok) // service was found, but it was different -> keep looking
+ {
+ ++i;
+ serviceName = initialServiceName + "-" + TQString::number(i);
+ }
+ }
+ while (!ok);
+ }
+ if ( m_pService )
+ {
+ // Existing service selected
+ serviceName = m_pService->name();
+ initialServiceName = serviceName;
+ fullExec = m_pService->exec();
+ }
+
+ if (terminal->isChecked())
+ {
+ TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") );
+ preferredTerminal = confGroup.readPathEntry("TerminalApplication", TQString::fromLatin1("konsole"));
+ m_command = preferredTerminal;
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ m_command += TQString::fromLatin1(" --noclose");
+ m_command += TQString::fromLatin1(" -e ");
+ m_command += edit->url();
+ kdDebug(250) << "Setting m_command to " << m_command << endl;
+ }
+ if ( m_pService && terminal->isChecked() != m_pService->terminal() )
+ m_pService = 0L; // It's not exactly this service we're running
+
+ bool bRemember = remember && remember->isChecked();
+
+ if ( !bRemember && m_pService)
+ {
+ accept();
+ return;
+ }
+
+ if (!bRemember && !d->saveNewApps)
+ {
+ // Create temp service
+ m_pService = new KService(initialServiceName, fullExec, TQString::null);
+ if (terminal->isChecked())
+ {
+ m_pService->setTerminal(true);
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ m_pService->setTerminalOptions("--noclose");
+ }
+ accept();
+ return;
+ }
+
+ // if we got here, we can't seem to find a service for what they
+ // wanted. The other possibility is that they have asked for the
+ // association to be remembered. Create/update service.
+
+ TQString newPath;
+ TQString oldPath;
+ TQString menuId;
+ if (m_pService)
+ {
+ oldPath = m_pService->desktopEntryPath();
+ newPath = m_pService->locateLocal();
+ menuId = m_pService->menuId();
+ kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl;
+ }
+ else
+ {
+ newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId);
+ kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl;
+ }
+
+ int maxPreference = 1;
+ if (!qServiceType.isEmpty())
+ {
+ KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
+ if (!offerList.isEmpty())
+ maxPreference = offerList.first().preference();
+ }
+
+ KDesktopFile *desktop = 0;
+ if (!oldPath.isEmpty() && (oldPath != newPath))
+ {
+ KDesktopFile orig(oldPath, true);
+ desktop = orig.copyTo(newPath);
+ }
+ else
+ {
+ desktop = new KDesktopFile(newPath);
+ }
+ desktop->writeEntry("Type", TQString::fromLatin1("Application"));
+ desktop->writeEntry("Name", initialServiceName);
+ desktop->writePathEntry("Exec", fullExec);
+ if (terminal->isChecked())
+ {
+ desktop->writeEntry("Terminal", true);
+ // only add --noclose when we are sure it is konsole we're using
+ if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
+ desktop->writeEntry("TerminalOptions", "--noclose");
+ }
+ else
+ {
+ desktop->writeEntry("Terminal", false);
+ }
+ desktop->writeEntry("InitialPreference", maxPreference + 1);
+
+
+ if (bRemember || d->saveNewApps)
+ {
+ TQStringList mimeList = desktop->readListEntry("MimeType", ';');
+ if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
+ mimeList.append(qServiceType);
+ desktop->writeEntry("MimeType", mimeList, ';');
+
+ if ( !qServiceType.isEmpty() )
+ {
+ // Also make sure the "auto embed" setting for this mimetype is off
+ KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) );
+ mimeDesktop.writeEntry( "X-TDE-AutoEmbed", false );
+ mimeDesktop.sync();
+ }
+ }
+
+ // write it all out to the file
+ desktop->sync();
+ delete desktop;
+
+ KService::rebuildKSycoca(this);
+
+ m_pService = KService::serviceByMenuId( menuId );
+
+ Q_ASSERT( m_pService );
+
+ accept();
+}
+
+TQString KOpenWithDlg::text() const
+{
+ if (!m_command.isEmpty())
+ return m_command;
+ else
+ return edit->url();
+}
+
+void KOpenWithDlg::hideNoCloseOnExit()
+{
+ // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
+ nocloseonexit->setChecked( false );
+ nocloseonexit->hide();
+}
+
+void KOpenWithDlg::hideRunInTerminal()
+{
+ terminal->hide();
+ hideNoCloseOnExit();
+}
+
+void KOpenWithDlg::accept()
+{
+ KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() );
+ if ( combo ) {
+ combo->addToHistory( edit->url() );
+
+ TDEConfig *kc = TDEGlobal::config();
+ TDEConfigGroupSaver ks( kc, TQString::fromLatin1("Open-with settings") );
+ kc->writeEntry( TQString::fromLatin1("History"), combo->historyItems() );
+ kc->writeEntry(TQString::fromLatin1("CompletionMode"),
+ combo->completionMode());
+ // don't store the completion-list, as it contains all of KURLCompletion's
+ // executables
+ kc->sync();
+ }
+
+ TQDialog::accept();
+}
+
+
+///////////////
+
+#ifndef KDE_NO_COMPAT
+bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls )
+{
+ KOpenWithDlg l( urls, i18n("Open with:"), TQString::null, 0L );
+ if ( l.exec() )
+ {
+ KService::Ptr service = l.service();
+ if ( !!service )
+ return KRun::run( *service, urls );
+
+ kdDebug(250) << "No service set, running " << l.text() << endl;
+ return KRun::run( l.text(), urls );
+ }
+ return false;
+}
+#endif
+
+#include "kopenwith.moc"
+#include "kopenwith_p.moc"
+
diff --git a/tdeio/tdefile/kopenwith.h b/tdeio/tdefile/kopenwith.h
new file mode 100644
index 000000000..90c43ceb1
--- /dev/null
+++ b/tdeio/tdefile/kopenwith.h
@@ -0,0 +1,209 @@
+//
+/* 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 __open_with_h__
+#define __open_with_h__
+
+#include <tqdialog.h>
+
+#include <kurl.h>
+#include <krun.h>
+#include <kservice.h>
+
+class TDEApplicationTree;
+class KURLRequester;
+
+class TQWidget;
+class TQCheckBox;
+class TQPushButton;
+class TQLabel;
+
+class KOpenWithDlgPrivate;
+
+/* ------------------------------------------------------------------------- */
+/**
+ * "Open with" dialog box.
+ * Used automatically by KRun, and used by libkonq.
+ *
+ * @author David Faure <faure@kde.org>
+ */
+class TDEIO_EXPORT KOpenWithDlg : public TQDialog //#TODO: Use KDialogBase for KDE4
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param urls the URLs that should be opened. The list can be empty,
+ * if the dialog is used to choose an application but not for some particular URLs.
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const KURL::List& urls, TQWidget *parent = 0L );
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param urls is the URL that should be opened
+ * @param text appears as a label on top of the entry box.
+ * @param value is the initial value of the line
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const KURL::List& urls, const TQString& text, const TQString& value,
+ TQWidget *parent = 0L );
+
+ /**
+ * Create a dialog to select a service for a given service type.
+ * Note that this dialog doesn't apply to URLs.
+ *
+ * @param serviceType the service type we want to choose an application for.
+ * @param value is the initial value of the line
+ * @param parent parent widget
+ */
+ KOpenWithDlg( const TQString& serviceType, const TQString& value,
+ TQWidget *parent = 0L );
+
+ /**
+ * Create a dialog to select an application
+ * Note that this dialog doesn't apply to URLs.
+ *
+ * @param parent parent widget
+ * @since 3.1
+ */
+ KOpenWithDlg( TQWidget *parent = 0L );
+
+ /**
+ * Destructor
+ */
+ ~KOpenWithDlg();
+
+ /**
+ * @return the text the user entered
+ */
+ TQString text() const;
+ /**
+ * Hide the "Do not &close when command exits" Checkbox
+ */
+ void hideNoCloseOnExit();
+ /**
+ * Hide the "Run in &terminal" Checkbox
+ */
+ void hideRunInTerminal();
+ /**
+ * @return the chosen service in the application tree
+ * Can be null, if the user typed some text and didn't select a service.
+ */
+ KService::Ptr service() const { return m_pService; }
+ /**
+ * Set whether a new .desktop file should be created if the user selects an
+ * application for which no corresponding .desktop file can be found.
+ *
+ * Regardless of this setting a new .desktop file may still be created if
+ * the user has chosen to remember the file association.
+ *
+ * The default is false: no .desktop files are created.
+ * @since 3.2
+ */
+ void setSaveNewApplications(bool b);
+
+public slots:
+ /**
+ * The slot for clearing the edit widget
+ */
+ void slotClear();
+ void slotSelected( const TQString&_name, const TQString& _exec );
+ void slotHighlighted( const TQString& _name, const TQString& _exec );
+ void slotTextChanged();
+ void slotTerminalToggled(bool);
+ void slotDbClick();
+ void slotOK();
+
+protected slots:
+ /**
+ * Reimplemented from TQDialog::accept() to save history of the combobox
+ */
+ virtual void accept();
+
+protected:
+
+ /**
+ * Determine service type from URLs
+ */
+ void setServiceType( const KURL::List& _urls );
+
+ /**
+ * Create a dialog that asks for a application to open a given
+ * URL(s) with.
+ *
+ * @param text appears as a label on top of the entry box.
+ * @param value is the initial value of the line
+ */
+ void init( const TQString& text, const TQString& value );
+
+ KURLRequester * edit;
+ TQString m_command;
+
+ TDEApplicationTree* m_pTree;
+ TQLabel *label;
+
+ TQString qName, qServiceType;
+ bool m_terminaldirty;
+ TQCheckBox *terminal, *remember, *nocloseonexit;
+ TQPushButton *UNUSED;
+ TQPushButton *UNUSED2;
+
+ KService::Ptr m_pService;
+
+ KOpenWithDlgPrivate *d;
+};
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef KDE_NO_COMPAT
+/**
+ * This class handles the displayOpenWithDialog call, made by KRun
+ * when it has no idea what to do with a URL.
+ * It displays the open-with dialog box.
+ *
+ * If you use KRun you _need_ to create an instance of KFileOpenWithHandler
+ * (except if you can make sure you only use it for executables or
+ * Type=Application desktop files)
+ *
+ *
+ */
+class TDEIO_EXPORT_DEPRECATED KFileOpenWithHandler : public KOpenWithHandler
+{
+public:
+ KFileOpenWithHandler() : KOpenWithHandler() {}
+ virtual ~KFileOpenWithHandler() {}
+
+ /**
+ * Opens an open-with dialog box for @p urls
+ * @returns true if the operation succeeded
+ */
+ virtual bool displayOpenWithDialog( const KURL::List& urls );
+};
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+#endif
diff --git a/tdeio/tdefile/kopenwith_p.h b/tdeio/tdefile/kopenwith_p.h
new file mode 100644
index 000000000..8231da27d
--- /dev/null
+++ b/tdeio/tdefile/kopenwith_p.h
@@ -0,0 +1,101 @@
+//
+/* 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 __open_with_p_h__
+#define __open_with_p_h__
+
+#include <kurl.h>
+#include <klistview.h>
+
+class KURLRequester;
+
+class TQWidget;
+class TQCheckBox;
+class TQPushButton;
+class TQLabel;
+class TQStringList;
+
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @internal
+ */
+class KAppTreeListItem : public TQListViewItem
+{
+ bool parsed;
+ bool directory;
+ TQString path;
+ TQString exec;
+
+protected:
+ int compare(TQListViewItem *i, int col, bool ascending ) const;
+ TQString key(int column, bool ascending) const;
+
+ void init(const TQPixmap& pixmap, bool parse, bool dir, const TQString &_path, const TQString &exec);
+
+public:
+ KAppTreeListItem( KListView* parent, const TQString & name, const TQPixmap& pixmap,
+ bool parse, bool dir, const TQString &p, const TQString &c );
+ KAppTreeListItem( TQListViewItem* parent, const TQString & name, const TQPixmap& pixmap,
+ bool parse, bool dir, const TQString &p, const TQString &c );
+ bool isDirectory();
+
+protected:
+ virtual void activate();
+ virtual void setOpen( bool o );
+
+ friend class TDEApplicationTree;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @internal
+ */
+class TDEApplicationTree : public KListView
+{
+ Q_OBJECT
+public:
+ TDEApplicationTree( TQWidget *parent );
+
+ /**
+ * Add a group of .desktop/.kdelnk entries
+ */
+ void addDesktopGroup( const TQString &relPath, KAppTreeListItem *item = 0 );
+
+ bool isDirSel();
+
+protected:
+ void resizeEvent( TQResizeEvent *_ev );
+ KAppTreeListItem* currentitem;
+ void cleanupTree();
+
+public slots:
+ void slotItemHighlighted(TQListViewItem* i);
+ void slotSelectionChanged(TQListViewItem* i);
+
+signals:
+ void selected( const TQString& _name, const TQString& _exec );
+ void highlighted( const TQString& _name, const TQString& _exec );
+};
+
+/* ------------------------------------------------------------------------- */
+
+#endif
diff --git a/tdeio/tdefile/kpreviewprops.cpp b/tdeio/tdefile/kpreviewprops.cpp
new file mode 100644
index 000000000..a053d5627
--- /dev/null
+++ b/tdeio/tdefile/kpreviewprops.cpp
@@ -0,0 +1,89 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Stephan Binner <binner@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 "kpreviewprops.h"
+
+#include <tqlayout.h>
+
+#include <tdefilemetapreview.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+class KPreviewPropsPlugin::KPreviewPropsPluginPrivate
+{
+public:
+ KPreviewPropsPluginPrivate() {}
+ ~KPreviewPropsPluginPrivate() {}
+};
+
+KPreviewPropsPlugin::KPreviewPropsPlugin(KPropertiesDialog* props)
+ : KPropsDlgPlugin(props)
+{
+ d = new KPreviewPropsPluginPrivate;
+
+ if (properties->items().count()>1)
+ return;
+
+ createLayout();
+}
+
+void KPreviewPropsPlugin::createLayout()
+{
+ // let the dialog create the page frame
+ TQFrame* topframe = properties->addPage(i18n("P&review"));
+ topframe->setFrameStyle(TQFrame::NoFrame);
+
+ TQVBoxLayout* tmp = new TQVBoxLayout(topframe, 0, 0);
+
+ preview = new KFileMetaPreview(topframe);
+
+ tmp->addWidget(preview) ;
+ connect( properties, TQT_SIGNAL( aboutToShowPage( TQWidget * ) ), TQT_SLOT( aboutToShowPage( TQWidget* ) ) );
+}
+
+KPreviewPropsPlugin::~KPreviewPropsPlugin()
+{
+ delete d;
+}
+
+bool KPreviewPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1)
+ return false;
+ if( !TDEGlobalSettings::showFilePreview(_items.first()->url()))
+ return false;
+ KMimeType::Ptr mt = KMimeType::findByURL( _items.first()->url() );
+ if ( mt->inherits("inode/directory") || mt->name() == "application/octet-stream" )
+ return false;
+
+ //TODO Copy everything of KFileMetaPreview::previewProviderFor() ?
+
+ return true;
+}
+
+void KPreviewPropsPlugin::aboutToShowPage( TQWidget* widget )
+{
+ if ( TQT_TQOBJECT(widget) != TQT_TQOBJECT(preview->parent()) )
+ return;
+
+ disconnect( properties, TQT_SIGNAL( aboutToShowPage( TQWidget * ) ), this, TQT_SLOT( aboutToShowPage( TQWidget* ) ) );
+ preview->showPreview(properties->item()->url());
+}
+
+#include "kpreviewprops.moc"
diff --git a/tdeio/tdefile/kpreviewprops.h b/tdeio/tdefile/kpreviewprops.h
new file mode 100644
index 000000000..d934af22a
--- /dev/null
+++ b/tdeio/tdefile/kpreviewprops.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Stephan Binner <binner@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 __KPREVIEWPROPS_H__
+#define __KPREVIEWPROPS_H__
+
+#include <kpropertiesdialog.h>
+
+class KFileMetaPreview;
+
+/*!
+ * PreviewProps plugin
+ * This plugin displays a preview of the given file
+ * @since 3.5
+ */
+class TDEIO_EXPORT KPreviewPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+
+public:
+
+ KPreviewPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KPreviewPropsPlugin();
+
+ /**
+ * Tests whether a preview for the first item should be shown
+ */
+ static bool supports( KFileItemList _items );
+
+private slots:
+ void aboutToShowPage( TQWidget* );
+
+private:
+ KFileMetaPreview* preview;
+ void createLayout();
+
+ class KPreviewPropsPluginPrivate;
+ KPreviewPropsPluginPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/kpreviewwidgetbase.cpp b/tdeio/tdefile/kpreviewwidgetbase.cpp
new file mode 100644
index 000000000..979da919e
--- /dev/null
+++ b/tdeio/tdefile/kpreviewwidgetbase.cpp
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "kpreviewwidgetbase.h"
+#include <tqstringlist.h>
+
+class KPreviewWidgetBase::KPreviewWidgetBasePrivate
+{
+public:
+ TQStringList supportedMimeTypes;
+};
+
+TQPtrDict<KPreviewWidgetBase::KPreviewWidgetBasePrivate> * KPreviewWidgetBase::s_private;
+
+KPreviewWidgetBase::KPreviewWidgetBase( TQWidget *parent, const char *name )
+ : TQWidget( parent, name )
+{
+ if ( !s_private )
+ s_private = new TQPtrDict<KPreviewWidgetBasePrivate>();
+
+ s_private->insert( this, new KPreviewWidgetBasePrivate() );
+}
+
+KPreviewWidgetBase::~KPreviewWidgetBase()
+{
+ s_private->remove( this );
+ if ( s_private->isEmpty() )
+ {
+ delete s_private;
+ s_private = 0L;
+ }
+}
+
+void KPreviewWidgetBase::setSupportedMimeTypes( const TQStringList& mimeTypes )
+{
+ d()->supportedMimeTypes = mimeTypes;
+}
+
+TQStringList KPreviewWidgetBase::supportedMimeTypes() const
+{
+ return d()->supportedMimeTypes;
+}
+
+#include "kpreviewwidgetbase.moc"
diff --git a/tdeio/tdefile/kpreviewwidgetbase.h b/tdeio/tdefile/kpreviewwidgetbase.h
new file mode 100644
index 000000000..3597070ee
--- /dev/null
+++ b/tdeio/tdefile/kpreviewwidgetbase.h
@@ -0,0 +1,92 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 2001 Frerich Raabe <raabe@kde.org>
+ * 2003 Carsten Pfeiffer <pfeiffer@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 __KPREVIEWWIDGETBASE_H__
+#define __KPREVIEWWIDGETBASE_H__
+
+#include <tqptrdict.h>
+#include <tqwidget.h>
+
+#include <tdelibs_export.h>
+
+class KURL;
+
+/**
+ * Abstract baseclass for all preview widgets which shall be used via
+ * KFileDialog::setPreviewWidget(const KPreviewWidgetBase *).
+ * Ownership will be transferred to KFileDialog, so you have to create
+ * the preview with "new" and let KFileDialog delete it.
+ *
+ * Just derive your custom preview widget from KPreviewWidgetBase and implement
+ * all the pure virtual methods. The slot showPreview(const KURL &) is called
+ * every time the file selection changes.
+ *
+ * @short Abstract baseclass for all preview widgets.
+ * @author Frerich Raabe <raabe@kde.org>
+ */
+class TDEIO_EXPORT KPreviewWidgetBase : public TQWidget
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor. Construct the user interface of your preview widget here
+ * and pass the KFileDialog this preview widget is going to be used in as
+ * the parent.
+ *
+ * @param parent The KFileDialog this preview widget is going to be used in
+ * @param name The internal name of this object
+ */
+ KPreviewWidgetBase(TQWidget *parent, const char *name=0);
+ ~KPreviewWidgetBase();
+
+public slots:
+ /**
+ * This slot is called every time the user selects another file in the
+ * file dialog. Implement the stuff necessary to reflect the change here.
+ *
+ * @param url The URL of the currently selected file.
+ */
+ virtual void showPreview(const KURL &url) = 0;
+
+ /**
+ * Reimplement this to clear the preview. This is called when e.g. the
+ * selection is cleared or when multiple selections exist, or the directory
+ * is changed.
+ */
+ virtual void clearPreview() = 0;
+
+ TQStringList supportedMimeTypes() const;
+
+protected:
+ void setSupportedMimeTypes( const TQStringList& mimeTypes );
+
+protected:
+ virtual void virtual_hook( int, void* ) {};
+
+private:
+ class KPreviewWidgetBasePrivate;
+ KPreviewWidgetBasePrivate * d() const {
+ return s_private->find( const_cast<KPreviewWidgetBase*>( this ) );
+ }
+ static TQPtrDict<KPreviewWidgetBasePrivate> * s_private;
+};
+
+#endif
diff --git a/tdeio/tdefile/kpropertiesdesktopadvbase.ui b/tdeio/tdefile/kpropertiesdesktopadvbase.ui
new file mode 100644
index 000000000..fd8e39781
--- /dev/null
+++ b/tdeio/tdefile/kpropertiesdesktopadvbase.ui
@@ -0,0 +1,280 @@
+
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesDesktopAdvBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>widget11</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>463</width>
+ <height>294</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Terminal</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>terminalCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Run in terminal</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if the application you want to run is a text mode application or if you want the information that is provided by the terminal emulator window.</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="1">
+ <property name="name">
+ <cstring>terminalEditLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Terminal options:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>terminalEdit</cstring>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>terminalCloseCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Do not &amp;close when command exits</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if the text mode application offers relevant information on exit. Keeping the terminal emulator open allows you to retrieve this information.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="2">
+ <property name="name">
+ <cstring>terminalEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2_2</cstring>
+ </property>
+ <property name="title">
+ <string>User</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>suidCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Ru&amp;n as a different user</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to run this application with a different user id. Every process has a different user id associated with it. This id code determines file access and other permissions. The password of the user is required to use this option.</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLabel" row="1" column="1">
+ <property name="name">
+ <cstring>suidEditLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>suidEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user name you want to run the application as.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="2">
+ <property name="name">
+ <cstring>suidEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user name you want to run the application as here.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup4</cstring>
+ </property>
+ <property name="title">
+ <string>Startup</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>startupInfoCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Enable &amp;launch feedback</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to make clear that your application has started. This visual feedback may appear as a busy cursor or in the taskbar.</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>systrayCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Place in system tray</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to have a system tray handle for your application.</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel12</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;DCOP registration:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>dcopCombo</cstring>
+ </property>
+ </widget>
+ <widget class="TQComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Multiple Instances</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Single Instance</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Run Until Finished</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>dcopCombo</cstring>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer33</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalCloseCheck</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>terminalCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalEditLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>suidCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>suidEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>suidCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>suidEditLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/tdeio/tdefile/kpropertiesdesktopbase.ui b/tdeio/tdefile/kpropertiesdesktopbase.ui
new file mode 100644
index 000000000..a0894dc70
--- /dev/null
+++ b/tdeio/tdefile/kpropertiesdesktopbase.ui
@@ -0,0 +1,316 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesDesktopBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KPropertiesDesktopBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>304</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer row="5" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLabel" row="6" column="0" rowspan="1" colspan="7">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Supported file types:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>filetypeList</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;This list should show the types of file that your application can handle. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;
+&lt;p&gt;If you want to associate this application with one or more mimetypes that are not in this list, click on the button &lt;b&gt;Add&lt;/b&gt; below. If there are one or more filetypes that this application cannot handle, you may want to remove them from the list clicking on the button &lt;b&gt;Remove&lt;/b&gt; below.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KListView" row="7" column="0" rowspan="1" colspan="7">
+ <column>
+ <property name="text">
+ <string>Mimetype</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>filetypeList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;This list should show the types of file that your application can handle. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;
+&lt;p&gt;If you want to associate this application with one or more mimetypes that are not in this list, click on the button &lt;b&gt;Add&lt;/b&gt; below. If there are one or more filetypes that this application cannot handle, you may want to remove them from the list clicking on the button &lt;b&gt;Remove&lt;/b&gt; below.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>nameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the name you want to give to this application here. This application will appear under this name in the applications menu and in the panel.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>nameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the name you want to give to this application here. This application will appear under this name in the applications menu and in the panel.</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the description of this application, based on its use, here. Examples: a dial up application (KPPP) would be "Dial up tool".</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>genNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the description of this application, based on its use, here. Examples: a dial up application (KPPP) would be "Dial up tool".</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Comm&amp;ent:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commentEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type any comment you think is useful here.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>commentEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type any comment you think is useful here.</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;mmand:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commandEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the command to start this application here.
+
+Following the command, you can have several place holders which will be replaced with the actual values when the actual program is run:
+%f - a single file name
+%F - a list of files; use for applications that can open several local files at once
+%u - a single URL
+%U - a list of URLs
+%d - the directory of the file to open
+%D - a list of directories
+%i - the icon
+%m - the mini-icon
+%c - the caption</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="2" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>commandEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Type the command to start this application here.
+
+Following the command, you can have several place holders which will be replaced with the actual values when the actual program is run:
+%f - a single file name
+%F - a list of files; use for applications that can open several local files at once
+%u - a single URL
+%U - a list of URLs
+%d - the directory of the file to open
+%D - a list of directories
+%i - the icon
+%m - the mini-icon
+%c - the caption</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="3" column="6">
+ <property name="name">
+ <cstring>browseButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Browse...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to browse your file system in order to find the desired executable.</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Work path:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>pathEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Sets the working directory for your application.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="4" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>pathEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Sets the working directory for your application.</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="8" column="0">
+ <property name="name">
+ <cstring>addFiletypeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click on this button if you want to add a type of file (mimetype) that your application can handle.</string>
+ </property>
+ </widget>
+ <spacer row="8" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer31_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>53</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton" row="8" column="3">
+ <property name="name">
+ <cstring>delFiletypeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you want to remove a type of file (mimetype) that your application cannot handle, select the mimetype in the list above and click on this button.</string>
+ </property>
+ </widget>
+ <spacer row="8" column="4">
+ <property name="name">
+ <cstring>spacer31_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>53</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton" row="8" column="5" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>advancedButton</cstring>
+ </property>
+ <property name="text">
+ <string>Ad&amp;vanced Options</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to modify the way this application will run, launch feedback, DCOP options or to run it as a different user.</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/tdeio/tdefile/kpropertiesdialog.cpp b/tdeio/tdefile/kpropertiesdialog.cpp
new file mode 100644
index 000000000..a76fdc336
--- /dev/null
+++ b/tdeio/tdefile/kpropertiesdialog.cpp
@@ -0,0 +1,4170 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org>
+ Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (c) 2000 David Faure <faure@kde.org>
+ Copyright (c) 2003 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.
+*/
+
+/*
+ * kpropertiesdialog.cpp
+ * View/Edit Properties of files, locally or remotely
+ *
+ * some FilePermissionsPropsPlugin-changes by
+ * Henner Zeller <zeller@think.de>
+ * some layout management by
+ * Bertrand Leconte <B.Leconte@mail.dotcom.fr>
+ * the rest of the layout management, bug fixes, adaptation to libtdeio,
+ * template feature by
+ * David Faure <faure@kde.org>
+ * More layout, cleanups, and fixes by
+ * Preston Brown <pbrown@kde.org>
+ * Plugin capability, cleanups and port to KDialogBase by
+ * Simon Hausmann <hausmann@kde.org>
+ * KDesktopPropsPlugin by
+ * Waldo Bastian <bastian@kde.org>
+ */
+
+#include <config.h>
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <sys/types.h>
+}
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqcheckbox.h>
+#include <tqstrlist.h>
+#include <tqstringlist.h>
+#include <tqtextstream.h>
+#include <tqpainter.h>
+#include <tqlayout.h>
+#include <tqcombobox.h>
+#include <tqgroupbox.h>
+#include <tqwhatsthis.h>
+#include <tqtooltip.h>
+#include <tqstyle.h>
+#include <tqprogressbar.h>
+#include <tqvbox.h>
+#include <tqvaluevector.h>
+
+#ifdef USE_POSIX_ACL
+extern "C" {
+#include <sys/param.h>
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+}
+#endif
+
+#include <kapplication.h>
+#include <kdialog.h>
+#include <kdirsize.h>
+#include <kdirwatch.h>
+#include <kdirnotify_stub.h>
+#include <kdiskfreesp.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kicondialog.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <tdeio/job.h>
+#include <tdeio/chmodjob.h>
+#include <tdeio/renamedlg.h>
+#include <tdeio/netaccess.h>
+#include <tdeio/kservicetypefactory.h>
+#include <tdefiledialog.h>
+#include <kmimetype.h>
+#include <kmountpoint.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kservice.h>
+#include <kcompletion.h>
+#include <klineedit.h>
+#include <kseparator.h>
+#include <ksqueezedtextlabel.h>
+#include <klibloader.h>
+#include <ktrader.h>
+#include <tdeparts/componentfactory.h>
+#include <kmetaprops.h>
+#include <kpreviewprops.h>
+#include <kprocess.h>
+#include <krun.h>
+#include <klistview.h>
+#include <kacl.h>
+#include "tdefilesharedlg.h"
+
+#include "kpropertiesdesktopbase.h"
+#include "kpropertiesdesktopadvbase.h"
+#include "kpropertiesmimetypebase.h"
+#ifdef USE_POSIX_ACL
+#include "kacleditwidget.h"
+#endif
+
+#include "kpropertiesdialog.h"
+
+#ifdef Q_WS_WIN
+# include <win32_utils.h>
+#endif
+
+static TQString nameFromFileName(TQString nameStr)
+{
+ if ( nameStr.endsWith(".desktop") )
+ nameStr.truncate( nameStr.length() - 8 );
+ if ( nameStr.endsWith(".kdelnk") )
+ nameStr.truncate( nameStr.length() - 7 );
+ // Make it human-readable (%2F => '/', ...)
+ nameStr = TDEIO::decodeFileName( nameStr );
+ return nameStr;
+}
+
+mode_t KFilePermissionsPropsPlugin::fperm[3][4] = {
+ {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID},
+ {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID},
+ {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX}
+ };
+
+class KPropertiesDialog::KPropertiesDialogPrivate
+{
+public:
+ KPropertiesDialogPrivate()
+ {
+ m_aborted = false;
+ fileSharePage = 0;
+ }
+ ~KPropertiesDialogPrivate()
+ {
+ }
+ bool m_aborted:1;
+ TQWidget* fileSharePage;
+};
+
+KPropertiesDialog::KPropertiesDialog (KFileItem* item,
+ TQWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(TDEIO::decodeFileName(item->url().fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+ assert( item );
+ m_items.append( new KFileItem(*item) ); // deep copy
+
+ m_singleUrl = item->url();
+ assert(!m_singleUrl.isEmpty());
+
+ init (modal, autoShow);
+}
+
+KPropertiesDialog::KPropertiesDialog (const TQString& title,
+ TQWidget* parent, const char* name, bool modal)
+ : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+
+ init (modal, false);
+}
+
+KPropertiesDialog::KPropertiesDialog (KFileItemList _items,
+ TQWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ // TODO: replace <never used> with "Properties for 1 item". It's very confusing how it has to be translated otherwise
+ // (empty translation before the "\n" is not allowed by msgfmt...)
+ _items.count()>1 ? i18n( "<never used>","Properties for %n Selected Items",_items.count()) :
+ i18n( "Properties for %1" ).arg(TDEIO::decodeFileName(_items.first()->url().fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal)
+{
+ d = new KPropertiesDialogPrivate;
+
+ assert( !_items.isEmpty() );
+ m_singleUrl = _items.first()->url();
+ assert(!m_singleUrl.isEmpty());
+
+ KFileItemListIterator it ( _items );
+ // Deep copy
+ for ( ; it.current(); ++it )
+ m_items.append( new KFileItem( **it ) );
+
+ init (modal, autoShow);
+}
+
+#ifndef KDE_NO_COMPAT
+KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */,
+ TQWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(TDEIO::decodeFileName(_url.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+ m_singleUrl( _url )
+{
+ d = new KPropertiesDialogPrivate;
+
+ TDEIO::UDSEntry entry;
+
+ TDEIO::NetAccess::stat(_url, entry, parent);
+
+ m_items.append( new KFileItem( entry, _url ) );
+ init (modal, autoShow);
+}
+#endif
+
+KPropertiesDialog::KPropertiesDialog (const KURL& _url,
+ TQWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(TDEIO::decodeFileName(_url.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+ m_singleUrl( _url )
+{
+ d = new KPropertiesDialogPrivate;
+
+ TDEIO::UDSEntry entry;
+
+ TDEIO::NetAccess::stat(_url, entry, parent);
+
+ m_items.append( new KFileItem( entry, _url ) );
+ init (modal, autoShow);
+}
+
+KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir,
+ const TQString& _defaultName,
+ TQWidget* parent, const char* name,
+ bool modal, bool autoShow)
+ : KDialogBase (KDialogBase::Tabbed,
+ i18n( "Properties for %1" ).arg(TDEIO::decodeFileName(_tempUrl.fileName())),
+ KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
+ parent, name, modal),
+
+ m_singleUrl( _tempUrl ),
+ m_defaultName( _defaultName ),
+ m_currentDir( _currentDir )
+{
+ d = new KPropertiesDialogPrivate;
+
+ assert(!m_singleUrl.isEmpty());
+
+ // Create the KFileItem for the _template_ file, in order to read from it.
+ m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) );
+ init (modal, autoShow);
+}
+
+bool KPropertiesDialog::showDialog(KFileItem* item, TQWidget* parent,
+ const char* name, bool modal)
+{
+#ifdef Q_WS_WIN
+ TQString localPath = item->localPath();
+ if (!localPath.isEmpty())
+ return showWin32FilePropertyDialog(localPath);
+#endif
+ new KPropertiesDialog(item, parent, name, modal);
+ return true;
+}
+
+bool KPropertiesDialog::showDialog(const KURL& _url, TQWidget* parent,
+ const char* name, bool modal)
+{
+#ifdef Q_WS_WIN
+ if (_url.isLocalFile())
+ return showWin32FilePropertyDialog( _url.path() );
+#endif
+ new KPropertiesDialog(_url, parent, name, modal);
+ return true;
+}
+
+bool KPropertiesDialog::showDialog(const KFileItemList& _items, TQWidget* parent,
+ const char* name, bool modal)
+{
+ if (_items.count()==1)
+ return KPropertiesDialog::showDialog(_items.getFirst(), parent, name, modal);
+ new KPropertiesDialog(_items, parent, name, modal);
+ return true;
+}
+
+void KPropertiesDialog::init (bool modal, bool autoShow)
+{
+ m_pageList.setAutoDelete( true );
+ m_items.setAutoDelete( true );
+
+ insertPages();
+
+ if (autoShow)
+ {
+ if (!modal)
+ show();
+ else
+ exec();
+ }
+}
+
+void KPropertiesDialog::showFileSharingPage()
+{
+ if (d->fileSharePage) {
+ showPage( pageIndex( d->fileSharePage));
+ }
+}
+
+void KPropertiesDialog::setFileSharingPage(TQWidget* page) {
+ d->fileSharePage = page;
+}
+
+
+void KPropertiesDialog::setFileNameReadOnly( bool ro )
+{
+ KPropsDlgPlugin *it;
+
+ for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() )
+ {
+ KFilePropsPlugin* plugin = dynamic_cast<KFilePropsPlugin*>(it);
+ if ( plugin ) {
+ plugin->setFileNameReadOnly( ro );
+ break;
+ }
+ }
+}
+
+void KPropertiesDialog::slotStatResult( TDEIO::Job * )
+{
+}
+
+KPropertiesDialog::~KPropertiesDialog()
+{
+ m_pageList.clear();
+ delete d;
+}
+
+void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin)
+{
+ connect (plugin, TQT_SIGNAL (changed ()),
+ plugin, TQT_SLOT (setDirty ()));
+
+ m_pageList.append (plugin);
+}
+
+bool KPropertiesDialog::canDisplay( KFileItemList _items )
+{
+ // TODO: cache the result of those calls. Currently we parse .desktop files far too many times
+ return KFilePropsPlugin::supports( _items ) ||
+ KFilePermissionsPropsPlugin::supports( _items ) ||
+ KDesktopPropsPlugin::supports( _items ) ||
+ KBindingPropsPlugin::supports( _items ) ||
+ KURLPropsPlugin::supports( _items ) ||
+ KDevicePropsPlugin::supports( _items ) ||
+ KFileMetaPropsPlugin::supports( _items ) ||
+ KPreviewPropsPlugin::supports( _items );
+}
+
+void KPropertiesDialog::slotOk()
+{
+ KPropsDlgPlugin *page;
+ d->m_aborted = false;
+
+ KFilePropsPlugin * filePropsPlugin = 0L;
+ if ( m_pageList.first()->isA("KFilePropsPlugin") )
+ filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first());
+
+ // If any page is dirty, then set the main one (KFilePropsPlugin) as
+ // dirty too. This is what makes it possible to save changes to a global
+ // desktop file into a local one. In other cases, it doesn't hurt.
+ for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() )
+ if ( page->isDirty() && filePropsPlugin )
+ {
+ filePropsPlugin->setDirty();
+ break;
+ }
+
+ // Apply the changes in the _normal_ order of the tabs now
+ // This is because in case of renaming a file, KFilePropsPlugin will call
+ // KPropertiesDialog::rename, so other tab will be ok with whatever order
+ // BUT for file copied from templates, we need to do the renaming first !
+ for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() )
+ if ( page->isDirty() )
+ {
+ kdDebug( 250 ) << "applying changes for " << page->className() << endl;
+ page->applyChanges();
+ // applyChanges may change d->m_aborted.
+ }
+ else
+ kdDebug( 250 ) << "skipping page " << page->className() << endl;
+
+ if ( !d->m_aborted && filePropsPlugin )
+ filePropsPlugin->postApplyChanges();
+
+ if ( !d->m_aborted )
+ {
+ emit applied();
+ emit propertiesClosed();
+ deleteLater();
+ accept();
+ } // else, keep dialog open for user to fix the problem.
+}
+
+void KPropertiesDialog::slotCancel()
+{
+ emit canceled();
+ emit propertiesClosed();
+
+ deleteLater();
+ done( Rejected );
+}
+
+void KPropertiesDialog::insertPages()
+{
+ if (m_items.isEmpty())
+ return;
+
+ if ( KFilePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFilePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KFilePermissionsPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KDesktopPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KDesktopPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KBindingPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KBindingPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KURLPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KURLPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KDevicePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KDevicePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KFileMetaPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( KPreviewPropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KPreviewPropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ if ( kapp->authorizeKAction("sharefile") &&
+ KFileSharePropsPlugin::supports( m_items ) )
+ {
+ KPropsDlgPlugin *p = new KFileSharePropsPlugin( this );
+ insertPlugin (p);
+ }
+
+ //plugins
+
+ if ( m_items.count() != 1 )
+ return;
+
+ KFileItem *item = m_items.first();
+ TQString mimetype = item->mimetype();
+
+ if ( mimetype.isEmpty() )
+ return;
+
+ TQString query = TQString::fromLatin1(
+ "('KPropsDlg/Plugin' in ServiceTypes) and "
+ "((not exist [X-TDE-Protocol]) or "
+ " ([X-TDE-Protocol] == '%1' ) )" ).arg(item->url().protocol());
+
+ kdDebug( 250 ) << "trader query: " << query << endl;
+ KTrader::OfferList offers = KTrader::self()->query( mimetype, query );
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+ for (; it != end; ++it )
+ {
+ KPropsDlgPlugin *plugin = KParts::ComponentFactory
+ ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(),
+ TQT_TQOBJECT(this),
+ (*it)->name().latin1() );
+ if ( !plugin )
+ continue;
+
+ insertPlugin( plugin );
+ }
+}
+
+void KPropertiesDialog::updateUrl( const KURL& _newUrl )
+{
+ Q_ASSERT( m_items.count() == 1 );
+ kdDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl.url() << endl;
+ KURL newUrl = _newUrl;
+ emit saveAs(m_singleUrl, newUrl);
+ kdDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl.url() << endl;
+
+ m_singleUrl = newUrl;
+ m_items.first()->setURL( newUrl );
+ assert(!m_singleUrl.isEmpty());
+ // If we have an Desktop page, set it dirty, so that a full file is saved locally
+ // Same for a URL page (because of the Name= hack)
+ for ( TQPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it )
+ if ( it.current()->isA("KExecPropsPlugin") || // KDE4 remove me
+ it.current()->isA("KURLPropsPlugin") ||
+ it.current()->isA("KDesktopPropsPlugin"))
+ {
+ //kdDebug(250) << "Setting page dirty" << endl;
+ it.current()->setDirty();
+ break;
+ }
+}
+
+void KPropertiesDialog::rename( const TQString& _name )
+{
+ Q_ASSERT( m_items.count() == 1 );
+ kdDebug(250) << "KPropertiesDialog::rename " << _name << endl;
+ KURL newUrl;
+ // if we're creating from a template : use currentdir
+ if ( !m_currentDir.isEmpty() )
+ {
+ newUrl = m_currentDir;
+ newUrl.addPath( _name );
+ }
+ else
+ {
+ TQString tmpurl = m_singleUrl.url();
+ if ( tmpurl.at(tmpurl.length() - 1) == '/')
+ // It's a directory, so strip the trailing slash first
+ tmpurl.truncate( tmpurl.length() - 1);
+ newUrl = tmpurl;
+ newUrl.setFileName( _name );
+ }
+ updateUrl( newUrl );
+}
+
+void KPropertiesDialog::abortApplying()
+{
+ d->m_aborted = true;
+}
+
+class KPropsDlgPlugin::KPropsDlgPluginPrivate
+{
+public:
+ KPropsDlgPluginPrivate()
+ {
+ }
+ ~KPropsDlgPluginPrivate()
+ {
+ }
+
+ bool m_bDirty;
+};
+
+KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props )
+: TQObject( _props, 0L )
+{
+ d = new KPropsDlgPluginPrivate;
+ properties = _props;
+ fontHeight = 2*properties->fontMetrics().height();
+ d->m_bDirty = false;
+}
+
+KPropsDlgPlugin::~KPropsDlgPlugin()
+{
+ delete d;
+}
+
+bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item )
+{
+ // only local files
+ bool isLocal;
+ KURL url = _item->mostLocalURL( isLocal );
+ if ( !isLocal )
+ return false;
+
+ // only regular files
+ if ( !S_ISREG( _item->mode() ) )
+ return false;
+
+ TQString t( url.path() );
+
+ // only if readable
+ FILE *f = fopen( TQFile::encodeName(t), "r" );
+ if ( f == 0L )
+ return false;
+ fclose(f);
+
+ // return true if desktop file
+ return ( (_item->mimetype() == "application/x-desktop")
+ || (_item->mimetype() == "media/builtin-mydocuments")
+ || (_item->mimetype() == "media/builtin-mycomputer")
+ || (_item->mimetype() == "media/builtin-mynetworkplaces")
+ || (_item->mimetype() == "media/builtin-printers")
+ || (_item->mimetype() == "media/builtin-trash")
+ || (_item->mimetype() == "media/builtin-webbrowser") );
+}
+
+void KPropsDlgPlugin::setDirty( bool b )
+{
+ d->m_bDirty = b;
+}
+
+void KPropsDlgPlugin::setDirty()
+{
+ d->m_bDirty = true;
+}
+
+bool KPropsDlgPlugin::isDirty() const
+{
+ return d->m_bDirty;
+}
+
+void KPropsDlgPlugin::applyChanges()
+{
+ kdWarning(250) << "applyChanges() not implemented in page !" << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class KFilePropsPlugin::KFilePropsPluginPrivate
+{
+public:
+ KFilePropsPluginPrivate()
+ {
+ dirSizeJob = 0L;
+ dirSizeUpdateTimer = 0L;
+ m_lined = 0;
+ m_freeSpaceLabel = 0;
+ }
+ ~KFilePropsPluginPrivate()
+ {
+ if ( dirSizeJob )
+ dirSizeJob->kill();
+ }
+
+ KDirSize * dirSizeJob;
+ TQTimer *dirSizeUpdateTimer;
+ TQFrame *m_frame;
+ bool bMultiple;
+ bool bIconChanged;
+ bool bKDesktopMode;
+ bool bDesktopFile;
+ TQLabel *m_freeSpaceLabel;
+ TQString mimeType;
+ TQString oldFileName;
+ KLineEdit* m_lined;
+};
+
+KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KFilePropsPluginPrivate;
+ d->bMultiple = (properties->items().count() > 1);
+ d->bIconChanged = false;
+ d->bKDesktopMode = (TQCString(tqApp->name()) == "kdesktop"); // nasty heh?
+ d->bDesktopFile = KDesktopPropsPlugin::supports(properties->items());
+ kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl;
+
+ // We set this data from the first item, and we'll
+ // check that the other items match against it, resetting when not.
+ bool isLocal;
+ KFileItem * item = properties->item();
+ KURL url = item->mostLocalURL( isLocal );
+ bool isReallyLocal = item->url().isLocalFile();
+ bool bDesktopFile = isDesktopFile(item);
+ kdDebug() << "url=" << url << " bDesktopFile=" << bDesktopFile << " isLocal=" << isLocal << " isReallyLocal=" << isReallyLocal << endl;
+ mode_t mode = item->mode();
+ bool hasDirs = item->isDir() && !item->isLink();
+ bool hasRoot = url.path() == TQString::fromLatin1("/");
+ TQString iconStr = KMimeType::iconForURL(url, mode);
+ TQString directory = properties->kurl().directory();
+ TQString protocol = properties->kurl().protocol();
+ TQString mimeComment = item->mimeComment();
+ d->mimeType = item->mimetype();
+ bool hasTotalSize;
+ TDEIO::filesize_t totalSize = item->size(hasTotalSize);
+ TQString magicMimeComment;
+ if ( isLocal ) {
+ KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
+ if ( magicMimeType->name() != KMimeType::defaultMimeType() )
+ magicMimeComment = magicMimeType->comment();
+ }
+
+ // Those things only apply to 'single file' mode
+ TQString filename = TQString::null;
+ bool isTrash = false;
+ bool isDevice = false;
+ m_bFromTemplate = false;
+
+ // And those only to 'multiple' mode
+ uint iDirCount = hasDirs ? 1 : 0;
+ uint iFileCount = 1-iDirCount;
+
+ d->m_frame = properties->addPage (i18n("&General"));
+
+ TQVBoxLayout *vbl = new TQVBoxLayout( d->m_frame, 0,
+ KDialog::spacingHint(), "vbl");
+ TQGridLayout *grid = new TQGridLayout(0, 3); // unknown rows
+ grid->setColStretch(0, 0);
+ grid->setColStretch(1, 0);
+ grid->setColStretch(2, 1);
+ grid->addColSpacing(1, KDialog::spacingHint());
+ vbl->addLayout(TQT_TQLAYOUT(grid));
+ int curRow = 0;
+
+ if ( !d->bMultiple )
+ {
+ TQString path;
+ if ( !m_bFromTemplate ) {
+ isTrash = ( properties->kurl().protocol().find( "trash", 0, false)==0 );
+ if ( properties->kurl().protocol().find("device", 0, false)==0)
+ isDevice = true;
+ // Extract the full name, but without file: for local files
+ if ( isReallyLocal )
+ path = properties->kurl().path();
+ else
+ path = properties->kurl().prettyURL();
+ } else {
+ path = properties->currentDir().path(1) + properties->defaultName();
+ directory = properties->currentDir().prettyURL();
+ }
+
+ if (KExecPropsPlugin::supports(properties->items()) || // KDE4 remove me
+ d->bDesktopFile ||
+ KBindingPropsPlugin::supports(properties->items())) {
+ determineRelativePath( path );
+ }
+
+ // Extract the file name only
+ filename = properties->defaultName();
+ if ( filename.isEmpty() ) { // no template
+ filename = item->name(); // this gives support for UDS_NAME, e.g. for kio_trash or kio_system
+ } else {
+ m_bFromTemplate = true;
+ setDirty(); // to enforce that the copy happens
+ }
+ d->oldFileName = filename;
+
+ // Make it human-readable
+ filename = nameFromFileName( filename );
+
+ if ( d->bKDesktopMode && d->bDesktopFile ) {
+ KDesktopFile config( url.path(), true /* readonly */ );
+ if ( config.hasKey( "Name" ) ) {
+ filename = config.readName();
+ }
+ }
+
+ oldName = filename;
+ }
+ else
+ {
+ // Multiple items: see what they have in common
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
+ {
+ KURL url = (*it)->url();
+ kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl;
+ // The list of things we check here should match the variables defined
+ // at the beginning of this method.
+ if ( url.isLocalFile() != isLocal )
+ isLocal = false; // not all local
+ if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile )
+ bDesktopFile = false; // not all desktop files
+ if ( (*it)->mode() != mode )
+ mode = (mode_t)0;
+ if ( KMimeType::iconForURL(url, mode) != iconStr )
+ iconStr = "tdemultiple";
+ if ( url.directory() != directory )
+ directory = TQString::null;
+ if ( url.protocol() != protocol )
+ protocol = TQString::null;
+ if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment )
+ mimeComment = TQString::null;
+ if ( isLocal && !magicMimeComment.isNull() ) {
+ KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
+ if ( magicMimeType->comment() != magicMimeComment )
+ magicMimeComment = TQString::null;
+ }
+
+ if ( url.path() == TQString::fromLatin1("/") )
+ hasRoot = true;
+ if ( (*it)->isDir() && !(*it)->isLink() )
+ {
+ iDirCount++;
+ hasDirs = true;
+ }
+ else
+ {
+ iFileCount++;
+ bool hasSize;
+ totalSize += (*it)->size(hasSize);
+ hasTotalSize = hasTotalSize || hasSize;
+ }
+ }
+ }
+
+ if (!isReallyLocal && !protocol.isEmpty())
+ {
+ directory += ' ';
+ directory += '(';
+ directory += protocol;
+ directory += ')';
+ }
+
+ if ( !isDevice && !isTrash && (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ )
+ {
+ KIconButton *iconButton = new KIconButton( d->m_frame );
+ int bsize = 66 + 2 * iconButton->style().pixelMetric(TQStyle::PM_ButtonMargin);
+ iconButton->setFixedSize(bsize, bsize);
+ iconButton->setIconSize(48);
+ iconButton->setStrictIconSize(false);
+ // This works for everything except Device icons on unmounted devices
+ // So we have to really open .desktop files
+ TQString iconStr = KMimeType::findByURL( url, mode )->icon( url, isLocal );
+ if ( bDesktopFile && isLocal )
+ {
+ KDesktopFile config( url.path(), true );
+ config.setDesktopGroup();
+ iconStr = config.readEntry( "Icon" );
+ if ( config.hasDeviceType() )
+ iconButton->setIconType( KIcon::Desktop, KIcon::Device );
+ else
+ iconButton->setIconType( KIcon::Desktop, KIcon::Application );
+ } else
+ iconButton->setIconType( KIcon::Desktop, KIcon::Place );
+ iconButton->setIcon(iconStr);
+ iconArea = iconButton;
+ connect( iconButton, TQT_SIGNAL( iconChanged(TQString) ),
+ this, TQT_SLOT( slotIconChanged() ) );
+ } else {
+ TQLabel *iconLabel = new TQLabel( d->m_frame );
+ int bsize = 66 + 2 * iconLabel->style().pixelMetric(TQStyle::PM_ButtonMargin);
+ iconLabel->setFixedSize(bsize, bsize);
+ iconLabel->setPixmap( TDEGlobal::iconLoader()->loadIcon( iconStr, KIcon::Desktop, 48) );
+ iconArea = iconLabel;
+ }
+ grid->addWidget(iconArea, curRow, 0, Qt::AlignLeft);
+
+ if (d->bMultiple || isTrash || isDevice || hasRoot)
+ {
+ TQLabel *lab = new TQLabel(d->m_frame );
+ if ( d->bMultiple )
+ lab->setText( TDEIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) );
+ else
+ lab->setText( filename );
+ nameArea = lab;
+ } else
+ {
+ d->m_lined = new KLineEdit( d->m_frame );
+ d->m_lined->setText(filename);
+ nameArea = d->m_lined;
+ d->m_lined->setFocus();
+
+ // Enhanced rename: Don't highlight the file extension.
+ TQString pattern;
+ KServiceTypeFactory::self()->findFromPattern( filename, &pattern );
+ if (!pattern.isEmpty() && pattern.at(0)=='*' && pattern.find('*',1)==-1)
+ d->m_lined->setSelection(0, filename.length()-pattern.stripWhiteSpace().length()+1);
+ else
+ {
+ int lastDot = filename.findRev('.');
+ if (lastDot > 0)
+ d->m_lined->setSelection(0, lastDot);
+ }
+
+ connect( d->m_lined, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SLOT( nameFileChanged(const TQString & ) ) );
+ }
+
+ grid->addWidget(nameArea, curRow++, 2);
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
+ ++curRow;
+
+ TQLabel *l;
+ if ( !mimeComment.isEmpty() && !isDevice && !isTrash)
+ {
+ l = new TQLabel(i18n("Type:"), d->m_frame );
+
+ grid->addWidget(l, curRow, 0);
+
+ TQHBox *box = new TQHBox(d->m_frame);
+ box->setSpacing(20);
+ l = new TQLabel(mimeComment, box );
+
+#ifdef Q_WS_X11
+ //TODO: wrap for win32 or mac?
+ TQPushButton *button = new TQPushButton(box);
+
+ TQIconSet iconSet = SmallIconSet(TQString::fromLatin1("configure"));
+ TQPixmap pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal );
+ button->setIconSet( iconSet );
+ button->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ if ( d->mimeType == KMimeType::defaultMimeType() )
+ TQToolTip::add(button, i18n("Create new file type"));
+ else
+ TQToolTip::add(button, i18n("Edit file type"));
+
+ connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEditFileType() ));
+
+ if (!kapp->authorizeKAction("editfiletype"))
+ button->hide();
+#endif
+
+ grid->addWidget(box, curRow++, 2);
+ }
+
+ if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment )
+ {
+ l = new TQLabel(i18n("Contents:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new TQLabel(magicMimeComment, d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if ( !directory.isEmpty() )
+ {
+ l = new TQLabel( i18n("Location:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel( d->m_frame );
+ l->setText( directory );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if( hasDirs || hasTotalSize ) {
+ l = new TQLabel(i18n("Size:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ m_sizeLabel = new TQLabel( d->m_frame );
+ grid->addWidget( m_sizeLabel, curRow++, 2 );
+ } else {
+ m_sizeLabel = 0;
+ }
+
+ if ( !hasDirs ) // Only files [and symlinks]
+ {
+ if(hasTotalSize) {
+ m_sizeLabel->setText(TDEIO::convertSizeWithBytes(totalSize));
+ }
+
+ m_sizeDetermineButton = 0L;
+ m_sizeStopButton = 0L;
+ }
+ else // Directory
+ {
+ TQHBoxLayout * sizelay = new TQHBoxLayout(KDialog::spacingHint());
+ grid->addLayout( sizelay, curRow++, 2 );
+
+ // buttons
+ m_sizeDetermineButton = new TQPushButton( i18n("Calculate"), d->m_frame );
+ m_sizeStopButton = new TQPushButton( i18n("Stop"), d->m_frame );
+ connect( m_sizeDetermineButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSizeDetermine() ) );
+ connect( m_sizeStopButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSizeStop() ) );
+ sizelay->addWidget(m_sizeDetermineButton, 0);
+ sizelay->addWidget(m_sizeStopButton, 0);
+ sizelay->addStretch(10); // so that the buttons don't grow horizontally
+
+ // auto-launch for local dirs only, and not for '/'
+ if ( isLocal && !hasRoot )
+ {
+ m_sizeDetermineButton->setText( i18n("Refresh") );
+ slotSizeDetermine();
+ }
+ else
+ m_sizeStopButton->setEnabled( false );
+ }
+
+ if (!d->bMultiple && item->isLink()) {
+ l = new TQLabel(i18n("Points to:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel(item->linkDest(), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ if (!d->bMultiple) // Dates for multiple don't make much sense...
+ {
+ TQDateTime dt;
+ bool hasTime;
+ time_t tim = item->time(TDEIO::UDS_CREATION_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new TQLabel(i18n("Created:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new TQLabel(TDEGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ tim = item->time(TDEIO::UDS_MODIFICATION_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new TQLabel(i18n("Modified:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new TQLabel(TDEGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+
+ tim = item->time(TDEIO::UDS_ACCESS_TIME, hasTime);
+ if ( hasTime )
+ {
+ l = new TQLabel(i18n("Accessed:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ dt.setTime_t( tim );
+ l = new TQLabel(TDEGlobal::locale()->formatDateTime(dt), d->m_frame );
+ grid->addWidget(l, curRow++, 2);
+ }
+ }
+
+ if ( isLocal && hasDirs ) // only for directories
+ {
+ sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
+ ++curRow;
+
+ TQString mountPoint = TDEIO::findPathMountPoint( url.path() );
+
+ if (mountPoint != "/")
+ {
+ l = new TQLabel(i18n("Mounted on:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ l = new KSqueezedTextLabel( mountPoint, d->m_frame );
+ grid->addWidget( l, curRow++, 2 );
+ }
+
+ l = new TQLabel(i18n("Free disk space:"), d->m_frame );
+ grid->addWidget(l, curRow, 0);
+
+ d->m_freeSpaceLabel = new TQLabel( d->m_frame );
+ grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 );
+
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ),
+ this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ) );
+ job->readDF( mountPoint );
+ }
+
+ vbl->addStretch(1);
+}
+
+// TQString KFilePropsPlugin::tabName () const
+// {
+// return i18n ("&General");
+// }
+
+void KFilePropsPlugin::setFileNameReadOnly( bool ro )
+{
+ if ( d->m_lined )
+ {
+ d->m_lined->setReadOnly( ro );
+ if (ro)
+ {
+ // Don't put the initial focus on the line edit when it is ro
+ TQPushButton *button = properties->actionButton(KDialogBase::Ok);
+ if (button)
+ button->setFocus();
+ }
+ }
+}
+
+void KFilePropsPlugin::slotEditFileType()
+{
+#ifdef Q_WS_X11
+ TQString mime;
+ if ( d->mimeType == KMimeType::defaultMimeType() ) {
+ int pos = d->oldFileName.findRev( '.' );
+ if ( pos != -1 )
+ mime = "*" + d->oldFileName.mid(pos);
+ else
+ mime = "*";
+ }
+ else
+ mime = d->mimeType;
+ //TODO: wrap for win32 or mac?
+ TQString keditfiletype = TQString::fromLatin1("keditfiletype");
+ KRun::runCommand( keditfiletype
+ + " --parent " + TQString::number( (ulong)properties->topLevelWidget()->winId())
+ + " " + TDEProcess::quote(mime),
+ keditfiletype, keditfiletype /*unused*/);
+#endif
+}
+
+void KFilePropsPlugin::slotIconChanged()
+{
+ d->bIconChanged = true;
+ emit changed();
+}
+
+void KFilePropsPlugin::nameFileChanged(const TQString &text )
+{
+ properties->enableButtonOK(!text.isEmpty());
+ emit changed();
+}
+
+void KFilePropsPlugin::determineRelativePath( const TQString & path )
+{
+ // now let's make it relative
+ TQStringList dirs;
+ if (KBindingPropsPlugin::supports(properties->items()))
+ {
+ m_sRelativePath =TDEGlobal::dirs()->relativeLocation("mime", path);
+ if (m_sRelativePath.startsWith("/"))
+ m_sRelativePath = TQString::null;
+ }
+ else
+ {
+ m_sRelativePath =TDEGlobal::dirs()->relativeLocation("apps", path);
+ if (m_sRelativePath.startsWith("/"))
+ {
+ m_sRelativePath =TDEGlobal::dirs()->relativeLocation("xdgdata-apps", path);
+ if (m_sRelativePath.startsWith("/"))
+ m_sRelativePath = TQString::null;
+ else
+ m_sRelativePath = path;
+ }
+ }
+ if ( m_sRelativePath.isEmpty() )
+ {
+ if (KBindingPropsPlugin::supports(properties->items()))
+ kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl;
+ }
+}
+
+void KFilePropsPlugin::slotFoundMountPoint( const TQString&,
+ unsigned long kBSize,
+ unsigned long /*kBUsed*/,
+ unsigned long kBAvail )
+{
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(TDEIO::convertSizeFromKB(kBAvail))
+ .arg(TDEIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+}
+
+// attention: copy&paste below, due to compiler bug
+// it doesn't like those unsigned long parameters -- unsigned long& are ok :-/
+void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const TQString& )
+{
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(TDEIO::convertSizeFromKB(kBAvail))
+ .arg(TDEIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+}
+
+void KFilePropsPlugin::slotDirSizeUpdate()
+{
+ TDEIO::filesize_t totalSize = d->dirSizeJob->totalSize();
+ TDEIO::filesize_t totalFiles = d->dirSizeJob->totalFiles();
+ TDEIO::filesize_t totalSubdirs = d->dirSizeJob->totalSubdirs();
+ m_sizeLabel->setText( i18n("Calculating... %1 (%2)\n%3, %4")
+ .arg(TDEIO::convertSize(totalSize))
+ .arg(TDEGlobal::locale()->formatNumber(totalSize, 0))
+ .arg(i18n("1 file","%n files",totalFiles))
+ .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
+}
+
+void KFilePropsPlugin::slotDirSizeFinished( TDEIO::Job * job )
+{
+ if (job->error())
+ m_sizeLabel->setText( job->errorString() );
+ else
+ {
+ TDEIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize();
+ TDEIO::filesize_t totalFiles = static_cast<KDirSize*>(job)->totalFiles();
+ TDEIO::filesize_t totalSubdirs = static_cast<KDirSize*>(job)->totalSubdirs();
+ m_sizeLabel->setText( TQString::fromLatin1("%1 (%2)\n%3, %4")
+ .arg(TDEIO::convertSize(totalSize))
+ .arg(TDEGlobal::locale()->formatNumber(totalSize, 0))
+ .arg(i18n("1 file","%n files",totalFiles))
+ .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
+ }
+ m_sizeStopButton->setEnabled(false);
+ // just in case you change something and try again :)
+ m_sizeDetermineButton->setText( i18n("Refresh") );
+ m_sizeDetermineButton->setEnabled(true);
+ d->dirSizeJob = 0L;
+ delete d->dirSizeUpdateTimer;
+ d->dirSizeUpdateTimer = 0L;
+}
+
+void KFilePropsPlugin::slotSizeDetermine()
+{
+ m_sizeLabel->setText( i18n("Calculating...") );
+ kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties->item() << endl;
+ kdDebug(250) << " URL=" << properties->item()->url().url() << endl;
+ d->dirSizeJob = KDirSize::dirSizeJob( properties->items() );
+ d->dirSizeUpdateTimer = new TQTimer(this);
+ connect( d->dirSizeUpdateTimer, TQT_SIGNAL( timeout() ),
+ TQT_SLOT( slotDirSizeUpdate() ) );
+ d->dirSizeUpdateTimer->start(500);
+ connect( d->dirSizeJob, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotDirSizeFinished( TDEIO::Job * ) ) );
+ m_sizeStopButton->setEnabled(true);
+ m_sizeDetermineButton->setEnabled(false);
+
+ // also update the "Free disk space" display
+ if ( d->m_freeSpaceLabel )
+ {
+ bool isLocal;
+ KFileItem * item = properties->item();
+ KURL url = item->mostLocalURL( isLocal );
+ TQString mountPoint = TDEIO::findPathMountPoint( url.path() );
+
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ),
+ this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ) );
+ job->readDF( mountPoint );
+ }
+}
+
+void KFilePropsPlugin::slotSizeStop()
+{
+ if ( d->dirSizeJob )
+ {
+ m_sizeLabel->setText( i18n("Stopped") );
+ d->dirSizeJob->kill();
+ d->dirSizeJob = 0;
+ }
+ if ( d->dirSizeUpdateTimer )
+ d->dirSizeUpdateTimer->stop();
+
+ m_sizeStopButton->setEnabled(false);
+ m_sizeDetermineButton->setEnabled(true);
+}
+
+KFilePropsPlugin::~KFilePropsPlugin()
+{
+ delete d;
+}
+
+bool KFilePropsPlugin::supports( KFileItemList /*_items*/ )
+{
+ return true;
+}
+
+// Don't do this at home
+void tqt_enter_modal( TQWidget *widget );
+void tqt_leave_modal( TQWidget *widget );
+
+void KFilePropsPlugin::applyChanges()
+{
+ if ( d->dirSizeJob )
+ slotSizeStop();
+
+ kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl;
+
+ if (nameArea->inherits(TQLINEEDIT_OBJECT_NAME_STRING))
+ {
+ TQString n = ((TQLineEdit *) nameArea)->text();
+ // Remove trailing spaces (#4345)
+ while ( n[n.length()-1].isSpace() )
+ n.truncate( n.length() - 1 );
+ if ( n.isEmpty() )
+ {
+ KMessageBox::sorry( properties, i18n("The new file name is empty."));
+ properties->abortApplying();
+ return;
+ }
+
+ // Do we need to rename the file ?
+ kdDebug(250) << "oldname = " << oldName << endl;
+ kdDebug(250) << "newname = " << n << endl;
+ if ( oldName != n || m_bFromTemplate ) { // true for any from-template file
+ TDEIO::Job * job = 0L;
+ KURL oldurl = properties->kurl();
+
+ TQString newFileName = TDEIO::encodeFileName(n);
+ if (d->bDesktopFile && !newFileName.endsWith(".desktop") && !newFileName.endsWith(".kdelnk"))
+ newFileName += ".desktop";
+
+ // Tell properties. Warning, this changes the result of properties->kurl() !
+ properties->rename( newFileName );
+
+ // Update also relative path (for apps and mimetypes)
+ if ( !m_sRelativePath.isEmpty() )
+ determineRelativePath( properties->kurl().path() );
+
+ kdDebug(250) << "New URL = " << properties->kurl().url() << endl;
+ kdDebug(250) << "old = " << oldurl.url() << endl;
+
+ // Don't remove the template !!
+ if ( !m_bFromTemplate ) // (normal renaming)
+ job = TDEIO::move( oldurl, properties->kurl() );
+ else // Copying a template
+ job = TDEIO::copy( oldurl, properties->kurl() );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotCopyFinished( TDEIO::Job * ) ) );
+ connect( job, TQT_SIGNAL( renamed( TDEIO::Job *, const KURL &, const KURL & ) ),
+ TQT_SLOT( slotFileRenamed( TDEIO::Job *, const KURL &, const KURL & ) ) );
+ // wait for job
+ TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
+ tqt_enter_modal(&dummy);
+ tqApp->enter_loop();
+ tqt_leave_modal(&dummy);
+ return;
+ }
+ properties->updateUrl(properties->kurl());
+ // Update also relative path (for apps and mimetypes)
+ if ( !m_sRelativePath.isEmpty() )
+ determineRelativePath( properties->kurl().path() );
+ }
+
+ // No job, keep going
+ slotCopyFinished( 0L );
+}
+
+void KFilePropsPlugin::slotCopyFinished( TDEIO::Job * job )
+{
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl;
+ if (job)
+ {
+ // allow apply() to return
+ tqApp->exit_loop();
+ if ( job->error() )
+ {
+ job->showErrorDialog( d->m_frame );
+ // Didn't work. Revert the URL to the old one
+ properties->updateUrl( static_cast<TDEIO::CopyJob*>(job)->srcURLs().first() );
+ properties->abortApplying(); // Don't apply the changes to the wrong file !
+ return;
+ }
+ }
+
+ assert( properties->item() );
+ assert( !properties->item()->url().isEmpty() );
+
+ // Save the file where we can -> usually in ~/.trinity/...
+ if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
+ {
+ KURL newURL;
+ newURL.setPath( locateLocal("mime", m_sRelativePath) );
+ properties->updateUrl( newURL );
+ }
+ else if (d->bDesktopFile && !m_sRelativePath.isEmpty())
+ {
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl;
+ KURL newURL;
+ newURL.setPath( KDesktopFile::locateLocal(m_sRelativePath) );
+ kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl;
+ properties->updateUrl( newURL );
+ }
+
+ if ( d->bKDesktopMode && d->bDesktopFile ) {
+ // Renamed? Update Name field
+ if ( d->oldFileName != properties->kurl().fileName() || m_bFromTemplate ) {
+ KDesktopFile config( properties->kurl().path() );
+ TQString nameStr = nameFromFileName(properties->kurl().fileName());
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+ }
+ }
+}
+
+void KFilePropsPlugin::applyIconChanges()
+{
+ KIconButton *iconButton = ::tqqt_cast<KIconButton *>( iconArea );
+ if ( !iconButton || !d->bIconChanged )
+ return;
+ // handle icon changes - only local files (or pseudo-local) for now
+ // TODO: Use KTempFile and TDEIO::file_copy with overwrite = true
+ KURL url = properties->kurl();
+ url = TDEIO::NetAccess::mostLocalURL( url, properties );
+ if (url.isLocalFile()) {
+ TQString path;
+
+ if (S_ISDIR(properties->item()->mode()))
+ {
+ path = url.path(1) + TQString::fromLatin1(".directory");
+ // don't call updateUrl because the other tabs (i.e. permissions)
+ // apply to the directory, not the .directory file.
+ }
+ else
+ path = url.path();
+
+ // Get the default image
+ TQString str = KMimeType::findByURL( url,
+ properties->item()->mode(),
+ true )->KServiceType::icon();
+ // Is it another one than the default ?
+ TQString sIcon;
+ if ( str != iconButton->icon() )
+ sIcon = iconButton->icon();
+ // (otherwise write empty value)
+
+ kdDebug(250) << "**" << path << "**" << endl;
+ TQFile f( path );
+
+ // If default icon and no .directory file -> don't create one
+ if ( !sIcon.isEmpty() || f.exists() )
+ {
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
+ "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KDesktopFile cfg(path);
+ kdDebug(250) << "sIcon = " << (sIcon) << endl;
+ kdDebug(250) << "str = " << (str) << endl;
+ cfg.writeEntry( "Icon", sIcon );
+ cfg.sync();
+ }
+ }
+}
+
+void KFilePropsPlugin::slotFileRenamed( TDEIO::Job *, const KURL &, const KURL & newUrl )
+{
+ // This is called in case of an existing local file during the copy/move operation,
+ // if the user chooses Rename.
+ properties->updateUrl( newUrl );
+}
+
+void KFilePropsPlugin::postApplyChanges()
+{
+ // Save the icon only after applying the permissions changes (#46192)
+ applyIconChanges();
+
+ KURL::List lst;
+ KFileItemList items = properties->items();
+ for ( KFileItemListIterator it( items ); it.current(); ++it )
+ lst.append((*it)->url());
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesChanged( lst );
+}
+
+class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
+{
+public:
+ KFilePermissionsPropsPluginPrivate()
+ {
+ }
+ ~KFilePermissionsPropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+ TQCheckBox *cbRecursive;
+ TQLabel *explanationLabel;
+ TQComboBox *ownerPermCombo, *groupPermCombo, *othersPermCombo;
+ TQCheckBox *extraCheckbox;
+ mode_t partialPermissions;
+ KFilePermissionsPropsPlugin::PermissionsMode pmode;
+ bool canChangePermissions;
+ bool isIrregular;
+ bool hasExtendedACL;
+ KACL extendedACL;
+ KACL defaultACL;
+ bool fileSystemSupportsACLs;
+};
+
+#define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR)
+#define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP)
+#define UniOthers (S_IROTH|S_IWOTH|S_IXOTH)
+#define UniRead (S_IRUSR|S_IRGRP|S_IROTH)
+#define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH)
+#define UniExec (S_IXUSR|S_IXGRP|S_IXOTH)
+#define UniSpecial (S_ISUID|S_ISGID|S_ISVTX)
+
+// synced with PermissionsTarget
+const mode_t KFilePermissionsPropsPlugin::permissionsMasks[3] = {UniOwner, UniGroup, UniOthers};
+const mode_t KFilePermissionsPropsPlugin::standardPermissions[4] = { 0, UniRead, UniRead|UniWrite, (mode_t)-1 };
+
+// synced with PermissionsMode and standardPermissions
+const char *KFilePermissionsPropsPlugin::permissionsTexts[4][4] = {
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can Read"),
+ I18N_NOOP("Can Read & Write"),
+ 0 },
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can View Content"),
+ I18N_NOOP("Can View & Modify Content"),
+ 0 },
+ { 0, 0, 0, 0}, // no texts for links
+ { I18N_NOOP("Forbidden"),
+ I18N_NOOP("Can View Content & Read"),
+ I18N_NOOP("Can View/Read & Modify/Write"),
+ 0 }
+};
+
+
+KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KFilePermissionsPropsPluginPrivate;
+ d->cbRecursive = 0L;
+ grpCombo = 0L; grpEdit = 0;
+ usrEdit = 0L;
+ TQString path = properties->kurl().path(-1);
+ TQString fname = properties->kurl().fileName();
+ bool isLocal = properties->kurl().isLocalFile();
+ bool isTrash = ( properties->kurl().protocol().find("trash", 0, false)==0 );
+ bool IamRoot = (geteuid() == 0);
+
+ KFileItem * item = properties->item();
+ bool isLink = item->isLink();
+ bool isDir = item->isDir(); // all dirs
+ bool hasDir = item->isDir(); // at least one dir
+ permissions = item->permissions(); // common permissions to all files
+ d->partialPermissions = permissions; // permissions that only some files have (at first we take everything)
+ d->isIrregular = isIrregular(permissions, isDir, isLink);
+ strOwner = item->user();
+ strGroup = item->group();
+ d->hasExtendedACL = item->ACL().isExtended() || item->defaultACL().isValid();
+ d->extendedACL = item->ACL();
+ d->defaultACL = item->defaultACL();
+ d->fileSystemSupportsACLs = false;
+
+ if ( properties->items().count() > 1 )
+ {
+ // Multiple items: see what they have in common
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
+ {
+ if (!d->isIrregular)
+ d->isIrregular |= isIrregular((*it)->permissions(),
+ (*it)->isDir() == isDir,
+ (*it)->isLink() == isLink);
+ d->hasExtendedACL = d->hasExtendedACL || (*it)->hasExtendedACL();
+ if ( (*it)->isLink() != isLink )
+ isLink = false;
+ if ( (*it)->isDir() != isDir )
+ isDir = false;
+ hasDir |= (*it)->isDir();
+ if ( (*it)->permissions() != permissions )
+ {
+ permissions &= (*it)->permissions();
+ d->partialPermissions |= (*it)->permissions();
+ }
+ if ( (*it)->user() != strOwner )
+ strOwner = TQString::null;
+ if ( (*it)->group() != strGroup )
+ strGroup = TQString::null;
+ }
+ }
+
+ if (isLink)
+ d->pmode = PermissionsOnlyLinks;
+ else if (isDir)
+ d->pmode = PermissionsOnlyDirs;
+ else if (hasDir)
+ d->pmode = PermissionsMixed;
+ else
+ d->pmode = PermissionsOnlyFiles;
+
+ // keep only what's not in the common permissions
+ d->partialPermissions = d->partialPermissions & ~permissions;
+
+ bool isMyFile = false;
+
+ if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person
+ struct passwd *myself = getpwuid( geteuid() );
+ if ( myself != 0L )
+ {
+ isMyFile = (strOwner == TQString::fromLocal8Bit(myself->pw_name));
+ } else
+ kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl;
+ } else {
+ //We don't know, for remote files, if they are ours or not.
+ //So we let the user change permissions, and
+ //TDEIO::chmod will tell, if he had no right to do it.
+ isMyFile = true;
+ }
+
+ d->canChangePermissions = (isMyFile || IamRoot) && (!isLink);
+
+
+ // create GUI
+
+ d->m_frame = properties->addPage(i18n("&Permissions"));
+
+ TQBoxLayout *box = new TQVBoxLayout( d->m_frame, 0, KDialog::spacingHint() );
+
+ TQWidget *l;
+ TQLabel *lbl;
+ TQGroupBox *gb;
+ TQGridLayout *gl;
+ TQPushButton* pbAdvancedPerm = 0;
+
+ /* Group: Access Permissions */
+ gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), d->m_frame );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+ box->addWidget (gb);
+
+ gl = new TQGridLayout (gb->layout(), 7, 2);
+ gl->setColStretch(1, 1);
+
+ l = d->explanationLabel = new TQLabel( "", gb );
+ if (isLink)
+ d->explanationLabel->setText(i18n("This file is a link and does not have permissions.",
+ "All files are links and do not have permissions.",
+ properties->items().count()));
+ else if (!d->canChangePermissions)
+ d->explanationLabel->setText(i18n("Only the owner can change permissions."));
+ gl->addMultiCellWidget(l, 0, 0, 0, 1);
+
+ lbl = new TQLabel( i18n("O&wner:"), gb);
+ gl->addWidget(lbl, 1, 0);
+ l = d->ownerPermCombo = new TQComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 1, 1);
+ connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
+ TQWhatsThis::add(l, i18n("Specifies the actions that the owner is allowed to do."));
+
+ lbl = new TQLabel( i18n("Gro&up:"), gb);
+ gl->addWidget(lbl, 2, 0);
+ l = d->groupPermCombo = new TQComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 2, 1);
+ connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
+ TQWhatsThis::add(l, i18n("Specifies the actions that the members of the group are allowed to do."));
+
+ lbl = new TQLabel( i18n("O&thers:"), gb);
+ gl->addWidget(lbl, 3, 0);
+ l = d->othersPermCombo = new TQComboBox(gb);
+ lbl->setBuddy(l);
+ gl->addWidget(l, 3, 1);
+ connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
+ TQWhatsThis::add(l, i18n("Specifies the actions that all users, who are neither "
+ "owner nor in the group, are allowed to do."));
+
+ if (!isLink) {
+ l = d->extraCheckbox = new TQCheckBox(hasDir ?
+ i18n("Only own&er can rename and delete folder content") :
+ i18n("Is &executable"),
+ gb );
+ connect( d->extraCheckbox, TQT_SIGNAL( clicked() ), this, TQT_SIGNAL( changed() ) );
+ gl->addWidget(l, 4, 1);
+ TQWhatsThis::add(l, hasDir ? i18n("Enable this option to allow only the folder's owner to "
+ "delete or rename the contained files and folders. Other "
+ "users can only add new files, which requires the 'Modify "
+ "Content' permission.")
+ : i18n("Enable this option to mark the file as executable. This only makes "
+ "sense for programs and scripts. It is required when you want to "
+ "execute them."));
+
+ TQLayoutItem *spacer = TQT_TQLAYOUTITEM(new TQSpacerItem(0, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding));
+ gl->addMultiCell(spacer, 5, 5, 0, 1);
+
+ pbAdvancedPerm = new TQPushButton(i18n("A&dvanced Permissions"), gb);
+ gl->addMultiCellWidget(pbAdvancedPerm, 6, 6, 0, 1, Qt::AlignRight);
+ connect(pbAdvancedPerm, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotShowAdvancedPermissions() ));
+ }
+ else
+ d->extraCheckbox = 0;
+
+
+ /**** Group: Ownership ****/
+ gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Ownership"), d->m_frame );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+ box->addWidget (gb);
+
+ gl = new TQGridLayout (gb->layout(), 4, 3);
+ gl->addRowSpacing(0, 10);
+
+ /*** Set Owner ***/
+ l = new TQLabel( i18n("User:"), gb );
+ gl->addWidget (l, 1, 0);
+
+ /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
+ * value. Huge sites having 10.000+ user have a fair chance of using NIS,
+ * (possibly) making this unacceptably slow.
+ * OTOH, it is nice to offer this functionality for the standard user.
+ */
+ int i, maxEntries = 1000;
+ struct passwd *user;
+ struct group *ge;
+
+ /* File owner: For root, offer a KLineEdit with autocompletion.
+ * For a user, who can never chown() a file, offer a TQLabel.
+ */
+ if (IamRoot && isLocal)
+ {
+ usrEdit = new KLineEdit( gb );
+ KCompletion *kcom = usrEdit->completionObject();
+ kcom->setOrder(KCompletion::Sorted);
+ setpwent();
+ for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(TQString::fromLatin1(user->pw_name));
+ endpwent();
+ usrEdit->setCompletionMode((i < maxEntries) ? TDEGlobalSettings::CompletionAuto :
+ TDEGlobalSettings::CompletionNone);
+ usrEdit->setText(strOwner);
+ gl->addWidget(usrEdit, 1, 1);
+ connect( usrEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ }
+ else
+ {
+ l = new TQLabel(strOwner, gb);
+ gl->addWidget(l, 1, 1);
+ }
+
+ /*** Set Group ***/
+
+ TQStringList groupList;
+ TQCString strUser;
+ user = getpwuid(geteuid());
+ if (user != 0L)
+ strUser = user->pw_name;
+
+#ifdef Q_OS_UNIX
+ setgrent();
+ for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++)
+ {
+ if (IamRoot)
+ groupList += TQString::fromLatin1(ge->gr_name);
+ else
+ {
+ /* pick the groups to which the user belongs */
+ char ** members = ge->gr_mem;
+ char * member;
+ while ((member = *members) != 0L) {
+ if (strUser == member) {
+ groupList += TQString::fromLocal8Bit(ge->gr_name);
+ break;
+ }
+ ++members;
+ }
+ }
+ }
+ endgrent();
+#endif //Q_OS_UNIX
+
+ /* add the effective Group to the list .. */
+ ge = getgrgid (getegid());
+ if (ge) {
+ TQString name = TQString::fromLatin1(ge->gr_name);
+ if (name.isEmpty())
+ name.setNum(ge->gr_gid);
+ if (groupList.find(name) == groupList.end())
+ groupList += name;
+ }
+
+ bool isMyGroup = groupList.contains(strGroup);
+
+ /* add the group the file currently belongs to ..
+ * .. if its not there already
+ */
+ if (!isMyGroup)
+ groupList += strGroup;
+
+ l = new TQLabel( i18n("Group:"), gb );
+ gl->addWidget (l, 2, 0);
+
+ /* Set group: if possible to change:
+ * - Offer a KLineEdit for root, since he can change to any group.
+ * - Offer a TQComboBox for a normal user, since he can change to a fixed
+ * (small) set of groups only.
+ * If not changeable: offer a TQLabel.
+ */
+ if (IamRoot && isLocal)
+ {
+ grpEdit = new KLineEdit(gb);
+ KCompletion *kcom = new KCompletion;
+ kcom->setItems(groupList);
+ grpEdit->setCompletionObject(kcom, true);
+ grpEdit->setAutoDeleteCompletionObject( true );
+ grpEdit->setCompletionMode(TDEGlobalSettings::CompletionAuto);
+ grpEdit->setText(strGroup);
+ gl->addWidget(grpEdit, 2, 1);
+ connect( grpEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ }
+ else if ((groupList.count() > 1) && isMyFile && isLocal)
+ {
+ grpCombo = new TQComboBox(gb, "combogrouplist");
+ grpCombo->insertStringList(groupList);
+ grpCombo->setCurrentItem(groupList.findIndex(strGroup));
+ gl->addWidget(grpCombo, 2, 1);
+ connect( grpCombo, TQT_SIGNAL( activated( int ) ),
+ this, TQT_SIGNAL( changed() ) );
+ }
+ else
+ {
+ l = new TQLabel(strGroup, gb);
+ gl->addWidget(l, 2, 1);
+ }
+
+ gl->setColStretch(2, 10);
+
+ // "Apply recursive" checkbox
+ if ( hasDir && !isLink && !isTrash )
+ {
+ d->cbRecursive = new TQCheckBox( i18n("Apply changes to all subfolders and their contents"), d->m_frame );
+ connect( d->cbRecursive, TQT_SIGNAL( clicked() ), this, TQT_SIGNAL( changed() ) );
+ box->addWidget( d->cbRecursive );
+ }
+
+ updateAccessControls();
+
+
+ if ( isTrash || !d->canChangePermissions )
+ {
+ //don't allow to change properties for file into trash
+ enableAccessControls(false);
+ if ( pbAdvancedPerm && !d->hasExtendedACL )
+ pbAdvancedPerm->setEnabled(false);
+ }
+
+ box->addStretch (10);
+}
+
+#ifdef USE_POSIX_ACL
+static bool fileSystemSupportsACL( const TQCString& pathCString )
+{
+ bool fileSystemSupportsACLs = false;
+#ifdef Q_OS_FREEBSD
+ struct statfs buf;
+ fileSystemSupportsACLs = ( statfs( pathCString.data(), &buf ) == 0 ) && ( buf.f_flags & MNT_ACLS );
+#else
+ fileSystemSupportsACLs =
+ getxattr( pathCString.data(), "system.posix_acl_access", NULL, 0 ) >= 0
+#ifdef ENODATA
+ || (errno == ENODATA)
+#endif
+#ifdef ENOATTR
+ || (errno == ENOATTR)
+#endif
+ ;
+#endif
+ return fileSystemSupportsACLs;
+}
+#endif
+
+
+void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() {
+
+ bool isDir = (d->pmode == PermissionsOnlyDirs) || (d->pmode == PermissionsMixed);
+ KDialogBase dlg(properties, 0, true, i18n("Advanced Permissions"),
+ KDialogBase::Ok|KDialogBase::Cancel);
+
+ TQLabel *l, *cl[3];
+ TQGroupBox *gb;
+ TQGridLayout *gl;
+
+ TQVBox *mainVBox = dlg.makeVBoxMainWidget();
+
+ // Group: Access Permissions
+ gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), mainVBox );
+ gb->layout()->setSpacing(KDialog::spacingHint());
+ gb->layout()->setMargin(KDialog::marginHint());
+
+ gl = new TQGridLayout (gb->layout(), 6, 6);
+ gl->addRowSpacing(0, 10);
+
+ TQValueVector<TQWidget*> theNotSpecials;
+
+ l = new TQLabel(i18n("Class"), gb );
+ gl->addWidget(l, 1, 0);
+ theNotSpecials.append( l );
+
+ if (isDir)
+ l = new TQLabel( i18n("Show\nEntries"), gb );
+ else
+ l = new TQLabel( i18n("Read"), gb );
+ gl->addWidget (l, 1, 1);
+ theNotSpecials.append( l );
+ TQString readWhatsThis;
+ if (isDir)
+ readWhatsThis = i18n("This flag allows viewing the content of the folder.");
+ else
+ readWhatsThis = i18n("The Read flag allows viewing the content of the file.");
+ TQWhatsThis::add(l, readWhatsThis);
+
+ if (isDir)
+ l = new TQLabel( i18n("Write\nEntries"), gb );
+ else
+ l = new TQLabel( i18n("Write"), gb );
+ gl->addWidget (l, 1, 2);
+ theNotSpecials.append( l );
+ TQString writeWhatsThis;
+ if (isDir)
+ writeWhatsThis = i18n("This flag allows adding, renaming and deleting of files. "
+ "Note that deleting and renaming can be limited using the Sticky flag.");
+ else
+ writeWhatsThis = i18n("The Write flag allows modifying the content of the file.");
+ TQWhatsThis::add(l, writeWhatsThis);
+
+ TQString execWhatsThis;
+ if (isDir) {
+ l = new TQLabel( i18n("Enter folder", "Enter"), gb );
+ execWhatsThis = i18n("Enable this flag to allow entering the folder.");
+ }
+ else {
+ l = new TQLabel( i18n("Exec"), gb );
+ execWhatsThis = i18n("Enable this flag to allow executing the file as a program.");
+ }
+ TQWhatsThis::add(l, execWhatsThis);
+ theNotSpecials.append( l );
+ // GJ: Add space between normal and special modes
+ TQSize size = l->sizeHint();
+ size.setWidth(size.width() + 15);
+ l->setFixedSize(size);
+ gl->addWidget (l, 1, 3);
+
+ l = new TQLabel( i18n("Special"), gb );
+ gl->addMultiCellWidget(l, 1, 1, 4, 5);
+ TQString specialWhatsThis;
+ if (isDir)
+ specialWhatsThis = i18n("Special flag. Valid for the whole folder, the exact "
+ "meaning of the flag can be seen in the right hand column.");
+ else
+ specialWhatsThis = i18n("Special flag. The exact meaning of the flag can be seen "
+ "in the right hand column.");
+ TQWhatsThis::add(l, specialWhatsThis);
+
+ cl[0] = new TQLabel( i18n("User"), gb );
+ gl->addWidget (cl[0], 2, 0);
+ theNotSpecials.append( cl[0] );
+
+ cl[1] = new TQLabel( i18n("Group"), gb );
+ gl->addWidget (cl[1], 3, 0);
+ theNotSpecials.append( cl[1] );
+
+ cl[2] = new TQLabel( i18n("Others"), gb );
+ gl->addWidget (cl[2], 4, 0);
+ theNotSpecials.append( cl[2] );
+
+ l = new TQLabel(i18n("Set UID"), gb);
+ gl->addWidget(l, 2, 5);
+ TQString setUidWhatsThis;
+ if (isDir)
+ setUidWhatsThis = i18n("If this flag is set, the owner of this folder will be "
+ "the owner of all new files.");
+ else
+ setUidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
+ "be executed with the permissions of the owner.");
+ TQWhatsThis::add(l, setUidWhatsThis);
+
+ l = new TQLabel(i18n("Set GID"), gb);
+ gl->addWidget(l, 3, 5);
+ TQString setGidWhatsThis;
+ if (isDir)
+ setGidWhatsThis = i18n("If this flag is set, the group of this folder will be "
+ "set for all new files.");
+ else
+ setGidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
+ "be executed with the permissions of the group.");
+ TQWhatsThis::add(l, setGidWhatsThis);
+
+ l = new TQLabel(i18n("File permission", "Sticky"), gb);
+ gl->addWidget(l, 4, 5);
+ TQString stickyWhatsThis;
+ if (isDir)
+ stickyWhatsThis = i18n("If the Sticky flag is set on a folder, only the owner "
+ "and root can delete or rename files. Otherwise everybody "
+ "with write permissions can do this.");
+ else
+ stickyWhatsThis = i18n("The Sticky flag on a file is ignored on Linux, but may "
+ "be used on some systems");
+ TQWhatsThis::add(l, stickyWhatsThis);
+
+ mode_t aPermissions, aPartialPermissions;
+ mode_t dummy1, dummy2;
+
+ if (!d->isIrregular) {
+ switch (d->pmode) {
+ case PermissionsOnlyFiles:
+ getPermissionMasks(aPartialPermissions,
+ dummy1,
+ aPermissions,
+ dummy2);
+ break;
+ case PermissionsOnlyDirs:
+ case PermissionsMixed:
+ getPermissionMasks(dummy1,
+ aPartialPermissions,
+ dummy2,
+ aPermissions);
+ break;
+ case PermissionsOnlyLinks:
+ aPermissions = UniRead | UniWrite | UniExec | UniSpecial;
+ aPartialPermissions = 0;
+ break;
+ }
+ }
+ else {
+ aPermissions = permissions;
+ aPartialPermissions = d->partialPermissions;
+ }
+
+ // Draw Checkboxes
+ TQCheckBox *cba[3][4];
+ for (int row = 0; row < 3 ; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ TQCheckBox *cb = new TQCheckBox( gb );
+ if ( col != 3 ) theNotSpecials.append( cb );
+ cba[row][col] = cb;
+ cb->setChecked(aPermissions & fperm[row][col]);
+ if ( aPartialPermissions & fperm[row][col] )
+ {
+ cb->setTristate();
+ cb->setNoChange();
+ }
+ else if (d->cbRecursive && d->cbRecursive->isChecked())
+ cb->setTristate();
+
+ cb->setEnabled( d->canChangePermissions );
+ gl->addWidget (cb, row+2, col+1);
+ switch(col) {
+ case 0:
+ TQWhatsThis::add(cb, readWhatsThis);
+ break;
+ case 1:
+ TQWhatsThis::add(cb, writeWhatsThis);
+ break;
+ case 2:
+ TQWhatsThis::add(cb, execWhatsThis);
+ break;
+ case 3:
+ switch(row) {
+ case 0:
+ TQWhatsThis::add(cb, setUidWhatsThis);
+ break;
+ case 1:
+ TQWhatsThis::add(cb, setGidWhatsThis);
+ break;
+ case 2:
+ TQWhatsThis::add(cb, stickyWhatsThis);
+ break;
+ }
+ break;
+ }
+ }
+ }
+ gl->setColStretch(6, 10);
+
+#ifdef USE_POSIX_ACL
+ KACLEditWidget *extendedACLs = 0;
+
+ // FIXME make it work with partial entries
+ if ( properties->items().count() == 1 ) {
+ TQCString pathCString = TQFile::encodeName( properties->item()->url().path() );
+ d->fileSystemSupportsACLs = fileSystemSupportsACL( pathCString );
+ }
+ if ( d->fileSystemSupportsACLs ) {
+ std::for_each( theNotSpecials.begin(), theNotSpecials.end(), std::mem_fun( &TQWidget::hide ) );
+ extendedACLs = new KACLEditWidget( mainVBox );
+ if ( d->extendedACL.isValid() && d->extendedACL.isExtended() )
+ extendedACLs->setACL( d->extendedACL );
+ else
+ extendedACLs->setACL( KACL( aPermissions ) );
+
+ if ( d->defaultACL.isValid() )
+ extendedACLs->setDefaultACL( d->defaultACL );
+
+ if ( properties->items().first()->isDir() )
+ extendedACLs->setAllowDefaults( true );
+ if ( !d->canChangePermissions )
+ extendedACLs->setReadOnly( true );
+
+ }
+#endif
+ if (dlg.exec() != KDialogBase::Accepted)
+ return;
+
+ mode_t andPermissions = mode_t(~0);
+ mode_t orPermissions = 0;
+ for (int row = 0; row < 3; ++row)
+ for (int col = 0; col < 4; ++col) {
+ switch (cba[row][col]->state())
+ {
+ case TQCheckBox::On:
+ orPermissions |= fperm[row][col];
+ //fall through
+ case TQCheckBox::Off:
+ andPermissions &= ~fperm[row][col];
+ break;
+ default: // NoChange
+ break;
+ }
+ }
+
+ d->isIrregular = false;
+ KFileItemList items = properties->items();
+ for (KFileItemListIterator it(items); it.current(); ++it) {
+ if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions,
+ (*it)->isDir(), (*it)->isLink())) {
+ d->isIrregular = true;
+ break;
+ }
+ }
+
+ permissions = orPermissions;
+ d->partialPermissions = andPermissions;
+
+#ifdef USE_POSIX_ACL
+ // override with the acls, if present
+ if ( extendedACLs ) {
+ d->extendedACL = extendedACLs->getACL();
+ d->defaultACL = extendedACLs->getDefaultACL();
+ d->hasExtendedACL = d->extendedACL.isExtended() || d->defaultACL.isValid();
+ permissions = d->extendedACL.basePermissions();
+ permissions |= ( andPermissions | orPermissions ) & ( S_ISUID|S_ISGID|S_ISVTX );
+ }
+#endif
+
+ updateAccessControls();
+ emit changed();
+}
+
+// TQString KFilePermissionsPropsPlugin::tabName () const
+// {
+// return i18n ("&Permissions");
+// }
+
+KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
+{
+ delete d;
+}
+
+bool KFilePermissionsPropsPlugin::supports( KFileItemList _items )
+{
+ KFileItemList::const_iterator it = _items.constBegin();
+ for ( ; it != _items.constEnd(); ++it ) {
+ KFileItem *item = *it;
+ if( !item->user().isEmpty() || !item->group().isEmpty() )
+ return true;
+ }
+ return false;
+}
+
+// sets a combo box in the Access Control frame
+void KFilePermissionsPropsPlugin::setComboContent(TQComboBox *combo, PermissionsTarget target,
+ mode_t permissions, mode_t partial) {
+ combo->clear();
+ if (d->pmode == PermissionsOnlyLinks) {
+ combo->insertItem(i18n("Link"));
+ combo->setCurrentItem(0);
+ return;
+ }
+
+ mode_t tMask = permissionsMasks[target];
+ int textIndex;
+ for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++)
+ if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite)))
+ break;
+ Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar
+
+ for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++)
+ combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i]));
+
+ if (partial & tMask & ~UniExec) {
+ combo->insertItem(i18n("Varying (No Change)"));
+ combo->setCurrentItem(3);
+ }
+ else
+ combo->setCurrentItem(textIndex);
+}
+
+// permissions are irregular if they cant be displayed in a combo box.
+bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) {
+ if (isLink) // links are always ok
+ return false;
+
+ mode_t p = permissions;
+ if (p & (S_ISUID | S_ISGID)) // setuid/setgid -> irregular
+ return true;
+ if (isDir) {
+ p &= ~S_ISVTX; // ignore sticky on dirs
+
+ // check supported flag combinations
+ mode_t p0 = p & UniOwner;
+ if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner))
+ return true;
+ p0 = p & UniGroup;
+ if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup))
+ return true;
+ p0 = p & UniOthers;
+ if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers))
+ return true;
+ return false;
+ }
+ if (p & S_ISVTX) // sticky on file -> irregular
+ return true;
+
+ // check supported flag combinations
+ mode_t p0 = p & UniOwner;
+ bool usrXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXUSR) {
+ if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR)))
+ return true;
+ usrXPossible = true;
+ }
+ else if (p0 == S_IWUSR)
+ return true;
+
+ p0 = p & UniGroup;
+ bool grpXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXGRP) {
+ if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP)))
+ return true;
+ grpXPossible = true;
+ }
+ else if (p0 == S_IWGRP)
+ return true;
+ if (p0 == 0)
+ grpXPossible = true;
+
+ p0 = p & UniOthers;
+ bool othXPossible = !p0; // true if this file could be an executable
+ if (p0 & S_IXOTH) {
+ if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH)))
+ return true;
+ othXPossible = true;
+ }
+ else if (p0 == S_IWOTH)
+ return true;
+
+ // check that there either all targets are executable-compatible, or none
+ return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible);
+}
+
+// enables/disabled the widgets in the Access Control frame
+void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) {
+ d->ownerPermCombo->setEnabled(enable);
+ d->groupPermCombo->setEnabled(enable);
+ d->othersPermCombo->setEnabled(enable);
+ if (d->extraCheckbox)
+ d->extraCheckbox->setEnabled(enable);
+ if ( d->cbRecursive )
+ d->cbRecursive->setEnabled(enable);
+}
+
+// updates all widgets in the Access Control frame
+void KFilePermissionsPropsPlugin::updateAccessControls() {
+ setComboContent(d->ownerPermCombo, PermissionsOwner,
+ permissions, d->partialPermissions);
+ setComboContent(d->groupPermCombo, PermissionsGroup,
+ permissions, d->partialPermissions);
+ setComboContent(d->othersPermCombo, PermissionsOthers,
+ permissions, d->partialPermissions);
+
+ switch(d->pmode) {
+ case PermissionsOnlyLinks:
+ enableAccessControls(false);
+ break;
+ case PermissionsOnlyFiles:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("This file uses advanced permissions",
+ "These files use advanced permissions.",
+ properties->items().count()) : "");
+ if (d->partialPermissions & UniExec) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & UniExec);
+ }
+ break;
+ case PermissionsOnlyDirs:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ // if this is a dir, and we can change permissions, don't dis-allow
+ // recursive, we can do that for ACL setting.
+ if ( d->cbRecursive )
+ d->cbRecursive->setEnabled( d->canChangePermissions && !d->isIrregular );
+
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("This folder uses advanced permissions.",
+ "These folders use advanced permissions.",
+ properties->items().count()) : "");
+ if (d->partialPermissions & S_ISVTX) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & S_ISVTX);
+ }
+ break;
+ case PermissionsMixed:
+ enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
+ if (d->canChangePermissions)
+ d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
+ i18n("These files use advanced permissions.") : "");
+ break;
+ if (d->partialPermissions & S_ISVTX) {
+ d->extraCheckbox->setTristate();
+ d->extraCheckbox->setNoChange();
+ }
+ else {
+ d->extraCheckbox->setTristate(false);
+ d->extraCheckbox->setChecked(permissions & S_ISVTX);
+ }
+ break;
+ }
+}
+
+// gets masks for files and dirs from the Access Control frame widgets
+void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions,
+ mode_t &andDirPermissions,
+ mode_t &orFilePermissions,
+ mode_t &orDirPermissions) {
+ andFilePermissions = mode_t(~UniSpecial);
+ andDirPermissions = mode_t(~(S_ISUID|S_ISGID));
+ orFilePermissions = 0;
+ orDirPermissions = 0;
+ if (d->isIrregular)
+ return;
+
+ mode_t m = standardPermissions[d->ownerPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniOwner;
+ if ((m & UniOwner) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
+ andFilePermissions &= ~(S_IRUSR | S_IWUSR);
+ else {
+ andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
+ if ((m & S_IRUSR) && (d->extraCheckbox->state() == TQButton::On))
+ orFilePermissions |= S_IXUSR;
+ }
+
+ orDirPermissions |= m & UniOwner;
+ if (m & S_IRUSR)
+ orDirPermissions |= S_IXUSR;
+ andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
+ }
+
+ m = standardPermissions[d->groupPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniGroup;
+ if ((m & UniGroup) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
+ andFilePermissions &= ~(S_IRGRP | S_IWGRP);
+ else {
+ andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
+ if ((m & S_IRGRP) && (d->extraCheckbox->state() == TQButton::On))
+ orFilePermissions |= S_IXGRP;
+ }
+
+ orDirPermissions |= m & UniGroup;
+ if (m & S_IRGRP)
+ orDirPermissions |= S_IXGRP;
+ andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
+ }
+
+ m = standardPermissions[d->othersPermCombo->currentItem()];
+ if (m != (mode_t) -1) {
+ orFilePermissions |= m & UniOthers;
+ if ((m & UniOthers) &&
+ ((d->pmode == PermissionsMixed) ||
+ ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
+ andFilePermissions &= ~(S_IROTH | S_IWOTH);
+ else {
+ andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
+ if ((m & S_IROTH) && (d->extraCheckbox->state() == TQButton::On))
+ orFilePermissions |= S_IXOTH;
+ }
+
+ orDirPermissions |= m & UniOthers;
+ if (m & S_IROTH)
+ orDirPermissions |= S_IXOTH;
+ andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
+ }
+
+ if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) &&
+ (d->extraCheckbox->state() != TQButton::NoChange)) {
+ andDirPermissions &= ~S_ISVTX;
+ if (d->extraCheckbox->state() == TQButton::On)
+ orDirPermissions |= S_ISVTX;
+ }
+}
+
+void KFilePermissionsPropsPlugin::applyChanges()
+{
+ mode_t orFilePermissions;
+ mode_t orDirPermissions;
+ mode_t andFilePermissions;
+ mode_t andDirPermissions;
+
+ if (!d->canChangePermissions)
+ return;
+
+ if (!d->isIrregular)
+ getPermissionMasks(andFilePermissions,
+ andDirPermissions,
+ orFilePermissions,
+ orDirPermissions);
+ else {
+ orFilePermissions = permissions;
+ andFilePermissions = d->partialPermissions;
+ orDirPermissions = permissions;
+ andDirPermissions = d->partialPermissions;
+ }
+
+ TQString owner, group;
+ if (usrEdit)
+ owner = usrEdit->text();
+ if (grpEdit)
+ group = grpEdit->text();
+ else if (grpCombo)
+ group = grpCombo->currentText();
+
+ if (owner == strOwner)
+ owner = TQString::null; // no change
+
+ if (group == strGroup)
+ group = TQString::null;
+
+ bool recursive = d->cbRecursive && d->cbRecursive->isChecked();
+ bool permissionChange = false;
+
+ KFileItemList files, dirs;
+ KFileItemList items = properties->items();
+ for (KFileItemListIterator it(items); it.current(); ++it) {
+ if ((*it)->isDir()) {
+ dirs.append(*it);
+ if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions))
+ permissionChange = true;
+ }
+ else if ((*it)->isFile()) {
+ files.append(*it);
+ if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions))
+ permissionChange = true;
+ }
+ }
+
+ const bool ACLChange = ( d->extendedACL != properties->item()->ACL() );
+ const bool defaultACLChange = ( d->defaultACL != properties->item()->defaultACL() );
+
+ if ( owner.isEmpty() && group.isEmpty() && !recursive
+ && !permissionChange && !ACLChange && !defaultACLChange )
+ return;
+
+ TDEIO::Job * job;
+ if (files.count() > 0) {
+ job = TDEIO::chmod( files, orFilePermissions, ~andFilePermissions,
+ owner, group, false );
+ if ( ACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
+ if ( defaultACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotChmodResult( TDEIO::Job * ) ) );
+ // Wait for job
+ TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
+ tqt_enter_modal(&dummy);
+ tqApp->enter_loop();
+ tqt_leave_modal(&dummy);
+ }
+ if (dirs.count() > 0) {
+ job = TDEIO::chmod( dirs, orDirPermissions, ~andDirPermissions,
+ owner, group, recursive );
+ if ( ACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
+ if ( defaultACLChange && d->fileSystemSupportsACLs )
+ job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotChmodResult( TDEIO::Job * ) ) );
+ // Wait for job
+ TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
+ tqt_enter_modal(&dummy);
+ tqApp->enter_loop();
+ tqt_leave_modal(&dummy);
+ }
+}
+
+void KFilePermissionsPropsPlugin::slotChmodResult( TDEIO::Job * job )
+{
+ kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
+ if (job->error())
+ job->showErrorDialog( d->m_frame );
+ // allow apply() to return
+ tqApp->exit_loop();
+}
+
+
+
+
+class KURLPropsPlugin::KURLPropsPluginPrivate
+{
+public:
+ KURLPropsPluginPrivate()
+ {
+ }
+ ~KURLPropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+};
+
+KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KURLPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("U&RL"));
+ TQVBoxLayout *layout = new TQVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
+
+ TQLabel *l;
+ l = new TQLabel( d->m_frame, "Label_1" );
+ l->setText( i18n("URL:") );
+ layout->addWidget(l);
+
+ URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
+ layout->addWidget(URLEdit);
+
+ TQString path = properties->kurl().path();
+
+ TQFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ URLStr = config.readPathEntry( "URL" );
+
+ if ( !URLStr.isNull() )
+ URLEdit->setURL( URLStr );
+
+ connect( URLEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+
+ layout->addStretch (1);
+}
+
+KURLPropsPlugin::~KURLPropsPlugin()
+{
+ delete d;
+}
+
+// TQString KURLPropsPlugin::tabName () const
+// {
+// return i18n ("U&RL");
+// }
+
+bool KURLPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasLinkType();
+}
+
+void KURLPropsPlugin::applyChanges()
+{
+ TQString path = properties->kurl().path();
+
+ TQFile f( path );
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("Link"));
+ config.writePathEntry( "URL", URLEdit->url() );
+ // Users can't create a Link .desktop file with a Name field,
+ // but distributions can. Update the Name field in that case.
+ if ( config.hasKey("Name") )
+ {
+ TQString nameStr = nameFromFileName(properties->kurl().fileName());
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+
+ }
+}
+
+
+/* ----------------------------------------------------
+ *
+ * KBindingPropsPlugin
+ *
+ * -------------------------------------------------- */
+
+class KBindingPropsPlugin::KBindingPropsPluginPrivate
+{
+public:
+ KBindingPropsPluginPrivate()
+ {
+ }
+ ~KBindingPropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+};
+
+KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
+{
+ d = new KBindingPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("A&ssociation"));
+ patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
+ commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
+ mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
+
+ TQBoxLayout *mainlayout = new TQVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
+ TQLabel* tmpQLabel;
+
+ tmpQLabel = new TQLabel( d->m_frame, "Label_1" );
+ tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //patternEdit->setGeometry( 10, 40, 210, 30 );
+ //patternEdit->setText( "" );
+ patternEdit->setMaxLength( 512 );
+ patternEdit->setMinimumSize( patternEdit->sizeHint() );
+ patternEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(patternEdit, 1);
+
+ tmpQLabel = new TQLabel( d->m_frame, "Label_2" );
+ tmpQLabel->setText( i18n("Mime Type") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //mimeEdit->setGeometry( 10, 160, 210, 30 );
+ mimeEdit->setMaxLength( 256 );
+ mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
+ mimeEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(mimeEdit, 1);
+
+ tmpQLabel = new TQLabel( d->m_frame, "Label_3" );
+ tmpQLabel->setText( i18n("Comment") );
+ tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
+ mainlayout->addWidget(tmpQLabel, 1);
+
+ //commentEdit->setGeometry( 10, 100, 210, 30 );
+ commentEdit->setMaxLength( 256 );
+ commentEdit->setMinimumSize( commentEdit->sizeHint() );
+ commentEdit->setFixedHeight( fontHeight );
+ mainlayout->addWidget(commentEdit, 1);
+
+ cbAutoEmbed = new TQCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
+ mainlayout->addWidget(cbAutoEmbed, 1);
+
+ mainlayout->addStretch (10);
+ mainlayout->activate();
+
+ TQFile f( _props->kurl().path() );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( _props->kurl().path() );
+ config.setDesktopGroup();
+ TQString patternStr = config.readEntry( "Patterns" );
+ TQString iconStr = config.readEntry( "Icon" );
+ TQString commentStr = config.readEntry( "Comment" );
+ m_sMimeStr = config.readEntry( "MimeType" );
+
+ if ( !patternStr.isEmpty() )
+ patternEdit->setText( patternStr );
+ if ( !commentStr.isEmpty() )
+ commentEdit->setText( commentStr );
+ if ( !m_sMimeStr.isEmpty() )
+ mimeEdit->setText( m_sMimeStr );
+ cbAutoEmbed->setTristate();
+ if ( config.hasKey( "X-TDE-AutoEmbed" ) )
+ cbAutoEmbed->setChecked( config.readBoolEntry( "X-TDE-AutoEmbed" ) );
+ else
+ cbAutoEmbed->setNoChange();
+
+ connect( patternEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( mimeEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( cbAutoEmbed, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+}
+
+KBindingPropsPlugin::~KBindingPropsPlugin()
+{
+ delete d;
+}
+
+// TQString KBindingPropsPlugin::tabName () const
+// {
+// return i18n ("A&ssociation");
+// }
+
+bool KBindingPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasMimeTypeType();
+}
+
+void KBindingPropsPlugin::applyChanges()
+{
+ TQString path = properties->kurl().path();
+ TQFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) )
+ {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("MimeType") );
+
+ config.writeEntry( "Patterns", patternEdit->text() );
+ config.writeEntry( "Comment", commentEdit->text() );
+ config.writeEntry( "Comment",
+ commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "MimeType", mimeEdit->text() );
+ if ( cbAutoEmbed->state() == TQButton::NoChange )
+ config.deleteEntry( "X-TDE-AutoEmbed", false );
+ else
+ config.writeEntry( "X-TDE-AutoEmbed", cbAutoEmbed->isChecked() );
+ config.sync();
+}
+
+/* ----------------------------------------------------
+ *
+ * KDevicePropsPlugin
+ *
+ * -------------------------------------------------- */
+
+class KDevicePropsPlugin::KDevicePropsPluginPrivate
+{
+public:
+ KDevicePropsPluginPrivate()
+ {
+ }
+ ~KDevicePropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+ TQStringList mountpointlist;
+ TQLabel *m_freeSpaceText;
+ TQLabel *m_freeSpaceLabel;
+ TQProgressBar *m_freeSpaceBar;
+};
+
+KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
+{
+ d = new KDevicePropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("De&vice"));
+
+ TQStringList devices;
+ KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
+
+ for(KMountPoint::List::ConstIterator it = mountPoints.begin();
+ it != mountPoints.end(); ++it)
+ {
+ KMountPoint *mp = *it;
+ TQString mountPoint = mp->mountPoint();
+ TQString device = mp->mountedFrom();
+ kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl;
+
+ if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty()
+ && device != "none")
+ {
+ devices.append( device + TQString::fromLatin1(" (")
+ + mountPoint + TQString::fromLatin1(")") );
+ m_devicelist.append(device);
+ d->mountpointlist.append(mountPoint);
+ }
+ }
+
+ TQGridLayout *layout = new TQGridLayout( d->m_frame, 0, 2, 0,
+ KDialog::spacingHint());
+ layout->setColStretch(1, 1);
+
+ TQLabel* label;
+ label = new TQLabel( d->m_frame );
+ label->setText( devices.count() == 0 ?
+ i18n("Device (/dev/fd0):") : // old style
+ i18n("Device:") ); // new style (combobox)
+ layout->addWidget(label, 0, 0);
+
+ device = new TQComboBox( true, d->m_frame, "ComboBox_device" );
+ device->insertStringList( devices );
+ layout->addWidget(device, 0, 1);
+ connect( device, TQT_SIGNAL( activated( int ) ),
+ this, TQT_SLOT( slotActivated( int ) ) );
+
+ readonly = new TQCheckBox( d->m_frame, "CheckBox_readonly" );
+ readonly->setText( i18n("Read only") );
+ layout->addWidget(readonly, 1, 1);
+
+ label = new TQLabel( d->m_frame );
+ label->setText( i18n("File system:") );
+ layout->addWidget(label, 2, 0);
+
+ TQLabel *fileSystem = new TQLabel( d->m_frame );
+ layout->addWidget(fileSystem, 2, 1);
+
+ label = new TQLabel( d->m_frame );
+ label->setText( devices.count()==0 ?
+ i18n("Mount point (/mnt/floppy):") : // old style
+ i18n("Mount point:")); // new style (combobox)
+ layout->addWidget(label, 3, 0);
+
+ mountpoint = new TQLabel( d->m_frame, "LineEdit_mountpoint" );
+
+ layout->addWidget(mountpoint, 3, 1);
+
+ // show disk free
+ d->m_freeSpaceText = new TQLabel(i18n("Free disk space:"), d->m_frame );
+ layout->addWidget(d->m_freeSpaceText, 4, 0);
+
+ d->m_freeSpaceLabel = new TQLabel( d->m_frame );
+ layout->addWidget( d->m_freeSpaceLabel, 4, 1 );
+
+ d->m_freeSpaceBar = new TQProgressBar( d->m_frame, "freeSpaceBar" );
+ layout->addMultiCellWidget(d->m_freeSpaceBar, 5, 5, 0, 1);
+
+ // we show it in the slot when we know the values
+ d->m_freeSpaceText->hide();
+ d->m_freeSpaceLabel->hide();
+ d->m_freeSpaceBar->hide();
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
+ layout->addMultiCellWidget(sep, 6, 6, 0, 1);
+
+ unmounted = new KIconButton( d->m_frame );
+ int bsize = 66 + 2 * unmounted->style().pixelMetric(TQStyle::PM_ButtonMargin);
+ unmounted->setFixedSize(bsize, bsize);
+ unmounted->setIconType(KIcon::Desktop, KIcon::Device);
+ layout->addWidget(unmounted, 7, 0);
+
+ label = new TQLabel( i18n("Unmounted Icon"), d->m_frame );
+ layout->addWidget(label, 7, 1);
+
+ layout->setRowStretch(8, 1);
+
+ TQString path( _props->kurl().path() );
+
+ TQFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ TQString deviceStr = config.readEntry( "Dev" );
+ TQString mountPointStr = config.readEntry( "MountPoint" );
+ bool ro = config.readBoolEntry( "ReadOnly", false );
+ TQString unmountedStr = config.readEntry( "UnmountIcon" );
+
+ fileSystem->setText( i18n(config.readEntry("FSType").local8Bit()) );
+
+ device->setEditText( deviceStr );
+ if ( !deviceStr.isEmpty() ) {
+ // Set default options for this device (first matching entry)
+ int index = m_devicelist.findIndex(deviceStr);
+ if (index != -1)
+ {
+ //kdDebug(250) << "found it " << index << endl;
+ slotActivated( index );
+ }
+ }
+
+ if ( !mountPointStr.isEmpty() )
+ {
+ mountpoint->setText( mountPointStr );
+ updateInfo();
+ }
+
+ readonly->setChecked( ro );
+
+ if ( unmountedStr.isEmpty() )
+ unmountedStr = KMimeType::defaultMimeTypePtr()->KServiceType::icon(); // default icon
+
+ unmounted->setIcon( unmountedStr );
+
+ connect( device, TQT_SIGNAL( activated( int ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( device, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( readonly, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( unmounted, TQT_SIGNAL( iconChanged( TQString ) ),
+ this, TQT_SIGNAL( changed() ) );
+
+ connect( device, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SLOT( slotDeviceChanged() ) );
+}
+
+KDevicePropsPlugin::~KDevicePropsPlugin()
+{
+ delete d;
+}
+
+// TQString KDevicePropsPlugin::tabName () const
+// {
+// return i18n ("De&vice");
+// }
+
+void KDevicePropsPlugin::updateInfo()
+{
+ // we show it in the slot when we know the values
+ d->m_freeSpaceText->hide();
+ d->m_freeSpaceLabel->hide();
+ d->m_freeSpaceBar->hide();
+
+ if ( !mountpoint->text().isEmpty() )
+ {
+ KDiskFreeSp * job = new KDiskFreeSp;
+ connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ),
+ this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString& ) ) );
+
+ job->readDF( mountpoint->text() );
+ }
+}
+
+void KDevicePropsPlugin::slotActivated( int index )
+{
+ // Update mountpoint so that it matches the device that was selected in the combo
+ device->setEditText( m_devicelist[index] );
+ mountpoint->setText( d->mountpointlist[index] );
+
+ updateInfo();
+}
+
+void KDevicePropsPlugin::slotDeviceChanged()
+{
+ // Update mountpoint so that it matches the typed device
+ int index = m_devicelist.findIndex( device->currentText() );
+ if ( index != -1 )
+ mountpoint->setText( d->mountpointlist[index] );
+ else
+ mountpoint->setText( TQString::null );
+
+ updateInfo();
+}
+
+void KDevicePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const TQString& )
+{
+ d->m_freeSpaceText->show();
+ d->m_freeSpaceLabel->show();
+
+ int percUsed = 100 - (int)(100.0 * kBAvail / kBSize);
+
+ d->m_freeSpaceLabel->setText(
+ // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
+ i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
+ .arg(TDEIO::convertSizeFromKB(kBAvail))
+ .arg(TDEIO::convertSizeFromKB(kBSize))
+ .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
+
+ d->m_freeSpaceBar->setProgress(percUsed, 100);
+ d->m_freeSpaceBar->show();
+}
+
+bool KDevicePropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasDeviceType();
+}
+
+void KDevicePropsPlugin::applyChanges()
+{
+ TQString path = properties->kurl().path();
+ TQFile f( path );
+ if ( !f.open( IO_ReadWrite ) )
+ {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient "
+ "access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("FSDevice") );
+
+ config.writeEntry( "Dev", device->currentText() );
+ config.writeEntry( "MountPoint", mountpoint->text() );
+
+ config.writeEntry( "UnmountIcon", unmounted->icon() );
+ kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
+
+ config.writeEntry( "ReadOnly", readonly->isChecked() );
+
+ config.sync();
+}
+
+
+/* ----------------------------------------------------
+ *
+ * KDesktopPropsPlugin
+ *
+ * -------------------------------------------------- */
+
+
+KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ TQFrame *frame = properties->addPage(i18n("&Application"));
+ TQVBoxLayout *mainlayout = new TQVBoxLayout( frame, 0, KDialog::spacingHint() );
+
+ w = new KPropertiesDesktopBase(frame);
+ mainlayout->addWidget(w);
+
+ bool bKDesktopMode = (TQCString(tqApp->name()) == "kdesktop"); // nasty heh?
+
+ if (bKDesktopMode)
+ {
+ // Hide Name entry
+ w->nameEdit->hide();
+ w->nameLabel->hide();
+ }
+
+ w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly);
+ w->pathEdit->lineEdit()->setAcceptDrops(false);
+
+ connect( w->nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
+ connect( w->genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
+ connect( w->commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
+ connect( w->commandEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
+ connect( w->pathEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
+
+ connect( w->browseButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) );
+ connect( w->addFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAddFiletype() ) );
+ connect( w->delFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDelFiletype() ) );
+ connect( w->advancedButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAdvanced() ) );
+
+ // now populate the page
+ TQString path = _props->kurl().path();
+ TQFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KDesktopFile config( path );
+ TQString nameStr = config.readName();
+ TQString genNameStr = config.readGenericName();
+ TQString commentStr = config.readComment();
+ TQString commandStr = config.readPathEntry( "Exec" );
+ if (commandStr.left(12) == "ksystraycmd ")
+ {
+ commandStr.remove(0, 12);
+ m_systrayBool = true;
+ }
+ else
+ m_systrayBool = false;
+
+ m_origCommandStr = commandStr;
+ TQString pathStr = config.readPathEntry( "Path" );
+ m_terminalBool = config.readBoolEntry( "Terminal" );
+ m_terminalOptionStr = config.readEntry( "TerminalOptions" );
+ m_suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" );
+ m_suidUserStr = config.readEntry( "X-TDE-Username" );
+ if( config.hasKey( "StartupNotify" ))
+ m_startupBool = config.readBoolEntry( "StartupNotify", true );
+ else
+ m_startupBool = config.readBoolEntry( "X-TDE-StartupNotify", true );
+ m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower();
+
+ TQStringList mimeTypes = config.readListEntry( "MimeType", ';' );
+
+ if ( nameStr.isEmpty() || bKDesktopMode ) {
+ // We'll use the file name if no name is specified
+ // because we _need_ a Name for a valid file.
+ // But let's do it in apply, not here, so that we pick up the right name.
+ setDirty();
+ }
+ if ( !bKDesktopMode )
+ w->nameEdit->setText(nameStr);
+
+ w->genNameEdit->setText( genNameStr );
+ w->commentEdit->setText( commentStr );
+ w->commandEdit->setText( commandStr );
+ w->pathEdit->lineEdit()->setText( pathStr );
+ w->filetypeList->setAllColumnsShowFocus(true);
+
+ KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
+ for(TQStringList::ConstIterator it = mimeTypes.begin();
+ it != mimeTypes.end(); )
+ {
+ KMimeType::Ptr p = KMimeType::mimeType(*it);
+ ++it;
+ TQString preference;
+ if (it != mimeTypes.end())
+ {
+ bool numeric;
+ (*it).toInt(&numeric);
+ if (numeric)
+ {
+ preference = *it;
+ ++it;
+ }
+ }
+ if (p && (p != defaultMimetype))
+ {
+ new TQListViewItem(w->filetypeList, p->name(), p->comment(), preference);
+ }
+ }
+
+}
+
+KDesktopPropsPlugin::~KDesktopPropsPlugin()
+{
+}
+
+void KDesktopPropsPlugin::slotSelectMimetype()
+{
+ TQListView *w = (TQListView*)sender();
+ TQListViewItem *item = w->firstChild();
+ while(item)
+ {
+ if (item->isSelected())
+ w->setSelected(item, false);
+ item = item->nextSibling();
+ }
+}
+
+void KDesktopPropsPlugin::slotAddFiletype()
+{
+ KDialogBase dlg(w, "KPropertiesMimetypes", true,
+ i18n("Add File Type for %1").arg(properties->kurl().fileName()),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
+
+ KGuiItem okItem(i18n("&Add"), TQString::null /* no icon */,
+ i18n("Add the selected file types to\nthe list of supported file types."),
+ i18n("Add the selected file types to\nthe list of supported file types."));
+ dlg.setButtonOK(okItem);
+
+ KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg);
+
+ dlg.setMainWidget(mw);
+
+ {
+ mw->listView->setRootIsDecorated(true);
+ mw->listView->setSelectionMode(TQListView::Extended);
+ mw->listView->setAllColumnsShowFocus(true);
+ mw->listView->setFullWidth(true);
+ mw->listView->setMinimumSize(500,400);
+
+ connect(mw->listView, TQT_SIGNAL(selectionChanged()),
+ this, TQT_SLOT(slotSelectMimetype()));
+ connect(mw->listView, TQT_SIGNAL(doubleClicked( TQListViewItem *, const TQPoint &, int )),
+ &dlg, TQT_SLOT( slotOk()));
+
+ TQMap<TQString,TQListViewItem*> majorMap;
+ TQListViewItem *majorGroup;
+ KMimeType::List mimetypes = KMimeType::allMimeTypes();
+ TQValueListIterator<KMimeType::Ptr> it(mimetypes.begin());
+ for (; it != mimetypes.end(); ++it) {
+ TQString mimetype = (*it)->name();
+ if (mimetype == KMimeType::defaultMimeType())
+ continue;
+ int index = mimetype.find("/");
+ TQString maj = mimetype.left(index);
+ TQString min = mimetype.mid(index+1);
+
+ TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( maj );
+ if ( mit == majorMap.end() ) {
+ majorGroup = new TQListViewItem( mw->listView, maj );
+ majorGroup->setExpandable(true);
+ mw->listView->setOpen(majorGroup, true);
+ majorMap.insert( maj, majorGroup );
+ }
+ else
+ {
+ majorGroup = mit.data();
+ }
+
+ TQListViewItem *item = new TQListViewItem(majorGroup, min, (*it)->comment());
+ item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small)));
+ }
+ TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( "all" );
+ if ( mit != majorMap.end())
+ {
+ mw->listView->setCurrentItem(mit.data());
+ mw->listView->ensureItemVisible(mit.data());
+ }
+ }
+
+ if (dlg.exec() == KDialogBase::Accepted)
+ {
+ KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
+ TQListViewItem *majorItem = mw->listView->firstChild();
+ while(majorItem)
+ {
+ TQString major = majorItem->text(0);
+
+ TQListViewItem *minorItem = majorItem->firstChild();
+ while(minorItem)
+ {
+ if (minorItem->isSelected())
+ {
+ TQString mimetype = major + "/" + minorItem->text(0);
+ KMimeType::Ptr p = KMimeType::mimeType(mimetype);
+ if (p && (p != defaultMimetype))
+ {
+ mimetype = p->name();
+ bool found = false;
+ TQListViewItem *item = w->filetypeList->firstChild();
+ while (item)
+ {
+ if (mimetype == item->text(0))
+ {
+ found = true;
+ break;
+ }
+ item = item->nextSibling();
+ }
+ if (!found) {
+ new TQListViewItem(w->filetypeList, p->name(), p->comment());
+ emit changed();
+ }
+ }
+ }
+ minorItem = minorItem->nextSibling();
+ }
+
+ majorItem = majorItem->nextSibling();
+ }
+
+ }
+}
+
+void KDesktopPropsPlugin::slotDelFiletype()
+{
+ delete w->filetypeList->currentItem();
+ emit changed();
+}
+
+void KDesktopPropsPlugin::checkCommandChanged()
+{
+ if (KRun::binaryName(w->commandEdit->text(), true) !=
+ KRun::binaryName(m_origCommandStr, true))
+ {
+ TQString m_origCommandStr = w->commandEdit->text();
+ m_dcopServiceType= TQString::null; // Reset
+ }
+}
+
+void KDesktopPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl;
+ TQString path = properties->kurl().path();
+
+ TQFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ // If the command is changed we reset certain settings that are strongly
+ // coupled to the command.
+ checkCommandChanged();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("Application"));
+ config.writeEntry( "Comment", w->commentEdit->text() );
+ config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "GenericName", w->genNameEdit->text() );
+ config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat
+
+ if (m_systrayBool)
+ config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") );
+ else
+ config.writePathEntry( "Exec", w->commandEdit->text() );
+ config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() );
+
+ // Write mimeTypes
+ TQStringList mimeTypes;
+ for( TQListViewItem *item = w->filetypeList->firstChild();
+ item; item = item->nextSibling() )
+ {
+ TQString preference = item->text(2);
+ mimeTypes.append(item->text(0));
+ if (!preference.isEmpty())
+ mimeTypes.append(preference);
+ }
+
+ config.writeEntry( "MimeType", mimeTypes, ';' );
+
+ if ( !w->nameEdit->isHidden() ) {
+ TQString nameStr = w->nameEdit->text();
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+ }
+
+ config.writeEntry("Terminal", m_terminalBool);
+ config.writeEntry("TerminalOptions", m_terminalOptionStr);
+ config.writeEntry("X-TDE-SubstituteUID", m_suidBool);
+ config.writeEntry("X-TDE-Username", m_suidUserStr);
+ config.writeEntry("StartupNotify", m_startupBool);
+ config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType);
+ config.sync();
+
+ // KSycoca update needed?
+ TQString sycocaPath = TDEGlobal::dirs()->relativeLocation("apps", path);
+ bool updateNeeded = !sycocaPath.startsWith("/");
+ if (!updateNeeded)
+ {
+ sycocaPath = TDEGlobal::dirs()->relativeLocation("xdgdata-apps", path);
+ updateNeeded = !sycocaPath.startsWith("/");
+ }
+ if (updateNeeded)
+ KService::rebuildKSycoca(w);
+}
+
+
+void KDesktopPropsPlugin::slotBrowseExec()
+{
+ KURL f = KFileDialog::getOpenURL( TQString::null,
+ TQString::null, w );
+ if ( f.isEmpty() )
+ return;
+
+ if ( !f.isLocalFile()) {
+ KMessageBox::sorry(w, i18n("Only executables on local file systems are supported."));
+ return;
+ }
+
+ TQString path = f.path();
+ KRun::shellQuote( path );
+ w->commandEdit->setText( path );
+}
+
+void KDesktopPropsPlugin::slotAdvanced()
+{
+ KDialogBase dlg(w, "KPropertiesDesktopAdv", true,
+ i18n("Advanced Options for %1").arg(properties->kurl().fileName()),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
+ KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg);
+
+ dlg.setMainWidget(w);
+
+ // If the command is changed we reset certain settings that are strongly
+ // coupled to the command.
+ checkCommandChanged();
+
+ // check to see if we use konsole if not do not add the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") );
+ TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
+ TQString::fromLatin1("konsole"));
+
+ bool terminalCloseBool = false;
+
+ if (preferredTerminal == "konsole")
+ {
+ terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0);
+ w->terminalCloseCheck->setChecked(terminalCloseBool);
+ m_terminalOptionStr.replace( "--noclose", "");
+ }
+ else
+ {
+ w->terminalCloseCheck->hide();
+ }
+
+ w->terminalCheck->setChecked(m_terminalBool);
+ w->terminalEdit->setText(m_terminalOptionStr);
+ w->terminalCloseCheck->setEnabled(m_terminalBool);
+ w->terminalEdit->setEnabled(m_terminalBool);
+ w->terminalEditLabel->setEnabled(m_terminalBool);
+
+ w->suidCheck->setChecked(m_suidBool);
+ w->suidEdit->setText(m_suidUserStr);
+ w->suidEdit->setEnabled(m_suidBool);
+ w->suidEditLabel->setEnabled(m_suidBool);
+
+ w->startupInfoCheck->setChecked(m_startupBool);
+ w->systrayCheck->setChecked(m_systrayBool);
+
+ if (m_dcopServiceType == "unique")
+ w->dcopCombo->setCurrentItem(2);
+ else if (m_dcopServiceType == "multi")
+ w->dcopCombo->setCurrentItem(1);
+ else if (m_dcopServiceType == "wait")
+ w->dcopCombo->setCurrentItem(3);
+ else
+ w->dcopCombo->setCurrentItem(0);
+
+ // Provide username completion up to 1000 users.
+ KCompletion *kcom = new KCompletion;
+ kcom->setOrder(KCompletion::Sorted);
+ struct passwd *pw;
+ int i, maxEntries = 1000;
+ setpwent();
+ for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(TQString::fromLatin1(pw->pw_name));
+ endpwent();
+ if (i < maxEntries)
+ {
+ w->suidEdit->setCompletionObject(kcom, true);
+ w->suidEdit->setAutoDeleteCompletionObject( true );
+ w->suidEdit->setCompletionMode(TDEGlobalSettings::CompletionAuto);
+ }
+ else
+ {
+ delete kcom;
+ }
+
+ connect( w->terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->terminalCloseCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->terminalCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->suidCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->startupInfoCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->systrayCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( w->dcopCombo, TQT_SIGNAL( highlighted( int ) ),
+ this, TQT_SIGNAL( changed() ) );
+
+ if ( dlg.exec() == TQDialog::Accepted )
+ {
+ m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace();
+ m_terminalBool = w->terminalCheck->isChecked();
+ m_suidBool = w->suidCheck->isChecked();
+ m_suidUserStr = w->suidEdit->text().stripWhiteSpace();
+ m_startupBool = w->startupInfoCheck->isChecked();
+ m_systrayBool = w->systrayCheck->isChecked();
+
+ if (w->terminalCloseCheck->isChecked())
+ {
+ m_terminalOptionStr.append(" --noclose");
+ }
+
+ switch(w->dcopCombo->currentItem())
+ {
+ case 1: m_dcopServiceType = "multi"; break;
+ case 2: m_dcopServiceType = "unique"; break;
+ case 3: m_dcopServiceType = "wait"; break;
+ default: m_dcopServiceType = "none"; break;
+ }
+ }
+}
+
+bool KDesktopPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
+}
+
+void KPropertiesDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+void KPropsDlgPlugin::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+
+
+
+/**
+ * The following code is obsolete and only kept for binary compatibility
+ * To be removed in KDE 4
+ */
+
+class KExecPropsPlugin::KExecPropsPluginPrivate
+{
+public:
+ KExecPropsPluginPrivate()
+ {
+ }
+ ~KExecPropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+ TQCheckBox *nocloseonexitCheck;
+};
+
+KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new KExecPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("E&xecute"));
+ TQVBoxLayout * mainlayout = new TQVBoxLayout( d->m_frame, 0,
+ KDialog::spacingHint());
+
+ // Now the widgets in the top layout
+
+ TQLabel* l;
+ l = new TQLabel( i18n( "Comman&d:" ), d->m_frame );
+ mainlayout->addWidget(l);
+
+ TQHBoxLayout * hlayout;
+ hlayout = new TQHBoxLayout(KDialog::spacingHint());
+ mainlayout->addLayout(hlayout);
+
+ execEdit = new KLineEdit( d->m_frame );
+ TQWhatsThis::add(execEdit,i18n(
+ "Following the command, you can have several place holders which will be replaced "
+ "with the actual values when the actual program is run:\n"
+ "%f - a single file name\n"
+ "%F - a list of files; use for applications that can open several local files at once\n"
+ "%u - a single URL\n"
+ "%U - a list of URLs\n"
+ "%d - the folder of the file to open\n"
+ "%D - a list of folders\n"
+ "%i - the icon\n"
+ "%m - the mini-icon\n"
+ "%c - the caption"));
+ hlayout->addWidget(execEdit, 1);
+
+ l->setBuddy( execEdit );
+
+ execBrowse = new TQPushButton( d->m_frame );
+ execBrowse->setText( i18n("&Browse...") );
+ hlayout->addWidget(execBrowse);
+
+ // The groupbox about swallowing
+ TQGroupBox* tmpQGroupBox;
+ tmpQGroupBox = new TQGroupBox( i18n("Panel Embedding"), d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ TQGridLayout *grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2);
+ grid->setSpacing( KDialog::spacingHint() );
+ grid->setColStretch(1, 1);
+
+ l = new TQLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
+ grid->addWidget(l, 0, 0);
+
+ swallowExecEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(swallowExecEdit, 0, 1);
+
+ l->setBuddy( swallowExecEdit );
+
+ l = new TQLabel( i18n( "&Window title:" ), tmpQGroupBox );
+ grid->addWidget(l, 1, 0);
+
+ swallowTitleEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(swallowTitleEdit, 1, 1);
+
+ l->setBuddy( swallowTitleEdit );
+
+ // The groupbox about run in terminal
+
+ tmpQGroupBox = new TQGroupBox( d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ grid = new TQGridLayout(tmpQGroupBox->layout(), 3, 2);
+ grid->setSpacing( KDialog::spacingHint() );
+ grid->setColStretch(1, 1);
+
+ terminalCheck = new TQCheckBox( tmpQGroupBox );
+ terminalCheck->setText( i18n("&Run in terminal") );
+ grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
+
+ // check to see if we use konsole if not do not add the nocloseonexit
+ // because we don't know how to do this on other terminal applications
+ TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") );
+ TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
+ TQString::fromLatin1("konsole"));
+
+ int posOptions = 1;
+ d->nocloseonexitCheck = 0L;
+ if (preferredTerminal == "konsole")
+ {
+ posOptions = 2;
+ d->nocloseonexitCheck = new TQCheckBox( tmpQGroupBox );
+ d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") );
+ grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1);
+ }
+
+ terminalLabel = new TQLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
+ grid->addWidget(terminalLabel, posOptions, 0);
+
+ terminalEdit = new KLineEdit( tmpQGroupBox );
+ grid->addWidget(terminalEdit, posOptions, 1);
+
+ terminalLabel->setBuddy( terminalEdit );
+
+ // The groupbox about run with substituted uid.
+
+ tmpQGroupBox = new TQGroupBox( d->m_frame );
+ tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
+
+ mainlayout->addWidget(tmpQGroupBox);
+
+ grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2);
+ grid->setSpacing(KDialog::spacingHint());
+ grid->setColStretch(1, 1);
+
+ suidCheck = new TQCheckBox(tmpQGroupBox);
+ suidCheck->setText(i18n("Ru&n as a different user"));
+ grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
+
+ suidLabel = new TQLabel(i18n( "&Username:" ), tmpQGroupBox);
+ grid->addWidget(suidLabel, 1, 0);
+
+ suidEdit = new KLineEdit(tmpQGroupBox);
+ grid->addWidget(suidEdit, 1, 1);
+
+ suidLabel->setBuddy( suidEdit );
+
+ mainlayout->addStretch(1);
+
+ // now populate the page
+ TQString path = _props->kurl().path();
+ TQFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDollarExpansion( false );
+ config.setDesktopGroup();
+ execStr = config.readPathEntry( "Exec" );
+ swallowExecStr = config.readPathEntry( "SwallowExec" );
+ swallowTitleStr = config.readEntry( "SwallowTitle" );
+ termBool = config.readBoolEntry( "Terminal" );
+ termOptionsStr = config.readEntry( "TerminalOptions" );
+ suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" );
+ suidUserStr = config.readEntry( "X-TDE-Username" );
+
+ if ( !swallowExecStr.isNull() )
+ swallowExecEdit->setText( swallowExecStr );
+ if ( !swallowTitleStr.isNull() )
+ swallowTitleEdit->setText( swallowTitleStr );
+
+ if ( !execStr.isNull() )
+ execEdit->setText( execStr );
+
+ if ( d->nocloseonexitCheck )
+ {
+ d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) );
+ termOptionsStr.replace( "--noclose", "");
+ }
+ if ( !termOptionsStr.isNull() )
+ terminalEdit->setText( termOptionsStr );
+
+ terminalCheck->setChecked( termBool );
+ enableCheckedEdit();
+
+ suidCheck->setChecked( suidBool );
+ suidEdit->setText( suidUserStr );
+ enableSuidEdit();
+
+ // Provide username completion up to 1000 users.
+ KCompletion *kcom = new KCompletion;
+ kcom->setOrder(KCompletion::Sorted);
+ struct passwd *pw;
+ int i, maxEntries = 1000;
+ setpwent();
+ for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
+ kcom->addItem(TQString::fromLatin1(pw->pw_name));
+ endpwent();
+ if (i < maxEntries)
+ {
+ suidEdit->setCompletionObject(kcom, true);
+ suidEdit->setAutoDeleteCompletionObject( true );
+ suidEdit->setCompletionMode(TDEGlobalSettings::CompletionAuto);
+ }
+ else
+ {
+ delete kcom;
+ }
+
+ connect( swallowExecEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( swallowTitleEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( execEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ if (d->nocloseonexitCheck)
+ connect( d->nocloseonexitCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( terminalCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( suidCheck, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+
+ connect( execBrowse, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) );
+ connect( terminalCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableCheckedEdit() ) );
+ connect( suidCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableSuidEdit() ) );
+
+}
+
+KExecPropsPlugin::~KExecPropsPlugin()
+{
+ delete d;
+}
+
+void KExecPropsPlugin::enableCheckedEdit()
+{
+ bool checked = terminalCheck->isChecked();
+ terminalLabel->setEnabled( checked );
+ if (d->nocloseonexitCheck)
+ d->nocloseonexitCheck->setEnabled( checked );
+ terminalEdit->setEnabled( checked );
+}
+
+void KExecPropsPlugin::enableSuidEdit()
+{
+ bool checked = suidCheck->isChecked();
+ suidLabel->setEnabled( checked );
+ suidEdit->setEnabled( checked );
+}
+
+bool KExecPropsPlugin::supports( KFileItemList _items )
+{
+ if ( _items.count() != 1 )
+ return false;
+ KFileItem * item = _items.first();
+ // check if desktop file
+ if ( !KPropsDlgPlugin::isDesktopFile( item ) )
+ return false;
+ // open file and check type
+ KDesktopFile config( item->url().path(), true /* readonly */ );
+ return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
+}
+
+void KExecPropsPlugin::applyChanges()
+{
+ kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
+ TQString path = properties->kurl().path();
+
+ TQFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
+ "sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("Application"));
+ config.writePathEntry( "Exec", execEdit->text() );
+ config.writePathEntry( "SwallowExec", swallowExecEdit->text() );
+ config.writeEntry( "SwallowTitle", swallowTitleEdit->text() );
+ config.writeEntry( "Terminal", terminalCheck->isChecked() );
+ TQString temp = terminalEdit->text();
+ if (d->nocloseonexitCheck )
+ if ( d->nocloseonexitCheck->isChecked() )
+ temp += TQString::fromLatin1("--noclose ");
+ temp = temp.stripWhiteSpace();
+ config.writeEntry( "TerminalOptions", temp );
+ config.writeEntry( "X-TDE-SubstituteUID", suidCheck->isChecked() );
+ config.writeEntry( "X-TDE-Username", suidEdit->text() );
+}
+
+
+void KExecPropsPlugin::slotBrowseExec()
+{
+ KURL f = KFileDialog::getOpenURL( TQString::null,
+ TQString::null, d->m_frame );
+ if ( f.isEmpty() )
+ return;
+
+ if ( !f.isLocalFile()) {
+ KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
+ return;
+ }
+
+ TQString path = f.path();
+ KRun::shellQuote( path );
+ execEdit->setText( path );
+}
+
+class TDEApplicationPropsPlugin::TDEApplicationPropsPluginPrivate
+{
+public:
+ TDEApplicationPropsPluginPrivate()
+ {
+ m_kdesktopMode = TQCString(tqApp->name()) == "kdesktop"; // nasty heh?
+ }
+ ~TDEApplicationPropsPluginPrivate()
+ {
+ }
+
+ TQFrame *m_frame;
+ bool m_kdesktopMode;
+};
+
+TDEApplicationPropsPlugin::TDEApplicationPropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new TDEApplicationPropsPluginPrivate;
+ d->m_frame = properties->addPage(i18n("&Application"));
+ TQVBoxLayout *toplayout = new TQVBoxLayout( d->m_frame, 0, KDialog::spacingHint());
+
+ TQIconSet iconSet;
+ TQPixmap pixMap;
+
+ addExtensionButton = new TQPushButton( TQString::null, d->m_frame );
+ iconSet = SmallIconSet( "back" );
+ addExtensionButton->setIconSet( iconSet );
+ pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal );
+ addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ connect( addExtensionButton, TQT_SIGNAL( clicked() ),
+ TQT_SLOT( slotAddExtension() ) );
+
+ delExtensionButton = new TQPushButton( TQString::null, d->m_frame );
+ iconSet = SmallIconSet( "forward" );
+ delExtensionButton->setIconSet( iconSet );
+ delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ connect( delExtensionButton, TQT_SIGNAL( clicked() ),
+ TQT_SLOT( slotDelExtension() ) );
+
+ TQLabel *l;
+
+ TQGridLayout *grid = new TQGridLayout(2, 2);
+ grid->setColStretch(1, 1);
+ toplayout->addLayout(TQT_TQLAYOUT(grid));
+
+ if ( d->m_kdesktopMode )
+ {
+ // in kdesktop the name field comes from the first tab
+ nameEdit = 0L;
+ }
+ else
+ {
+ l = new TQLabel(i18n("Name:"), d->m_frame, "Label_4" );
+ grid->addWidget(l, 0, 0);
+
+ nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
+ grid->addWidget(nameEdit, 0, 1);
+ }
+
+ l = new TQLabel(i18n("Description:"), d->m_frame, "Label_5" );
+ grid->addWidget(l, 1, 0);
+
+ genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
+ grid->addWidget(genNameEdit, 1, 1);
+
+ l = new TQLabel(i18n("Comment:"), d->m_frame, "Label_3" );
+ grid->addWidget(l, 2, 0);
+
+ commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
+ grid->addWidget(commentEdit, 2, 1);
+
+ l = new TQLabel(i18n("File types:"), d->m_frame);
+ toplayout->addWidget(l, 0, AlignLeft);
+
+ grid = new TQGridLayout(4, 3);
+ grid->setColStretch(0, 1);
+ grid->setColStretch(2, 1);
+ grid->setRowStretch( 0, 1 );
+ grid->setRowStretch( 3, 1 );
+ toplayout->addLayout(TQT_TQLAYOUT(grid), 2);
+
+ extensionsList = new TQListBox( d->m_frame );
+ extensionsList->setSelectionMode( TQListBox::Extended );
+ grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
+
+ grid->addWidget(addExtensionButton, 1, 1);
+ grid->addWidget(delExtensionButton, 2, 1);
+
+ availableExtensionsList = new TQListBox( d->m_frame );
+ availableExtensionsList->setSelectionMode( TQListBox::Extended );
+ grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
+
+ TQString path = properties->kurl().path() ;
+ TQFile f( path );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ f.close();
+
+ KDesktopFile config( path );
+ TQString commentStr = config.readComment();
+ TQString genNameStr = config.readGenericName();
+
+ TQStringList selectedTypes = config.readListEntry( "ServiceTypes" );
+ // For compatibility with KDE 1.x
+ selectedTypes += config.readListEntry( "MimeType", ';' );
+
+ TQString nameStr = config.readName();
+ if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
+ // We'll use the file name if no name is specified
+ // because we _need_ a Name for a valid file.
+ // But let's do it in apply, not here, so that we pick up the right name.
+ setDirty();
+ }
+
+ commentEdit->setText( commentStr );
+ genNameEdit->setText( genNameStr );
+ if ( nameEdit )
+ nameEdit->setText( nameStr );
+
+ selectedTypes.sort();
+ TQStringList::Iterator sit = selectedTypes.begin();
+ for( ; sit != selectedTypes.end(); ++sit ) {
+ if ( !((*sit).isEmpty()) )
+ extensionsList->insertItem( *sit );
+ }
+
+ KMimeType::List mimeTypes = KMimeType::allMimeTypes();
+ TQValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
+ for ( ; it2 != mimeTypes.end(); ++it2 )
+ addMimeType ( (*it2)->name() );
+
+ updateButton();
+
+ connect( extensionsList, TQT_SIGNAL( highlighted( int ) ),
+ this, TQT_SLOT( updateButton() ) );
+ connect( availableExtensionsList, TQT_SIGNAL( highlighted( int ) ),
+ this, TQT_SLOT( updateButton() ) );
+
+ connect( addExtensionButton, TQT_SIGNAL( clicked() ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( delExtensionButton, TQT_SIGNAL( clicked() ),
+ this, TQT_SIGNAL( changed() ) );
+ if ( nameEdit )
+ connect( nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( availableExtensionsList, TQT_SIGNAL( selected( int ) ),
+ this, TQT_SIGNAL( changed() ) );
+ connect( extensionsList, TQT_SIGNAL( selected( int ) ),
+ this, TQT_SIGNAL( changed() ) );
+}
+
+TDEApplicationPropsPlugin::~TDEApplicationPropsPlugin()
+{
+ delete d;
+}
+
+// TQString TDEApplicationPropsPlugin::tabName () const
+// {
+// return i18n ("&Application");
+// }
+
+void TDEApplicationPropsPlugin::updateButton()
+{
+ addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
+ delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
+}
+
+void TDEApplicationPropsPlugin::addMimeType( const TQString & name )
+{
+ // Add a mimetype to the list of available mime types if not in the extensionsList
+
+ bool insert = true;
+
+ for ( uint i = 0; i < extensionsList->count(); i++ )
+ if ( extensionsList->text( i ) == name )
+ insert = false;
+
+ if ( insert )
+ {
+ availableExtensionsList->insertItem( name );
+ availableExtensionsList->sort();
+ }
+}
+
+bool TDEApplicationPropsPlugin::supports( KFileItemList _items )
+{
+ // same constraints as KExecPropsPlugin : desktop file with Type = Application
+ return KExecPropsPlugin::supports( _items );
+}
+
+void TDEApplicationPropsPlugin::applyChanges()
+{
+ TQString path = properties->kurl().path();
+
+ TQFile f( path );
+
+ if ( !f.open( IO_ReadWrite ) ) {
+ KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
+ "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
+ return;
+ }
+ f.close();
+
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ config.writeEntry( "Type", TQString::fromLatin1("Application"));
+ config.writeEntry( "Comment", commentEdit->text() );
+ config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat
+ config.writeEntry( "GenericName", genNameEdit->text() );
+ config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat
+
+ TQStringList selectedTypes;
+ for ( uint i = 0; i < extensionsList->count(); i++ )
+ selectedTypes.append( extensionsList->text( i ) );
+
+ config.writeEntry( "MimeType", selectedTypes, ';' );
+ config.writeEntry( "ServiceTypes", "" );
+ // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
+
+ TQString nameStr = nameEdit ? nameEdit->text() : TQString::null;
+ if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
+ nameStr = nameFromFileName(properties->kurl().fileName());
+
+ config.writeEntry( "Name", nameStr );
+ config.writeEntry( "Name", nameStr, true, false, true );
+
+ config.sync();
+}
+
+void TDEApplicationPropsPlugin::slotAddExtension()
+{
+ TQListBoxItem *item = availableExtensionsList->firstItem();
+ TQListBoxItem *nextItem;
+
+ while ( item )
+ {
+ nextItem = item->next();
+
+ if ( item->isSelected() )
+ {
+ extensionsList->insertItem( item->text() );
+ availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
+ }
+
+ item = nextItem;
+ }
+
+ extensionsList->sort();
+ updateButton();
+}
+
+void TDEApplicationPropsPlugin::slotDelExtension()
+{
+ TQListBoxItem *item = extensionsList->firstItem();
+ TQListBoxItem *nextItem;
+
+ while ( item )
+ {
+ nextItem = item->next();
+
+ if ( item->isSelected() )
+ {
+ availableExtensionsList->insertItem( item->text() );
+ extensionsList->removeItem( extensionsList->index( item ) );
+ }
+
+ item = nextItem;
+ }
+
+ availableExtensionsList->sort();
+ updateButton();
+}
+
+
+
+#include "kpropertiesdialog.moc"
diff --git a/tdeio/tdefile/kpropertiesdialog.h b/tdeio/tdefile/kpropertiesdialog.h
new file mode 100644
index 000000000..db89487a8
--- /dev/null
+++ b/tdeio/tdefile/kpropertiesdialog.h
@@ -0,0 +1,918 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org>
+ Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
+ 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.
+*/
+
+/*
+ * This file holds the definitions for all classes used to
+ * display a properties dialog.
+ */
+
+#ifndef __propsdlg_h
+#define __propsdlg_h
+
+#include <tqstring.h>
+#include <tqptrlist.h>
+
+#include <kdemacros.h>
+#include <kurl.h>
+#include <tdefileitem.h>
+#include <kdialogbase.h>
+
+class TQLineEdit;
+class TQCheckBox;
+class TQPushButton;
+class KLineEdit;
+class KURLRequester;
+class TQButton;
+class KIconButton;
+class KPropsDlgPlugin;
+class TQComboBox;
+
+#define KPropsPage KPropsDlgPlugin
+
+namespace TDEIO { class Job; }
+
+/**
+ * The main properties dialog class.
+ * A Properties Dialog is a dialog which displays various information
+ * about a particular file or URL, or several files or URLs.
+ * This main class holds various related classes, which are instantiated in
+ * the form of tab entries in the tabbed dialog that this class provides.
+ * The various tabs themselves will let the user view, and sometimes change,
+ * information about the file or URL.
+ *
+ * \image html kpropertiesdialog.png "Typical KProperties Dialog"
+ *
+ * This class must be created with (void)new KPropertiesDialog(...)
+ * It will take care of deleting itself.
+ *
+ * If you are looking for more flexibility, see KFileMetaInfo and
+ * KFileMetaInfoWidget.
+ */
+class TDEIO_EXPORT KPropertiesDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Determine whether there are any property pages available for the
+ * given file items.
+ * @param _items the list of items to check.
+ * @return true if there are any property pages, otherwise false.
+ */
+ static bool canDisplay( KFileItemList _items );
+
+ /**
+ * Brings up a Properties dialog, as shown above.
+ * This is the normal constructor for
+ * file-manager type applications, where you have a KFileItem instance
+ * to work with. Normally you will use this
+ * method rather than the one below.
+ *
+ * @param item file item whose properties should be displayed.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically.
+ */
+ KPropertiesDialog( KFileItem * item,
+ TQWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * \overload
+ *
+ * You use this constructor for cases where you have a number of items,
+ * rather than a single item. Be careful which methods you use
+ * when passing a list of files or URLs, since some of them will only
+ * work on the first item in a list.
+ *
+ * @param _items list of file items whose properties should be displayed.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically.
+ */
+ KPropertiesDialog( KFileItemList _items,
+ TQWidget *parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated You should use the following constructor instead of this one.
+ * The only change that is required is to delete the _mode argument.
+ *
+ * @param _url the URL whose properties should be displayed
+ * @param _mode unused.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whether it should show itself automatically. */
+ KPropertiesDialog( const KURL& _url, mode_t _mode,
+ TQWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true) KDE_DEPRECATED;
+#endif
+
+ /**
+ * Brings up a Properties dialog. Convenience constructor for
+ * non-file-manager applications, where you have a KURL rather than a
+ * KFileItem or KFileItemList.
+ *
+ * @param _url the URL whose properties should be displayed
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * IMPORTANT: This constructor, together with modal=true, leads to a grave
+ * display bug (due to TDEIO::stat() being run before the dialog has all the
+ * necessary information). Do not use this combination for now.
+ * For local files with a known mimetype, simply create a KFileItem and pass
+ * it to the other constructor.
+ *
+ * @param autoShow tells the dialog whethr it should show itself automatically.
+ */
+ KPropertiesDialog( const KURL& _url,
+ TQWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * Creates a properties dialog for a new .desktop file (whose name
+ * is not known yet), based on a template. Special constructor for
+ * "File / New" in file-manager type applications.
+ *
+ * @param _tempUrl template used for reading only
+ * @param _currentDir directory where the file will be written to
+ * @param _defaultName something to put in the name field,
+ * like mimetype.desktop
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ * @param autoShow tells the dialog whethr it should show itself automatically.
+ */
+ KPropertiesDialog( const KURL& _tempUrl, const KURL& _currentDir,
+ const TQString& _defaultName,
+ TQWidget* parent = 0L, const char* name = 0L,
+ bool modal = false, bool autoShow = true);
+
+ /**
+ * Creates an empty properties dialog (for applications that want use
+ * a standard dialog, but for things not doable via the plugin-mechanism).
+ *
+ * @param title is the string display as the "filename" in the caption of the dialog.
+ * @param parent is the parent of the dialog widget.
+ * @param name is the internal name.
+ * @param modal tells the dialog whether it should be modal.
+ */
+ KPropertiesDialog (const TQString& title,
+ TQWidget* parent = 0L, const char* name = 0L, bool modal = false);
+
+ /**
+ * Cleans up the properties dialog and frees any associated resources,
+ * including the dialog itself. Note that when a properties dialog is
+ * closed it cleans up and deletes itself.
+ */
+ virtual ~KPropertiesDialog();
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p item points to a local file, native (non modal) property
+ * dialog is displayed (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(KFileItem* item, TQWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p _url points to a local file, native (non modal) property
+ * dialog is displayed (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(const KURL& _url, TQWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Immediately displays a Properties dialog using constructor with
+ * the same parameters.
+ * On MS Windows, if @p _items has one element and this element points
+ * to a local file, native (non modal) property dialog is displayed
+ * (@p parent and @p modal are ignored in this case).
+ *
+ * @return true on succesfull dialog displaying (can be false on win32).
+ * @since 3.4
+ */
+ static bool showDialog(const KFileItemList& _items, TQWidget* parent = 0,
+ const char* name = 0, bool modal = false);
+
+ /**
+ * Adds a "3rd party" properties plugin to the dialog. Useful
+ * for extending the properties mechanism.
+ *
+ * To create a new plugin type, inherit from the base class KPropsDlgPlugin
+ * and implement all the methods. If you define a service .desktop file
+ * for your plugin, you do not need to call insertPlugin().
+ *
+ * @param plugin is a pointer to the KPropsDlgPlugin. The Properties
+ * dialog will do destruction for you. The KPropsDlgPlugin \b must
+ * have been created with the KPropertiesDialog as its parent.
+ * @see KPropsDlgPlugin
+ */
+ void insertPlugin (KPropsDlgPlugin *plugin);
+
+ /**
+ * The URL of the file that has its properties being displayed.
+ * This is only valid if the KPropertiesDialog was created/shown
+ * for one file or URL.
+ *
+ * @return a parsed URL.
+ */
+ const KURL& kurl() const { return m_singleUrl; }
+
+ /**
+ * @return the file item for which the dialog is shown
+ *
+ * Warning: this method returns the first item of the list.
+ * This means that you should use this only if you are sure the dialog is used
+ * for a single item. Otherwise, you probably want items() instead.
+ */
+ KFileItem *item() { return m_items.first(); }
+
+ /**
+ * @return the items for which the dialog is shown
+ */
+ KFileItemList items() const { return m_items; }
+
+ /**
+ * @return a pointer to the dialog
+ * @deprecated KPropertiesDialog directly inherits from KDialogBase, so use \a this instead
+ */
+ KDE_DEPRECATED KDialogBase* dialog() { return this; }
+ /**
+ * @return a pointer to the dialog
+ * @deprecated KPropertiesDialog directly inherits from KDialogBase, so use \a this instead
+ */
+ KDE_DEPRECATED const KDialogBase* dialog() const { return this; }
+
+ /**
+ * If the dialog is being built from a template, this method
+ * returns the current directory. If no template, it returns TQString::null.
+ * See the template form of the constructor.
+ *
+ * @return the current directory or TQString::null
+ */
+ const KURL& currentDir() const { return m_currentDir; }
+
+ /**
+ * If the dialog is being built from a template, this method
+ * returns the default name. If no template, it returns TQString::null.
+ * See the template form of the constructor.
+ * @return the default name or TQString::null
+ */
+ const TQString& defaultName() const { return m_defaultName; }
+
+ /**
+ * Updates the item URL (either called by rename or because
+ * a global apps/mimelnk desktop file is being saved)
+ * Can only be called if the dialog applies to a single file or URL.
+ * @param _newUrl the new URL
+ */
+ void updateUrl( const KURL& _newUrl );
+
+ /**
+ * Renames the item to the specified name. This can only be called if
+ * the dialog applies to a single file or URL.
+ * @param _name new filename, encoded.
+ * \see FilePropsDlgPlugin::applyChanges
+ */
+ void rename( const TQString& _name );
+
+ /**
+ * To abort applying changes.
+ */
+ void abortApplying();
+
+ /**
+ * Shows the page that was previously set by
+ * setFileSharingPage(), or does nothing if no page
+ * was set yet.
+ * \see setFileSharingPage
+ * @since 3.1
+ */
+ void showFileSharingPage();
+
+ /**
+ * Sets the file sharing page.
+ * This page is shown when calling showFileSharingPage().
+ *
+ * @param page the page to set
+ * \see showFileSharingPage
+ * @since 3.3
+ */
+ void setFileSharingPage(TQWidget* page);
+
+ /**
+ * Call this to make the filename lineedit readonly, to prevent the user
+ * from renaming the file.
+ * \param ro true if the lineedit should be read only
+ * @since 3.2
+ */
+ void setFileNameReadOnly( bool ro );
+
+public slots:
+ /**
+ * Called when the user presses 'Ok'.
+ */
+ virtual void slotOk(); // Deletes the PropertiesDialog instance
+ /**
+ * Called when the user presses 'Cancel'.
+ */
+ virtual void slotCancel(); // Deletes the PropertiesDialog instance
+
+signals:
+ /**
+ * This signal is emitted when the Properties Dialog is closed (for
+ * example, with OK or Cancel buttons)
+ */
+ void propertiesClosed();
+
+ /**
+ * This signal is emitted when the properties changes are applied (for
+ * example, with the OK button)
+ */
+ void applied();
+
+ /**
+ * This signal is emitted when the properties changes are aborted (for
+ * example, with the Cancel button)
+ */
+
+ void canceled();
+ /**
+ * Emitted before changes to @p oldUrl are saved as @p newUrl.
+ * The receiver may change @p newUrl to point to an alternative
+ * save location.
+ */
+ void saveAs(const KURL &oldUrl, KURL &newUrl);
+
+private:
+
+ /**
+ * Common initialization for all constructors
+ */
+ void init (bool modal = false, bool autoShow = true);
+
+ /**
+ * Inserts all pages in the dialog.
+ */
+ void insertPages();
+
+ /**
+ * The URL of the props dialog (when shown for only one file)
+ */
+ KURL m_singleUrl;
+
+ /**
+ * List of items this props dialog is shown for
+ */
+ KFileItemList m_items;
+
+ /**
+ * For templates
+ */
+ TQString m_defaultName;
+ KURL m_currentDir;
+
+ /**
+ * List of all plugins inserted ( first one first )
+ */
+ TQPtrList<KPropsDlgPlugin> m_pageList;
+
+private slots:
+ void slotStatResult( TDEIO::Job * ); // No longer used
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KPropertiesDialogPrivate;
+ KPropertiesDialogPrivate *d;
+};
+
+/**
+ * A Plugin in the Properties dialog
+ * This is an abstract class. You must inherit from this class
+ * to build a new kind of tabbed page for the KPropertiesDialog.
+ * A plugin in itself is just a library containing code, not a dialog's page.
+ * It's up to the plugin to insert pages into the parent dialog.
+ *
+ * To make a plugin available, define a service that implements the KPropsDlg/Plugin
+ * servicetype, as well as the mimetypes for which the plugin should be created.
+ * For instance, ServiceTypes=KPropsDlg/Plugin,text/html,application/x-mymimetype.
+ *
+ * You can also include X-TDE-Protocol=file if you want that plugin
+ * to be loaded only for local files, for instance.
+ */
+class TDEIO_EXPORT KPropsDlgPlugin : public TQObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ * To insert tabs into the properties dialog, use the add methods provided by
+ * KDialogBase (the properties dialog is a KDialogBase).
+ */
+ KPropsDlgPlugin( KPropertiesDialog *_props );
+ virtual ~KPropsDlgPlugin();
+
+ /**
+ * Applies all changes to the file.
+ * This function is called when the user presses 'Ok'. The last plugin inserted
+ * is called first.
+ */
+ virtual void applyChanges();
+
+ /**
+ * Convenience method for most ::supports methods
+ * @return true if the file is a local, regular, readable, desktop file
+ */
+ static bool isDesktopFile( KFileItem * _item );
+
+ void setDirty( bool b );
+ bool isDirty() const;
+
+public slots:
+ void setDirty(); // same as setDirty( true )
+
+signals:
+ /**
+ * Emit this signal when the user changed anything in the plugin's tabs.
+ * The hosting PropertiesDialog will call applyChanges only if the
+ * PropsPlugin has emitted this signal before.
+ */
+ void changed();
+
+protected:
+ /**
+ * Pointer to the dialog
+ */
+ KPropertiesDialog *properties;
+
+ int fontHeight;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KPropsDlgPluginPrivate;
+ KPropsDlgPluginPrivate *d;
+};
+
+/**
+ * 'General' plugin
+ * This plugin displays the name of the file, its size and access times.
+ * @internal
+ */
+class TDEIO_EXPORT KFilePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KFilePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFilePropsPlugin();
+
+ /**
+ * Applies all changes made. This plugin must be always the first
+ * plugin in the dialog, since this function may rename the file which
+ * may confuse other applyChanges functions.
+ */
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the files specified by _items need a 'General' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+ /**
+ * Called after all plugins applied their changes
+ */
+ void postApplyChanges();
+
+ void setFileNameReadOnly( bool ro );
+
+protected slots:
+ void slotEditFileType();
+ void slotCopyFinished( TDEIO::Job * );
+ void slotFileRenamed( TDEIO::Job *, const KURL &, const KURL & );
+ void slotDirSizeUpdate();
+ void slotDirSizeFinished( TDEIO::Job * );
+ void slotFoundMountPoint( const TQString& mp, unsigned long kBSize,
+ unsigned long kBUsed, unsigned long kBAvail );
+ void slotSizeStop();
+ void slotSizeDetermine();
+
+private slots:
+ // workaround for compiler bug
+ void slotFoundMountPoint( const unsigned long& kBSize, const unsigned long&
+ kBUsed, const unsigned long& kBAvail, const TQString& mp );
+ void nameFileChanged(const TQString &text );
+ void slotIconChanged();
+
+private:
+ void determineRelativePath( const TQString & path );
+ void applyIconChanges();
+
+ TQWidget *iconArea;
+ TQWidget *nameArea;
+
+ TQLabel *m_sizeLabel;
+ TQPushButton *m_sizeDetermineButton;
+ TQPushButton *m_sizeStopButton;
+
+ TQString m_sRelativePath;
+ bool m_bFromTemplate;
+
+ /**
+ * The initial filename
+ */
+ TQString oldName;
+
+ class KFilePropsPluginPrivate;
+ KFilePropsPluginPrivate *d;
+};
+
+/**
+ * 'Permissions' plugin
+ * In this plugin you can modify permissions and change
+ * the owner of a file.
+ * @internal
+ */
+class TDEIO_EXPORT KFilePermissionsPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ enum PermissionsMode {
+ PermissionsOnlyFiles = 0,
+ PermissionsOnlyDirs = 1,
+ PermissionsOnlyLinks = 2,
+ PermissionsMixed = 3
+ };
+
+ enum PermissionsTarget {
+ PermissionsOwner = 0,
+ PermissionsGroup = 1,
+ PermissionsOthers = 2
+ };
+
+ /**
+ * Constructor
+ */
+ KFilePermissionsPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFilePermissionsPropsPlugin();
+
+ virtual void applyChanges();
+
+ /**
+ * Tests whether the file specified by _items needs a 'Permissions' plugin.
+ */
+ static bool supports( KFileItemList _items );
+
+private slots:
+
+ void slotChmodResult( TDEIO::Job * );
+ void slotShowAdvancedPermissions();
+
+private:
+ void setComboContent(TQComboBox *combo, PermissionsTarget target,
+ mode_t permissions, mode_t partial);
+ bool isIrregular(mode_t permissions, bool isDir, bool isLink);
+ void enableAccessControls(bool enable);
+ void updateAccessControls();
+ void getPermissionMasks(mode_t &andFilePermissions,
+ mode_t &andDirPermissions,
+ mode_t &orFilePermissions,
+ mode_t &orDirPermissions);
+
+ static const mode_t permissionsMasks[3];
+ static const mode_t standardPermissions[4];
+ static const char *permissionsTexts[4][4];
+
+ // unused, for binary compatibility!
+ TQCheckBox *permBox[3][4];
+
+ TQComboBox *grpCombo;
+
+ KLineEdit *usrEdit, *grpEdit;
+
+ /**
+ * Old permissions
+ */
+ mode_t permissions;
+ /**
+ * Old group
+ */
+ TQString strGroup;
+ /**
+ * Old owner
+ */
+ TQString strOwner;
+
+ // unused, for compatibility
+ static mode_t fperm[3][4];
+
+ class KFilePermissionsPropsPluginPrivate;
+ KFilePermissionsPropsPluginPrivate *d;
+};
+
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * URL=....
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ */
+class TDEIO_EXPORT KURLPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KURLPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KURLPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+private:
+ KURLRequester *URLEdit;
+ KIconButton *iconBox;
+
+ TQString URLStr;
+ TQString iconStr;
+
+ TQPixmap pixmap;
+ TQString pixmapFile;
+private:
+ class KURLPropsPluginPrivate;
+ KURLPropsPluginPrivate *d;
+};
+
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=MimeType
+ * @internal
+ */
+class TDEIO_EXPORT KBindingPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KBindingPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KBindingPropsPlugin();
+
+ virtual void applyChanges();
+ static bool supports( KFileItemList _items );
+
+private:
+
+ TQLineEdit *commentEdit;
+ TQLineEdit *patternEdit;
+ TQLineEdit *mimeEdit;
+ TQString m_sMimeStr;
+
+ TQCheckBox * cbAutoEmbed;
+
+ class KBindingPropsPluginPrivate;
+ KBindingPropsPluginPrivate *d;
+};
+
+/**
+ * Properties plugin for device .desktop files
+ * @internal
+ */
+class TDEIO_EXPORT KDevicePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ KDevicePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KDevicePropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+private slots:
+ void slotActivated( int );
+ void slotDeviceChanged();
+ void slotFoundMountPoint( const unsigned long& kBSize,
+ const unsigned long& /*kBUsed*/,
+ const unsigned long& kBAvail,
+ const TQString& );
+
+private:
+ void updateInfo();
+
+private:
+ TQComboBox* device;
+ TQLabel* mountpoint;
+ TQCheckBox* readonly;
+ void* unused;
+ //KIconButton* mounted;
+ KIconButton* unmounted;
+
+ TQStringList m_devicelist;
+ int indexDevice;
+ int indexMountPoint;
+ int indexFSType;
+
+ TQPixmap pixmap;
+ TQString pixmapFile;
+
+ class KDevicePropsPluginPrivate;
+ KDevicePropsPluginPrivate *d;
+};
+
+class KPropertiesDesktopBase;
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ */
+class TDEIO_EXPORT KDesktopPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KDesktopPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KDesktopPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotAddFiletype();
+ void slotDelFiletype();
+ void slotBrowseExec();
+ void slotAdvanced();
+ void slotSelectMimetype();
+
+private:
+ void checkCommandChanged();
+
+private:
+ KPropertiesDesktopBase* w;
+
+ TQString m_origCommandStr;
+ TQString m_terminalOptionStr;
+ TQString m_suidUserStr;
+ TQString m_dcopServiceType;
+ bool m_terminalBool;
+ bool m_terminalCloseBool;
+ bool m_suidBool;
+ bool m_startupBool;
+ bool m_systrayBool;
+
+ class KDesktopPropsPluginPrivate;
+ KDesktopPropsPluginPrivate *d;
+};
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ * @deprecated replaced with KDesktopPropsPlugin
+ */
+ /// Remove in KDE4
+class TDEIO_EXPORT_DEPRECATED KExecPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KExecPropsPlugin( KPropertiesDialog *_props );
+ virtual ~KExecPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotBrowseExec();
+
+private slots:
+ void enableCheckedEdit();
+ void enableSuidEdit();
+
+private:
+
+ TQLabel *terminalLabel;
+ TQLabel *suidLabel;
+ KLineEdit *execEdit;
+ TQCheckBox *terminalCheck;
+ TQCheckBox *suidCheck;
+ KLineEdit *terminalEdit;
+ KLineEdit *suidEdit;
+ KLineEdit *swallowExecEdit;
+ KLineEdit *swallowTitleEdit;
+ TQButton *execBrowse;
+
+ TQString execStr;
+ TQString swallowExecStr;
+ TQString swallowTitleStr;
+ TQString termOptionsStr;
+ bool termBool;
+ bool suidBool;
+ TQString suidUserStr;
+
+ class KExecPropsPluginPrivate;
+ KExecPropsPluginPrivate *d;
+};
+
+/**
+ * Used to edit the files containing
+ * [Desktop Entry]
+ * Type=Application
+ *
+ * Such files are used to represent a program in kicker and konqueror.
+ * @internal
+ * @deprecated replaced with KDesktopPropsPlugin
+ */
+ /// Remove in KDE4
+class TDEIO_EXPORT_DEPRECATED TDEApplicationPropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ TDEApplicationPropsPlugin( KPropertiesDialog *_props );
+ virtual ~TDEApplicationPropsPlugin();
+
+ virtual void applyChanges();
+
+ static bool supports( KFileItemList _items );
+
+public slots:
+ void slotDelExtension();
+ void slotAddExtension();
+
+private slots:
+ void updateButton();
+
+private:
+ void addMimeType( const TQString & name );
+
+ TQLineEdit *commentEdit;
+ TQLineEdit *genNameEdit;
+ TQLineEdit *nameEdit;
+ TQListBox *extensionsList;
+ TQListBox *availableExtensionsList;
+ TQPushButton *addExtensionButton;
+ TQPushButton *delExtensionButton;
+
+ class TDEApplicationPropsPluginPrivate;
+ TDEApplicationPropsPluginPrivate *d;
+};
+
+#endif
+
diff --git a/tdeio/tdefile/kpropertiesmimetypebase.ui b/tdeio/tdefile/kpropertiesmimetypebase.ui
new file mode 100644
index 000000000..df7c796da
--- /dev/null
+++ b/tdeio/tdefile/kpropertiesmimetypebase.ui
@@ -0,0 +1,70 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPropertiesMimetypeBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>widget2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>265</width>
+ <height>213</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Select one or more file types to add:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>listView</cstring>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Mimetype</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Select one or more types of file that your application can handle here. This list is organized by &lt;u&gt;mimetypes&lt;/u&gt;.&lt;/p&gt;
+&lt;p&gt;MIME, Multipurpose Internet (e)Mail Extension, is a standard protocol for identifying the type of data based on filename extensions and correspondent &lt;u&gt;mimetypes&lt;/u&gt;. Example: the "bmp" part that comes after the dot in flower.bmp indicates that it is a specific kind of image, &lt;u&gt;image/x-bmp&lt;/u&gt;. To know which application should open each type of file, the system should be informed about the abilities of each application to handle these extensions and mimetypes.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">klistview.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/tdeio/tdefile/kpropsdlg.h b/tdeio/tdefile/kpropsdlg.h
new file mode 100644
index 000000000..502a346e9
--- /dev/null
+++ b/tdeio/tdefile/kpropsdlg.h
@@ -0,0 +1,4 @@
+// This is now called kpropertiesdialog.h
+#ifndef KDE_NO_COMPAT
+#include <kpropertiesdialog.h>
+#endif
diff --git a/tdeio/tdefile/kpropsdlgplugin.desktop b/tdeio/tdefile/kpropsdlgplugin.desktop
new file mode 100644
index 000000000..f74e3895e
--- /dev/null
+++ b/tdeio/tdefile/kpropsdlgplugin.desktop
@@ -0,0 +1,87 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=KPropsDlg/Plugin
+Comment=Plugin for the Properties Dialog
+Comment[af]=Inprop module vir die Eienskappe Dialoog
+Comment[ar]=ملحق لمربع حوار خصائص
+Comment[az]=SeçənÉ™klÉ™r RabitÉ™ Qutusu Üçün ÆlavÉ™
+Comment[bg]=ПриÑтавка за диалога "ИнформациÑ"
+Comment[bn]=বৈশিষà§à¦Ÿà§à¦¯à¦¾à¦¬à¦²à§€ ডায়ালগ-à¦à¦° জনà§à¦¯ পà§à¦²à¦¾à¦—-ইন
+Comment[br]=Adveziant evit kendiviz ar perzhioù
+Comment[bs]=Dodatak za Properties dijalog
+Comment[ca]=Connector per al diàleg de les propietats
+Comment[cs]=Modul pro dialog vlastností
+Comment[csb]=Plugins dialogòwégò òkna Swòjiznë
+Comment[cy]=Ategyn am yr Ymgom Priodweddau
+Comment[da]=Plugin til egenskabsdialog
+Comment[de]=Erweiterung für den Eigenschaften-Dialog
+Comment[el]=ΠÏόσθετο για το Διάλογο ιδιοτήτων
+Comment[en_GB]=Plugin for the Properties Dialogue
+Comment[eo]=Internaĵo por la Eco-dialogo
+Comment[es]=Plugin para el diálogo de propiedades
+Comment[et]=Omaduste dialoogi plugin
+Comment[eu]=Propietateen elkarrizketa-koadroaren plugin-a
+Comment[fa]=وصله برای محاورۀ ویژگیها
+Comment[fi]=Lisäosa asetusikkunalle
+Comment[fr]=Module externe pour la boîte de dialogue des propriétés
+Comment[fy]=Plugin foar de 'Eigenskippen'-dialooch
+Comment[gl]=Plugin para o Diálogo de Propriedades
+Comment[he]=תוסף לדו־שיח המ×פייני×
+Comment[hi]=विशेषता संवाद के लिठपà¥à¤²à¤—इन
+Comment[hr]=Dodatak dijaloga 'Svojstva'
+Comment[hu]=Beépülő modul a tulajdonságok párbeszédablakhoz
+Comment[id]=Plugin untuk Dialog Properties
+Comment[is]=Ãforrit fyrir stillingarforritið
+Comment[it]=Plugin per la finestra delle proprietà
+Comment[ja]=設定ダイアログプラグイン
+Comment[ka]=პáƒáƒ áƒáƒ›áƒ”ტრების გáƒáƒ›áƒáƒ áƒ—ვის დიáƒáƒšáƒáƒ’ის მáƒáƒ“ული
+Comment[kk]=ҚаÑиеттер диалогтың модулі
+Comment[km]=កម្មវិធី​ជំនួយ​ážáž¶áž„​ក្នុង​សម្រាប់​ប្រអប់ លក្ážážŽáŸˆâ€‹ážŸáž˜áŸ’áž”ážáŸ’ážáž·
+Comment[ko]=대화창 íŠ¹ì„±ì„ ìœ„í•œ 플러그ì¸
+Comment[lb]=Plugin fir den Eegeschaften-Dialog
+Comment[lt]=Priedas savybių dialogui
+Comment[lv]=Īpašību Dialoga Iespraudnis
+Comment[mk]=Приклучок за дијалогот за ÑвојÑтва
+Comment[mn]=Шинж чанарууд диалогийн Plugin
+Comment[ms]=Plugmasuk untuk Dialog Ciri-ciri
+Comment[mt]=Plugin għad-djalogu tal-propjetajiet
+Comment[nb]=Programtillegg for dialogvinduet for egenskaper
+Comment[nds]=Plugin för den Egenschappen-Dialoog
+Comment[ne]=विशेषता संवादका लागि पà¥à¤²à¤—इन
+Comment[nl]=Plugin voor de 'Eigenschappen'-dialoog
+Comment[nn]=Tillegg til eigenskapar-dialogen
+Comment[nso]=Tsenyo ya Poledisano ya Dithoto
+Comment[oc]=Branquament pel dialeg de propietats
+Comment[pa]=ਵਿਸ਼ੇਸਤਾ ਵਾਰਤਾਲਾਪ ਲਈ ਪਲੱਗਿੰਨ
+Comment[pl]=Wtyczka do okna dialogowego Właściwości
+Comment[pt]='Plugin' para o diálogo de propriedades
+Comment[pt_BR]=Plug-in para a janela de Propriedades
+Comment[ro]=Modul pentru dialogul de proprietăţi
+Comment[ru]=Модуль Ð´Ð»Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð° наÑтроек
+Comment[rw]=Icomeka ry'Ikiganiro cy'Ibiranga
+Comment[se]=Lassemoduvla iešvuođahtaláseža várás
+Comment[sk]=modul pre ialóg ílastnosti
+Comment[sl]=Vstavek za pogovorno okno z lastnostmi
+Comment[sq]=Shtojcë për Dialogun e Rekuizitave
+Comment[sr]=Прикључак за дијалог Ñа ÑвојÑтвима
+Comment[sr@Latn]=PrikljuÄak za dijalog sa svojstvima
+Comment[sv]=Insticksprogram för egenskapsdialogen
+Comment[ta]=பணà¯à®ªà¯à®•à®³à¯ உரையாடலà¯à®•à¯à®•à®¾à®© சொரà¯à®•à¯à®ªà¯à®ªà¯Šà®°à¯à®³à¯
+Comment[te]=లకà±à°·à°£à°¾à°² సంభాషణ కొరకౠపà±à°²à°—à°¿à°¨à±
+Comment[tg]=ШтепÑели барои ХуÑуÑиÑтҳои Тирезаи Диалогӣ Ðндохтан
+Comment[th]=ปลั๊à¸à¸­à¸´à¸™à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸¥à¹ˆà¸­à¸‡à¸„ุณสมบัติ
+Comment[tr]=Özellikler İletişim Kutusu İçin Eklenti
+Comment[tt]=Caylaw Dialogı öçen Östämä
+Comment[uk]=Втулок Ð´Ð»Ñ Ð´Ñ–Ð°Ð»Ð¾Ð³Ñƒ влаÑтивоÑтей
+Comment[uz]=Xossalar dialogi uchun plagin
+Comment[uz@cyrillic]=ХоÑÑалар диалоги учун плагин
+Comment[ven]=U pulaga ha zwishumiswa zwa nyambedzano
+Comment[vi]=Bộ cầm phít cho hộp thoại đặc tả.
+Comment[xh]=Iplagi yangaphakathi Yezinto zobumnini Zencoko yababini
+Comment[zh_CN]=属性对è¯çš„æ’件
+Comment[zh_HK]=屬性å°è©±ç›’的外掛程å¼
+Comment[zh_TW]=屬性å°è©±ç›’的外掛程å¼
+Comment[zu]=I-plugin Yengxoxo Yezinkomba zobunini
+
+[PropertyDef::X-TDE-Protocol]
+Type=TQString
diff --git a/tdeio/tdefile/krecentdirs.cpp b/tdeio/tdefile/krecentdirs.cpp
new file mode 100644
index 000000000..6f4a01f3b
--- /dev/null
+++ b/tdeio/tdefile/krecentdirs.cpp
@@ -0,0 +1,99 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Waldo Bastian <bastian@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <krecentdirs.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+
+#define MAX_DIR_HISTORY 3
+
+static void recentdirs_done(TDEConfig *config)
+{
+ if (config == TDEGlobal::config())
+ {
+ config->sync();
+ }
+ else
+ {
+ delete config;
+ }
+}
+
+static TDEConfig *recentdirs_readList(TQString &key, TQStringList &result, bool readOnly)
+{
+ TDEConfig *config;
+ if ((key.length() < 2) || (key[0] != ':'))
+ key = ":default";
+ if (key[1] == ':')
+ {
+ key = key.mid(2);
+ config = new KSimpleConfig(TQString::fromLatin1("krecentdirsrc"), readOnly);
+ }
+ else
+ {
+ key = key.mid(1);
+ config = TDEGlobal::config();
+ config->setGroup(TQString::fromLatin1("Recent Dirs"));
+ }
+
+ result=config->readPathListEntry(key);
+ if (result.isEmpty())
+ {
+ result.append(TDEGlobalSettings::documentPath());
+ }
+ return config;
+}
+
+TQStringList KRecentDirs::list(const TQString &fileClass)
+{
+ TQString key = fileClass;
+ TQStringList result;
+ recentdirs_done(recentdirs_readList(key, result, true));
+ return result;
+}
+
+TQString KRecentDirs::dir(const TQString &fileClass)
+{
+ TQStringList result = list(fileClass);
+ return result[0];
+}
+
+void KRecentDirs::add(const TQString &fileClass, const TQString &directory)
+{
+ TQString key = fileClass;
+ TQStringList result;
+ TDEConfig *config = recentdirs_readList(key, result, false);
+ // make sure the dir is first in history
+ result.remove(directory);
+ result.prepend(directory);
+ while(result.count() > MAX_DIR_HISTORY)
+ result.remove(result.fromLast());
+ config->writePathEntry(key, result);
+ recentdirs_done(config);
+}
+
diff --git a/tdeio/tdefile/krecentdirs.h b/tdeio/tdefile/krecentdirs.h
new file mode 100644
index 000000000..774655e51
--- /dev/null
+++ b/tdeio/tdefile/krecentdirs.h
@@ -0,0 +1,70 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Waldo Bastian <bastian@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef __KRECENTDIRS_H
+#define __KRECENTDIRS_H
+
+#include <tqstringlist.h>
+
+#include <tdelibs_export.h>
+
+/**
+ * The goal of this class is to make sure that, when the user needs to
+ * specify a file via the file selection dialog, this dialog will start
+ * in the directory most likely to contain the desired files.
+ *
+ * This works as follows: Each time the file selection dialog is
+ * shown, the programmer can specify a "file-class". The file-dialog will
+ * then start with the directory associated with this file-class. When
+ * the dialog closes, the directory currently shown in the file-dialog
+ * will be associated with the file-class.
+ *
+ * A file-class can either start with ':' or with '::'. If it starts with
+ * a single ':' the file-class is specific to the current application.
+ * If the file-class starts with '::' it is global to all applications.
+ */
+class TDEIO_EXPORT KRecentDirs
+{
+public:
+ /**
+ * Returns a list of directories associated with this file-class.
+ * The most recently used directory is at the front of the list.
+ */
+ static TQStringList list(const TQString &fileClass);
+
+ /**
+ * Returns the most recently used directory accociated with this file-class.
+ */
+ static TQString dir(const TQString &fileClass);
+
+ /**
+ * Associates @p directory with @p fileClass
+ */
+ static void add(const TQString &fileClass, const TQString &directory);
+};
+
+#endif
diff --git a/tdeio/tdefile/krecentdocument.cpp b/tdeio/tdefile/krecentdocument.cpp
new file mode 100644
index 000000000..1ec4a98c8
--- /dev/null
+++ b/tdeio/tdefile/krecentdocument.cpp
@@ -0,0 +1,177 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Daniel M. Duley <mosfet@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <krecentdocument.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kdesktopfile.h>
+#include <tqdir.h>
+#include <tqfileinfo.h>
+#include <tqtextstream.h>
+#include <tqstringlist.h>
+#include <tqregexp.h>
+
+#include <sys/types.h>
+#include <utime.h>
+
+TQString KRecentDocument::recentDocumentDirectory()
+{
+ // need to change this path, not sure where
+ return locateLocal("data", TQString::fromLatin1("RecentDocuments/"));
+}
+
+TQStringList KRecentDocument::recentDocuments()
+{
+ TQDir d(recentDocumentDirectory(), "*.desktop", TQDir::Time,
+ TQDir::Files | TQDir::Readable | TQDir::Hidden);
+
+ if (!d.exists())
+ d.mkdir(recentDocumentDirectory());
+
+ TQStringList list = d.entryList();
+ TQStringList fullList;
+
+ for (TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ TQString pathDesktop = d.absFilePath( *it );
+ KDesktopFile tmpDesktopFile( pathDesktop, false);
+ KURL urlDesktopFile(tmpDesktopFile.readURL());
+ if( urlDesktopFile.isLocalFile() && !TQFile(urlDesktopFile.path()).exists())
+ d.remove(pathDesktop);
+ else
+ fullList.append( pathDesktop );
+ }
+
+ return fullList;
+}
+
+void KRecentDocument::add(const KURL& url)
+{
+ KRecentDocument::add(url, tqApp->argv()[0]); // ### argv[0] might not match the service filename!
+}
+
+void KRecentDocument::add(const KURL& url, const TQString& desktopEntryName)
+{
+ if ( url.isLocalFile() && !TDEGlobal::dirs()->relativeLocation("tmp", url.path()).startsWith("/"))
+ return;
+
+ TQString openStr = url.url();
+ openStr.replace( TQRegExp("\\$"), "$$" ); // Desktop files with type "Link" are $-variable expanded
+
+ kdDebug(250) << "KRecentDocument::add for " << openStr << endl;
+ TDEConfig *config = TDEGlobal::config();
+ TQString oldGrp = config->group();
+ config->setGroup(TQString::fromLatin1("RecentDocuments"));
+ bool useRecent = config->readBoolEntry(TQString::fromLatin1("UseRecent"), true);
+ int maxEntries = config->readNumEntry(TQString::fromLatin1("MaxEntries"), 10);
+
+ config->setGroup(oldGrp);
+ if(!useRecent)
+ return;
+
+ TQString path = recentDocumentDirectory();
+
+ TQString dStr = path + url.fileName();
+
+ TQString ddesktop = dStr + TQString::fromLatin1(".desktop");
+
+ int i=1;
+ // check for duplicates
+ while(TQFile::exists(ddesktop)){
+ // see if it points to the same file and application
+ KSimpleConfig tmp(ddesktop);
+ tmp.setDesktopGroup();
+ if(tmp.readEntry(TQString::fromLatin1("X-TDE-LastOpenedWith"))
+ == desktopEntryName)
+ {
+ utime(TQFile::encodeName(ddesktop), NULL);
+ return;
+ }
+ // if not append a (num) to it
+ ++i;
+ if ( i > maxEntries )
+ break;
+ ddesktop = dStr + TQString::fromLatin1("[%1].desktop").arg(i);
+ }
+
+ TQDir dir(path);
+ // check for max entries, delete oldest files if exceeded
+ TQStringList list = dir.entryList(TQDir::Files | TQDir::Hidden, TQDir::Time | TQDir::Reversed);
+ i = list.count();
+ if(i > maxEntries-1){
+ TQStringList::Iterator it;
+ it = list.begin();
+ while(i > maxEntries-1){
+ TQFile::remove(dir.absPath() + TQString::fromLatin1("/") + (*it));
+ --i, ++it;
+ }
+ }
+
+ // create the applnk
+ KSimpleConfig conf(ddesktop);
+ conf.setDesktopGroup();
+ conf.writeEntry( TQString::fromLatin1("Type"), TQString::fromLatin1("Link") );
+ conf.writePathEntry( TQString::fromLatin1("URL"), openStr );
+ // If you change the line below, change the test in the above loop
+ conf.writeEntry( TQString::fromLatin1("X-TDE-LastOpenedWith"), desktopEntryName );
+ TQString name = url.fileName();
+ if (name.isEmpty())
+ name = openStr;
+ conf.writeEntry( TQString::fromLatin1("Name"), name );
+ conf.writeEntry( TQString::fromLatin1("Icon"), KMimeType::iconForURL( url ) );
+}
+
+void KRecentDocument::add(const TQString &openStr, bool isUrl)
+{
+ if( isUrl ) {
+ add( KURL( openStr ) );
+ } else {
+ KURL url;
+ url.setPath( openStr );
+ add( url );
+ }
+}
+
+void KRecentDocument::clear()
+{
+ TQStringList list = recentDocuments();
+ TQDir dir;
+ for(TQStringList::Iterator it = list.begin(); it != list.end() ; ++it)
+ dir.remove(*it);
+}
+
+int KRecentDocument::maximumItems()
+{
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver sa(config, TQString::fromLatin1("RecentDocuments"));
+ return config->readNumEntry(TQString::fromLatin1("MaxEntries"), 10);
+}
+
+
diff --git a/tdeio/tdefile/krecentdocument.h b/tdeio/tdefile/krecentdocument.h
new file mode 100644
index 000000000..968559968
--- /dev/null
+++ b/tdeio/tdefile/krecentdocument.h
@@ -0,0 +1,105 @@
+/* -*- c++ -*-
+ * Copyright (C)2000 Daniel M. Duley <mosfet@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef __KRECENTDOCUMENT_H
+#define __KRECENTDOCUMENT_H
+
+#include <tqstring.h>
+#include <kurl.h>
+
+/**
+ * Manage the "Recent Document Menu" entries displayed by
+ * applications such as Kicker and Konqueror.
+ *
+ * These entries are automatically generated .desktop files pointing
+ * to the current application and document. You should call the
+ * static add() method whenever the user opens or saves a new
+ * document if you want it to show up in the menu.
+ *
+ * You don't have to worry about this if you are using any
+ * KFileDialog derived class to open and save documents, as it
+ * already calls this class. User defined limits on the maximum
+ * number of documents to save, etc... are all automatically handled.
+ *
+ * @author Daniel M. Duley <mosfet@kde.org>
+ */
+class TDEIO_EXPORT KRecentDocument
+{
+public:
+
+ /**
+ *
+ * Return a list of absolute paths to recent document .desktop files,
+ * sorted by date.
+ *
+ */
+ static TQStringList recentDocuments();
+
+ /**
+ * Add a new item to the Recent Document menu.
+ *
+ * @param url The url to add.
+ */
+ static void add(const KURL& url);
+
+ /**
+ * Add a new item to the Recent Document menu, specifying the application to open it with.
+ * The above add() method uses argv[0] for the app name, which isn't always flexible enough.
+ * This method is used when an application launches another one to open a document.
+ *
+ * @param url The url to add.
+ * @param desktopEntryName The desktopEntryName of the service to use for opening this document.
+ */
+ static void add(const KURL& url, const TQString& desktopEntryName);
+
+ /**
+ *
+ * Add a new item to the Recent Document menu. Calls add( url ).
+ *
+ * @param documentStr The full path to the document or URL to add.
+ * @param isURL Set to @p true if @p documentStr is an URL and not a local file path.
+ */
+ static void add(const TQString &documentStr, bool isURL = false);
+
+ /**
+ * Clear the recent document menu of all entries.
+ */
+ static void clear();
+
+ /**
+ * Returns the maximum amount of recent document entries allowed.
+ */
+ static int maximumItems();
+
+ /**
+ * Returns the path to the directory where recent document .desktop files
+ * are stored.
+ */
+ static TQString recentDocumentDirectory();
+};
+
+#endif
diff --git a/tdeio/tdefile/kurlbar.cpp b/tdeio/tdefile/kurlbar.cpp
new file mode 100644
index 000000000..e142845e1
--- /dev/null
+++ b/tdeio/tdefile/kurlbar.cpp
@@ -0,0 +1,1049 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 <unistd.h>
+
+#include <tqapplication.h>
+#include <tqcheckbox.h>
+#include <tqdrawutil.h>
+#include <tqfontmetrics.h>
+#include <tqlabel.h>
+#include <tqgrid.h>
+#include <tqpainter.h>
+#include <tqpopupmenu.h>
+#include <tqstyle.h>
+#include <tqvbox.h>
+#include <tqwhatsthis.h>
+
+#include <kaboutdata.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kicondialog.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <kprotocolinfo.h>
+#include <kstringhandler.h>
+#include <kurldrag.h>
+#include <kurlrequester.h>
+#include <tdeio/global.h>
+#include <tdeio/netaccess.h>
+
+#include "kurlbar.h"
+
+/**
+ * Handles tooltips in the KURLBar
+ * @internal
+ */
+class KURLBarToolTip : public TQToolTip
+{
+public:
+ KURLBarToolTip( TQListBox *view ) : TQToolTip( view ), m_view( view ) {}
+
+protected:
+ virtual void maybeTip( const TQPoint& point ) {
+ TQListBoxItem *item = m_view->itemAt( point );
+ if ( item ) {
+ TQString text = static_cast<KURLBarItem*>( item )->toolTip();
+ if ( !text.isEmpty() )
+ tip( m_view->itemRect( item ), text );
+ }
+ }
+
+private:
+ TQListBox *m_view;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+class KURLBarItem::KURLBarItemPrivate
+{
+public:
+ KURLBarItemPrivate()
+ {
+ isPersistent = true;
+ }
+
+ bool isPersistent;
+};
+
+KURLBarItem::KURLBarItem( KURLBar *parent,
+ const KURL& url, bool persistent, const TQString& description,
+ const TQString& icon, KIcon::Group group )
+ : TQListBoxPixmap( KIconLoader::unknown() /*, parent->listBox()*/ ),
+ m_url( url ),
+ m_pixmap( 0L ),
+ m_parent( parent ),
+ m_appLocal( true )
+{
+ init( icon, group, description, persistent );
+}
+
+KURLBarItem::KURLBarItem( KURLBar *parent,
+ const KURL& url, const TQString& description,
+ const TQString& icon, KIcon::Group group )
+ : TQListBoxPixmap( KIconLoader::unknown() /*, parent->listBox()*/ ),
+ m_url( url ),
+ m_pixmap( 0L ),
+ m_parent( parent ),
+ m_appLocal( true )
+{
+ init( icon, group, description, true /*persistent*/ );
+}
+
+void KURLBarItem::init( const TQString& icon, KIcon::Group group,
+ const TQString& description, bool persistent )
+{
+ d = new KURLBarItemPrivate;
+ d->isPersistent = persistent;
+
+ setCustomHighlighting( true );
+ setIcon( icon, group );
+ setDescription( description );
+}
+
+KURLBarItem::~KURLBarItem()
+{
+ delete d;
+}
+
+void KURLBarItem::setURL( const KURL& url )
+{
+ m_url = url;
+ if ( m_description.isEmpty() )
+ setText( url.fileName() );
+}
+
+void KURLBarItem::setIcon( const TQString& icon, KIcon::Group group )
+{
+ m_icon = icon;
+ m_group = group;
+
+ if ( icon.isEmpty() )
+ m_pixmap = KMimeType::pixmapForURL( m_url, 0, group, iconSize() );
+ else
+ m_pixmap = TDEGlobal::iconLoader()->loadIcon( icon, group, iconSize(),
+ KIcon::DefaultState );
+}
+
+void KURLBarItem::setDescription( const TQString& desc )
+{
+ m_description = desc;
+ setText( desc.isEmpty() ? m_url.fileName() : desc );
+}
+
+void KURLBarItem::setApplicationLocal( bool local )
+{
+ if ( !local && !isPersistent() )
+ {
+ kdWarning() << "KURLBar: dynamic (non-persistent) items can not be global." << endl;
+ return;
+ }
+
+ m_appLocal = local;
+}
+
+void KURLBarItem::setToolTip( const TQString& tip )
+{
+ m_toolTip = tip;
+}
+
+TQString KURLBarItem::toolTip() const
+{
+ return m_toolTip.isEmpty() ? m_url.prettyURL() : m_toolTip;
+}
+
+int KURLBarItem::iconSize() const
+{
+ return m_parent->iconSize();
+}
+
+void KURLBarItem::paint( TQPainter *p )
+{
+ TQListBox *box = listBox();
+ int w = width( box );
+ static const int margin = KDialog::spacingHint();
+
+ // draw sunken selection
+ if ( isCurrent() || isSelected() ) {
+ int h = height( box );
+
+ TQBrush brush = box->colorGroup().brush( TQColorGroup::Highlight );
+ p->fillRect( 0, 0, w, h, brush );
+ TQPen pen = p->pen();
+ TQPen oldPen = pen;
+ pen.setColor( box->colorGroup().mid() );
+ p->setPen( pen );
+
+ p->drawPoint( 0, 0 );
+ p->drawPoint( 0, h - 1 );
+ p->drawPoint( w - 1, 0 );
+ p->drawPoint( w - 1, h - 1 );
+
+ p->setPen( oldPen );
+ }
+
+ if ( m_parent->iconSize() < KIcon::SizeMedium ) {
+ // small icon -> draw icon next to text
+
+ // ### mostly cut & paste of TQListBoxPixmap::paint() until Qt 3.1
+ // (where it will properly use pixmap() instead of the internal pixmap)
+ const TQPixmap *pm = pixmap();
+ int yPos = QMAX( 0, (height(box) - pm->height())/2 );
+
+ p->drawPixmap( margin, yPos, *pm );
+ if ( !text().isEmpty() ) {
+ TQFontMetrics fm = p->fontMetrics();
+ if ( pm->height() < fm.height() )
+ yPos = fm.ascent() + fm.leading()/2;
+ else
+ yPos = pm->height()/2 - fm.height()/2 + fm.ascent();
+
+ yPos += margin;
+ int stringWidth = box->width() - pm->width() - 2 - (margin * 2);
+ TQString visibleText = KStringHandler::rPixelSqueeze( text(), fm, stringWidth );
+ int xPos = pm->width() + margin + 2;
+
+ if ( isCurrent() || isSelected() ) {
+ p->setPen( box->colorGroup().highlight().dark(115) );
+ p->drawText( xPos + ( TQApplication::reverseLayout() ? -1 : 1),
+ yPos + 1, visibleText );
+ p->setPen( box->colorGroup().highlightedText() );
+ }
+
+ p->drawText( xPos, yPos, visibleText );
+ }
+ // end cut & paste (modulo pixmap centering)
+ }
+
+ else {
+ // big icons -> draw text below icon
+ int y = margin;
+ const TQPixmap *pm = pixmap();
+
+ if ( !pm->isNull() ) {
+ int x = (w - pm->width()) / 2;
+ x = QMAX( x, margin );
+ p->drawPixmap( x, y, *pm );
+ }
+
+ if ( !text().isEmpty() ) {
+ TQFontMetrics fm = p->fontMetrics();
+ y += pm->height() + fm.height() - fm.descent();
+
+ int stringWidth = box->width() - (margin * 2);
+ TQString visibleText = KStringHandler::rPixelSqueeze( text(), fm, stringWidth );
+ int x = (w - fm.width( visibleText )) / 2;
+ x = QMAX( x, margin );
+
+ if ( isCurrent() || isSelected() ) {
+ p->setPen( box->colorGroup().highlight().dark(115) );
+ p->drawText( x + ( TQApplication::reverseLayout() ? -1 : 1),
+ y + 1, visibleText );
+ p->setPen( box->colorGroup().highlightedText() );
+ }
+
+ p->drawText( x, y, visibleText );
+ }
+ }
+}
+
+TQSize KURLBarItem::sizeHint() const
+{
+ int wmin = 0;
+ int hmin = 0;
+ const KURLBarListBox *lb =static_cast<const KURLBarListBox*>(listBox());
+
+ if ( m_parent->iconSize() < KIcon::SizeMedium ) {
+ wmin = TQListBoxPixmap::width( lb ) + KDialog::spacingHint() * 2;
+ hmin = TQListBoxPixmap::height( lb ) + KDialog::spacingHint() * 2;
+ }
+ else {
+ wmin = QMAX(lb->fontMetrics().width(text()), pixmap()->width()) + KDialog::spacingHint() * 2;
+ hmin = lb->fontMetrics().lineSpacing() + pixmap()->height() + KDialog::spacingHint() * 2;
+ }
+
+ if ( lb->isVertical() )
+ wmin = QMIN( wmin, lb->viewport()->sizeHint().width() );
+ else
+ hmin = QMIN( hmin, lb->viewport()->sizeHint().height() );
+
+ return TQSize( wmin, hmin );
+}
+
+int KURLBarItem::width( const TQListBox *lb ) const
+{
+ if ( static_cast<const KURLBarListBox *>( lb )->isVertical() )
+ return QMAX( sizeHint().width(), lb->viewport()->width() );
+ else
+ return sizeHint().width();
+}
+
+int KURLBarItem::height( const TQListBox *lb ) const
+{
+ if ( static_cast<const KURLBarListBox *>( lb )->isVertical() )
+ return sizeHint().height();
+ else
+ return QMAX( sizeHint().height(), lb->viewport()->height() );
+}
+
+bool KURLBarItem::isPersistent() const
+{
+ return d->isPersistent;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+class KURLBar::KURLBarPrivate
+{
+public:
+ KURLBarPrivate()
+ {
+ currentURL.setPath( TQDir::homeDirPath() );
+ defaultIconSize = 0;
+ }
+
+ int defaultIconSize;
+ KURL currentURL;
+};
+
+
+KURLBar::KURLBar( bool useGlobalItems, TQWidget *parent, const char *name, WFlags f )
+ : TQFrame( parent, name, f ),
+ m_activeItem( 0L ),
+ m_useGlobal( useGlobalItems ),
+ m_isModified( false ),
+ m_isImmutable( false ),
+ m_listBox( 0L ),
+ m_iconSize( KIcon::SizeMedium )
+{
+ d = new KURLBarPrivate();
+
+ setListBox( 0L );
+ setSizePolicy( TQSizePolicy( isVertical() ?
+ TQSizePolicy::Maximum :
+ TQSizePolicy::Preferred,
+ isVertical() ?
+ TQSizePolicy::Preferred :
+ TQSizePolicy::Maximum ));
+ TQWhatsThis::add(this, i18n("<qt>The <b>Quick Access</b> panel provides easy access to commonly used file locations.<p>"
+ "Clicking on one of the shortcut entries will take you to that location.<p>"
+ "By right clicking on an entry you can add, edit and remove shortcuts.</qt>"));
+}
+
+KURLBar::~KURLBar()
+{
+ delete d;
+}
+
+KURLBarItem * KURLBar::insertItem(const KURL& url, const TQString& description,
+ bool applicationLocal,
+ const TQString& icon, KIcon::Group group )
+{
+ KURLBarItem *item = new KURLBarItem(this, url, description, icon, group);
+ item->setApplicationLocal( applicationLocal );
+ m_listBox->insertItem( item );
+ return item;
+}
+
+KURLBarItem * KURLBar::insertDynamicItem(const KURL& url, const TQString& description,
+ const TQString& icon, KIcon::Group group )
+{
+ KURLBarItem *item = new KURLBarItem(this, url, false, description, icon, group);
+ m_listBox->insertItem( item );
+ return item;
+}
+
+void KURLBar::setOrientation( Qt::Orientation orient )
+{
+ m_listBox->setOrientation( orient );
+ setSizePolicy( TQSizePolicy( isVertical() ?
+ TQSizePolicy::Maximum :
+ TQSizePolicy::Preferred,
+ isVertical() ?
+ TQSizePolicy::Preferred :
+ TQSizePolicy::Maximum ));
+}
+
+Qt::Orientation KURLBar::orientation() const
+{
+ return m_listBox->orientation();
+}
+
+void KURLBar::setListBox( KURLBarListBox *view )
+{
+ delete m_listBox;
+
+ if ( !view ) {
+ m_listBox = new KURLBarListBox( this, "urlbar listbox" );
+ setOrientation( Qt::Vertical );
+ }
+ else {
+ m_listBox = view;
+ if ( m_listBox->parentWidget() != this )
+ m_listBox->reparent( this, TQPoint(0,0) );
+ m_listBox->resize( width(), height() );
+ }
+
+ m_listBox->setSelectionMode( KListBox::Single );
+ paletteChange( palette() );
+ m_listBox->setFocusPolicy( TQ_TabFocus );
+
+ connect( m_listBox, TQT_SIGNAL( mouseButtonClicked( int, TQListBoxItem *, const TQPoint & ) ),
+ TQT_SLOT( slotSelected( int, TQListBoxItem * )));
+ connect( m_listBox, TQT_SIGNAL( dropped( TQDropEvent * )),
+ this, TQT_SLOT( slotDropped( TQDropEvent * )));
+ connect( m_listBox, TQT_SIGNAL( contextMenuRequested( TQListBoxItem *,
+ const TQPoint& )),
+ TQT_SLOT( slotContextMenuRequested( TQListBoxItem *, const TQPoint& )));
+ connect( m_listBox, TQT_SIGNAL( returnPressed( TQListBoxItem * ) ),
+ TQT_SLOT( slotSelected( TQListBoxItem * ) ));
+}
+
+void KURLBar::setIconSize( int size )
+{
+ if ( size == m_iconSize )
+ return;
+
+ m_iconSize = size;
+
+ // reload the icons with the new size
+ KURLBarItem *item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+ while ( item ) {
+ item->setIcon( item->icon(), item->iconGroup() );
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+
+ resize( sizeHint() );
+ updateGeometry();
+}
+
+void KURLBar::clear()
+{
+ m_listBox->clear();
+}
+
+void KURLBar::resizeEvent( TQResizeEvent *e )
+{
+ TQFrame::resizeEvent( e );
+ m_listBox->resize( width(), height() );
+}
+
+void KURLBar::paletteChange( const TQPalette & )
+{
+ TQPalette pal = palette();
+ TQColor gray = pal.color( TQPalette::Normal, TQColorGroup::Background );
+ TQColor selectedTextColor = pal.color( TQPalette::Normal, TQColorGroup::BrightText );
+ TQColor foreground = pal.color( TQPalette::Normal, TQColorGroup::Foreground );
+ pal.setColor( TQPalette::Normal, TQColorGroup::Base, gray );
+ pal.setColor( TQPalette::Normal, TQColorGroup::HighlightedText, selectedTextColor );
+ pal.setColor( TQPalette::Normal, TQColorGroup::Text, foreground );
+ pal.setColor( TQPalette::Inactive, TQColorGroup::Base, gray );
+ pal.setColor( TQPalette::Inactive, TQColorGroup::HighlightedText, selectedTextColor );
+ pal.setColor( TQPalette::Inactive, TQColorGroup::Text, foreground );
+
+ setPalette( pal );
+}
+
+TQSize KURLBar::sizeHint() const
+{
+ return m_listBox->sizeHint();
+
+#if 0
+ // this code causes vertical and or horizontal scrollbars appearing
+ // depending on the text, font, moonphase and earth rotation. Just using
+ // m_listBox->sizeHint() fixes this (although the widget can then be
+ // resized to a smaller size so that scrollbars appear).
+ int w = 0;
+ int h = 0;
+ KURLBarItem *item;
+ bool vertical = isVertical();
+
+ for ( item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+ item;
+ item = static_cast<KURLBarItem*>( item->next() ) ) {
+
+ TQSize sh = item->sizeHint();
+
+ if ( vertical ) {
+ w = QMAX( w, sh.width() );
+ h += sh.height();
+ }
+ else {
+ w += sh.width();
+ h = QMAX( h, sh.height() );
+ }
+ }
+
+// if ( vertical && m_listBox->verticalScrollBar()->isVisible() )
+// w += m_listBox->verticalScrollBar()->width();
+// else if ( !vertical && m_listBox->horizontalScrollBar()->isVisible() )
+// h += m_listBox->horizontalScrollBar()->height();
+
+ if ( w == 0 && h == 0 )
+ return TQSize( 100, 200 );
+ else
+ return TQSize( 6 + w, h );
+#endif
+}
+
+TQSize KURLBar::minimumSizeHint() const
+{
+ TQSize s = sizeHint(); // ###
+ int w = s.width() + m_listBox->verticalScrollBar()->width();
+ int h = s.height() + m_listBox->horizontalScrollBar()->height();
+ return TQSize( w, h );
+}
+
+void KURLBar::slotSelected( int button, TQListBoxItem *item )
+{
+ if ( button != Qt::LeftButton )
+ return;
+
+ slotSelected( item );
+}
+
+void KURLBar::slotSelected( TQListBoxItem *item )
+{
+ if ( item && item != m_activeItem )
+ m_activeItem = static_cast<KURLBarItem*>( item );
+
+ if ( m_activeItem ) {
+ m_listBox->setCurrentItem( m_activeItem );
+ emit activated( m_activeItem->url() );
+ }
+}
+
+void KURLBar::setCurrentItem( const KURL& url )
+{
+ d->currentURL = url;
+
+ TQString u = url.url(-1);
+
+ if ( m_activeItem && m_activeItem->url().url(-1) == u )
+ return;
+
+ bool hasURL = false;
+ TQListBoxItem *item = m_listBox->firstItem();
+ while ( item ) {
+ if ( static_cast<KURLBarItem*>( item )->url().url(-1) == u ) {
+ m_activeItem = static_cast<KURLBarItem*>( item );
+ m_listBox->setCurrentItem( item );
+ m_listBox->setSelected( item, true );
+ hasURL = true;
+ break;
+ }
+ item = item->next();
+ }
+
+ if ( !hasURL ) {
+ m_activeItem = 0L;
+ m_listBox->clearSelection();
+ }
+}
+
+KURLBarItem * KURLBar::currentItem() const
+{
+ TQListBoxItem *item = m_listBox->item( m_listBox->currentItem() );
+ if ( item )
+ return static_cast<KURLBarItem *>( item );
+ return 0L;
+}
+
+KURL KURLBar::currentURL() const
+{
+ KURLBarItem *item = currentItem();
+ return item ? item->url() : KURL();
+}
+
+void KURLBar::readConfig( TDEConfig *appConfig, const TQString& itemGroup )
+{
+ m_isImmutable = appConfig->groupIsImmutable( itemGroup );
+ TDEConfigGroupSaver cs( appConfig, itemGroup );
+ d->defaultIconSize = m_iconSize;
+ m_iconSize = appConfig->readNumEntry( "Speedbar IconSize", m_iconSize );
+
+ if ( m_useGlobal ) { // read global items
+ TDEConfig *globalConfig = TDEGlobal::config();
+ TDEConfigGroupSaver cs( globalConfig, (TQString)(itemGroup +" (Global)"));
+ int num = globalConfig->readNumEntry( "Number of Entries" );
+ for ( int i = 0; i < num; i++ ) {
+ readItem( i, globalConfig, false );
+ }
+ }
+
+ // read application local items
+ int num = appConfig->readNumEntry( "Number of Entries" );
+ for ( int i = 0; i < num; i++ ) {
+ readItem( i, appConfig, true );
+ }
+}
+
+void KURLBar::readItem( int i, TDEConfig *config, bool applicationLocal )
+{
+ TQString number = TQString::number( i );
+ KURL url = KURL::fromPathOrURL( config->readPathEntry( TQString("URL_") + number ));
+ if ( !url.isValid() || !KProtocolInfo::isKnownProtocol( url ))
+ return; // nothing we could do.
+
+ TQString description = config->readEntry( TQString("Description_") + number );
+
+ if (description.isEmpty() && url.protocol()=="beagle") {
+ TDEIO::UDSEntry uds;
+ const KURL kurl("beagle:?beagled-status");
+ if (!TDEIO::NetAccess::stat(kurl, uds))
+ return;
+
+ description = i18n("Desktop Search");
+ }
+
+ insertItem( url,
+ description,
+ applicationLocal,
+ config->readEntry( TQString("Icon_") + number ),
+ static_cast<KIcon::Group>(
+ config->readNumEntry( TQString("IconGroup_") + number )) );
+}
+
+void KURLBar::writeConfig( TDEConfig *config, const TQString& itemGroup )
+{
+ TDEConfigGroupSaver cs1( config, itemGroup );
+ if(!config->hasDefault("Speedbar IconSize") && m_iconSize == d->defaultIconSize )
+ config->revertToDefault("Speedbar IconSize");
+ else
+ config->writeEntry( "Speedbar IconSize", m_iconSize );
+
+ if ( !m_isModified )
+ return;
+
+ int i = 0;
+ int numLocal = 0;
+ KURLBarItem *item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+
+ while ( item )
+ {
+ if ( item->isPersistent() ) // we only save persistent items
+ {
+ if ( item->applicationLocal() )
+ {
+ writeItem( item, numLocal, config, false );
+ numLocal++;
+ }
+
+ i++;
+ }
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+ config->writeEntry("Number of Entries", numLocal);
+
+
+ // write the global entries to kdeglobals, if any
+ bool haveGlobalEntries = (i > numLocal);
+ if ( m_useGlobal && haveGlobalEntries ) {
+ config->setGroup( itemGroup + " (Global)" );
+
+ int numGlobals = 0;
+ item = static_cast<KURLBarItem*>( m_listBox->firstItem() );
+
+ while ( item )
+ {
+ if ( item->isPersistent() ) // we only save persistent items
+ {
+ if ( !item->applicationLocal() )
+ {
+ writeItem( item, numGlobals, config, true );
+ numGlobals++;
+ }
+ }
+
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+ config->writeEntry("Number of Entries", numGlobals, true, true);
+ }
+
+ m_isModified = false;
+}
+
+void KURLBar::writeItem( KURLBarItem *item, int i, TDEConfig *config,
+ bool global )
+{
+ if ( !item->isPersistent() )
+ return;
+
+ TQString Description = "Description_";
+ TQString URL = "URL_";
+ TQString Icon = "Icon_";
+ TQString IconGroup = "IconGroup_";
+
+ TQString number = TQString::number( i );
+ config->writePathEntry( URL + number, item->url().prettyURL(), true, global );
+
+ config->writeEntry( Description + number, item->description(),true,global);
+ config->writeEntry( Icon + number, item->icon(), true, global );
+ config->writeEntry( IconGroup + number, item->iconGroup(), true, global );
+}
+
+
+void KURLBar::slotDropped( TQDropEvent *e )
+{
+ KURL::List urls;
+ if ( KURLDrag::decode( e, urls ) ) {
+ KURL url;
+ TQString description;
+ TQString icon;
+ bool appLocal = false;
+
+ KURL::List::Iterator it = urls.begin();
+ for ( ; it != urls.end(); ++it ) {
+ (void) insertItem( *it, description, appLocal, icon );
+ m_isModified = true;
+ updateGeometry();
+ }
+ }
+}
+
+void KURLBar::slotContextMenuRequested( TQListBoxItem *_item, const TQPoint& pos )
+{
+ if (m_isImmutable)
+ return;
+
+ KURLBarItem *item = dynamic_cast<KURLBarItem*>( _item );
+
+ static const int IconSize = 10;
+ static const int AddItem = 20;
+ static const int EditItem = 30;
+ static const int RemoveItem = 40;
+
+ KURL lastURL = m_activeItem ? m_activeItem->url() : KURL();
+
+ bool smallIcons = m_iconSize < KIcon::SizeMedium;
+ TQPopupMenu *popup = new TQPopupMenu();
+ popup->insertItem( smallIcons ?
+ i18n("&Large Icons") : i18n("&Small Icons"),
+ IconSize );
+ popup->insertSeparator();
+
+ if (item != 0L && item->isPersistent())
+ {
+ popup->insertItem(SmallIconSet("edit"), i18n("&Edit Entry..."), EditItem);
+ popup->insertSeparator();
+ }
+
+ popup->insertItem(SmallIconSet("filenew"), i18n("&Add Entry..."), AddItem);
+
+ if (item != 0L && item->isPersistent())
+ {
+ popup->insertItem( SmallIconSet("editdelete"), i18n("&Remove Entry"),
+ RemoveItem );
+ }
+
+ int result = popup->exec( pos );
+ switch ( result ) {
+ case IconSize:
+ setIconSize( smallIcons ? KIcon::SizeMedium : KIcon::SizeSmallMedium );
+ m_listBox->triggerUpdate( true );
+ break;
+ case AddItem:
+ addNewItem();
+ break;
+ case EditItem:
+ editItem( static_cast<KURLBarItem *>( item ) );
+ break;
+ case RemoveItem:
+ delete item;
+ m_isModified = true;
+ break;
+ default: // abort
+ break;
+ }
+
+ // reset current item
+ m_activeItem = 0L;
+ setCurrentItem( lastURL );
+}
+
+bool KURLBar::addNewItem()
+{
+ KURLBarItem *item = new KURLBarItem( this, d->currentURL,
+ i18n("Enter a description") );
+ if ( editItem( item ) ) {
+ m_listBox->insertItem( item );
+ return true;
+ }
+
+ delete item;
+ return false;
+}
+
+bool KURLBar::editItem( KURLBarItem *item )
+{
+ if ( !item || !item->isPersistent() ) // should never happen tho
+ return false;
+
+ KURL url = item->url();
+ TQString description = item->description();
+ TQString icon = item->icon();
+ bool appLocal = item->applicationLocal();
+
+ if ( KURLBarItemDialog::getInformation( m_useGlobal,
+ url, description,
+ icon, appLocal,
+ m_iconSize, this ))
+ {
+ item->setURL( url );
+ item->setDescription( description );
+ item->setIcon( icon );
+ item->setApplicationLocal( appLocal );
+ m_listBox->triggerUpdate( true );
+ m_isModified = true;
+ updateGeometry();
+ return true;
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+KURLBarListBox::KURLBarListBox( TQWidget *parent, const char *name )
+ : KListBox( parent, name )
+{
+ m_toolTip = new KURLBarToolTip( this );
+ setAcceptDrops( true );
+ viewport()->setAcceptDrops( true );
+}
+
+KURLBarListBox::~KURLBarListBox()
+{
+ delete m_toolTip;
+}
+
+void KURLBarListBox::paintEvent( TQPaintEvent* )
+{
+ TQPainter p(this);
+ p.setPen( colorGroup().mid() );
+ p.drawRect( 0, 0, width(), height() );
+}
+
+TQDragObject * KURLBarListBox::dragObject()
+{
+ KURL::List urls;
+ KURLBarItem *item = static_cast<KURLBarItem*>( firstItem() );
+
+ while ( item ) {
+ if ( item->isSelected() )
+ urls.append( item->url() );
+ item = static_cast<KURLBarItem*>( item->next() );
+ }
+
+ if ( !urls.isEmpty() ) // ### use custom drag-object with description etc.?
+ return new KURLDrag( urls, this, "urlbar drag" );
+
+ return 0L;
+}
+
+void KURLBarListBox::contentsDragEnterEvent( TQDragEnterEvent *e )
+{
+ e->accept( KURLDrag::canDecode( e ));
+}
+
+void KURLBarListBox::contentsDropEvent( TQDropEvent *e )
+{
+ emit dropped( e );
+}
+
+void KURLBarListBox::contextMenuEvent( TQContextMenuEvent *e )
+{
+ if (e)
+ {
+ emit contextMenuRequested( itemAt( e->globalPos() ), e->globalPos() );
+ e->consume(); // Consume the event to avoid multiple contextMenuEvent calls...
+ }
+}
+
+void KURLBarListBox::setOrientation( Qt::Orientation orient )
+{
+ if ( orient == Qt::Vertical ) {
+ setColumnMode( 1 );
+ setRowMode( Variable );
+ }
+ else {
+ setRowMode( 1 );
+ setColumnMode( Variable );
+ }
+
+ m_orientation = orient;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+bool KURLBarItemDialog::getInformation( bool allowGlobal, KURL& url,
+ TQString& description, TQString& icon,
+ bool& appLocal, int iconSize,
+ TQWidget *parent )
+{
+ KURLBarItemDialog *dialog = new KURLBarItemDialog( allowGlobal, url,
+ description, icon,
+ appLocal,
+ iconSize, parent );
+ if ( dialog->exec() == TQDialog::Accepted ) {
+ // set the return parameters
+ url = dialog->url();
+ description = dialog->description();
+ icon = dialog->icon();
+ appLocal = dialog->applicationLocal();
+
+ delete dialog;
+ return true;
+ }
+
+ delete dialog;
+ return false;
+}
+
+KURLBarItemDialog::KURLBarItemDialog( bool allowGlobal, const KURL& url,
+ const TQString& description,
+ TQString icon, bool appLocal,
+ int iconSize,
+ TQWidget *parent, const char *name )
+ : KDialogBase( parent, name, true,
+ i18n("Edit Quick Access Entry"), Ok | Cancel, Ok, true )
+{
+ TQVBox *box = new TQVBox( this );
+ TQString text = i18n("<qt><b>Please provide a description, URL and icon for this Quick Access entry.</b></br></qt>");
+ TQLabel *label = new TQLabel( text, box );
+ box->setSpacing( spacingHint() );
+
+ TQGrid *grid = new TQGrid( 2, box );
+ grid->setSpacing( spacingHint() );
+
+ TQString whatsThisText = i18n("<qt>This is the text that will appear in the Quick Access panel.<p>"
+ "The description should consist of one or two words "
+ "that will help you remember what this entry refers to.</qt>");
+ label = new TQLabel( i18n("&Description:"), grid );
+ m_edit = new KLineEdit( grid, "description edit" );
+ m_edit->setText( description.isEmpty() ? url.fileName() : description );
+ label->setBuddy( m_edit );
+ TQWhatsThis::add( label, whatsThisText );
+ TQWhatsThis::add( m_edit, whatsThisText );
+
+ whatsThisText = i18n("<qt>This is the location associated with the entry. Any valid URL may be used. For example:<p>"
+ "%1<br>http://www.kde.org<br>ftp://ftp.kde.org/pub/kde/stable<p>"
+ "By clicking on the button next to the text edit box you can browse to an "
+ "appropriate URL.</qt>").arg(TQDir::homeDirPath());
+ label = new TQLabel( i18n("&URL:"), grid );
+ m_urlEdit = new KURLRequester( url.prettyURL(), grid );
+ m_urlEdit->setMode( KFile::Directory );
+ label->setBuddy( m_urlEdit );
+ TQWhatsThis::add( label, whatsThisText );
+ TQWhatsThis::add( m_urlEdit, whatsThisText );
+
+ whatsThisText = i18n("<qt>This is the icon that will appear in the Quick Access panel.<p>"
+ "Click on the button to select a different icon.</qt>");
+ label = new TQLabel( i18n("Choose an &icon:"), grid );
+ m_iconButton = new KIconButton( grid, "icon button" );
+ m_iconButton->setIconSize( iconSize );
+ if ( icon.isEmpty() )
+ icon = KMimeType::iconForURL( url );
+ m_iconButton->setIcon( icon );
+ label->setBuddy( m_iconButton );
+ TQWhatsThis::add( label, whatsThisText );
+ TQWhatsThis::add( m_iconButton, whatsThisText );
+
+ if ( allowGlobal ) {
+ TQString appName;
+ if ( TDEGlobal::instance()->aboutData() )
+ appName = TDEGlobal::instance()->aboutData()->programName();
+ if ( appName.isEmpty() )
+ appName = TQString::fromLatin1( TDEGlobal::instance()->instanceName() );
+ m_appLocal = new TQCheckBox( i18n("&Only show when using this application (%1)").arg( appName ), box );
+ m_appLocal->setChecked( appLocal );
+ TQWhatsThis::add( m_appLocal,
+ i18n("<qt>Select this setting if you want this "
+ "entry to show only when using the current application (%1).<p>"
+ "If this setting is not selected, the entry will be available in all "
+ "applications.</qt>")
+ .arg(appName));
+ }
+ else
+ m_appLocal = 0L;
+ connect(m_urlEdit->lineEdit(),TQT_SIGNAL(textChanged ( const TQString & )),this,TQT_SLOT(urlChanged(const TQString & )));
+ m_edit->setFocus();
+ setMainWidget( box );
+}
+
+KURLBarItemDialog::~KURLBarItemDialog()
+{
+}
+
+void KURLBarItemDialog::urlChanged(const TQString & text )
+{
+ enableButtonOK( !text.isEmpty() );
+}
+
+KURL KURLBarItemDialog::url() const
+{
+ TQString text = m_urlEdit->url();
+ KURL u;
+ if ( text.at(0) == '/' )
+ u.setPath( text );
+ else
+ u = text;
+
+ return u;
+}
+
+TQString KURLBarItemDialog::description() const
+{
+ return m_edit->text();
+}
+
+TQString KURLBarItemDialog::icon() const
+{
+ return m_iconButton->icon();
+}
+
+bool KURLBarItemDialog::applicationLocal() const
+{
+ if ( !m_appLocal )
+ return true;
+
+ return m_appLocal->isChecked();
+}
+
+void KURLBarItem::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KURLBar::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KURLBarListBox::virtual_hook( int id, void* data )
+{ KListBox::virtual_hook( id, data ); }
+
+
+#include "kurlbar.moc"
diff --git a/tdeio/tdefile/kurlbar.h b/tdeio/tdefile/kurlbar.h
new file mode 100644
index 000000000..32c05ec58
--- /dev/null
+++ b/tdeio/tdefile/kurlbar.h
@@ -0,0 +1,660 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 KURLBAR_H
+#define KURLBAR_H
+
+#include <tqevent.h>
+#include <tqframe.h>
+#include <tqtooltip.h>
+
+#include <kdialogbase.h>
+#include <kicontheme.h>
+#include <klistbox.h>
+#include <kurl.h>
+
+class TDEConfig;
+class KURLBar;
+
+/**
+ * An item to be used in KURLBar / KURLBarListBox. All the properties
+ * (url, icon, description, tooltip) can be changed dynamically.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @see KURLBar
+ * @see KURLBarListBox
+ */
+class TDEIO_EXPORT KURLBarItem : public TQListBoxPixmap
+{
+public:
+ /**
+ * Creates a KURLBarItem to be used in the @p parent KURLBar. You need
+ * to insert the item into the listbox manually, if you don't use
+ * KURLBar::insertItem().
+ *
+ * If description is empty, it will try to use the filename/directory
+ * of @p url, which will be shown as text of the item.
+ * @p url will be used as tooltip, unless you set a different tip with
+ * setToolTip().
+ * @p persistent specifies whether this item is a persistent item or a
+ * dynamic item, that is not saved with KURLBar::writeConfig().
+ * @since 3.2
+ */
+ KURLBarItem( KURLBar *parent, const KURL& url, bool persistent,
+ const TQString& description = TQString::null,
+ const TQString& icon = TQString::null,
+ KIcon::Group group = KIcon::Panel );
+
+ /**
+ * Creates a persistent KURLBarItem to be used in the @p parent KURLBar. You need
+ * to insert the item into the listbox manually, if you don't use
+ * KURLBar::insertItem().
+ *
+ * If description is empty, it will try to use the filename/directory
+ * of @p url, which will be shown as text of the item.
+ * @p url will be used as tooltip, unless you set a different tip with
+ * setToolTip().
+ * @p persistent specifies whether this item is a persistent item or a
+ * dynamic item, that is not saved with KURLBar::writeConfig().
+ */
+ KURLBarItem( KURLBar *parent, const KURL& url,
+ const TQString& description = TQString::null,
+ const TQString& icon = TQString::null,
+ KIcon::Group group = KIcon::Panel );
+
+ /**
+ * Destroys the item
+ */
+ ~KURLBarItem();
+
+ /**
+ * Sets @p url for this item. Also updates the visible text to the
+ * filename/directory of the url, if no description is set.
+ * @see url
+ */
+ void setURL( const KURL& url );
+ /**
+ * @p sets the icon for this item. See KIconLoader for a description
+ * of the icon groups.
+ * @see icon
+ */
+ void setIcon( const TQString& icon, KIcon::Group group = KIcon::Panel );
+ /**
+ * Sets the description of this item that will be shown as item-text.
+ * @see description
+ */
+ void setDescription( const TQString& desc );
+ /**
+ * Sets a tooltip to be used for this item.
+ * @see toolTip
+ */
+ void setToolTip( const TQString& tip );
+
+ /**
+ * returns the preferred size of this item
+ * @since 3.1
+ */
+ TQSize sizeHint() const;
+
+ /**
+ * returns the width of this item.
+ */
+ virtual int width( const TQListBox * ) const;
+ /**
+ * returns the height of this item.
+ */
+ virtual int height( const TQListBox * ) const;
+
+ /**
+ * returns the url of this item.
+ * @see setURL
+ */
+ const KURL& url() const { return m_url; }
+ /**
+ * returns the description of this item.
+ * @see setDescription
+ */
+ const TQString& description() const { return m_description; }
+ /**
+ * returns the icon of this item.
+ * @see setIcon
+ */
+ const TQString& icon() const { return m_icon; }
+ /**
+ * returns the tooltip of this item.
+ * @see setToolTip
+ */
+ TQString toolTip() const;
+ /**
+ * returns the icon-group of this item (determines icon-effects).
+ * @see setIcon
+ */
+ KIcon::Group iconGroup() const { return m_group; }
+ /**
+ * returns the pixmap of this item.
+ */
+ virtual const TQPixmap * pixmap() const { return &m_pixmap; }
+
+ /**
+ * Makes this item a local or global one. This has only an effect
+ * on persistent items of course.
+ * @see isPersistent
+ * @see applicationLocal
+ */
+ void setApplicationLocal( bool local );
+
+ /**
+ * returns whether this is a global item or a local one. KURLBar
+ * can differentiate between global and local items (only for the current
+ * application) for easy extensiblity.
+ * @see setApplicationLocal
+ */
+ bool applicationLocal() const { return m_appLocal; }
+
+ /**
+ * returns whether this item is persistent (via KURLBar::writeConfig()
+ * and KURLBar::readConfig()) or not.
+ * @since 3.2
+ */
+ bool isPersistent() const;
+
+protected:
+ virtual void paint( TQPainter *p );
+
+private:
+ int iconSize() const;
+ void init( const TQString& icon, KIcon::Group group,
+ const TQString& description, bool persistent );
+
+ KURL m_url;
+ TQString m_description;
+ TQString m_icon;
+ TQString m_toolTip;
+ TQPixmap m_pixmap;
+ KIcon::Group m_group;
+ KURLBar *m_parent;
+ bool m_appLocal :1;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarItemPrivate;
+ KURLBarItemPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class KURLBarListBox;
+
+/**
+ * KURLBar is a widget that displays icons together with a description. They
+ * can be arranged either horizontally or vertically. Clicking on an item
+ * will cause the activated() signal to be emitted. The user can edit
+ * existing items by choosing "Edit entry" in the contextmenu. He can also
+ * remove or add new entries (via drag&drop or the context menu).
+ *
+ * KURLBar offers the methods readConfig() and writeConfig() to
+ * read and write the configuration of all the entries. It can differentiate
+ * between global and local entries -- global entries will be saved in the
+ * global configuration (kdeglobals), while local entries will be saved in
+ * your application's TDEConfig object.
+ *
+ * Due to the configurability, you usually only insert some default entries
+ * once and then solely use the read and writeConfig methods to preserve the
+ * user's configuration.
+ *
+ * The widget has a "current" item, that is visualized to differentiate it
+ * from others.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ * @short A URL-bar widget, as used in the KFileDialog
+ */
+class TDEIO_EXPORT KURLBar : public TQFrame
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLBar. Set @p useGlobalItems to true if you want to
+ * allow global/local item separation.
+ */
+ KURLBar( bool useGlobalItems,
+ TQWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ /**
+ * Destroys the KURLBar.
+ */
+ ~KURLBar();
+
+ /**
+ * Inserts a new item into the KURLBar and returns the created
+ * KURLBarItem.
+ *
+ * @p url the url of the item
+ * @p description the description of the item (shown in the view)
+ * @p applicationLocal whether this should be a global or a local item
+ * @p icon an icon -- if empty, the default icon for the url will be used
+ * @p group the icon-group for using icon-effects
+ */
+ virtual KURLBarItem * insertItem( const KURL& url,
+ const TQString& description,
+ bool applicationLocal = true,
+ const TQString& icon = TQString::null,
+ KIcon::Group group = KIcon::Panel );
+ /**
+ * Inserts a new dynamic item into the KURLBar and returns the created
+ * KURLBarItem.
+ *
+ * @p url the url of the item
+ * @p description the description of the item (shown in the view)
+ * @p icon an icon -- if empty, the default icon for the url will be used
+ * @p group the icon-group for using icon-effects
+ * @since 3.2
+ */
+ virtual KURLBarItem * insertDynamicItem( const KURL& url,
+ const TQString& description,
+ const TQString& icon = TQString::null,
+ KIcon::Group group = KIcon::Panel );
+ /**
+ * The items can be arranged either vertically in one column or
+ * horizontally in one row.
+ * @see orientation
+ */
+ virtual void setOrientation( Qt::Orientation orient );
+ /**
+ * @returns the current orientation mode.
+ * @see setOrientation
+ */
+ Orientation orientation() const;
+
+ /**
+ * Allows to set a custom KURLBarListBox.
+ * Note: The previous listbox will be deleted. Items of the previous
+ * listbox will not be moved to the new box.
+ * @see listBox
+ */
+ virtual void setListBox( KURLBarListBox * );
+ /**
+ * @returns the KURLBarListBox that is used.
+ * @see setListBox
+ */
+ KURLBarListBox *listBox() const { return m_listBox; }
+
+ /**
+ * Sets the default iconsize to be used for items inserted with
+ * insertItem. By default KIcon::SizeMedium.
+ * @see iconsize
+ */
+ virtual void setIconSize( int size );
+ /**
+ * @returns the default iconsize used for items inserted with
+ * insertItem. By default KIcon::SizeMedium
+ * @see setIconSize
+ */
+ int iconSize() const { return m_iconSize; }
+
+ /**
+ * Clears the view, removes all items.
+ */
+ virtual void clear();
+
+ /**
+ * @returns a proper sizehint, depending on the orientation and the number
+ * of items available.
+ */
+ virtual TQSize sizeHint() const;
+
+ /**
+ * @returns a proper minimum size (reimplemented)
+ */
+ virtual TQSize minimumSizeHint() const;
+
+ /**
+ * Call this method to read a saved configuration from @p config,
+ * inside the group @p itemGroup. All items in there will be restored.
+ * The reading of every item is delegated to the readItem() method.
+ */
+ virtual void readConfig( TDEConfig *config, const TQString& itemGroup );
+ /**
+ * Call this method to save the current configuration into @p config,
+ * inside the group @p iconGroup. The writeItem() method is used
+ * to save each item.
+ */
+ virtual void writeConfig( TDEConfig *config, const TQString& itemGroup );
+
+ /**
+ * Called from readConfig() to read the i'th from @p config.
+ * After reading a KURLBarItem is created and initialized with the read
+ * values (as well as the given @p applicationLocal).
+ */
+ virtual void readItem( int i, TDEConfig *config, bool applicationLocal );
+ /**
+ * Called from writeConfig() to save the KURLBarItem @p item as the
+ * i'th entry in the config-object.
+ * @p global tell whether it should be saved in the global configuration
+ * or not (using TDEConfig::writeEntry( key, value, true, global ) ).
+ */
+ virtual void writeItem( KURLBarItem *item, int i, TDEConfig *, bool global );
+
+ /**
+ * @returns the current KURLBarItem, or 0L if none.
+ * @see setCurrentItem
+ * @see currentURL
+ */
+ KURLBarItem * currentItem() const;
+ /**
+ * @returns the url of the current item or an invalid url, if there is
+ * no current item.
+ * @see currentItem
+ * @see setCurrentItem
+ */
+ KURL currentURL() const;
+
+ /**
+ * @returns true when the urlbar was modified by the user (e.g. by
+ * editing/adding/removing one or more entries). Will be reset to false
+ * after calling writeConfig().
+ */
+ bool isModified() const { return m_isModified; }
+
+ /**
+ * @returns true when the urlbar may not be modified by the user
+ */
+ bool isImmutable() const { return m_isImmutable; }
+
+ /**
+ * @returns true if the bar is in vertical mode.
+ */
+ bool isVertical() const { return orientation() == Qt::Vertical; }
+
+public slots:
+ /**
+ * Makes the item with the url @p url the current item. Does nothing
+ * if no item with that url is available.
+ * @see currentItem
+ * @see currentURL
+ */
+ virtual void setCurrentItem( const KURL& url );
+
+signals:
+ /**
+ * This signal is emitted when the user activated an item, e.g., by
+ * clicking on it.
+ */
+ void activated( const KURL& url );
+
+protected:
+ /**
+ * Pops up a KURLBarItemDialog to let the user add a new item.
+ * Uses editItem() to do the job.
+ * @returns false if the user aborted the dialog and no item is added.
+ */
+ virtual bool addNewItem();
+ /**
+ * Pops up a KURLBarItemDialog to let the user edit the properties
+ * of @p item. Invoked e.g. by addNewItem(), when the user drops
+ * a url onto the bar or from the contextmenu.
+ * @returns false if the user aborted the dialog and @p item is not
+ * changed.
+ */
+ virtual bool editItem( KURLBarItem *item );
+
+ virtual void resizeEvent( TQResizeEvent * );
+
+ virtual void paletteChange( const TQPalette & );
+
+ /**
+ * The currently active item.
+ */
+ KURLBarItem * m_activeItem;
+ /**
+ * Whether we support global entries or just local ones.
+ */
+ bool m_useGlobal :1;
+
+ /**
+ * Whether the urlbar was modified by the user (e.g. by
+ * editing/adding/removing an item).
+ */
+ bool m_isModified :1;
+
+ /**
+ * Whether the urlbar may be modified by the user.
+ * If immutable is true, the urlbar can not be modified.
+ */
+ bool m_isImmutable :1;
+
+protected slots:
+ /**
+ * Reimplemented to show a contextmenu, allowing the user to add, edit
+ * or remove items, or change the iconsize.
+ */
+ virtual void slotContextMenuRequested( TQListBoxItem *, const TQPoint& pos );
+ /**
+ * Called when an item has been selected. Emits the activated()
+ * signal.
+ */
+ virtual void slotSelected( TQListBoxItem * );
+
+ /**
+ * Called when a url was dropped onto the bar to show a
+ * KURLBarItemDialog.
+ */
+ virtual void slotDropped( TQDropEvent * );
+
+private slots:
+ void slotSelected( int button, TQListBoxItem * );
+
+private:
+ KURLBarListBox *m_listBox;
+ int m_iconSize;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarPrivate;
+ KURLBarPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class TQDragObject;
+class KURLBarToolTip;
+
+/**
+ * This is the listbox used in KURLBar. It is a subclass of KListBox to support
+ * drag & drop and to set up the row / column mode.
+ *
+ * The widget has just one row or one column, depending on orientation().
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KURLBarListBox : public KListBox
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLBarListBox.
+ */
+ KURLBarListBox( TQWidget *parent = 0, const char *name = 0 );
+ /**
+ * Destroys the box.
+ */
+ ~KURLBarListBox();
+
+ /**
+ * Sets the orientation of the widget. Horizontal means, all items are
+ * arranged in one row. Vertical means, all items are arranged in one
+ * column.
+ * @see orientation
+ */
+ virtual void setOrientation( Qt::Orientation orient );
+ /**
+ * @returns the current orientation.
+ * @see setOrientation
+ */
+ Qt::Orientation orientation() const { return m_orientation; }
+
+ bool isVertical() const { return m_orientation == Qt::Vertical; }
+
+signals:
+ /**
+ * Emitted when a drop-event happened.
+ */
+ void dropped( TQDropEvent *e );
+
+protected:
+ /**
+ * @returns a suitable TQDragObject when an item is dragged.
+ */
+ virtual TQDragObject * dragObject();
+
+ virtual void contentsDragEnterEvent( TQDragEnterEvent * );
+ virtual void contentsDropEvent( TQDropEvent * );
+ virtual void contextMenuEvent( TQContextMenuEvent * );
+ virtual void paintEvent( TQPaintEvent* );
+
+private:
+ Qt::Orientation m_orientation;
+ KURLBarToolTip *m_toolTip;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURLBarListBoxPrivate;
+ KURLBarListBoxPrivate *d;
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+class TQCheckBox;
+class KIconButton;
+class KLineEdit;
+class KURLRequester;
+
+/**
+ * A dialog that allows editing entries of a KURLBar ( KURLBarItem).
+ * The dialog offers to configure a given url, description and icon.
+ * See the class-method getInformation() for easy usage.
+ *
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KURLBarItemDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * A convenience method to show the dialog and retrieve all the
+ * properties via the given parameters. The parameters are used to
+ * initialize the dialog and then return the user-configured values.
+ *
+ * See the KURLBarItem constructor for the parameter description.
+ */
+ static bool getInformation( bool allowGlobal, KURL& url,
+ TQString& description, TQString& icon,
+ bool& appLocal, int iconSize,
+ TQWidget *parent = 0 );
+
+ /**
+ * Constructs a KURLBarItemDialog.
+ *
+ * @p allowGlobal if you set this to true, the dialog will have a checkbox
+ * for the user to decide if he wants the entry to be
+ * available globally or just for the current application.
+ * @p url the url of the item
+ * @p description a short, translated description of the item
+ * @p icon an icon for the item
+ * @p appLocal tells whether the item should be local for this application
+ * or be available globally
+ * @p iconSize determines the size of the icon that is shown/selectable
+ * @p parent the parent-widget for the dialog
+ *
+ * If you leave the icon empty, the default icon for the given url will be
+ * used (KMimeType::pixmapForURL()).
+ */
+ KURLBarItemDialog( bool allowGlobal, const KURL& url,
+ const TQString& description, TQString icon,
+ bool appLocal = true,
+ int iconSize = KIcon::SizeMedium,
+ TQWidget *parent = 0, const char *name = 0 );
+ /**
+ * Destroys the dialog.
+ */
+ ~KURLBarItemDialog();
+
+ /**
+ * @returns the configured url
+ */
+ KURL url() const;
+
+ /**
+ * @returns the configured description
+ */
+ TQString description() const;
+
+ /**
+ * @returns the configured icon
+ */
+ TQString icon() const;
+
+ /**
+ * @returns whether the item should be local to the application or global.
+ * If allowGlobal was set to false in the constructor, this will always
+ * return true.
+ */
+ bool applicationLocal() const;
+
+protected:
+ /**
+ * The KURLRequester used for editing the url
+ */
+ KURLRequester * m_urlEdit;
+ /**
+ * The KLineEdit used for editing the description
+ */
+ KLineEdit * m_edit;
+ /**
+ * The KIconButton to configure the icon
+ */
+ KIconButton * m_iconButton;
+ /**
+ * The TQCheckBox to modify the local/global setting
+ */
+ TQCheckBox * m_appLocal;
+
+public slots:
+ void urlChanged(const TQString & );
+
+private:
+ class KURLBarItemDialogPrivate;
+ KURLBarItemDialogPrivate *d;
+};
+
+
+#endif // KURLBAR_H
diff --git a/tdeio/tdefile/kurlcombobox.cpp b/tdeio/tdefile/kurlcombobox.cpp
new file mode 100644
index 000000000..e01be4548
--- /dev/null
+++ b/tdeio/tdefile/kurlcombobox.cpp
@@ -0,0 +1,363 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@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 <tqdir.h>
+#include <tqlistbox.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmimetype.h>
+
+#include <kurlcombobox.h>
+
+class KURLComboBox::KURLComboBoxPrivate
+{
+public:
+ KURLComboBoxPrivate() {
+ dirpix = SmallIcon(TQString::fromLatin1("folder"));
+ }
+
+ TQPixmap dirpix;
+};
+
+
+KURLComboBox::KURLComboBox( Mode mode, TQWidget *parent, const char *name )
+ : KComboBox( parent, name )
+{
+ init( mode );
+}
+
+
+KURLComboBox::KURLComboBox( Mode mode, bool rw, TQWidget *parent,
+ const char *name )
+ : KComboBox( rw, parent, name )
+{
+ init( mode );
+}
+
+
+KURLComboBox::~KURLComboBox()
+{
+ delete d;
+}
+
+
+void KURLComboBox::init( Mode mode )
+{
+ d = new KURLComboBoxPrivate();
+
+ myMode = mode;
+ urlAdded = false;
+ myMaximum = 10; // default
+ itemList.setAutoDelete( true );
+ defaultList.setAutoDelete( true );
+ setInsertionPolicy( NoInsertion );
+ setTrapReturnKey( true );
+ setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Fixed ));
+
+ opendirPix = SmallIcon(TQString::fromLatin1("folder_open"));
+
+ connect( this, TQT_SIGNAL( activated( int )), TQT_SLOT( slotActivated( int )));
+}
+
+
+TQStringList KURLComboBox::urls() const
+{
+ kdDebug(250) << "::urls()" << endl;
+ //static const TQString &fileProt = TDEGlobal::staticQString("file:");
+ TQStringList list;
+ TQString url;
+ for ( int i = defaultList.count(); i < count(); i++ ) {
+ url = text( i );
+ if ( !url.isEmpty() ) {
+ //if ( url.at(0) == '/' )
+ // list.append( url.prepend( fileProt ) );
+ //else
+ list.append( url );
+ }
+ }
+
+ return list;
+}
+
+
+void KURLComboBox::addDefaultURL( const KURL& url, const TQString& text )
+{
+ addDefaultURL( url, getPixmap( url ), text );
+}
+
+
+void KURLComboBox::addDefaultURL( const KURL& url, const TQPixmap& pix,
+ const TQString& text )
+{
+ KURLComboItem *item = new KURLComboItem;
+ item->url = url;
+ item->pixmap = pix;
+ if ( text.isEmpty() )
+ if ( url.isLocalFile() )
+ item->text = url.path( myMode );
+ else
+ item->text = url.prettyURL( myMode );
+ else
+ item->text = text;
+
+ defaultList.append( item );
+}
+
+
+void KURLComboBox::setDefaults()
+{
+ clear();
+ itemMapper.clear();
+
+ KURLComboItem *item;
+ for ( unsigned int id = 0; id < defaultList.count(); id++ ) {
+ item = defaultList.at( id );
+ insertURLItem( item );
+ }
+}
+
+void KURLComboBox::setURLs( TQStringList urls )
+{
+ setURLs( urls, RemoveBottom );
+}
+
+void KURLComboBox::setURLs( TQStringList urls, OverLoadResolving remove )
+{
+ setDefaults();
+ itemList.clear();
+
+ if ( urls.isEmpty() )
+ return;
+
+ TQStringList::Iterator it = urls.begin();
+
+ // kill duplicates
+ TQString text;
+ while ( it != urls.end() ) {
+ while ( urls.contains( *it ) > 1 ) {
+ it = urls.remove( it );
+ continue;
+ }
+ ++it;
+ }
+
+ // limit to myMaximum items
+ /* Note: overload is an (old) C++ keyword, some compilers (KCC) choke
+ on that, so call it Overload (capital 'O'). (matz) */
+ int Overload = urls.count() - myMaximum + defaultList.count();
+ while ( Overload > 0 ) {
+ urls.remove((remove == RemoveBottom) ? urls.fromLast() : urls.begin());
+ Overload--;
+ }
+
+ it = urls.begin();
+
+ KURLComboItem *item = 0L;
+ KURL u;
+
+ while ( it != urls.end() ) {
+ if ( (*it).isEmpty() ) {
+ ++it;
+ continue;
+ }
+ u = KURL::fromPathOrURL( *it );
+
+ // Don't restore if file doesn't exist anymore
+ if (u.isLocalFile() && !TQFile::exists(u.path())) {
+ ++it;
+ continue;
+ }
+
+ item = new KURLComboItem;
+ item->url = u;
+ item->pixmap = getPixmap( u );
+
+ if ( u.isLocalFile() )
+ item->text = u.path( myMode ); // don't show file:/
+ else
+ item->text = *it;
+
+ insertURLItem( item );
+ itemList.append( item );
+ ++it;
+ }
+}
+
+
+void KURLComboBox::setURL( const KURL& url )
+{
+ if ( url.isEmpty() )
+ return;
+
+ blockSignals( true );
+
+ // check for duplicates
+ TQMap<int,const KURLComboItem*>::ConstIterator mit = itemMapper.begin();
+ TQString urlToInsert = url.url(-1);
+ while ( mit != itemMapper.end() ) {
+ if ( urlToInsert == mit.data()->url.url(-1) ) {
+ setCurrentItem( mit.key() );
+
+ if ( myMode == Directories )
+ updateItem( mit.data(), mit.key(), opendirPix );
+
+ blockSignals( false );
+ return;
+ }
+ ++mit;
+ }
+
+ // not in the combo yet -> create a new item and insert it
+
+ // first remove the old item
+ if ( urlAdded ) {
+ itemList.removeLast();
+ urlAdded = false;
+ }
+
+ setDefaults();
+
+ TQPtrListIterator<KURLComboItem> it( itemList );
+ for( ; it.current(); ++it )
+ insertURLItem( it.current() );
+
+ KURLComboItem *item = new KURLComboItem;
+ item->url = url;
+ item->pixmap = getPixmap( url );
+ if ( url.isLocalFile() )
+ item->text = url.path( myMode );
+ else
+ item->text = url.prettyURL( myMode );
+ kdDebug(250) << "setURL: text=" << item->text << endl;
+
+ int id = count();
+ TQString text = /*isEditable() ? item->url.prettyURL( myMode ) : */ item->text;
+
+ if ( myMode == Directories )
+ KComboBox::insertItem( opendirPix, text, id );
+ else
+ KComboBox::insertItem( item->pixmap, text, id );
+ itemMapper.insert( id, item );
+ itemList.append( item );
+
+ setCurrentItem( id );
+ urlAdded = true;
+ blockSignals( false );
+}
+
+
+void KURLComboBox::slotActivated( int index )
+{
+ const KURLComboItem *item = itemMapper[ index ];
+
+ if ( item ) {
+ setURL( item->url );
+ emit urlActivated( item->url );
+ }
+}
+
+
+void KURLComboBox::insertURLItem( const KURLComboItem *item )
+{
+// kdDebug(250) << "insertURLItem " << item->text << endl;
+ int id = count();
+ KComboBox::insertItem( item->pixmap, item->text, id );
+ itemMapper.insert( id, item );
+}
+
+
+void KURLComboBox::setMaxItems( int max )
+{
+ myMaximum = max;
+
+ if ( count() > myMaximum ) {
+ int oldCurrent = currentItem();
+
+ setDefaults();
+
+ TQPtrListIterator<KURLComboItem> it( itemList );
+ int Overload = itemList.count() - myMaximum + defaultList.count();
+ for ( int i = 0; i <= Overload; i++ )
+ ++it;
+
+ for( ; it.current(); ++it )
+ insertURLItem( it.current() );
+
+ if ( count() > 0 ) { // restore the previous currentItem
+ if ( oldCurrent >= count() )
+ oldCurrent = count() -1;
+ setCurrentItem( oldCurrent );
+ }
+ }
+}
+
+
+void KURLComboBox::removeURL( const KURL& url, bool checkDefaultURLs )
+{
+ TQMap<int,const KURLComboItem*>::ConstIterator mit = itemMapper.begin();
+ while ( mit != itemMapper.end() ) {
+ if ( url.url(-1) == mit.data()->url.url(-1) ) {
+ if ( !itemList.remove( mit.data() ) && checkDefaultURLs )
+ defaultList.remove( mit.data() );
+ }
+ ++mit;
+ }
+
+ blockSignals( true );
+ setDefaults();
+ TQPtrListIterator<KURLComboItem> it( itemList );
+ while ( it.current() ) {
+ insertURLItem( *it );
+ ++it;
+ }
+ blockSignals( false );
+}
+
+
+TQPixmap KURLComboBox::getPixmap( const KURL& url ) const
+{
+ if ( myMode == Directories )
+ return d->dirpix;
+ else
+ return KMimeType::pixmapForURL( url, 0, KIcon::Small );
+}
+
+
+// updates "item" with pixmap "pixmap" and sets the URL instead of text
+// works around a Qt bug.
+void KURLComboBox::updateItem( const KURLComboItem *item,
+ int index, const TQPixmap& pixmap )
+{
+ // TQComboBox::changeItem() doesn't honor the pixmap when
+ // using an editable combobox, so we just remove and insert
+ if ( editable() ) {
+ removeItem( index );
+ insertItem( pixmap,
+ item->url.isLocalFile() ? item->url.path( myMode ) :
+ item->url.prettyURL( myMode ),
+ index );
+ }
+ else
+ changeItem( pixmap, item->text, index );
+}
+
+
+#include "kurlcombobox.moc"
diff --git a/tdeio/tdefile/kurlcombobox.h b/tdeio/tdefile/kurlcombobox.h
new file mode 100644
index 000000000..a1fd9182d
--- /dev/null
+++ b/tdeio/tdefile/kurlcombobox.h
@@ -0,0 +1,229 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@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 KURLCOMBOBOX_H
+#define KURLCOMBOBOX_H
+
+#include <tqevent.h>
+#include <tqptrlist.h>
+#include <tqmap.h>
+#include <tqpixmap.h>
+#include <tqstringlist.h>
+
+#include <kcombobox.h>
+#include <kurl.h>
+
+/**
+ * This combobox shows a number of recent URLs/directories, as well as some
+ * default directories.
+ * It will manage the default dirs root-directory, home-directory and
+ * Desktop-directory, as well as a number of URLs set via setURLs()
+ * and one additional entry to be set via setURL().
+ *
+ * @short A combo box showing a number of recent URLs/directories
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KURLComboBox : public KComboBox
+{
+ Q_OBJECT
+ TQ_PROPERTY(TQStringList urls READ urls WRITE setURLs DESIGNABLE true)
+ TQ_PROPERTY(int maxItems READ maxItems WRITE setMaxItems DESIGNABLE true)
+
+public:
+ /**
+ * This enum describes which kind of items is shown in the combo box.
+ */
+ enum Mode { Files = -1, Directories = 1, Both = 0 };
+ /**
+ * This Enumeration is used in setURL() to determine which items
+ * will be removed when the given list is larger than maxItems().
+ *
+ * @li RemoveTop means that items will be removed from top
+ * @li RemoveBottom means, that items will be removed from the bottom
+ */
+ enum OverLoadResolving { RemoveTop, RemoveBottom };
+
+ /**
+ * Constructs a KURLComboBox.
+ * @param mode is either Files, Directories or Both and controls the
+ * following behavior:
+ * @li Files all inserted URLs will be treated as files, therefore the
+ * url shown in the combo will never show a trailing /
+ * the icon will be the one associated with the file's mimetype.
+ * @li Directories all inserted URLs will be treated as directories, will
+ * have a trailing slash in the combobox. The current
+ * directory will show the "open folder" icon, other
+ * directories the "folder" icon.
+ * @li Both Don't mess with anything, just show the url as given.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ */
+ KURLComboBox( Mode mode, TQWidget *parent=0, const char *name=0 );
+ KURLComboBox( Mode mode, bool rw, TQWidget *parent=0, const char *name=0 );
+ /**
+ * Destructs the combo box.
+ */
+ ~KURLComboBox();
+
+ /**
+ * Sets the current url. This combo handles exactly one url additionally
+ * to the default items and those set via setURLs(). So you can call
+ * setURL() as often as you want, it will always replace the previous one
+ * set via setURL().
+ * If @p url is already in the combo, the last item will stay there
+ * and the existing item becomes the current item.
+ * The current item will always have the open-directory-pixmap as icon.
+ *
+ * Note that you won't receive any signals, e.g. textChanged(),
+ * returnPressed() or activated() upon calling this method.
+ */
+ void setURL( const KURL& url );
+
+ /**
+ * Inserts @p urls into the combobox below the "default urls" (see
+ * addDefaultURL).
+ *
+ * If the list of urls contains more items than maxItems, the first items
+ * will be stripped.
+ */
+ void setURLs( TQStringList urls );
+
+ /**
+ * Inserts @p urls into the combobox below the "default urls" (see
+ * addDefaultURL).
+ *
+ * If the list of urls contains more items than maxItems, the @p remove
+ * parameter determines whether the first or last items will be stripped.
+ */
+ void setURLs( TQStringList urls, OverLoadResolving remove );
+
+ /**
+ * @returns a list of all urls currently handled. The list contains at most
+ * maxItems() items.
+ * Use this to save the list of urls in a config-file and reinsert them
+ * via setURLs() next time.
+ * Note that all default urls set via addDefaultURL() are not
+ * returned, they will automatically be set via setURLs() or setURL().
+ * You will always get fully qualified urls, i.e. with protocol like
+ * file:/
+ */
+ TQStringList urls() const;
+
+ /**
+ * Sets how many items should be handled and displayed by the combobox.
+ * @see maxItems
+ */
+ void setMaxItems( int );
+
+ /**
+ * @returns the maximum of items the combobox handles.
+ * @see setMaxItems
+ */
+ int maxItems() const { return myMaximum; }
+
+ /**
+ * Adds a url that will always be shown in the combobox, it can't be
+ * "rotated away". Default urls won't be returned in urls() and don't
+ * have to be set via setURLs().
+ * If you want to specify a special pixmap, use the overloaded method with
+ * the pixmap parameter.
+ * Default URLs will be inserted into the combobox by setDefaults()
+ */
+ void addDefaultURL( const KURL& url, const TQString& text = TQString::null );
+
+ /**
+ * Adds a url that will always be shown in the combobox, it can't be
+ * "rotated away". Default urls won't be returned in urls() and don't
+ * have to be set via setURLs().
+ * If you don't need to specify a pixmap, use the overloaded method without
+ * the pixmap parameter.
+ * Default URLs will be inserted into the combobox by setDefaults()
+ */
+ void addDefaultURL( const KURL& url, const TQPixmap& pix,
+ const TQString& text = TQString::null );
+
+ /**
+ * Clears all items and inserts the default urls into the combo. Will be
+ * called implicitly upon the first call to setURLs() or setURL()
+ * @see addDefaultURL
+ */
+ void setDefaults();
+
+ /**
+ * Removes any occurrence of @p url. If @p checkDefaultURLs is false
+ * default-urls won't be removed.
+ */
+ void removeURL( const KURL& url, bool checkDefaultURLs = true );
+
+signals:
+ /**
+ * Emitted when an item was clicked at.
+ * @param url is the url of the now current item. If it is a local url,
+ * it won't have a protocol (file:/), otherwise it will.
+ */
+ void urlActivated( const KURL& url );
+
+
+protected slots:
+ void slotActivated( int );
+
+
+protected:
+ struct _KURLComboItem {
+ TQString text;
+ KURL url;
+ TQPixmap pixmap;
+ };
+ typedef _KURLComboItem KURLComboItem;
+ TQPtrList<KURLComboItem> itemList;
+ TQPtrList<KURLComboItem> defaultList;
+ TQMap<int,const KURLComboItem*> itemMapper;
+
+ void init( Mode mode );
+ void insertURLItem( const KURLComboItem * );
+
+ /**
+ * Uses KMimeType::pixmapForURL() to return a proper pixmap for @p url.
+ * In directory mode, a folder icon is always returned.
+ */
+ TQPixmap getPixmap( const KURL& url ) const;
+
+ /**
+ * Updates @p item with @p pixmap and sets the url instead of the text
+ * of the KURLComboItem.
+ * Also works around a Qt bug.
+ */
+ void updateItem( const KURLComboItem *item, int index, const TQPixmap& pix);
+
+ TQPixmap opendirPix;
+ int firstItemIndex;
+
+
+private:
+ bool urlAdded;
+ int myMaximum;
+ Mode myMode; // can be used as parameter to KUR::path( int ) or url( int )
+ // to specify if we want a trailing slash or not
+
+private:
+ class KURLComboBoxPrivate;
+ KURLComboBoxPrivate *d;
+};
+
+
+#endif // KURLCOMBOBOX_H
diff --git a/tdeio/tdefile/kurlrequester.cpp b/tdeio/tdefile/kurlrequester.cpp
new file mode 100644
index 000000000..cca8c0529
--- /dev/null
+++ b/tdeio/tdefile/kurlrequester.cpp
@@ -0,0 +1,430 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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 <sys/stat.h>
+#include <unistd.h>
+
+#include <tqstring.h>
+#include <tqtooltip.h>
+#include <tqapplication.h>
+
+#include <kaccel.h>
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdirselectdialog.h>
+#include <tdefiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlcompletion.h>
+#include <kurldrag.h>
+#include <kprotocolinfo.h>
+
+#include "kurlrequester.h"
+
+
+class KURLDragPushButton : public KPushButton
+{
+public:
+ KURLDragPushButton( TQWidget *parent, const char *name=0 )
+ : KPushButton( parent, name ) {
+ setDragEnabled( true );
+ }
+ ~KURLDragPushButton() {}
+
+ void setURL( const KURL& url ) {
+ m_urls.clear();
+ m_urls.append( url );
+ }
+
+ /* not needed so far
+ void setURLs( const KURL::List& urls ) {
+ m_urls = urls;
+ }
+ const KURL::List& urls() const { return m_urls; }
+ */
+
+protected:
+ virtual TQDragObject *dragObject() {
+ if ( m_urls.isEmpty() )
+ return 0L;
+
+ TQDragObject *drag = new KURLDrag( m_urls, this, "url drag" );
+ return drag;
+ }
+
+private:
+ KURL::List m_urls;
+
+};
+
+
+/*
+*************************************************************************
+*/
+
+class KURLRequester::KURLRequesterPrivate
+{
+public:
+ KURLRequesterPrivate() {
+ edit = 0L;
+ combo = 0L;
+ fileDialogMode = KFile::File | KFile::ExistingOnly | KFile::LocalOnly;
+ }
+
+ void setText( const TQString& text ) {
+ if ( combo )
+ {
+ if (combo->editable())
+ {
+ combo->setEditText( text );
+ }
+ else
+ {
+ combo->insertItem( text );
+ combo->setCurrentItem( combo->count()-1 );
+ }
+ }
+ else
+ {
+ edit->setText( text );
+ }
+ }
+
+ void connectSignals( TQObject *receiver ) {
+ TQObject *sender;
+ if ( combo )
+ sender = TQT_TQOBJECT(combo);
+ else
+ sender = TQT_TQOBJECT(edit);
+
+ connect( sender, TQT_SIGNAL( textChanged( const TQString& )),
+ receiver, TQT_SIGNAL( textChanged( const TQString& )));
+ connect( sender, TQT_SIGNAL( returnPressed() ),
+ receiver, TQT_SIGNAL( returnPressed() ));
+ connect( sender, TQT_SIGNAL( returnPressed( const TQString& ) ),
+ receiver, TQT_SIGNAL( returnPressed( const TQString& ) ));
+ }
+
+ void setCompletionObject( KCompletion *comp ) {
+ if ( combo )
+ combo->setCompletionObject( comp );
+ else
+ edit->setCompletionObject( comp );
+ }
+
+ /**
+ * replaces ~user or $FOO, if necessary
+ */
+ TQString url() {
+ TQString txt = combo ? combo->currentText() : edit->text();
+ KURLCompletion *comp;
+ if ( combo )
+ comp = dynamic_cast<KURLCompletion*>(combo->completionObject());
+ else
+ comp = dynamic_cast<KURLCompletion*>(edit->completionObject());
+
+ if ( comp )
+ return comp->replacedPath( txt );
+ else
+ return txt;
+ }
+
+ KLineEdit *edit;
+ KComboBox *combo;
+ int fileDialogMode;
+ TQString fileDialogFilter;
+};
+
+
+
+KURLRequester::KURLRequester( TQWidget *editWidget, TQWidget *parent,
+ const char *name )
+ : TQHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+
+ // must have this as parent
+ editWidget->reparent( this, 0, TQPoint(0,0) );
+ d->edit = dynamic_cast<KLineEdit*>( editWidget );
+ d->combo = dynamic_cast<KComboBox*>( editWidget );
+
+ init();
+}
+
+
+KURLRequester::KURLRequester( TQWidget *parent, const char *name )
+ : TQHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+ init();
+}
+
+
+KURLRequester::KURLRequester( const TQString& url, TQWidget *parent,
+ const char *name )
+ : TQHBox( parent, name )
+{
+ d = new KURLRequesterPrivate;
+ init();
+ setKURL( KURL::fromPathOrURL( url ) );
+}
+
+
+KURLRequester::~KURLRequester()
+{
+ delete myCompletion;
+ delete myFileDialog;
+ delete d;
+}
+
+
+void KURLRequester::init()
+{
+ myFileDialog = 0L;
+ myShowLocalProt = false;
+
+ if ( !d->combo && !d->edit )
+ d->edit = new KLineEdit( this, "line edit" );
+
+ myButton = new KURLDragPushButton( this, "tdefile button");
+ TQIconSet iconSet = SmallIconSet(TQString::fromLatin1("fileopen"));
+ TQPixmap pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal );
+ myButton->setIconSet( iconSet );
+ myButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
+ TQToolTip::add(myButton, i18n("Open file dialog"));
+
+ connect( myButton, TQT_SIGNAL( pressed() ), TQT_SLOT( slotUpdateURL() ));
+
+ setSpacing( KDialog::spacingHint() );
+
+ TQWidget *widget = d->combo ? (TQWidget*) d->combo : (TQWidget*) d->edit;
+ widget->installEventFilter( this );
+ setFocusProxy( widget );
+
+ d->connectSignals( TQT_TQOBJECT(this) );
+ connect( myButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotOpenDialog() ));
+
+ myCompletion = new KURLCompletion();
+ d->setCompletionObject( myCompletion );
+
+ KAccel *accel = new KAccel( this );
+ accel->insert( KStdAccel::Open, TQT_TQOBJECT(this), TQT_SLOT( slotOpenDialog() ));
+ accel->readSettings();
+}
+
+
+void KURLRequester::setURL( const TQString& url )
+{
+ if ( myShowLocalProt )
+ {
+ d->setText( url );
+ }
+ else
+ {
+ // ### This code is broken (e.g. for paths with '#')
+ if ( url.startsWith("file://") )
+ d->setText( url.mid( 7 ) );
+ else if ( url.startsWith("file:") )
+ d->setText( url.mid( 5 ) );
+ else
+ d->setText( url );
+ }
+}
+
+void KURLRequester::setKURL( const KURL& url )
+{
+ if ( myShowLocalProt )
+ d->setText( url.url() );
+ else
+ d->setText( url.pathOrURL() );
+}
+
+void KURLRequester::setCaption( const TQString& caption )
+{
+ TQWidget::setCaption( caption );
+ if (myFileDialog)
+ myFileDialog->setCaption( caption );
+}
+
+TQString KURLRequester::url() const
+{
+ return d->url();
+}
+
+void KURLRequester::slotOpenDialog()
+{
+ KURL newurl;
+ if ( (d->fileDialogMode & KFile::Directory) && !(d->fileDialogMode & KFile::File) ||
+ /* catch possible fileDialog()->setMode( KFile::Directory ) changes */
+ (myFileDialog && ( (myFileDialog->mode() & KFile::Directory) &&
+ (myFileDialog->mode() & (KFile::File | KFile::Files)) == 0 ) ) )
+ {
+ newurl = KDirSelectDialog::selectDirectory(url(), d->fileDialogMode & KFile::LocalOnly);
+ if ( !newurl.isValid() )
+ {
+ return;
+ }
+ }
+ else
+ {
+ emit openFileDialog( this );
+
+ KFileDialog *dlg = fileDialog();
+ if ( !d->url().isEmpty() ) {
+ KURL u( url() );
+ // If we won't be able to list it (e.g. http), then don't try :)
+ if ( KProtocolInfo::supportsListing( u ) )
+ dlg->setSelection( u.url() );
+ }
+
+ if ( dlg->exec() != TQDialog::Accepted )
+ {
+ return;
+ }
+
+ newurl = dlg->selectedURL();
+ }
+
+ setKURL( newurl );
+ emit urlSelected( d->url() );
+}
+
+void KURLRequester::setMode(uint mode)
+{
+ Q_ASSERT( (mode & KFile::Files) == 0 );
+ d->fileDialogMode = mode;
+ if ( (mode & KFile::Directory) && !(mode & KFile::File) )
+ myCompletion->setMode( KURLCompletion::DirCompletion );
+
+ if (myFileDialog)
+ myFileDialog->setMode( d->fileDialogMode );
+}
+
+unsigned int KURLRequester::mode() const
+{
+ return d->fileDialogMode;
+}
+
+void KURLRequester::setFilter(const TQString &filter)
+{
+ d->fileDialogFilter = filter;
+ if (myFileDialog)
+ myFileDialog->setFilter( d->fileDialogFilter );
+}
+
+TQString KURLRequester::filter( ) const
+{
+ return d->fileDialogFilter;
+}
+
+
+KFileDialog * KURLRequester::fileDialog() const
+{
+ if ( !myFileDialog ) {
+ TQWidget *p = parentWidget();
+ myFileDialog = new KFileDialog( TQString::null, d->fileDialogFilter, p,
+ "file dialog", true );
+
+ myFileDialog->setMode( d->fileDialogMode );
+ myFileDialog->setCaption( caption() );
+ }
+
+ return myFileDialog;
+}
+
+
+void KURLRequester::setShowLocalProtocol( bool b )
+{
+ if ( myShowLocalProt == b )
+ return;
+
+ myShowLocalProt = b;
+ setKURL( url() );
+}
+
+void KURLRequester::clear()
+{
+ d->setText( TQString::null );
+}
+
+KLineEdit * KURLRequester::lineEdit() const
+{
+ return d->edit;
+}
+
+KComboBox * KURLRequester::comboBox() const
+{
+ return d->combo;
+}
+
+void KURLRequester::slotUpdateURL()
+{
+ // bin compat, myButton is declared as QPushButton
+ KURL u;
+ u = KURL( KURL( TQDir::currentDirPath() + '/' ), url() );
+ (static_cast<KURLDragPushButton *>( myButton ))->setURL( u );
+}
+
+bool KURLRequester::eventFilter( TQObject *obj, TQEvent *ev )
+{
+ if ( ( TQT_BASE_OBJECT(d->edit) == TQT_BASE_OBJECT(obj) ) || ( TQT_BASE_OBJECT(d->combo) == TQT_BASE_OBJECT(obj) ) )
+ {
+ if (( ev->type() == TQEvent::FocusIn ) || ( ev->type() == TQEvent::FocusOut ))
+ // Forward focusin/focusout events to the urlrequester; needed by file form element in tdehtml
+ TQApplication::sendEvent( this, ev );
+ }
+ return TQWidget::eventFilter( obj, ev );
+}
+
+KPushButton * KURLRequester::button() const
+{
+ return myButton;
+}
+
+KEditListBox::CustomEditor KURLRequester::customEditor()
+{
+ setSizePolicy(TQSizePolicy( TQSizePolicy::Preferred,
+ TQSizePolicy::Fixed));
+
+ KLineEdit *edit = d->edit;
+ if ( !edit && d->combo )
+ edit = dynamic_cast<KLineEdit*>( d->combo->lineEdit() );
+
+#ifndef NDEBUG
+ if ( !edit )
+ kdWarning() << "KURLRequester's lineedit is not a KLineEdit!??\n";
+#endif
+
+ KEditListBox::CustomEditor editor( this, edit );
+ return editor;
+}
+
+void KURLRequester::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+KURLComboRequester::KURLComboRequester( TQWidget *parent,
+ const char *name )
+ : KURLRequester( new KComboBox(false), parent, name)
+{
+}
+
+#include "kurlrequester.moc"
diff --git a/tdeio/tdefile/kurlrequester.h b/tdeio/tdefile/kurlrequester.h
new file mode 100644
index 000000000..55bc0fd83
--- /dev/null
+++ b/tdeio/tdefile/kurlrequester.h
@@ -0,0 +1,301 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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 KURLREQUESTER_H
+#define KURLREQUESTER_H
+
+#include <tqhbox.h>
+
+#include <keditlistbox.h>
+#include <tdefile.h>
+#include <kpushbutton.h>
+#include <kurl.h>
+
+class KComboBox;
+class KFileDialog;
+class KLineEdit;
+class KURLCompletion;
+class KURLDragPushButton;
+
+class TQString;
+class TQTimer;
+
+/**
+ * This class is a widget showing a lineedit and a button, which invokes a
+ * filedialog. File name completion is available in the lineedit.
+ *
+ * The defaults for the filedialog are to ask for one existing local file, i.e.
+ * KFileDialog::setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly )
+ * The default filter is "*", i.e. show all files, and the start directory is
+ * the current working directory, or the last directory where a file has been
+ * selected.
+ *
+ * You can change this behavior by using setMode() or setFilter().
+ *
+ * \image html kurlrequester.png "KDE URL Requester"
+ *
+ * @short A widget to request a filename/url from the user
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KURLRequester : public TQHBox
+{
+ Q_OBJECT
+ TQ_PROPERTY( TQString url READ url WRITE setURL )
+ TQ_PROPERTY( bool showLocalProtocol READ showLocalProtocol WRITE setShowLocalProtocol )
+ TQ_PROPERTY( TQString filter READ filter WRITE setFilter )
+ TQ_PROPERTY( uint mode READ mode WRITE setMode )
+
+public:
+ /**
+ * Constructs a KURLRequester widget.
+ */
+ KURLRequester( TQWidget *parent=0, const char *name=0 );
+
+ /**
+ * Constructs a KURLRequester widget with the initial URL @p url.
+ * // TODO KDE4: Use KURL instead
+ */
+ KURLRequester( const TQString& url, TQWidget *parent=0, const char *name=0 );
+
+ /**
+ * Special constructor, which creates a KURLRequester widget with a custom
+ * edit-widget. The edit-widget can be either a KComboBox or a KLineEdit
+ * (or inherited thereof). Note: for geometry management reasons, the
+ * edit-widget is reparented to have the KURLRequester as parent.
+ */
+ KURLRequester( TQWidget *editWidget, TQWidget *parent, const char *name=0 );
+ /**
+ * Destructs the KURLRequester.
+ */
+ ~KURLRequester();
+
+ /**
+ * @returns the current url in the lineedit. May be malformed, if the user
+ * entered something weird. ~user or environment variables are substituted
+ * for local files.
+ * // TODO KDE4: Use KURL so that the result is properly defined
+ */
+ TQString url() const;
+
+ /**
+ * Enables/disables showing file:/ in the lineedit, when a local file has
+ * been selected in the filedialog or was set via setURL().
+ * Default is false, not showing file:/
+ * @see showLocalProtocol
+ */
+ void setShowLocalProtocol( bool b );
+
+ /**
+ * Sets the mode of the file dialog.
+ * Note: you can only select one file with the filedialog,
+ * so KFile::Files doesn't make much sense.
+ * @see KFileDialog::setMode()
+ */
+ void setMode( uint m );
+
+ /**
+ * Returns the current mode
+ * @see KFileDialog::mode()
+ * @since 3.3
+ */
+ uint mode() const;
+
+
+ /**
+ * Sets the filter for the file dialog.
+ * @see KFileDialog::setFilter()
+ */
+ void setFilter( const TQString& filter );
+
+ /**
+ * Returns the current filter for the file dialog.
+ * @see KFileDialog::filter()
+ * @since 3.3
+ */
+ TQString filter() const;
+
+ /**
+ * @returns whether local files will be prefixed with file:/ in the
+ * lineedit
+ * @see setShowLocalProtocol
+ */
+ bool showLocalProtocol() const { return myShowLocalProt; }
+ // ## KDE4: there's no reason to keep this, it should always be false
+
+ /**
+ * @returns a pointer to the filedialog
+ * You can use this to customize the dialog, e.g. to specify a filter.
+ * Never returns 0L.
+ *
+ * Remove in KDE4? KURLRequester should use KDirSelectDialog for
+ * (mode & KFile::Directory) && !(mode & KFile::File)
+ */
+ virtual KFileDialog * fileDialog() const;
+
+ /**
+ * @returns a pointer to the lineedit, either the default one, or the
+ * special one, if you used the special constructor.
+ *
+ * It is provided so that you can e.g. set an own completion object
+ * (e.g. KShellCompletion) into it.
+ */
+ KLineEdit * lineEdit() const;
+
+ /**
+ * @returns a pointer to the combobox, in case you have set one using the
+ * special constructor. Returns 0L otherwise.
+ */
+ KComboBox * comboBox() const;
+
+ /**
+ * @returns a pointer to the pushbutton. It is provided so that you can
+ * specify an own pixmap or a text, if you really need to.
+ */
+ KPushButton * button() const;
+
+ /**
+ * @returns the KURLCompletion object used in the lineedit/combobox.
+ */
+ KURLCompletion *completionObject() const { return myCompletion; }
+
+ /**
+ * @returns an object, suitable for use with KEditListBox. It allows you
+ * to put this KURLRequester into a KEditListBox.
+ * Basically, do it like this:
+ * \code
+ * KURLRequester *req = new KURLRequester( someWidget );
+ * [...]
+ * KEditListBox *editListBox = new KEditListBox( i18n("Some Title"), req->customEditor(), someWidget );
+ * \endcode
+ * @since 3.1
+ */
+ KEditListBox::CustomEditor customEditor();
+
+public slots:
+ /**
+ * Sets the url in the lineedit to @p url. Depending on the state of
+ * showLocalProtocol(), file:/ on local files will be shown or not.
+ * @since 3.1
+ * // TODO KDE4: Use KURL instead
+ */
+ void setURL( const TQString& url );
+
+ /**
+ * Sets the url in the lineedit to @p url.
+ * @since 3.4
+ * // TODO KDE4: rename to setURL
+ */
+ void setKURL( const KURL& url );
+
+ /**
+ * Sets the caption of the file dialog.
+ * @since 3.1
+ */
+ virtual void setCaption( const TQString& caption );
+
+ /**
+ * Clears the lineedit/combobox.
+ */
+ void clear();
+
+signals:
+ // forwards from LineEdit
+ /**
+ * Emitted when the text in the lineedit changes.
+ * The parameter contains the contents of the lineedit.
+ * @since 3.1
+ */
+ void textChanged( const TQString& );
+
+ /**
+ * Emitted when return or enter was pressed in the lineedit.
+ */
+ void returnPressed();
+
+ /**
+ * Emitted when return or enter was pressed in the lineedit.
+ * The parameter contains the contents of the lineedit.
+ */
+ void returnPressed( const TQString& );
+
+ /**
+ * Emitted before the filedialog is going to open. Connect
+ * to this signal to "configure" the filedialog, e.g. set the
+ * filefilter, the mode, a preview-widget, etc. It's usually
+ * not necessary to set a URL for the filedialog, as it will
+ * get set properly from the editfield contents.
+ *
+ * If you use multiple KURLRequesters, you can connect all of them
+ * to the same slot and use the given KURLRequester pointer to know
+ * which one is going to open.
+ */
+ void openFileDialog( KURLRequester * );
+
+ /**
+ * Emitted when the user changed the URL via the file dialog.
+ * The parameter contains the contents of the lineedit.
+ * // TODO KDE4: Use KURL instead
+ */
+ void urlSelected( const TQString& );
+
+protected:
+ void init();
+
+ KURLCompletion * myCompletion;
+
+
+private:
+ KURLDragPushButton * myButton;
+ bool myShowLocalProt;
+ mutable KFileDialog * myFileDialog;
+
+
+protected slots:
+ /**
+ * Called when the button is pressed to open the filedialog.
+ * Also called when KStdAccel::Open (default is Ctrl-O) is pressed.
+ */
+ void slotOpenDialog();
+
+private slots:
+ void slotUpdateURL();
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ bool eventFilter( TQObject *obj, TQEvent *ev );
+private:
+ class KURLRequesterPrivate;
+ KURLRequesterPrivate *d;
+};
+
+/**
+ * URL requester with a combo box, for use in Designer
+ */
+class TDEIO_EXPORT KURLComboRequester : public KURLRequester
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs a KURLRequester widget with a combobox.
+ */
+ KURLComboRequester( TQWidget *parent=0, const char *name=0 );
+};
+
+
+#endif // KURLREQUESTER_H
diff --git a/tdeio/tdefile/kurlrequesterdlg.cpp b/tdeio/tdefile/kurlrequesterdlg.cpp
new file mode 100644
index 000000000..7524ea149
--- /dev/null
+++ b/tdeio/tdefile/kurlrequesterdlg.cpp
@@ -0,0 +1,135 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Wilco Greven <greven@kde.org>
+
+ 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 <sys/stat.h>
+#include <unistd.h>
+
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqstring.h>
+#include <tqtoolbutton.h>
+
+#include <kaccel.h>
+#include <tdefiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <krecentdocument.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+
+#include "kurlrequesterdlg.h"
+
+
+KURLRequesterDlg::KURLRequesterDlg( const TQString& urlName, TQWidget *parent,
+ const char *name, bool modal )
+ : KDialogBase( Plain, TQString::null, Ok|Cancel|User1, Ok, parent, name,
+ modal, true, KStdGuiItem::clear() )
+{
+ initDialog(i18n( "Location:" ), urlName);
+}
+
+KURLRequesterDlg::KURLRequesterDlg( const TQString& urlName, const TQString& _text, TQWidget *parent, const char *name, bool modal )
+ : KDialogBase( Plain, TQString::null, Ok|Cancel|User1, Ok, parent, name,
+ modal, true, KStdGuiItem::clear() )
+{
+ initDialog(_text, urlName);
+}
+
+KURLRequesterDlg::~KURLRequesterDlg()
+{
+}
+
+void KURLRequesterDlg::initDialog(const TQString &text,const TQString &urlName)
+{
+ TQVBoxLayout * topLayout = new TQVBoxLayout( plainPage(), 0,
+ spacingHint() );
+
+ TQLabel * label = new TQLabel( text , plainPage() );
+ topLayout->addWidget( label );
+
+ urlRequester_ = new KURLRequester( urlName, plainPage(), "urlRequester" );
+ urlRequester_->setMinimumWidth( urlRequester_->sizeHint().width() * 3 );
+ topLayout->addWidget( urlRequester_ );
+ urlRequester_->setFocus();
+ connect( urlRequester_->lineEdit(), TQT_SIGNAL(textChanged(const TQString&)),
+ TQT_SLOT(slotTextChanged(const TQString&)) );
+ bool state = !urlName.isEmpty();
+ enableButtonOK( state );
+ enableButton( KDialogBase::User1, state );
+ /*
+ KFile::Mode mode = static_cast<KFile::Mode>( KFile::File |
+ KFile::ExistingOnly );
+ urlRequester_->setMode( mode );
+ */
+ connect( this, TQT_SIGNAL( user1Clicked() ), TQT_SLOT( slotClear() ) );
+}
+
+void KURLRequesterDlg::slotTextChanged(const TQString & text)
+{
+ bool state = !text.stripWhiteSpace().isEmpty();
+ enableButtonOK( state );
+ enableButton( KDialogBase::User1, state );
+}
+
+void KURLRequesterDlg::slotClear()
+{
+ urlRequester_->clear();
+}
+
+KURL KURLRequesterDlg::selectedURL() const
+{
+ if ( result() == TQDialog::Accepted )
+ return KURL::fromPathOrURL( urlRequester_->url() );
+ else
+ return KURL();
+}
+
+
+KURL KURLRequesterDlg::getURL(const TQString& dir, TQWidget *parent,
+ const TQString& caption)
+{
+ KURLRequesterDlg dlg(dir, parent, "filedialog", true);
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.exec();
+
+ const KURL& url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add(url);
+
+ return url;
+}
+
+KFileDialog * KURLRequesterDlg::fileDialog()
+{
+ return urlRequester_->fileDialog();
+}
+
+KURLRequester * KURLRequesterDlg::urlRequester()
+{
+ return urlRequester_;
+}
+
+#include "kurlrequesterdlg.moc"
+
+// vim:ts=4:sw=4:tw=78
diff --git a/tdeio/tdefile/kurlrequesterdlg.h b/tdeio/tdefile/kurlrequesterdlg.h
new file mode 100644
index 000000000..07b70d745
--- /dev/null
+++ b/tdeio/tdefile/kurlrequesterdlg.h
@@ -0,0 +1,114 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Wilco Greven <greven@kde.org>
+
+ 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 KURLREQUESTERDIALOG_H
+#define KURLREQUESTERDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class KURLCompletion;
+class KURLRequester;
+class KFileDialog;
+/**
+ * Dialog in which a user can enter a filename or url. It is a dialog
+ * encapsulating KURLRequester. The API is derived from
+ * KFileDialog.
+ *
+ * @short Simple dialog to enter a filename/url.
+ * @author Wilco Greven <greven@kde.org>
+ */
+class TDEIO_EXPORT KURLRequesterDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KURLRequesterDlg.
+ *
+ * @param url The url of the directory to start in. Use TQString::null
+ * to start in the current working directory, or the last
+ * directory where a file has been selected.
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ * @param modal Specifies whether the dialog should be opened as modal
+ * or not.
+ */
+ KURLRequesterDlg( const TQString& url, TQWidget *parent,
+ const char *name, bool modal = true );
+
+ /**
+ * Constructs a KURLRequesterDlg.
+ *
+ * @param url The url of the directory to start in. Use TQString::null
+ * to start in the current working directory, or the last
+ * directory where a file has been selected.
+ * @param text Text of the label
+ * @param parent The parent object of this widget.
+ * @param name The name of this widget.
+ * @param modal Specifies whether the dialog should be opened as modal
+ * or not.
+ */
+ KURLRequesterDlg( const TQString& url, const TQString& text,
+ TQWidget *parent, const char *name, bool modal=true );
+ /**
+ * Destructs the dialog.
+ */
+ ~KURLRequesterDlg();
+
+ /**
+ * Returns the fully qualified filename.
+ */
+ KURL selectedURL() const;
+
+ /**
+ * Creates a modal dialog, executes it and returns the selected URL.
+ *
+ * @param url This specifies the initial path of the input line.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The caption to use for the dialog.
+ */
+ static KURL getURL(const TQString& url = TQString::null,
+ TQWidget *parent= 0, const TQString& caption = TQString::null);
+
+ /**
+ * Returns a pointer to the file dialog used by the KURLRequester.
+ */
+ KFileDialog * fileDialog();
+ /**
+ * Returns a pointer to the KURLRequester.
+ */
+ KURLRequester *urlRequester();
+
+private slots:
+ void slotClear();
+ void slotTextChanged(const TQString &);
+private:
+ void initDialog(const TQString &text, const TQString &url);
+ KURLRequester *urlRequester_;
+
+ class KURLRequesterDlgPrivate;
+ KURLRequesterDlgPrivate *d;
+
+};
+
+#endif // KURLREQUESTERDIALOG_H
+
+// vim:ts=4:sw=4:tw=78
diff --git a/tdeio/tdefile/tdefile.h b/tdeio/tdefile/tdefile.h
new file mode 100644
index 000000000..d4616b642
--- /dev/null
+++ b/tdeio/tdefile/tdefile.h
@@ -0,0 +1,129 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ version 2, License 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 KFILE_H
+#define KFILE_H
+
+#include <tqdir.h>
+
+#include "tdelibs_export.h"
+
+/**
+ * KFile is a class which provides a namespace for some enumerated
+ * values associated with the tdefile library. You will never need to
+ * construct a KFile object itself.
+ */
+
+class TDEIO_EXPORT KFile
+{
+public:
+ /**
+ * Modes of operation for the dialog.
+ * @li @p File - Get a single file name from the user.
+ * @li @p Directory - Get a directory name from the user.
+ * @li @p Files - Get multiple file names from the user.
+ * @li @p ExistingOnly - Never return a filename which does not exist yet
+ * @li @p LocalOnly - Don't return remote filenames
+ */
+ enum Mode {
+ File = 1,
+ Directory = 2,
+ Files = 4,
+ ExistingOnly = 8,
+ LocalOnly = 16,
+ ModeMax = 65536
+ };
+
+ enum FileView {
+ Default = 0,
+ Simple = 1,
+ Detail = 2,
+ SeparateDirs = 4,
+ PreviewContents = 8,
+ PreviewInfo = 16,
+ FileViewMax = 65536
+ };
+
+ enum SelectionMode {
+ Single = 1,
+ Multi = 2,
+ Extended = 4,
+ NoSelection = 8
+ };
+
+
+ //
+ // some bittests
+ //
+
+
+ // sorting specific
+
+ // grr, who had the idea to set TQDir::Name to 0x0?
+ static bool isSortByName( const TQDir::SortSpec& sort ) {
+ return (sort & TQDir::Time) != TQDir::Time &&
+ (sort & TQDir::Size) != TQDir::Size;
+ }
+
+ static bool isSortBySize( const TQDir::SortSpec& sort ) {
+ return (sort & TQDir::Size) == TQDir::Size;
+ }
+
+ static bool isSortByDate( const TQDir::SortSpec& sort ) {
+ return (sort & TQDir::Time) == TQDir::Time;
+ }
+
+ static bool isSortDirsFirst( const TQDir::SortSpec& sort ) {
+ return (sort & TQDir::DirsFirst) == TQDir::DirsFirst;
+ }
+
+ static bool isSortCaseInsensitive( const TQDir::SortSpec& sort ) {
+ return (sort & TQDir::IgnoreCase) == TQDir::IgnoreCase;
+ }
+
+
+ // view specific
+ static bool isDefaultView( const FileView& view ) {
+ return (view & Default) == Default;
+ }
+
+ static bool isSimpleView( const FileView& view ) {
+ return (view & Simple) == Simple;
+ }
+
+ static bool isDetailView( const FileView& view ) {
+ return (view & Detail) == Detail;
+ }
+
+ static bool isSeparateDirs( const FileView& view ) {
+ return (view & SeparateDirs) == SeparateDirs;
+ }
+
+ static bool isPreviewContents( const FileView& view ) {
+ return (view & PreviewContents) == PreviewContents;
+ }
+
+ /**
+ * @since 3.1
+ */
+ static bool isPreviewInfo( const FileView& view ) {
+ return (view & PreviewInfo) == PreviewInfo;
+ }
+
+};
+
+#endif // KFILE_H
diff --git a/tdeio/tdefile/tdefilebookmarkhandler.cpp b/tdeio/tdefile/tdefilebookmarkhandler.cpp
new file mode 100644
index 000000000..d05a94541
--- /dev/null
+++ b/tdeio/tdefile/tdefilebookmarkhandler.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <kbookmarkimporter.h>
+#include <kbookmarkdombuilder.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+
+#include "tdefiledialog.h"
+#include "tdefilebookmarkhandler.h"
+
+KFileBookmarkHandler::KFileBookmarkHandler( KFileDialog *dialog )
+ : TQObject( dialog, "KFileBookmarkHandler" ),
+ KBookmarkOwner(),
+ m_dialog( dialog )
+{
+ m_menu = new KPopupMenu( dialog, "bookmark menu" );
+
+ TQString file = locate( "data", "tdefile/bookmarks.xml" );
+ if ( file.isEmpty() )
+ file = locateLocal( "data", "tdefile/bookmarks.xml" );
+
+ KBookmarkManager *manager = KBookmarkManager::managerForFile( file, false);
+
+ // import old bookmarks
+ if ( !KStandardDirs::exists( file ) ) {
+ TQString oldFile = locate( "data", "tdefile/bookmarks.html" );
+ if ( !oldFile.isEmpty() )
+ importOldBookmarks( oldFile, manager );
+ }
+
+ manager->setUpdate( true );
+ manager->setShowNSBookmarks( false );
+
+ m_bookmarkMenu = new KBookmarkMenu( manager, this, m_menu,
+ dialog->actionCollection(), true );
+}
+
+KFileBookmarkHandler::~KFileBookmarkHandler()
+{
+ delete m_bookmarkMenu;
+}
+
+TQString KFileBookmarkHandler::currentURL() const
+{
+ return m_dialog->baseURL().url();
+}
+
+void KFileBookmarkHandler::importOldBookmarks( const TQString& path,
+ KBookmarkManager *manager )
+{
+ KBookmarkDomBuilder *builder = new KBookmarkDomBuilder( manager->root(), manager );
+ KNSBookmarkImporter importer( path );
+ builder->connectImporter( &importer );
+ importer.parseNSBookmarks();
+ delete builder;
+ manager->save();
+}
+
+void KFileBookmarkHandler::virtual_hook( int id, void* data )
+{ KBookmarkOwner::virtual_hook( id, data ); }
+
+#include "tdefilebookmarkhandler.moc"
diff --git a/tdeio/tdefile/tdefilebookmarkhandler.h b/tdeio/tdefile/tdefilebookmarkhandler.h
new file mode 100644
index 000000000..9b615c87e
--- /dev/null
+++ b/tdeio/tdefile/tdefilebookmarkhandler.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 KFILEBOOKMARKHANDLER_H
+#define KFILEBOOKMARKHANDLER_H
+
+#include <kbookmarkmanager.h>
+#include <kbookmarkmenu.h>
+
+class TQTextStream;
+class KPopupMenu;
+
+
+class TDEIO_EXPORT KFileBookmarkHandler : public TQObject, public KBookmarkOwner
+{
+ Q_OBJECT
+
+public:
+ KFileBookmarkHandler( KFileDialog *dialog );
+ ~KFileBookmarkHandler();
+
+ TQPopupMenu * popupMenu();
+
+ // KBookmarkOwner interface:
+ virtual void openBookmarkURL( const TQString& url ) { emit openURL( url ); }
+ virtual TQString currentURL() const;
+
+ KPopupMenu *menu() const { return m_menu; }
+
+signals:
+ void openURL( const TQString& url );
+
+private:
+ void importOldBookmarks( const TQString& path, KBookmarkManager *manager );
+
+ KFileDialog *m_dialog;
+ KPopupMenu *m_menu;
+ KBookmarkMenu *m_bookmarkMenu;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileBookmarkHandlerPrivate;
+ KFileBookmarkHandlerPrivate *d;
+};
+
+
+#endif // KFILEBOOKMARKHANDLER_H
diff --git a/tdeio/tdefile/tdefiledetailview.cpp b/tdeio/tdefile/tdefiledetailview.cpp
new file mode 100644
index 000000000..b989104e8
--- /dev/null
+++ b/tdeio/tdefile/tdefiledetailview.cpp
@@ -0,0 +1,686 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ 2000, 2001 Carsten Pfeiffer <pfeiffer@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 <tqevent.h>
+#include <tqkeycode.h>
+#include <tqheader.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+
+#include <kapplication.h>
+#include <tdefileitem.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kicontheme.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+
+#include "tdefiledetailview.h"
+#include "config-tdefile.h"
+
+#define COL_NAME 0
+#define COL_SIZE 1
+#define COL_DATE 2
+#define COL_PERM 3
+#define COL_OWNER 4
+#define COL_GROUP 5
+
+class KFileDetailView::KFileDetailViewPrivate
+{
+public:
+ KFileDetailViewPrivate() : dropItem(0)
+ { }
+
+ KFileListViewItem *dropItem;
+ TQTimer autoOpenTimer;
+};
+
+KFileDetailView::KFileDetailView(TQWidget *parent, const char *name)
+ : KListView(parent, name), KFileView(), d(new KFileDetailViewPrivate())
+{
+ // this is always the static section, not the index depending on column order
+ m_sortingCol = COL_NAME;
+ m_blockSortingSignal = false;
+ setViewName( i18n("Detailed View") );
+
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "Size" ) );
+ addColumn( i18n( "Date" ) );
+ addColumn( i18n( "Permissions" ) );
+ addColumn( i18n( "Owner" ) );
+ addColumn( i18n( "Group" ) );
+ setShowSortIndicator( true );
+ setAllColumnsShowFocus( true );
+ setDragEnabled(true);
+
+ connect( header(), TQT_SIGNAL( clicked(int)),
+ TQT_SLOT(slotSortingChanged(int) ));
+
+
+ connect( this, TQT_SIGNAL( returnPressed(TQListViewItem *) ),
+ TQT_SLOT( slotActivate( TQListViewItem *) ) );
+
+ connect( this, TQT_SIGNAL( clicked(TQListViewItem *, const TQPoint&, int)),
+ TQT_SLOT( selected( TQListViewItem *) ) );
+ connect( this, TQT_SIGNAL( doubleClicked(TQListViewItem *, const TQPoint&, int)),
+ TQT_SLOT( slotActivate( TQListViewItem *) ) );
+
+ connect( this, TQT_SIGNAL(contextMenuRequested( TQListViewItem *,
+ const TQPoint &, int )),
+ this, TQT_SLOT( slotActivateMenu( TQListViewItem *, const TQPoint& )));
+
+ KFile::SelectionMode sm = KFileView::selectionMode();
+ switch ( sm ) {
+ case KFile::Multi:
+ TQListView::setSelectionMode( TQListView::Multi );
+ break;
+ case KFile::Extended:
+ TQListView::setSelectionMode( TQListView::Extended );
+ break;
+ case KFile::NoSelection:
+ TQListView::setSelectionMode( TQListView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ TQListView::setSelectionMode( TQListView::Single );
+ break;
+ }
+
+ // for highlighting
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( slotSelectionChanged() ));
+ else
+ connect( this, TQT_SIGNAL( selectionChanged( TQListViewItem * ) ),
+ TQT_SLOT( highlighted( TQListViewItem * ) ));
+
+ // DND
+ connect( &(d->autoOpenTimer), TQT_SIGNAL( timeout() ),
+ this, TQT_SLOT( slotAutoOpen() ));
+
+ setSorting( sorting() );
+
+ m_resolver =
+ new KMimeTypeResolver<KFileListViewItem,KFileDetailView>( this );
+}
+
+KFileDetailView::~KFileDetailView()
+{
+ delete m_resolver;
+ delete d;
+}
+
+void KFileDetailView::readConfig( TDEConfig *config, const TQString& group )
+{
+ restoreLayout( config, group );
+}
+
+void KFileDetailView::writeConfig( TDEConfig *config, const TQString& group )
+{
+ saveLayout( config, group );
+}
+
+void KFileDetailView::setSelected( const KFileItem *info, bool enable )
+{
+ if ( !info )
+ return;
+
+ // we can only hope that this casts works
+ KFileListViewItem *item = (KFileListViewItem*)info->extraData( this );
+
+ if ( item )
+ KListView::setSelected( item, enable );
+}
+
+void KFileDetailView::setCurrentItem( const KFileItem *item )
+{
+ if ( !item )
+ return;
+ KFileListViewItem *it = (KFileListViewItem*) item->extraData( this );
+ if ( it )
+ KListView::setCurrentItem( it );
+}
+
+KFileItem * KFileDetailView::currentFileItem() const
+{
+ KFileListViewItem *current = static_cast<KFileListViewItem*>( currentItem() );
+ if ( current )
+ return current->fileInfo();
+
+ return 0L;
+}
+
+void KFileDetailView::clearSelection()
+{
+ KListView::clearSelection();
+}
+
+void KFileDetailView::selectAll()
+{
+ if (KFileView::selectionMode() == KFile::NoSelection ||
+ KFileView::selectionMode() == KFile::Single)
+ return;
+
+ KListView::selectAll( true );
+}
+
+void KFileDetailView::invertSelection()
+{
+ KListView::invertSelection();
+}
+
+void KFileDetailView::slotActivateMenu (TQListViewItem *item,const TQPoint& pos )
+{
+ if ( !item ) {
+ sig->activateMenu( 0, pos );
+ return;
+ }
+ KFileListViewItem *i = (KFileListViewItem*) item;
+ sig->activateMenu( i->fileInfo(), pos );
+}
+
+void KFileDetailView::clearView()
+{
+ m_resolver->m_lstPendingMimeIconItems.clear();
+ KListView::clear();
+}
+
+void KFileDetailView::insertItem( KFileItem *i )
+{
+ KFileView::insertItem( i );
+
+ KFileListViewItem *item = new KFileListViewItem( (TQListView*) this, i );
+
+ setSortingKey( item, i );
+
+ i->setExtraData( this, item );
+
+ if ( !i->isMimeTypeKnown() )
+ m_resolver->m_lstPendingMimeIconItems.append( item );
+}
+
+void KFileDetailView::slotActivate( TQListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->activate( fi );
+}
+
+void KFileDetailView::selected( TQListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ if ( TDEGlobalSettings::singleClick() ) {
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
+ sig->activate( fi );
+ }
+}
+
+void KFileDetailView::highlighted( TQListViewItem *item )
+{
+ if ( !item )
+ return;
+
+ const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->highlightFile( fi );
+}
+
+
+void KFileDetailView::setSelectionMode( KFile::SelectionMode sm )
+{
+ disconnect( this, TQT_SIGNAL( selectionChanged() ));
+ disconnect( this, TQT_SIGNAL( selectionChanged( TQListViewItem * ) ));
+
+ KFileView::setSelectionMode( sm );
+
+ switch ( KFileView::selectionMode() ) {
+ case KFile::Multi:
+ TQListView::setSelectionMode( TQListView::Multi );
+ break;
+ case KFile::Extended:
+ TQListView::setSelectionMode( TQListView::Extended );
+ break;
+ case KFile::NoSelection:
+ TQListView::setSelectionMode( TQListView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ TQListView::setSelectionMode( TQListView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( slotSelectionChanged() ));
+ else
+ connect( this, TQT_SIGNAL( selectionChanged( TQListViewItem * )),
+ TQT_SLOT( highlighted( TQListViewItem * )));
+}
+
+bool KFileDetailView::isSelected( const KFileItem *i ) const
+{
+ if ( !i )
+ return false;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ return (item && item->isSelected());
+}
+
+
+void KFileDetailView::updateView( bool b )
+{
+ if ( !b )
+ return;
+
+ TQListViewItemIterator it( (TQListView*)this );
+ for ( ; it.current(); ++it ) {
+ KFileListViewItem *item=static_cast<KFileListViewItem *>(it.current());
+ item->setPixmap( 0, item->fileInfo()->pixmap(KIcon::SizeSmall) );
+ }
+}
+
+void KFileDetailView::updateView( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ if ( !item )
+ return;
+
+ item->init();
+ setSortingKey( item, i );
+
+ //item->repaint(); // only repaints if visible
+}
+
+void KFileDetailView::setSortingKey( KFileListViewItem *item,
+ const KFileItem *i )
+{
+ // see also setSorting()
+ TQDir::SortSpec spec = KFileView::sorting();
+
+ if ( spec & TQDir::Time )
+ item->setKey( sortingKey( i->time( TDEIO::UDS_MODIFICATION_TIME ),
+ i->isDir(), spec ));
+ else if ( spec & TQDir::Size )
+ item->setKey( sortingKey( i->size(), i->isDir(), spec ));
+
+ else // Name or Unsorted
+ item->setKey( sortingKey( i->text(), i->isDir(), spec ));
+}
+
+
+void KFileDetailView::removeItem( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+ m_resolver->m_lstPendingMimeIconItems.remove( item );
+ delete item;
+
+ KFileView::removeItem( i );
+}
+
+void KFileDetailView::slotSortingChanged( int col )
+{
+ // col is the section here, not the index!
+
+ TQDir::SortSpec sort = sorting();
+ int sortSpec = -1;
+ bool reversed = (col == m_sortingCol) && (sort & TQDir::Reversed) == 0;
+ m_sortingCol = col;
+
+ switch( col ) {
+ case COL_NAME:
+ sortSpec = (sort & ~TQDir::SortByMask | TQDir::Name);
+ break;
+ case COL_SIZE:
+ sortSpec = (sort & ~TQDir::SortByMask | TQDir::Size);
+ break;
+ case COL_DATE:
+ sortSpec = (sort & ~TQDir::SortByMask | TQDir::Time);
+ break;
+
+ // the following columns have no equivalent in TQDir, so we set it
+ // to TQDir::Unsorted and remember the column (m_sortingCol)
+ case COL_OWNER:
+ case COL_GROUP:
+ case COL_PERM:
+ // grmbl, TQDir::Unsorted == SortByMask.
+ sortSpec = (sort & ~TQDir::SortByMask);// | TQDir::Unsorted;
+ break;
+ default:
+ break;
+ }
+
+ if ( reversed )
+ sortSpec |= TQDir::Reversed;
+ else
+ sortSpec &= ~TQDir::Reversed;
+
+ if ( sort & TQDir::IgnoreCase )
+ sortSpec |= TQDir::IgnoreCase;
+ else
+ sortSpec &= ~TQDir::IgnoreCase;
+
+
+ KFileView::setSorting( static_cast<TQDir::SortSpec>( sortSpec ) );
+
+ KFileItem *item;
+ KFileItemListIterator it( *items() );
+
+ if ( sortSpec & TQDir::Time ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->time( TDEIO::UDS_MODIFICATION_TIME ), item->isDir(), sortSpec ));
+ }
+
+ else if ( sortSpec & TQDir::Size ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
+ sortSpec ));
+ }
+ else { // Name or Unsorted -> use column text
+ for ( ; (item = it.current()); ++it ) {
+ KFileListViewItem *i = viewItem( item );
+ i->setKey( sortingKey( i->text(m_sortingCol), item->isDir(),
+ sortSpec ));
+ }
+ }
+
+ KListView::setSorting( m_sortingCol, !reversed );
+ KListView::sort();
+
+ if ( !m_blockSortingSignal )
+ sig->changeSorting( static_cast<TQDir::SortSpec>( sortSpec ) );
+}
+
+
+void KFileDetailView::setSorting( TQDir::SortSpec spec )
+{
+ int col = 0;
+ if ( spec & TQDir::Time )
+ col = COL_DATE;
+ else if ( spec & TQDir::Size )
+ col = COL_SIZE;
+ else if ( spec & TQDir::Unsorted )
+ col = m_sortingCol;
+ else
+ col = COL_NAME;
+
+ // inversed, because slotSortingChanged will reverse it
+ if ( spec & TQDir::Reversed )
+ spec = (TQDir::SortSpec) (spec & ~TQDir::Reversed);
+ else
+ spec = (TQDir::SortSpec) (spec | TQDir::Reversed);
+
+ m_sortingCol = col;
+ KFileView::setSorting( (TQDir::SortSpec) spec );
+
+
+ // don't emit sortingChanged() when called via setSorting()
+ m_blockSortingSignal = true; // can't use blockSignals()
+ slotSortingChanged( col );
+ m_blockSortingSignal = false;
+}
+
+void KFileDetailView::ensureItemVisible( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
+
+ if ( item )
+ KListView::ensureItemVisible( item );
+}
+
+// we're in multiselection mode
+void KFileDetailView::slotSelectionChanged()
+{
+ sig->highlightFile( 0L );
+}
+
+KFileItem * KFileDetailView::firstFileItem() const
+{
+ KFileListViewItem *item = static_cast<KFileListViewItem*>( firstChild() );
+ if ( item )
+ return item->fileInfo();
+ return 0L;
+}
+
+KFileItem * KFileDetailView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileListViewItem *item = viewItem( fileItem );
+ if ( item && item->itemBelow() )
+ return ((KFileListViewItem*) item->itemBelow())->fileInfo();
+ else
+ return 0L;
+ }
+ else
+ return firstFileItem();
+}
+
+KFileItem * KFileDetailView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileListViewItem *item = viewItem( fileItem );
+ if ( item && item->itemAbove() )
+ return ((KFileListViewItem*) item->itemAbove())->fileInfo();
+ else
+ return 0L;
+ }
+ else
+ return firstFileItem();
+}
+
+void KFileDetailView::keyPressEvent( TQKeyEvent *e )
+{
+ KListView::keyPressEvent( e );
+
+ if ( e->key() == Key_Return || e->key() == Key_Enter ) {
+ if ( e->state() & ControlButton )
+ e->ignore();
+ else
+ e->accept();
+ }
+}
+
+//
+// mimetype determination on demand
+//
+void KFileDetailView::mimeTypeDeterminationFinished()
+{
+ // anything to do?
+}
+
+void KFileDetailView::determineIcon( KFileListViewItem *item )
+{
+ (void) item->fileInfo()->determineMimeType();
+ updateView( item->fileInfo() );
+}
+
+void KFileDetailView::listingCompleted()
+{
+ m_resolver->start();
+}
+
+TQDragObject *KFileDetailView::dragObject()
+{
+ // create a list of the URL:s that we want to drag
+ KURL::List urls;
+ KFileItemListIterator it( * KFileView::selectedItems() );
+ for ( ; it.current(); ++it ){
+ urls.append( (*it)->url() );
+ }
+ TQPixmap pixmap;
+ if( urls.count() > 1 )
+ pixmap = DesktopIcon( "tdemultiple", KIcon::SizeSmall );
+ if( pixmap.isNull() )
+ pixmap = currentFileItem()->pixmap( KIcon::SizeSmall );
+
+ TQPoint hotspot;
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ TQDragObject* myDragObject = new KURLDrag( urls, widget() );
+ myDragObject->setPixmap( pixmap, hotspot );
+ return myDragObject;
+}
+
+void KFileDetailView::slotAutoOpen()
+{
+ d->autoOpenTimer.stop();
+ if( !d->dropItem )
+ return;
+
+ KFileItem *fileItem = d->dropItem->fileInfo();
+ if (!fileItem)
+ return;
+
+ if( fileItem->isFile() )
+ return;
+
+ if ( fileItem->isDir() || fileItem->isLink())
+ sig->activate( fileItem );
+}
+
+bool KFileDetailView::acceptDrag(TQDropEvent* e) const
+{
+ return KURLDrag::canDecode( e ) &&
+ (e->source()!= const_cast<KFileDetailView*>(this)) &&
+ ( e->action() == TQDropEvent::Copy
+ || e->action() == TQDropEvent::Move
+ || e->action() == TQDropEvent::Link );
+}
+
+void KFileDetailView::contentsDragEnterEvent( TQDragEnterEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileDetailView::contentsDragMoveEvent( TQDragMoveEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ if (d->dropItem != item)
+ {
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileDetailView::contentsDragLeaveEvent( TQDragLeaveEvent * )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+}
+
+void KFileDetailView::contentsDropEvent( TQDropEvent *e )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
+ KFileItem * fileItem = 0;
+ if (item)
+ fileItem = item->fileInfo();
+
+ emit dropped(e, fileItem);
+
+ KURL::List urls;
+ if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
+ {
+ emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
+ sig->dropURLs(fileItem, e, urls);
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////
+
+
+void KFileListViewItem::init()
+{
+ KFileListViewItem::setPixmap( COL_NAME, inf->pixmap(KIcon::SizeSmall));
+
+ setText( COL_NAME, inf->text() );
+ setText( COL_SIZE, TDEGlobal::locale()->formatNumber( inf->size(), 0));
+ setText( COL_DATE, inf->timeString() );
+ setText( COL_PERM, inf->permissionsString() );
+ setText( COL_OWNER, inf->user() );
+ setText( COL_GROUP, inf->group() );
+}
+
+
+void KFileDetailView::virtual_hook( int id, void* data )
+{ KListView::virtual_hook( id, data );
+ KFileView::virtual_hook( id, data ); }
+
+#include "tdefiledetailview.moc"
diff --git a/tdeio/tdefile/tdefiledetailview.h b/tdeio/tdefile/tdefiledetailview.h
new file mode 100644
index 000000000..114b10dec
--- /dev/null
+++ b/tdeio/tdefile/tdefiledetailview.h
@@ -0,0 +1,219 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@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 KFILEDETAILVIEW_H
+#define KFILEDETAILVIEW_H
+
+class KFileItem;
+class TQWidget;
+class TQKeyEvent;
+
+#include <klistview.h>
+#include <kmimetyperesolver.h>
+
+#include "tdefileview.h"
+
+/**
+ * An item for the listiew, that has a reference to its corresponding
+ * KFileItem.
+ */
+class TDEIO_EXPORT KFileListViewItem : public KListViewItem
+{
+public:
+ KFileListViewItem( TQListView *parent, const TQString &text,
+ const TQPixmap &icon, KFileItem *fi )
+ : KListViewItem( parent, text ), inf( fi ) {
+ setPixmap( 0, icon );
+ setText( 0, text );
+ }
+
+ /**
+ * @since 3.1
+ */
+ KFileListViewItem( TQListView *parent, KFileItem *fi )
+ : KListViewItem( parent ), inf( fi ) {
+ init();
+ }
+
+ KFileListViewItem( TQListView *parent, const TQString &text,
+ const TQPixmap &icon, KFileItem *fi,
+ TQListViewItem *after)
+ : KListViewItem( parent, after ), inf( fi ) {
+ setPixmap( 0, icon );
+ setText( 0, text );
+ }
+ ~KFileListViewItem() {
+ inf->removeExtraData( listView() );
+ }
+
+ /**
+ * @returns the corresponding KFileItem
+ */
+ KFileItem *fileInfo() const {
+ return inf;
+ }
+
+ virtual TQString key( int /*column*/, bool /*ascending*/ ) const {
+ return m_key;
+ }
+
+ void setKey( const TQString& key ) { m_key = key; }
+
+ TQRect rect() const
+ {
+ TQRect r = listView()->itemRect(this);
+ return TQRect( listView()->viewportToContents( r.topLeft() ),
+ TQSize( r.width(), r.height() ) );
+ }
+
+ /**
+ * @since 3.1
+ */
+ void init();
+
+private:
+ KFileItem *inf;
+ TQString m_key;
+
+private:
+ class KFileListViewItemPrivate;
+ KFileListViewItemPrivate *d;
+
+};
+
+/**
+ * A list-view capable of showing KFileItem'. Used in the filedialog
+ * for example. Most of the documentation is in KFileView class.
+ *
+ * @see KDirOperator
+ * @see KCombiView
+ * @see KFileIconView
+ */
+class TDEIO_EXPORT KFileDetailView : public KListView, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFileDetailView(TQWidget *parent, const char *name);
+ virtual ~KFileDetailView();
+
+ virtual TQWidget *widget() { return this; }
+ virtual void clearView();
+ virtual void setAutoUpdate( bool ) {} // ### unused. remove in KDE4
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem( const KFileItem *);
+ virtual void listingCompleted();
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected(const KFileItem *i) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void insertItem( KFileItem *i );
+
+ // implemented to get noticed about sorting changes (for sortingIndicator)
+ virtual void setSorting( TQDir::SortSpec );
+
+ void ensureItemVisible( const KFileItem * );
+
+ // for KMimeTypeResolver
+ void mimeTypeDeterminationFinished();
+ void determineIcon( KFileListViewItem *item );
+ TQScrollView *scrollWidget() const { return (TQScrollView*) this; }
+
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null);
+
+signals:
+ /**
+ * The user dropped something.
+ * @p fileItem points to the item dropped on or can be 0 if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(TQDropEvent *event, KFileItem *fileItem);
+ /**
+ * The user dropped the URLs @p urls.
+ * @p url points to the item dropped on or can be empty if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(TQDropEvent *event, const KURL::List &urls, const KURL &url);
+
+protected:
+ virtual void keyPressEvent( TQKeyEvent * );
+
+ // DND support
+ virtual TQDragObject *dragObject();
+ virtual void contentsDragEnterEvent( TQDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( TQDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( TQDragLeaveEvent *e );
+ virtual void contentsDropEvent( TQDropEvent *ev );
+ virtual bool acceptDrag(TQDropEvent* e ) const;
+
+ int m_sortingCol;
+
+protected slots:
+ void slotSelectionChanged();
+
+private slots:
+ void slotSortingChanged( int );
+ void selected( TQListViewItem *item );
+ void slotActivate( TQListViewItem *item );
+ void highlighted( TQListViewItem *item );
+ void slotActivateMenu ( TQListViewItem *item, const TQPoint& pos );
+ void slotAutoOpen();
+
+private:
+ virtual void insertItem(TQListViewItem *i) { KListView::insertItem(i); }
+ virtual void setSorting(int i, bool b) { KListView::setSorting(i, b); }
+ virtual void setSelected(TQListViewItem *i, bool b) { KListView::setSelected(i, b); }
+
+ inline KFileListViewItem * viewItem( const KFileItem *item ) const {
+ if ( item )
+ return (KFileListViewItem *) item->extraData( this );
+ return 0L;
+ }
+
+ void setSortingKey( KFileListViewItem *item, const KFileItem *i );
+
+
+ bool m_blockSortingSignal;
+ KMimeTypeResolver<KFileListViewItem,KFileDetailView> *m_resolver;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileDetailViewPrivate;
+ KFileDetailViewPrivate *d;
+};
+
+#endif // KFILEDETAILVIEW_H
diff --git a/tdeio/tdefile/tdefiledialog.cpp b/tdeio/tdefile/tdefiledialog.cpp
new file mode 100644
index 000000000..4fb399716
--- /dev/null
+++ b/tdeio/tdefile/tdefiledialog.cpp
@@ -0,0 +1,2380 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2003 Clarence Dang <dang@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 "tdefiledialog.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <tqptrcollection.h>
+#include <tqcheckbox.h>
+#include <tqcombobox.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <tqptrlist.h>
+#include <tqpixmap.h>
+#include <tqtextcodec.h>
+#include <tqtooltip.h>
+#include <tqtimer.h>
+#include <tqwhatsthis.h>
+#include <tqfiledialog.h>
+
+#include <kaccel.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kcharsets.h>
+#include <kcmdlineargs.h>
+#include <kcompletionbox.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kimageio.h>
+#include <tdeio/job.h>
+#include <tdeio/netaccess.h>
+#include <tdeio/scheduler.h>
+#include <tdeio/kservicetypefactory.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <kpushbutton.h>
+#include <krecentdirs.h>
+#include <kshell.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+#include <kstaticdeleter.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kurl.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+#include <kuser.h>
+
+#include "config-tdefile.h"
+#include "kpreviewwidgetbase.h"
+
+#include <kdirselectdialog.h>
+#include <tdefileview.h>
+#include <krecentdocument.h>
+#include <tdefilefiltercombo.h>
+#include <kdiroperator.h>
+#include <kimagefilepreview.h>
+
+#include <tdefilespeedbar.h>
+#include <tdefilebookmarkhandler.h>
+
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+#endif
+
+enum Buttons { HOTLIST_BUTTON,
+ PATH_COMBO, CONFIGURE_BUTTON };
+
+template class TQPtrList<TDEIO::StatJob>;
+
+namespace {
+ static void silenceQToolBar(TQtMsgType, const char *)
+ {
+ }
+}
+
+struct KFileDialogPrivate
+{
+ // the last selected url
+ KURL url;
+
+ // the selected filenames in multiselection mode -- FIXME
+ TQString filenames;
+
+ // the name of the filename set by setSelection
+ TQString selection;
+
+ // now following all kind of widgets, that I need to rebuild
+ // the geometry management
+ TQBoxLayout *boxLayout;
+ TQWidget *mainWidget;
+
+ TQLabel *locationLabel;
+
+ // @deprecated remove in KDE4
+ TQLabel *filterLabel;
+ KURLComboBox *pathCombo;
+ KPushButton *okButton, *cancelButton;
+ KFileSpeedBar *urlBar;
+ TQHBoxLayout *urlBarLayout;
+ TQWidget *customWidget;
+
+ // Automatically Select Extension stuff
+ TQCheckBox *autoSelectExtCheckBox;
+ bool autoSelectExtChecked; // whether or not the _user_ has checked the above box
+ TQString extension; // current extension for this filter
+
+ TQPtrList<TDEIO::StatJob> statJobs;
+
+ KURL::List urlList; //the list of selected urls
+
+ TQStringList mimetypes; //the list of possible mimetypes to save as
+
+ // indicates if the location edit should be kept or cleared when changing
+ // directories
+ bool keepLocation :1;
+
+ // the KDirOperators view is set in KFileDialog::show(), so to avoid
+ // setting it again and again, we have this nice little boolean :)
+ bool hasView :1;
+
+ bool hasDefaultFilter :1; // necessary for the operationMode
+ KFileDialog::OperationMode operationMode;
+
+ // The file class used for KRecentDirs
+ TQString fileClass;
+
+ KFileBookmarkHandler *bookmarkHandler;
+
+ // the ID of the path drop down so subclasses can place their custom widgets properly
+ int m_pathComboIndex;
+};
+
+KURL *KFileDialog::lastDirectory; // to set the start path
+
+static KStaticDeleter<KURL> ldd;
+
+KFileDialog::KFileDialog(const TQString& startDir, const TQString& filter,
+ TQWidget *parent, const char* name, bool modal)
+ : KDialogBase( parent, name, modal, TQString::null, 0 )
+{
+ init( startDir, filter, 0 );
+}
+
+KFileDialog::KFileDialog(const TQString& startDir, const TQString& filter,
+ TQWidget *parent, const char* name, bool modal, TQWidget* widget)
+ : KDialogBase( parent, name, modal, TQString::null, 0 )
+{
+ init( startDir, filter, widget );
+}
+
+
+KFileDialog::~KFileDialog()
+{
+ hide();
+
+ TDEConfig *config = TDEGlobal::config();
+
+ if (d->urlBar)
+ d->urlBar->save( config );
+
+ config->sync();
+
+ delete d->bookmarkHandler; // Should be deleted before ops!
+ delete ops;
+ delete d;
+}
+
+void KFileDialog::setLocationLabel(const TQString& text)
+{
+ d->locationLabel->setText(text);
+}
+
+void KFileDialog::setFilter(const TQString& filter)
+{
+ int pos = filter.find('/');
+
+ // Check for an un-escaped '/', if found
+ // interpret as a MIME filter.
+
+ if (pos > 0 && filter[pos - 1] != '\\') {
+ TQStringList filters = TQStringList::split( " ", filter );
+ setMimeFilter( filters );
+ return;
+ }
+
+ // Strip the escape characters from
+ // escaped '/' characters.
+
+ TQString copy (filter);
+ for (pos = 0; (pos = copy.find("\\/", pos)) != -1; ++pos)
+ copy.remove(pos, 1);
+
+ ops->clearFilter();
+ filterWidget->setFilter(copy);
+ ops->setNameFilter(filterWidget->currentFilter());
+ d->hasDefaultFilter = false;
+ filterWidget->setEditable( true );
+
+ updateAutoSelectExtension ();
+}
+
+TQString KFileDialog::currentFilter() const
+{
+ return filterWidget->currentFilter();
+}
+
+// deprecated
+void KFileDialog::setFilterMimeType(const TQString &label,
+ const KMimeType::List &types,
+ const KMimeType::Ptr &defaultType)
+{
+ d->mimetypes.clear();
+ d->filterLabel->setText(label);
+
+ KMimeType::List::ConstIterator it;
+ for( it = types.begin(); it != types.end(); ++it)
+ d->mimetypes.append( (*it)->name() );
+
+ setMimeFilter( d->mimetypes, defaultType->name() );
+}
+
+void KFileDialog::setMimeFilter( const TQStringList& mimeTypes,
+ const TQString& defaultType )
+{
+ d->mimetypes = mimeTypes;
+ filterWidget->setMimeFilter( mimeTypes, defaultType );
+
+ TQStringList types = TQStringList::split(" ", filterWidget->currentFilter());
+ types.append( TQString::fromLatin1( "inode/directory" ));
+ ops->clearFilter();
+ ops->setMimeFilter( types );
+ d->hasDefaultFilter = !defaultType.isEmpty();
+ filterWidget->setEditable( !d->hasDefaultFilter ||
+ d->operationMode != Saving );
+
+ updateAutoSelectExtension ();
+}
+
+void KFileDialog::clearFilter()
+{
+ d->mimetypes.clear();
+ filterWidget->setFilter( TQString::null );
+ ops->clearFilter();
+ d->hasDefaultFilter = false;
+ filterWidget->setEditable( true );
+
+ updateAutoSelectExtension ();
+}
+
+TQString KFileDialog::currentMimeFilter() const
+{
+ int i = filterWidget->currentItem();
+ if (filterWidget->showsAllTypes())
+ i--;
+
+ if ((i >= 0) && (i < (int) d->mimetypes.count()))
+ return d->mimetypes[i];
+ return TQString::null; // The "all types" item has no mimetype
+}
+
+KMimeType::Ptr KFileDialog::currentFilterMimeType()
+{
+ return KMimeType::mimeType( currentMimeFilter() );
+}
+
+void KFileDialog::setPreviewWidget(const TQWidget *w) {
+ ops->setPreviewWidget(w);
+ ops->clearHistory();
+ d->hasView = true;
+}
+
+void KFileDialog::setPreviewWidget(const KPreviewWidgetBase *w) {
+ ops->setPreviewWidget(w);
+ ops->clearHistory();
+ d->hasView = true;
+}
+
+KURL KFileDialog::getCompleteURL(const TQString &_url)
+{
+ TQString url = KShell::tildeExpand(_url);
+ KURL u;
+
+ if ( KURL::isRelativeURL(url) ) // only a full URL isn't relative. Even /path is.
+ {
+ if (!url.isEmpty() && !TQDir::isRelativePath(url) ) // absolute path
+ u.setPath( url );
+ else
+ {
+ u = ops->url();
+ u.addPath( url ); // works for filenames and relative paths
+ u.cleanPath(); // fix "dir/.."
+ }
+ }
+ else // complete URL
+ u = url;
+
+ return u;
+}
+
+// FIXME: check for "existing" flag here?
+void KFileDialog::slotOk()
+{
+ kdDebug(tdefile_area) << "slotOK\n";
+
+ // a list of all selected files/directories (if any)
+ // can only be used if the user didn't type any filenames/urls himself
+ const KFileItemList *items = ops->selectedItems();
+
+ if ( (mode() & KFile::Directory) != KFile::Directory ) {
+ if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) {
+ if ( !items || items->isEmpty() )
+ {
+ TQString msg;
+ if ( d->operationMode == Saving )
+ msg = i18n("Please specify the filename to save to.");
+ else
+ msg = i18n("Please select the file to open.");
+ KMessageBox::information(this, msg);
+ return;
+ }
+
+ // weird case: the location edit is empty, but there are
+ // highlighted files
+ else {
+
+ bool multi = (mode() & KFile::Files) != 0;
+ KFileItemListIterator it( *items );
+ TQString endQuote = TQString::fromLatin1("\" ");
+ TQString name, files;
+ while ( it.current() ) {
+ name = (*it)->name();
+ if ( multi ) {
+ name.prepend( '"' );
+ name.append( endQuote );
+ }
+
+ files.append( name );
+ ++it;
+ }
+ setLocationText( files );
+ return;
+ }
+ }
+ }
+
+ bool dirOnly = ops->dirOnlyMode();
+
+ // we can use our tdefileitems, no need to parse anything
+ if ( items && !locationEdit->lineEdit()->edited() &&
+ !(items->isEmpty() && !dirOnly) ) {
+
+ d->urlList.clear();
+ d->filenames = TQString::null;
+
+ if ( dirOnly ) {
+ d->url = ops->url();
+ }
+ else {
+ if ( !(mode() & KFile::Files) ) {// single selection
+ d->url = items->getFirst()->url();
+ }
+
+ else { // multi (dirs and/or files)
+ d->url = ops->url();
+ KFileItemListIterator it( *items );
+ while ( it.current() ) {
+ d->urlList.append( (*it)->url() );
+ ++it;
+ }
+ }
+ }
+
+ KURL url = TDEIO::NetAccess::mostLocalURL(d->url,topLevelWidget());
+ if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly &&
+ !url.isLocalFile() ) {
+// ### after message freeze, add message for directories!
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ return;
+ }
+
+ d->url = url;
+ accept();
+ return;
+ }
+
+
+ KURL selectedURL;
+
+ if ( (mode() & KFile::Files) == KFile::Files ) {// multiselection mode
+ TQString locationText = locationEdit->currentText();
+ if ( locationText.contains( '/' )) {
+ // relative path? -> prepend the current directory
+ KURL u( ops->url(), KShell::tildeExpand(locationText));
+ if ( u.isValid() )
+ selectedURL = u;
+ else
+ selectedURL = ops->url();
+ }
+ else // simple filename -> just use the current URL
+ selectedURL = ops->url();
+ }
+
+ else {
+ selectedURL = getCompleteURL(locationEdit->currentText());
+
+ // appendExtension() may change selectedURL
+ appendExtension (selectedURL);
+ }
+
+ if ( !selectedURL.isValid() ) {
+ KMessageBox::sorry( d->mainWidget, i18n("%1\ndoes not appear to be a valid URL.\n").arg(d->url.url()), i18n("Invalid URL") );
+ return;
+ }
+
+ KURL url = TDEIO::NetAccess::mostLocalURL(selectedURL,topLevelWidget());
+ if ( (mode() & KFile::LocalOnly) == KFile::LocalOnly &&
+ !url.isLocalFile() ) {
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ return;
+ }
+
+ d->url = url;
+
+ // d->url is a correct URL now
+
+ if ( (mode() & KFile::Directory) == KFile::Directory ) {
+ kdDebug(tdefile_area) << "Directory" << endl;
+ bool done = true;
+ if ( d->url.isLocalFile() ) {
+ if ( locationEdit->currentText().stripWhiteSpace().isEmpty() ) {
+ TQFileInfo info( d->url.path() );
+ if ( info.isDir() ) {
+ d->filenames = TQString::null;
+ d->urlList.clear();
+ d->urlList.append( d->url );
+ accept();
+ }
+ else if (!info.exists() && (mode() & KFile::File) != KFile::File) {
+ // directory doesn't exist, create and enter it
+ if ( ops->mkdir( d->url.url(), true ))
+ return;
+ else
+ accept();
+ }
+ else { // d->url is not a directory,
+ // maybe we are in File(s) | Directory mode
+ if ( (mode() & KFile::File) == KFile::File ||
+ (mode() & KFile::Files) == KFile::Files )
+ done = false;
+ }
+ }
+ else // Directory mode, with file[s]/dir[s] selected
+ {
+ if ( mode() & KFile::ExistingOnly )
+ {
+ if ( ops->dirOnlyMode() )
+ {
+ KURL fullURL(d->url, locationEdit->currentText());
+ if ( TQFile::exists( fullURL.path() ) )
+ {
+ d->url = fullURL;
+ d->filenames = TQString::null;
+ d->urlList.clear();
+ accept();
+ return;
+ }
+ else // doesn't exist -> reject
+ return;
+ }
+ }
+
+ d->filenames = locationEdit->currentText();
+ accept(); // what can we do?
+ }
+
+ }
+ else { // FIXME: remote directory, should we allow that?
+// tqDebug( "**** Selected remote directory: %s", d->url.url().latin1());
+ d->filenames = TQString::null;
+ d->urlList.clear();
+ d->urlList.append( d->url );
+
+ if ( mode() & KFile::ExistingOnly )
+ done = false;
+ else
+ accept();
+ }
+
+ if ( done )
+ return;
+ }
+
+ if (!kapp->authorizeURLAction("open", KURL(), d->url))
+ {
+ TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, d->url.prettyURL());
+ KMessageBox::error( d->mainWidget, msg);
+ return;
+ }
+
+ TDEIO::StatJob *job = 0L;
+ d->statJobs.clear();
+ d->filenames = KShell::tildeExpand(locationEdit->currentText());
+
+ if ( (mode() & KFile::Files) == KFile::Files &&
+ !locationEdit->currentText().contains( '/' )) {
+ kdDebug(tdefile_area) << "Files\n";
+ KURL::List list = parseSelectedURLs();
+ for ( KURL::List::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ if (!kapp->authorizeURLAction("open", KURL(), *it))
+ {
+ TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, (*it).prettyURL());
+ KMessageBox::error( d->mainWidget, msg);
+ return;
+ }
+ }
+ for ( KURL::List::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ job = TDEIO::stat( *it, !(*it).isLocalFile() );
+ job->setWindow (topLevelWidget());
+ TDEIO::Scheduler::scheduleJob( job );
+ d->statJobs.append( job );
+ connect( job, TQT_SIGNAL( result(TDEIO::Job *) ),
+ TQT_SLOT( slotStatResult( TDEIO::Job *) ));
+ }
+ return;
+ }
+
+ job = TDEIO::stat(d->url,!d->url.isLocalFile());
+ job->setWindow (topLevelWidget());
+ d->statJobs.append( job );
+ connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotStatResult(TDEIO::Job*)));
+}
+
+
+static bool isDirectory (const TDEIO::UDSEntry &t)
+{
+ bool isDir = false;
+
+ for (TDEIO::UDSEntry::ConstIterator it = t.begin();
+ it != t.end();
+ it++)
+ {
+ if ((*it).m_uds == TDEIO::UDS_FILE_TYPE)
+ {
+ isDir = S_ISDIR ((mode_t) ((*it).m_long));
+ break;
+ }
+ }
+
+ return isDir;
+}
+
+// FIXME : count all errors and show messagebox when d->statJobs.count() == 0
+// in case of an error, we cancel the whole operation (clear d->statJobs and
+// don't call accept)
+void KFileDialog::slotStatResult(TDEIO::Job* job)
+{
+ kdDebug(tdefile_area) << "slotStatResult" << endl;
+ TDEIO::StatJob *sJob = static_cast<TDEIO::StatJob *>( job );
+
+ if ( !d->statJobs.removeRef( sJob ) ) {
+ return;
+ }
+
+ int count = d->statJobs.count();
+
+ // errors mean in general, the location is no directory ;/
+ // Can we be sure that it is exististant at all? (pfeiffer)
+ if (sJob->error() && count == 0 && !ops->dirOnlyMode())
+ {
+ accept();
+ return;
+ }
+
+ TDEIO::UDSEntry t = sJob->statResult();
+ if (isDirectory (t))
+ {
+ if ( ops->dirOnlyMode() )
+ {
+ d->filenames = TQString::null;
+ d->urlList.clear();
+ accept();
+ }
+ else // in File[s] mode, directory means error -> cd into it
+ {
+ if ( count == 0 ) {
+ locationEdit->clearEdit();
+ locationEdit->lineEdit()->setEdited( false );
+ setURL( sJob->url() );
+ }
+ }
+ d->statJobs.clear();
+ return;
+ }
+ else if ( ops->dirOnlyMode() )
+ {
+ return; // ### error message?
+ }
+
+ kdDebug(tdefile_area) << "filename " << sJob->url().url() << endl;
+
+ if ( count == 0 )
+ accept();
+}
+
+void KFileDialog::accept()
+{
+ setResult( TQDialog::Accepted ); // parseSelectedURLs() checks that
+
+ *lastDirectory = ops->url();
+ if (!d->fileClass.isEmpty())
+ KRecentDirs::add(d->fileClass, ops->url().url());
+
+ // clear the topmost item, we insert it as full path later on as item 1
+ locationEdit->changeItem( TQString::null, 0 );
+
+ KURL::List list = selectedURLs();
+ TQValueListConstIterator<KURL> it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ const KURL& url = *it;
+ // we strip the last slash (-1) because KURLComboBox does that as well
+ // when operating in file-mode. If we wouldn't , dupe-finding wouldn't
+ // work.
+ TQString file = url.isLocalFile() ? url.path(-1) : url.prettyURL(-1);
+
+ // remove dupes
+ for ( int i = 1; i < locationEdit->count(); i++ ) {
+ if ( locationEdit->text( i ) == file ) {
+ locationEdit->removeItem( i-- );
+ break;
+ }
+ }
+ locationEdit->insertItem( file, 1 );
+ }
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setForceGlobal( true );
+ writeConfig( config, ConfigGroup );
+ config->setForceGlobal( false );
+
+ saveRecentFiles( config );
+ config->sync();
+
+ KDialogBase::accept();
+
+ addToRecentDocuments();
+
+ if ( (mode() & KFile::Files) != KFile::Files ) // single selection
+ emit fileSelected(d->url.url());
+
+ ops->close();
+ emit okClicked();
+}
+
+
+void KFileDialog::fileHighlighted(const KFileItem *i)
+{
+ if (i && i->isDir())
+ return;
+
+
+ if ( (ops->mode() & KFile::Files) != KFile::Files ) {
+ if ( !i )
+ return;
+
+ d->url = i->url();
+
+ if ( !locationEdit->hasFocus() ) { // don't disturb while editing
+ setLocationText( i->name() );
+ }
+ emit fileHighlighted(d->url.url());
+ }
+
+ else {
+ multiSelectionChanged();
+ emit selectionChanged();
+ }
+}
+
+void KFileDialog::fileSelected(const KFileItem *i)
+{
+ if (i && i->isDir())
+ return;
+
+ if ( (ops->mode() & KFile::Files) != KFile::Files ) {
+ if ( !i )
+ return;
+
+ d->url = i->url();
+ setLocationText( i->name() );
+ }
+ else {
+ multiSelectionChanged();
+ emit selectionChanged();
+ }
+ slotOk();
+}
+
+
+// I know it's slow to always iterate thru the whole filelist
+// (ops->selectedItems()), but what can we do?
+void KFileDialog::multiSelectionChanged()
+{
+ if ( locationEdit->hasFocus() ) // don't disturb
+ return;
+
+ locationEdit->lineEdit()->setEdited( false );
+ KFileItem *item;
+ const KFileItemList *list = ops->selectedItems();
+ if ( !list ) {
+ locationEdit->clearEdit();
+ return;
+ }
+
+ static const TQString &begin = TDEGlobal::staticQString(" \"");
+ KFileItemListIterator it ( *list );
+ TQString text;
+ while ( (item = it.current()) ) {
+ text.append( begin ).append( item->name() ).append( '\"' );
+ ++it;
+ }
+
+ setLocationText( text.stripWhiteSpace() );
+}
+
+void KFileDialog::setLocationText( const TQString& text )
+{
+ // setCurrentItem() will cause textChanged() being emitted,
+ // so slotLocationChanged() will be called. Make sure we don't clear
+ // the KDirOperator's view-selection in there
+ disconnect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ),
+ this, TQT_SLOT( slotLocationChanged( const TQString& ) ) );
+ locationEdit->setCurrentItem( 0 );
+ connect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ),
+ TQT_SLOT( slotLocationChanged( const TQString& )) );
+ locationEdit->setEditText( text );
+
+ // don't change selection when user has clicked on an item
+ if ( d->operationMode == Saving && !locationEdit->isVisible())
+ setNonExtSelection();
+}
+
+static const char autocompletionWhatsThisText[] = I18N_NOOP("<p>While typing in the text area, you may be presented "
+ "with possible matches. "
+ "This feature can be controlled by clicking with the right mouse button "
+ "and selecting a preferred mode from the <b>Text Completion</b> menu.") "</qt>";
+void KFileDialog::updateLocationWhatsThis (void)
+{
+ TQString whatsThisText;
+ if (d->operationMode == KFileDialog::Saving)
+ {
+ whatsThisText = "<qt>" + i18n("This is the name to save the file as.") +
+ i18n (autocompletionWhatsThisText);
+ }
+ else if (ops->mode() & KFile::Files)
+ {
+ whatsThisText = "<qt>" + i18n("This is the list of files to open. More than "
+ "one file can be specified by listing several "
+ "files, separated by spaces.") +
+ i18n (autocompletionWhatsThisText);
+ }
+ else
+ {
+ whatsThisText = "<qt>" + i18n("This is the name of the file to open.") +
+ i18n (autocompletionWhatsThisText);
+ }
+
+ TQWhatsThis::add(d->locationLabel, whatsThisText);
+ TQWhatsThis::add(locationEdit, whatsThisText);
+}
+
+void KFileDialog::init(const TQString& startDir, const TQString& filter, TQWidget* widget)
+{
+ initStatic();
+ d = new KFileDialogPrivate();
+
+ d->boxLayout = 0;
+ d->keepLocation = false;
+ d->operationMode = Opening;
+ d->bookmarkHandler = 0;
+ d->hasDefaultFilter = false;
+ d->hasView = false;
+ d->mainWidget = new TQWidget( this, "KFileDialog::mainWidget");
+ setMainWidget( d->mainWidget );
+ d->okButton = new KPushButton( KStdGuiItem::ok(), d->mainWidget );
+ d->okButton->setDefault( true );
+ d->cancelButton = new KPushButton(KStdGuiItem::cancel(), d->mainWidget);
+ connect( d->okButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOk() ));
+ connect( d->cancelButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotCancel() ));
+ d->customWidget = widget;
+ d->autoSelectExtCheckBox = 0; // delayed loading
+ d->autoSelectExtChecked = false;
+ d->urlBar = 0; // delayed loading
+
+ TQtMsgHandler oldHandler = tqInstallMsgHandler( silenceQToolBar );
+ toolbar = new KToolBar( d->mainWidget, "KFileDialog::toolbar", true);
+ toolbar->setFlat(true);
+ tqInstallMsgHandler( oldHandler );
+
+ d->pathCombo = new KURLComboBox( KURLComboBox::Directories, true,
+ toolbar, "path combo" );
+ TQToolTip::add( d->pathCombo, i18n("Current location") );
+ TQWhatsThis::add( d->pathCombo, "<qt>" + i18n("This is the currently listed location. "
+ "The drop-down list also lists commonly used locations. "
+ "This includes standard locations, such as your home folder, as well as "
+ "locations that have been visited recently.") + i18n (autocompletionWhatsThisText));
+
+ KURL u;
+ u.setPath( TQDir::rootDirPath() );
+ TQString text = i18n("Root Folder: %1").arg( u.path() );
+ d->pathCombo->addDefaultURL( u,
+ KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ u.setPath( TQDir::homeDirPath() );
+ text = i18n("Home Folder: %1").arg( u.path( +1 ) );
+ d->pathCombo->addDefaultURL( u, KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ KURL docPath;
+ docPath.setPath( TDEGlobalSettings::documentPath() );
+ if ( (u.path(+1) != docPath.path(+1)) &&
+ TQDir(docPath.path(+1)).exists() )
+ {
+ text = i18n("Documents: %1").arg( docPath.path( +1 ) );
+ d->pathCombo->addDefaultURL( docPath,
+ KMimeType::pixmapForURL( docPath, 0, KIcon::Small ),
+ text );
+ }
+
+ u.setPath( TDEGlobalSettings::desktopPath() );
+ text = i18n("Desktop: %1").arg( u.path( +1 ) );
+ d->pathCombo->addDefaultURL( u,
+ KMimeType::pixmapForURL( u, 0, KIcon::Small ),
+ text );
+
+ d->url = getStartURL( startDir, d->fileClass );
+ d->selection = d->url.url();
+
+ // If local, check it exists. If not, go up until it exists.
+ if ( d->url.isLocalFile() )
+ {
+ if ( !TQFile::exists( d->url.path() ) )
+ {
+ d->url = d->url.upURL();
+ TQDir dir( d->url.path() );
+ while ( !dir.exists() )
+ {
+ d->url = d->url.upURL();
+ dir.setPath( d->url.path() );
+ }
+ }
+ }
+
+ ops = new KDirOperator(d->url, d->mainWidget, "KFileDialog::ops");
+ ops->setOnlyDoubleClickSelectsFiles( true );
+ connect(ops, TQT_SIGNAL(urlEntered(const KURL&)),
+ TQT_SLOT(urlEntered(const KURL&)));
+ connect(ops, TQT_SIGNAL(fileHighlighted(const KFileItem *)),
+ TQT_SLOT(fileHighlighted(const KFileItem *)));
+ connect(ops, TQT_SIGNAL(fileSelected(const KFileItem *)),
+ TQT_SLOT(fileSelected(const KFileItem *)));
+ connect(ops, TQT_SIGNAL(finishedLoading()),
+ TQT_SLOT(slotLoadingFinished()));
+
+ ops->setupMenu(KDirOperator::SortActions |
+ KDirOperator::FileActions |
+ KDirOperator::ViewActions);
+ KActionCollection *coll = ops->actionCollection();
+
+ // plug nav items into the toolbar
+ coll->action( "up" )->plug( toolbar );
+ coll->action( "up" )->setWhatsThis(i18n("<qt>Click this button to enter the parent folder.<p>"
+ "For instance, if the current location is file:/home/%1 clicking this "
+ "button will take you to file:/home.</qt>").arg( KUser().loginName() ));
+ coll->action( "back" )->plug( toolbar );
+ coll->action( "back" )->setWhatsThis(i18n("Click this button to move backwards one step in the browsing history."));
+ coll->action( "forward" )->plug( toolbar );
+ coll->action( "forward" )->setWhatsThis(i18n("Click this button to move forward one step in the browsing history."));
+ coll->action( "reload" )->plug( toolbar );
+ coll->action( "reload" )->setWhatsThis(i18n("Click this button to reload the contents of the current location."));
+ coll->action( "mkdir" )->setShortcut(Key_F10);
+ coll->action( "mkdir" )->plug( toolbar );
+ coll->action( "mkdir" )->setWhatsThis(i18n("Click this button to create a new folder."));
+
+ KToggleAction *showSidebarAction =
+ new KToggleAction(i18n("Show Quick Access Navigation Panel"), Key_F9, coll,"toggleSpeedbar");
+ showSidebarAction->setCheckedState(i18n("Hide Quick Access Navigation Panel"));
+ connect( showSidebarAction, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( toggleSpeedbar( bool )) );
+
+ KToggleAction *showBookmarksAction =
+ new KToggleAction(i18n("Show Bookmarks"), 0, coll, "toggleBookmarks");
+ showBookmarksAction->setCheckedState(i18n("Hide Bookmarks"));
+ connect( showBookmarksAction, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( toggleBookmarks( bool )) );
+
+ KActionMenu *menu = new KActionMenu( i18n("Configure"), "configure", TQT_TQOBJECT(this), "extra menu" );
+ menu->setWhatsThis(i18n("<qt>This is the configuration menu for the file dialog. "
+ "Various options can be accessed from this menu including: <ul>"
+ "<li>how files are sorted in the list</li>"
+ "<li>types of view, including icon and list</li>"
+ "<li>showing of hidden files</li>"
+ "<li>the Quick Access navigation panel</li>"
+ "<li>file previews</li>"
+ "<li>separating folders from files</li></ul></qt>"));
+ menu->insert( coll->action( "sorting menu" ));
+ menu->insert( coll->action( "separator" ));
+ coll->action( "short view" )->setShortcut(Key_F6);
+ menu->insert( coll->action( "short view" ));
+ coll->action( "detailed view" )->setShortcut(Key_F7);
+ menu->insert( coll->action( "detailed view" ));
+ menu->insert( coll->action( "separator" ));
+ coll->action( "show hidden" )->setShortcut(Key_F8);
+ menu->insert( coll->action( "show hidden" ));
+ menu->insert( showSidebarAction );
+ menu->insert( showBookmarksAction );
+ coll->action( "preview" )->setShortcut(Key_F11);
+ menu->insert( coll->action( "preview" ));
+ coll->action( "separate dirs" )->setShortcut(Key_F12);
+ menu->insert( coll->action( "separate dirs" ));
+
+ menu->setDelayed( false );
+ connect( menu->popupMenu(), TQT_SIGNAL( aboutToShow() ),
+ ops, TQT_SLOT( updateSelectionDependentActions() ));
+ menu->plug( toolbar );
+
+ //Insert a separator.
+ KToolBarSeparator* spacerWidget = new KToolBarSeparator(Qt::Horizontal, false /*no line*/,
+ toolbar);
+ d->m_pathComboIndex = toolbar->insertWidget(-1, -1, spacerWidget);
+ toolbar->insertWidget(PATH_COMBO, 0, d->pathCombo);
+
+
+ toolbar->setItemAutoSized (PATH_COMBO);
+ toolbar->setIconText(KToolBar::IconOnly);
+ toolbar->setBarPos(KToolBar::Top);
+ toolbar->setMovingEnabled(false);
+ toolbar->adjustSize();
+
+ KURLCompletion *pathCompletionObj = new KURLCompletion( KURLCompletion::DirCompletion );
+ d->pathCombo->setCompletionObject( pathCompletionObj );
+ d->pathCombo->setAutoDeleteCompletionObject( true );
+
+ connect( d->pathCombo, TQT_SIGNAL( urlActivated( const KURL& )),
+ this, TQT_SLOT( enterURL( const KURL& ) ));
+ connect( d->pathCombo, TQT_SIGNAL( returnPressed( const TQString& )),
+ this, TQT_SLOT( enterURL( const TQString& ) ));
+
+ TQString whatsThisText;
+
+ // the Location label/edit
+ d->locationLabel = new TQLabel(i18n("&Location:"), d->mainWidget);
+ locationEdit = new KURLComboBox(KURLComboBox::Files, true,
+ d->mainWidget, "LocationEdit");
+ locationEdit->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed));
+ connect( locationEdit, TQT_SIGNAL( textChanged( const TQString& ) ),
+ TQT_SLOT( slotLocationChanged( const TQString& )) );
+
+ updateLocationWhatsThis ();
+ d->locationLabel->setBuddy(locationEdit);
+
+ locationEdit->setFocus();
+ KURLCompletion *fileCompletionObj = new KURLCompletion( KURLCompletion::FileCompletion );
+ TQString dir = d->url.url(+1);
+ pathCompletionObj->setDir( dir );
+ fileCompletionObj->setDir( dir );
+ locationEdit->setCompletionObject( fileCompletionObj );
+ locationEdit->setAutoDeleteCompletionObject( true );
+ connect( fileCompletionObj, TQT_SIGNAL( match( const TQString& ) ),
+ TQT_SLOT( fileCompletion( const TQString& )) );
+
+ connect( locationEdit, TQT_SIGNAL( returnPressed() ),
+ this, TQT_SLOT( slotOk()));
+ connect(locationEdit, TQT_SIGNAL( activated( const TQString& )),
+ this, TQT_SLOT( locationActivated( const TQString& ) ));
+
+ // the Filter label/edit
+ whatsThisText = i18n("<qt>This is the filter to apply to the file list. "
+ "File names that do not match the filter will not be shown.<p>"
+ "You may select from one of the preset filters in the "
+ "drop down menu, or you may enter a custom filter "
+ "directly into the text area.<p>"
+ "Wildcards such as * and ? are allowed.</qt>");
+ d->filterLabel = new TQLabel(i18n("&Filter:"), d->mainWidget);
+ TQWhatsThis::add(d->filterLabel, whatsThisText);
+ filterWidget = new KFileFilterCombo(d->mainWidget,
+ "KFileDialog::filterwidget");
+ filterWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed));
+ TQWhatsThis::add(filterWidget, whatsThisText);
+ setFilter(filter);
+ d->filterLabel->setBuddy(filterWidget);
+ connect(filterWidget, TQT_SIGNAL(filterChanged()), TQT_SLOT(slotFilterChanged()));
+
+ // the Automatically Select Extension checkbox
+ // (the text, visibility etc. is set in updateAutoSelectExtension(), which is called by readConfig())
+ d->autoSelectExtCheckBox = new TQCheckBox (d->mainWidget);
+ connect(d->autoSelectExtCheckBox, TQT_SIGNAL(clicked()), TQT_SLOT(slotAutoSelectExtClicked()));
+
+ initGUI(); // activate GM
+
+ TDEConfig* config = TDEGlobal::config();
+ readRecentFiles( config );
+
+ adjustSize();
+
+ ops->setViewConfig( config, ConfigGroup );
+ readConfig( config, ConfigGroup );
+ setSelection(d->selection);
+}
+
+void KFileDialog::initSpeedbar()
+{
+ d->urlBar = new KFileSpeedBar( d->mainWidget, "url bar" );
+ connect( d->urlBar, TQT_SIGNAL( activated( const KURL& )),
+ TQT_SLOT( enterURL( const KURL& )) );
+
+ // need to set the current url of the urlbar manually (not via urlEntered()
+ // here, because the initial url of KDirOperator might be the same as the
+ // one that will be set later (and then urlEntered() won't be emitted).
+ // ### REMOVE THIS when KDirOperator's initial URL (in the c'tor) is gone.
+ d->urlBar->setCurrentItem( d->url );
+
+ d->urlBarLayout->insertWidget( 0, d->urlBar );
+}
+
+void KFileDialog::initGUI()
+{
+ delete d->boxLayout; // deletes all sub layouts
+
+ d->boxLayout = new TQVBoxLayout( d->mainWidget, 0, KDialog::spacingHint());
+ d->boxLayout->addWidget(toolbar, AlignTop);
+
+ d->urlBarLayout = new TQHBoxLayout( d->boxLayout ); // needed for the urlBar that may appear
+ TQVBoxLayout *vbox = new TQVBoxLayout( d->urlBarLayout );
+
+ vbox->addWidget(ops, 4);
+ vbox->addSpacing(3);
+
+ TQGridLayout* lafBox= new TQGridLayout(2, 3, KDialog::spacingHint());
+
+ lafBox->addWidget(d->locationLabel, 0, 0, Qt::AlignVCenter);
+ lafBox->addWidget(locationEdit, 0, 1, Qt::AlignVCenter);
+ lafBox->addWidget(d->okButton, 0, 2, Qt::AlignVCenter);
+
+ lafBox->addWidget(d->filterLabel, 1, 0, Qt::AlignVCenter);
+ lafBox->addWidget(filterWidget, 1, 1, Qt::AlignVCenter);
+ lafBox->addWidget(d->cancelButton, 1, 2, Qt::AlignVCenter);
+
+ lafBox->setColStretch(1, 4);
+
+ vbox->addLayout(TQT_TQLAYOUT(lafBox), 0);
+ vbox->addSpacing(3);
+
+ // add the Automatically Select Extension checkbox
+ vbox->addWidget (d->autoSelectExtCheckBox);
+ vbox->addSpacing (3);
+
+ setTabOrder(ops, d->autoSelectExtCheckBox);
+ setTabOrder (d->autoSelectExtCheckBox, locationEdit);
+ setTabOrder(locationEdit, filterWidget);
+ setTabOrder(filterWidget, d->okButton);
+ setTabOrder(d->okButton, d->cancelButton);
+ setTabOrder(d->cancelButton, d->pathCombo);
+ setTabOrder(d->pathCombo, ops);
+
+ // If a custom widget was specified...
+ if ( d->customWidget != 0 )
+ {
+ // ...add it to the dialog, below the filter list box.
+
+ // Change the parent so that this widget is a child of the main widget
+ d->customWidget->reparent( d->mainWidget, TQPoint() );
+
+ vbox->addWidget( d->customWidget );
+ vbox->addSpacing(3);
+
+ // FIXME: This should adjust the tab orders so that the custom widget
+ // comes after the Cancel button. The code appears to do this, but the result
+ // somehow screws up the tab order of the file path combo box. Not a major
+ // problem, but ideally the tab order with a custom widget should be
+ // the same as the order without one.
+ setTabOrder(d->cancelButton, d->customWidget);
+ setTabOrder(d->customWidget, d->pathCombo);
+ }
+ else
+ {
+ setTabOrder(d->cancelButton, d->pathCombo);
+ }
+
+ setTabOrder(d->pathCombo, ops);
+}
+
+void KFileDialog::slotFilterChanged()
+{
+ TQString filter = filterWidget->currentFilter();
+ ops->clearFilter();
+
+ if ( filter.find( '/' ) > -1 ) {
+ TQStringList types = TQStringList::split( " ", filter );
+ types.prepend( "inode/directory" );
+ ops->setMimeFilter( types );
+ }
+ else
+ ops->setNameFilter( filter );
+
+ ops->updateDir();
+
+ updateAutoSelectExtension ();
+
+ emit filterChanged( filter );
+}
+
+
+void KFileDialog::setURL(const KURL& url, bool clearforward)
+{
+ d->selection = TQString::null;
+ ops->setURL( url, clearforward);
+}
+
+// Protected
+void KFileDialog::urlEntered(const KURL& url)
+{
+ TQString filename = locationEdit->currentText();
+ d->selection = TQString::null;
+
+ if ( d->pathCombo->count() != 0 ) { // little hack
+ d->pathCombo->setURL( url );
+ }
+
+ if (url.protocol()=="beagle" && url.path()=="/") {
+ d->pathCombo->setEditText("beagle:/<"+i18n("search term")+">");
+ d->pathCombo->lineEdit()->setSelection(8,255);
+ d->pathCombo->setFocus();
+ }
+
+ locationEdit->blockSignals( true );
+ locationEdit->setCurrentItem( 0 );
+ if ( d->keepLocation )
+ locationEdit->setEditText( filename );
+
+ locationEdit->blockSignals( false );
+
+ TQString dir = url.url(+1);
+ static_cast<KURLCompletion*>( d->pathCombo->completionObject() )->setDir( dir );
+ static_cast<KURLCompletion*>( locationEdit->completionObject() )->setDir( dir );
+
+ if ( d->urlBar )
+ d->urlBar->setCurrentItem( url );
+}
+
+void KFileDialog::locationActivated( const TQString& url )
+{
+ // This guard prevents any URL _typed_ by the user from being interpreted
+ // twice (by returnPressed/slotOk and here, activated/locationActivated)
+ // after the user presses Enter. Without this, _both_ setSelection and
+ // slotOk would "u.addPath( url )" ...so instead we leave it up to just
+ // slotOk....
+ if (!locationEdit->lineEdit()->edited())
+ setSelection( url );
+}
+
+void KFileDialog::enterURL( const KURL& url)
+{
+ setURL( url );
+}
+
+void KFileDialog::enterURL( const TQString& url )
+{
+ setURL( KURL::fromPathOrURL( KURLCompletion::replacedPath( url, true, true )) );
+}
+
+void KFileDialog::toolbarCallback(int) // SLOT
+{
+ /*
+ * yes, nothing uses this anymore.
+ * it used to be used to show the configure dialog
+ */
+}
+
+
+void KFileDialog::setSelection(const TQString& url)
+{
+ kdDebug(tdefile_area) << "setSelection " << url << endl;
+
+ if (url.isEmpty()) {
+ d->selection = TQString::null;
+ return;
+ }
+
+ KURL u = getCompleteURL(url);
+ if (!u.isValid()) { // if it still is
+ kdWarning() << url << " is not a correct argument for setSelection!" << endl;
+ return;
+ }
+
+ if (!KProtocolInfo::supportsListing(u)) {
+ locationEdit->lineEdit()->setEdited( true );
+ return;
+ }
+
+ /* we strip the first / from the path to avoid file://usr which means
+ * / on host usr
+ */
+ KFileItem i(KFileItem::Unknown, KFileItem::Unknown, u, true );
+ // KFileItem i(u.path());
+ if ( i.isDir() && u.isLocalFile() && TQFile::exists( u.path() ) ) {
+ // trust isDir() only if the file is
+ // local (we cannot stat non-local urls) and if it exists!
+ // (as KFileItem does not check if the file exists or not
+ // -> the statbuffer is undefined -> isDir() is unreliable) (Simon)
+ setURL(u, true);
+ }
+ else {
+ TQString filename = u.url();
+ int sep = filename.findRev('/');
+ if (sep >= 0) { // there is a / in it
+ if ( KProtocolInfo::supportsListing( u )) {
+ KURL dir(u);
+ dir.setQuery( TQString::null );
+ dir.setFileName( TQString::null );
+ setURL(dir, true );
+ }
+
+ // filename must be decoded, or "name with space" would become
+ // "name%20with%20space", so we use KURL::fileName()
+ filename = u.fileName();
+ kdDebug(tdefile_area) << "filename " << filename << endl;
+ d->selection = filename;
+ setLocationText( filename );
+
+ // tell the line edit that it has been edited
+ // otherwise we won't know this was set by the user
+ // and it will be ignored if there has been an
+ // auto completion. this caused bugs where automcompletion
+ // would start, the user would pick something from the
+ // history and then hit Ok only to get the autocompleted
+ // selection. OOOPS.
+ locationEdit->lineEdit()->setEdited( true );
+ }
+
+ d->url = ops->url();
+ d->url.addPath(filename);
+ }
+}
+
+void KFileDialog::slotLoadingFinished()
+{
+ if ( !d->selection.isNull() )
+ ops->setCurrentItem( d->selection );
+}
+
+// ### remove in KDE4
+void KFileDialog::pathComboChanged( const TQString& )
+{
+}
+void KFileDialog::dirCompletion( const TQString& ) // SLOT
+{
+}
+void KFileDialog::fileCompletion( const TQString& match )
+{
+ if ( match.isEmpty() && ops->view() )
+ ops->view()->clearSelection();
+ else
+ ops->setCurrentItem( match );
+}
+
+void KFileDialog::slotLocationChanged( const TQString& text )
+{
+ if ( text.isEmpty() && ops->view() )
+ ops->view()->clearSelection();
+
+ updateFilter();
+}
+
+void KFileDialog::updateStatusLine(int /* dirs */, int /* files */)
+{
+ kdWarning() << "KFileDialog::updateStatusLine is deprecated! The status line no longer exists. Do not try and use it!" << endl;
+}
+
+TQString KFileDialog::getOpenFileName(const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent, const TQString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFile();
+}
+
+TQString KFileDialog::getOpenFileNameWId(const TQString& startDir,
+ const TQString& filter,
+ WId parent_id, const TQString& caption)
+{
+ TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id ));
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+#ifdef Q_WS_X11
+ if( parent == NULL && parent_id != 0 )
+ XSetTransientForHint( tqt_xdisplay(), dlg.winId(), parent_id );
+#else
+ // TODO
+#endif
+
+ dlg.setOperationMode( KFileDialog::Opening );
+
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFile();
+}
+
+TQStringList KFileDialog::getOpenFileNames(const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode(KFile::Files | KFile::LocalOnly);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedFiles();
+}
+
+KURL KFileDialog::getOpenURL(const TQString& startDir, const TQString& filter,
+ TQWidget *parent, const TQString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode( KFile::File );
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedURL();
+}
+
+KURL::List KFileDialog::getOpenURLs(const TQString& startDir,
+ const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ KFileDialog dlg(startDir, filter, parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+
+ dlg.setCaption(caption.isNull() ? i18n("Open") : caption);
+ dlg.setMode(KFile::Files);
+ dlg.ops->clearHistory();
+ dlg.exec();
+
+ return dlg.selectedURLs();
+}
+
+KURL KFileDialog::getExistingURL(const TQString& startDir,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ return KDirSelectDialog::selectDirectory(startDir, false, parent, caption);
+}
+
+TQString KFileDialog::getExistingDirectory(const TQString& startDir,
+ TQWidget *parent,
+ const TQString& caption)
+{
+#ifdef Q_WS_WIN
+ return TQFileDialog::getExistingDirectory(startDir, parent, "getExistingDirectory",
+ caption, true, true);
+#else
+ KURL url = KDirSelectDialog::selectDirectory(startDir, true, parent,
+ caption);
+ if ( url.isValid() )
+ return url.path();
+
+ return TQString::null;
+#endif
+}
+
+KURL KFileDialog::getImageOpenURL( const TQString& startDir, TQWidget *parent,
+ const TQString& caption)
+{
+ TQStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading );
+ KFileDialog dlg(startDir,
+ mimetypes.join(" "),
+ parent, "filedialog", true);
+ dlg.setOperationMode( Opening );
+ dlg.setCaption( caption.isNull() ? i18n("Open") : caption );
+ dlg.setMode( KFile::File );
+
+ KImageFilePreview *ip = new KImageFilePreview( &dlg );
+ dlg.setPreviewWidget( ip );
+ dlg.exec();
+
+ return dlg.selectedURL();
+}
+
+KURL KFileDialog::selectedURL() const
+{
+ if ( result() == TQDialog::Accepted )
+ return d->url;
+ else
+ return KURL();
+}
+
+KURL::List KFileDialog::selectedURLs() const
+{
+ KURL::List list;
+ if ( result() == TQDialog::Accepted ) {
+ if ( (ops->mode() & KFile::Files) == KFile::Files )
+ list = parseSelectedURLs();
+ else
+ list.append( d->url );
+ }
+ return list;
+}
+
+
+KURL::List& KFileDialog::parseSelectedURLs() const
+{
+ if ( d->filenames.isEmpty() ) {
+ return d->urlList;
+ }
+
+ d->urlList.clear();
+ if ( d->filenames.contains( '/' )) { // assume _one_ absolute filename
+ static const TQString &prot = TDEGlobal::staticQString(":/");
+ KURL u;
+ if ( d->filenames.find( prot ) != -1 )
+ u = d->filenames;
+ else
+ u.setPath( d->filenames );
+
+ if ( u.isValid() )
+ d->urlList.append( u );
+ else
+ KMessageBox::error( d->mainWidget,
+ i18n("The chosen filenames do not\n"
+ "appear to be valid."),
+ i18n("Invalid Filenames") );
+ }
+
+ else
+ d->urlList = tokenize( d->filenames );
+
+ d->filenames = TQString::null; // indicate that we parsed that one
+
+ return d->urlList;
+}
+
+
+// FIXME: current implementation drawback: a filename can't contain quotes
+KURL::List KFileDialog::tokenize( const TQString& line ) const
+{
+ KURL::List urls;
+ KURL u( ops->url() );
+ TQString name;
+
+ int count = line.contains( '"' );
+ if ( count == 0 ) { // no " " -> assume one single file
+ u.setFileName( line );
+ if ( u.isValid() )
+ urls.append( u );
+
+ return urls;
+ }
+
+ if ( (count % 2) == 1 ) { // odd number of " -> error
+ TQWidget *that = const_cast<KFileDialog *>(this);
+ KMessageBox::sorry(that, i18n("The requested filenames\n"
+ "%1\n"
+ "do not appear to be valid;\n"
+ "make sure every filename is enclosed in double quotes.").arg(line),
+ i18n("Filename Error"));
+ return urls;
+ }
+
+ int start = 0;
+ int index1 = -1, index2 = -1;
+ while ( true ) {
+ index1 = line.find( '"', start );
+ index2 = line.find( '"', index1 + 1 );
+
+ if ( index1 < 0 )
+ break;
+
+ // get everything between the " "
+ name = line.mid( index1 + 1, index2 - index1 - 1 );
+ u.setFileName( name );
+ if ( u.isValid() )
+ urls.append( u );
+
+ start = index2 + 1;
+ }
+ return urls;
+}
+
+
+TQString KFileDialog::selectedFile() const
+{
+ if ( result() == TQDialog::Accepted )
+ {
+ KURL url = TDEIO::NetAccess::mostLocalURL(d->url,topLevelWidget());
+ if (url.isLocalFile())
+ return url.path();
+ else {
+ KMessageBox::sorry( d->mainWidget,
+ i18n("You can only select local files."),
+ i18n("Remote Files Not Accepted") );
+ }
+ }
+ return TQString::null;
+}
+
+TQStringList KFileDialog::selectedFiles() const
+{
+ TQStringList list;
+ KURL url;
+
+ if ( result() == TQDialog::Accepted ) {
+ if ( (ops->mode() & KFile::Files) == KFile::Files ) {
+ KURL::List urls = parseSelectedURLs();
+ TQValueListConstIterator<KURL> it = urls.begin();
+ while ( it != urls.end() ) {
+ url = TDEIO::NetAccess::mostLocalURL(*it,topLevelWidget());
+ if ( url.isLocalFile() )
+ list.append( url.path() );
+ ++it;
+ }
+ }
+
+ else { // single-selection mode
+ if ( d->url.isLocalFile() )
+ list.append( d->url.path() );
+ }
+ }
+
+ return list;
+}
+
+KURL KFileDialog::baseURL() const
+{
+ return ops->url();
+}
+
+TQString KFileDialog::getSaveFileName(const TQString& dir, const TQString& filter,
+ TQWidget *parent,
+ const TQString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true);
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setOperationMode( Saving );
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+
+ dlg.exec();
+
+ TQString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ return filename;
+}
+
+TQString KFileDialog::getSaveFileNameWId(const TQString& dir, const TQString& filter,
+ WId parent_id,
+ const TQString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ TQWidget* parent = TQT_TQWIDGET(TQWidget::find( parent_id ));
+ KFileDialog dlg( specialDir ? dir : TQString::null, filter, parent, "filedialog", true);
+#ifdef Q_WS_X11
+ if( parent == NULL && parent_id != 0 )
+ XSetTransientForHint(tqt_xdisplay(), dlg.winId(), parent_id);
+#else
+ // TODO
+#endif
+
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setOperationMode( KFileDialog::Saving);
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+
+ dlg.exec();
+
+ TQString filename = dlg.selectedFile();
+ if (!filename.isEmpty())
+ KRecentDocument::add(filename);
+
+ return filename;
+}
+
+KURL KFileDialog::getSaveURL(const TQString& dir, const TQString& filter,
+ TQWidget *parent, const TQString& caption)
+{
+ bool specialDir = dir.at(0) == ':';
+ KFileDialog dlg(specialDir ? dir : TQString::null, filter, parent, "filedialog", true);
+ if ( !specialDir )
+ dlg.setSelection( dir ); // may also be a filename
+
+ dlg.setCaption(caption.isNull() ? i18n("Save As") : caption);
+ dlg.setOperationMode( Saving );
+
+ dlg.exec();
+
+ KURL url = dlg.selectedURL();
+ if (url.isValid())
+ KRecentDocument::add( url );
+
+ return url;
+}
+
+void KFileDialog::show()
+{
+ if ( !d->hasView ) { // delayed view-creation
+ ops->setView(KFile::Default);
+ ops->clearHistory();
+ d->hasView = true;
+ }
+
+ KDialogBase::show();
+}
+
+void KFileDialog::setMode( KFile::Mode m )
+{
+ ops->setMode(m);
+ if ( ops->dirOnlyMode() ) {
+ filterWidget->setDefaultFilter( i18n("*|All Folders") );
+ }
+ else {
+ filterWidget->setDefaultFilter( i18n("*|All Files") );
+ }
+
+ updateAutoSelectExtension ();
+}
+
+void KFileDialog::setMode( unsigned int m )
+{
+ setMode(static_cast<KFile::Mode>( m ));
+}
+
+KFile::Mode KFileDialog::mode() const
+{
+ return ops->mode();
+}
+
+
+void KFileDialog::readConfig( TDEConfig *kc, const TQString& group )
+{
+ if ( !kc )
+ return;
+
+ TQString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ ops->readConfig( kc, group );
+
+ KURLComboBox *combo = d->pathCombo;
+ combo->setURLs( kc->readPathListEntry( RecentURLs ), KURLComboBox::RemoveTop );
+ combo->setMaxItems( kc->readNumEntry( RecentURLsNumber,
+ DefaultRecentURLsNumber ) );
+ combo->setURL( ops->url() );
+ autoDirectoryFollowing = kc->readBoolEntry( AutoDirectoryFollowing,
+ DefaultDirectoryFollowing );
+
+ TDEGlobalSettings::Completion cm = (TDEGlobalSettings::Completion)
+ kc->readNumEntry( PathComboCompletionMode,
+ TDEGlobalSettings::completionMode() );
+ if ( cm != TDEGlobalSettings::completionMode() )
+ combo->setCompletionMode( cm );
+
+ cm = (TDEGlobalSettings::Completion)
+ kc->readNumEntry( LocationComboCompletionMode,
+ TDEGlobalSettings::completionMode() );
+ if ( cm != TDEGlobalSettings::completionMode() )
+ locationEdit->setCompletionMode( cm );
+
+ // show or don't show the speedbar
+ toggleSpeedbar( kc->readBoolEntry(ShowSpeedbar, true) );
+
+ // show or don't show the bookmarks
+ toggleBookmarks( kc->readBoolEntry(ShowBookmarks, false) );
+
+ // does the user want Automatically Select Extension?
+ d->autoSelectExtChecked = kc->readBoolEntry (AutoSelectExtChecked, DefaultAutoSelectExtChecked);
+ updateAutoSelectExtension ();
+
+ int w1 = minimumSize().width();
+ int w2 = toolbar->sizeHint().width() + 10;
+ if (w1 < w2)
+ setMinimumWidth(w2);
+
+ TQSize size = configDialogSize( group );
+ resize( size );
+ kc->setGroup( oldGroup );
+}
+
+void KFileDialog::writeConfig( TDEConfig *kc, const TQString& group )
+{
+ if ( !kc )
+ return;
+
+ TQString oldGroup = kc->group();
+ if ( !group.isEmpty() )
+ kc->setGroup( group );
+
+ kc->writePathEntry( RecentURLs, d->pathCombo->urls() );
+ saveDialogSize( group, true );
+ kc->writeEntry( PathComboCompletionMode, static_cast<int>(d->pathCombo->completionMode()) );
+ kc->writeEntry( LocationComboCompletionMode, static_cast<int>(locationEdit->completionMode()) );
+ kc->writeEntry( ShowSpeedbar, d->urlBar && !d->urlBar->isHidden() );
+ kc->writeEntry( ShowBookmarks, d->bookmarkHandler != 0 );
+ kc->writeEntry( AutoSelectExtChecked, d->autoSelectExtChecked );
+
+ ops->writeConfig( kc, group );
+ kc->setGroup( oldGroup );
+}
+
+
+void KFileDialog::readRecentFiles( TDEConfig *kc )
+{
+ TQString oldGroup = kc->group();
+ kc->setGroup( ConfigGroup );
+
+ locationEdit->setMaxItems( kc->readNumEntry( RecentFilesNumber,
+ DefaultRecentURLsNumber ) );
+ locationEdit->setURLs( kc->readPathListEntry( RecentFiles ),
+ KURLComboBox::RemoveBottom );
+ locationEdit->insertItem( TQString::null, 0 ); // dummy item without pixmap
+ locationEdit->setCurrentItem( 0 );
+
+ kc->setGroup( oldGroup );
+}
+
+void KFileDialog::saveRecentFiles( TDEConfig *kc )
+{
+ TQString oldGroup = kc->group();
+ kc->setGroup( ConfigGroup );
+
+ kc->writePathEntry( RecentFiles, locationEdit->urls() );
+
+ kc->setGroup( oldGroup );
+}
+
+KPushButton * KFileDialog::okButton() const
+{
+ return d->okButton;
+}
+
+KPushButton * KFileDialog::cancelButton() const
+{
+ return d->cancelButton;
+}
+
+KURLBar * KFileDialog::speedBar()
+{
+ return d->urlBar;
+}
+
+void KFileDialog::slotCancel()
+{
+ ops->close();
+ KDialogBase::slotCancel();
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setForceGlobal( true );
+ writeConfig( config, ConfigGroup );
+ config->setForceGlobal( false );
+}
+
+void KFileDialog::setKeepLocation( bool keep )
+{
+ d->keepLocation = keep;
+}
+
+bool KFileDialog::keepsLocation() const
+{
+ return d->keepLocation;
+}
+
+void KFileDialog::setOperationMode( OperationMode mode )
+{
+ d->operationMode = mode;
+ d->keepLocation = (mode == Saving);
+ filterWidget->setEditable( !d->hasDefaultFilter || mode != Saving );
+ if ( mode == Opening )
+ d->okButton->setGuiItem( KGuiItem( i18n("&Open"), "fileopen") );
+ else if ( mode == Saving ) {
+ d->okButton->setGuiItem( KStdGuiItem::save() );
+ setNonExtSelection();
+ }
+ else
+ d->okButton->setGuiItem( KStdGuiItem::ok() );
+ updateLocationWhatsThis ();
+ updateAutoSelectExtension ();
+}
+
+KFileDialog::OperationMode KFileDialog::operationMode() const
+{
+ return d->operationMode;
+}
+
+void KFileDialog::slotAutoSelectExtClicked()
+{
+ kdDebug (tdefile_area) << "slotAutoSelectExtClicked(): "
+ << d->autoSelectExtCheckBox->isChecked () << endl;
+
+ // whether the _user_ wants it on/off
+ d->autoSelectExtChecked = d->autoSelectExtCheckBox->isChecked ();
+
+ // update the current filename's extension
+ updateLocationEditExtension (d->extension /* extension hasn't changed */);
+}
+
+static TQString getExtensionFromPatternList (const TQStringList &patternList)
+{
+ TQString ret;
+ kdDebug (tdefile_area) << "\tgetExtension " << patternList << endl;
+
+ TQStringList::ConstIterator patternListEnd = patternList.end ();
+ for (TQStringList::ConstIterator it = patternList.begin ();
+ it != patternListEnd;
+ it++)
+ {
+ kdDebug (tdefile_area) << "\t\ttry: \'" << (*it) << "\'" << endl;
+
+ // is this pattern like "*.BMP" rather than useless things like:
+ //
+ // README
+ // *.
+ // *.*
+ // *.JP*G
+ // *.JP?
+ if ((*it).startsWith ("*.") &&
+ (*it).length () > 2 &&
+ (*it).find ('*', 2) < 0 && (*it).find ('?', 2) < 0)
+ {
+ ret = (*it).mid (1);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static TQString stripUndisplayable (const TQString &string)
+{
+ TQString ret = string;
+
+ ret.remove (':');
+ ret.remove ('&');
+
+ return ret;
+}
+
+
+TQString KFileDialog::currentFilterExtension (void)
+{
+ return d->extension;
+}
+
+void KFileDialog::updateAutoSelectExtension (void)
+{
+ if (!d->autoSelectExtCheckBox) return;
+
+ //
+ // Figure out an extension for the Automatically Select Extension thing
+ // (some Windows users apparently don't know what to do when confronted
+ // with a text file called "COPYING" but do know what to do with
+ // COPYING.txt ...)
+ //
+
+ kdDebug (tdefile_area) << "Figure out an extension: " << endl;
+ TQString lastExtension = d->extension;
+ d->extension = TQString::null;
+
+ // Automatically Select Extension is only valid if the user is _saving_ a _file_
+ if ((operationMode () == Saving) && (mode () & KFile::File))
+ {
+ //
+ // Get an extension from the filter
+ //
+
+ TQString filter = currentFilter ();
+ if (!filter.isEmpty ())
+ {
+ // e.g. "*.cpp"
+ if (filter.find ('/') < 0)
+ {
+ d->extension = getExtensionFromPatternList (TQStringList::split (" ", filter)).lower ();
+ kdDebug (tdefile_area) << "\tsetFilter-style: pattern ext=\'"
+ << d->extension << "\'" << endl;
+ }
+ // e.g. "text/html"
+ else
+ {
+ KMimeType::Ptr mime = KMimeType::mimeType (filter);
+
+ // first try X-TDE-NativeExtension
+ TQString nativeExtension = mime->property ("X-TDE-NativeExtension").toString ();
+ if (nativeExtension.at (0) == '.')
+ {
+ d->extension = nativeExtension.lower ();
+ kdDebug (tdefile_area) << "\tsetMimeFilter-style: native ext=\'"
+ << d->extension << "\'" << endl;
+ }
+
+ // no X-TDE-NativeExtension
+ if (d->extension.isEmpty ())
+ {
+ d->extension = getExtensionFromPatternList (mime->patterns ()).lower ();
+ kdDebug (tdefile_area) << "\tsetMimeFilter-style: pattern ext=\'"
+ << d->extension << "\'" << endl;
+ }
+ }
+ }
+
+
+ //
+ // GUI: checkbox
+ //
+
+ TQString whatsThisExtension;
+ if (!d->extension.isEmpty ())
+ {
+ // remember: sync any changes to the string with below
+ d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension (%1)").arg (d->extension));
+ whatsThisExtension = i18n ("the extension <b>%1</b>").arg (d->extension);
+
+ d->autoSelectExtCheckBox->setEnabled (true);
+ d->autoSelectExtCheckBox->setChecked (d->autoSelectExtChecked);
+ }
+ else
+ {
+ // remember: sync any changes to the string with above
+ d->autoSelectExtCheckBox->setText (i18n ("Automatically select filename e&xtension"));
+ whatsThisExtension = i18n ("a suitable extension");
+
+ d->autoSelectExtCheckBox->setChecked (false);
+ d->autoSelectExtCheckBox->setEnabled (false);
+ }
+
+ const TQString locationLabelText = stripUndisplayable (d->locationLabel->text ());
+ const TQString filterLabelText = stripUndisplayable (d->filterLabel->text ());
+ TQWhatsThis::add (d->autoSelectExtCheckBox,
+ "<qt>" +
+ i18n (
+ "This option enables some convenient features for "
+ "saving files with extensions:<br>"
+ "<ol>"
+ "<li>Any extension specified in the <b>%1</b> text "
+ "area will be updated if you change the file type "
+ "to save in.<br>"
+ "<br></li>"
+ "<li>If no extension is specified in the <b>%2</b> "
+ "text area when you click "
+ "<b>Save</b>, %3 will be added to the end of the "
+ "filename (if the filename does not already exist). "
+ "This extension is based on the file type that you "
+ "have chosen to save in.<br>"
+ "<br>"
+ "If you do not want TDE to supply an extension for the "
+ "filename, you can either turn this option off or you "
+ "can suppress it by adding a period (.) to the end of "
+ "the filename (the period will be automatically "
+ "removed)."
+ "</li>"
+ "</ol>"
+ "If unsure, keep this option enabled as it makes your "
+ "files more manageable."
+ )
+ .arg (locationLabelText)
+ .arg (locationLabelText)
+ .arg (whatsThisExtension)
+ + "</qt>"
+ );
+
+ d->autoSelectExtCheckBox->show ();
+
+
+ // update the current filename's extension
+ updateLocationEditExtension (lastExtension);
+ }
+ // Automatically Select Extension not valid
+ else
+ {
+ d->autoSelectExtCheckBox->setChecked (false);
+ d->autoSelectExtCheckBox->hide ();
+ }
+}
+
+// Updates the extension of the filename specified in locationEdit if the
+// Automatically Select Extension feature is enabled.
+// (this prevents you from accidently saving "file.kwd" as RTF, for example)
+void KFileDialog::updateLocationEditExtension (const TQString &lastExtension)
+{
+ if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ())
+ return;
+
+ TQString urlStr = locationEdit->currentText ();
+ if (urlStr.isEmpty ())
+ return;
+
+ KURL url = getCompleteURL (urlStr);
+ kdDebug (tdefile_area) << "updateLocationEditExtension (" << url << ")" << endl;
+
+ const int fileNameOffset = urlStr.findRev ('/') + 1;
+ TQString fileName = urlStr.mid (fileNameOffset);
+
+ const int dot = fileName.findRev ('.');
+ const int len = fileName.length ();
+ if (dot > 0 && // has an extension already and it's not a hidden file
+ // like ".hidden" (but we do accept ".hidden.ext")
+ dot != len - 1 // and not deliberately suppressing extension
+ )
+ {
+ // exists?
+ TDEIO::UDSEntry t;
+ if (TDEIO::NetAccess::stat (url, t, topLevelWidget()))
+ {
+ kdDebug (tdefile_area) << "\tfile exists" << endl;
+
+ if (isDirectory (t))
+ {
+ kdDebug (tdefile_area) << "\tisDir - won't alter extension" << endl;
+ return;
+ }
+
+ // --- fall through ---
+ }
+
+
+ //
+ // try to get rid of the current extension
+ //
+
+ // catch "double extensions" like ".tar.gz"
+ if (lastExtension.length () && fileName.endsWith (lastExtension))
+ fileName.truncate (len - lastExtension.length ());
+ // can only handle "single extensions"
+ else
+ fileName.truncate (dot);
+
+ // add extension
+ const TQString newText = urlStr.left (fileNameOffset) + fileName + d->extension;
+ if ( newText != locationEdit->currentText() )
+ {
+ locationEdit->setCurrentText (urlStr.left (fileNameOffset) + fileName + d->extension);
+ locationEdit->lineEdit()->setEdited (true);
+ }
+ }
+}
+
+// Updates the filter if the extension of the filename specified in locationEdit is changed
+// (this prevents you from accidently saving "file.kwd" as RTF, for example)
+void KFileDialog::updateFilter ()
+{
+ if ((operationMode() == Saving) && (mode() & KFile::File) ) {
+ const TQString urlStr = locationEdit->currentText ();
+ if (urlStr.isEmpty ())
+ return;
+
+ KMimeType::Ptr mime = KMimeType::findByPath(urlStr, 0, true);
+ if (mime && mime->name() != KMimeType::defaultMimeType()) {
+ if (filterWidget->currentFilter() != mime->name() &&
+ filterWidget->filters.findIndex(mime->name()) != -1) {
+ filterWidget->setCurrentFilter(mime->name());
+ }
+ }
+ }
+}
+
+// applies only to a file that doesn't already exist
+void KFileDialog::appendExtension (KURL &url)
+{
+ if (!d->autoSelectExtCheckBox->isChecked () || d->extension.isEmpty ())
+ return;
+
+ TQString fileName = url.fileName ();
+ if (fileName.isEmpty ())
+ return;
+
+ kdDebug (tdefile_area) << "appendExtension(" << url << ")" << endl;
+
+ const int len = fileName.length ();
+ const int dot = fileName.findRev ('.');
+
+ const bool suppressExtension = (dot == len - 1);
+ const bool unspecifiedExtension = (dot <= 0);
+
+ // don't TDEIO::NetAccess::Stat if unnecessary
+ if (!(suppressExtension || unspecifiedExtension))
+ return;
+
+ // exists?
+ TDEIO::UDSEntry t;
+ if (TDEIO::NetAccess::stat (url, t, topLevelWidget()))
+ {
+ kdDebug (tdefile_area) << "\tfile exists - won't append extension" << endl;
+ return;
+ }
+
+ // suppress automatically append extension?
+ if (suppressExtension)
+ {
+ //
+ // Strip trailing dot
+ // This allows lazy people to have autoSelectExtCheckBox->isChecked
+ // but don't want a file extension to be appended
+ // e.g. "README." will make a file called "README"
+ //
+ // If you really want a name like "README.", then type "README.."
+ // and the trailing dot will be removed (or just stop being lazy and
+ // turn off this feature so that you can type "README.")
+ //
+ kdDebug (tdefile_area) << "\tstrip trailing dot" << endl;
+ url.setFileName (fileName.left (len - 1));
+ }
+ // evilmatically append extension :) if the user hasn't specified one
+ else if (unspecifiedExtension)
+ {
+ kdDebug (tdefile_area) << "\tappending extension \'" << d->extension << "\'..." << endl;
+ url.setFileName (fileName + d->extension);
+ kdDebug (tdefile_area) << "\tsaving as \'" << url << "\'" << endl;
+ }
+}
+
+
+// adds the selected files/urls to 'recent documents'
+void KFileDialog::addToRecentDocuments()
+{
+ int m = ops->mode();
+
+ if ( m & KFile::LocalOnly ) {
+ TQStringList files = selectedFiles();
+ TQStringList::ConstIterator it = files.begin();
+ for ( ; it != files.end(); ++it )
+ KRecentDocument::add( *it );
+ }
+
+ else { // urls
+ KURL::List urls = selectedURLs();
+ KURL::List::ConstIterator it = urls.begin();
+ for ( ; it != urls.end(); ++it ) {
+ if ( (*it).isValid() )
+ KRecentDocument::add( *it );
+ }
+ }
+}
+
+KActionCollection * KFileDialog::actionCollection() const
+{
+ return ops->actionCollection();
+}
+
+void KFileDialog::keyPressEvent( TQKeyEvent *e )
+{
+ if ( e->key() == Key_Escape )
+ {
+ e->accept();
+ d->cancelButton->animateClick();
+ }
+ else
+ KDialogBase::keyPressEvent( e );
+}
+
+void KFileDialog::toggleSpeedbar( bool show )
+{
+ if ( show )
+ {
+ if ( !d->urlBar )
+ initSpeedbar();
+
+ d->urlBar->show();
+
+ // check to see if they have a home item defined, if not show the home button
+ KURLBarItem *urlItem = static_cast<KURLBarItem*>( d->urlBar->listBox()->firstItem() );
+ KURL homeURL;
+ homeURL.setPath( TQDir::homeDirPath() );
+ while ( urlItem )
+ {
+ if ( homeURL.equals( urlItem->url(), true ) )
+ {
+ ops->actionCollection()->action( "home" )->unplug( toolbar );
+ break;
+ }
+
+ urlItem = static_cast<KURLBarItem*>( urlItem->next() );
+ }
+ }
+ else
+ {
+ if (d->urlBar)
+ d->urlBar->hide();
+
+ if ( !ops->actionCollection()->action( "home" )->isPlugged( toolbar ) )
+ ops->actionCollection()->action( "home" )->plug( toolbar, 3 );
+ }
+
+ static_cast<KToggleAction *>(actionCollection()->action("toggleSpeedbar"))->setChecked( show );
+}
+
+void KFileDialog::toggleBookmarks(bool show)
+{
+ if (show)
+ {
+ if (d->bookmarkHandler)
+ {
+ return;
+ }
+
+ d->bookmarkHandler = new KFileBookmarkHandler( this );
+ connect( d->bookmarkHandler, TQT_SIGNAL( openURL( const TQString& )),
+ TQT_SLOT( enterURL( const TQString& )));
+
+ toolbar->insertButton(TQString::fromLatin1("bookmark"),
+ (int)HOTLIST_BUTTON, true,
+ i18n("Bookmarks"), 5);
+ toolbar->getButton(HOTLIST_BUTTON)->setPopup(d->bookmarkHandler->menu(),
+ true);
+ TQWhatsThis::add(toolbar->getButton(HOTLIST_BUTTON),
+ i18n("<qt>This button allows you to bookmark specific locations. "
+ "Click on this button to open the bookmark menu where you may add, "
+ "edit or select a bookmark.<p>"
+ "These bookmarks are specific to the file dialog, but otherwise operate "
+ "like bookmarks elsewhere in TDE.</qt>"));
+ }
+ else if (d->bookmarkHandler)
+ {
+ delete d->bookmarkHandler;
+ d->bookmarkHandler = 0;
+ toolbar->removeItem(HOTLIST_BUTTON);
+ }
+
+ static_cast<KToggleAction *>(actionCollection()->action("toggleBookmarks"))->setChecked( show );
+}
+
+int KFileDialog::pathComboIndex()
+{
+ return d->m_pathComboIndex;
+}
+
+// static
+void KFileDialog::initStatic()
+{
+ if ( lastDirectory )
+ return;
+
+ lastDirectory = ldd.setObject(lastDirectory, new KURL());
+}
+
+// static
+KURL KFileDialog::getStartURL( const TQString& startDir,
+ TQString& recentDirClass )
+{
+ initStatic();
+
+ recentDirClass = TQString::null;
+ KURL ret;
+
+ bool useDefaultStartDir = startDir.isEmpty();
+ if ( !useDefaultStartDir )
+ {
+ if (startDir[0] == ':')
+ {
+ recentDirClass = startDir;
+ ret = KURL::fromPathOrURL( KRecentDirs::dir(recentDirClass) );
+ }
+ else
+ {
+ ret = TDECmdLineArgs::makeURL( TQFile::encodeName(startDir) );
+ // If we won't be able to list it (e.g. http), then use default
+ if ( !KProtocolInfo::supportsListing( ret ) )
+ useDefaultStartDir = true;
+ }
+ }
+
+ if ( useDefaultStartDir )
+ {
+ if (lastDirectory->isEmpty()) {
+ lastDirectory->setPath(TDEGlobalSettings::documentPath());
+ KURL home;
+ home.setPath( TQDir::homeDirPath() );
+ // if there is no docpath set (== home dir), we prefer the current
+ // directory over it. We also prefer the homedir when our CWD is
+ // different from our homedirectory or when the document dir
+ // does not exist
+ if ( lastDirectory->path(+1) == home.path(+1) ||
+ TQDir::currentDirPath() != TQDir::homeDirPath() ||
+ !TQDir(lastDirectory->path(+1)).exists() )
+ lastDirectory->setPath(TQDir::currentDirPath());
+ }
+ ret = *lastDirectory;
+ }
+
+ return ret;
+}
+
+void KFileDialog::setStartDir( const KURL& directory )
+{
+ initStatic();
+ if ( directory.isValid() )
+ *lastDirectory = directory;
+}
+
+void KFileDialog::setNonExtSelection()
+{
+ // Enhanced rename: Don't highlight the file extension.
+ TQString pattern, filename = locationEdit->currentText().stripWhiteSpace();
+ KServiceTypeFactory::self()->findFromPattern( filename, &pattern );
+
+ if ( !pattern.isEmpty() && pattern.at( 0 ) == '*' && pattern.find( '*' , 1 ) == -1 )
+ locationEdit->lineEdit()->setSelection( 0, filename.length() - pattern.stripWhiteSpace().length()+1 );
+ else
+ {
+ int lastDot = filename.findRev( '.' );
+ if ( lastDot > 0 )
+ locationEdit->lineEdit()->setSelection( 0, lastDot );
+ }
+}
+
+void KFileDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+
+#include "tdefiledialog.moc"
diff --git a/tdeio/tdefile/tdefiledialog.h b/tdeio/tdefile/tdefiledialog.h
new file mode 100644
index 000000000..28b04aff6
--- /dev/null
+++ b/tdeio/tdefile/tdefiledialog.h
@@ -0,0 +1,989 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Frerich Raabe <raabe@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 __KFILEDIALOG_H__
+#define __KFILEDIALOG_H__
+
+#include <tqstring.h>
+
+#include <kdialogbase.h>
+#include <tdefile.h>
+#include <kurl.h>
+#include <kmimetype.h>
+#include <tdeio/jobclasses.h>
+
+class TQCheckBox;
+class TQHBoxLayout;
+class TQGridLayout;
+class TQLabel;
+class TQPopupMenu;
+class TQVBoxLayout;
+
+class KActionCollection;
+class KDirOperator;
+class KURLBar;
+class KURLComboBox;
+class KFileFilterCombo;
+class KFileView;
+class KFileItem;
+class KPushButton;
+class KToolBar;
+class KPreviewWidgetBase;
+
+struct KFileDialogPrivate;
+
+/**
+ * Provides a user (and developer) friendly way to
+ * select files and directories.
+ *
+ * The widget can be used as a drop in replacement for the
+ * TQFileDialog widget, but has greater functionality and a nicer GUI.
+ *
+ * You will usually want to use one of the static methods
+ * getOpenFileName(), getSaveFileName(), getOpenURL()
+ * or for multiple files getOpenFileNames() or getOpenURLs().
+ *
+ * The dialog has been designed to allow applications to customise it
+ * by subclassing. It uses geometry management to ensure that subclasses
+ * can easily add children that will be incorporated into the layout.
+ *
+ * \image html tdefiledialog.png "KDE File Dialog"
+ *
+ * @short A file selection dialog.
+ *
+ * @author Richard J. Moore <rich@kde.org>, Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KFileDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Defines some default behavior of the filedialog.
+ * E.g. in mode @p Opening and @p Saving, the selected files/urls will
+ * be added to the "recent documents" list. The Saving mode also implies
+ * setKeepLocation() being set.
+ *
+ * @p Other means that no default actions are performed.
+ *
+ * @see setOperationMode
+ * @see operationMode
+ */
+ enum OperationMode { Other = 0, Opening, Saving };
+
+ /**
+ * Constructs a file dialog.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param filter A shell glob or a mime-type-filter that specifies
+ * which files to display.
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ * See setFilter() for details on how to use this argument.
+ *
+ */
+ KFileDialog(const TQString& startDir, const TQString& filter,
+ TQWidget *parent, const char *name,
+ bool modal);
+
+ /**
+ * Constructs a file dialog.
+ *
+ * The parameters here are identical to the first constructor except
+ * for the addition of a TQWidget parameter.
+ *
+ * Historical note: The original version of KFileDialog did not have this extra
+ * parameter. It was added later, and, in order to maintain binary compatibility,
+ * it was placed in a new constructor instead of added to the original one.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ *
+ * @param filter A shell glob or a mime-type-filter that specifies
+ * which files to display.
+ * See setFilter() for details on how to use this argument.
+ *
+ * @param widget A widget, or a widget of widgets, for displaying custom
+ * data in the dialog. This can be used, for example, to
+ * display a check box with the caption "Open as read-only".
+ * When creating this widget, you don't need to specify a parent,
+ * since the widget's parent will be set automatically by KFileDialog.
+ * @param parent The parent widget of this dialog
+ * @param name The name of this object
+ * @param modal Whether to create a modal dialog or not
+ * @since 3.1
+ */
+ KFileDialog(const TQString& startDir, const TQString& filter,
+ TQWidget *parent, const char *name,
+ bool modal, TQWidget* widget);
+
+
+ /**
+ * Destructs the file dialog.
+ */
+ ~KFileDialog();
+
+ /**
+ * @returns The selected fully qualified filename.
+ */
+ KURL selectedURL() const;
+
+ /**
+ * @returns The list of selected URLs.
+ */
+ KURL::List selectedURLs() const;
+
+ /**
+ * @returns the currently shown directory.
+ */
+ KURL baseURL() const;
+
+ /**
+ * Returns the full path of the selected file in the local filesystem.
+ * (Local files only)
+ */
+ TQString selectedFile() const;
+
+ /**
+ * Returns a list of all selected local files.
+ */
+ TQStringList selectedFiles() const;
+
+ /**
+ * Sets the directory to view.
+ *
+ * @param url URL to show.
+ * @param clearforward Indicates whether the forward queue
+ * should be cleared.
+ */
+ void setURL(const KURL &url, bool clearforward = true);
+
+ /**
+ * Sets the file name to preselect to @p name
+ *
+ * This takes absolute URLs and relative file names.
+ */
+ void setSelection(const TQString& name);
+
+ /**
+ * Sets the operational mode of the filedialog to @p Saving, @p Opening
+ * or @p Other. This will set some flags that are specific to loading
+ * or saving files. E.g. setKeepLocation() makes mostly sense for
+ * a save-as dialog. So setOperationMode( KFileDialog::Saving ); sets
+ * setKeepLocation for example.
+ *
+ * The mode @p Saving, together with a default filter set via
+ * setMimeFilter() will make the filter combobox read-only.
+ *
+ * The default mode is @p Opening.
+ *
+ * Call this method right after instantiating KFileDialog.
+ *
+ * @see operationMode
+ * @see KFileDialog::OperationMode
+ */
+ void setOperationMode( KFileDialog::OperationMode );
+
+ /**
+ * @returns the current operation mode, Opening, Saving or Other. Default
+ * is Other.
+ *
+ * @see operationMode
+ * @see KFileDialog::OperationMode
+ */
+ OperationMode operationMode() const;
+
+ /**
+ * Sets whether the filename/url should be kept when changing directories.
+ * This is for example useful when having a predefined filename where
+ * the full path for that file is searched.
+ *
+ * This is implicitly set when operationMode() is KFileDialog::Saving
+ *
+ * getSaveFileName() and getSaveURL() set this to true by default, so that
+ * you can type in the filename and change the directory without having
+ * to type the name again.
+ */
+ void setKeepLocation( bool keep );
+
+ /**
+ * @returns whether the contents of the location edit are kept when
+ * changing directories.
+ */
+ bool keepsLocation() const;
+
+ /**
+ * Sets the filter to be used to @p filter.
+ *
+ * You can set more
+ * filters for the user to select separated by '\n'. Every
+ * filter entry is defined through namefilter|text to diplay.
+ * If no | is found in the expression, just the namefilter is
+ * shown. Examples:
+ *
+ * \code
+ * tdefile->setFilter("*.cpp|C++ Source Files\n*.h|Header files");
+ * tdefile->setFilter("*.cpp");
+ * tdefile->setFilter("*.cpp|Sources (*.cpp)");
+ * tdefile->setFilter("*.cpp|" + i18n("Sources (*.cpp)"));
+ * tdefile->setFilter("*.cpp *.cc *.C|C++ Source Files\n*.h *.H|Header files");
+ * \endcode
+ *
+ * Note: The text to display is not parsed in any way. So, if you
+ * want to show the suffix to select by a specific filter, you must
+ * repeat it.
+ *
+ * If the filter contains an unescaped '/', a mimetype-filter is assumed.
+ * If you would like a '/' visible in your filter it can be escaped with
+ * a '\'. You can specify multiple mimetypes like this (separated with
+ * space):
+ *
+ * \code
+ * tdefile->setFilter( "image/png text/html text/plain" );
+ * tdefile->setFilter( "*.cue|CUE\\/BIN Files (*.cue)" );
+ * \endcode
+ *
+ * @see filterChanged
+ * @see setMimeFilter
+ */
+ void setFilter(const TQString& filter);
+
+ /**
+ * Returns the current filter as entered by the user or one of the
+ * predefined set via setFilter().
+ *
+ * @see setFilter()
+ * @see filterChanged()
+ */
+ TQString currentFilter() const;
+
+ /**
+ * Sets the filter up to specify the output type.
+ *
+ * @param label the label to use instead of "Filter:"
+ * @param types a list of mimetypes that can be used as output format
+ * @param defaultType the default mimetype to use as output format.
+ *
+ * Do not use in conjunction with setFilter()
+ * @deprecated
+ */
+ void setFilterMimeType(const TQString &label, const KMimeType::List &types, const KMimeType::Ptr &defaultType) KDE_DEPRECATED;
+
+ /**
+ * Returns the mimetype for the desired output format.
+ *
+ * This is only valid if setFilterMimeType() has been called
+ * previously.
+ *
+ * @see setFilterMimeType()
+ */
+ KMimeType::Ptr currentFilterMimeType();
+
+ /**
+ * Sets the filter up to specify the output type.
+ *
+ * @param types a list of mimetypes that can be used as output format
+ * @param defaultType the default mimetype to use as output format, if any.
+ * If @p defaultType is set, it will be set as the current item.
+ * Otherwise, a first item showing all the mimetypes will be created.
+ * Typically, @p defaultType should be empty for loading and set for saving.
+ *
+ * Do not use in conjunction with setFilter()
+ */
+ void setMimeFilter( const TQStringList& types,
+ const TQString& defaultType = TQString::null );
+
+ /**
+ * The mimetype for the desired output format.
+ *
+ * This is only valid if setMimeFilter() has been called
+ * previously.
+ *
+ * @see setMimeFilter()
+ */
+ TQString currentMimeFilter() const;
+
+ /**
+ * Clears any mime- or namefilter. Does not reload the directory.
+ */
+ void clearFilter();
+
+ /**
+ * @deprecated
+ * Add a preview widget and enter the preview mode.
+ *
+ * In this mode
+ * the dialog is split and the right part contains your widget.
+ * This widget has to inherit TQWidget and it has to implement
+ * a slot showPreview(const KURL &); which is called
+ * every time the file changes. You may want to look at
+ * koffice/lib/kofficecore/koFilterManager.cc for some hints :)
+ *
+ * Ownership is transferred to KFileDialog. You need to create the
+ * preview-widget with "new", i.e. on the heap.
+ */
+ void setPreviewWidget(const TQWidget *w) KDE_DEPRECATED;
+
+ /**
+ * Adds a preview widget and enters the preview mode.
+ *
+ * In this mode the dialog is split and the right part contains your
+ * preview widget.
+ *
+ * Ownership is transferred to KFileDialog. You need to create the
+ * preview-widget with "new", i.e. on the heap.
+ *
+ * @param w The widget to be used for the preview.
+ */
+ void setPreviewWidget(const KPreviewWidgetBase *w);
+
+ /**
+ * Creates a modal file dialog and return the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static TQString getOpenFileName(const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+ /**
+ * Use this version only if you have no TQWidget available as
+ * parent widget. This can be the case if the parent widget is
+ * a widget in another process or if the parent widget is a
+ * non-Qt widget. For example, in a GTK program.
+ *
+ * @since 3.4
+ */
+ static TQString getOpenFileNameWId(const TQString& startDir,
+ const TQString& filter,
+ WId parent_id, const TQString& caption);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filenames or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static TQStringList getOpenFileNames(const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent = 0,
+ const TQString& caption= TQString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * URL or an empty string if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing URL.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getOpenURL(const TQString& startDir = TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * URLs or an empty list if none was chosen.
+ *
+ * Note that with
+ * this method the user must select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL::List getOpenURLs(const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent = 0,
+ const TQString& caption= TQString::null);
+
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static TQString getSaveFileName(const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+ /**
+ * This function accepts the window id of the parent window, instead
+ * of TQWidget*. It should be used only when necessary.
+ * @since 3.4
+ */
+ static TQString getSaveFileNameWId(const TQString& dir, const TQString& filter,
+ WId parent_id,
+ const TQString& caption);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * filename or an empty string if none was chosen.
+ *
+ * Note that with this
+ * method the user need not select an existing filename.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li a relative path or a filename determining the
+ * directory to start in and the file to be selected.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param filter This is a space separated list of shell globs.
+ * You can set the text to be displayed for the glob, and
+ * provide multiple globs. See setFilter() for details on
+ * how to do this...
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getSaveURL(const TQString& startDir= TQString::null,
+ const TQString& filter= TQString::null,
+ TQWidget *parent= 0,
+ const TQString& caption = TQString::null);
+
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * directory or an empty string if none was chosen.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static TQString getExistingDirectory(const TQString & startDir = TQString::null,
+ TQWidget * parent = 0,
+ const TQString& caption= TQString::null);
+
+ /**
+ * Creates a modal file dialog and returns the selected
+ * directory or an empty string if none was chosen.
+ *
+ * Contrary to getExistingDirectory(), this method allows the
+ * selection of a remote directory.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ * @since 3.1
+ */
+ static KURL getExistingURL(const TQString & startDir = TQString::null,
+ TQWidget * parent = 0,
+ const TQString& caption= TQString::null);
+ /**
+ * Creates a modal file dialog with an image previewer and returns the
+ * selected url or an empty string if none was chosen.
+ *
+ * @param startDir This can either be
+ * @li The URL of the directory to start in.
+ * @li TQString::null to start in the current working
+ * directory, or the last directory where a file has been
+ * selected.
+ * @li ':&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in the same application that specified
+ * the same keyword.
+ * @li '::&lt;keyword&gt;' to start in the directory last used
+ * by a filedialog in any application that specified the
+ * same keyword.
+ * @param parent The widget the dialog will be centered on initially.
+ * @param caption The name of the dialog widget.
+ */
+ static KURL getImageOpenURL( const TQString& startDir = TQString::null,
+ TQWidget *parent = 0,
+ const TQString& caption = TQString::null );
+ virtual void show();
+
+ /**
+ * Convenient overload of the other setMode(unsigned int) method.
+ */
+ void setMode( KFile::Mode m );
+
+ /**
+ * Sets the mode of the dialog.
+ *
+ * The mode is defined as (in tdefile.h):
+ * \code
+ * enum Mode {
+ * File = 1,
+ * Directory = 2,
+ * Files = 4,
+ * ExistingOnly = 8,
+ * LocalOnly = 16
+ * };
+ * \endcode
+ * You can OR the values, e.g.
+ * \code
+ * KFile::Mode mode = static_cast<KFile::Mode>( KFile::Files |
+ * KFile::ExistingOnly |
+ * KFile::LocalOnly );
+ * setMode( mode );
+ * \endcode
+ */
+ void setMode( unsigned int m );
+
+ /**
+ * Returns the mode of the filedialog.
+ * @see setMode()
+ */
+ KFile::Mode mode() const;
+
+ /**
+ * Sets the text to be displayed in front of the selection.
+ *
+ * The default is "Location".
+ * Most useful if you want to make clear what
+ * the location is used for.
+ */
+ void setLocationLabel(const TQString& text);
+
+ /**
+ * Returns a pointer to the toolbar.
+ *
+ * You can use this to insert custom
+ * items into it, e.g.:
+ * \code
+ * yourAction = new KAction( i18n("Your Action"), 0,
+ * this, TQT_SLOT( yourSlot() ),
+ * this, "action name" );
+ * yourAction->plug( tdefileDialog->toolBar() );
+ * \endcode
+ */
+ KToolBar *toolBar() const { return toolbar; }
+
+ /**
+ * @returns a pointer to the OK-Button in the filedialog. You may use it
+ * e.g. to set a custom text to it.
+ */
+ KPushButton *okButton() const;
+
+ /**
+ * @returns a pointer to the Cancel-Button in the filedialog. You may use
+ * it e.g. to set a custom text to it.
+ */
+ KPushButton *cancelButton() const;
+
+ /**
+ * @returns the KURLBar object used as the "speed bar". You can add custom
+ * entries to it like that:
+ * \code
+ * KURLBar *urlBar = fileDialog->speedBar();
+ * if ( urlBar )
+ * urlBar->insertDynamicItem( someURL, i18n("The URL's description") );
+ * \endcode
+ *
+ * Note that this method may return a null-pointer if the user configured
+ * to not use the speed-bar.
+ * @see KURLBar
+ * @see KURLBar::insertDynamicItem
+ * @since 3.2
+ */
+ KURLBar *speedBar();
+
+ /**
+ * @returns a pointer to the action collection, holding all the used
+ * KActions.
+ */
+ KActionCollection *actionCollection() const;
+
+ /**
+ * @returns the index of the path combobox so when inserting widgets into
+ * the dialog (e.g. subclasses) they can do so without hardcoding in an index
+ */
+ int pathComboIndex();
+
+ /**
+ * This method implements the logic to determine the user's default directory
+ * to be listed. E.g. the documents direcory, home directory or a recently
+ * used directory.
+ * @param startDir A url/directory, to be used. May use the ':' and '::' syntax
+ * as documented in the KFileDialog() constructor.
+ * @param recentDirClass If the ':' or '::' syntax is used, recentDirClass
+ * will contain the string to be used later for KRecentDir::dir()
+ * @return The URL that should be listed by default (e.g. by KFileDialog or
+ * KDirSelectDialog).
+ * @since 3.1
+ */
+ static KURL getStartURL( const TQString& startDir, TQString& recentDirClass );
+
+ /**
+ * @internal
+ * Used by KDirSelectDialog to share the dialog's start directory.
+ */
+ static void setStartDir( const KURL& directory );
+
+signals:
+ /**
+ * Emitted when the user selects a file. It is only emitted in single-
+ * selection mode. The best way to get notified about selected file(s)
+ * is to connect to the okClicked() signal inherited from KDialogBase
+ * and call selectedFile(), selectedFiles(),
+ * selectedURL() or selectedURLs().
+ */
+ void fileSelected(const TQString&);
+
+ /**
+ * Emitted when the user highlights a file.
+ */
+ void fileHighlighted(const TQString&);
+
+ /**
+ * Emitted when the user hilights one or more files in multiselection mode.
+ *
+ * Note: fileHighlighted() or fileSelected() are @em not
+ * emitted in multiselection mode. You may use selectedItems() to
+ * ask for the current highlighted items.
+ * @see fileSelected
+ */
+ void selectionChanged();
+
+ /**
+ * Emitted when the filter changed, i.e. the user entered an own filter
+ * or chose one of the predefined set via setFilter().
+ *
+ * @param filter contains the new filter (only the extension part,
+ * not the explanation), i.e. "*.cpp" or "*.cpp *.cc".
+ *
+ * @see setFilter()
+ * @see currentFilter()
+ */
+ void filterChanged( const TQString& filter );
+
+protected:
+ KToolBar *toolbar;
+
+ static KURL *lastDirectory;
+
+ KURLComboBox *locationEdit;
+
+ KFileFilterCombo *filterWidget;
+
+ /**
+ * Reimplemented to animate the cancel button.
+ */
+ virtual void keyPressEvent( TQKeyEvent *e );
+
+ /**
+ * Perform basic initialization tasks. Called by constructors.
+ * @since 3.1
+ */
+ void init(const TQString& startDir, const TQString& filter, TQWidget* widget);
+
+ /**
+ * rebuild geometry management.
+ *
+ */
+ virtual void initGUI();
+
+ /**
+ * called when an item is highlighted/selected in multiselection mode.
+ * handles setting the locationEdit.
+ */
+ void multiSelectionChanged();
+
+ /**
+ * Reads configuration and applies it (size, recent directories, ...)
+ */
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+
+ /**
+ * Saves the current configuration
+ */
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null );
+
+ /**
+ * Reads the recent used files and inserts them into the location combobox
+ */
+ virtual void readRecentFiles( TDEConfig * );
+
+ /**
+ * Saves the entries from the location combobox.
+ */
+ virtual void saveRecentFiles( TDEConfig * );
+
+ /**
+ * Parses the string "line" for files. If line doesn't contain any ", the
+ * whole line will be interpreted as one file. If the number of " is odd,
+ * an empty list will be returned. Otherwise, all items enclosed in " "
+ * will be returned as correct urls.
+ */
+ KURL::List tokenize(const TQString& line) const;
+
+ /**
+ * Returns the absolute version of the URL specified in locationEdit.
+ * @since 3.2
+ */
+ KURL getCompleteURL(const TQString&);
+
+ /**
+ * Returns the filename extension associated with the currentFilter().
+ * TQString::null is returned if an extension is not available or if
+ * operationMode() != Saving.
+ * @since 3.2
+ */
+ TQString currentFilterExtension();
+
+ /**
+ * Updates the currentFilterExtension and the availability of the
+ * Automatically Select Extension Checkbox (visible if operationMode()
+ * == Saving and enabled if an extension _will_ be associated with the
+ * currentFilter(), _after_ this call). You should call this after
+ * filterWidget->setCurrentItem().
+ * @since 3.2
+ */
+ void updateAutoSelectExtension();
+
+
+protected slots:
+ void urlEntered( const KURL& );
+ void enterURL( const KURL& url );
+ void enterURL( const TQString& url );
+ void locationActivated( const TQString& url );
+
+ /**
+ * @deprecated,
+ */
+ // ### remove in KDE4
+ void toolbarCallback(int);
+ /**
+ * @deprecated
+ */
+ // ### remove in KDE4
+ void pathComboChanged( const TQString& );
+ /**
+ * @deprecated
+ */
+ // ### remove in KDE4
+ void dirCompletion( const TQString& );
+
+ void slotFilterChanged();
+ void fileHighlighted(const KFileItem *i);
+ void fileSelected(const KFileItem *i);
+ void slotStatResult(TDEIO::Job* job);
+ void slotLoadingFinished();
+
+ void fileCompletion( const TQString& );
+ /**
+ * @since 3.1
+ */
+ void toggleSpeedbar( bool );
+
+ /**
+ * @since 3.4
+ */
+ void toggleBookmarks(bool show);
+
+ /**
+ * @deprecated
+ */
+ virtual void updateStatusLine(int dirs, int files);
+
+ virtual void slotOk();
+ virtual void accept();
+ virtual void slotCancel();
+
+ void slotAutoSelectExtClicked();
+ void addToRecentDocuments();
+ void initSpeedbar();
+
+private slots:
+ void slotLocationChanged( const TQString& text );
+
+private:
+ KFileDialog(const KFileDialog&);
+ KFileDialog operator=(const KFileDialog&);
+
+ void setLocationText( const TQString& text );
+ void updateLocationWhatsThis();
+
+ void appendExtension(KURL &url);
+ void updateLocationEditExtension(const TQString &);
+ void updateFilter();
+
+ static void initStatic();
+
+ void setNonExtSelection();
+
+protected:
+ KDirOperator *ops;
+ bool autoDirectoryFollowing;
+
+ KURL::List& parseSelectedURLs() const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KFileDialogPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/tdefilefiltercombo.cpp b/tdeio/tdefile/tdefilefiltercombo.cpp
new file mode 100644
index 000000000..cd7bd54d3
--- /dev/null
+++ b/tdeio/tdefile/tdefilefiltercombo.cpp
@@ -0,0 +1,203 @@
+/* This file is part of the KDE libraries
+ Copyright (C) Stephan Kulow <coolo@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 <klocale.h>
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+#include <config-tdefile.h>
+
+#include "tdefilefiltercombo.h"
+
+class KFileFilterCombo::KFileFilterComboPrivate
+{
+public:
+ KFileFilterComboPrivate() {
+ hasAllSupportedFiles = false;
+ defaultFilter = i18n("*|All Files");
+ isMimeFilter = false;
+ }
+
+ // when we have more than 3 mimefilters and no default-filter,
+ // we don't show the comments of all mimefilters in one line,
+ // instead we show "All supported files". We have to translate
+ // that back to the list of mimefilters in currentFilter() tho.
+ bool hasAllSupportedFiles;
+ // true when setMimeFilter was called
+ bool isMimeFilter;
+ TQString lastFilter;
+ TQString defaultFilter;
+};
+
+KFileFilterCombo::KFileFilterCombo( TQWidget *parent, const char *name)
+ : KComboBox(true, parent, name), d( new KFileFilterComboPrivate )
+{
+ setTrapReturnKey( true );
+ setInsertionPolicy(NoInsertion);
+ connect( this, TQT_SIGNAL( activated( int )), this, TQT_SIGNAL( filterChanged() ));
+ connect( this, TQT_SIGNAL( returnPressed() ), this, TQT_SIGNAL( filterChanged() ));
+ connect( this, TQT_SIGNAL( filterChanged() ), TQT_SLOT( slotFilterChanged() ));
+ m_allTypes = false;
+}
+
+KFileFilterCombo::~KFileFilterCombo()
+{
+ delete d;
+}
+
+void KFileFilterCombo::setFilter(const TQString& filter)
+{
+ clear();
+ filters.clear();
+ d->hasAllSupportedFiles = false;
+
+ if (!filter.isEmpty()) {
+ TQString tmp = filter;
+ int index = tmp.find('\n');
+ while (index > 0) {
+ filters.append(tmp.left(index));
+ tmp = tmp.mid(index + 1);
+ index = tmp.find('\n');
+ }
+ filters.append(tmp);
+ }
+ else
+ filters.append( d->defaultFilter );
+
+ TQStringList::ConstIterator it;
+ TQStringList::ConstIterator end(filters.end());
+ for (it = filters.begin(); it != end; ++it) {
+ int tab = (*it).find('|');
+ insertItem((tab < 0) ? *it :
+ (*it).mid(tab + 1));
+ }
+
+ d->lastFilter = currentText();
+ d->isMimeFilter = false;
+}
+
+TQString KFileFilterCombo::currentFilter() const
+{
+ TQString f = currentText();
+ if (f == text(currentItem())) { // user didn't edit the text
+ f = *filters.at(currentItem());
+ if ( d->isMimeFilter || (currentItem() == 0 && d->hasAllSupportedFiles) ) {
+ return f; // we have a mimetype as filter
+ }
+ }
+
+ int tab = f.find('|');
+ if (tab < 0)
+ return f;
+ else
+ return f.left(tab);
+}
+
+void KFileFilterCombo::setCurrentFilter( const TQString& filter )
+{
+ int pos = 0;
+ for( TQStringList::ConstIterator it = filters.begin();
+ it != filters.end();
+ ++it, ++pos ) {
+ if( *it == filter ) {
+ setCurrentItem( pos );
+ filterChanged();
+ return;
+ }
+ }
+ setCurrentText( filter );
+ filterChanged();
+}
+
+void KFileFilterCombo::setMimeFilter( const TQStringList& types,
+ const TQString& defaultType )
+{
+ clear();
+ filters.clear();
+ TQString delim = TQString::fromLatin1(", ");
+ d->hasAllSupportedFiles = false;
+
+ m_allTypes = defaultType.isEmpty() && (types.count() > 1);
+
+ TQString allComments, allTypes;
+ int i = 0;
+ for(TQStringList::ConstIterator it = types.begin(); it != types.end(); ++it, ++i)
+ {
+ if ( m_allTypes && it != types.begin() ) {
+ allComments += delim;
+ allTypes += ' ';
+ }
+
+ kdDebug(tdefile_area) << *it << endl;
+ KMimeType::Ptr type = KMimeType::mimeType( *it );
+ filters.append( type->name() );
+ if ( m_allTypes )
+ {
+ allTypes += type->name();
+ allComments += type->comment();
+ }
+ insertItem( type->comment() );
+ if ( type->name() == defaultType )
+ setCurrentItem( i );
+ }
+
+ if ( m_allTypes )
+ {
+ if ( i < 3 ) // show the mime-comments of at max 3 types
+ insertItem( allComments, 0 );
+ else {
+ insertItem( i18n("All Supported Files"), 0 );
+ d->hasAllSupportedFiles = true;
+ }
+
+ filters.prepend( allTypes );
+ }
+
+ d->lastFilter = currentText();
+ d->isMimeFilter = true;
+}
+
+void KFileFilterCombo::slotFilterChanged()
+{
+ d->lastFilter = currentText();
+}
+
+bool KFileFilterCombo::eventFilter( TQObject *o, TQEvent *e )
+{
+ if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(lineEdit()) && e->type() == TQEvent::FocusOut ) {
+ if ( currentText() != d->lastFilter )
+ emit filterChanged();
+ }
+
+ return KComboBox::eventFilter( o, e );
+}
+
+void KFileFilterCombo::setDefaultFilter( const TQString& filter )
+{
+ d->defaultFilter = filter;
+}
+
+TQString KFileFilterCombo::defaultFilter() const
+{
+ return d->defaultFilter;
+}
+
+void KFileFilterCombo::virtual_hook( int id, void* data )
+{ KComboBox::virtual_hook( id, data ); }
+
+#include "tdefilefiltercombo.moc"
diff --git a/tdeio/tdefile/tdefilefiltercombo.h b/tdeio/tdefile/tdefilefiltercombo.h
new file mode 100644
index 000000000..589376d0c
--- /dev/null
+++ b/tdeio/tdefile/tdefilefiltercombo.h
@@ -0,0 +1,104 @@
+/* This file is part of the KDE libraries
+ Copyright (C) Stephan Kulow <coolo@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 KFILEFILTERCOMBO_H
+#define KFILEFILTERCOMBO_H
+
+#include <tqstringlist.h>
+#include <tqptrdict.h>
+
+#include <kcombobox.h>
+#include <kmimetype.h>
+
+class KFileFilterComboPrivate;
+
+class TDEIO_EXPORT KFileFilterCombo : public KComboBox
+{
+ Q_OBJECT
+
+ public:
+ KFileFilterCombo(TQWidget *parent= 0, const char *name= 0);
+ ~KFileFilterCombo();
+
+ void setFilter(const TQString& filter);
+
+ /**
+ * @returns the current filter, either something like "*.cpp *.h"
+ * or the current mimetype, like "text/html", or a list of those, like
+ " "text/html text/plain image/png", all separated with one space.
+ */
+ TQString currentFilter() const;
+
+ /**
+ * Sets the current filter. Filter must match one of the filter items
+ * passed before to this widget.
+ * @since 3.4
+ */
+ void setCurrentFilter( const TQString& filter );
+
+ /**
+ * Sets a list of mimetypes.
+ * If @p defaultType is set, it will be set as the current item.
+ * Otherwise, a first item showing all the mimetypes will be created.
+ */
+ void setMimeFilter( const TQStringList& types, const TQString& defaultType );
+
+ /**
+ * @return true if the filter's first item is the list of all mimetypes
+ */
+ bool showsAllTypes() const { return m_allTypes; }
+
+ /**
+ * This method allows you to set a default-filter, that is used when an
+ * empty filter is set. Make sure you call this before calling
+ * setFilter().
+ *
+ * By default, this is set to i18n("*|All Files")
+ * @see defaultFilter
+ */
+ void setDefaultFilter( const TQString& filter );
+
+ /**
+ * @return the default filter, used when an empty filter is set.
+ * @see setDefaultFilter
+ */
+ TQString defaultFilter() const;
+
+ protected:
+ virtual bool eventFilter( TQObject *o, TQEvent *e );
+
+// KDE4: those variables are private. filters() was added
+ TQStringList filters;
+ bool m_allTypes;
+
+ signals:
+ void filterChanged();
+
+private slots:
+ void slotFilterChanged();
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ friend class KFileDialog; // gone in KDE4
+ class KFileFilterComboPrivate;
+ KFileFilterComboPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/tdefileiconview.cpp b/tdeio/tdefile/tdefileiconview.cpp
new file mode 100644
index 000000000..474364042
--- /dev/null
+++ b/tdeio/tdefile/tdefileiconview.cpp
@@ -0,0 +1,943 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ 2000,2001,2002 Carsten Pfeiffer <pfeiffer@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 <tqt.h>
+
+#include <tqfontmetrics.h>
+#include <tqkeycode.h>
+#include <tqlabel.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqregexp.h>
+#include <tqtimer.h>
+#include <tqtooltip.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <tdefileitem.h>
+#include <kiconeffect.h>
+#include <kglobalsettings.h>
+#include <kurldrag.h>
+#include <tdeio/previewjob.h>
+
+#include "tdefileiconview.h"
+#include "config-tdefile.h"
+
+#define DEFAULT_PREVIEW_SIZE 60
+#define DEFAULT_SHOW_PREVIEWS false
+#define DEFAULT_VIEW_MODE "SmallColumns"
+
+KFileIconViewItem::~KFileIconViewItem()
+{
+ fileInfo()->removeExtraData( iconView() );
+}
+
+class KFileIconView::KFileIconViewPrivate
+{
+public:
+ KFileIconViewPrivate( KFileIconView *parent ) {
+ previewIconSize = 60;
+ job = 0;
+ dropItem = 0;
+
+ noArrangement = false;
+ ignoreMaximumSize = false;
+ smallColumns = new KRadioAction( i18n("Small Icons"), 0, TQT_TQOBJECT(parent),
+ TQT_SLOT( slotSmallColumns() ),
+ parent->actionCollection(),
+ "small columns" );
+
+ largeRows = new KRadioAction( i18n("Large Icons"), 0, TQT_TQOBJECT(parent),
+ TQT_SLOT( slotLargeRows() ),
+ parent->actionCollection(),
+ "large rows" );
+
+ smallColumns->setExclusiveGroup(TQString::fromLatin1("IconView mode"));
+ largeRows->setExclusiveGroup(TQString::fromLatin1("IconView mode"));
+
+ previews = new KToggleAction( i18n("Thumbnail Previews"), 0,
+ parent->actionCollection(),
+ "show previews" );
+ zoomIn = KStdAction::zoomIn( TQT_TQOBJECT(parent), TQT_SLOT( zoomIn() ),
+ parent->actionCollection(), "zoomIn" );
+ zoomOut = KStdAction::zoomOut( TQT_TQOBJECT(parent), TQT_SLOT( zoomOut() ),
+ parent->actionCollection(), "zoomOut" );
+
+ previews->setGroup("previews");
+ zoomIn->setGroup("previews");
+ zoomOut->setGroup("previews");
+
+ connect( previews, TQT_SIGNAL( toggled( bool )),
+ parent, TQT_SLOT( slotPreviewsToggled( bool )));
+
+ connect( &previewTimer, TQT_SIGNAL( timeout() ),
+ parent, TQT_SLOT( showPreviews() ));
+ connect( &autoOpenTimer, TQT_SIGNAL( timeout() ),
+ parent, TQT_SLOT( slotAutoOpen() ));
+ }
+
+ ~KFileIconViewPrivate() {
+ if ( job )
+ job->kill();
+ }
+
+ KRadioAction *smallColumns, *largeRows;
+ KAction *zoomIn, *zoomOut;
+ KToggleAction *previews;
+ TDEIO::PreviewJob *job;
+ KFileIconViewItem *dropItem;
+ TQTimer previewTimer;
+ TQTimer autoOpenTimer;
+ TQStringList previewMimeTypes;
+ int previewIconSize;
+ bool noArrangement :1;
+ bool ignoreMaximumSize :1;
+};
+
+KFileIconView::KFileIconView(TQWidget *parent, const char *name)
+ : KIconView(parent, name), KFileView()
+{
+ d = new KFileIconViewPrivate( this );
+
+ setViewName( i18n("Icon View") );
+
+ toolTip = 0;
+ setResizeMode( Adjust );
+ setMaxItemWidth( 300 );
+ setWordWrapIconText( false );
+ setArrangement( TopToBottom );
+ setAutoArrange( true );
+ setItemsMovable( false );
+ setMode( KIconView::Select );
+ KIconView::setSorting( true );
+ // as long as TQIconView only shows tooltips when the cursor is over the
+ // icon (and not the text), we have to create our own tooltips
+ setShowToolTips( false );
+ slotSmallColumns();
+ d->smallColumns->setChecked( true );
+
+ connect( this, TQT_SIGNAL( returnPressed(TQIconViewItem *) ),
+ TQT_SLOT( slotActivate( TQIconViewItem *) ) );
+
+ // we want single click _and_ double click (as convenience)
+ connect( this, TQT_SIGNAL( clicked(TQIconViewItem *, const TQPoint&) ),
+ TQT_SLOT( selected( TQIconViewItem *) ) );
+ connect( this, TQT_SIGNAL( doubleClicked(TQIconViewItem *, const TQPoint&) ),
+ TQT_SLOT( slotActivate( TQIconViewItem *) ) );
+
+ connect( this, TQT_SIGNAL( onItem( TQIconViewItem * ) ),
+ TQT_SLOT( showToolTip( TQIconViewItem * ) ) );
+ connect( this, TQT_SIGNAL( onViewport() ),
+ TQT_SLOT( removeToolTip() ) );
+ connect( this, TQT_SIGNAL( contextMenuRequested(TQIconViewItem*,const TQPoint&)),
+ TQT_SLOT( slotActivateMenu( TQIconViewItem*, const TQPoint& ) ) );
+
+ KFile::SelectionMode sm = KFileView::selectionMode();
+ switch ( sm ) {
+ case KFile::Multi:
+ TQIconView::setSelectionMode( TQIconView::Multi );
+ break;
+ case KFile::Extended:
+ TQIconView::setSelectionMode( TQIconView::Extended );
+ break;
+ case KFile::NoSelection:
+ TQIconView::setSelectionMode( TQIconView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ TQIconView::setSelectionMode( TQIconView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( slotSelectionChanged() ));
+ else
+ connect( this, TQT_SIGNAL( selectionChanged( TQIconViewItem * )),
+ TQT_SLOT( highlighted( TQIconViewItem * )));
+
+ viewport()->installEventFilter( this );
+
+ // for mimetype resolving
+ m_resolver = new KMimeTypeResolver<KFileIconViewItem,KFileIconView>(this);
+}
+
+KFileIconView::~KFileIconView()
+{
+ delete m_resolver;
+ removeToolTip();
+ delete d;
+}
+
+void KFileIconView::readConfig( TDEConfig *kc, const TQString& group )
+{
+ TQString gr = group.isEmpty() ? TQString("KFileIconView") : group;
+ TDEConfigGroupSaver cs( kc, gr );
+ TQString small = TQString::fromLatin1("SmallColumns");
+ d->previewIconSize = kc->readNumEntry( "Preview Size", DEFAULT_PREVIEW_SIZE );
+ d->previews->setChecked( kc->readBoolEntry( "ShowPreviews", DEFAULT_SHOW_PREVIEWS ) );
+
+ if ( kc->readEntry("ViewMode", DEFAULT_VIEW_MODE ) == small ) {
+ d->smallColumns->setChecked( true );
+ slotSmallColumns();
+ }
+ else {
+ d->largeRows->setChecked( true );
+ slotLargeRows();
+ }
+
+ if ( d->previews->isChecked() )
+ showPreviews();
+}
+
+void KFileIconView::writeConfig( TDEConfig *kc, const TQString& group )
+{
+ TQString gr = group.isEmpty() ? TQString("KFileIconView") : group;
+ TDEConfigGroupSaver cs( kc, gr );
+
+ TQString viewMode = d->smallColumns->isChecked() ?
+ TQString::fromLatin1("SmallColumns") :
+ TQString::fromLatin1("LargeRows");
+ if(!kc->hasDefault( "ViewMode" ) && viewMode == DEFAULT_VIEW_MODE )
+ kc->revertToDefault( "ViewMode" );
+ else
+ kc->writeEntry( "ViewMode", viewMode );
+
+ int previewsIconSize = d->previewIconSize;
+ if(!kc->hasDefault( "Preview Size" ) && previewsIconSize == DEFAULT_PREVIEW_SIZE )
+ kc->revertToDefault( "Preview Size" );
+ else
+ kc->writeEntry( "Preview Size", previewsIconSize );
+
+ bool showPreviews = d->previews->isChecked();
+ if(!kc->hasDefault( "ShowPreviews" ) && showPreviews == DEFAULT_SHOW_PREVIEWS )
+ kc->revertToDefault( "ShowPreviews" );
+ else
+ kc->writeEntry( "ShowPreviews", showPreviews );
+}
+
+void KFileIconView::removeToolTip()
+{
+ delete toolTip;
+ toolTip = 0;
+}
+
+void KFileIconView::showToolTip( TQIconViewItem *item )
+{
+ delete toolTip;
+ toolTip = 0;
+
+ if ( !item )
+ return;
+
+ int w = maxItemWidth() - ( itemTextPos() == TQIconView::Bottom ? 0 :
+ item->pixmapRect().width() ) - 4;
+ if ( fontMetrics().width( item->text() ) >= w ) {
+ toolTip = new TQLabel( TQString::fromLatin1(" %1 ").arg(item->text()), 0,
+ "myToolTip",
+ (WFlags)(WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM) );
+ toolTip->setFrameStyle( TQFrame::Plain | TQFrame::Box );
+ toolTip->setLineWidth( 1 );
+ toolTip->setAlignment( AlignLeft | AlignTop );
+ toolTip->move( TQCursor::pos() + TQPoint( 14, 14 ) );
+ toolTip->adjustSize();
+ TQRect screen = TQApplication::desktop()->screenGeometry(
+ TQApplication::desktop()->screenNumber(TQCursor::pos()));
+ if (toolTip->x()+toolTip->width() > screen.right()) {
+ toolTip->move(toolTip->x()+screen.right()-toolTip->x()-toolTip->width(), toolTip->y());
+ }
+ if (toolTip->y()+toolTip->height() > screen.bottom()) {
+ toolTip->move(toolTip->x(), screen.bottom()-toolTip->y()-toolTip->height()+toolTip->y());
+ }
+ toolTip->setFont( TQToolTip::font() );
+ toolTip->setPalette( TQToolTip::palette(), true );
+ toolTip->show();
+ }
+}
+
+void KFileIconView::slotActivateMenu( TQIconViewItem* item, const TQPoint& pos )
+{
+ if ( !item ) {
+ sig->activateMenu( 0, pos );
+ return;
+ }
+ KFileIconViewItem *i = (KFileIconViewItem*) item;
+ sig->activateMenu( i->fileInfo(), pos );
+}
+
+void KFileIconView::hideEvent( TQHideEvent *e )
+{
+ removeToolTip();
+ KIconView::hideEvent( e );
+}
+
+void KFileIconView::keyPressEvent( TQKeyEvent *e )
+{
+ KIconView::keyPressEvent( e );
+
+ // ignore Ctrl-Return so that the dialog can catch it.
+ if ( (e->state() & ControlButton) &&
+ (e->key() == Key_Return || e->key() == Key_Enter) )
+ e->ignore();
+}
+
+void KFileIconView::setSelected( const KFileItem *info, bool enable )
+{
+ KFileIconViewItem *item = viewItem( info );
+ if ( item )
+ KIconView::setSelected( item, enable, true );
+}
+
+void KFileIconView::selectAll()
+{
+ if (KFileView::selectionMode() == KFile::NoSelection ||
+ KFileView::selectionMode() == KFile::Single)
+ return;
+
+ KIconView::selectAll( true );
+}
+
+void KFileIconView::clearSelection()
+{
+ KIconView::clearSelection();
+}
+
+void KFileIconView::invertSelection()
+{
+ KIconView::invertSelection();
+}
+
+void KFileIconView::clearView()
+{
+ m_resolver->m_lstPendingMimeIconItems.clear();
+
+ KIconView::clear();
+ stopPreview();
+}
+
+void KFileIconView::insertItem( KFileItem *i )
+{
+ KFileView::insertItem( i );
+
+ TQIconView* qview = static_cast<TQIconView*>( this );
+ // Since creating and initializing an item leads to a repaint,
+ // we disable updates on the IconView for a while.
+ qview->setUpdatesEnabled( false );
+ KFileIconViewItem *item = new KFileIconViewItem( qview, i );
+ initItem( item, i, true );
+ qview->setUpdatesEnabled( true );
+
+ if ( !i->isMimeTypeKnown() )
+ m_resolver->m_lstPendingMimeIconItems.append( item );
+
+ i->setExtraData( this, item );
+}
+
+void KFileIconView::slotActivate( TQIconViewItem *item )
+{
+ if ( !item )
+ return;
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->activate( fi );
+}
+
+void KFileIconView::selected( TQIconViewItem *item )
+{
+ if ( !item || (TDEApplication::keyboardMouseState() & (ShiftButton | ControlButton)) != 0 )
+ return;
+
+ if ( TDEGlobalSettings::singleClick() ) {
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
+ sig->activate( fi );
+ }
+}
+
+void KFileIconView::setCurrentItem( const KFileItem *item )
+{
+ KFileIconViewItem *it = viewItem( item );
+ if ( it )
+ KIconView::setCurrentItem( it );
+}
+
+KFileItem * KFileIconView::currentFileItem() const
+{
+ KFileIconViewItem *current = static_cast<KFileIconViewItem*>( currentItem() );
+ if ( current )
+ return current->fileInfo();
+
+ return 0L;
+}
+
+void KFileIconView::highlighted( TQIconViewItem *item )
+{
+ if ( !item )
+ return;
+ const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
+ if ( fi )
+ sig->highlightFile( fi );
+}
+
+void KFileIconView::setSelectionMode( KFile::SelectionMode sm )
+{
+ disconnect( TQT_SIGNAL( selectionChanged() ), this );
+ disconnect( TQT_SIGNAL( selectionChanged( TQIconViewItem * )), this );
+
+ KFileView::setSelectionMode( sm );
+ switch ( KFileView::selectionMode() ) {
+ case KFile::Multi:
+ TQIconView::setSelectionMode( TQIconView::Multi );
+ break;
+ case KFile::Extended:
+ TQIconView::setSelectionMode( TQIconView::Extended );
+ break;
+ case KFile::NoSelection:
+ TQIconView::setSelectionMode( TQIconView::NoSelection );
+ break;
+ default: // fall through
+ case KFile::Single:
+ TQIconView::setSelectionMode( TQIconView::Single );
+ break;
+ }
+
+ if ( sm == KFile::Multi || sm == KFile::Extended )
+ connect( this, TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( slotSelectionChanged() ));
+ else
+ connect( this, TQT_SIGNAL( selectionChanged( TQIconViewItem * )),
+ TQT_SLOT( highlighted( TQIconViewItem * )));
+}
+
+bool KFileIconView::isSelected( const KFileItem *i ) const
+{
+ KFileIconViewItem *item = viewItem( i );
+ return (item && item->isSelected());
+}
+
+void KFileIconView::updateView( bool b )
+{
+ if ( !b )
+ return; // eh?
+
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>(TQIconView::firstItem());
+ if ( item ) {
+ do {
+ if ( d->previews->isChecked() ) {
+ if ( canPreview( item->fileInfo() ) )
+ item->setPixmapSize( TQSize( d->previewIconSize, d->previewIconSize ) );
+ }
+ else {
+ // unset pixmap size (used for previews)
+ if ( !item->pixmapSize().isNull() )
+ item->setPixmapSize( TQSize( 0, 0 ) );
+ }
+ // recalculate item parameters but avoid an in-place repaint
+ item->setPixmap( (item->fileInfo())->pixmap( myIconSize ), true, false );
+ item = static_cast<KFileIconViewItem *>(item->nextItem());
+ } while ( item != 0L );
+ }
+}
+
+void KFileIconView::updateView( const KFileItem *i )
+{
+ KFileIconViewItem *item = viewItem( i );
+ if ( item )
+ initItem( item, i, true );
+}
+
+void KFileIconView::removeItem( const KFileItem *i )
+{
+ if ( !i )
+ return;
+
+ if ( d->job )
+ d->job->removeItem( i );
+
+ KFileIconViewItem *item = viewItem( i );
+ m_resolver->m_lstPendingMimeIconItems.remove( item );
+ delete item;
+
+ KFileView::removeItem( i );
+}
+
+void KFileIconView::setIconSize( int size )
+{
+ myIconSize = size;
+ updateIcons();
+}
+
+void KFileIconView::setPreviewSize( int size )
+{
+ if ( size < 30 )
+ size = 30; // minimum
+
+ d->previewIconSize = size;
+ if ( d->previews->isChecked() )
+ showPreviews();
+}
+
+void KFileIconView::setIgnoreMaximumSize(bool ignoreSize)
+{
+ d->ignoreMaximumSize = ignoreSize;
+}
+
+void KFileIconView::updateIcons()
+{
+ updateView( true );
+ arrangeItemsInGrid();
+}
+
+void KFileIconView::ensureItemVisible( const KFileItem *i )
+{
+ KFileIconViewItem *item = viewItem( i );
+ if ( item )
+ KIconView::ensureItemVisible( item );
+}
+
+void KFileIconView::slotSelectionChanged()
+{
+ sig->highlightFile( 0L );
+}
+
+void KFileIconView::slotSmallColumns()
+{
+ // setItemTextPos(), setArrangement(), setWordWrapIconText() and
+ // setIconSize() all call arrangeItemsInGrid() :( Prevent this.
+ d->noArrangement = true; // stop arrangeItemsInGrid()!
+
+ // Make sure to uncheck previews if selected
+ if ( d->previews->isChecked() )
+ {
+ stopPreview();
+ d->previews->setChecked( false );
+ }
+ setGridX( -1 );
+ setMaxItemWidth( 300 );
+ setItemTextPos( Right );
+ setArrangement( TopToBottom );
+ setWordWrapIconText( false );
+ setSpacing( 0 );
+
+ d->noArrangement = false; // now we can arrange
+ setIconSize( KIcon::SizeSmall );
+}
+
+void KFileIconView::slotLargeRows()
+{
+ // setItemTextPos(), setArrangement(), setWordWrapIconText() and
+ // setIconSize() all call arrangeItemsInGrid() :( Prevent this.
+ d->noArrangement = true; // stop arrangeItemsInGrid()!
+
+ setGridX( TDEGlobal::iconLoader()->currentSize( KIcon::Desktop ) + 50 );
+ setItemTextPos( Bottom );
+ setArrangement( LeftToRight );
+ setWordWrapIconText( true );
+ setSpacing( 5 ); // default in QIconView
+
+ d->noArrangement = false; // now we can arrange
+ setIconSize( KIcon::SizeMedium );
+}
+
+void KFileIconView::stopPreview()
+{
+ if ( d->job ) {
+ d->job->kill();
+ d->job = 0L;
+ }
+}
+
+void KFileIconView::slotPreviewsToggled( bool on )
+{
+ if ( on )
+ showPreviews();
+ else {
+ stopPreview();
+ slotLargeRows();
+ }
+}
+
+void KFileIconView::showPreviews()
+{
+ if ( d->previewMimeTypes.isEmpty() )
+ d->previewMimeTypes = TDEIO::PreviewJob::supportedMimeTypes();
+
+ stopPreview();
+ d->previews->setChecked( true );
+
+ if ( !d->largeRows->isChecked() ) {
+ d->largeRows->setChecked( true );
+ slotLargeRows(); // also sets the icon size and updates the grid
+ }
+ else {
+ updateIcons();
+ }
+
+ d->job = TDEIO::filePreview(*items(), d->previewIconSize,d->previewIconSize);
+ d->job->setIgnoreMaximumSize(d->ignoreMaximumSize);
+
+ connect( d->job, TQT_SIGNAL( result( TDEIO::Job * )),
+ this, TQT_SLOT( slotPreviewResult( TDEIO::Job * )));
+ connect( d->job, TQT_SIGNAL( gotPreview( const KFileItem*, const TQPixmap& )),
+ TQT_SLOT( gotPreview( const KFileItem*, const TQPixmap& ) ));
+// connect( d->job, TQT_SIGNAL( failed( const KFileItem* )),
+// this, TQT_SLOT( slotFailed( const KFileItem* ) ));
+}
+
+void KFileIconView::slotPreviewResult( TDEIO::Job *job )
+{
+ if ( job == d->job )
+ d->job = 0L;
+}
+
+void KFileIconView::gotPreview( const KFileItem *item, const TQPixmap& pix )
+{
+ KFileIconViewItem *it = viewItem( item );
+ if ( it )
+ if( item->overlays() & KIcon::HiddenOverlay )
+ {
+ TQPixmap p( pix );
+
+ KIconEffect::semiTransparent( p );
+ it->setPixmap( p );
+ }
+ else
+ it->setPixmap( pix );
+}
+
+bool KFileIconView::canPreview( const KFileItem *item ) const
+{
+ TQStringList::Iterator it = d->previewMimeTypes.begin();
+ TQRegExp r;
+ r.setWildcard( true );
+
+ for ( ; it != d->previewMimeTypes.end(); ++it ) {
+ TQString type = *it;
+ // the "mimetype" can be "image/*"
+ if ( type.at( type.length() - 1 ) == '*' ) {
+ r.setPattern( type );
+ if ( r.search( item->mimetype() ) != -1 )
+ return true;
+ }
+ else
+ if ( item->mimetype() == type )
+ return true;
+ }
+
+ return false;
+}
+
+KFileItem * KFileIconView::firstFileItem() const
+{
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>( firstItem() );
+ if ( item )
+ return item->fileInfo();
+ return 0L;
+}
+
+KFileItem * KFileIconView::nextItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileIconViewItem *item = viewItem( fileItem );
+ if ( item && item->nextItem() )
+ return ((KFileIconViewItem*) item->nextItem())->fileInfo();
+ }
+ return 0L;
+}
+
+KFileItem * KFileIconView::prevItem( const KFileItem *fileItem ) const
+{
+ if ( fileItem ) {
+ KFileIconViewItem *item = viewItem( fileItem );
+ if ( item && item->prevItem() )
+ return ((KFileIconViewItem*) item->prevItem())->fileInfo();
+ }
+ return 0L;
+}
+
+void KFileIconView::setSorting( TQDir::SortSpec spec )
+{
+ KFileView::setSorting( spec );
+ KFileItemListIterator it( *items() );
+
+ KFileItem *item;
+
+ if ( spec & TQDir::Time ) {
+ for ( ; (item = it.current()); ++it )
+ // warning, time_t is often signed -> cast it
+ viewItem(item)->setKey( sortingKey( (unsigned long)item->time( TDEIO::UDS_MODIFICATION_TIME ), item->isDir(), spec ));
+ }
+
+ else if ( spec & TQDir::Size ) {
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
+ spec ));
+ }
+ else { // Name or Unsorted
+ for ( ; (item = it.current()); ++it )
+ viewItem(item)->setKey( sortingKey( item->text(), item->isDir(),
+ spec ));
+ }
+
+ KIconView::setSorting( true, !isReversed() );
+ sort( !isReversed() );
+}
+
+//
+// mimetype determination on demand
+//
+void KFileIconView::mimeTypeDeterminationFinished()
+{
+ // anything to do?
+}
+
+void KFileIconView::determineIcon( KFileIconViewItem *item )
+{
+ (void) item->fileInfo()->determineMimeType();
+ updateView( item->fileInfo() );
+}
+
+void KFileIconView::listingCompleted()
+{
+ arrangeItemsInGrid();
+
+ // TQIconView doesn't set the current item automatically, so we have to do
+ // that. We don't want to emit selectionChanged() tho.
+ if ( !currentItem() ) {
+ bool block = signalsBlocked();
+ blockSignals( true );
+ TQIconViewItem *item = viewItem( firstFileItem() );
+ KIconView::setCurrentItem( item );
+ KIconView::setSelected( item, false );
+ blockSignals( block );
+ }
+
+ m_resolver->start( d->previews->isChecked() ? 0 : 10 );
+}
+
+// need to remove our tooltip, eventually
+bool KFileIconView::eventFilter( TQObject *o, TQEvent *e )
+{
+ if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(viewport()) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(this) ) {
+ int type = e->type();
+ if ( type == TQEvent::Leave ||
+ type == TQEvent::FocusOut )
+ removeToolTip();
+ }
+
+ return KIconView::eventFilter( o, e );
+}
+
+/////////////////////////////////////////////////////////////////
+
+// ### workaround for Qt3 Bug
+void KFileIconView::showEvent( TQShowEvent *e )
+{
+ KIconView::showEvent( e );
+}
+
+
+void KFileIconView::initItem( KFileIconViewItem *item, const KFileItem *i,
+ bool updateTextAndPixmap )
+{
+ if ( d->previews->isChecked() && canPreview( i ) )
+ item->setPixmapSize( TQSize( d->previewIconSize, d->previewIconSize ) );
+
+ if ( updateTextAndPixmap )
+ {
+ // this causes a repaint of the item, which we want to avoid during
+ // directory listing, when all items are created. We want to paint all
+ // items at once, not every single item in that case.
+ item->setText( i->text() , false, false );
+ item->setPixmap( i->pixmap( myIconSize ) );
+ }
+
+ // see also setSorting()
+ TQDir::SortSpec spec = KFileView::sorting();
+
+ if ( spec & TQDir::Time )
+ // warning, time_t is often signed -> cast it
+ item->setKey( sortingKey( (unsigned long) i->time( TDEIO::UDS_MODIFICATION_TIME ),
+ i->isDir(), spec ));
+ else if ( spec & TQDir::Size )
+ item->setKey( sortingKey( i->size(), i->isDir(), spec ));
+
+ else // Name or Unsorted
+ item->setKey( sortingKey( i->text(), i->isDir(), spec ));
+
+ //tqDebug("** key for: %s: %s", i->text().latin1(), item->key().latin1());
+
+ if ( d->previews->isChecked() )
+ d->previewTimer.start( 10, true );
+}
+
+void KFileIconView::arrangeItemsInGrid( bool update )
+{
+ if ( d->noArrangement )
+ return;
+
+ KIconView::arrangeItemsInGrid( update );
+}
+
+void KFileIconView::zoomIn()
+{
+ setPreviewSize( d->previewIconSize + 30 );
+}
+
+void KFileIconView::zoomOut()
+{
+ setPreviewSize( d->previewIconSize - 30 );
+}
+
+TQDragObject *KFileIconView::dragObject()
+{
+ // create a list of the URL:s that we want to drag
+ KURL::List urls;
+ KFileItemListIterator it( * KFileView::selectedItems() );
+ for ( ; it.current(); ++it ){
+ urls.append( (*it)->url() );
+ }
+ TQPixmap pixmap;
+ if( urls.count() > 1 )
+ pixmap = DesktopIcon( "tdemultiple", iconSize() );
+ if( pixmap.isNull() )
+ pixmap = currentFileItem()->pixmap( iconSize() );
+
+ TQPoint hotspot;
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ TQDragObject* myDragObject = new KURLDrag( urls, widget() );
+ myDragObject->setPixmap( pixmap, hotspot );
+ return myDragObject;
+}
+
+void KFileIconView::slotAutoOpen()
+{
+ d->autoOpenTimer.stop();
+ if( !d->dropItem )
+ return;
+
+ KFileItem *fileItem = d->dropItem->fileInfo();
+ if (!fileItem)
+ return;
+
+ if( fileItem->isFile() )
+ return;
+
+ if ( fileItem->isDir() || fileItem->isLink())
+ sig->activate( fileItem );
+}
+
+bool KFileIconView::acceptDrag(TQDropEvent* e) const
+{
+ return KURLDrag::canDecode( e ) &&
+ (e->source()!=const_cast<KFileIconView*>(this)) &&
+ ( e->action() == TQDropEvent::Copy
+ || e->action() == TQDropEvent::Move
+ || e->action() == TQDropEvent::Link );
+}
+
+void KFileIconView::contentsDragEnterEvent( TQDragEnterEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileIconView::contentsDragMoveEvent( TQDragMoveEvent *e )
+{
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ if ((dropOptions() & AutoOpenDirs) == 0)
+ return;
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ if ( item ) { // are we over an item ?
+ if (d->dropItem != item)
+ {
+ d->dropItem = item;
+ d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
+ }
+ }
+ else
+ {
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+ }
+}
+
+void KFileIconView::contentsDragLeaveEvent( TQDragLeaveEvent * )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+}
+
+void KFileIconView::contentsDropEvent( TQDropEvent *e )
+{
+ d->dropItem = 0;
+ d->autoOpenTimer.stop();
+
+ if ( ! acceptDrag( e ) ) { // can we decode this ?
+ e->ignore(); // No
+ return;
+ }
+ e->acceptAction(); // Yes
+
+ KFileIconViewItem *item = dynamic_cast<KFileIconViewItem*>(findItem( contentsToViewport( e->pos() ) ));
+ KFileItem * fileItem = 0;
+ if (item)
+ fileItem = item->fileInfo();
+
+ emit dropped(e, fileItem);
+
+ KURL::List urls;
+ if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
+ {
+ emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
+ sig->dropURLs(fileItem, e, urls);
+ }
+}
+
+void KFileIconView::virtual_hook( int id, void* data )
+{ KIconView::virtual_hook( id, data );
+ KFileView::virtual_hook( id, data ); }
+
+#include "tdefileiconview.moc"
diff --git a/tdeio/tdefile/tdefileiconview.h b/tdeio/tdefile/tdefileiconview.h
new file mode 100644
index 000000000..0b7c7877e
--- /dev/null
+++ b/tdeio/tdefile/tdefileiconview.h
@@ -0,0 +1,267 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@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 KFILEICONVIEW_H
+#define KFILEICONVIEW_H
+
+#include <tqt.h>
+
+#include <kiconview.h>
+#include <kiconloader.h>
+#include <tdefileview.h>
+#include <kmimetyperesolver.h>
+#include <tdefile.h>
+
+class KFileItem;
+class TQWidget;
+class TQLabel;
+
+/**
+ * An item for the iconview, that has a reference to its corresponding
+ * KFileItem.
+ */
+class TDEIO_EXPORT KFileIconViewItem : public KIconViewItem
+{
+public:
+ KFileIconViewItem( TQIconView *parent, const TQString &text,
+ const TQPixmap &pixmap,
+ KFileItem *fi )
+ : KIconViewItem( parent, text, pixmap ), inf( fi ) {}
+ /**
+ * @since 3.1
+ */
+ KFileIconViewItem( TQIconView *parent, KFileItem *fi )
+ : KIconViewItem( parent ), inf( fi ) {}
+
+ virtual ~KFileIconViewItem();
+
+ /**
+ * @returns the corresponding KFileItem
+ */
+ KFileItem *fileInfo() const {
+ return inf;
+ }
+
+private:
+ KFileItem *inf;
+
+private:
+ class KFileIconViewItemPrivate;
+ KFileIconViewItemPrivate *d;
+
+};
+
+namespace TDEIO {
+ class Job;
+}
+
+/**
+ * An icon-view capable of showing KFileItem's. Used in the filedialog
+ * for example. Most of the documentation is in KFileView class.
+ *
+ * @see KDirOperator
+ * @see KCombiView
+ * @see KFileDetailView
+ */
+class TDEIO_EXPORT KFileIconView : public KIconView, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFileIconView(TQWidget *parent, const char *name);
+ virtual ~KFileIconView();
+
+ virtual TQWidget *widget() { return this; }
+ virtual void clearView();
+ virtual void setAutoUpdate( bool ) {} // ### unused. remove in KDE4
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem(const KFileItem*);
+
+ virtual void listingCompleted();
+
+ virtual void insertItem( KFileItem *i );
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected(const KFileItem *i) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ /**
+ * Sets the size of the icons to show. Defaults to KIcon::SizeSmall.
+ */
+ void setIconSize( int size );
+
+ /**
+ * Sets the size of the previews. Defaults to KIcon::SizeLarge.
+ */
+ void setPreviewSize( int size );
+
+ /**
+ * Disables the "Maximum file size" configuration option for previews
+ *
+ * Set this before calling showPreviews()
+ *
+ * @since 3.4
+ **/
+ void setIgnoreMaximumSize(bool ignoreSize=true);
+
+ /**
+ * @returns the current size used for icons.
+ */
+ int iconSize() const { return myIconSize; }
+
+ void ensureItemVisible( const KFileItem * );
+
+ virtual void setSorting(TQDir::SortSpec sort);
+
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null);
+
+ // for KMimeTypeResolver
+ void mimeTypeDeterminationFinished();
+ void determineIcon( KFileIconViewItem *item );
+ TQScrollView *scrollWidget() const { return (TQScrollView*) this; }
+ void setAcceptDrops(bool b)
+ {
+ KIconView::setAcceptDrops(b);
+ viewport()->setAcceptDrops(b);
+ }
+
+public slots:
+ /**
+ * Starts loading previews for all files shown and shows them. Switches
+ * into 'large rows' mode, if that isn't the current mode yet.
+ *
+ * @sa setIgnoreMaximumSize
+ */
+ void showPreviews();
+
+ void zoomIn();
+
+ void zoomOut();
+
+ /**
+ * Reimplemented for performance reasons.
+ * @since 3.1
+ */
+ virtual void arrangeItemsInGrid( bool updated = true );
+
+protected:
+ /**
+ * Reimplemented to not let TQIconView eat return-key events
+ */
+ virtual void keyPressEvent( TQKeyEvent * );
+
+ /**
+ * Reimplemented to remove an eventual tooltip
+ */
+ virtual void hideEvent( TQHideEvent * );
+
+ // ### workaround for Qt3 bug (see #35080)
+ virtual void showEvent( TQShowEvent * );
+
+ virtual bool eventFilter( TQObject *o, TQEvent *e );
+
+ // DND support
+ virtual TQDragObject *dragObject();
+ virtual void contentsDragEnterEvent( TQDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( TQDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( TQDragLeaveEvent *e );
+ virtual void contentsDropEvent( TQDropEvent *ev );
+
+ // KDE4: Make virtual
+ bool acceptDrag(TQDropEvent* e ) const;
+
+private slots:
+ void selected( TQIconViewItem *item );
+ void slotActivate( TQIconViewItem * );
+ void highlighted( TQIconViewItem *item );
+ void showToolTip( TQIconViewItem *item );
+ void removeToolTip();
+ void slotActivateMenu( TQIconViewItem *, const TQPoint& );
+ void slotSelectionChanged();
+
+ void slotSmallColumns();
+ void slotLargeRows();
+ void slotPreviewsToggled( bool );
+
+ void slotPreviewResult( TDEIO::Job * );
+ void gotPreview( const KFileItem *item, const TQPixmap& pix );
+ void slotAutoOpen();
+
+signals:
+ /**
+ * The user dropped something.
+ * @p fileItem points to the item dropped on or can be 0 if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(TQDropEvent *event, KFileItem *fileItem);
+ /**
+ * The user dropped the URLs @p urls.
+ * @p url points to the item dropped on or can be empty if the
+ * user dropped on empty space.
+ * @since 3.2
+ */
+ void dropped(TQDropEvent *event, const KURL::List &urls, const KURL &url);
+
+private:
+ KMimeTypeResolver<KFileIconViewItem,KFileIconView> *m_resolver;
+
+ TQLabel *toolTip;
+ int th;
+ int myIconSize;
+
+ virtual void insertItem(TQIconViewItem *a, TQIconViewItem *b) { KIconView::insertItem(a, b); }
+ virtual void setSelectionMode(TQIconView::SelectionMode m) { KIconView::setSelectionMode(m); }
+ virtual void setSelected(TQIconViewItem *i, bool a, bool b) { KIconView::setSelected(i, a, b); }
+
+ bool canPreview( const KFileItem * ) const;
+ void stopPreview();
+
+ void updateIcons();
+
+ inline KFileIconViewItem * viewItem( const KFileItem *item ) const {
+ if ( item )
+ return (KFileIconViewItem *) item->extraData( this );
+ return 0L;
+ }
+
+ void initItem(KFileIconViewItem *item, const KFileItem *i,
+ bool updateTextAndPixmap );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileIconViewPrivate;
+ KFileIconViewPrivate *d;
+};
+
+#endif // KFILESIMPLEVIEW_H
diff --git a/tdeio/tdefile/tdefilemetainfowidget.cpp b/tdeio/tdefile/tdefilemetainfowidget.cpp
new file mode 100644
index 000000000..dea9ea353
--- /dev/null
+++ b/tdeio/tdefile/tdefilemetainfowidget.cpp
@@ -0,0 +1,375 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ 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.
+
+ $Id$
+ */
+
+#include "tdefilemetainfowidget.h"
+
+#include <keditcl.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <tqspinbox.h>
+#include <tqdatetimeedit.h>
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqlayout.h>
+#include <tqvalidator.h>
+
+/*
+ Widgets used for different types:
+
+ bool : QCheckBox
+ int : QSpinBox
+ TQString : KComboBox if the validator is a KStringListValidator, else lineedit
+ TQDateTime : QDateTimeEdit
+
+*/
+
+KFileMetaInfoWidget::KFileMetaInfoWidget(KFileMetaInfoItem item,
+ TQValidator* val,
+ TQWidget* parent, const char* name)
+ : TQWidget(parent, name),
+ m_value(item.value()),
+ m_item(item),
+ m_validator(val)
+{
+ init(item, ReadWrite);
+}
+
+KFileMetaInfoWidget::KFileMetaInfoWidget(KFileMetaInfoItem item,
+ Mode mode,
+ TQValidator* val,
+ TQWidget* parent, const char* name)
+ : TQWidget(parent, name),
+ m_value(item.value()),
+ m_item(item),
+ m_validator(val)
+{
+ init(item, mode);
+}
+
+void KFileMetaInfoWidget::init(KFileMetaInfoItem item, Mode mode)
+{
+ kdDebug(7033) << "*** item " << m_item.key()
+ << " is a " << value().typeName() << endl;
+
+ if (m_item.isEditable() && !(mode & ReadOnly))
+ m_widget = makeWidget();
+ else
+ switch (m_value.type())
+ {
+ case TQVariant::Image :
+ m_widget = new TQLabel(this, "info image");
+ static_cast<TQLabel*>(m_widget)->setPixmap(TQPixmap(m_value.toImage()));
+ break;
+ case TQVariant::Pixmap :
+ m_widget = new TQLabel(this, "info pixmap");
+ static_cast<TQLabel*>(m_widget)->setPixmap(m_value.toPixmap());
+ break;
+ default:
+ m_widget = new TQLabel(item.string(true), this, "info label");
+ }
+
+ (new TQHBoxLayout(this))->addWidget(m_widget);
+}
+
+KFileMetaInfoWidget::~KFileMetaInfoWidget()
+{
+}
+
+TQWidget* KFileMetaInfoWidget::makeWidget()
+{
+ TQString valClass;
+ TQWidget* w;
+
+ switch (m_value.type())
+ {
+ case TQVariant::Invalid: // no type
+ // just make a label
+ w = new TQLabel(i18n("<Error>"), this, "label");
+ break;
+
+ case TQVariant::Int: // an int
+ case TQVariant::UInt: // an unsigned int
+ w = makeIntWidget();
+ break;
+
+ case TQVariant::Bool: // a bool
+ w = makeBoolWidget();
+ break;
+
+ case TQVariant::Double: // a double
+ w = makeDoubleWidget();
+ break;
+
+
+ case TQVariant::Date: // a QDate
+ w = makeDateWidget();
+ break;
+
+ case TQVariant::Time: // a QTime
+ w = makeTimeWidget();
+ break;
+
+ case TQVariant::DateTime: // a QDateTime
+ w = makeDateTimeWidget();
+ break;
+
+#if 0
+ case TQVariant::Size: // a QSize
+ case TQVariant::String: // a QString
+ case TQVariant::List: // a QValueList
+ case TQVariant::Map: // a QMap
+ case TQVariant::StringList: // a QStringList
+ case TQVariant::Font: // a QFont
+ case TQVariant::Pixmap: // a QPixmap
+ case TQVariant::Brush: // a QBrush
+ case TQVariant::Rect: // a QRect
+ case TQVariant::Color: // a QColor
+ case TQVariant::Palette: // a QPalette
+ case TQVariant::ColorGroup: // a QColorGroup
+ case TQVariant::IconSet: // a QIconSet
+ case TQVariant::Point: // a QPoint
+ case TQVariant::Image: // a QImage
+ case TQVariant::CString: // a QCString
+ case TQVariant::PointArray: // a QPointArray
+ case TQVariant::Region: // a QRegion
+ case TQVariant::Bitmap: // a QBitmap
+ case TQVariant::Cursor: // a QCursor
+ case TQVariant::ByteArray: // a QByteArray
+ case TQVariant::BitArray: // a QBitArray
+ case TQVariant::SizePolicy: // a QSizePolicy
+ case TQVariant::KeySequence: // a QKeySequence
+#endif
+ default:
+ w = makeStringWidget();
+ }
+
+ kdDebug(7033) << "*** item " << m_item.key()
+ << "is a " << m_item.value().typeName() << endl;
+ if (m_validator)
+ kdDebug(7033) << " and validator is a " << m_validator->className() << endl;
+
+ kdDebug(7033) << "*** created a " << w->className() << " for it\n";
+
+ return w;
+}
+
+// ****************************************************************
+// now the different methods to make the widgets for specific types
+// ****************************************************************
+
+TQWidget* KFileMetaInfoWidget::makeBoolWidget()
+{
+ TQCheckBox* cb = new TQCheckBox(this, "metainfo bool widget");
+ cb->setChecked(m_item.value().toBool());
+ connect(cb, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotChanged(bool)));
+ return cb;
+}
+
+TQWidget* KFileMetaInfoWidget::makeIntWidget()
+{
+ TQSpinBox* sb = new TQSpinBox(this, "metainfo integer widget");
+ sb->setValue(m_item.value().toInt());
+
+ if (m_validator)
+ {
+ if (m_validator->inherits(TQINTVALIDATOR_OBJECT_NAME_STRING))
+ {
+ sb->setMinValue(static_cast<TQIntValidator*>(m_validator)->bottom());
+ sb->setMaxValue(static_cast<TQIntValidator*>(m_validator)->top());
+ }
+ reparentValidator(sb, m_validator);
+ sb->setValidator(m_validator);
+ }
+
+ // make sure that an uint cannot be set to a value < 0
+ if (m_item.type() == TQVariant::UInt)
+ sb->setMinValue(QMAX(sb->minValue(), 0));
+
+ connect(sb, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotChanged(int)));
+ return sb;
+}
+
+TQWidget* KFileMetaInfoWidget::makeDoubleWidget()
+{
+ KDoubleNumInput* dni = new KDoubleNumInput(m_item.value().toDouble(),
+ this, "metainfo double widget");
+
+
+ if (m_validator)
+ {
+ if (m_validator->inherits("QDoubleValidator"))
+ {
+ dni->setMinValue(static_cast<TQDoubleValidator*>(m_validator)->bottom());
+ dni->setMaxValue(static_cast<TQDoubleValidator*>(m_validator)->top());
+ }
+ reparentValidator(dni, m_validator);
+ }
+
+ connect(dni, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotChanged(double)));
+ return dni;
+}
+
+TQWidget* KFileMetaInfoWidget::makeStringWidget()
+{
+ if (m_validator && m_validator->inherits("KStringListValidator"))
+ {
+ KComboBox* b = new KComboBox(true, this, "metainfo combobox");
+ KStringListValidator* val = static_cast<KStringListValidator*>
+ (m_validator);
+ b->insertStringList(val->stringList());
+ b->setCurrentText(m_item.value().toString());
+ connect(b, TQT_SIGNAL(activated(const TQString &)), this, TQT_SLOT(slotComboChanged(const TQString &)));
+ b->setValidator(val);
+ reparentValidator(b, val);
+ return b;
+ }
+
+ if ( m_item.attributes() & KFileMimeTypeInfo::MultiLine ) {
+ KEdit *edit = new KEdit( this );
+ edit->setText( m_item.value().toString() );
+ connect( edit, TQT_SIGNAL( textChanged() ),
+ this, TQT_SLOT( slotMultiLineEditChanged() ));
+ // can't use a validator with a TQTextEdit, but we may need to delete it
+ if ( m_validator )
+ reparentValidator( edit, m_validator );
+ return edit;
+ }
+
+ KLineEdit* e = new KLineEdit(m_item.value().toString(), this);
+ if (m_validator)
+ {
+ e->setValidator(m_validator);
+ reparentValidator(e, m_validator);
+ }
+ connect(e, TQT_SIGNAL(textChanged(const TQString&)),
+ this, TQT_SLOT(slotLineEditChanged(const TQString&)));
+ return e;
+}
+
+TQWidget* KFileMetaInfoWidget::makeDateWidget()
+{
+ TQWidget *e = new TQDateEdit(m_item.value().toDate(), this);
+ connect(e, TQT_SIGNAL(valueChanged(const TQDate&)),
+ this, TQT_SLOT(slotDateChanged(const TQDate&)));
+ return e;
+}
+
+TQWidget* KFileMetaInfoWidget::makeTimeWidget()
+{
+ return new TQTimeEdit(m_item.value().toTime(), this);
+}
+
+TQWidget* KFileMetaInfoWidget::makeDateTimeWidget()
+{
+ return new TQDateTimeEdit(m_item.value().toDateTime(), this);
+}
+
+void KFileMetaInfoWidget::reparentValidator( TQWidget *widget,
+ TQValidator *validator )
+{
+ if ( !validator->parent() )
+ widget->insertChild( validator );
+}
+
+// ****************************************************************
+// now the slots that let us get notified if the value changed in the child
+// ****************************************************************
+
+void KFileMetaInfoWidget::slotChanged(bool value)
+{
+ Q_ASSERT(m_widget->inherits(TQCOMBOBOX_OBJECT_NAME_STRING));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotChanged(int value)
+{
+ Q_ASSERT(m_widget->inherits(TQSPINBOX_OBJECT_NAME_STRING));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotChanged(double value)
+{
+ Q_ASSERT(m_widget->inherits("KDoubleNumInput"));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotComboChanged(const TQString &value)
+{
+ Q_ASSERT(m_widget->inherits("KComboBox"));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotLineEditChanged(const TQString& value)
+{
+ Q_ASSERT(m_widget->inherits("KLineEdit"));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+// that may be a little expensive for long texts, but what can we do?
+void KFileMetaInfoWidget::slotMultiLineEditChanged()
+{
+ Q_ASSERT(m_widget->inherits(TQTEXTEDIT_OBJECT_NAME_STRING));
+ m_value = TQVariant( static_cast<const TQTextEdit*>( sender() )->text() );
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotDateChanged(const TQDate& value)
+{
+ Q_ASSERT(m_widget->inherits(TQDATEEDIT_OBJECT_NAME_STRING));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotTimeChanged(const TQTime& value)
+{
+ Q_ASSERT(m_widget->inherits(TQTIMEEDIT_OBJECT_NAME_STRING));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+void KFileMetaInfoWidget::slotDateTimeChanged(const TQDateTime& value)
+{
+ Q_ASSERT(m_widget->inherits(TQDATETIMEEDIT_OBJECT_NAME_STRING));
+ m_value = TQVariant(value);
+ emit valueChanged(m_value);
+ m_dirty = true;
+}
+
+#include "tdefilemetainfowidget.moc"
diff --git a/tdeio/tdefile/tdefilemetainfowidget.h b/tdeio/tdefile/tdefilemetainfowidget.h
new file mode 100644
index 000000000..8f1d2b5b7
--- /dev/null
+++ b/tdeio/tdefile/tdefilemetainfowidget.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001,2002 Rolf Magnus <ramagnus@kde.org>
+
+ 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 __KFILEMETAINFOWIDGET_H__
+#define __KFILEMETAINFOWIDGET_H__
+
+#include <tqwidget.h>
+#include <tqvariant.h>
+#include <tdefilemetainfo.h>
+
+/*!
+ * A widget to display file meta infos (like id3 for mp3)
+ */
+class TDEIO_EXPORT KFileMetaInfoWidget: public TQWidget
+{
+ Q_OBJECT
+public:
+ enum Mode
+ {
+ ReadOnly = 1, ///Only display the meta infos, and do not permit the user to edit them
+ ReadWrite = 0, ///Permits user to edit the displayed meta-info
+ Reserve = 0xff
+ };
+
+ KFileMetaInfoWidget(KFileMetaInfoItem item, TQValidator* val = 0,
+ TQWidget* parent = 0, const char* name = 0);
+
+ KFileMetaInfoWidget(KFileMetaInfoItem item, Mode mode, TQValidator* val = 0,
+ TQWidget* parent = 0, const char* name = 0);
+
+ virtual ~KFileMetaInfoWidget();
+
+ bool apply()
+ {
+ return m_item.isEditable() && m_item.setValue(m_value);
+ }
+
+ void setValue(const TQVariant& value) { m_value = value; }
+ TQVariant value()const { return m_value; }
+ TQValidator* validator() const { return m_validator; }
+ KFileMetaInfoItem item()const { return m_item; }
+
+signals:
+ void valueChanged(const TQVariant& value);
+
+protected:
+ void reparentValidator(TQWidget *widget, TQValidator *validator);
+ virtual TQWidget* makeWidget();
+
+ TQWidget* makeBoolWidget();
+ TQWidget* makeIntWidget();
+ TQWidget* makeDoubleWidget();
+ TQWidget* makeStringWidget();
+ TQWidget* makeDateWidget();
+ TQWidget* makeTimeWidget();
+ TQWidget* makeDateTimeWidget();
+
+private slots:
+ void slotChanged(bool value);
+ void slotChanged(int value);
+ void slotChanged(double value);
+ void slotComboChanged(const TQString &value);
+ void slotLineEditChanged(const TQString& value);
+ void slotMultiLineEditChanged();
+ void slotDateChanged(const TQDate& value);
+ void slotTimeChanged(const TQTime& value);
+ void slotDateTimeChanged(const TQDateTime& value);
+
+private:
+ void init(KFileMetaInfoItem item, Mode mode);
+
+ TQVariant m_value; // the value will be saved here until apply() is called
+ KFileMetaInfoItem m_item;
+ TQWidget* m_widget;
+ TQValidator* m_validator;
+ bool m_dirty : 1;
+};
+
+#endif
diff --git a/tdeio/tdefile/tdefilemetapreview.cpp b/tdeio/tdefile/tdefilemetapreview.cpp
new file mode 100644
index 000000000..d587511e4
--- /dev/null
+++ b/tdeio/tdefile/tdefilemetapreview.cpp
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include "tdefilemetapreview.h"
+
+#include <tqlayout.h>
+
+#include <tdeio/previewjob.h>
+#include <klibloader.h>
+#include <kimagefilepreview.h>
+#include <kmimetype.h>
+
+bool KFileMetaPreview::s_tryAudioPreview = true;
+
+KFileMetaPreview::KFileMetaPreview( TQWidget *parent, const char *name )
+ : KPreviewWidgetBase( parent, name ),
+ haveAudioPreview( false )
+{
+ TQHBoxLayout *layout = new TQHBoxLayout( this, 0, 0 );
+ m_stack = new TQWidgetStack( this );
+ layout->addWidget( m_stack );
+
+ // ###
+// m_previewProviders.setAutoDelete( true );
+ initPreviewProviders();
+}
+
+KFileMetaPreview::~KFileMetaPreview()
+{
+}
+
+void KFileMetaPreview::initPreviewProviders()
+{
+ m_previewProviders.clear();
+ // hardcoded so far
+
+ // image previews
+ KImageFilePreview *imagePreview = new KImageFilePreview( m_stack );
+ (void) m_stack->addWidget( imagePreview );
+ m_stack->raiseWidget( imagePreview );
+ resize( imagePreview->sizeHint() );
+
+ TQStringList mimeTypes = imagePreview->supportedMimeTypes();
+ TQStringList::ConstIterator it = mimeTypes.begin();
+ for ( ; it != mimeTypes.end(); ++it )
+ {
+// tqDebug(".... %s", (*it).latin1());
+ m_previewProviders.insert( *it, imagePreview );
+ }
+}
+
+KPreviewWidgetBase * KFileMetaPreview::previewProviderFor( const TQString& mimeType )
+{
+// tqDebug("### looking for: %s", mimeType.latin1());
+ // often the first highlighted item, where we can be sure, there is no plugin
+ // (this "folders reflect icons" is a konq-specific thing, right?)
+ if ( mimeType == "inode/directory" )
+ return 0L;
+
+ KPreviewWidgetBase *provider = m_previewProviders.find( mimeType );
+ if ( provider )
+ return provider;
+
+//tqDebug("#### didn't find anything for: %s", mimeType.latin1());
+
+ if ( s_tryAudioPreview &&
+ !mimeType.startsWith("text/") && !mimeType.startsWith("image/") )
+ {
+ if ( !haveAudioPreview )
+ {
+ KPreviewWidgetBase *audioPreview = createAudioPreview( m_stack );
+ if ( audioPreview )
+ {
+ haveAudioPreview = true;
+ (void) m_stack->addWidget( audioPreview );
+ TQStringList mimeTypes = audioPreview->supportedMimeTypes();
+ TQStringList::ConstIterator it = mimeTypes.begin();
+ for ( ; it != mimeTypes.end(); ++it )
+ m_previewProviders.insert( *it, audioPreview );
+ }
+ }
+ }
+
+ // with the new mimetypes from the audio-preview, try again
+ provider = m_previewProviders.find( mimeType );
+ if ( provider )
+ return provider;
+
+ // ### mimetype may be image/* for example, try that
+ int index = mimeType.find( '/' );
+ if ( index > 0 )
+ {
+ provider = m_previewProviders.find( mimeType.left( index + 1 ) + "*" );
+ if ( provider )
+ return provider;
+ }
+
+ KMimeType::Ptr mimeInfo = KMimeType::mimeType( mimeType );
+ if ( mimeInfo )
+ {
+ // check mime type inheritance
+ TQString parentMimeType = mimeInfo->parentMimeType();
+ while ( !parentMimeType.isEmpty() )
+ {
+ provider = m_previewProviders.find( parentMimeType );
+ if ( provider )
+ return provider;
+
+ KMimeType::Ptr parentMimeInfo = KMimeType::mimeType( parentMimeType );
+ if ( !parentMimeInfo ) break;
+
+ parentMimeType = parentMimeInfo->parentMimeType();
+ }
+
+ // check X-TDE-Text property
+ TQVariant textProperty = mimeInfo->property( "X-TDE-text" );
+ if ( textProperty.isValid() && textProperty.type() == TQVariant::Bool )
+ {
+ if ( textProperty.toBool() )
+ {
+ provider = m_previewProviders.find( "text/plain" );
+ if ( provider )
+ return provider;
+
+ provider = m_previewProviders.find( "text/*" );
+ if ( provider )
+ return provider;
+ }
+ }
+ }
+
+ return 0L;
+}
+
+void KFileMetaPreview::showPreview(const KURL &url)
+{
+ KMimeType::Ptr mt = KMimeType::findByURL( url );
+ KPreviewWidgetBase *provider = previewProviderFor( mt->name() );
+ if ( provider )
+ {
+ if ( provider != m_stack->visibleWidget() ) // stop the previous preview
+ clearPreview();
+
+ m_stack->setEnabled( true );
+ m_stack->raiseWidget( provider );
+ provider->showPreview( url );
+ }
+ else
+ {
+ clearPreview();
+ m_stack->setEnabled( false );
+ }
+}
+
+void KFileMetaPreview::clearPreview()
+{
+ if ( m_stack->visibleWidget() )
+ static_cast<KPreviewWidgetBase*>( m_stack->visibleWidget() )->clearPreview();
+}
+
+void KFileMetaPreview::addPreviewProvider( const TQString& mimeType,
+ KPreviewWidgetBase *provider )
+{
+ m_previewProviders.insert( mimeType, provider );
+}
+
+void KFileMetaPreview::clearPreviewProviders()
+{
+ TQDictIterator<KPreviewWidgetBase> it( m_previewProviders );
+ for ( ; it.current(); ++it )
+ m_stack->removeWidget( it.current() );
+
+ m_previewProviders.clear();
+}
+
+// static
+KPreviewWidgetBase * KFileMetaPreview::createAudioPreview( TQWidget *parent )
+{
+ KLibFactory *factory = KLibLoader::self()->factory( "tdefileaudiopreview" );
+ if ( !factory )
+ {
+ s_tryAudioPreview = false;
+ return 0L;
+ }
+
+ return dynamic_cast<KPreviewWidgetBase*>( factory->create( TQT_TQOBJECT(parent), "tdefileaudiopreview" ));
+}
+
+void KFileMetaPreview::virtual_hook( int, void* ) {}
+
+#include "tdefilemetapreview.moc"
diff --git a/tdeio/tdefile/tdefilemetapreview.h b/tdeio/tdefile/tdefilemetapreview.h
new file mode 100644
index 000000000..f26cd29b5
--- /dev/null
+++ b/tdeio/tdefile/tdefilemetapreview.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the KDE project.
+ * Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+ *
+ * You can Freely distribute this program under the GNU Library General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef KFILEMETAPREVIEW_H
+#define KFILEMETAPREVIEW_H
+
+#include <tqdict.h>
+#include <tqwidgetstack.h>
+
+#include <kpreviewwidgetbase.h>
+#include <kurl.h>
+
+class TDEIO_EXPORT KFileMetaPreview : public KPreviewWidgetBase
+{
+ Q_OBJECT
+
+public:
+ KFileMetaPreview(TQWidget *parent, const char *name = 0);
+ ~KFileMetaPreview();
+
+ virtual void addPreviewProvider( const TQString& mimeType,
+ KPreviewWidgetBase *provider );
+ virtual void clearPreviewProviders();
+
+public slots:
+ virtual void showPreview(const KURL &url);
+ virtual void clearPreview();
+
+protected:
+ virtual KPreviewWidgetBase *previewProviderFor( const TQString& mimeType );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ void initPreviewProviders();
+
+ TQWidgetStack *m_stack;
+ TQDict<KPreviewWidgetBase> m_previewProviders;
+ bool haveAudioPreview;
+
+ // may return 0L
+ static KPreviewWidgetBase * createAudioPreview( TQWidget *parent );
+ static bool s_tryAudioPreview;
+
+private:
+ class KFileMetaPreviewPrivate;
+ KFileMetaPreviewPrivate *d;
+};
+
+#endif // KFILEMETAPREVIEW_H
diff --git a/tdeio/tdefile/tdefilepreview.cpp b/tdeio/tdefile/tdefilepreview.cpp
new file mode 100644
index 000000000..4e9365361
--- /dev/null
+++ b/tdeio/tdefile/tdefilepreview.cpp
@@ -0,0 +1,279 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000 Werner Trobin <wtrobin@carinthia.com>
+
+ 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 <kaction.h>
+#include <tdefilepreview.h>
+#include <tdefilepreview.moc>
+#include <klocale.h>
+
+#include <tqlabel.h>
+
+#include "config-tdefile.h"
+
+KFilePreview::KFilePreview(KFileView *view, TQWidget *parent, const char *name)
+ : TQSplitter(parent, name), KFileView()
+{
+ if ( view )
+ init( view );
+ else
+ init( new KFileIconView( (TQSplitter*) this, "left" ));
+}
+
+
+KFilePreview::KFilePreview(TQWidget *parent, const char *name) :
+ TQSplitter(parent, name), KFileView()
+{
+ init( new KFileIconView((TQSplitter*)this, "left") );
+}
+
+KFilePreview::~KFilePreview()
+{
+ // Why copy the actions in the first place? --ellis, 13 Jan 02.
+ //// don't delete the view's actions (inserted into our collection)!
+ //for ( uint i = 0; i < left->actionCollection()->count(); i++ )
+ // actionCollection()->take( left->actionCollection()->action( i ));
+
+ // don't delete the preview, we can reuse it
+ // (it will get deleted by ~KDirOperator)
+ if ( preview && preview->parentWidget() == this ) {
+ preview->reparent(0L, 0, TQPoint(0, 0), false);
+ }
+}
+
+void KFilePreview::init( KFileView *view )
+{
+ setViewName( i18n("Preview") );
+
+ left = 0L;
+ setFileView( view );
+
+ preview = new TQWidget((TQSplitter*)this, "preview");
+ TQString tmp = i18n("No preview available.");
+ TQLabel *l = new TQLabel(tmp, preview);
+ l->setMinimumSize(l->sizeHint());
+ l->move(10, 5);
+ preview->setMinimumWidth(l->sizeHint().width()+20);
+ setResizeMode(preview, TQSplitter::KeepSize);
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //for ( uint i = 0; i < view->actionCollection()->count(); i++ )
+ // actionCollection()->insert( view->actionCollection()->action( i ));
+}
+
+void KFilePreview::setFileView( KFileView *view )
+{
+ Q_ASSERT( view );
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //if ( left ) { // remove any previous actions
+ // for ( uint i = 0; i < left->actionCollection()->count(); i++ )
+ // actionCollection()->take( left->actionCollection()->action( i ));
+ //}
+
+ delete left;
+ view->widget()->reparent( this, TQPoint(0,0) );
+ view->KFileView::setViewMode(All);
+ view->setParentView(this);
+ view->setSorting( sorting() );
+ left = view;
+
+ connect( left->signaler(), TQT_SIGNAL( fileHighlighted(const KFileItem*) ),
+ TQT_SLOT( slotHighlighted( const KFileItem * )));
+
+ // Why copy the actions? --ellis, 13 Jan 02.
+ //for ( uint i = 0; i < view->actionCollection()->count(); i++ )
+ // actionCollection()->insert( view->actionCollection()->action( i ));
+}
+
+// this url parameter is useless... it's the url of the current directory.
+// what for?
+void KFilePreview::setPreviewWidget(const TQWidget *w, const KURL &)
+{
+ left->setOnlyDoubleClickSelectsFiles( onlyDoubleClickSelectsFiles() );
+
+ if (w) {
+ connect(this, TQT_SIGNAL( showPreview(const KURL &) ),
+ w, TQT_SLOT( showPreview(const KURL &) ));
+ connect( this, TQT_SIGNAL( clearPreview() ),
+ w, TQT_SLOT( clearPreview() ));
+ }
+ else {
+ preview->hide();
+ return;
+ }
+
+ delete preview;
+ preview = const_cast<TQWidget*>(w);
+ preview->reparent((TQSplitter*)this, 0, TQPoint(0, 0), true);
+ preview->resize(preview->sizeHint());
+ preview->show();
+}
+
+void KFilePreview::insertItem(KFileItem *item)
+{
+ KFileView::insertItem( item );
+ left->insertItem(item);
+}
+
+void KFilePreview::setSorting( TQDir::SortSpec sort )
+{
+ left->setSorting( sort );
+ KFileView::setSorting( left->sorting() );
+}
+
+void KFilePreview::clearView()
+{
+ left->clearView();
+ emit clearPreview();
+}
+
+void KFilePreview::updateView(bool b)
+{
+ left->updateView(b);
+ if(preview)
+ preview->repaint(b);
+}
+
+void KFilePreview::updateView(const KFileItem *i)
+{
+ left->updateView(i);
+}
+
+void KFilePreview::removeItem(const KFileItem *i)
+{
+ if ( left->isSelected( i ) )
+ emit clearPreview();
+
+ left->removeItem(i);
+ KFileView::removeItem( i );
+}
+
+void KFilePreview::listingCompleted()
+{
+ left->listingCompleted();
+}
+
+void KFilePreview::clear()
+{
+ KFileView::clear();
+ left->KFileView::clear();
+}
+
+void KFilePreview::clearSelection()
+{
+ left->clearSelection();
+ emit clearPreview();
+}
+
+void KFilePreview::selectAll()
+{
+ left->selectAll();
+}
+
+void KFilePreview::invertSelection()
+{
+ left->invertSelection();
+}
+
+bool KFilePreview::isSelected( const KFileItem *i ) const
+{
+ return left->isSelected( i );
+}
+
+void KFilePreview::setSelectionMode(KFile::SelectionMode sm) {
+ left->setSelectionMode( sm );
+}
+
+void KFilePreview::setSelected(const KFileItem *item, bool enable) {
+ left->setSelected( item, enable );
+}
+
+void KFilePreview::setCurrentItem( const KFileItem *item )
+{
+ left->setCurrentItem( item );
+}
+
+KFileItem * KFilePreview::currentFileItem() const
+{
+ return left->currentFileItem();
+}
+
+void KFilePreview::slotHighlighted(const KFileItem* item)
+{
+ if ( item )
+ emit showPreview( item->url() );
+
+ else { // item = 0 -> multiselection mode
+ const KFileItemList *items = selectedItems();
+ if ( items->count() == 1 )
+ emit showPreview( items->getFirst()->url() );
+ else
+ emit clearPreview();
+ }
+
+ // the preview widget appears and takes some space of the left view,
+ // so we may have to scroll to make the current item visible
+ left->ensureItemVisible(item);
+ }
+
+void KFilePreview::ensureItemVisible(const KFileItem *item)
+{
+ left->ensureItemVisible(item);
+}
+
+KFileItem * KFilePreview::firstFileItem() const
+{
+ return left->firstFileItem();
+}
+
+KFileItem * KFilePreview::nextItem( const KFileItem *item ) const
+{
+ return left->nextItem( item );
+}
+
+KFileItem * KFilePreview::prevItem( const KFileItem *item ) const
+{
+ return left->prevItem( item );
+}
+
+KActionCollection * KFilePreview::actionCollection() const
+{
+ if ( left )
+ return left->actionCollection();
+ else {
+ kdWarning() << "KFilePreview::actionCollection(): called before setFileView()." << endl; //ellis
+ return KFileView::actionCollection();
+ }
+}
+
+void KFilePreview::readConfig( TDEConfig *config, const TQString& group )
+{
+ left->readConfig( config, group );
+}
+
+void KFilePreview::writeConfig( TDEConfig *config, const TQString& group )
+{
+ left->writeConfig( config, group );
+}
+
+void KFilePreview::virtual_hook( int id, void* data )
+{ KFileView::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdefile/tdefilepreview.h b/tdeio/tdefile/tdefilepreview.h
new file mode 100644
index 000000000..38db862ac
--- /dev/null
+++ b/tdeio/tdefile/tdefilepreview.h
@@ -0,0 +1,122 @@
+/* -*- c++ -*-
+ This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2000 Werner Trobin <wtrobin@carinthia.com>
+
+ 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 _KFILEPREVIEW_H
+#define _KFILEPREVIEW_H
+
+#include <tqsplitter.h>
+#include <tqwidget.h>
+#include <tqstring.h>
+
+#include <kurl.h>
+#include <tdefileitem.h>
+#include <tdefileiconview.h>
+#include <tdefiledetailview.h>
+#include <tdefile.h>
+
+/*!
+ * This KFileView is an empbedded preview for some file types.
+ */
+class TDEIO_EXPORT KFilePreview : public TQSplitter, public KFileView
+{
+ Q_OBJECT
+
+public:
+ KFilePreview(TQWidget *parent, const char *name);
+ KFilePreview(KFileView *view, TQWidget *parent, const char *name);
+ virtual ~KFilePreview();
+
+ virtual TQWidget *widget() { return this; }
+ virtual void clearView();
+
+ /**
+ * Delets the current view and sets the view to the given @p view.
+ * The view is reparented to have this as parent, if necessary.
+ */
+ void setFileView(KFileView *view);
+
+ /**
+ * @returns the current fileview
+ */
+ KFileView* fileView() const { return left; }
+
+ virtual void updateView( bool );
+ virtual void updateView(const KFileItem*);
+ virtual void removeItem(const KFileItem*);
+ virtual void listingCompleted();
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+
+ virtual void setSelected(const KFileItem *, bool);
+ virtual bool isSelected( const KFileItem * ) const;
+ virtual void clearSelection();
+ virtual void selectAll();
+ virtual void invertSelection();
+
+ virtual void insertItem(KFileItem *);
+ virtual void clear();
+
+ virtual void setCurrentItem( const KFileItem * );
+ virtual KFileItem * currentFileItem() const;
+ virtual KFileItem * firstFileItem() const;
+ virtual KFileItem * nextItem( const KFileItem * ) const;
+ virtual KFileItem * prevItem( const KFileItem * ) const;
+
+ virtual void setSorting( TQDir::SortSpec sort );
+
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null);
+
+ /**
+ * This overrides KFileView::actionCollection() by returning
+ * the actionCollection() of the KFileView (member left) it contains.
+ * This means that KFilePreview will never create a KActionCollection
+ * object of its own.
+ */
+ virtual KActionCollection * actionCollection() const;
+
+ void ensureItemVisible(const KFileItem *);
+
+ void setPreviewWidget(const TQWidget *w, const KURL &u);
+
+protected slots:
+ virtual void slotHighlighted( const KFileItem * );
+
+signals:
+ void showPreview(const KURL &);
+ void clearPreview();
+
+private:
+ void init( KFileView *view );
+
+ KFileView *left;
+ TQWidget *preview;
+ TQString viewname;
+
+protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFilePreviewPrivate;
+ KFilePreviewPrivate *d;
+};
+#endif
diff --git a/tdeio/tdefile/tdefilesharedlg.cpp b/tdeio/tdefile/tdefilesharedlg.cpp
new file mode 100644
index 000000000..8e6f9e650
--- /dev/null
+++ b/tdeio/tdefile/tdefilesharedlg.cpp
@@ -0,0 +1,325 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ 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 "tdefilesharedlg.h"
+#include <tqvbox.h>
+#include <tqlabel.h>
+#include <tqdir.h>
+#include <tqradiobutton.h>
+#include <tqbuttongroup.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <kprocess.h>
+#include <kprocio.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <tdeio/tdefileshare.h>
+#include <kseparator.h>
+#include <tqpushbutton.h>
+#include <kapplication.h>
+#include <ksimpleconfig.h>
+#include <kmessagebox.h>
+
+class KFileSharePropsPlugin::Private
+{
+public:
+ TQVBox *m_vBox;
+ TDEProcess *m_configProc;
+ bool m_bAllShared;
+ bool m_bAllUnshared;
+ bool m_bAllReadOnly;
+};
+
+KFileSharePropsPlugin::KFileSharePropsPlugin( KPropertiesDialog *_props )
+ : KPropsDlgPlugin( _props )
+{
+ d = new Private;
+ d->m_vBox = _props->addVBoxPage( i18n("&Share") );
+ d->m_configProc = 0;
+ properties->setFileSharingPage(d->m_vBox);
+ m_widget = 0L;
+ init();
+}
+
+KFileSharePropsPlugin::~KFileSharePropsPlugin()
+{
+ if (d->m_configProc)
+ d->m_configProc->detach(); // Detach to prevent that we kill the process
+ delete d;
+}
+
+bool KFileSharePropsPlugin::supports( const KFileItemList& items )
+{
+ // Do not show dialog if in advanced mode,
+ // because the advanced dialog is shown already.
+ if (KFileShare::shareMode() == KFileShare::Advanced) {
+ kdDebug() << "KFileSharePropsPlugin::supports: false because sharemode is advanced" << endl;
+ return false;
+ }
+
+ KFileItemListIterator it( items );
+ for ( ; it.current(); ++it )
+ {
+ bool isLocal = ( *it )->isLocalFile();
+ // We only support local dirs
+ if ( !(*it)->isDir() || !isLocal )
+ return false;
+ // And sharing the trash doesn't make sense
+ if ( isLocal && (*it)->url().path( 1 ) == TDEGlobalSettings::trashPath() )
+ return false;
+ }
+ return true;
+}
+
+void KFileSharePropsPlugin::init()
+{
+ // We store the main widget, so that it's possible (later) to call init()
+ // more than once, to update the page if something changed (e.g. after
+ // the user has been authorized)
+ delete m_widget;
+ m_rbShare = 0L;
+ m_rbUnShare = 0L;
+ m_rbSharerw = 0L;
+ m_widget = new TQWidget( d->m_vBox );
+ TQVBoxLayout * vbox = new TQVBoxLayout( m_widget );
+ //TQHBoxLayout * hbox = new TQHBoxLayout( vbox );
+
+ switch ( KFileShare::authorization() ) {
+ case KFileShare::Authorized:
+ {
+ // Check if all selected dirs are in $HOME
+ TQString home = TQDir::homeDirPath();
+ if ( home[home.length()-1] != '/' )
+ home += '/';
+ bool ok = true;
+ KFileItemList items = properties->items();
+ // We have 3 possibilities: all shared, all unshared (ro,rw), or mixed.
+ d->m_bAllShared = true;
+ d->m_bAllUnshared = true;
+ d->m_bAllReadOnly = true;
+ KFileItemListIterator it( items );
+ for ( ; it.current() && ok; ++it ) {
+ TQString path = (*it)->url().path();
+ // 0 => not shared
+ // 1 => shared read only
+ // 3 => shared writeable
+ int dirStatus = KFileShare::isDirectoryShared( path );
+ if ( !path.startsWith( home ) )
+ ok = false;
+ if ( dirStatus == 1 ) {
+ d->m_bAllUnshared = false;
+ }
+ else if ( dirStatus == 3 ) {
+ d->m_bAllUnshared = false;
+ d->m_bAllReadOnly = false;
+ }
+ else {
+ d->m_bAllReadOnly = false;
+ }
+ }
+ if ( !ok )
+ {
+ vbox->addWidget( new TQLabel( i18n( "Only folders in your home folder can be shared."),
+ m_widget ), 0 );
+ }
+ else
+ {
+ // Everything ok, show the share/unshare GUI
+ vbox->setSpacing( KDialog::spacingHint() );
+ vbox->setMargin( KDialog::marginHint() );
+
+ TQButtonGroup *rbGroup = new TQButtonGroup( m_widget );
+ rbGroup->hide();
+ m_rbUnShare = new TQRadioButton( i18n("Not shared"), m_widget );
+ connect( m_rbUnShare, TQT_SIGNAL( toggled(bool) ), TQT_SIGNAL( changed() ) );
+ vbox->addWidget( m_rbUnShare, 0 );
+ rbGroup->insert( m_rbUnShare );
+
+ m_rbShare = new TQRadioButton( i18n("Shared - read only for others"), m_widget );
+ connect( m_rbShare, TQT_SIGNAL( toggled(bool) ), TQT_SIGNAL( changed() ) );
+ vbox->addWidget( m_rbShare, 0 );
+ rbGroup->insert( m_rbShare );
+
+ m_rbSharerw = new TQRadioButton( i18n("Shared - writeable for others"), m_widget );
+ connect( m_rbSharerw, TQT_SIGNAL( toggled(bool) ), TQT_SIGNAL( changed() ) );
+ vbox->addWidget( m_rbSharerw, 0 );
+ rbGroup->insert( m_rbSharerw );
+
+ //TQLabel *testlabel1 = new TQLabel(i18n("Enter Samba Share Name here"),m_widget);
+ //m_leSmbShareName = new TQLineEdit(m_widget);
+ //m_leSmbShareName->setMaxLength(12);
+
+ //hbox->addWidget( testlabel1, 0 );
+ //hbox->addWidget( m_leSmbShareName );
+ //vbox->addLayout( hbox );
+
+ // Activate depending on status
+ if ( d->m_bAllShared )
+ m_rbSharerw->setChecked(true);
+ if ( d->m_bAllUnshared )
+ m_rbUnShare->setChecked(true);
+ if ( d->m_bAllReadOnly )
+ m_rbShare->setChecked(true);
+
+ // Some help text
+ TQLabel *label = new TQLabel( i18n("Sharing this folder makes it available under Linux/UNIX (NFS) and Windows (Samba).") , m_widget );
+ label->setAlignment( TQt::AlignAuto | TQt::AlignVCenter | TQt::WordBreak );
+ vbox->addWidget( label, 0 );
+
+ KSeparator* sep=new KSeparator(m_widget);
+ vbox->addWidget( sep, 0 );
+ label = new TQLabel( i18n("You can also reconfigure file sharing authorization.") , m_widget );
+ label->setAlignment( TQt::AlignAuto | TQt::AlignVCenter | TQt::WordBreak );
+ vbox->addWidget( label, 0 );
+ m_pbConfig = new TQPushButton( i18n("Configure File Sharing..."), m_widget );
+ connect( m_pbConfig, TQT_SIGNAL( clicked() ), TQT_SLOT( slotConfigureFileSharing() ) );
+ vbox->addWidget( m_pbConfig, 0, Qt::AlignHCenter );
+
+ vbox->addStretch( 10 );
+
+ if( !KFileShare::sambaActive() && !KFileShare::nfsActive())
+ m_widget->setEnabled( false );
+ }
+ }
+ break;
+ case KFileShare::ErrorNotFound:
+ vbox->addWidget( new TQLabel( i18n("Error running 'filesharelist'. Check if installed and in $PATH or /usr/sbin."),
+ m_widget ), 0 );
+ break;
+ case KFileShare::UserNotAllowed:
+ {
+ vbox->setSpacing( 10 );
+ if (KFileShare::sharingEnabled()) {
+ vbox->addWidget( new TQLabel( i18n("You need to be authorized to share folders."),
+ m_widget ), 0 );
+ } else {
+ vbox->addWidget( new TQLabel( i18n("File sharing is disabled."),
+ m_widget ), 0 );
+ }
+ TQHBoxLayout* hBox = new TQHBoxLayout( (TQWidget *)0L );
+ vbox->addLayout( hBox, 0 );
+ m_pbConfig = new TQPushButton( i18n("Configure File Sharing..."), m_widget );
+ connect( m_pbConfig, TQT_SIGNAL( clicked() ), TQT_SLOT( slotConfigureFileSharing() ) );
+ hBox->addWidget( m_pbConfig, 0, Qt::AlignHCenter );
+ vbox->addStretch( 10 ); // align items on top
+ break;
+ }
+ case KFileShare::NotInitialized:
+ kdWarning() << "KFileShare Authorization still NotInitialized after calling authorization() - impossible" << endl;
+ break;
+ }
+ m_widget->show(); // In case the dialog was shown already.
+}
+
+void KFileSharePropsPlugin::slotConfigureFileSharing()
+{
+ if (d->m_configProc) return;
+
+ d->m_configProc = new TDEProcess(this);
+ (*d->m_configProc) << KStandardDirs::findExe("tdesu") << locate("exe", "tdecmshell") << "fileshare";
+ if (!d->m_configProc->start( TDEProcess::NotifyOnExit ))
+ {
+ delete d->m_configProc;
+ d->m_configProc = 0;
+ return;
+ }
+ connect(d->m_configProc, TQT_SIGNAL(processExited(TDEProcess *)),
+ this, TQT_SLOT(slotConfigureFileSharingDone()));
+ m_pbConfig->setEnabled(false);
+}
+
+void KFileSharePropsPlugin::slotConfigureFileSharingDone()
+{
+ delete d->m_configProc;
+ d->m_configProc = 0;
+ KFileShare::readConfig();
+ KFileShare::readShareList();
+ init();
+}
+
+void KFileSharePropsPlugin::applyChanges()
+{
+ kdDebug() << "KFileSharePropsPlugin::applyChanges" << endl;
+ if ( m_rbShare && m_rbUnShare && m_rbSharerw )
+ {
+ bool share = m_rbShare->isChecked();
+
+ if (share && d->m_bAllShared)
+ return; // Nothing to do
+ if (!share && d->m_bAllUnshared)
+ return; // Nothing to do
+
+ KFileItemList items = properties->items();
+ KFileItemListIterator it( items );
+ bool ok = true;
+ for ( ; it.current() && ok; ++it ) {
+ TQString path = (*it)->url().path();
+ ok = SuSEsetShared( path, share, m_rbSharerw->isChecked() );
+ if (!ok) {
+ if (share)
+ KMessageBox::detailedError(properties,
+ i18n("Sharing folder '%1' failed.").arg(path),
+ i18n("An error occurred while trying to share folder '%1'. "
+ "Make sure that the Perl script 'fileshareset' is set suid root.")
+ .arg(path));
+ else
+ KMessageBox::error(properties,
+ i18n("Unsharing folder '%1' failed.").arg(path),
+ i18n("An error occurred while trying to unshare folder '%1'. "
+ "Make sure that the Perl script 'fileshareset' is set suid root.")
+ .arg(path));
+
+ properties->abortApplying();
+ break;
+ }
+ }
+
+ // Get the change back into our cached info
+ KFileShare::readShareList();
+ }
+}
+
+bool KFileSharePropsPlugin::setShared( const TQString& path, bool shared )
+{
+ return SuSEsetShared( path, shared, true );
+}
+
+bool KFileSharePropsPlugin::SuSEsetShared( const TQString& path, bool shared, bool readonly )
+{
+ kdDebug() << "KFileSharePropsPlugin::setShared " << path << ","
+ << shared << readonly << endl;
+ return KFileShare::SuSEsetShared( path, shared, readonly );
+}
+
+TQWidget* KFileSharePropsPlugin::page() const
+{
+ return d->m_vBox;
+}
+
+#include "tdefilesharedlg.moc"
+
+//TODO: do we need to monitor /etc/security/fileshare.conf ?
+// if the user is added to the 'fileshare' group, we wouldn't be notified
+// Of course the config module can notify us.
+// TODO: listen to such notifications ;)
diff --git a/tdeio/tdefile/tdefilesharedlg.h b/tdeio/tdefile/tdefilesharedlg.h
new file mode 100644
index 000000000..aa818db64
--- /dev/null
+++ b/tdeio/tdefile/tdefilesharedlg.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ 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 tdefilesharedlg_h
+#define tdefilesharedlg_h
+
+#include <kpropertiesdialog.h>
+class TQVBoxLayout;
+class TQRadioButton;
+class TQPushButton;
+
+/**
+ * This plugin provides a page to KPropsDlg, showing the "file sharing" options
+ * @author David Faure <david@mandrakesoft.com>
+ * @since 3.1
+ */
+class TDEIO_EXPORT KFileSharePropsPlugin : public KPropsDlgPlugin
+{
+ Q_OBJECT
+public:
+ KFileSharePropsPlugin( KPropertiesDialog *_props );
+ virtual ~KFileSharePropsPlugin();
+
+ /**
+ * Apply all changes to the file.
+ * This function is called when the user presses 'Ok'. The last plugin inserted
+ * is called first.
+ */
+ virtual void applyChanges();
+
+ static bool supports( const KFileItemList& items );
+
+ TQWidget* page() const;
+
+protected slots:
+ void slotConfigureFileSharing();
+ void slotConfigureFileSharingDone();
+
+private:
+ void init();
+ bool setShared( const TQString&path, bool shared );
+ bool SuSEsetShared( const TQString&path, bool shared, bool readonly );
+
+ TQWidget *m_widget;
+ TQRadioButton *m_rbShare;
+ TQRadioButton *m_rbSharerw;
+ TQRadioButton *m_rbUnShare;
+ //TQLineEdit *m_leSmbShareName;
+ TQPushButton *m_pbConfig;
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/tdefilespeedbar.cpp b/tdeio/tdefile/tdefilespeedbar.cpp
new file mode 100644
index 000000000..ca7e19003
--- /dev/null
+++ b/tdeio/tdefile/tdefilespeedbar.cpp
@@ -0,0 +1,147 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 "tdefilespeedbar.h"
+#include "config-tdefile.h"
+
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqtextcodec.h>
+#include <tqtextstream.h>
+
+#include <tdeconfig.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+
+KFileSpeedBar::KFileSpeedBar( TQWidget *parent, const char *name )
+ : KURLBar( true, parent, name )
+{
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver cs( config, ConfigGroup );
+ m_initializeSpeedbar = config->readBoolEntry( "Set speedbar defaults",
+ true );
+ setIconSize(KIcon::SizeSmallMedium);
+ readConfig( TDEGlobal::config(), "KFileDialog Speedbar" );
+
+ if ( m_initializeSpeedbar )
+ {
+ KURL u;
+ u.setPath( TDEGlobalSettings::desktopPath() );
+ insertItem( u, i18n("Desktop"), false );
+
+//TODO: win32
+ if ((TDEGlobalSettings::documentPath() != (TQDir::homeDirPath()+"/")) &&
+ TQDir(TDEGlobalSettings::documentPath()).exists())
+ {
+ u.setPath( TDEGlobalSettings::documentPath() );
+ insertItem( u, i18n("Documents"), false, "folder_txt" );
+ }
+
+ u.setPath( TQDir::homeDirPath() );
+ insertItem( u, i18n("Home Folder"), false,
+ "folder_home" );
+
+ u = "media:/";
+ if ( KProtocolInfo::isKnownProtocol( u ) )
+ insertItem( u, i18n("Storage Media"), false,
+ KProtocolInfo::icon( "media" ) );
+
+ if ( TQFile::exists( TQDir::homeDirPath()+"/.config/user-dirs.dirs" ) )
+ {
+ TQString download, music, pictures, videos, templates, publicShares;
+
+ TQFile f( TQDir::homeDirPath()+"/.config/user-dirs.dirs" );
+ if (!f.open(IO_ReadOnly))
+ return;
+
+ TQTextStream s( &f );
+ s.setCodec( TQTextCodec::codecForLocale() );
+
+ // read the xdg user dirs
+ TQString line = s.readLine();
+ while (!line.isNull())
+ {
+ if (line.startsWith("XDG_DOWNLOAD_DIR="))
+ download = line.remove("XDG_DOWNLOAD_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+ else if (line.startsWith("XDG_MUSIC_DIR="))
+ music = line.remove("XDG_MUSIC_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+ else if (line.startsWith("XDG_PICTURES_DIR="))
+ pictures = line.remove("XDG_PICTURES_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+ else if (line.startsWith("XDG_VIDEOS_DIR="))
+ videos = line.remove("XDG_VIDEOS_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+ else if (line.startsWith("XDG_TEMPLATES_DIR="))
+ templates = line.remove("XDG_TEMPLATES_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+ else if (line.startsWith("XDG_PUBLICSHARES_DIR="))
+ publicShares = line.remove("XDG_PUBLICSHARES_DIR=").remove("\"").replace("$HOME", TQDir::homeDirPath());
+
+ line = s.readLine();
+ }
+ // now add in the speedbar
+ if (!download.isEmpty())
+ insertItem( download, i18n( "Download" ), false, "folder_html" );
+ if (!music.isEmpty())
+ insertItem( music, i18n( "Music" ), false, "folder_sound" );
+ if (!pictures.isEmpty())
+ insertItem( pictures, i18n( "Pictures" ), false, "folder_image" );
+ if (!videos.isEmpty())
+ insertItem( videos, i18n( "Videos" ), false, "folder_video" );
+ if (!templates.isEmpty())
+ insertItem( templates, i18n( "Templates" ), false, "folder_video" );
+ if (!publicShares.isEmpty())
+ insertItem( publicShares, i18n( "Public" ), false, "folder_video" );
+ }
+
+ u = "remote:/";
+ if ( KProtocolInfo::isKnownProtocol( u ) )
+ insertItem( u, i18n("Network Folders"), false,
+ KProtocolInfo::icon( "remote" ) );
+ }
+}
+
+KFileSpeedBar::~KFileSpeedBar()
+{
+}
+
+void KFileSpeedBar::save( TDEConfig *config )
+{
+ if ( m_initializeSpeedbar && isModified() )
+ {
+ TDEConfigGroup conf( config, ConfigGroup );
+ // write to kdeglobals
+ conf.writeEntry( "Set speedbar defaults", false, true, true );
+ }
+
+ writeConfig( config, "KFileDialog Speedbar" );
+}
+
+TQSize KFileSpeedBar::sizeHint() const
+{
+ TQSize sizeHint = KURLBar::sizeHint();
+ int ems = fontMetrics().width("mmmmmmmmmmmm");
+ if (sizeHint.width() < ems)
+ {
+ sizeHint.setWidth(ems);
+ }
+ return sizeHint;
+}
+
+#include "tdefilespeedbar.moc"
diff --git a/tdeio/tdefile/tdefilespeedbar.h b/tdeio/tdefile/tdefilespeedbar.h
new file mode 100644
index 000000000..d1c2a689e
--- /dev/null
+++ b/tdeio/tdefile/tdefilespeedbar.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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, version 2.
+
+ 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 KFILESPEEDBAR_H
+#define KFILESPEEDBAR_H
+
+#include <kurlbar.h>
+
+class TDEConfig;
+
+class TDEIO_EXPORT KFileSpeedBar : public KURLBar
+{
+ Q_OBJECT
+public:
+ KFileSpeedBar( TQWidget *parent = 0, const char *name = 0 );
+ ~KFileSpeedBar();
+
+ virtual void save( TDEConfig *config );
+ virtual TQSize sizeHint() const;
+
+private:
+ bool m_initializeSpeedbar : 1;
+
+};
+
+#endif // KFILESPEEDBAR_H
diff --git a/tdeio/tdefile/tdefiletreebranch.cpp b/tdeio/tdefile/tdefiletreebranch.cpp
new file mode 100644
index 000000000..f95cb4d47
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreebranch.cpp
@@ -0,0 +1,528 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2002 Klaas Freitag <freitag@suse.de>
+
+ 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 <tqfile.h>
+
+#include <tdefileitem.h>
+#include <kdebug.h>
+#include <kde_file.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "tdefiletreeviewitem.h"
+#include "tdefiletreebranch.h"
+
+
+/* --- KFileTreeViewToplevelItem --- */
+KFileTreeBranch::KFileTreeBranch( KFileTreeView *parent, const KURL& url,
+ const TQString& name,
+ const TQPixmap& pix, bool showHidden,
+ KFileTreeViewItem *branchRoot )
+
+ : KDirLister( false ),
+ m_root( branchRoot ),
+ m_startURL( url ),
+ m_name ( name ),
+ m_rootIcon( pix ),
+ m_openRootIcon( pix ),
+ m_recurseChildren(true),
+ m_showExtensions(true)
+{
+ kdDebug( 250) << "Creating branch for url " << url.prettyURL() << endl;
+
+ /* if non exists, create one */
+ if( ! branchRoot )
+ {
+ m_root = new KFileTreeViewItem( parent,
+ new KFileItem( url, "inode/directory",
+ S_IFDIR ),
+ this );
+ }
+
+ m_root->setExpandable( true );
+ m_root->setPixmap( 0, pix );
+ m_root->setText( 0, name );
+
+ setShowingDotFiles( showHidden );
+
+ connect( this, TQT_SIGNAL( refreshItems(const KFileItemList&)),
+ this, TQT_SLOT ( slotRefreshItems( const KFileItemList& )));
+
+ connect( this, TQT_SIGNAL( newItems(const KFileItemList&)),
+ this, TQT_SLOT ( addItems( const KFileItemList& )));
+
+ connect( this, TQT_SIGNAL( completed(const KURL& )),
+ this, TQT_SLOT(slCompleted(const KURL&)));
+
+ connect( this, TQT_SIGNAL( started( const KURL& )),
+ this, TQT_SLOT( slotListerStarted( const KURL& )));
+
+ connect( this, TQT_SIGNAL( deleteItem( KFileItem* )),
+ this, TQT_SLOT( slotDeleteItem( KFileItem* )));
+
+ connect( this, TQT_SIGNAL( canceled(const KURL&) ),
+ this, TQT_SLOT( slotCanceled(const KURL&) ));
+
+ connect( this, TQT_SIGNAL( clear()),
+ this, TQT_SLOT( slotDirlisterClear()));
+
+ connect( this, TQT_SIGNAL( clear(const KURL&)),
+ this, TQT_SLOT( slotDirlisterClearURL(const KURL&)));
+
+ connect( this, TQT_SIGNAL( redirection( const KURL& , const KURL& ) ),
+ this, TQT_SLOT( slotRedirect( const KURL&, const KURL& )));
+
+ m_openChildrenURLs.append( url );
+}
+
+void KFileTreeBranch::setOpenPixmap( const TQPixmap& pix )
+{
+ m_openRootIcon = pix;
+
+ if( root()->isOpen())
+ {
+ root()->setPixmap( 0, pix );
+ }
+}
+
+void KFileTreeBranch::slotListerStarted( const KURL &url )
+{
+ /* set the parent correct if it is zero. */
+ kdDebug( 250) << "Starting to list " << url.prettyURL() << endl;
+}
+
+
+KFileTreeViewItem *KFileTreeBranch::parentKFTVItem( KFileItem *item )
+{
+ KFileTreeViewItem *parent = 0;
+
+ if( ! item ) return 0;
+
+ /* If it is a directory, check, if it exists in the dict. If not, go one up
+ * and check again.
+ */
+ KURL url = item->url();
+ // kdDebug(250) << "Item's url is " << url.prettyURL() << endl;
+ KURL dirUrl( url );
+ dirUrl.setFileName( TQString::null );
+ // kdDebug(250) << "Directory url is " << dirUrl.prettyURL() << endl;
+
+ parent = findTVIByURL( dirUrl );
+ // kdDebug(250) << "Returning as parent item <" << parent << ">" << endl;
+ return( parent );
+}
+
+
+void KFileTreeBranch::slotRefreshItems( const KFileItemList& list )
+{
+ KFileItemListIterator it( list );
+ kdDebug(250) << "Refreshing " << list.count() << " items !" << endl;
+ KFileItem *currItem;
+ KFileTreeViewItem *item = 0;
+
+ while ( (currItem = it.current()) != 0 )
+ {
+ item = findTVIByURL(currItem->url());
+ if (item) {
+ item->setPixmap(0, item->fileItem()->pixmap( KIcon::SizeSmall ));
+ item->setText( 0, item->fileItem()->text());
+ }
+ ++it;
+ }
+}
+
+void KFileTreeBranch::addItems( const KFileItemList& list )
+{
+ KFileItemListIterator it( list );
+ kdDebug(250) << "Adding " << list.count() << " items !" << endl;
+ KFileItem *currItem;
+ KFileTreeViewItemList treeViewItList;
+ KFileTreeViewItem *parentItem = 0;
+
+ while ( (currItem = it.current()) != 0 )
+ {
+ parentItem = parentKFTVItem( currItem );
+
+
+ /* Only create a new KFileTreeViewItem if it does not yet exist */
+ KFileTreeViewItem *newKFTVI =
+ static_cast<KFileTreeViewItem *>(currItem->extraData( this ));
+
+ if( ! newKFTVI )
+ {
+ newKFTVI = createTreeViewItem( parentItem, currItem );
+ if (!newKFTVI)
+ {
+ // TODO: Don't fail if parentItem == 0
+ ++it;
+ continue;
+ }
+ currItem->setExtraData( this, newKFTVI );
+
+ /* Cut off the file extension in case it is not a directory */
+ if( !m_showExtensions && !currItem->isDir() ) /* Need to cut the extension */
+ {
+ TQString name = currItem->text();
+ int mPoint = name.findRev( '.' );
+ if( mPoint > 0 )
+ name = name.left( mPoint );
+ newKFTVI->setText( 0, name );
+ }
+ }
+
+ /* Now try to find out if there are children for dirs in the treeview */
+ /* This stats a directory on the local file system and checks the */
+ /* hardlink entry in the stat-buf. This works only for local directories. */
+ if( dirOnlyMode() && !m_recurseChildren && currItem->isLocalFile( ) && currItem->isDir() )
+ {
+ KURL url = currItem->url();
+ TQString filename = url.directory( false, true ) + url.fileName();
+ /* do the stat trick of Carsten. The problem is, that the hardlink
+ * count only contains directory links. Thus, this method only seem
+ * to work in dir-only mode */
+ kdDebug(250) << "Doing stat on " << filename << endl;
+ KDE_struct_stat statBuf;
+ if( KDE_stat( TQFile::encodeName( filename ), &statBuf ) == 0 )
+ {
+ int hardLinks = statBuf.st_nlink; /* Count of dirs */
+ kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl;
+ // If the link count is > 2, the directory likely has subdirs. If it's < 2
+ // it's something weird like a mounted SMB share. In that case we don't know
+ // if there are subdirs, thus show it as expandable.
+
+ if( hardLinks != 2 )
+ {
+ newKFTVI->setExpandable(true);
+ }
+ else
+ {
+ newKFTVI->setExpandable(false);
+ }
+ if( hardLinks >= 2 ) // "Normal" directory with subdirs
+ {
+ kdDebug(250) << "Emitting for " << url.prettyURL() << endl;
+ emit( directoryChildCount( newKFTVI, hardLinks-2)); // parentItem, hardLinks-1 ));
+ }
+ }
+ else
+ {
+ kdDebug(250) << "stat of " << filename << " failed !" << endl;
+ }
+ }
+ ++it;
+
+ treeViewItList.append( newKFTVI );
+ }
+
+ emit newTreeViewItems( this, treeViewItList );
+}
+
+KFileTreeViewItem* KFileTreeBranch::createTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem *fileItem )
+{
+ KFileTreeViewItem *tvi = 0;
+ if( parent && fileItem )
+ {
+ tvi = new KFileTreeViewItem( parent,
+ fileItem,
+ this );
+ }
+ else
+ {
+ kdDebug(250) << "createTreeViewItem: Have no parent" << endl;
+ }
+ return( tvi );
+}
+
+void KFileTreeBranch::setChildRecurse( bool t )
+{
+ m_recurseChildren = t;
+ if( t == false )
+ m_openChildrenURLs.clear();
+}
+
+
+void KFileTreeBranch::setShowExtensions( bool visible )
+{
+ m_showExtensions = visible;
+}
+
+bool KFileTreeBranch::showExtensions( ) const
+{
+ return( m_showExtensions );
+}
+
+/*
+ * The signal that tells that a directory was deleted may arrive before the signal
+ * for its children arrive. Thus, we must walk through the children of a dir and
+ * remove them before removing the dir itself.
+ */
+void KFileTreeBranch::slotDeleteItem( KFileItem *it )
+{
+ if( !it ) return;
+ kdDebug(250) << "Slot Delete Item hitted for " << it->url().prettyURL() << endl;
+
+ KFileTreeViewItem *kfti = static_cast<KFileTreeViewItem*>(it->extraData(this));
+
+ if( kfti )
+ {
+ kdDebug( 250 ) << "Child count: " << kfti->childCount() << endl;
+ if( kfti->childCount() > 0 )
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(kfti->firstChild());
+
+ while( child )
+ {
+ kdDebug(250) << "Calling child to be deleted !" << endl;
+ KFileTreeViewItem *nextChild = static_cast<KFileTreeViewItem*>(child->nextSibling());
+ slotDeleteItem( child->fileItem());
+ child = nextChild;
+ }
+ }
+
+ kdDebug(250) << "Found corresponding KFileTreeViewItem" << endl;
+ if( m_lastFoundURL.equals(it->url(), true ))
+ {
+ m_lastFoundURL = KURL();
+ m_lastFoundItem = 0L;
+ }
+ delete( kfti );
+ }
+ else
+ {
+ kdDebug(250) << "Error: tdefiletreeviewitem: "<< kfti << endl;
+ }
+}
+
+
+void KFileTreeBranch::slotCanceled( const KURL& url )
+{
+ // ### anything else to do?
+ // remove the url from the childrento-recurse-list
+ m_openChildrenURLs.remove( url);
+
+ // stop animations etc.
+ KFileTreeViewItem *item = findTVIByURL(url);
+ if (!item) return; // Uh oh...
+ emit populateFinished(item);
+}
+
+void KFileTreeBranch::slotDirlisterClear()
+{
+ kdDebug(250)<< "*** Clear all !" << endl;
+ /* this slots needs to clear all listed items, but NOT the root item */
+ if( m_root )
+ deleteChildrenOf( m_root );
+}
+
+void KFileTreeBranch::slotDirlisterClearURL( const KURL& url )
+{
+ kdDebug(250)<< "*** Clear for URL !" << url.prettyURL() << endl;
+ KFileItem *item = findByURL( url );
+ if( item )
+ {
+ KFileTreeViewItem *ftvi =
+ static_cast<KFileTreeViewItem *>(item->extraData( this ));
+ deleteChildrenOf( ftvi );
+ }
+}
+
+void KFileTreeBranch::deleteChildrenOf( TQListViewItem *parent )
+{
+ // for some strange reason, slotDirlisterClearURL() sometimes calls us
+ // with a 0L parent.
+ if ( !parent )
+ return;
+
+ while ( parent->firstChild() )
+ delete parent->firstChild();
+}
+
+void KFileTreeBranch::slotRedirect( const KURL& oldUrl, const KURL&newUrl )
+{
+ if( oldUrl.equals( m_startURL, true ))
+ {
+ m_startURL = newUrl;
+ }
+}
+
+KFileTreeViewItem* KFileTreeBranch::findTVIByURL( const KURL& url )
+{
+ KFileTreeViewItem *resultItem = 0;
+
+ if( m_startURL.equals(url, true) )
+ {
+ kdDebug(250) << "findByURL: Returning root as a parent !" << endl;
+ resultItem = m_root;
+ }
+ else if( m_lastFoundURL.equals( url, true ))
+ {
+ kdDebug(250) << "findByURL: Returning from lastFoundURL!" << endl;
+ resultItem = m_lastFoundItem;
+ }
+ else
+ {
+ kdDebug(250) << "findByURL: searching by dirlister: " << url.url() << endl;
+
+ KFileItem *it = findByURL( url );
+
+ if( it )
+ {
+ resultItem = static_cast<KFileTreeViewItem*>(it->extraData(this));
+ m_lastFoundItem = resultItem;
+ m_lastFoundURL = url;
+ }
+ }
+
+ return( resultItem );
+}
+
+
+void KFileTreeBranch::slCompleted( const KURL& url )
+{
+ kdDebug(250) << "SlotCompleted hit for " << url.prettyURL() << endl;
+ KFileTreeViewItem *currParent = findTVIByURL( url );
+ if( ! currParent ) return;
+
+ kdDebug(250) << "current parent " << currParent << " is already listed: "
+ << currParent->alreadyListed() << endl;
+
+ emit( populateFinished(currParent));
+ emit( directoryChildCount(currParent, currParent->childCount()));
+
+ /* This is a walk through the children of the last populated directory.
+ * Here we start the dirlister on every child of the dir and wait for its
+ * finish. When it has finished, we go to the next child.
+ * This must be done for non local file systems in dirOnly- and Full-Mode
+ * and for local file systems only in full mode, because the stat trick
+ * (see addItem-Method) does only work for dirs, not for files in the directory.
+ */
+ /* Set bit that the parent dir was listed completely */
+ currParent->setListed(true);
+
+ kdDebug(250) << "recurseChildren: " << m_recurseChildren << endl;
+ kdDebug(250) << "isLocalFile: " << m_startURL.isLocalFile() << endl;
+ kdDebug(250) << "dirOnlyMode: " << dirOnlyMode() << endl;
+
+
+ if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) )
+ {
+ bool wantRecurseUrl = false;
+ /* look if the url is in the list for url to recurse */
+ for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
+ it != m_openChildrenURLs.end(); ++it )
+ {
+ /* it is only interesting that the url _is_in_ the list. */
+ if( (*it).equals( url, true ) )
+ wantRecurseUrl = true;
+ }
+
+ KFileTreeViewItem *nextChild = 0;
+ kdDebug(250) << "Recursing " << url.prettyURL() << "? " << wantRecurseUrl << endl;
+
+ if( wantRecurseUrl && currParent )
+ {
+
+ /* now walk again through the tree and populate the children to get +-signs */
+ /* This is the starting point. The visible folder has finished,
+ processing the children has not yet started */
+ nextChild = static_cast<KFileTreeViewItem*>
+ (static_cast<TQListViewItem*>(currParent)->firstChild());
+
+ if( ! nextChild )
+ {
+ /* This happens if there is no child at all */
+ kdDebug( 250 ) << "No children to recuse" << endl;
+ }
+
+ /* Since we have listed the children to recurse, we can remove the entry
+ * in the list of the URLs to see the children.
+ */
+ m_openChildrenURLs.remove(url);
+ }
+
+ if( nextChild ) /* This implies that idx > -1 */
+ {
+ /* Next child is defined. We start a dirlister job on every child item
+ * which is a directory to find out how much children are in the child
+ * of the last opened dir
+ */
+
+ /* Skip non directory entries */
+ while( nextChild )
+ {
+ if( nextChild->isDir() && ! nextChild->alreadyListed())
+ {
+ KFileItem *kfi = nextChild->fileItem();
+ if( kfi && kfi->isReadable())
+ {
+ KURL recurseUrl = kfi->url();
+ kdDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyURL() << endl;
+ openURL( recurseUrl, true );
+ }
+ }
+ nextChild = static_cast<KFileTreeViewItem*>(static_cast<TQListViewItem*>(nextChild->nextSibling()));
+ // kdDebug(250) << "Next child " << m_nextChild << endl;
+ }
+ }
+ }
+ else
+ {
+ kdDebug(250) << "skipping to recurse in complete-slot" << endl;
+ }
+}
+
+/* This slot is called when a treeviewitem is expanded in the gui */
+bool KFileTreeBranch::populate( const KURL& url, KFileTreeViewItem *currItem )
+{
+ bool ret = false;
+ if( ! currItem )
+ return ret;
+
+ kdDebug(250) << "Populating <" << url.prettyURL() << ">" << endl;
+
+ /* Add this url to the list of urls to recurse for children */
+ if( m_recurseChildren )
+ {
+ m_openChildrenURLs.append( url );
+ kdDebug(250) << "Appending to list " << url.prettyURL() << endl;
+ }
+
+ if( ! currItem->alreadyListed() )
+ {
+ /* start the lister */
+ ret = openURL( url, true );
+ }
+ else
+ {
+ kdDebug(250) << "Children already existing in treeview!" << endl;
+ slCompleted( url );
+ ret = true;
+ }
+ return ret;
+}
+
+void KFileTreeBranch::virtual_hook( int id, void* data )
+{ KDirLister::virtual_hook( id, data ); }
+
+#include "tdefiletreebranch.moc"
+
diff --git a/tdeio/tdefile/tdefiletreebranch.h b/tdeio/tdefile/tdefiletreebranch.h
new file mode 100644
index 000000000..a8548b10c
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreebranch.h
@@ -0,0 +1,242 @@
+
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Klaas Freitag <freitag@suse.de>
+
+ 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 tdefile_tree_branch_h
+#define tdefile_tree_branch_h
+
+#include <tqdict.h>
+#include <tqlistview.h>
+
+#include <tdefileitem.h>
+#include <tdeio/global.h>
+#include <kdirlister.h>
+#include <tdeio/job.h>
+#include <tdefiletreeviewitem.h>
+
+class KURL;
+class KFileTreeView;
+
+
+/**
+ * This is the branch class of the KFileTreeView, which represents one
+ * branch in the treeview. Every branch has a root which is an url. The branch
+ * lists the files under the root. Every branch uses its own dirlister and can
+ * have its own filter etc.
+ *
+ * @short Branch object for KFileTreeView object.
+ *
+ */
+
+class TDEIO_EXPORT KFileTreeBranch : public KDirLister
+{
+ Q_OBJECT
+public:
+ /**
+ * constructs a branch for KFileTreeView. Does not yet start to list it.
+ * @param url start url of the branch.
+ * @param name the name of the branch, which is displayed in the first column of the treeview.
+ * @param pix is a pixmap to display as an icon of the branch.
+ * @param showHidden flag to make hidden files visible or not.
+ * @param branchRoot is the KFileTreeViewItem to use as the root of the
+ * branch, with the default 0 meaning to let KFileTreeBranch create
+ * it for you.
+ */
+ KFileTreeBranch( KFileTreeView*, const KURL& url, const TQString& name,
+ const TQPixmap& pix, bool showHidden = false,
+ KFileTreeViewItem *branchRoot = 0 );
+
+ /**
+ * @returns the root url of the branch.
+ */
+ KURL rootUrl() const { return( m_startURL ); }
+
+ /**
+ * sets a KFileTreeViewItem as root widget for the branch.
+ * That must be created outside of the branch. All KFileTreeViewItems
+ * the branch is allocating will become children of that object.
+ * @param r the KFileTreeViewItem to become the root item.
+ */
+ virtual void setRoot( KFileTreeViewItem *r ){ m_root = r; };
+
+ /**
+ * @returns the root item.
+ */
+ KFileTreeViewItem *root( ) { return( m_root );}
+
+ /**
+ * @returns the name of the branch.
+ */
+ TQString name() const { return( m_name ); }
+
+ /**
+ * sets the name of the branch.
+ */
+ virtual void setName( const TQString n ) { m_name = n; };
+
+ /*
+ * returns the current root item pixmap set in the constructor. The root
+ * item pixmap defaults to the icon for directories.
+ * @see openPixmap()
+ */
+ const TQPixmap& pixmap(){ return(m_rootIcon); }
+
+ /*
+ * returns the current root item pixmap set by setOpenPixmap()
+ * which is displayed if the branch is expanded.
+ * The root item pixmap defaults to the icon for directories.
+ * @see pixmap()
+ * Note that it depends on KFileTreeView::showFolderOpenPximap weather
+ * open pixmap are displayed or not.
+ */
+ const TQPixmap& openPixmap() { return(m_openRootIcon); }
+
+ /**
+ * @returns whether the items in the branch show their file extensions in the
+ * tree or not. See setShowExtensions for more information.
+ */
+ bool showExtensions( ) const;
+
+ /**
+ * sets the root of the branch open or closed.
+ */
+ void setOpen( bool setopen = true )
+ { if( root() ) root()->setOpen( setopen ); }
+
+ /**
+ * sets if children recursion is wanted or not. If this is switched off, the
+ * child directories of a just opened directory are not listed internally.
+ * That means that it can not be determined if the sub directories are
+ * expandable or not. If this is switched off there will be no call to
+ * setExpandable.
+ * @param t set to true to switch on child recursion
+ */
+ void setChildRecurse( bool t=true );
+
+ /**
+ * @returns if child recursion is on or off.
+ * @see setChildRecurse
+ */
+ bool childRecurse()
+ { return m_recurseChildren; }
+
+public slots:
+ /**
+ * populates a branch. This method must be called after a branch was added
+ * to a KFileTreeView using method addBranch.
+ * @param url is the url of the root item where the branch starts.
+ * @param currItem is the current parent.
+ */
+ virtual bool populate( const KURL &url, KFileTreeViewItem* currItem );
+
+ /**
+ * sets printing of the file extensions on or off. If you pass false to this
+ * slot, all items of this branch will not show their file extensions in the
+ * tree.
+ * @param visible flags if the extensions should be visible or not.
+ */
+ virtual void setShowExtensions( bool visible = true );
+
+ void setOpenPixmap( const TQPixmap& pix );
+
+protected:
+ /**
+ * allocates a KFileTreeViewItem for the branch
+ * for new items.
+ */
+ virtual KFileTreeViewItem *createTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem *fileItem );
+
+public:
+ /**
+ * find the according KFileTreeViewItem by an url
+ */
+ virtual KFileTreeViewItem *findTVIByURL( const KURL& );
+
+signals:
+ /**
+ * emitted with the item of a directory which was finished to populate
+ */
+ void populateFinished( KFileTreeViewItem * );
+
+ /**
+ * emitted with a list of new or updated KFileTreeViewItem which were
+ * found in a branch. Note that this signal is emitted very often and may slow
+ * down the performance of the treeview !
+ */
+ void newTreeViewItems( KFileTreeBranch*, const KFileTreeViewItemList& );
+
+ /**
+ * emitted with the exact count of children for a directory.
+ */
+ void directoryChildCount( KFileTreeViewItem* item, int count );
+
+private slots:
+ void slotRefreshItems( const KFileItemList& );
+ void addItems( const KFileItemList& );
+ void slCompleted( const KURL& );
+ void slotCanceled( const KURL& );
+ void slotListerStarted( const KURL& );
+ void slotDeleteItem( KFileItem* );
+ void slotDirlisterClear();
+ void slotDirlisterClearURL( const KURL& url );
+ void slotRedirect( const KURL& oldUrl, const KURL&newUrl );
+
+private:
+ KFileTreeViewItem *parentKFTVItem( KFileItem *item );
+ static void deleteChildrenOf( TQListViewItem *parent );
+
+ KFileTreeViewItem *m_root;
+ KURL m_startURL;
+ TQString m_name;
+ TQPixmap m_rootIcon;
+ TQPixmap m_openRootIcon;
+
+ /* this list holds the url's which children are opened. */
+ KURL::List m_openChildrenURLs;
+
+
+ /* The next two members are used for caching purposes in findTVIByURL. */
+ KURL m_lastFoundURL;
+ KFileTreeViewItem *m_lastFoundItem;
+
+ bool m_recurseChildren :1;
+ bool m_showExtensions :1;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileTreeBranchPrivate;
+ KFileTreeBranchPrivate *d;
+};
+
+
+/**
+ * List of KFileTreeBranches
+ */
+typedef TQPtrList<KFileTreeBranch> KFileTreeBranchList;
+
+/**
+ * Iterator for KFileTreeBranchLists
+ */
+typedef TQPtrListIterator<KFileTreeBranch> KFileTreeBranchIterator;
+
+#endif
+
diff --git a/tdeio/tdefile/tdefiletreeview.cpp b/tdeio/tdefile/tdefiletreeview.cpp
new file mode 100644
index 000000000..480c58ec3
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreeview.cpp
@@ -0,0 +1,677 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@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 <tqapplication.h>
+#include <tqheader.h>
+#include <tqtimer.h>
+#include <kdebug.h>
+#include <kdirnotify_stub.h>
+#include <kglobalsettings.h>
+#include <tdefileitem.h>
+#include <tdefileview.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <tdeio/job.h>
+#include <tdeio/global.h>
+#include <kurldrag.h>
+#include <kiconloader.h>
+
+
+#include "tdefiletreeview.h"
+#include "tdefiletreebranch.h"
+#include "tdefiletreeviewitem.h"
+
+KFileTreeView::KFileTreeView( TQWidget *parent, const char *name )
+ : KListView( parent, name ),
+ m_wantOpenFolderPixmaps( true ),
+ m_toolTip( this )
+{
+ setDragEnabled(true);
+ setSelectionModeExt( KListView::Single );
+
+ m_animationTimer = new TQTimer( this );
+ connect( m_animationTimer, TQT_SIGNAL( timeout() ),
+ this, TQT_SLOT( slotAnimation() ) );
+
+ m_currentBeforeDropItem = 0;
+ m_dropItem = 0;
+
+ m_autoOpenTimer = new TQTimer( this );
+ connect( m_autoOpenTimer, TQT_SIGNAL( timeout() ),
+ this, TQT_SLOT( slotAutoOpenFolder() ) );
+
+ /* The executed-Slot only opens a path, while the expanded-Slot populates it */
+ connect( this, TQT_SIGNAL( executed( TQListViewItem * ) ),
+ this, TQT_SLOT( slotExecuted( TQListViewItem * ) ) );
+ connect( this, TQT_SIGNAL( expanded ( TQListViewItem *) ),
+ this, TQT_SLOT( slotExpanded( TQListViewItem *) ));
+ connect( this, TQT_SIGNAL( collapsed( TQListViewItem *) ),
+ this, TQT_SLOT( slotCollapsed( TQListViewItem* )));
+
+
+ /* connections from the konqtree widget */
+ connect( this, TQT_SIGNAL( selectionChanged() ),
+ this, TQT_SLOT( slotSelectionChanged() ) );
+ connect( this, TQT_SIGNAL( onItem( TQListViewItem * )),
+ this, TQT_SLOT( slotOnItem( TQListViewItem * ) ) );
+ connect( this, TQT_SIGNAL(itemRenamed(TQListViewItem*, const TQString &, int)),
+ this, TQT_SLOT(slotItemRenamed(TQListViewItem*, const TQString &, int)));
+
+
+ m_bDrag = false;
+ m_branches.setAutoDelete( true );
+
+ m_openFolderPixmap = DesktopIcon( "folder_open",KIcon::SizeSmall,KIcon::ActiveState );
+}
+
+KFileTreeView::~KFileTreeView()
+{
+ // we must make sure that the KFileTreeViewItems are deleted _before_ the
+ // branches are deleted. Otherwise, the KFileItems would be destroyed
+ // and the KFileTreeViewItems had dangling pointers to them.
+ hide();
+ clear();
+ m_branches.clear(); // finally delete the branches and KFileItems
+}
+
+
+bool KFileTreeView::isValidItem( TQListViewItem *item)
+{
+ if (!item)
+ return false;
+ TQPtrList<TQListViewItem> lst;
+ TQListViewItemIterator it( this );
+ while ( it.current() )
+ {
+ if ( it.current() == item )
+ return true;
+ ++it;
+ }
+ return false;
+}
+
+void KFileTreeView::contentsDragEnterEvent( TQDragEnterEvent *ev )
+{
+ if ( ! acceptDrag( ev ) )
+ {
+ ev->ignore();
+ return;
+ }
+ ev->acceptAction();
+ m_currentBeforeDropItem = selectedItem();
+
+ TQListViewItem *item = itemAt( contentsToViewport( ev->pos() ) );
+ if( item )
+ {
+ m_dropItem = item;
+ m_autoOpenTimer->start( KFileView::autoOpenDelay() );
+ }
+ else
+ {
+ m_dropItem = 0;
+}
+}
+
+void KFileTreeView::contentsDragMoveEvent( TQDragMoveEvent *e )
+{
+ if( ! acceptDrag( e ) )
+ {
+ e->ignore();
+ return;
+ }
+ e->acceptAction();
+
+
+ TQListViewItem *afterme;
+ TQListViewItem *parent;
+
+ findDrop( e->pos(), parent, afterme );
+
+ // "afterme" is 0 when aiming at a directory itself
+ TQListViewItem *item = afterme ? afterme : parent;
+
+ if( item && item->isSelectable() )
+ {
+ setSelected( item, true );
+ if( item != m_dropItem ) {
+ m_autoOpenTimer->stop();
+ m_dropItem = item;
+ m_autoOpenTimer->start( KFileView::autoOpenDelay() );
+ }
+ }
+ else
+ {
+ m_autoOpenTimer->stop();
+ m_dropItem = 0;
+ }
+}
+
+void KFileTreeView::contentsDragLeaveEvent( TQDragLeaveEvent * )
+{
+ // Restore the current item to what it was before the dragging (#17070)
+ if ( isValidItem(m_currentBeforeDropItem) )
+ {
+ setSelected( m_currentBeforeDropItem, true );
+ ensureItemVisible( m_currentBeforeDropItem );
+ }
+ else if ( isValidItem(m_dropItem) )
+ setSelected( m_dropItem, false ); // no item selected
+ m_currentBeforeDropItem = 0;
+ m_dropItem = 0;
+
+}
+
+void KFileTreeView::contentsDropEvent( TQDropEvent *e )
+{
+
+ m_autoOpenTimer->stop();
+ m_dropItem = 0;
+
+ kdDebug(250) << "contentsDropEvent !" << endl;
+ if( ! acceptDrag( e ) ) {
+ e->ignore();
+ return;
+ }
+
+ e->acceptAction();
+ TQListViewItem *afterme;
+ TQListViewItem *parent;
+ findDrop(e->pos(), parent, afterme);
+
+ //kdDebug(250) << " parent=" << (parent?parent->text(0):TQString::null)
+ // << " afterme=" << (afterme?afterme->text(0):TQString::null) << endl;
+
+ if (e->source() == viewport() && itemsMovable())
+ movableDropEvent(parent, afterme);
+ else
+ {
+ emit dropped(e, afterme);
+ emit dropped(this, e, afterme);
+ emit dropped(e, parent, afterme);
+ emit dropped(this, e, parent, afterme);
+
+ KURL::List urls;
+ KURLDrag::decode( e, urls );
+ emit dropped( this, e, urls );
+
+ KURL parentURL;
+ if( parent )
+ parentURL = static_cast<KFileTreeViewItem*>(parent)->url();
+ else
+ // can happen when dropping above the root item
+ // Should we choose the first branch in such a case ??
+ return;
+
+ emit dropped( urls, parentURL );
+ emit dropped( this , e, urls, parentURL );
+ }
+}
+
+bool KFileTreeView::acceptDrag(TQDropEvent* e ) const
+{
+
+ bool ancestOK= acceptDrops();
+ // kdDebug(250) << "Do accept drops: " << ancestOK << endl;
+ ancestOK = ancestOK && itemsMovable();
+ // kdDebug(250) << "acceptDrag: " << ancestOK << endl;
+ // kdDebug(250) << "canDecode: " << KURLDrag::canDecode(e) << endl;
+ // kdDebug(250) << "action: " << e->action() << endl;
+
+ /* KListView::acceptDrag(e); */
+ /* this is what KListView does:
+ * acceptDrops() && itemsMovable() && (e->source()==viewport());
+ * ask acceptDrops and itemsMovable, but not the third
+ */
+ return ancestOK && KURLDrag::canDecode( e ) &&
+ // Why this test? All DnDs are one of those AFAIK (DF)
+ ( e->action() == TQDropEvent::Copy
+ || e->action() == TQDropEvent::Move
+ || e->action() == TQDropEvent::Link );
+}
+
+
+
+TQDragObject * KFileTreeView::dragObject()
+{
+
+ KURL::List urls;
+ const TQPtrList<TQListViewItem> fileList = selectedItems();
+ TQPtrListIterator<TQListViewItem> it( fileList );
+ for ( ; it.current(); ++it )
+ {
+ urls.append( static_cast<KFileTreeViewItem*>(it.current())->url() );
+ }
+ TQPoint hotspot;
+ TQPixmap pixmap;
+ if( urls.count() > 1 ){
+ pixmap = DesktopIcon( "tdemultiple", 16 );
+ }
+ if( pixmap.isNull() )
+ pixmap = currentKFileTreeViewItem()->fileItem()->pixmap( 16 );
+ hotspot.setX( pixmap.width() / 2 );
+ hotspot.setY( pixmap.height() / 2 );
+ TQDragObject* dragObject = new KURLDrag( urls, this );
+ if( dragObject )
+ dragObject->setPixmap( pixmap, hotspot );
+ return dragObject;
+}
+
+
+
+void KFileTreeView::slotCollapsed( TQListViewItem *item )
+{
+ KFileTreeViewItem *kftvi = static_cast<KFileTreeViewItem*>(item);
+ kdDebug(250) << "hit slotCollapsed" << endl;
+ if( kftvi && kftvi->isDir())
+ {
+ item->setPixmap( 0, itemIcon(kftvi));
+ }
+}
+
+void KFileTreeView::slotExpanded( TQListViewItem *item )
+{
+ kdDebug(250) << "slotExpanded here !" << endl;
+
+ if( ! item ) return;
+
+ KFileTreeViewItem *it = static_cast<KFileTreeViewItem*>(item);
+ KFileTreeBranch *branch = it->branch();
+
+ /* Start the animation for the branch object */
+ if( it->isDir() && branch && item->childCount() == 0 )
+ {
+ /* check here if the branch really needs to be populated again */
+ kdDebug(250 ) << "starting to open " << it->url().prettyURL() << endl;
+ startAnimation( it );
+ bool branchAnswer = branch->populate( it->url(), it );
+ kdDebug(250) << "Branches answer: " << branchAnswer << endl;
+ if( ! branchAnswer )
+ {
+ kdDebug(250) << "ERR: Could not populate!" << endl;
+ stopAnimation( it );
+ }
+ }
+
+ /* set a pixmap 'open folder' */
+ if( it->isDir() && isOpen( item ) )
+ {
+ kdDebug(250)<< "Setting open Pixmap" << endl;
+ item->setPixmap( 0, itemIcon( it )); // 0, m_openFolderPixmap );
+ }
+}
+
+
+
+void KFileTreeView::slotExecuted( TQListViewItem *item )
+{
+ if ( !item )
+ return;
+ /* This opens the dir and causes the Expanded-slot to be called,
+ * which strolls through the children.
+ */
+ if( static_cast<KFileTreeViewItem*>(item)->isDir())
+ {
+ item->setOpen( !item->isOpen() );
+ }
+}
+
+
+void KFileTreeView::slotAutoOpenFolder()
+{
+ m_autoOpenTimer->stop();
+
+ if ( !isValidItem(m_dropItem) || m_dropItem->isOpen() )
+ return;
+
+ m_dropItem->setOpen( true );
+ m_dropItem->repaint();
+}
+
+
+void KFileTreeView::slotSelectionChanged()
+{
+ if ( !m_dropItem ) // don't do this while the dragmove thing
+ {
+ }
+}
+
+
+KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const TQString& name,
+ bool showHidden )
+{
+ const TQPixmap& folderPix = KMimeType::mimeType("inode/directory")->pixmap( KIcon::Desktop,KIcon::SizeSmall );
+
+ return addBranch( path, name, folderPix, showHidden);
+}
+
+KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const TQString& name,
+ const TQPixmap& pix, bool showHidden )
+{
+ kdDebug(250) << "adding another root " << path.prettyURL() << endl;
+
+ /* Open a new branch */
+ KFileTreeBranch *newBranch = new KFileTreeBranch( this, path, name, pix,
+ showHidden );
+ return addBranch(newBranch);
+}
+
+KFileTreeBranch *KFileTreeView::addBranch(KFileTreeBranch *newBranch)
+{
+ connect( newBranch, TQT_SIGNAL(populateFinished( KFileTreeViewItem* )),
+ this, TQT_SLOT( slotPopulateFinished( KFileTreeViewItem* )));
+
+ connect( newBranch, TQT_SIGNAL( newTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& )),
+ this, TQT_SLOT( slotNewTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& )));
+
+ m_branches.append( newBranch );
+ return( newBranch );
+}
+
+KFileTreeBranch *KFileTreeView::branch( const TQString& searchName )
+{
+ KFileTreeBranch *branch = 0;
+ TQPtrListIterator<KFileTreeBranch> it( m_branches );
+
+ while ( (branch = it.current()) != 0 ) {
+ ++it;
+ TQString bname = branch->name();
+ kdDebug(250) << "This is the branches name: " << bname << endl;
+ if( bname == searchName )
+ {
+ kdDebug(250) << "Found branch " << bname << " and return ptr" << endl;
+ return( branch );
+ }
+ }
+ return ( 0L );
+}
+
+KFileTreeBranchList& KFileTreeView::branches()
+{
+ return( m_branches );
+}
+
+
+bool KFileTreeView::removeBranch( KFileTreeBranch *branch )
+{
+ if(m_branches.contains(branch))
+ {
+ delete (branch->root());
+ m_branches.remove( branch );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void KFileTreeView::setDirOnlyMode( KFileTreeBranch* branch, bool bom )
+{
+ if( branch )
+ {
+ branch->setDirOnlyMode( bom );
+ }
+}
+
+
+void KFileTreeView::slotPopulateFinished( KFileTreeViewItem *it )
+{
+ if( it && it->isDir())
+ stopAnimation( it );
+}
+
+void KFileTreeView::slotNewTreeViewItems( KFileTreeBranch* branch, const KFileTreeViewItemList& itemList )
+{
+ if( ! branch ) return;
+ kdDebug(250) << "hitting slotNewTreeViewItems" << endl;
+
+ /* Sometimes it happens that new items should become selected, i.e. if the user
+ * creates a new dir, he probably wants it to be selected. This can not be done
+ * right after creating the directory or file, because it takes some time until
+ * the item appears here in the treeview. Thus, the creation code sets the member
+ * m_neUrlToSelect to the required url. If this url appears here, the item becomes
+ * selected and the member nextUrlToSelect will be cleared.
+ */
+ if( ! m_nextUrlToSelect.isEmpty() )
+ {
+ KFileTreeViewItemListIterator it( itemList );
+
+ bool end = false;
+ for( ; !end && it.current(); ++it )
+ {
+ KURL url = (*it)->url();
+
+ if( m_nextUrlToSelect.equals(url, true )) // ignore trailing / on dirs
+ {
+ setCurrentItem( static_cast<TQListViewItem*>(*it) );
+ m_nextUrlToSelect = KURL();
+ end = true;
+ }
+ }
+ }
+}
+
+TQPixmap KFileTreeView::itemIcon( KFileTreeViewItem *item, int gap ) const
+{
+ TQPixmap pix;
+ kdDebug(250) << "Setting icon for column " << gap << endl;
+
+ if( item )
+ {
+ /* Check if it is a branch root */
+ KFileTreeBranch *brnch = item->branch();
+ if( item == brnch->root() )
+ {
+ pix = brnch->pixmap();
+ if( m_wantOpenFolderPixmaps && brnch->root()->isOpen() )
+ {
+ pix = brnch->openPixmap();
+ }
+ }
+ else
+ {
+ // TODO: different modes, user Pixmaps ?
+ pix = item->fileItem()->pixmap( KIcon::SizeSmall ); // , KIcon::DefaultState);
+
+ /* Only if it is a dir and the user wants open dir pixmap and it is open,
+ * change the fileitem's pixmap to the open folder pixmap. */
+ if( item->isDir() && m_wantOpenFolderPixmaps )
+ {
+ if( isOpen( static_cast<TQListViewItem*>(item)))
+ pix = m_openFolderPixmap;
+ }
+ }
+ }
+
+ return pix;
+}
+
+
+void KFileTreeView::slotAnimation()
+{
+ MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.begin();
+ MapCurrentOpeningFolders::Iterator end = m_mapCurrentOpeningFolders.end();
+ for (; it != end;)
+ {
+ KFileTreeViewItem *item = it.key();
+ if (!isValidItem(item))
+ {
+ ++it;
+ m_mapCurrentOpeningFolders.remove(item);
+ continue;
+ }
+
+ uint & iconNumber = it.data().iconNumber;
+ TQString icon = TQString::fromLatin1( it.data().iconBaseName ).append( TQString::number( iconNumber ) );
+ // kdDebug(250) << "Loading icon " << icon << endl;
+ item->setPixmap( 0, DesktopIcon( icon,KIcon::SizeSmall,KIcon::ActiveState )); // KFileTreeViewFactory::instance() ) );
+
+ iconNumber++;
+ if ( iconNumber > it.data().iconCount )
+ iconNumber = 1;
+
+ ++it;
+ }
+}
+
+
+void KFileTreeView::startAnimation( KFileTreeViewItem * item, const char * iconBaseName, uint iconCount )
+{
+ /* TODO: allow specific icons */
+ if( ! item )
+ {
+ kdDebug(250) << " startAnimation Got called without valid item !" << endl;
+ return;
+ }
+
+ m_mapCurrentOpeningFolders.insert( item,
+ AnimationInfo( iconBaseName,
+ iconCount,
+ itemIcon(item, 0) ) );
+ if ( !m_animationTimer->isActive() )
+ m_animationTimer->start( 50 );
+}
+
+void KFileTreeView::stopAnimation( KFileTreeViewItem * item )
+{
+ if( ! item ) return;
+
+ kdDebug(250) << "Stoping Animation !" << endl;
+
+ MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.find(item);
+ if ( it != m_mapCurrentOpeningFolders.end() )
+ {
+ if( item->isDir() && isOpen( item) )
+ {
+ kdDebug(250) << "Setting folder open pixmap !" << endl;
+ item->setPixmap( 0, itemIcon( item ));
+ }
+ else
+ {
+ item->setPixmap( 0, it.data().originalPixmap );
+ }
+ m_mapCurrentOpeningFolders.remove( item );
+ }
+ else
+ {
+ if( item )
+ kdDebug(250)<< "StopAnimation - could not find item " << item->url().prettyURL()<< endl;
+ else
+ kdDebug(250)<< "StopAnimation - item is zero !" << endl;
+ }
+ if (m_mapCurrentOpeningFolders.isEmpty())
+ m_animationTimer->stop();
+}
+
+KFileTreeViewItem * KFileTreeView::currentKFileTreeViewItem() const
+{
+ return static_cast<KFileTreeViewItem *>( selectedItem() );
+}
+
+KURL KFileTreeView::currentURL() const
+{
+ KFileTreeViewItem *item = currentKFileTreeViewItem();
+ if ( item )
+ return currentKFileTreeViewItem()->url();
+ else
+ return KURL();
+}
+
+void KFileTreeView::slotOnItem( TQListViewItem *item )
+{
+ KFileTreeViewItem *i = static_cast<KFileTreeViewItem *>( item );
+ if( i )
+ {
+ const KURL url = i->url();
+ if ( url.isLocalFile() )
+ emit onItem( url.path() );
+ else
+ emit onItem( url.prettyURL() );
+ }
+}
+
+void KFileTreeView::slotItemRenamed(TQListViewItem* item, const TQString &name, int col)
+{
+ (void) item;
+ kdDebug(250) << "Do not bother: " << name << col << endl;
+}
+
+KFileTreeViewItem *KFileTreeView::findItem( const TQString& branchName, const TQString& relUrl )
+{
+ KFileTreeBranch *br = branch( branchName );
+ return( findItem( br, relUrl ));
+}
+
+KFileTreeViewItem *KFileTreeView::findItem( KFileTreeBranch* brnch, const TQString& relUrl )
+{
+ KFileTreeViewItem *ret = 0;
+ if( brnch )
+ {
+ KURL url = brnch->rootUrl();
+
+ if( ! relUrl.isEmpty() && TQDir::isRelativePath(relUrl) )
+ {
+ TQString partUrl( relUrl );
+
+ if( partUrl.endsWith("/"))
+ partUrl.truncate( relUrl.length()-1 );
+
+ url.addPath( partUrl );
+
+ kdDebug(250) << "assembled complete dir string " << url.prettyURL() << endl;
+
+ KFileItem *fi = brnch->findByURL( url );
+ if( fi )
+ {
+ ret = static_cast<KFileTreeViewItem*>( fi->extraData( brnch ));
+ kdDebug(250) << "Found item !" <<ret << endl;
+ }
+ }
+ else
+ {
+ ret = brnch->root();
+ }
+ }
+ return( ret );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+void KFileTreeViewToolTip::maybeTip( const TQPoint & )
+{
+#if 0
+ TQListViewItem *item = m_view->itemAt( point );
+ if ( item ) {
+ TQString text = static_cast<KFileViewItem*>( item )->toolTipText();
+ if ( !text.isEmpty() )
+ tip ( m_view->itemRect( item ), text );
+ }
+#endif
+}
+
+void KFileTreeView::virtual_hook( int id, void* data )
+{ KListView::virtual_hook( id, data ); }
+
+#include "tdefiletreeview.moc"
diff --git a/tdeio/tdefile/tdefiletreeview.h b/tdeio/tdefile/tdefiletreeview.h
new file mode 100644
index 000000000..11d695288
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreeview.h
@@ -0,0 +1,273 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2002 Klaas Freitag <freitag@suse.de>
+
+ 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 tdefile_tree_view_h
+#define tdefile_tree_view_h
+
+#include <tqmap.h>
+#include <tqpoint.h>
+#include <tqpixmap.h>
+#include <tqstrlist.h>
+#include <tqtooltip.h>
+
+#include <klistview.h>
+#include <kdirnotify.h>
+#include <tdeio/job.h>
+#include <tdefiletreeviewitem.h>
+#include <tdefiletreebranch.h>
+
+class TQTimer;
+
+
+
+class TDEIO_EXPORT KFileTreeViewToolTip : public TQToolTip
+{
+public:
+ KFileTreeViewToolTip( TQListView *view ) : TQToolTip( view ), m_view( view ) {}
+
+protected:
+ virtual void maybeTip( const TQPoint & );
+
+private:
+ TQListView *m_view;
+};
+
+
+/**
+ * The filetreeview offers a treeview on the file system which behaves like
+ * a QTreeView showing files and/or directories in the file system.
+ *
+ * KFileTreeView is able to handle more than one URL, represented by
+ * KFileTreeBranch.
+ *
+ * Typical usage:
+ * 1. create a KFileTreeView fitting in your layout and add columns to it
+ * 2. call addBranch to create one or more branches
+ * 3. retrieve the root item with KFileTreeBranch::root() and set it open
+ * if desired. That starts the listing.
+ */
+class TDEIO_EXPORT KFileTreeView : public KListView
+{
+ Q_OBJECT
+public:
+ KFileTreeView( TQWidget *parent, const char *name = 0 );
+ virtual ~KFileTreeView();
+
+ /**
+ * @return the current (i.e. selected) item
+ */
+ KFileTreeViewItem * currentKFileTreeViewItem() const;
+
+ /**
+ * @return the URL of the current selected item.
+ */
+ KURL currentURL() const;
+
+ /**
+ * Adds a branch to the treeview item.
+ *
+ * This high-level function creates the branch, adds it to the treeview and
+ * connects some signals. Note that directory listing does not start until
+ * a branch is expanded either by opening the root item by user or by setOpen
+ * on the root item.
+ *
+ * @returns a pointer to the new branch or zero
+ * @param path is the base url of the branch
+ * @param name is the name of the branch, which will be the text for column 0
+ * @param showHidden says if hidden files and directories should be visible
+ */
+ KFileTreeBranch* addBranch( const KURL &path, const TQString& name, bool showHidden = false );
+
+ /**
+ * same as the function above but with a pixmap to set for the branch.
+ */
+ virtual KFileTreeBranch* addBranch( const KURL &path, const TQString& name ,
+ const TQPixmap& pix, bool showHidden = false );
+
+ /**
+ * same as the function above but letting the user create the branch.
+ */
+ virtual KFileTreeBranch* addBranch( KFileTreeBranch * );
+
+ /**
+ * removes the branch from the treeview.
+ * @param branch is a pointer to the branch
+ * @returns true on success.
+ */
+ virtual bool removeBranch( KFileTreeBranch *branch );
+
+ /**
+ * @returns a pointer to the KFileTreeBranch in the KFileTreeView or zero on failure.
+ * @param searchName is the name of a branch
+ */
+ KFileTreeBranch *branch( const TQString& searchName );
+
+
+ /**
+ * @returns a list of pointers to all existing branches in the treeview.
+ **/
+ KFileTreeBranchList& branches();
+
+ /**
+ * set the directory mode for branches. If true is passed, only directories will be loaded.
+ * @param branch is a pointer to a KFileTreeBranch
+ */
+ virtual void setDirOnlyMode( KFileTreeBranch *branch, bool );
+
+ /**
+ * searches a branch for a KFileTreeViewItem identified by the relative url given as
+ * second parameter. The method adds the branches base url to the relative path and finds
+ * the item.
+ * @returns a pointer to the item or zero if the item does not exist.
+ * @param brnch is a pointer to the branch to search in
+ * @param relUrl is the branch relativ url
+ */
+ KFileTreeViewItem *findItem( KFileTreeBranch* brnch, const TQString& relUrl );
+
+ /**
+ * see method above, differs only in the first parameter. Finds the branch by its name.
+ */
+ KFileTreeViewItem *findItem( const TQString& branchName, const TQString& relUrl );
+
+ /**
+ * @returns a flag indicating if extended folder pixmaps are displayed or not.
+ */
+ bool showFolderOpenPixmap() const { return m_wantOpenFolderPixmaps; };
+
+public slots:
+
+ /**
+ * set the flag to show 'extended' folder icons on or off. If switched on, folders will
+ * have an open folder pixmap displayed if their children are visible, and the standard
+ * closed folder pixmap (from mimetype folder) if they are closed.
+ * If switched off, the plain mime pixmap is displayed.
+ * @param showIt = false displays mime type pixmap only
+ */
+ virtual void setShowFolderOpenPixmap( bool showIt = true )
+ { m_wantOpenFolderPixmaps = showIt; }
+
+protected:
+ /**
+ * @returns true if we can decode the drag and support the action
+ */
+
+ virtual bool acceptDrag(TQDropEvent* event) const;
+ virtual TQDragObject * dragObject();
+
+ virtual void startAnimation( KFileTreeViewItem* item, const char * iconBaseName = "kde", uint iconCount = 6 );
+ virtual void stopAnimation( KFileTreeViewItem* item );
+ virtual void contentsDragEnterEvent( TQDragEnterEvent *e );
+ virtual void contentsDragMoveEvent( TQDragMoveEvent *e );
+ virtual void contentsDragLeaveEvent( TQDragLeaveEvent *e );
+ virtual void contentsDropEvent( TQDropEvent *ev );
+
+protected slots:
+ virtual void slotNewTreeViewItems( KFileTreeBranch*,
+ const KFileTreeViewItemList& );
+
+ virtual void slotSetNextUrlToSelect( const KURL &url )
+ { m_nextUrlToSelect = url; }
+
+ virtual TQPixmap itemIcon( KFileTreeViewItem*, int gap = 0 ) const;
+
+private slots:
+ void slotExecuted( TQListViewItem * );
+ void slotExpanded( TQListViewItem * );
+ void slotCollapsed( TQListViewItem *item );
+
+ void slotSelectionChanged();
+
+ void slotAnimation();
+
+ void slotAutoOpenFolder();
+
+ void slotOnItem( TQListViewItem * );
+ void slotItemRenamed(TQListViewItem*, const TQString &, int);
+
+ void slotPopulateFinished( KFileTreeViewItem* );
+
+
+signals:
+
+ void onItem( const TQString& );
+ /* New signals if you like it ? */
+ void dropped( TQWidget*, TQDropEvent* );
+ void dropped( TQWidget*, TQDropEvent*, KURL::List& );
+ void dropped( KURL::List&, KURL& );
+ // The drop event allows to differentiate between move and copy
+ void dropped( TQWidget*, TQDropEvent*, KURL::List&, KURL& );
+
+ void dropped( TQDropEvent *e, TQListViewItem * after);
+ void dropped(KFileTreeView *, TQDropEvent *, TQListViewItem *);
+ void dropped(TQDropEvent *e, TQListViewItem * parent, TQListViewItem * after);
+ void dropped(KFileTreeView *, TQDropEvent *, TQListViewItem *, TQListViewItem *);
+
+protected:
+ KURL m_nextUrlToSelect;
+
+
+private:
+ // Returns whether item is still a valid item in the tree
+ bool isValidItem( TQListViewItem *item);
+ void clearTree();
+
+
+ /* List that holds the branches */
+ KFileTreeBranchList m_branches;
+
+
+ struct AnimationInfo
+ {
+ AnimationInfo( const char * _iconBaseName, uint _iconCount, const TQPixmap & _originalPixmap )
+ : iconBaseName(_iconBaseName), iconCount(_iconCount), iconNumber(1), originalPixmap(_originalPixmap) {}
+ AnimationInfo() : iconCount(0) {}
+ TQCString iconBaseName;
+ uint iconCount;
+ uint iconNumber;
+ TQPixmap originalPixmap;
+ };
+ typedef TQMap<KFileTreeViewItem *, AnimationInfo> MapCurrentOpeningFolders;
+ MapCurrentOpeningFolders m_mapCurrentOpeningFolders;
+
+
+ TQTimer *m_animationTimer;
+
+ TQPoint m_dragPos;
+ bool m_bDrag;
+
+ bool m_wantOpenFolderPixmaps; // Flag weather the folder should have open-folder pixmaps
+
+ TQListViewItem *m_currentBeforeDropItem; // The item that was current before the drag-enter event happened
+ TQListViewItem *m_dropItem; // The item we are moving the mouse over (during a drag)
+ TQStrList m_lstDropFormats;
+ TQPixmap m_openFolderPixmap;
+ TQTimer *m_autoOpenTimer;
+
+ KFileTreeViewToolTip m_toolTip;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileTreeViewPrivate;
+ KFileTreeViewPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdefile/tdefiletreeviewitem.cpp b/tdeio/tdefile/tdefiletreeviewitem.cpp
new file mode 100644
index 000000000..4df2daaa1
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreeviewitem.cpp
@@ -0,0 +1,83 @@
+/* This file is part of the KDEproject
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@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 <kdebug.h>
+#include <tdefileitem.h>
+#include <kicontheme.h>
+
+#include "tdefiletreeviewitem.h"
+
+/* --- KFileTreeViewItem --- */
+/*
+ */
+KFileTreeViewItem::KFileTreeViewItem( KFileTreeViewItem *parent,
+ KFileItem* item,
+ KFileTreeBranch *brnch )
+ : KListViewItem( parent ),
+ m_tdefileitem( item ),
+ m_branch( brnch ),
+ m_wasListed(false)
+{
+ setPixmap(0, item->pixmap( KIcon::SizeSmall ));
+ setText( 0, item->text());
+
+}
+
+KFileTreeViewItem::KFileTreeViewItem( KFileTreeView* parent,
+ KFileItem* item,
+ KFileTreeBranch *brnch )
+ :KListViewItem( (TQListView*)parent ),
+ m_tdefileitem(item ),
+ m_branch( brnch ),
+ m_wasListed(false)
+{
+ setPixmap(0, item->pixmap( KIcon::SizeSmall ));
+ setText( 0, item->text());
+}
+
+KFileTreeViewItem::~KFileTreeViewItem()
+{
+ if ( m_tdefileitem )
+ m_tdefileitem->removeExtraData( m_branch );
+}
+
+bool KFileTreeViewItem::alreadyListed() const
+{
+ return m_wasListed;
+}
+
+void KFileTreeViewItem::setListed( bool wasListed )
+{
+ m_wasListed = wasListed;
+}
+
+KURL KFileTreeViewItem::url() const
+{
+ return m_tdefileitem ? m_tdefileitem->url() : KURL();
+}
+
+TQString KFileTreeViewItem::path() const
+{
+ return m_tdefileitem ? m_tdefileitem->url().path() : TQString::null;
+}
+
+bool KFileTreeViewItem::isDir() const
+{
+ return m_tdefileitem ? m_tdefileitem->isDir() : false;
+}
diff --git a/tdeio/tdefile/tdefiletreeviewitem.h b/tdeio/tdefile/tdefiletreeviewitem.h
new file mode 100644
index 000000000..8fdb2789c
--- /dev/null
+++ b/tdeio/tdefile/tdefiletreeviewitem.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@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 tdefile_tree_view_item_h
+#define tdefile_tree_view_item_h
+
+#include <tqptrlist.h>
+#include <klistview.h>
+
+#include <tdefileitem.h>
+#include <tdeio/global.h>
+#include <kdirlister.h>
+#include <tdeio/job.h>
+
+class KURL;
+class KFileTreeView;
+class KFileTreeBranch;
+class KFileTreeItem;
+
+
+/**
+ * An item for a KFileTreeView that knows about its own KFileItem.
+ */
+class TDEIO_EXPORT KFileTreeViewItem : public KListViewItem
+{
+public:
+ KFileTreeViewItem( KFileTreeViewItem*, KFileItem*, KFileTreeBranch * );
+ KFileTreeViewItem( KFileTreeView*, KFileItem*, KFileTreeBranch * );
+ ~KFileTreeViewItem();
+
+ /**
+ * @return the KFileTreeBranch the item is sorted in.
+ */
+ KFileTreeBranch* branch() const { return m_branch; }
+
+ /**
+ * @return the KFileItem the viewitem is representing.
+ */
+ KFileItem *fileItem() const { return m_tdefileitem; }
+
+ /**
+ * @return the path of the item.
+ */
+ TQString path() const;
+
+ /**
+ * @return the items KURL
+ */
+ KURL url() const;
+
+ /**
+ * @return if the item represents a directory
+ */
+ bool isDir() const;
+
+ /**
+ * @return if this directory was already seen by a KDirLister.
+ */
+ bool alreadyListed() const;
+
+ /**
+ * set the flag if the directory was already listed.
+ */
+ void setListed( bool wasListed );
+
+protected:
+
+private:
+
+ KFileItem *m_tdefileitem;
+ KFileTreeBranch *m_branch;
+ bool m_wasListed;
+ class KFileTreeViewItemPrivate;
+ KFileTreeViewItemPrivate *d;
+};
+
+
+/**
+ * List of KFileTreeViewItems
+ */
+typedef TQPtrList<KFileTreeViewItem> KFileTreeViewItemList;
+
+/**
+ * Iterator for KFileTreeViewItemList
+ */
+typedef TQPtrListIterator<KFileTreeViewItem> KFileTreeViewItemListIterator;
+
+
+#endif
+
diff --git a/tdeio/tdefile/tdefileview.cpp b/tdeio/tdefile/tdefileview.cpp
new file mode 100644
index 000000000..558053cc8
--- /dev/null
+++ b/tdeio/tdefile/tdefileview.cpp
@@ -0,0 +1,429 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Stephan Kulow <coolo@kde.org>
+ 1998 Daniel Grana <grana@ie.iwi.unibe.ch>
+ 2001 Carsten Pfeiffer <pfeiffer@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 <assert.h>
+#include <stdlib.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "config-tdefile.h"
+#include "tdefileview.h"
+
+#ifdef Unsorted // the "I hate X.h" modus
+#undef Unsorted
+#endif
+
+TQDir::SortSpec KFileView::defaultSortSpec = static_cast<TQDir::SortSpec>(TQDir::Name | TQDir::IgnoreCase | TQDir::DirsFirst);
+
+class KFileView::KFileViewPrivate
+{
+public:
+ KFileViewPrivate()
+ {
+ actions = 0;
+ dropOptions = 0;
+ }
+
+ ~KFileViewPrivate()
+ {
+ if( actions ) {
+ actions->clear(); // so that the removed() signal is emitted!
+ delete actions;
+ }
+ }
+
+ TQGuardedPtr<KActionCollection> actions;
+ int dropOptions;
+};
+
+
+KFileView::KFileView()
+{
+ d = new KFileViewPrivate();
+ m_sorting = KFileView::defaultSortSpec;
+
+ sig = new KFileViewSignaler();
+ sig->setName("view-signaller");
+
+ m_selectedList = 0L;
+ filesNumber = 0;
+ dirsNumber = 0;
+
+ view_mode = All;
+ selection_mode = KFile::Single;
+ m_viewName = i18n("Unknown View");
+
+ myOnlyDoubleClickSelectsFiles = false;
+ m_itemList.setAutoDelete( false ); // just references
+}
+
+KFileView::~KFileView()
+{
+ delete d;
+ delete sig;
+ delete m_selectedList;
+}
+
+void KFileView::setParentView(KFileView *parent)
+{
+ if ( parent ) { // pass all signals right to our parent
+ TQObject::connect(sig, TQT_SIGNAL( activatedMenu(const KFileItem *,
+ const TQPoint& ) ),
+ parent->sig, TQT_SIGNAL( activatedMenu(const KFileItem *,
+ const TQPoint& )));
+ TQObject::connect(sig, TQT_SIGNAL( dirActivated(const KFileItem *)),
+ parent->sig, TQT_SIGNAL( dirActivated(const KFileItem*)));
+ TQObject::connect(sig, TQT_SIGNAL( fileSelected(const KFileItem *)),
+ parent->sig, TQT_SIGNAL( fileSelected(const KFileItem*)));
+ TQObject::connect(sig, TQT_SIGNAL( fileHighlighted(const KFileItem *) ),
+ parent->sig,TQT_SIGNAL(fileHighlighted(const KFileItem*)));
+ TQObject::connect(sig, TQT_SIGNAL( sortingChanged( TQDir::SortSpec ) ),
+ parent->sig, TQT_SIGNAL(sortingChanged( TQDir::SortSpec)));
+ TQObject::connect(sig, TQT_SIGNAL( dropped(const KFileItem *, TQDropEvent*, const KURL::List&) ),
+ parent->sig, TQT_SIGNAL(dropped(const KFileItem *, TQDropEvent*, const KURL::List&)));
+ }
+}
+
+bool KFileView::updateNumbers(const KFileItem *i)
+{
+ if (!( viewMode() & Files ) && i->isFile())
+ return false;
+
+ if (!( viewMode() & Directories ) && i->isDir())
+ return false;
+
+ if (i->isDir())
+ dirsNumber++;
+ else
+ filesNumber++;
+
+ return true;
+}
+
+void qt_qstring_stats();
+
+// filter out files if we're in directory mode and count files/directories
+// and insert into the view
+void KFileView::addItemList(const KFileItemList& list)
+{
+ KFileItem *tmp;
+
+ for (KFileItemListIterator it(list); (tmp = it.current()); ++it)
+ {
+ if (!updateNumbers(tmp))
+ continue;
+
+ insertItem( tmp );
+ }
+
+#ifdef Q2HELPER
+ qt_qstring_stats();
+#endif
+}
+
+void KFileView::insertItem( KFileItem * )
+{
+}
+
+void KFileView::setSorting(TQDir::SortSpec new_sort)
+{
+ m_sorting = new_sort;
+}
+
+void KFileView::clear()
+{
+ m_itemList.clear();
+ filesNumber = 0;
+ dirsNumber = 0;
+ clearView();
+}
+
+void KFileView::sortReversed()
+{
+ int spec = sorting();
+
+ setSorting( static_cast<TQDir::SortSpec>( spec ^ TQDir::Reversed ) );
+}
+
+#if 0
+int KFileView::compareItems(const KFileItem *fi1, const KFileItem *fi2) const
+{
+ static const TQString &dirup = TDEGlobal::staticQString("..");
+ bool bigger = true;
+ bool keepFirst = false;
+ bool dirsFirst = ((m_sorting & TQDir::DirsFirst) == TQDir::DirsFirst);
+
+ if (fi1 == fi2)
+ return 0;
+
+ // .. is always bigger, independent of the sort criteria
+ if ( fi1->name() == dirup ) {
+ bigger = false;
+ keepFirst = dirsFirst;
+ }
+ else if ( fi2->name() == dirup ) {
+ bigger = true;
+ keepFirst = dirsFirst;
+ }
+
+ else {
+ if ( fi1->isDir() != fi2->isDir() && dirsFirst ) {
+ bigger = fi2->isDir();
+ keepFirst = true;
+ }
+ else {
+
+ TQDir::SortSpec sort = static_cast<TQDir::SortSpec>(m_sorting & TQDir::SortByMask);
+
+ //if (fi1->isDir() || fi2->isDir())
+ // sort = static_cast<TQDir::SortSpec>(KFileView::defaultSortSpec & TQDir::SortByMask);
+
+ switch (sort) {
+ case TQDir::Name:
+ default:
+sort_by_name:
+ if ( (m_sorting & TQDir::IgnoreCase) == TQDir::IgnoreCase )
+ bigger = (fi1->name( true ) > fi2->name( true ));
+ else
+ bigger = (fi1->name() > fi2->name());
+ break;
+ case TQDir::Time:
+ {
+ time_t t1 = fi1->time( TDEIO::UDS_MODIFICATION_TIME );
+ time_t t2 = fi2->time( TDEIO::UDS_MODIFICATION_TIME );
+ if ( t1 != t2 ) {
+ bigger = (t1 > t2);
+ break;
+ }
+
+ // Sort by name if both items have the same timestamp.
+ // Don't honor the reverse flag tho.
+ else {
+ keepFirst = true;
+ goto sort_by_name;
+ }
+ }
+ case TQDir::Size:
+ {
+ TDEIO::filesize_t s1 = fi1->size();
+ TDEIO::filesize_t s2 = fi2->size();
+ if ( s1 != s2 ) {
+ bigger = (s1 > s2);
+ break;
+ }
+
+ // Sort by name if both items have the same size.
+ // Don't honor the reverse flag tho.
+ else {
+ keepFirst = true;
+ goto sort_by_name;
+ }
+ }
+ case TQDir::Unsorted:
+ bigger = true; // nothing
+ break;
+ }
+ }
+ }
+
+ if (reversed && !keepFirst ) // don't reverse dirs to the end!
+ bigger = !bigger;
+
+ return (bigger ? 1 : -1);
+}
+#endif
+
+void KFileView::updateView(bool f)
+{
+ widget()->repaint(f);
+}
+
+void KFileView::updateView(const KFileItem *)
+{
+}
+
+void KFileView::setCurrentItem(const TQString &filename )
+{
+ if (!filename.isNull()) {
+ KFileItem *item;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) ) {
+ if (item->name() == filename) {
+ setCurrentItem( item );
+ return;
+ }
+ }
+ }
+
+ kdDebug(tdefile_area) << "setCurrentItem: no match found: " << filename << endl;
+}
+
+const KFileItemList * KFileView::items() const
+{
+ KFileItem *item = 0L;
+
+ // only ever use m_itemList in this method!
+ m_itemList.clear();
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ m_itemList.append( item );
+
+ return &m_itemList;
+}
+
+
+const KFileItemList * KFileView::selectedItems() const
+{
+ if ( !m_selectedList )
+ m_selectedList = new KFileItemList;
+
+ m_selectedList->clear();
+
+ KFileItem *item;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) ) {
+ if ( isSelected( item ) )
+ m_selectedList->append( item );
+ }
+
+ return m_selectedList;
+}
+
+void KFileView::selectAll()
+{
+ if (selection_mode == KFile::NoSelection || selection_mode== KFile::Single)
+ return;
+
+ KFileItem *item = 0L;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ setSelected( item, true );
+}
+
+
+void KFileView::invertSelection()
+{
+ KFileItem *item = 0L;
+ for ( (item = firstFileItem()); item; item = nextItem( item ) )
+ setSelected( item, !isSelected( item ) );
+}
+
+
+void KFileView::setSelectionMode( KFile::SelectionMode sm )
+{
+ selection_mode = sm;
+}
+
+KFile::SelectionMode KFileView::selectionMode() const
+{
+ return selection_mode;
+}
+
+void KFileView::setViewMode( ViewMode vm )
+{
+ view_mode = vm;
+}
+
+void KFileView::removeItem( const KFileItem *item )
+{
+ if ( !item )
+ return;
+
+ if ( item->isDir() )
+ dirsNumber--;
+ else
+ filesNumber--;
+
+ if ( m_selectedList )
+ m_selectedList->removeRef( item );
+}
+
+void KFileView::listingCompleted()
+{
+ // empty default impl.
+}
+
+KActionCollection * KFileView::actionCollection() const
+{
+ if ( !d->actions )
+ d->actions = new KActionCollection( widget(), "KFileView::d->actions" );
+ return d->actions;
+}
+
+void KFileView::readConfig( TDEConfig *, const TQString& )
+{
+}
+
+void KFileView::writeConfig( TDEConfig *, const TQString& )
+{
+}
+
+TQString KFileView::sortingKey( const TQString& value, bool isDir, int sortSpec )
+{
+ bool reverse = sortSpec & TQDir::Reversed;
+ bool dirsFirst = sortSpec & TQDir::DirsFirst;
+ char start = (isDir && dirsFirst) ? (reverse ? '2' : '0') : '1';
+ TQString result = (sortSpec & TQDir::IgnoreCase) ? value.lower() : value;
+ return result.prepend( start );
+}
+
+TQString KFileView::sortingKey( TDEIO::filesize_t value, bool isDir, int sortSpec)
+{
+ bool reverse = sortSpec & TQDir::Reversed;
+ bool dirsFirst = sortSpec & TQDir::DirsFirst;
+ char start = (isDir && dirsFirst) ? (reverse ? '2' : '0') : '1';
+ return TDEIO::number( value ).rightJustify( 24, '0' ).prepend( start );
+}
+
+void KFileView::setDropOptions(int options)
+{
+ virtual_hook(VIRTUAL_SET_DROP_OPTIONS, &options); // Virtual call
+}
+
+void KFileView::setDropOptions_impl(int options)
+{
+ d->dropOptions = options;
+}
+
+int KFileView::dropOptions()
+{
+ return d->dropOptions;
+}
+
+int KFileView::autoOpenDelay()
+{
+ return (TQApplication::startDragTime() * 3) / 2;
+}
+
+void KFileView::virtual_hook( int id, void* data)
+{
+ switch(id) {
+ case VIRTUAL_SET_DROP_OPTIONS:
+ setDropOptions_impl(*(int *)data);
+ break;
+ default:
+ /*BASE::virtual_hook( id, data );*/
+ break;
+ }
+}
+
+#include "tdefileview.moc"
diff --git a/tdeio/tdefile/tdefileview.h b/tdeio/tdefile/tdefileview.h
new file mode 100644
index 000000000..8f4918030
--- /dev/null
+++ b/tdeio/tdefile/tdefileview.h
@@ -0,0 +1,444 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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 KFILEVIEW_H
+#define KFILEVIEW_H
+
+class TQPoint;
+class KActionCollection;
+
+#include <tqwidget.h>
+
+#include "tdefileitem.h"
+#include "tdefile.h"
+
+/**
+ * internal class to make easier to use signals possible
+ * @internal
+ **/
+class TDEIO_EXPORT KFileViewSignaler : public TQObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Call this method when an item is selected (depends on single click /
+ * double click configuration). Emits the appropriate signal.
+ **/
+ void activate( const KFileItem *item ) {
+ if ( item->isDir() )
+ emit dirActivated( item );
+ else
+ emit fileSelected( item );
+ }
+ /**
+ * emits the highlighted signal for item. Call this in your view class
+ * whenever the selection changes.
+ */
+ void highlightFile(const KFileItem *i) { emit fileHighlighted(i); }
+
+ void activateMenu( const KFileItem *i, const TQPoint& pos ) {
+ emit activatedMenu( i, pos );
+ }
+
+ void changeSorting( TQDir::SortSpec sorting ) {
+ emit sortingChanged( sorting );
+ }
+
+ void dropURLs(const KFileItem *i, TQDropEvent*e, const KURL::List&urls) {
+ emit dropped(i, e, urls);
+ }
+
+signals:
+ void dirActivated(const KFileItem*);
+
+ void sortingChanged( TQDir::SortSpec );
+
+ /**
+ * the item maybe be 0L, indicating that we're in multiselection mode and
+ * the selection has changed.
+ */
+ void fileHighlighted(const KFileItem*);
+ void fileSelected(const KFileItem*);
+ void activatedMenu( const KFileItem *i, const TQPoint& );
+ void dropped(const KFileItem *, TQDropEvent*, const KURL::List&);
+};
+
+/**
+ * This class defines an interface to all file views. Its intent is
+ * to allow to switch the view of the files in the selector very easily.
+ * It defines some pure virtual functions, that must be implemented to
+ * make a file view working.
+ *
+ * Since this class is not a widget, but it's meant to be added to other
+ * widgets, its most important function is widget. This should return
+ * a pointer to the implemented widget.
+ *
+ * @short A base class for views of the KDE file selector
+ * @author Stephan Kulow <coolo@kde.org>
+ **/
+class TDEIO_EXPORT KFileView {
+
+public:
+ KFileView();
+
+ /**
+ * Destructor
+ */
+ virtual ~KFileView();
+
+ /**
+ * inserts a list of items.
+ **/
+ void addItemList(const KFileItemList &list);
+
+ /**
+ * a pure virtual function to get a TQWidget, that can be added to
+ * other widgets. This function is needed to make it possible for
+ * derived classes to derive from other widgets.
+ **/
+ virtual TQWidget *widget() = 0;
+
+ /**
+ * ### As const-method, to be fixed in 3.0
+ */
+ TQWidget *widget() const { return const_cast<KFileView*>(this)->widget(); }
+
+ /**
+ * Sets @p filename the current item in the view, if available.
+ */
+ void setCurrentItem( const TQString &filename );
+
+ /**
+ * Reimplement this to set @p item the current item in the view, e.g.
+ * the item having focus.
+ */
+ virtual void setCurrentItem( const KFileItem *item ) = 0;
+
+ /**
+ * @returns the "current" KFileItem, e.g. where the cursor is.
+ * Returns 0L when there is no current item (e.g. in an empty view).
+ * Subclasses have to implement this.
+ */
+ virtual KFileItem *currentFileItem() const = 0;
+
+ /**
+ * Clears the view and all item lists.
+ */
+ virtual void clear();
+
+ /**
+ * does a repaint of the view.
+ *
+ * The default implementation calls
+ * \code
+ * widget()->repaint(f)
+ * \endcode
+ **/
+ virtual void updateView(bool f = true);
+
+ virtual void updateView(const KFileItem*);
+
+ /**
+ * Removes an item from the list; has to be implemented by the view.
+ * Call KFileView::removeItem( item ) after removing it.
+ */
+ virtual void removeItem(const KFileItem *item);
+
+ /**
+ * This hook is called when all items of the currently listed directory
+ * are listed and inserted into the view, i.e. there won't come any new
+ * items anymore.
+ */
+ virtual void listingCompleted();
+
+ /**
+ * Returns the sorting order of the internal list. Newly added files
+ * are added through this sorting.
+ */
+ TQDir::SortSpec sorting() const { return m_sorting; }
+
+ /**
+ * Sets the sorting order of the view.
+ *
+ * Default is TQDir::Name | TQDir::IgnoreCase | TQDir::DirsFirst
+ * Override this in your subclass and sort accordingly (usually by
+ * setting the sorting-key for every item and telling QIconView
+ * or TQListView to sort.
+ *
+ * A view may choose to use a different sorting than TQDir::Name, Time
+ * or Size. E.g. to sort by mimetype or any possible string. Set the
+ * sorting to TQDir::Unsorted for that and do the rest internally.
+ *
+ * @see sortingKey
+ */
+ virtual void setSorting(TQDir::SortSpec sort);
+
+ /**
+ * Tells whether the current items are in reversed order (shortcut to
+ * sorting() & TQDir::Reversed).
+ */
+ bool isReversed() const { return (m_sorting & TQDir::Reversed); }
+
+ void sortReversed();
+
+ /**
+ * @returns the number of dirs and files
+ **/
+ uint count() const { return filesNumber + dirsNumber; }
+
+ /**
+ * @returns the number of files.
+ **/
+ uint numFiles() const { return filesNumber; }
+
+ /**
+ * @returns the number of directories
+ **/
+ uint numDirs() const { return dirsNumber; }
+
+ virtual void setSelectionMode( KFile::SelectionMode sm );
+ virtual KFile::SelectionMode selectionMode() const;
+
+ enum ViewMode {
+ Files = 1,
+ Directories = 2,
+ All = Files | Directories
+ };
+ virtual void setViewMode( ViewMode vm );
+ virtual ViewMode viewMode() const { return view_mode; }
+
+ /**
+ * @returns the localized name of the view, which could be displayed
+ * somewhere, e.g. in a menu, where the user can choose between views.
+ * @see setViewName
+ */
+ TQString viewName() const { return m_viewName; }
+
+ /**
+ * Sets the name of the view, which could be displayed somewhere.
+ * E.g. "Image Preview".
+ */
+ void setViewName( const TQString& name ) { m_viewName = name; }
+
+ virtual void setParentView(KFileView *parent);
+
+ /**
+ * The derived view must implement this function to add
+ * the file in the widget.
+ *
+ * Make sure to call this implementation, i.e.
+ * KFileView::insertItem( i );
+ *
+ */
+ virtual void insertItem( KFileItem *i);
+
+ /**
+ * pure virtual function, that should be implemented to clear
+ * the view. At this moment the list is already empty
+ **/
+ virtual void clearView() = 0;
+
+ /**
+ * pure virtual function, that should be implemented to make item i
+ * visible, i.e. by scrolling the view appropriately.
+ */
+ virtual void ensureItemVisible( const KFileItem *i ) = 0;
+
+ /**
+ * Clears any selection, unhighlights everything. Must be implemented by
+ * the view.
+ */
+ virtual void clearSelection() = 0;
+
+ /**
+ * Selects all items. You may want to override this, if you can implement
+ * it more efficiently than calling setSelected() with every item.
+ * This works only in Multiselection mode of course.
+ */
+ virtual void selectAll();
+
+ /**
+ * Inverts the current selection, i.e. selects all items, that were up to
+ * now not selected and deselects the other.
+ */
+ virtual void invertSelection();
+
+ /**
+ * Tells the view that it should highlight the item.
+ * This function must be implemented by the view.
+ **/
+ virtual void setSelected(const KFileItem *, bool enable) = 0;
+
+ /**
+ * @returns whether the given item is currently selected.
+ * Must be implemented by the view.
+ */
+ virtual bool isSelected( const KFileItem * ) const = 0;
+
+ /**
+ * @returns all currently highlighted items.
+ */
+ const KFileItemList * selectedItems() const;
+
+ /**
+ * @returns all items currently available in the current sort-order
+ */
+ const KFileItemList * items() const;
+
+ virtual KFileItem * firstFileItem() const = 0;
+ virtual KFileItem * nextItem( const KFileItem * ) const = 0;
+ virtual KFileItem * prevItem( const KFileItem * ) const = 0;
+
+ /**
+ * This is a KFileDialog specific hack: we want to select directories with
+ * single click, but not files. But as a generic class, we have to be able
+ * to select files on single click as well.
+ *
+ * This gives us the opportunity to do both.
+ *
+ * Every view has to decide when to call select( item ) when a file was
+ * single-clicked, based on onlyDoubleClickSelectsFiles().
+ */
+ void setOnlyDoubleClickSelectsFiles( bool enable ) {
+ myOnlyDoubleClickSelectsFiles = enable;
+ }
+
+ /**
+ * @returns whether files (not directories) should only be select()ed by
+ * double-clicks.
+ * @see setOnlyDoubleClickSelectsFiles
+ */
+ bool onlyDoubleClickSelectsFiles() const {
+ return myOnlyDoubleClickSelectsFiles;
+ }
+
+ /**
+ * increases the number of dirs and files.
+ * @returns true if the item fits the view mode
+ */
+ bool updateNumbers(const KFileItem *i);
+
+ /**
+ * @returns the view-specific action-collection. Every view should
+ * add its actions here (if it has any) to make them available to
+ * e.g. the KDirOperator's popup-menu.
+ */
+ virtual KActionCollection * actionCollection() const;
+
+ KFileViewSignaler * signaler() const { return sig; }
+
+ virtual void readConfig( TDEConfig *, const TQString& group = TQString::null );
+ virtual void writeConfig( TDEConfig *, const TQString& group = TQString::null);
+
+ /**
+ * Various options for drag and drop support.
+ * These values can be or'd together.
+ * @li @p AutoOpenDirs Automatically open directory after hovering above it
+ * for a short while while dragging.
+ * @since 3.2
+ */
+ enum DropOptions {
+ AutoOpenDirs = 1
+ };
+ /**
+ * Specify DND options. See DropOptions for details.
+ * All options are disabled by default.
+ * @since 3.2
+ */
+ // KDE 4: Make virtual
+ void setDropOptions(int options);
+
+ /**
+ * Returns the DND options in effect.
+ * See DropOptions for details.
+ * @since 3.2
+ */
+ int dropOptions();
+
+ /**
+ * This method calculates a TQString from the given parameters, that is
+ * suitable for sorting with e.g. TQIconView or TQListView. Their
+ * Item-classes usually have a setKey( const TQString& ) method or a virtual
+ * method TQString key() that is used for sorting.
+ *
+ * @param value Any string that should be used as sort criterion
+ * @param isDir Tells whether the key is computed for an item representing
+ * a directory (directories are usually sorted before files)
+ * @param sortSpec An ORed combination of TQDir::SortSpec flags.
+ * Currently, the values IgnoreCase, Reversed and
+ * DirsFirst are taken into account.
+ */
+ static TQString sortingKey( const TQString& value, bool isDir, int sortSpec);
+
+ /**
+ * An overloaded method that takes not a TQString, but a number as sort
+ * criterion. You can use this for file-sizes or dates/times for example.
+ * If you use a time_t, you need to cast that to TDEIO::filesize_t because
+ * of ambiguity problems.
+ */
+ static TQString sortingKey( TDEIO::filesize_t value, bool isDir,int sortSpec);
+
+ /**
+ * @internal
+ * delay before auto opening a directory
+ */
+ static int autoOpenDelay();
+
+protected:
+ /**
+ * @internal
+ * class to distribute the signals
+ **/
+ KFileViewSignaler *sig;
+
+private:
+ static TQDir::SortSpec defaultSortSpec;
+ TQDir::SortSpec m_sorting;
+ TQString m_viewName;
+
+ /**
+ * counters
+ **/
+ uint filesNumber;
+ uint dirsNumber;
+
+ ViewMode view_mode;
+ KFile::SelectionMode selection_mode;
+
+ // never use! It's only guaranteed to contain valid items in the items()
+ // method!
+ mutable KFileItemList m_itemList;
+
+ mutable KFileItemList *m_selectedList;
+ bool myOnlyDoubleClickSelectsFiles;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ /* @internal for virtual_hook */
+ enum { VIRTUAL_SET_DROP_OPTIONS = 1 };
+ void setDropOptions_impl(int options);
+private:
+ class KFileViewPrivate;
+ KFileViewPrivate *d;
+};
+
+#endif // KFILEINFOLISTWIDGET_H
diff --git a/tdeio/tdefile/tests/Makefile.am b/tdeio/tdefile/tests/Makefile.am
new file mode 100644
index 000000000..d869f11f5
--- /dev/null
+++ b/tdeio/tdefile/tests/Makefile.am
@@ -0,0 +1,41 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997-1998 Stephan Kulow (coolo@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.
+
+INCLUDES = $(all_includes)
+
+AM_LDFLAGS = $(QT_LDFLAGS) $(X_LDFLAGS) $(KDE_RPATH)
+
+check_PROGRAMS = kfstest kurlrequestertest tdefiletreeviewtest \
+ kopenwithtest kdirselectdialogtest kicondialogtest \
+ knotifytest kcustommenueditortest
+
+# noinst_HEADERS =
+
+METASOURCES = AUTO
+
+LDADD = $(LIB_KIO)
+kcustommenueditortest_SOURCES = kcustommenueditortest.cpp
+kurlrequestertest_SOURCES = kurlrequestertest.cpp
+kfstest_SOURCES = kfstest.cpp kfdtest.cpp
+tdefiletreeviewtest_SOURCES = tdefiletreeviewtest.cpp
+kopenwithtest_SOURCES = kopenwithtest.cpp
+kdirselectdialogtest_SOURCES = kdirselectdialogtest.cpp
+kicondialogtest_SOURCES = kicondialogtest.cpp
+knotifytest_SOURCES = knotifytest.cpp
+
diff --git a/tdeio/tdefile/tests/kcustommenueditortest.cpp b/tdeio/tdefile/tests/kcustommenueditortest.cpp
new file mode 100644
index 000000000..df2c692f6
--- /dev/null
+++ b/tdeio/tdefile/tests/kcustommenueditortest.cpp
@@ -0,0 +1,19 @@
+#include "kcustommenueditor.h"
+#include <kapplication.h>
+#include <klocale.h>
+#include <tdeconfig.h>
+
+int main(int argc, char** argv)
+{
+ KLocale::setMainCatalogue("tdelibs");
+ TDEApplication app(argc, argv, "KCustomMenuEditorTest");
+ KCustomMenuEditor editor(0);
+ TDEConfig *cfg = new TDEConfig("kdesktop_custom_menu2");
+ editor.load(cfg);
+ if (editor.exec())
+ {
+ editor.save(cfg);
+ cfg->sync();
+ }
+}
+
diff --git a/tdeio/tdefile/tests/kdirselectdialogtest.cpp b/tdeio/tdefile/tests/kdirselectdialogtest.cpp
new file mode 100644
index 000000000..3d15c47d0
--- /dev/null
+++ b/tdeio/tdefile/tests/kdirselectdialogtest.cpp
@@ -0,0 +1,17 @@
+#include <kapplication.h>
+#include <kdirselectdialog.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+
+int main( int argc, char **argv )
+{
+ TDEApplication app(argc, argv, "kdirselectdialogtest");
+
+ KURL u = KDirSelectDialog::selectDirectory( (argc >= 1) ? argv[1] : TQString::null );
+ if ( u.isValid() )
+ KMessageBox::information( 0L,
+ TQString::fromLatin1("You selected the url: %1")
+ .arg( u.prettyURL() ), "Selected URL" );
+
+ return 0;
+}
diff --git a/tdeio/tdefile/tests/kfdtest.cpp b/tdeio/tdefile/tests/kfdtest.cpp
new file mode 100644
index 000000000..60c8b6d70
--- /dev/null
+++ b/tdeio/tdefile/tests/kfdtest.cpp
@@ -0,0 +1,34 @@
+#include "kfdtest.h"
+
+#include <tqstringlist.h>
+#include <tdefiledialog.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <tqtimer.h>
+
+KFDTest::KFDTest( const TQString& startDir, TQObject *parent, const char *name )
+ : TQObject( parent, name ),
+ m_startDir( startDir )
+{
+ TQTimer::singleShot( 1000, this, TQT_SLOT( doit() ));
+}
+
+void KFDTest::doit()
+{
+ KFileDialog *dlg = new KFileDialog( m_startDir, TQString::null, 0L,
+ "file dialog", true );
+ dlg->setMode( KFile::File);
+ dlg->setOperationMode( KFileDialog::Saving );
+ TQStringList filter;
+ filter << "all/allfiles" << "text/plain";
+ dlg->setMimeFilter( filter, "all/allfiles" );
+
+ if ( dlg->exec() == KDialog::Accepted )
+ {
+ KMessageBox::information(0, TQString::fromLatin1("You selected the file: %1").arg( dlg->selectedURL().prettyURL() ));
+ }
+
+// tqApp->quit();
+}
+
+#include "kfdtest.moc"
diff --git a/tdeio/tdefile/tests/kfdtest.h b/tdeio/tdefile/tests/kfdtest.h
new file mode 100644
index 000000000..6c59550b8
--- /dev/null
+++ b/tdeio/tdefile/tests/kfdtest.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2003 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef KFDTEST_H
+#define KFDTEST_H
+
+#include <tqobject.h>
+
+class KFDTest : public TQObject
+{
+ Q_OBJECT
+
+public:
+ KFDTest( const TQString& startDir, TQObject *parent = 0, const char *name = 0);
+
+public slots:
+ void doit();
+
+private:
+ TQString m_startDir;
+};
+
+
+#endif // KFDTEST_H
diff --git a/tdeio/tdefile/tests/kfstest.cpp b/tdeio/tdefile/tests/kfstest.cpp
new file mode 100644
index 000000000..f6ee69687
--- /dev/null
+++ b/tdeio/tdefile/tests/kfstest.cpp
@@ -0,0 +1,183 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997, 1998 Richard Moore <rich@kde.org>
+ 1998 Stephan Kulow <coolo@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 <unistd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <tqdir.h>
+#include <tqlayout.h>
+#include <tqstringlist.h>
+#include <tqwidget.h>
+
+#include <tdefiledialog.h>
+#include <tdefileiconview.h>
+#include <kmessagebox.h>
+#include <tdeconfig.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kurlbar.h>
+#include <kdiroperator.h>
+#include <tdefile.h>
+#include <kdebug.h>
+#include <kicondialog.h>
+
+#include "kfdtest.h"
+
+int main(int argc, char **argv)
+{
+ TDEApplication a(argc, argv, "kfstest");
+ TQString name1;
+ TQStringList names;
+
+ TQString argv1;
+ TQString startDir;
+ if (argc > 1)
+ argv1 = TQString::fromLatin1(argv[1]);
+ if ( argc > 2 )
+ startDir = TQString::fromLatin1( argv[2]);
+
+ if (argv1 == TQString::fromLatin1("diroperator")) {
+ KDirOperator *op = new KDirOperator(startDir, 0, "operator");
+ op->setViewConfig( TDEGlobal::config(), "TestGroup" );
+ op->setView(KFile::Simple);
+ op->show();
+ a.setMainWidget(op);
+ a.exec();
+ }
+
+ else if (argv1 == TQString::fromLatin1("justone")) {
+ TQString name = KFileDialog::getOpenFileName(startDir);
+ tqDebug("filename=%s",name.latin1());
+ }
+
+ else if (argv1 == TQString::fromLatin1("existingURL")) {
+ KURL url = KFileDialog::getExistingURL();
+ tqDebug("URL=%s",url.url().latin1());
+ name1 = url.url();
+ }
+
+ else if (argv1 == TQString::fromLatin1("preview")) {
+ KURL u = KFileDialog::getImageOpenURL();
+ tqDebug("filename=%s", u.url().latin1());
+ }
+
+ else if (argv1 == TQString::fromLatin1("preselect")) {
+ names = KFileDialog::getOpenFileNames(TQString::fromLatin1("/etc/passwd"));
+ TQStringList::Iterator it = names.begin();
+ while ( it != names.end() ) {
+ tqDebug("selected file: %s", (*it).latin1());
+ ++it;
+ }
+ }
+
+ else if (argv1 == TQString::fromLatin1("dirs"))
+ name1 = KFileDialog::getExistingDirectory();
+
+ else if (argv1 == TQString::fromLatin1("heap")) {
+ KFileDialog *dlg = new KFileDialog( startDir, TQString::null, 0L,
+ "file dialog", true );
+ dlg->setMode( KFile::File);
+ dlg->setOperationMode( KFileDialog::Saving );
+ TQStringList filter;
+ filter << "all/allfiles" << "text/plain";
+ dlg->setMimeFilter( filter, "all/allfiles" );
+ KURLBar *urlBar = dlg->speedBar();
+ if ( urlBar )
+ {
+ urlBar->insertDynamicItem( KURL("ftp://ftp.kde.org"),
+ TQString::fromLatin1("KDE FTP Server") );
+ }
+
+ if ( dlg->exec() == KDialog::Accepted )
+ name1 = dlg->selectedURL().url();
+ }
+
+ else if ( argv1 == TQString::fromLatin1("eventloop") )
+ {
+ KFDTest *test = new KFDTest( startDir );
+ return a.exec();
+ }
+
+ else if (argv1 == TQString::fromLatin1("save")) {
+ KURL u = KFileDialog::getSaveURL();
+// TQString(TQDir::homeDirPath() + TQString::fromLatin1("/testfile")),
+// TQString::null, 0L);
+ name1 = u.url();
+ }
+
+ else if (argv1 == TQString::fromLatin1("icon")) {
+ KIconDialog dlg;
+ TQString icon = dlg.selectIcon();
+ kdDebug() << icon << endl;
+ }
+
+// else if ( argv1 == TQString::fromLatin1("dirselect") ) {
+// KURL url;
+// url.setPath( "/" );
+// KURL selected = KDirSelectDialog::selectDirectory( url );
+// name1 = selected.url();
+// tqDebug("*** selected: %s", selected.url().latin1());
+// }
+
+ else {
+ KFileDialog dlg(startDir,
+ TQString::fromLatin1("*|All Files\n"
+ "*.lo *.o *.la|All libtool Files"),
+ 0, 0, true);
+// dlg.setFilter( "*.tdevelop" );
+ dlg.setMode( (KFile::Mode) (KFile::Files |
+ KFile::Directory |
+ KFile::ExistingOnly |
+ KFile::LocalOnly) );
+// TQStringList filter;
+// filter << "text/plain" << "text/html" << "image/png";
+// dlg.setMimeFilter( filter );
+// KMimeType::List types;
+// types.append( KMimeType::mimeType( "text/plain" ) );
+// types.append( KMimeType::mimeType( "text/html" ) );
+// dlg.setFilterMimeType( "Filetypes:", types, types.first() );
+ if ( dlg.exec() == TQDialog::Accepted ) {
+ KURL::List list = dlg.selectedURLs();
+ KURL::List::ConstIterator it = list.begin();
+ tqDebug("*** selectedURLs(): ");
+ while ( it != list.end() ) {
+ name1 = (*it).url();
+ tqDebug(" -> %s", name1.latin1());
+ ++it;
+ }
+ tqDebug("*** selectedFile: %s", dlg.selectedFile().latin1());
+ tqDebug("*** selectedURL: %s", dlg.selectedURL().url().latin1());
+ tqDebug("*** selectedFiles: ");
+ TQStringList l = dlg.selectedFiles();
+ TQStringList::Iterator it2 = l.begin();
+ while ( it2 != l.end() ) {
+ tqDebug(" -> %s", (*it2).latin1());
+ ++it2;
+ }
+ }
+ }
+
+ if (!(name1.isNull()))
+ KMessageBox::information(0, TQString::fromLatin1("You selected the file " ) + name1,
+ TQString::fromLatin1("Your Choice"));
+ return 0;
+}
diff --git a/tdeio/tdefile/tests/kicondialogtest.cpp b/tdeio/tdefile/tests/kicondialogtest.cpp
new file mode 100644
index 000000000..b2c56e159
--- /dev/null
+++ b/tdeio/tdefile/tests/kicondialogtest.cpp
@@ -0,0 +1,19 @@
+#include <kapplication.h>
+#include <kicondialog.h>
+
+int main( int argc, char **argv )
+{
+ TDEApplication app( argc, argv, "kicondialogtest" );
+
+// KIconDialog::getIcon();
+
+ KIconButton button;
+ app.setMainWidget( &button );
+ button.show();
+
+
+ return app.exec();
+}
+
+/* vim: et sw=4
+ */
diff --git a/tdeio/tdefile/tests/knotifytest.cpp b/tdeio/tdefile/tests/knotifytest.cpp
new file mode 100644
index 000000000..0493b59b4
--- /dev/null
+++ b/tdeio/tdefile/tests/knotifytest.cpp
@@ -0,0 +1,10 @@
+#include <kapplication.h>
+#include <knotifydialog.h>
+
+int main( int argc, char **argv )
+{
+ TDEApplication app( argc, argv, "knotifytest" );
+ KNotifyDialog *dlg = new KNotifyDialog();
+ dlg->addApplicationEvents( "twin" );
+ return dlg->exec();
+}
diff --git a/tdeio/tdefile/tests/kopenwithtest.cpp b/tdeio/tdefile/tests/kopenwithtest.cpp
new file mode 100644
index 000000000..f78b1830b
--- /dev/null
+++ b/tdeio/tdefile/tests/kopenwithtest.cpp
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2003 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 <kapplication.h>
+#include <tqwidget.h>
+#include <tqstringlist.h>
+#include <tqdir.h>
+#include <kopenwith.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+int main(int argc, char **argv)
+{
+ TDEApplication app(argc, argv, "kopenwithtest");
+ KURL::List list;
+
+ list += KURL("file:///tmp/testfile.txt");
+
+ // Test with one URL
+ KOpenWithDlg* dlg = new KOpenWithDlg(list, "OpenWith_Text", "OpenWith_Value", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ // Test with two URLs
+ list += KURL("http://www.kde.org/index.html");
+ dlg = new KOpenWithDlg(list, "OpenWith_Text", "OpenWith_Value", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ // Test with a mimetype
+ TQString mimetype = "text/plain";
+ dlg = new KOpenWithDlg( mimetype, "kedit", 0);
+ if(dlg->exec()) {
+ kdDebug() << "Dialog ended successfully\ntext: " << dlg->text() << endl;
+ }
+ else
+ kdDebug() << "Dialog was canceled." << endl;
+ delete dlg;
+
+ return 0;
+}
+
diff --git a/tdeio/tdefile/tests/kurlrequestertest.cpp b/tdeio/tdefile/tests/kurlrequestertest.cpp
new file mode 100644
index 000000000..0e4851cfb
--- /dev/null
+++ b/tdeio/tdefile/tests/kurlrequestertest.cpp
@@ -0,0 +1,16 @@
+#include <kapplication.h>
+#include <keditlistbox.h>
+#include <kurlrequester.h>
+#include <kurlrequesterdlg.h>
+
+int main( int argc, char **argv )
+{
+ TDEApplication app( argc, argv, "kurlrequestertest" );
+ KURL url = KURLRequesterDlg::getURL( "ftp://ftp.kde.org" );
+ tqDebug( "Selected url: %s", url.url().latin1());
+
+ KURLRequester *req = new KURLRequester();
+ KEditListBox *el = new KEditListBox( TQString::fromLatin1("Test"), req->customEditor() );
+ el->show();
+ return app.exec();
+}
diff --git a/tdeio/tdefile/tests/tdefiletreeviewtest.cpp b/tdeio/tdefile/tests/tdefiletreeviewtest.cpp
new file mode 100644
index 000000000..b74468fda
--- /dev/null
+++ b/tdeio/tdefile/tests/tdefiletreeviewtest.cpp
@@ -0,0 +1,165 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Klaas Freitag <freitag@suse.de>
+
+ 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 <tqdir.h>
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kmainwindow.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kstatusbar.h>
+
+#include <tdefiletreeview.h>
+#include "tdefiletreeviewtest.h"
+
+
+#include "tdefiletreeviewtest.moc"
+
+testFrame::testFrame():KMainWindow(0,"Test FileTreeView"),
+ dirOnlyMode(false)
+
+{
+ treeView = new KFileTreeView( this );
+ treeView->setDragEnabled( true );
+ treeView->setAcceptDrops( true );
+ treeView->setDropVisualizer( true );
+
+
+ /* Connect to see the status bar */
+ KStatusBar* sta = statusBar();
+ connect( treeView, TQT_SIGNAL( onItem( const TQString& )),
+ sta, TQT_SLOT( message( const TQString& )));
+
+ connect( treeView, TQT_SIGNAL( dropped( TQWidget*, TQDropEvent*, KURL::List& )),
+ this, TQT_SLOT( urlsDropped( TQWidget*, TQDropEvent*, KURL::List& )));
+
+ connect( treeView, TQT_SIGNAL( dropped( KURL::List&, KURL& )), this,
+ TQT_SLOT( copyURLs( KURL::List&, KURL& )));
+
+ treeView->addColumn( "File" );
+ treeView->addColumn( "ChildCount" );
+ setCentralWidget( treeView );
+ resize( 600, 400 );
+
+ showPath( KURL::fromPathOrURL( TQDir::homeDirPath() ));
+}
+
+void testFrame::showPath( const KURL &url )
+{
+ TQString fname = "TestBranch"; // url.fileName ();
+ /* try a user icon */
+ KIconLoader *loader = TDEGlobal::iconLoader();
+ TQPixmap pix = loader->loadIcon( "contents2", KIcon::Small );
+ TQPixmap pixOpen = loader->loadIcon( "contents", KIcon::Small );
+
+ KFileTreeBranch *nb = treeView->addBranch( url, fname, pix );
+
+ if( nb )
+ {
+ if( dirOnlyMode ) treeView->setDirOnlyMode( nb, true );
+ nb->setOpenPixmap( pixOpen );
+
+ connect( nb, TQT_SIGNAL(populateFinished(KFileTreeViewItem*)),
+ this, TQT_SLOT(slotPopulateFinished(KFileTreeViewItem*)));
+ connect( nb, TQT_SIGNAL( directoryChildCount( KFileTreeViewItem *, int )),
+ this, TQT_SLOT( slotSetChildCount( KFileTreeViewItem*, int )));
+ // nb->setChildRecurse(false );
+
+ nb->setOpen(true);
+ }
+
+
+}
+
+void testFrame::urlsDropped( TQWidget* , TQDropEvent* , KURL::List& list )
+{
+ KURL::List::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ kdDebug() << "Url dropped: " << (*it).prettyURL() << endl;
+ }
+}
+
+void testFrame::copyURLs( KURL::List& list, KURL& to )
+{
+ KURL::List::ConstIterator it = list.begin();
+ kdDebug() << "Copy to " << to.prettyURL() << endl;
+ for ( ; it != list.end(); ++it ) {
+ kdDebug() << "Url: " << (*it).prettyURL() << endl;
+ }
+
+}
+
+
+void testFrame::slotPopulateFinished(KFileTreeViewItem *item )
+{
+ if( item )
+ {
+#if 0
+ int cc = item->childCount();
+
+ kdDebug() << "setting column 2 of treeview with count " << cc << endl;
+
+ item->setText( 1, TQString::number( cc ));
+#endif
+ }
+ else
+ {
+ kdDebug() << "slotPopFinished for uninitalised item" << endl;
+ }
+}
+
+void testFrame::slotSetChildCount( KFileTreeViewItem *item, int c )
+{
+ if( item )
+ item->setText(1, TQString::number( c ));
+}
+
+int main(int argc, char **argv)
+{
+ TDEApplication a(argc, argv, "tdefiletreeviewtest");
+ TQString name1;
+ TQStringList names;
+
+ TQString argv1;
+ testFrame *tf;
+
+ tf = new testFrame();
+ a.setMainWidget( tf );
+
+ if (argc > 1)
+ {
+ for( int i = 1; i < argc; i++ )
+ {
+ argv1 = TQString::fromLatin1(argv[i]);
+ kdDebug() << "Opening " << argv1 << endl;
+ if( argv1 == "-d" )
+ tf->setDirOnly();
+ else
+ {
+ KURL u( argv1 );
+ tf->showPath( u );
+ }
+ }
+ }
+ tf->show();
+ int ret = a.exec();
+ return( ret );
+}
diff --git a/tdeio/tdefile/tests/tdefiletreeviewtest.h b/tdeio/tdefile/tests/tdefiletreeviewtest.h
new file mode 100644
index 000000000..4ae791ce5
--- /dev/null
+++ b/tdeio/tdefile/tests/tdefiletreeviewtest.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Klaas Freitag <freitag@suse.de>
+
+ 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 KFILETREEVIEWTEST
+#define KFILETREEVIEWTEST
+
+class testFrame: public KMainWindow
+{
+ Q_OBJECT
+public:
+ testFrame();
+ void showPath( const KURL & );
+ void setDirOnly( ) { dirOnlyMode = true; }
+public slots:
+ void slotPopulateFinished(KFileTreeViewItem *);
+ void slotSetChildCount( KFileTreeViewItem *item, int c );
+
+ void urlsDropped( TQWidget*, TQDropEvent*, KURL::List& );
+ void copyURLs( KURL::List& list, KURL& to );
+private:
+ KFileTreeView *treeView;
+ bool dirOnlyMode;
+};
+
+
+#endif
diff --git a/tdeio/tdefileplugin.desktop b/tdeio/tdefileplugin.desktop
new file mode 100644
index 000000000..6609551a6
--- /dev/null
+++ b/tdeio/tdefileplugin.desktop
@@ -0,0 +1,88 @@
+[Desktop Entry]
+Type=ServiceType
+X-TDE-ServiceType=KFilePlugin
+Name=KFile Meta Data Plugin
+Name[af]=Klêer Meta Data Inprop module
+Name[ar]=ملحق KFile Meta Data
+Name[az]=KFile Meta Data ÆlavÉ™si
+Name[bg]=ПриÑтавка за мета данни
+Name[bn]=কে-ফাইল মেটা-ডেটা পà§à¦²à¦¾à¦—-ইন
+Name[bs]=KFile Meta Data dodatak
+Name[ca]=Connector de meta dades KFile
+Name[cs]=Modul KFile pro metadata
+Name[csb]=Plugins do sprôwianiô pòdôwkama nieznónegò fòrmatu
+Name[cy]=Ategyn Meta-ddata KFfeil
+Name[da]=KFile Metadata-plugin
+Name[de]=KFile: Metadaten-Modul
+Name[el]=ΠÏόσθετο μετα-δεδομένων του KFile
+Name[eo]=Dosierinterdatuma kromaĵo
+Name[es]=Plugin de meta datos KFile
+Name[et]=KFile'i metaandmete plugin
+Name[eu]=KFile metadatuen plugin-a
+Name[fa]=وصلۀ Ùرادادۀ KFile
+Name[fi]=KFile-metatietolisäosa
+Name[fr]=Module externe de métadonnées KFile
+Name[ga]=Breiseán meiteashonraí do KFile
+Name[gl]=Plugin para Meta Dados de KFile
+Name[he]=תוסף מט×Ö¾× ×ª×•× ×™× ×¢×‘×•×¨ KFile
+Name[hi]=KFile मेटा ङाटा पà¥à¤²à¤—इन
+Name[hr]=KFile dodatak za meta-podatke
+Name[hu]=KFile metaadat-modul
+Name[id]=Plugin Meta Data KBerkas
+Name[is]=KFile lýsiskráar-íforrit
+Name[it]=Plugin informazioni aggiuntive per KFile
+Name[ja]=KFile メタデータプラグイン
+Name[ka]=KFile-ს მეტáƒáƒ›áƒáƒœáƒáƒªáƒ”მთრმáƒáƒ“ული
+Name[kk]=KFile метадеректер модулі
+Name[km]=កម្មវិធី​ជំនួយ​ážáž¶áž„​ក្នុង​នៃ​ទិន្ននáŸáž™â€‹áž˜áŸážáž¶ KFile
+Name[ko]=KíŒŒì¼ ë©”íƒ€ ìžë£Œ 플러그ì¸
+Name[lb]=KFile-Metadonnéeë-Plugin
+Name[lt]=KFile Meta duomenų priedas
+Name[lv]=KFailu Meta Datu Iespraudnis
+Name[mk]=KFile приклучок за мета податоци
+Name[mn]=KFile: Мита өгөгдлийн -Plugin
+Name[ms]=Plug masuk Data Meta KFile
+Name[mt]=Plagin metadata ta' KFile
+Name[nb]=KFile programtillegg for metadata
+Name[nds]=KFile, Metadaten-Plugin
+Name[ne]=K फाइल मेटाडेटा पà¥à¤²à¤—इन
+Name[nn]=KFile-programtillegg for metadata
+Name[nso]=Tsenyo ya Data ya Meta wa KFaele
+Name[pa]=KFile ਮੈਟਾ ਡਾਟਾ ਪਲੱਗਿੰਨ
+Name[pl]=Wtyczka do obsługi danych nieznanego formatu
+Name[pt]='Plugin' de Meta-Dados do KFile
+Name[pt_BR]=Plug-in KFile de Meta Dados
+Name[ro]=Modul metadate KFile
+Name[ru]=Модуль метаданных KFile
+Name[rw]=Icyomeka ry'Ibyatanzwe Bidasanzwe bya KIdosiye
+Name[se]=KFile lassemoduvla metadieđuid várás
+Name[sk]=Modul KFile pre meta dáta
+Name[sl]=Vstavek za meta podatke pri KFile
+Name[sq]=Shtojca KFile Meta Data
+Name[sr]=KFile прикључак за мета податке
+Name[sr@Latn]=KFile prikljuÄak za meta podatke
+Name[sv]=Kfil-metadatainsticksprogram
+Name[ta]=கேகோபà¯à®ªà¯ மெடà¯à®Ÿà®¾ தகவல௠சொரà¯à®•à¯à®ªà¯à®ªà¯Šà®°à¯à®³à¯
+Name[te]=కెదసà±à°¤à±à°°à°‚ మెటా దతà±à°¤à°¾à°‚సం à°ªà±à°²à°—à°¿à°¨à±
+Name[tg]=KФайли Модули Meta Сана
+Name[th]=ปลั๊à¸à¸­à¸´à¸™à¸‚้อมูลเมตาของ KFile
+Name[tr]=KFile Meta Veri Eklentisi
+Name[tt]=KFile Meta-Bireme öçen Östämä
+Name[uk]=Втулок метаданих KFile
+Name[uz]=KFile meta maʼlumot uchun plagin
+Name[uz@cyrillic]=KFile мета маълумот учун плагин
+Name[ven]=Meta data pulagini ya faela ya K
+Name[vi]=Bộ cầm phít siêu dữ liệu KFile
+Name[xh]=Iplagi yangaphakathi ye KFile Meta Data
+Name[zh_CN]=KFile 元数æ®æ’件
+Name[zh_HK]=KFile 元資料外掛程å¼
+Name[zh_TW]=KFile 資料定義外掛程å¼
+
+[PropertyDef::PreferredItems]
+Type=TQStringList
+
+[PropertyDef::PreferredGroups]
+Type=TQStringList
+
+[PropertyDef::SupportsThumbnail]
+Type=bool
diff --git a/tdeio/tdeio/CMakeLists.txt b/tdeio/tdeio/CMakeLists.txt
new file mode 100644
index 000000000..8aaf395b6
--- /dev/null
+++ b/tdeio/tdeio/CMakeLists.txt
@@ -0,0 +1,138 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdeio/kssl
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/dcop
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore/network
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/kssl
+ ${CMAKE_SOURCE_DIR}/interfaces
+ ${LIBR_INCLUDEDIR}
+ ${GAMIN_INCLUDEDIR}
+)
+
+link_directories(
+ ${GAMIN_LIBDIR}
+)
+
+##### headers ###################################
+
+install( FILES
+ kservicetype.h kmimetype.h kmimemagic.h kservice.h
+ krun.h kdirwatch.h kautomount.h kuserprofile.h
+ kshred.h kar.h ktar.h kzip.h ktrader.h kurifilter.h
+ kurlcompletion.h kshellcompletion.h tdefileitem.h
+ tdefileshare.h ksambashare.h knfsshare.h kdirlister.h
+ kservicegroup.h kimageio.h kdirnotify.h kdirnotify_stub.h
+ kurlpixmapprovider.h kprotocolinfo.h kprotocolmanager.h
+ kfilterbase.h kfilterdev.h kemailsettings.h kscan.h
+ kdatatool.h karchive.h tdefilefilter.h tdefilemetainfo.h
+ renamedlgplugin.h kmimetyperesolver.h kdcopservicestarter.h
+ kremoteencoding.h kmimetypechooser.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} )
+
+# FIXME seems that ACL is no longer optional
+#if( USE_POSIX_ACL )
+ install( FILES kacl.h DESTINATION ${INCLUDE_INSTALL_DIR} )
+#endif( USE_POSIX_ACL )
+
+install( FILES
+ connection.h slaveinterface.h slave.h slaveconfig.h
+ sessiondata.h global.h passdlg.h netaccess.h job.h
+ scheduler.h jobclasses.h paste.h slavebase.h
+ progressbase.h defaultprogress.h statusbarprogress.h
+ tcpslavebase.h forwardingslavebase.h observer.h
+ chmodjob.h kmdbase.h authinfo.h ioslave_defaults.h
+ http_slave_defaults.h previewjob.h thumbcreator.h
+ metainfojob.h davjob.h renamedlg.h skipdlg.h
+ ${CMAKE_CURRENT_BINARY_DIR}/uiserver_stub.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/tdeio )
+
+
+##### tdeiocore ###################################
+
+set( target tdeiocore )
+
+set( ${target}_SRCS
+ authinfo.cpp kshred.cpp kprotocolmanager.cpp slave.cpp
+ slaveinterface.cpp observer.stub sessiondata.cpp
+ scheduler.cpp connection.cpp job.cpp global.cpp
+ slaveconfig.cpp kurlpixmapprovider.cpp netaccess.cpp
+ paste.cpp pastedialog.cpp kmimemagic.cpp tcpslavebase.cpp
+ slavebase.cpp passdlg.cpp forwardingslavebase.cpp
+ progressbase.cpp defaultprogress.cpp statusbarprogress.cpp
+ kdirnotify.cpp kdirnotify.skel kdirnotify_stub.cpp
+ observer.cpp ../misc/uiserver.stub observer.skel kemailsettings.cpp
+ kprotocolinfo.cpp renamedlg.cpp skipdlg.cpp kremoteencoding.cpp
+ kmimetypechooser.cpp
+)
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+ DEPENDENCIES dcopidl
+)
+
+
+##### tdesycoca ###################################
+
+set( target tdesycoca )
+
+set( ${target}_SRCS
+ kdirwatch.cpp tdefileshare.cpp ksambashare.cpp
+ knfsshare.cpp ktrader.cpp ktraderparse.cpp
+ ktraderparsetree.cpp kservicetypefactory.cpp
+ kservicetype.cpp kmimetype.cpp kservicegroup.cpp
+ kservice.cpp kservicefactory.cpp kuserprofile.cpp
+ kservicegroupfactory.cpp kurifilter.cpp kfilterbase.cpp
+ kfilterdev.cpp kshellcompletion.cpp kurlcompletion.cpp
+ kautomount.cpp krun.cpp tdefileitem.cpp kdirlister.cpp
+ kimageio.cpp yacc.c lex.c chmodjob.cpp kscan.cpp
+ kar.cpp ktar.cpp kzip.cpp previewjob.cpp metainfojob.cpp
+ davjob.cpp kdatatool.cpp karchive.cpp tdefilefilter.cpp
+ tdefilemetainfo.cpp kdcopservicestarter.cpp dataslave.cpp
+ dataprotocol.cpp
+)
+
+# FIXME seems that ACL is no longer optional
+#if( USE_POSIX_ACL )
+ set( ${target}_SRCS ${${target}_SRCS} kacl.cpp posixacladdons.cpp )
+#endif( USE_POSIX_ACL )
+
+tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK ${GAMIN_LIBRARIES}
+)
+
+
+##### tdelficon ###################################
+
+if( HAVE_ELFICON )
+
+ set( target tdelficon )
+
+ set( ${target}_SRCS
+ tdelficon.cpp
+ )
+
+ tde_add_library( ${target} STATIC_PIC AUTOMOC
+ SOURCES ${${target}_SRCS}
+ )
+
+endif( HAVE_ELFICON )
diff --git a/tdeio/tdeio/KFILEMETAINFO_ISSUES b/tdeio/tdeio/KFILEMETAINFO_ISSUES
new file mode 100644
index 000000000..a4486f85f
--- /dev/null
+++ b/tdeio/tdeio/KFILEMETAINFO_ISSUES
@@ -0,0 +1,4 @@
+Bugs:
+=====
+
+currently none known
diff --git a/tdeio/tdeio/Makefile.am b/tdeio/tdeio/Makefile.am
new file mode 100644
index 000000000..f0766f5c8
--- /dev/null
+++ b/tdeio/tdeio/Makefile.am
@@ -0,0 +1,129 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Torben Weis (weis@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.
+
+AM_CPPFLAGS = -D_LARGEFILE64_SOURCE
+
+INCLUDES= -I$(top_srcdir) -I$(srcdir)/.. -I$(top_srcdir)/tdecore/network -I$(srcdir)/../kssl -I../kssl -I$(srcdir)/../../interfaces $(all_includes) $(SSL_INCLUDES)
+
+noinst_LTLIBRARIES = libtdeiocore.la libtdesycoca.la
+
+# convenience lib - no LDFLAGS or LIBADD !
+
+libtdesycoca_la_SOURCES = \
+ kdirwatch.cpp \
+ tdefileshare.cpp ksambashare.cpp knfsshare.cpp \
+ ktrader.cpp ktraderparse.cpp ktraderparsetree.cpp \
+ kservicetypefactory.cpp kservicetype.cpp \
+ kmimetype.cpp kservicegroup.cpp \
+ kservice.cpp kservicefactory.cpp \
+ kuserprofile.cpp kservicegroupfactory.cpp \
+ kurifilter.cpp \
+ kfilterbase.cpp kfilterdev.cpp \
+ kshellcompletion.cpp kurlcompletion.cpp \
+ kautomount.cpp krun.cpp \
+ tdefileitem.cpp kdirlister.cpp kimageio.cpp \
+ yacc.c lex.c \
+ chmodjob.cpp kscan.cpp kar.cpp ktar.cpp kzip.cpp previewjob.cpp metainfojob.cpp davjob.cpp \
+ kdatatool.cpp karchive.cpp tdefilefilter.cpp \
+ tdefilemetainfo.cpp kdcopservicestarter.cpp \
+ dataslave.cpp dataprotocol.cpp
+#if USE_POSIX_ACL
+ libtdesycoca_la_SOURCES += kacl.cpp posixacladdons.cpp
+#endif
+
+include_HEADERS = \
+ kservicetype.h kmimetype.h kmimemagic.h kservice.h \
+ krun.h kdirwatch.h kautomount.h kuserprofile.h \
+ kshred.h kar.h ktar.h kzip.h ktrader.h kurifilter.h kurlcompletion.h \
+ kshellcompletion.h tdefileitem.h tdefileshare.h ksambashare.h knfsshare.h \
+ kdirlister.h kservicegroup.h \
+ kimageio.h kdirnotify.h kdirnotify_stub.h \
+ kurlpixmapprovider.h kprotocolinfo.h kprotocolmanager.h \
+ kfilterbase.h kfilterdev.h kemailsettings.h kscan.h kdatatool.h \
+ karchive.h tdefilefilter.h tdefilemetainfo.h renamedlgplugin.h \
+ kmimetyperesolver.h kdcopservicestarter.h kremoteencoding.h \
+ kmimetypechooser.h
+#if USE_POSIX_ACL
+include_HEADERS += kacl.h
+#endif
+
+#libtdeiocore_la_LDFLAGS = $(all_libraries)
+#libtdeiocore_la_LIBADD = ../../tdeui/libtdeui.la ../../tdesu/libtdesu.la $(LIBZ) $(LIBFAM) $(LIBVOLMGT)
+
+libtdeiocore_la_SOURCES = authinfo.cpp \
+ kshred.cpp \
+ kprotocolmanager.cpp \
+ slave.cpp slaveinterface.cpp observer.stub \
+ sessiondata.cpp scheduler.cpp \
+ connection.cpp \
+ job.cpp global.cpp \
+ slaveconfig.cpp kurlpixmapprovider.cpp \
+ netaccess.cpp paste.cpp pastedialog.cpp \
+ kmimemagic.cpp \
+ tcpslavebase.cpp slavebase.cpp passdlg.cpp \
+ forwardingslavebase.cpp \
+ progressbase.cpp defaultprogress.cpp \
+ statusbarprogress.cpp \
+ kdirnotify.cpp kdirnotify.skel kdirnotify_stub.cpp \
+ observer.cpp uiserver.stub observer.skel \
+ kemailsettings.cpp \
+ kprotocolinfo.cpp \
+ renamedlg.cpp skipdlg.cpp kremoteencoding.cpp \
+ kmimetypechooser.cpp
+
+uiserver_DIR = $(top_srcdir)/tdeio/misc
+
+METASOURCES = AUTO
+
+tdeioincludedir = $(includedir)/tdeio
+tdeioinclude_HEADERS = connection.h \
+ slaveinterface.h slave.h slaveconfig.h \
+ sessiondata.h global.h passdlg.h \
+ netaccess.h job.h scheduler.h \
+ jobclasses.h paste.h slavebase.h \
+ progressbase.h defaultprogress.h \
+ statusbarprogress.h tcpslavebase.h \
+ forwardingslavebase.h \
+ observer.h chmodjob.h uiserver_stub.h \
+ kmdbase.h authinfo.h \
+ ioslave_defaults.h http_slave_defaults.h previewjob.h thumbcreator.h \
+ metainfojob.h davjob.h renamedlg.h skipdlg.h
+
+# Internal
+noinst_HEADERS = kservicetypefactory.h kservicefactory.h \
+ kmessageboxwrapper.h \
+ ktraderparse.h ktraderparsetree.h yacc.h \
+ kimageiofactory.h kdirwatch_p.h kdirlister_p.h \
+ renamedlg.h skipdlg.h dataslave.h dataprotocol.h \
+ kservice_p.h
+#if USE_POSIX_ACL
+noinst_HEADERS += posixacladdons.h
+#endif
+
+parserfiles = yacc.y lex.l
+
+EXTRA_DIST = $(parserfiles)
+
+parser: $(parserfiles)
+ cd $(srcdir) ;\
+ flex -olex.c -Pkiotrader lex.l ;\
+ bison -d -p kiotrader yacc.y && mv yacc.tab.c yacc.c; mv yacc.tab.h yacc.h
+
+.PHONY: parser
+
+include ../../admin/Doxyfile.am
diff --git a/tdeio/tdeio/authinfo.cpp b/tdeio/tdeio/authinfo.cpp
new file mode 100644
index 000000000..b95a40585
--- /dev/null
+++ b/tdeio/tdeio/authinfo.cpp
@@ -0,0 +1,332 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2001 Dawit Alemayehu <adawit@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 <config.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqdir.h>
+#include <tqfile.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+#include <kstaticdeleter.h>
+#include <kde_file.h>
+
+#include "tdeio/authinfo.h"
+
+#define NETRC_READ_BUF_SIZE 4096
+
+using namespace TDEIO;
+
+AuthInfo::AuthInfo()
+{
+ modified = false;
+ readOnly = false;
+ verifyPath = false;
+ keepPassword = false;
+}
+
+AuthInfo::AuthInfo( const AuthInfo& info )
+{
+ (*this) = info;
+}
+
+AuthInfo& AuthInfo::operator= ( const AuthInfo& info )
+{
+ url = info.url;
+ username = info.username;
+ password = info.password;
+ prompt = info.prompt;
+ caption = info.caption;
+ comment = info.comment;
+ commentLabel = info.commentLabel;
+ realmValue = info.realmValue;
+ digestInfo = info.digestInfo;
+ verifyPath = info.verifyPath;
+ readOnly = info.readOnly;
+ keepPassword = info.keepPassword;
+ modified = info.modified;
+ return *this;
+}
+
+TQDataStream& TDEIO::operator<< (TQDataStream& s, const AuthInfo& a)
+{
+ s << a.url << a.username << a.password << a.prompt << a.caption
+ << a.comment << a.commentLabel << a.realmValue << a.digestInfo
+ << TQ_UINT8(a.verifyPath ? 1:0) << TQ_UINT8(a.readOnly ? 1:0)
+ << TQ_UINT8(a.keepPassword ? 1:0) << TQ_UINT8(a.modified ? 1:0);
+ return s;
+}
+
+TQDataStream& TDEIO::operator>> (TQDataStream& s, AuthInfo& a)
+{
+ TQ_UINT8 verify = 0;
+ TQ_UINT8 ro = 0;
+ TQ_UINT8 keep = 0;
+ TQ_UINT8 mod = 0;
+
+ s >> a.url >> a.username >> a.password >> a.prompt >> a.caption
+ >> a.comment >> a.commentLabel >> a.realmValue >> a.digestInfo
+ >> verify >> ro >> keep >> mod;
+ a.verifyPath = (verify != 0);
+ a.readOnly = (ro != 0);
+ a.keepPassword = (keep != 0);
+ a.modified = (mod != 0);
+ return s;
+}
+
+
+NetRC* NetRC::instance = 0L;
+
+NetRC::NetRC()
+{
+ isDirty = false;
+}
+
+NetRC::~NetRC()
+{
+ delete instance;
+ instance = 0L;
+}
+
+NetRC* NetRC::self()
+{
+ if ( !instance )
+ instance = new NetRC();
+ return instance;
+}
+
+bool NetRC::lookup( const KURL& url, AutoLogin& login, bool userealnetrc,
+ TQString type, int mode )
+{
+ // kdDebug() << "AutoLogin lookup for: " << url.host() << endl;
+ if ( !url.isValid() )
+ return false;
+
+ if ( type.isEmpty() )
+ type = url.protocol();
+
+ if ( loginMap.isEmpty() || isDirty )
+ {
+ loginMap.clear();
+
+ TQString filename = locateLocal("config", "kionetrc");
+ bool status = parse (openf (filename));
+
+ if ( userealnetrc )
+ {
+ filename = TQDir::homeDirPath()+ TQDir::separator() + ".netrc";
+ status |= parse (openf(filename));
+ }
+
+ if ( !status )
+ return false;
+ }
+
+ if ( !loginMap.contains( type ) )
+ return false;
+
+ LoginList l = loginMap[type];
+ if ( l.isEmpty() )
+ return false;
+
+ for (LoginList::Iterator it = l.begin(); it != l.end(); ++it)
+ {
+ AutoLogin &log = *it;
+
+ if ( (mode & defaultOnly) == defaultOnly &&
+ log.machine == TQString::fromLatin1("default") &&
+ (login.login.isEmpty() || login.login == log.login) )
+ {
+ login.type = log.type;
+ login.machine = log.machine;
+ login.login = log.login;
+ login.password = log.password;
+ login.macdef = log.macdef;
+ }
+
+ if ( (mode & presetOnly) == presetOnly &&
+ log.machine == TQString::fromLatin1("preset") &&
+ (login.login.isEmpty() || login.login == log.login) )
+ {
+ login.type = log.type;
+ login.machine = log.machine;
+ login.login = log.login;
+ login.password = log.password;
+ login.macdef = log.macdef;
+ }
+
+ if ( (mode & exactOnly) == exactOnly &&
+ log.machine == url.host() &&
+ (login.login.isEmpty() || login.login == log.login) )
+ {
+ login.type = log.type;
+ login.machine = log.machine;
+ login.login = log.login;
+ login.password = log.password;
+ login.macdef = log.macdef;
+ break;
+ }
+ }
+
+ return true;
+}
+
+int NetRC::openf( const TQString& f )
+{
+ KDE_struct_stat sbuff;
+ TQCString ef = TQFile::encodeName(f);
+ if ( KDE_stat(ef, &sbuff) != 0 )
+ return -1;
+
+ // Security check!!
+ if ( sbuff.st_mode != (S_IFREG|S_IRUSR|S_IWUSR) ||
+ sbuff.st_uid != geteuid() )
+ return -1;
+
+ return KDE_open( ef, O_RDONLY );
+}
+
+TQString NetRC::extract( const char* buf, const char* key, int& pos )
+{
+ int idx = pos;
+ int m_len = strlen(key);
+ int b_len = strlen(buf);
+
+ while( idx < b_len )
+ {
+ while( buf[idx] == ' ' || buf[idx] == '\t' )
+ idx++;
+
+ if ( strncasecmp( buf+idx, key, m_len ) != 0 )
+ idx++;
+ else
+ {
+ idx += m_len;
+ while( buf[idx] == ' ' || buf[idx] == '\t' )
+ idx++;
+
+ int start = idx;
+ while( buf[idx] != ' ' && buf[idx] != '\t' &&
+ buf[idx] != '\n' && buf[idx] != '\r' )
+ idx++;
+
+ if ( idx > start )
+ {
+ pos = idx;
+ return TQString::fromLatin1( buf+start, idx-start);
+ }
+ }
+ }
+
+ return TQString::null;
+}
+
+bool NetRC::parse( int fd )
+{
+ if (fd == -1)
+ return false;
+
+ TQString type;
+ TQString macro;
+
+ uint index = 0;
+ bool isMacro = false;
+ char* buf = new char[NETRC_READ_BUF_SIZE];
+ FILE* fstream = KDE_fdopen( fd,"rb" );
+
+ while ( fgets (buf, NETRC_READ_BUF_SIZE, fstream) != 0L )
+ {
+ int pos = 0;
+
+ while ( buf[pos] == ' ' || buf[pos] == '\t' )
+ pos++;
+
+ if ( buf[pos] == '#' || buf[pos] == '\n' ||
+ buf[pos] == '\r' || buf[pos] == '\0' )
+ {
+ if ( buf[pos] != '#' && isMacro )
+ isMacro = false;
+
+ continue;
+ }
+
+ if ( isMacro )
+ {
+ int tail = strlen(buf);
+ while( buf[tail-1] == '\n' || buf[tail-1] =='\r' )
+ tail--;
+
+ TQString mac = TQString::fromLatin1(buf, tail).stripWhiteSpace();
+ if ( !mac.isEmpty() )
+ loginMap[type][index].macdef[macro].append( mac );
+
+ continue;
+ }
+
+ AutoLogin l;
+ l.machine = extract( buf, "machine", pos );
+ if ( l.machine.isEmpty() )
+ {
+ if (strncasecmp(buf+pos, "default", 7) == 0 )
+ {
+ pos += 7;
+ l.machine = TQString::fromLatin1("default");
+ }
+ else if (strncasecmp(buf+pos, "preset", 6) == 0 )
+ {
+ pos += 6;
+ l.machine = TQString::fromLatin1("preset");
+ }
+ }
+ // kdDebug() << "Machine: " << l.machine << endl;
+
+ l.login = extract( buf, "login", pos );
+ // kdDebug() << "Login: " << l.login << endl;
+
+ l.password = extract( buf, "password", pos );
+ if ( l.password.isEmpty() )
+ l.password = extract( buf, "account", pos );
+ // kdDebug() << "Password: " << l.password << endl;
+
+ type = l.type = extract( buf, "type", pos );
+ if ( l.type.isEmpty() && !l.machine.isEmpty() )
+ type = l.type = TQString::fromLatin1("ftp");
+ // kdDebug() << "Type: " << l.type << endl;
+
+ macro = extract( buf, "macdef", pos );
+ isMacro = !macro.isEmpty();
+ // kdDebug() << "Macro: " << macro << endl;
+
+ loginMap[l.type].append(l);
+ index = loginMap[l.type].count()-1;
+ }
+
+ delete [] buf;
+ fclose (fstream);
+ close (fd);
+ return true;
+}
diff --git a/tdeio/tdeio/authinfo.h b/tdeio/tdeio/authinfo.h
new file mode 100644
index 000000000..019311ef8
--- /dev/null
+++ b/tdeio/tdeio/authinfo.h
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2001 Dawit Alemayehu <adawit@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 __KIO_AUTHINFO_H
+#define __KIO_AUTHINFO_H
+
+#include <tqmap.h>
+#include <tqvaluelist.h>
+#include <kurl.h>
+
+
+namespace TDEIO {
+
+/**
+ * This class is intended to make it easier to prompt for, cache
+ * and retrieve authorization information.
+ *
+ * When using this class to cache, retrieve or prompt authentication
+ * information, you only need to set the necessary attributes. For
+ * example, to check whether a password is already cached, the only
+ * required information is the URL of the resource and optionally
+ * whether or not a path match should be performed. Similarly, to
+ * prompt for password you only need to optionally set the prompt,
+ * username (if already supplied), comment and commentLabel fields.
+ *
+ * <em>SPECIAL NOTE:</em> If you extend this class to add additional
+ * parameters do not forget to overload the stream insertion and
+ * extraction operators ("<<" and ">>") so that the added data can
+ * be correctly serialzed.
+ *
+ * @short A two way messaging class for passing authentication information.
+ * @author Dawit Alemayehu <adawit@kde.org>
+ */
+class TDEIO_EXPORT AuthInfo
+{
+ TDEIO_EXPORT friend TQDataStream& operator<< (TQDataStream& s, const AuthInfo& a);
+ TDEIO_EXPORT friend TQDataStream& operator>> (TQDataStream& s, AuthInfo& a);
+
+public:
+ /**
+ * Default constructor.
+ */
+ AuthInfo();
+
+ /**
+ * Copy constructor.
+ */
+ AuthInfo( const AuthInfo& info );
+
+ /**
+ * Overloaded equal to operator.
+ */
+ AuthInfo& operator=( const AuthInfo& info );
+
+ /**
+ * Use this method to check if the object was modified.
+ * @return true if the object has been modified
+ */
+ bool isModified() const { return modified; }
+
+ /**
+ * Use this method to indicate that this object has been modified.
+ * @param flag true to mark the object as modified, false to clear
+ */
+ void setModified( bool flag ) { modified = flag; }
+
+ /**
+ * The URL for which authentication is to be stored.
+ *
+ * This field is required when attempting to cache authorization
+ * and retrieve it. However, it is not needed when prompting
+ * the user for authorization info.
+ *
+ * This setting is @em required except when prompting the
+ * user for password.
+ */
+ KURL url;
+
+ /**
+ * This is @em required for caching.
+ */
+ TQString username;
+
+ /**
+ * This is @em required for caching.
+ */
+ TQString password;
+
+ /**
+ * Information to be displayed when prompting
+ * the user for authentication information.
+ *
+ * @note If this field is not set, the authentication
+ * dialog simply displays the preset default prompt.
+ *
+ * This setting is @em optional and empty by default.
+ */
+ TQString prompt;
+
+ /**
+ * The text to displayed in the title bar of
+ * the password prompting dialog.
+ *
+ * @note If this field is not set, the authentication
+ * dialog simply displays the preset default caption.
+ *
+ * This setting is @em optional and empty by default.
+ */
+ TQString caption;
+
+ /**
+ * Additional comment to be displayed when prompting
+ * the user for authentication information.
+ *
+ * This field allows you to display a short (no more than
+ * 80 characters) extra description in the password prompt
+ * dialog. For example, this field along with the
+ * commentLabel can be used to describe the server that
+ * requested the authentication:
+ *
+ * \code
+ * Server: Squid Proxy @ foo.com
+ * \endcode
+ *
+ * where "Server:" is the commentLabel and the rest is the
+ * actual comment. Note that it is always better to use
+ * the @p commentLabel field as it will be placed properly
+ * in the dialog rather than to include it within the actual
+ * comment.
+ *
+ * This setting is @em optional and empty by default.
+ */
+ TQString comment;
+
+ /**
+ * Descriptive label to be displayed in front of the
+ * comment when prompting the user for password.
+ *
+ * This setting is @em optional and only applicable when
+ * the comment field is also set.
+ */
+ TQString commentLabel;
+
+ /**
+ * A unique identifier that allows caching of multiple
+ * passwords for different resources in the same server.
+ *
+ * Mostly this setting is applicable to the HTTP protocol
+ * whose authentication scheme explicitly defines the use
+ * of such a unique key. However, any protocol that can
+ * generate or supply a unique id can effectively use it
+ * to distinguish passwords.
+ *
+ * (If you are instead interested in caching the authentication
+ * info for multiple users to the same server, refer to
+ * multipleUserCaching below)
+ *
+ * This setting is @em optional and not set by default.
+ */
+ TQString realmValue;
+
+ /**
+ * Field to store any extra authentication information for
+ * protocols that need it (ex: http).
+ *
+ * This setting is @em optional and mostly applicable for HTTP
+ * protocol. However, any protocol can make use of it to
+ * store extra info.
+ */
+ TQString digestInfo;
+
+ /**
+ * Flag that, if set, indicates whether a path match should be
+ * performed when requesting for cached authorization.
+ *
+ * A path is deemed to be a match if it is equal to or is a subset
+ * of the cached path. For example, if stored path is "/foo/bar"
+ * and the request's path set to "/foo/bar/acme", then it is a match
+ * whereas it would not if the request's path was set to "/foo".
+ *
+ * This setting is @em optional and false by default.
+ */
+ bool verifyPath;
+
+ /**
+ * Flag which if set forces the username field to be read-only.
+ *
+ * This setting is @em optional and false by default.
+ */
+ bool readOnly;
+
+ /**
+ * Flag to indicate the persistence of the given password.
+ *
+ * This is a two-way flag, when set before calling openPassDlg
+ * it makes the "keep Password" check box visible to the user.
+ * In return the flag will indicate the state of the check box.
+ * By default if the flag is checked the password will be cached
+ * for the entire life of the current KDE session otherwise the
+ * cached password is deleted right after the application using
+ * it has been closed.
+ */
+ bool keepPassword;
+
+protected:
+ bool modified;
+private:
+ class AuthInfoPrivate* d;
+};
+
+TDEIO_EXPORT TQDataStream& operator<< (TQDataStream& s, const AuthInfo& a);
+TDEIO_EXPORT TQDataStream& operator>> (TQDataStream& s, AuthInfo& a);
+
+/**
+ * A Singleton class that provides access to passwords
+ * stored in .netrc files for automatic login purposes.
+ * This is only meant to address backward compatability
+ * with old automated ftp client style logins...
+ *
+ * @short An interface to the ftp .netrc files
+ * @author Dawit Alemayehu <adawit@kde.org>
+ */
+class TDEIO_EXPORT NetRC
+{
+public:
+
+ /**
+ * Specifies the mode to be used when searching for a
+ * matching automatic login info for a given site :
+ *
+ * @li exactOnly search entries with exact host name matches.
+ * @li defaultOnly search entries that are specified as "default".
+ * @li presetOnly search entries that are specified as "preset".
+ *
+ * @see lookup
+ */
+ enum LookUpMode
+ {
+ exactOnly = 0x0002,
+ defaultOnly = 0x0004,
+ presetOnly = 0x0008
+ };
+
+ /**
+ * Contains auto login information.
+ * @see lookup()
+ */
+ struct AutoLogin
+ {
+ TQString type;
+ TQString machine;
+ TQString login;
+ TQString password;
+ TQMap<TQString, TQStringList> macdef;
+ };
+
+ /**
+ * A reference to the instance of the class.
+ * @return the class
+ */
+ static NetRC* self();
+
+ /**
+ * Looks up the @p login information for the given @p url.
+ *
+ * @param url the url whose login information will be checked
+ * @param login the login information will be writte here
+ * @param userealnetrc if true, use $HOME/.netrc fle
+ * @param type the type of the login. If null, the @p url's protocol
+ * will be taken
+ * @param mode the LookUpMode flags (ORed) for the query
+ */
+ bool lookup( const KURL& url, AutoLogin& login,
+ bool userealnetrc = false,
+ TQString type = TQString::null,
+ int mode = (exactOnly|defaultOnly) );
+ /**
+ * Reloads the auto login information.
+ */
+ void reload() { isDirty = true; }
+
+protected:
+ TQString extract( const char*, const char*, int& );
+ int openf( const TQString& );
+ bool parse( int );
+
+private:
+ NetRC();
+ ~NetRC();
+
+private:
+ bool isDirty;
+
+ typedef TQValueList<AutoLogin> LoginList;
+ typedef TQMap<TQString, LoginList> LoginMap;
+ LoginMap loginMap;
+
+ static NetRC* instance;
+ class NetRCPrivate;
+ NetRCPrivate* d;
+};
+}
+#endif
diff --git a/tdeio/tdeio/chmodjob.cpp b/tdeio/tdeio/chmodjob.cpp
new file mode 100644
index 000000000..434466d77
--- /dev/null
+++ b/tdeio/tdeio/chmodjob.cpp
@@ -0,0 +1,258 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ David Faure <faure@kde.org>
+ 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.
+*/
+
+#include <config.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <tqtimer.h>
+#include <tqfile.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "tdeio/job.h"
+#include "tdeio/chmodjob.h"
+
+#include <kdirnotify_stub.h>
+
+using namespace TDEIO;
+
+ChmodJob::ChmodJob( const KFileItemList& lstItems, int permissions, int mask,
+ int newOwner, int newGroup,
+ bool recursive, bool showProgressInfo )
+ : TDEIO::Job( showProgressInfo ), state( STATE_LISTING ),
+ m_permissions( permissions ), m_mask( mask ),
+ m_newOwner( newOwner ), m_newGroup( newGroup ),
+ m_recursive( recursive ), m_lstItems( lstItems )
+{
+ TQTimer::singleShot( 0, this, TQT_SLOT(processList()) );
+}
+
+void ChmodJob::processList()
+{
+ while ( !m_lstItems.isEmpty() )
+ {
+ KFileItem * item = m_lstItems.first();
+ if ( !item->isLink() ) // don't do anything with symlinks
+ {
+ // File or directory -> remember to chmod
+ ChmodInfo info;
+ info.url = item->url();
+ // This is a toplevel file, we apply changes directly (no +X emulation here)
+ info.permissions = ( m_permissions & m_mask ) | ( item->permissions() & ~m_mask );
+ /*kdDebug(7007) << "\n current permissions=" << TQString::number(item->permissions(),8)
+ << "\n wanted permission=" << TQString::number(m_permissions,8)
+ << "\n with mask=" << TQString::number(m_mask,8)
+ << "\n with ~mask (mask bits we keep) =" << TQString::number((uint)~m_mask,8)
+ << "\n bits we keep =" << TQString::number(item->permissions() & ~m_mask,8)
+ << "\n new permissions = " << TQString::number(info.permissions,8)
+ << endl;*/
+ m_infos.prepend( info );
+ //kdDebug(7007) << "processList : Adding info for " << info.url.prettyURL() << endl;
+ // Directory and recursive -> list
+ if ( item->isDir() && m_recursive )
+ {
+ //kdDebug(7007) << "ChmodJob::processList dir -> listing" << endl;
+ TDEIO::ListJob * listJob = TDEIO::listRecursive( item->url(), false /* no GUI */ );
+ connect( listJob, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob( listJob );
+ return; // we'll come back later, when this one's finished
+ }
+ }
+ m_lstItems.removeFirst();
+ }
+ kdDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING" << endl;
+ // We have finished, move on
+ state = STATE_CHMODING;
+ chmodNextFile();
+}
+
+void ChmodJob::slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList & list )
+{
+ TDEIO::UDSEntryListConstIterator it = list.begin();
+ TDEIO::UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+ TDEIO::UDSEntry::ConstIterator it2 = (*it).begin();
+ mode_t permissions = 0;
+ bool isDir = false;
+ bool isLink = false;
+ TQString relativePath;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch( (*it2).m_uds ) {
+ case TDEIO::UDS_NAME:
+ relativePath = (*it2).m_str;
+ break;
+ case TDEIO::UDS_FILE_TYPE:
+ isDir = S_ISDIR((*it2).m_long);
+ break;
+ case TDEIO::UDS_LINK_DEST:
+ isLink = !(*it2).m_str.isEmpty();
+ break;
+ case TDEIO::UDS_ACCESS:
+ permissions = (mode_t)((*it2).m_long);
+ break;
+ default:
+ break;
+ }
+ }
+ if ( !isLink && relativePath != TQString::fromLatin1("..") )
+ {
+ ChmodInfo info;
+ info.url = m_lstItems.first()->url(); // base directory
+ info.url.addPath( relativePath );
+ int mask = m_mask;
+ // Emulate -X: only give +x to files that had a +x bit already
+ // So the check is the opposite : if the file had no x bit, don't touch x bits
+ // For dirs this doesn't apply
+ if ( !isDir )
+ {
+ int newPerms = m_permissions & mask;
+ if ( (newPerms & 0111) && !(permissions & 0111) )
+ {
+ // don't interfere with mandatory file locking
+ if ( newPerms & 02000 )
+ mask = mask & ~0101;
+ else
+ mask = mask & ~0111;
+ }
+ }
+ info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
+ /*kdDebug(7007) << "\n current permissions=" << TQString::number(permissions,8)
+ << "\n wanted permission=" << TQString::number(m_permissions,8)
+ << "\n with mask=" << TQString::number(mask,8)
+ << "\n with ~mask (mask bits we keep) =" << TQString::number((uint)~mask,8)
+ << "\n bits we keep =" << TQString::number(permissions & ~mask,8)
+ << "\n new permissions = " << TQString::number(info.permissions,8)
+ << endl;*/
+ // Prepend this info in our todo list.
+ // This way, the toplevel dirs are done last.
+ m_infos.prepend( info );
+ }
+ }
+}
+
+void ChmodJob::chmodNextFile()
+{
+ if ( !m_infos.isEmpty() )
+ {
+ ChmodInfo info = m_infos.first();
+ m_infos.remove( m_infos.begin() );
+ // First update group / owner (if local file)
+ // (permissions have to set after, in case of suid and sgid)
+ if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
+ {
+ TQString path = info.url.path();
+ if ( chown( TQFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
+ {
+ int answer = KMessageBox::warningContinueCancel( 0, i18n( "<qt>Could not modify the ownership of file <b>%1</b>. You have insufficient access to the file to perform the change.</qt>" ).arg(path), TQString::null, i18n("&Skip File") );
+ if (answer == KMessageBox::Cancel)
+ {
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ }
+ }
+ }
+
+ kdDebug(7007) << "ChmodJob::chmodNextFile chmod'ing " << info.url.prettyURL()
+ << " to " << TQString::number(info.permissions,8) << endl;
+ TDEIO::SimpleJob * job = TDEIO::chmod( info.url, info.permissions );
+ // copy the metadata for acl and default acl
+ const TQString aclString = queryMetaData( "ACL_STRING" );
+ const TQString defaultAclString = queryMetaData( "DEFAULT_ACL_STRING" );
+ if ( !aclString.isEmpty() )
+ job->addMetaData( "ACL_STRING", aclString );
+ if ( !defaultAclString.isEmpty() )
+ job->addMetaData( "DEFAULT_ACL_STRING", defaultAclString );
+ addSubjob(job);
+ }
+ else
+ // We have finished
+ emitResult();
+}
+
+void ChmodJob::slotResult( TDEIO::Job * job )
+{
+ if ( job->error() )
+ {
+ m_error = job->error();
+ m_errorText = job->errorText();
+ emitResult();
+ return;
+ }
+ //kdDebug(7007) << " ChmodJob::slotResult( TDEIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
+ switch ( state )
+ {
+ case STATE_LISTING:
+ subjobs.remove(job);
+ m_lstItems.removeFirst();
+ kdDebug(7007) << "ChmodJob::slotResult -> processList" << endl;
+ processList();
+ return;
+ case STATE_CHMODING:
+ subjobs.remove(job);
+ kdDebug(7007) << "ChmodJob::slotResult -> chmodNextFile" << endl;
+ chmodNextFile();
+ return;
+ default:
+ assert(0);
+ return;
+ }
+}
+
+// antlarr: KDE 4: Make owner and group be const TQString &
+TDEIO_EXPORT ChmodJob *TDEIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
+ TQString owner, TQString group,
+ bool recursive, bool showProgressInfo )
+{
+ uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
+ if ( !owner.isEmpty() )
+ {
+ struct passwd* pw = getpwnam(TQFile::encodeName(owner));
+ if ( pw == 0L )
+ kdError(250) << " ERROR: No user " << owner << endl;
+ else
+ newOwnerID = pw->pw_uid;
+ }
+ gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
+ if ( !group.isEmpty() )
+ {
+ struct group* g = getgrnam(TQFile::encodeName(group));
+ if ( g == 0L )
+ kdError(250) << " ERROR: No group " << group << endl;
+ else
+ newGroupID = g->gr_gid;
+ }
+ return new ChmodJob( lstItems, permissions, mask, newOwnerID, newGroupID, recursive, showProgressInfo );
+}
+
+void ChmodJob::virtual_hook( int id, void* data )
+{ TDEIO::Job::virtual_hook( id, data ); }
+
+#include "chmodjob.moc"
diff --git a/tdeio/tdeio/chmodjob.h b/tdeio/tdeio/chmodjob.h
new file mode 100644
index 000000000..105df0e4d
--- /dev/null
+++ b/tdeio/tdeio/chmodjob.h
@@ -0,0 +1,109 @@
+// -*- c++ -*-
+/* 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 __kio_chmodjob_h__
+#define __kio_chmodjob_h__
+
+#include <kurl.h>
+#include <tqstring.h>
+
+#include <tdeio/global.h>
+#include <tdeio/job.h>
+#include <tdefileitem.h>
+
+namespace TDEIO {
+
+ /**
+ * This job changes permissions on a list of files or directories,
+ * optionally in a recursive manner.
+ * @see TDEIO::chmod()
+ */
+ class TDEIO_EXPORT ChmodJob : public TDEIO::Job
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Create new ChmodJobs using the TDEIO::chmod() function.
+ */
+ ChmodJob( const KFileItemList & lstItems, int permissions, int mask,
+ int newOwner, int newGroup,
+ bool recursive, bool showProgressInfo );
+
+ protected:
+ void chmodNextFile();
+
+ protected slots:
+
+ virtual void slotResult( TDEIO::Job *job );
+ void slotEntries( TDEIO::Job * , const TDEIO::UDSEntryList & );
+ void processList();
+
+ private:
+ struct ChmodInfo
+ {
+ KURL url;
+ int permissions;
+ };
+ enum { STATE_LISTING, STATE_CHMODING } state;
+ int m_permissions;
+ int m_mask;
+ int m_newOwner;
+ int m_newGroup;
+ bool m_recursive;
+ KFileItemList m_lstItems;
+ TQValueList<ChmodInfo> m_infos;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class ChmodJobPrivate* d;
+ };
+
+
+ /**
+ * Creates a job that changes permissions/ownership on several files or directories,
+ * optionally recursively.
+ * This version of chmod uses a KFileItemList so that it directly knows
+ * what to do with the items. TODO: a version that takes a KURL::List,
+ * and a general job that stats each url and returns a KFileItemList.
+ *
+ * Note that change of ownership is only supported for local files.
+ *
+ * Inside directories, the "x" bits will only be changed for files that had
+ * at least one "x" bit before, and for directories.
+ * This emulates the behavior of chmod +X.
+ *
+ * @param lstItems The file items representing several files or directories.
+ * @param permissions the permissions we want to set
+ * @param mask the bits we are allowed to change.
+ * For instance, if mask is 0077, we don't change
+ * the "user" bits, only "group" and "others".
+ * @param newOwner If non-empty, the new owner for the files
+ * @param newGroup If non-empty, the new group for the files
+ * @param recursive whether to open directories recursively
+ * @param showProgressInfo true to show progess information
+ * @return The job handling the operation.
+ */
+ TDEIO_EXPORT ChmodJob * chmod( const KFileItemList& lstItems, int permissions, int mask,
+ TQString newOwner, TQString newGroup,
+ bool recursive, bool showProgressInfo = true );
+
+}
+
+#endif
diff --git a/tdeio/tdeio/configure.in.in b/tdeio/tdeio/configure.in.in
new file mode 100644
index 000000000..8683dfec1
--- /dev/null
+++ b/tdeio/tdeio/configure.in.in
@@ -0,0 +1,167 @@
+dnl ------------------------------------------------------------------------
+dnl Try to find if FAM is installed
+dnl ------------------------------------------------------------------------
+dnl
+kde_have_fam=yes
+AC_ARG_ENABLE(libfam,
+ AC_HELP_STRING([--disable-libfam],[don't search for libfam and do not use it]),
+[ kde_have_fam=$enableval ], [])dnl
+
+dnl Bloody libfam is C++ and certainly compiled by GNU C++. This means,
+dnl we can't use it, when compiling with another C++ compiler, as the
+dnl runtime systems would conflict (e.g. in KAI C++) (matz)
+test "$GXX" = yes || kde_have_fam=no
+
+if test "$kde_have_fam" = "yes" ; then
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ KDE_CHECK_LIB(fam, FAMOpen, [LIBFAM="-lfam"; kde_have_fam=yes],kde_have_fam=no)
+ if test $kde_have_fam = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_FAM, 1, [Define if your system has libfam])
+ fi
+ AC_LANG_RESTORE
+fi
+AC_SUBST(LIBFAM)
+dnl ------------------------------------------------------------------------
+dnl Try to find if LIBZ is installed
+dnl ------------------------------------------------------------------------
+dnl
+
+AC_FIND_ZLIB
+
+AC_CHECK_HEADERS(sys/mnttab.h sys/mntent.h mntent.h fstab.h sys/ucred.h sys/mount.h)
+AC_CHECK_FUNCS(setmntent getmntinfo)
+
+AH_VERBATIM(_GETMNTINFO, [
+#ifdef __osf__
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <sys/mount.h>
+int getmntinfo(struct statfs **mntbufp, int flags);
+#include <sys/fs_types.h> /* for mnt_names[] */
+#ifdef __cplusplus
+}
+#endif
+#endif
+])
+
+dnl ------------------------------------------------------------------------
+dnl Try to find if libvolmgt is installed (Solaris)
+dnl ------------------------------------------------------------------------
+kde_have_volmgt=yes
+AC_CHECK_LIB(volmgt, volmgt_running, [LIBVOLMGT=-lvolmgt], kde_have_volmgt=no)
+AC_SUBST(LIBVOLMGT)
+if test "$kde_have_volmgt" = "yes"; then
+ AC_DEFINE_UNQUOTED(HAVE_VOLMGT, 1, [Define, to enable volume management (Solaris 2.x), if you have -lvolmgt])
+fi
+
+dnl ------------------------------------------------------------------------
+dnl Try to find if we have Linux Dir Notification
+dnl ------------------------------------------------------------------------
+
+AC_ARG_ENABLE(dnotify,
+AC_HELP_STRING([--enable-dnotify],[enable use of Linux directory notifications]),
+[ kde_enable_dnotify=$enableval ], [])dnl
+
+AC_CHECK_GNU_EXTENSIONS
+
+if test "x$kde_enable_dnotify" = "xyes"; then
+ AC_MSG_CHECKING([for Linux Directory Notification])
+ AC_CACHE_VAL(kde_cv_have_dnotify,
+ [
+ kde_cv_have_dnotify=no
+ AC_LANG_SAVE
+ AC_LANG_C
+
+ AC_TRY_COMPILE(
+ [
+#include <fcntl.h>
+#include <signal.h>
+ ],
+ [
+#ifndef F_NOTIFY
+#error no dir notification
+#endif
+ int fd;
+ siginfo_t *t = 0;
+
+ fcntl(fd, F_SETSIG, SIGRTMIN);
+ fcntl(fd, F_NOTIFY, DN_DELETE|DN_CREATE|DN_MULTISHOT);
+
+ ],kde_cv_have_dnotify=yes)
+
+ AC_LANG_RESTORE
+ ])
+
+ if test "$kde_cv_have_dnotify" = "yes" ; then
+ AC_DEFINE_UNQUOTED(HAVE_DNOTIFY, 1, [Define if your system has Linux Directory Notification])
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+dnl ------------------------------------------------------------------------
+dnl Try to find if we have Linux Inode based Dir Notification
+dnl ------------------------------------------------------------------------
+
+AC_ARG_ENABLE(inotify,
+AC_HELP_STRING([--disable-inotify],[enable use of Linux inode notifications]),
+[ kde_enable_inotify=$enableval ], [kde_enable_inotify=yes])dnl
+
+AC_CHECK_GNU_EXTENSIONS
+
+if test "x$kde_enable_inotify" = "xyes"; then
+ AC_MSG_CHECKING([for Linux Inotify Notification])
+ AC_CACHE_VAL(kde_cv_have_inotify,
+ [
+ kde_cv_have_inotify=no
+ AC_LANG_SAVE
+ AC_LANG_C
+
+ AC_TRY_COMPILE(
+ [
+#include <asm/unistd.h>
+#define _S390_BITOPS_H
+#include <linux/inotify.h>
+ ],
+ [
+#ifndef IN_ALL_EVENTS
+#error no inotify notification
+#endif
+
+ ],kde_cv_have_inotify=yes,kde_cv_have_inotify=no)
+
+ AC_LANG_RESTORE
+ ])
+
+ AC_CACHE_VAL(kde_cv_have_sys_inotify,
+ [
+ kde_cv_have_sys_inotify=no
+ AC_LANG_SAVE
+ AC_LANG_C
+
+ AC_TRY_COMPILE(
+ [
+#include <sys/inotify.h>
+ ],
+ [
+#ifndef IN_ALL_EVENTS
+#error no inotify notification
+#endif
+ ],kde_cv_have_sys_inotify=yes,kde_cv_have_sys_inotify=no)
+
+ AC_LANG_RESTORE
+ ])
+
+ if test "$kde_cv_have_inotify" = "yes" -o "$kde_cv_have_sys_inotify" = "yes"; then
+ AC_DEFINE_UNQUOTED(HAVE_INOTIFY, 1, [Define if your system has Linux Inode Notification])
+ if test "$kde_cv_have_sys_inotify" = "yes"; then
+ AC_DEFINE_UNQUOTED(HAVE_SYS_INOTIFY, 1, [Define if your system has glibc support for inotify])
+ fi
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
diff --git a/tdeio/tdeio/connection.cpp b/tdeio/tdeio/connection.cpp
new file mode 100644
index 000000000..cbe737693
--- /dev/null
+++ b/tdeio/tdeio/connection.cpp
@@ -0,0 +1,273 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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.
+*/
+
+// $Id$
+
+#include <config.h>
+
+#include <kde_file.h>
+#include <ksock.h>
+#include <tqtimer.h>
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tdeio/connection.h"
+
+#include <kdebug.h>
+#include <tqsocketnotifier.h>
+
+using namespace TDEIO;
+
+Connection::Connection()
+{
+ f_out = 0;
+ fd_in = -1;
+ socket = 0;
+ notifier = 0;
+ receiver = 0;
+ member = 0;
+ m_suspended = false;
+ tasks.setAutoDelete(true);
+}
+
+Connection::~Connection()
+{
+ close();
+}
+
+void Connection::suspend()
+{
+ m_suspended = true;
+ if (notifier)
+ notifier->setEnabled(false);
+}
+
+void Connection::resume()
+{
+ m_suspended = false;
+ if (notifier)
+ notifier->setEnabled(true);
+}
+
+void Connection::close()
+{
+ delete notifier;
+ notifier = 0;
+ delete socket;
+ socket = 0;
+
+ // TDESocket has already closed the file descriptor, but we need to
+ // close the file-stream as well otherwise we leak memory.
+ // As a result we close the file descriptor twice, but that should
+ // be harmless
+ // KDE4: fix this
+ if (f_out)
+ fclose(f_out);
+ f_out = 0;
+ fd_in = -1;
+ tasks.clear();
+}
+
+void Connection::send(int cmd, const TQByteArray& data)
+{
+ if (!inited() || tasks.count() > 0) {
+ Task *task = new Task();
+ task->cmd = cmd;
+ task->data = data;
+ tasks.append(task);
+ } else {
+ sendnow( cmd, data );
+ }
+}
+
+void Connection::dequeue()
+{
+ if (!inited())
+ return;
+
+ while (tasks.count())
+ {
+ tasks.first();
+ Task *task = tasks.take();
+ sendnow( task->cmd, task->data );
+ delete task;
+ }
+}
+
+void Connection::init(TDESocket *sock)
+{
+ delete notifier;
+ notifier = 0;
+#ifdef Q_OS_UNIX //TODO: not yet available on WIN32
+ delete socket;
+ socket = sock;
+ fd_in = socket->socket();
+ f_out = KDE_fdopen( socket->socket(), "wb" );
+#endif
+ if (receiver && ( fd_in != -1 )) {
+ notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read);
+ if ( m_suspended ) {
+ suspend();
+ }
+ TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member);
+ }
+ dequeue();
+}
+
+void Connection::init(int _fd_in, int fd_out)
+{
+ delete notifier;
+ notifier = 0;
+ fd_in = _fd_in;
+ f_out = KDE_fdopen( fd_out, "wb" );
+ if (receiver && ( fd_in != -1 )) {
+ notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read);
+ if ( m_suspended ) {
+ suspend();
+ }
+ TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member);
+ }
+ dequeue();
+}
+
+
+void Connection::connect(TQObject *_receiver, const char *_member)
+{
+ receiver = _receiver;
+ member = _member;
+ delete notifier;
+ notifier = 0;
+ if (receiver && (fd_in != -1 )) {
+ notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read);
+ if ( m_suspended )
+ suspend();
+ TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member);
+ }
+}
+
+bool Connection::sendnow( int _cmd, const TQByteArray &data )
+{
+ if (f_out == 0) {
+ return false;
+ }
+
+ if (data.size() > 0xffffff)
+ return false;
+
+ static char buffer[ 64 ];
+ sprintf( buffer, "%6x_%2x_", data.size(), _cmd );
+
+ size_t n = fwrite( buffer, 1, 10, f_out );
+
+ if ( n != 10 ) {
+ kdError(7017) << "Could not send header" << endl;
+ return false;
+ }
+
+ n = fwrite( data.data(), 1, data.size(), f_out );
+
+ if ( n != data.size() ) {
+ kdError(7017) << "Could not write data" << endl;
+ return false;
+ }
+
+ if (fflush( f_out )) {
+ kdError(7017) << "Could not write data" << endl;
+ return false;
+ }
+
+ return true;
+}
+
+int Connection::read( int* _cmd, TQByteArray &data )
+{
+ if (fd_in == -1 ) {
+ kdError(7017) << "read: not yet inited" << endl;
+ return -1;
+ }
+
+ static char buffer[ 10 ];
+
+ again1:
+ ssize_t n = ::read( fd_in, buffer, 10);
+ if ( n == -1 && errno == EINTR )
+ goto again1;
+
+ if ( n == -1) {
+ kdError(7017) << "Header read failed, errno=" << errno << endl;
+ }
+
+ if ( n != 10 ) {
+ if ( n ) // 0 indicates end of file
+ kdError(7017) << "Header has invalid size (" << n << ")" << endl;
+ return -1;
+ }
+
+ buffer[ 6 ] = 0;
+ buffer[ 9 ] = 0;
+
+ char *p = buffer;
+ while( *p == ' ' ) p++;
+ long int len = strtol( p, 0L, 16 );
+
+ p = buffer + 7;
+ while( *p == ' ' ) p++;
+ long int cmd = strtol( p, 0L, 16 );
+
+ data.resize( len );
+
+ if ( len > 0L ) {
+ size_t bytesToGo = len;
+ size_t bytesRead = 0;
+ do {
+ n = ::read(fd_in, data.data()+bytesRead, bytesToGo);
+ if (n == -1) {
+ if (errno == EINTR)
+ continue;
+
+ kdError(7017) << "Data read failed, errno=" << errno << endl;
+ return -1;
+ }
+ if ( !n ) { // 0 indicates end of file
+ kdError(7017) << "Connection ended unexpectedly (" << n << "/" << bytesToGo << ")" << endl;
+ return -1;
+ }
+
+ bytesRead += n;
+ bytesToGo -= n;
+ }
+ while(bytesToGo);
+ }
+
+ *_cmd = cmd;
+ return len;
+}
+
+#include "connection.moc"
diff --git a/tdeio/tdeio/connection.h b/tdeio/tdeio/connection.h
new file mode 100644
index 000000000..fb0b50e15
--- /dev/null
+++ b/tdeio/tdeio/connection.h
@@ -0,0 +1,158 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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 __connection_h__
+#define __connection_h__
+
+#include <tdelibs_export.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <tqptrlist.h>
+#include <tqobject.h>
+
+class TDESocket;
+class TQSocketNotifier;
+
+namespace TDEIO {
+
+ struct TDEIO_EXPORT Task {
+ int cmd;
+ TQByteArray data;
+ };
+
+ /**
+ * This class provides a simple means for IPC between two applications
+ * via a pipe.
+ * It handles a queue of commands to be sent which makes it possible to
+ * queue data before an actual connection has been established.
+ */
+ class TDEIO_EXPORT Connection : public TQObject
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Creates a new connection.
+ * @see init()
+ */
+ Connection();
+ virtual ~Connection();
+
+ /**
+ * Initialize this connection to use the given socket.
+ * @param sock the socket to use
+ * @see inited()
+ */
+ void init(TDESocket *sock);
+ /**
+ * Initialize the connection to use the given file
+ * descriptors.
+ * @param fd_in the input file descriptor to use
+ * @param fd_out the output file descriptor to use
+ * @see inited()
+ */
+ void init(int fd_in, int fd_out); // Used by KDENOX
+ void connect(TQObject *receiver = 0, const char *member = 0);
+ /// Closes the connection.
+ void close();
+
+ /**
+ * Returns the input file descriptor.
+ * @return the input file descriptor
+ */
+ int fd_from() const { return fd_in; }
+ /**
+ * Returns the output file descriptor.
+ * @return the output file descriptor
+ */
+ int fd_to() const { return fileno( f_out ); }
+
+ /**
+ * Checks whether the connection has been initialized.
+ * @return true if the initialized
+ * @see init()
+ */
+ bool inited() const { return (fd_in != -1) && (f_out != 0); }
+
+ /**
+ * Sends/queues the given command to be sent.
+ * @param cmd the command to set
+ * @param arr the bytes to send
+ */
+ void send(int cmd, const TQByteArray &arr = TQByteArray());
+
+ /**
+ * Sends the given command immediately.
+ * @param _cmd the command to set
+ * @param data the bytes to send
+ * @return true if successful, false otherwise
+ */
+ bool sendnow( int _cmd, const TQByteArray &data );
+
+ /**
+ * Receive data.
+ *
+ * @param _cmd the received command will be written here
+ * @param data the received data will be written here
+ * @return >=0 indicates the received data size upon success
+ * -1 indicates error
+ */
+ int read( int* _cmd, TQByteArray &data );
+
+ /**
+ * Don't handle incoming data until resumed.
+ */
+ void suspend();
+
+ /**
+ * Resume handling of incoming data.
+ */
+ void resume();
+
+ /**
+ * Returns status of connection.
+ * @return true if suspended, false otherwise
+ */
+ bool suspended() const { return m_suspended; }
+
+ protected slots:
+ void dequeue();
+
+ protected:
+
+
+ private:
+ int fd_in;
+ FILE *f_out;
+ TDESocket *socket;
+ TQSocketNotifier *notifier;
+ TQObject *receiver;
+ const char *member;
+ TQPtrList<Task> tasks;
+ bool m_suspended;
+ private:
+ class ConnectionPrivate* d;
+ };
+
+}
+
+#endif
diff --git a/tdeio/tdeio/dataprotocol.cpp b/tdeio/tdeio/dataprotocol.cpp
new file mode 100644
index 000000000..acc7b28e9
--- /dev/null
+++ b/tdeio/tdeio/dataprotocol.cpp
@@ -0,0 +1,339 @@
+// dataprotocol.cpp
+// ==================
+//
+// Implementation of the data protocol (rfc 2397)
+//
+// Author: Leo Savernik
+// Email: l.savernik@aon.at
+// (C) 2002, 2003 by Leo Savernik
+// Created: Sam Dez 28 14:11:18 CET 2002
+
+/***************************************************************************
+ * *
+ * 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; version 2. *
+ * *
+ ***************************************************************************/
+
+#include "dataprotocol.h"
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kurl.h>
+#include <tdeio/global.h>
+
+#include <tqcstring.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqtextcodec.h>
+
+#ifdef DATAKIOSLAVE
+# include <kinstance.h>
+# include <stdlib.h>
+#endif
+#ifdef TESTKIO
+# include <iostream.h>
+#endif
+
+#if !defined(DATAKIOSLAVE) && !defined(TESTKIO)
+# define DISPATCH(f) dispatch_##f
+#else
+# define DISPATCH(f) f
+#endif
+
+using namespace TDEIO;
+#ifdef DATAKIOSLAVE
+extern "C" {
+
+ int kdemain( int argc, char **argv ) {
+ TDEInstance instance( "kio_data" );
+
+ kdDebug(7101) << "*** Starting kio_data " << endl;
+
+ if (argc != 4) {
+ kdDebug(7101) << "Usage: kio_data protocol domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+
+ DataProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug(7101) << "*** kio_data Done" << endl;
+ return 0;
+ }
+}
+#endif
+
+/** structure containing header information */
+struct DataHeader {
+ TQString mime_type; // mime type of content (lowercase)
+ MetaData attributes; // attribute/value pairs (attribute lowercase,
+ // value unchanged)
+ bool is_base64; // true if data is base64 encoded
+ TQString url; // reference to decoded url
+ int data_offset; // zero-indexed position within url
+ // where the real data begins. May point beyond
+ // the end to indicate that there is no data
+ TQString *charset; // shortcut to charset (it always exists)
+};
+
+// constant string data
+const TQChar text_plain_str[] = { 't','e','x','t','/','p','l','a','i','n' };
+const TQChar charset_str[] = { 'c','h','a','r','s','e','t' };
+const TQChar us_ascii_str[] = { 'u','s','-','a','s','c','i','i' };
+const TQChar base64_str[] = { 'b','a','s','e','6','4' };
+
+/** returns the position of the first occurrence of any of the given characters
+ * @p c1 to @p c3 or buf.length() if none is contained.
+ * @param buf buffer where to look for c
+ * @param begin zero-indexed starting position
+ * @param c1 character to find
+ * @param c2 alternative character to find or '\0' to ignore
+ * @param c3 alternative character to find or '\0' to ignore
+ */
+static int find(const TQString &buf, int begin, TQChar c1, TQChar c2 = '\0',
+ TQChar c3 = '\0') {
+ int pos = begin;
+ int size = (int)buf.length();
+ while (pos < size) {
+ TQChar ch = buf[pos];
+ if (ch == c1
+ || (c2 != '\0' && ch == c2)
+ || (c3 != '\0' && ch == c3))
+ break;
+ pos++;
+ }/*wend*/
+ return pos;
+}
+
+/** extracts the string between the current position @p pos and the first
+ * occurrence of either @p c1 to @p c3 exclusively and updates @p pos
+ * to point at the found delimiter or at the end of the buffer if
+ * neither character occurred.
+ * @param buf buffer where to look for
+ * @param pos zero-indexed position within buffer
+ * @param c1 character to find
+ * @param c2 alternative character to find or 0 to ignore
+ * @param c3 alternative character to find or 0 to ignore
+ */
+inline TQString extract(const TQString &buf, int &pos, TQChar c1,
+ TQChar c2 = '\0', TQChar c3 = '\0') {
+ int oldpos = pos;
+ pos = find(buf,oldpos,c1,c2,c3);
+ return TQString(buf.unicode() + oldpos, pos - oldpos);
+}
+
+/** ignores all whitespaces
+ * @param buf buffer to operate on
+ * @param pos position to shift to first non-whitespace character
+ * Upon return @p pos will either point to the first non-whitespace
+ * character or to the end of the buffer.
+ */
+inline void ignoreWS(const TQString &buf, int &pos) {
+ int size = (int)buf.length();
+ TQChar ch = buf[pos];
+ while (pos < size && (ch == ' ' || ch == '\t' || ch == '\n'
+ || ch == '\r'))
+ ch = buf[++pos];
+}
+
+/** parses a quoted string as per rfc 822.
+ *
+ * If trailing quote is missing, the whole rest of the buffer is returned.
+ * @param buf buffer to operate on
+ * @param pos position pointing to the leading quote
+ * @return the extracted string. @p pos will be updated to point to the
+ * character following the trailing quote.
+ */
+static TQString parseQuotedString(const TQString &buf, int &pos) {
+ int size = (int)buf.length();
+ TQString res;
+ pos++; // jump over leading quote
+ bool escaped = false; // if true means next character is literal
+ bool parsing = true; // true as long as end quote not found
+ while (parsing && pos < size) {
+ TQChar ch = buf[pos++];
+ if (escaped) {
+ res += ch;
+ escaped = false;
+ } else {
+ switch (ch) {
+ case '"': parsing = false; break;
+ case '\\': escaped = true; break;
+ default: res += ch; break;
+ }/*end switch*/
+ }/*end if*/
+ }/*wend*/
+ return res;
+}
+
+/** parses the header of a data url
+ * @param url the data url
+ * @param header_info fills the given DataHeader structure with the header
+ * information
+ */
+static void parseDataHeader(const KURL &url, DataHeader &header_info) {
+ TQConstString text_plain(text_plain_str,sizeof text_plain_str/sizeof text_plain_str[0]);
+ TQConstString charset(charset_str,sizeof charset_str/sizeof charset_str[0]);
+ TQConstString us_ascii(us_ascii_str,sizeof us_ascii_str/sizeof us_ascii_str[0]);
+ TQConstString base64(base64_str,sizeof base64_str/sizeof base64_str[0]);
+ // initialize header info members
+ header_info.mime_type = text_plain.string();
+ header_info.charset = &header_info.attributes.insert(
+ charset.string(),us_ascii.string())
+ .data();
+ header_info.is_base64 = false;
+
+ // decode url and save it
+ TQString &raw_url = header_info.url = TQString::fromLatin1("data:") + url.path();
+ int raw_url_len = (int)raw_url.length();
+
+ // jump over scheme part (must be "data:", we don't even check that)
+ header_info.data_offset = raw_url.find(':');
+ header_info.data_offset++; // jump over colon or to begin if scheme was missing
+
+ // read mime type
+ if (header_info.data_offset >= raw_url_len) return;
+ TQString mime_type = extract(raw_url,header_info.data_offset,';',',')
+ .stripWhiteSpace();
+ if (!mime_type.isEmpty()) header_info.mime_type = mime_type;
+
+ if (header_info.data_offset >= raw_url_len) return;
+ // jump over delimiter token and return if data reached
+ if (raw_url[header_info.data_offset++] == ',') return;
+
+ // read all attributes and store them
+ bool data_begin_reached = false;
+ while (!data_begin_reached && header_info.data_offset < raw_url_len) {
+ // read attribute
+ TQString attribute = extract(raw_url,header_info.data_offset,'=',';',',')
+ .stripWhiteSpace();
+ if (header_info.data_offset >= raw_url_len
+ || raw_url[header_info.data_offset] != '=') {
+ // no assigment, must be base64 option
+ if (attribute == base64.string())
+ header_info.is_base64 = true;
+ } else {
+ header_info.data_offset++; // jump over '=' token
+
+ // read value
+ ignoreWS(raw_url,header_info.data_offset);
+ if (header_info.data_offset >= raw_url_len) return;
+
+ TQString value;
+ if (raw_url[header_info.data_offset] == '"') {
+ value = parseQuotedString(raw_url,header_info.data_offset);
+ ignoreWS(raw_url,header_info.data_offset);
+ } else
+ value = extract(raw_url,header_info.data_offset,';',',')
+ .stripWhiteSpace();
+
+ // add attribute to map
+ header_info.attributes[attribute.lower()] = value;
+
+ }/*end if*/
+ if (header_info.data_offset < raw_url_len
+ && raw_url[header_info.data_offset] == ',')
+ data_begin_reached = true;
+ header_info.data_offset++; // jump over separator token
+ }/*wend*/
+}
+
+#ifdef DATAKIOSLAVE
+DataProtocol::DataProtocol(const TQCString &pool_socket, const TQCString &app_socket)
+ : SlaveBase("kio_data", pool_socket, app_socket) {
+#else
+DataProtocol::DataProtocol() {
+#endif
+ kdDebug() << "DataProtocol::DataProtocol()" << endl;
+}
+
+/* --------------------------------------------------------------------- */
+
+DataProtocol::~DataProtocol() {
+ kdDebug() << "DataProtocol::~DataProtocol()" << endl;
+}
+
+/* --------------------------------------------------------------------- */
+
+void DataProtocol::get(const KURL& url) {
+ ref();
+ //kdDebug() << "===============================================================================================================================================================================" << endl;
+ kdDebug() << "kio_data@"<<this<<"::get(const KURL& url)" << endl ;
+
+ DataHeader hdr;
+ parseDataHeader(url,hdr);
+
+ int size = (int)hdr.url.length();
+ int data_ofs = QMIN(hdr.data_offset,size);
+ // FIXME: string is copied, would be nice if we could have a reference only
+ TQString url_data = hdr.url.mid(data_ofs);
+ TQCString outData;
+
+#ifdef TESTKIO
+// cout << "current charset: \"" << *hdr.charset << "\"" << endl;
+#endif
+ if (hdr.is_base64) {
+ // base64 stuff is expected to contain the correct charset, so we just
+ // decode it and pass it to the receiver
+ KCodecs::base64Decode(url_data.local8Bit(),outData);
+ } else {
+ // FIXME: This is all flawed, must be reworked thoroughly
+ // non encoded data must be converted to the given charset
+ TQTextCodec *codec = TQTextCodec::codecForName(hdr.charset->latin1());
+ if (codec != 0) {
+ outData = codec->fromUnicode(url_data);
+ } else {
+ // if there is no approprate codec, just use local encoding. This
+ // should work for >90% of all cases.
+ outData = url_data.local8Bit();
+ }/*end if*/
+ }/*end if*/
+
+ //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+ //kdDebug() << "emit mimeType@"<<this << endl ;
+ mimeType(hdr.mime_type);
+ //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+ //kdDebug() << "emit totalSize@"<<this << endl ;
+ totalSize(outData.size());
+
+ //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+ //kdDebug() << "emit setMetaData@"<<this << endl ;
+#if defined(TESTKIO) || defined(DATAKIOSLAVE)
+ MetaData::ConstIterator it;
+ for (it = hdr.attributes.begin(); it != hdr.attributes.end(); ++it) {
+ setMetaData(it.key(),it.data());
+ }/*next it*/
+#else
+ setAllMetaData(hdr.attributes);
+#endif
+
+ //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+ //kdDebug() << "emit sendMetaData@"<<this << endl ;
+ sendMetaData();
+ //kdDebug() << "^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C" << endl;
+// kdDebug() << "(1) queue size " << dispatchQueue.size() << endl;
+ // empiric studies have shown that this shouldn't be queued & dispatched
+ /*DISPATCH*/(data(outData));
+// kdDebug() << "(2) queue size " << dispatchQueue.size() << endl;
+ DISPATCH(data(TQByteArray()));
+// kdDebug() << "(3) queue size " << dispatchQueue.size() << endl;
+ DISPATCH(finished());
+// kdDebug() << "(4) queue size " << dispatchQueue.size() << endl;
+ deref();
+}
+
+/* --------------------------------------------------------------------- */
+
+void DataProtocol::mimetype(const KURL &url) {
+ ref();
+ DataHeader hdr;
+ parseDataHeader(url,hdr);
+ mimeType(hdr.mime_type);
+ finished();
+ deref();
+}
+
+/* --------------------------------------------------------------------- */
+
diff --git a/tdeio/tdeio/dataprotocol.h b/tdeio/tdeio/dataprotocol.h
new file mode 100644
index 000000000..ed9bfc325
--- /dev/null
+++ b/tdeio/tdeio/dataprotocol.h
@@ -0,0 +1,71 @@
+// dataprotocol.h
+// ================
+//
+// Interface of the KDE data protocol core operations
+//
+// Author: Leo Savernik
+// Email: l.savernik@aon.at
+// (C) 2002 by Leo Savernik
+// Created: Sam Dez 28 14:11:18 CET 2002
+
+/***************************************************************************
+ * *
+ * 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; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef __dataprotocol_h__
+#define __dataprotocol_h__
+
+// dataprotocol.* interprets the following defines
+// DATAKIOSLAVE: define if you want to compile this into a stand-alone
+// tdeioslave
+// TESTKIO: define for test-driving
+// Both defines are mutually exclusive. Defining none of them compiles
+// DataProtocol for internal usage within libtdeiocore.
+
+class TQString;
+class TQCString;
+
+class KURL;
+
+#if defined(DATAKIOSLAVE)
+# include <tdeio/slavebase.h>
+#elif !defined(TESTKIO)
+# include "tdeio/dataslave.h"
+#endif
+
+namespace TDEIO {
+
+/** This tdeioslave provides support of data urls as specified by rfc 2397
+ * @see http://www.ietf.org/rfc/rfc2397.txt
+ * @author Leo Savernik
+ */
+#if defined(DATAKIOSLAVE)
+class DataProtocol : public TDEIO::SlaveBase {
+#elif defined(TESTKIO)
+class DataProtocol : public TestSlave {
+#else
+class DataProtocol : public DataSlave {
+#endif
+
+public:
+#if defined(DATAKIOSLAVE)
+ DataProtocol(const TQCString &pool_socket, const TQCString &app_socket);
+#else
+ DataProtocol();
+#endif
+ virtual ~DataProtocol();
+ virtual void mimetype(const KURL &url);
+ virtual void get(const KURL &url);
+#if defined(TESTKIO)
+ void ref() {}
+ void deref() {}
+#endif
+};
+
+}/*end namespace*/
+
+#endif
diff --git a/tdeio/tdeio/dataslave.cpp b/tdeio/tdeio/dataslave.cpp
new file mode 100644
index 000000000..528368ba5
--- /dev/null
+++ b/tdeio/tdeio/dataslave.cpp
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2003 Leo Savernik <l.savernik@aon.at>
+ * Derived from slave.cpp
+ *
+ * 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 <config.h>
+
+#include "dataslave.h"
+#include "dataprotocol.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <tqtimer.h>
+
+using namespace TDEIO;
+
+#define KIO_DATA_POLL_INTERVAL 0
+
+// don't forget to sync DISPATCH_DECL in dataslave.h
+#define DISPATCH_IMPL(type) \
+ void DataSlave::dispatch_##type() { \
+ if (_suspended) { \
+ QueueStruct q(Queue_##type); \
+ dispatchQueue.push_back(q); \
+ if (!timer->isActive()) timer->start(KIO_DATA_POLL_INTERVAL); \
+ } else \
+ type(); \
+ }
+
+// don't forget to sync DISPATCH_DECL1 in dataslave.h
+#define DISPATCH_IMPL1(type, paramtype, paramname) \
+ void DataSlave::dispatch_##type(paramtype paramname) { \
+ if (_suspended) { \
+ QueueStruct q(Queue_##type); \
+ q.paramname = paramname; \
+ dispatchQueue.push_back(q); \
+ if (!timer->isActive()) timer->start(KIO_DATA_POLL_INTERVAL); \
+ } else \
+ type(paramname); \
+ }
+
+
+DataSlave::DataSlave() :
+ Slave(true, 0, "data", TQString::null)
+{
+ //kdDebug() << this << k_funcinfo << endl;
+ _suspended = false;
+ timer = new TQTimer(this);
+ connect(timer, TQT_SIGNAL(timeout()), TQT_SLOT(dispatchNext()));
+}
+
+DataSlave::~DataSlave() {
+ //kdDebug() << this << k_funcinfo << endl;
+}
+
+void DataSlave::hold(const KURL &/*url*/) {
+ // ignored
+}
+
+void DataSlave::suspend() {
+ _suspended = true;
+ //kdDebug() << this << k_funcinfo << endl;
+ timer->stop();
+}
+
+void DataSlave::resume() {
+ _suspended = false;
+ //kdDebug() << this << k_funcinfo << endl;
+ // aarrrgh! This makes the once hyper fast and efficient data protocol
+ // implementation slow as molasses. But it wouldn't work otherwise,
+ // and I don't want to start messing around with threads
+ timer->start(KIO_DATA_POLL_INTERVAL);
+}
+
+// finished is a special case. If we emit it right away, then
+// TransferJob::start can delete the job even before the end of the method
+void DataSlave::dispatch_finished() {
+ QueueStruct q(Queue_finished);
+ dispatchQueue.push_back(q);
+ if (!timer->isActive()) timer->start(KIO_DATA_POLL_INTERVAL);
+}
+
+void DataSlave::dispatchNext() {
+ if (dispatchQueue.empty()) {
+ timer->stop();
+ return;
+ }
+
+ const QueueStruct &q = dispatchQueue.front();
+ //kdDebug() << this << k_funcinfo << "dispatching " << q.type << " " << dispatchQueue.size() << " left" << endl;
+ switch (q.type) {
+ case Queue_mimeType: mimeType(q.s); break;
+ case Queue_totalSize: totalSize(q.size); break;
+ case Queue_sendMetaData: sendMetaData(); break;
+ case Queue_data: data(q.ba); break;
+ case Queue_finished: finished(); break;
+ }/*end switch*/
+
+ dispatchQueue.pop_front();
+}
+
+void DataSlave::send(int cmd, const TQByteArray &arr) {
+ TQDataStream stream(arr, IO_ReadOnly);
+
+ KURL url;
+
+ switch (cmd) {
+ case CMD_GET: {
+ stream >> url;
+ get(url);
+ break;
+ }
+ case CMD_MIMETYPE: {
+ stream >> url;
+ mimetype(url);
+ break;
+ }
+ // ignore these (must not emit error, otherwise SIGSEGV occurs)
+ case CMD_META_DATA:
+ case CMD_SUBURL:
+ break;
+ default:
+ error(ERR_UNSUPPORTED_ACTION,
+ unsupportedActionErrorString(TQString::fromLatin1("data"),cmd));
+ }/*end switch*/
+}
+
+bool DataSlave::suspended() {
+ return _suspended;
+}
+
+void DataSlave::setHost(const TQString &/*host*/, int /*port*/,
+ const TQString &/*user*/, const TQString &/*passwd*/) {
+ // irrelevant -> will be ignored
+}
+
+void DataSlave::setConfig(const MetaData &/*config*/) {
+ // FIXME: decide to handle this directly or not at all
+#if 0
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ stream << config;
+ slaveconn.send( CMD_CONFIG, data );
+#endif
+}
+
+void DataSlave::setAllMetaData(const MetaData &md) {
+ meta_data = md;
+}
+
+void DataSlave::sendMetaData() {
+ emit metaData(meta_data);
+}
+
+void DataSlave::virtual_hook( int id, void* data ) {
+ switch (id) {
+ case VIRTUAL_SUSPEND: suspend(); return;
+ case VIRTUAL_RESUME: resume(); return;
+ case VIRTUAL_SEND: {
+ SendParams *params = reinterpret_cast<SendParams *>(data);
+ send(params->cmd, *params->arr);
+ return;
+ }
+ case VIRTUAL_HOLD: {
+ HoldParams *params = reinterpret_cast<HoldParams *>(data);
+ hold(*params->url);
+ return;
+ }
+ case VIRTUAL_SUSPENDED: {
+ SuspendedParams *params = reinterpret_cast<SuspendedParams *>(data);
+ params->retval = suspended();
+ return;
+ }
+ case VIRTUAL_SET_HOST: {
+ SetHostParams *params = reinterpret_cast<SetHostParams *>(data);
+ setHost(*params->host,params->port,*params->user,*params->passwd);
+ return;
+ }
+ case VIRTUAL_SET_CONFIG: {
+ SetConfigParams *params = reinterpret_cast<SetConfigParams *>(data);
+ setConfig(*params->config);
+ return;
+ }
+ default:
+ TDEIO::Slave::virtual_hook( id, data );
+ }
+}
+
+DISPATCH_IMPL1(mimeType, const TQString &, s)
+DISPATCH_IMPL1(totalSize, TDEIO::filesize_t, size)
+DISPATCH_IMPL(sendMetaData)
+DISPATCH_IMPL1(data, const TQByteArray &, ba)
+
+#undef DISPATCH_IMPL
+#undef DISPATCH_IMPL1
+
+#include "dataslave.moc"
diff --git a/tdeio/tdeio/dataslave.h b/tdeio/tdeio/dataslave.h
new file mode 100644
index 000000000..40cfef126
--- /dev/null
+++ b/tdeio/tdeio/dataslave.h
@@ -0,0 +1,126 @@
+// -*- c++ -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2003 Leo Savernik <l.savernik@aon.at>
+ * Derived from slave.h
+ *
+ * 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 __KIO_DATASLAVE_H__
+#define __KIO_DATASLAVE_H__
+
+#include <tdeio/global.h>
+#include <tdeio/slave.h>
+
+class TQTimer;
+
+// don't forget to sync DISPATCH_IMPL in dataslave.h
+#define DISPATCH_DECL(type) \
+ void dispatch_##type();
+
+// don't forget to sync DISPATCH_IMPL1 in dataslave.h
+#define DISPATCH_DECL1(type, paramtype, param) \
+ void dispatch_##type(paramtype param);
+
+namespace TDEIO {
+
+ /**
+ * This class provides a high performance implementation for the data
+ * url scheme (rfc2397).
+ *
+ * @internal
+ * Do not use this class in external applications. It is an implementation
+ * detail of KIO and subject to change without notice.
+ * @author Leo Savernik
+ */
+ class DataSlave : public TDEIO::Slave {
+ Q_OBJECT
+ public:
+ DataSlave();
+
+ virtual ~DataSlave();
+
+ virtual void setHost(const TQString &host, int port,
+ const TQString &user, const TQString &passwd);
+ virtual void setConfig(const MetaData &config);
+
+ virtual void suspend();
+ virtual void resume();
+ virtual bool suspended();
+ virtual void send(int cmd, const TQByteArray &data = TQByteArray());
+
+ virtual void hold(const KURL &url);
+
+ // pure virtual methods that are defined by the actual protocol
+ virtual void get(const KURL &url) = 0;
+ virtual void mimetype(const KURL &url) = 0;
+
+ protected:
+ /**
+ * Sets metadata
+ * @internal
+ */
+ void setAllMetaData(const MetaData &);
+ /**
+ * Sends metadata set with setAllMetaData
+ * @internal
+ */
+ void sendMetaData();
+
+ // queueing methods
+ /** identifiers of functions to be queued */
+ enum QueueType { Queue_mimeType = 1, Queue_totalSize,
+ Queue_sendMetaData, Queue_data, Queue_finished };
+ /** structure for queueing. It is very primitive, it doesn't
+ * even try to conserve memory.
+ */
+ struct QueueStruct {
+ QueueType type;
+ TQString s;
+ TDEIO::filesize_t size;
+ TQByteArray ba;
+
+ QueueStruct() {}
+ QueueStruct(QueueType type) : type(type) {}
+ };
+ typedef TQValueList<QueueStruct> DispatchQueue;
+ DispatchQueue dispatchQueue;
+
+ DISPATCH_DECL1(mimeType, const TQString &, s)
+ DISPATCH_DECL1(totalSize, TDEIO::filesize_t, size)
+ DISPATCH_DECL(sendMetaData)
+ DISPATCH_DECL1(data, const TQByteArray &, ba)
+ DISPATCH_DECL(finished)
+
+ protected slots:
+ /** dispatches next queued method. Does nothing if there are no
+ * queued methods.
+ */
+ void dispatchNext();
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ MetaData meta_data;
+ bool _suspended;
+ TQTimer *timer;
+ };
+
+}
+
+#undef DISPATCH_DECL
+#undef DISPATCH_DECL1
+
+#endif /*__KIO_DATASLAVE_H__*/
diff --git a/tdeio/tdeio/davjob.cpp b/tdeio/tdeio/davjob.cpp
new file mode 100644
index 000000000..986e76342
--- /dev/null
+++ b/tdeio/tdeio/davjob.cpp
@@ -0,0 +1,142 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Jan-Pascal van Best <janpascal@vanbest.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 <kurl.h>
+
+#include <tqobject.h>
+#include <tqptrlist.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqguardedptr.h>
+#include <tqdom.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <kdebug.h>
+#include <tdeio/jobclasses.h>
+#include <tdeio/global.h>
+#include <tdeio/http.h>
+#include <tdeio/davjob.h>
+#include <tdeio/job.h>
+#include <tdeio/slaveinterface.h>
+
+#define KIO_ARGS TQByteArray packedArgs; TQDataStream stream( packedArgs, IO_WriteOnly ); stream
+
+using namespace TDEIO;
+
+class DavJob::DavJobPrivate
+{
+public:
+ TQByteArray savedStaticData;
+ TQByteArray str_response; // replaces the TQString previously used in DavJob itself
+};
+
+DavJob::DavJob( const KURL& url, int method, const TQString& request, bool showProgressInfo )
+ : TransferJob( url, TDEIO::CMD_SPECIAL, TQByteArray(), TQByteArray(), showProgressInfo )
+{
+ d = new DavJobPrivate;
+ // We couldn't set the args when calling the parent constructor,
+ // so do it now.
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << (int) 7 << url << method;
+ // Same for static data
+ if ( ! request.isEmpty() && ! request.isNull() ) {
+ staticData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + request.utf8();
+ staticData.truncate( staticData.size() - 1 );
+ d->savedStaticData = staticData.copy();
+ }
+}
+
+void DavJob::slotData( const TQByteArray& data )
+{
+ if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error) {
+ unsigned int oldSize = d->str_response.size();
+ d->str_response.resize( oldSize + data.size() );
+ memcpy( d->str_response.data() + oldSize, data.data(), data.size() );
+ }
+}
+
+void DavJob::slotFinished()
+{
+ // kdDebug(7113) << "DavJob::slotFinished()" << endl;
+ // kdDebug(7113) << d->str_response << endl;
+ if (!m_redirectionURL.isEmpty() && m_redirectionURL.isValid() && (m_command == CMD_SPECIAL)) {
+ TQDataStream istream( m_packedArgs, IO_ReadOnly );
+ int s_cmd, s_method;
+ KURL s_url;
+ istream >> s_cmd;
+ istream >> s_url;
+ istream >> s_method;
+ // PROPFIND
+ if ( (s_cmd == 7) && (s_method == (int)TDEIO::DAV_PROPFIND) ) {
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << (int)7 << m_redirectionURL << (int)TDEIO::DAV_PROPFIND;
+ }
+ } else if ( ! m_response.setContent( d->str_response, true ) ) {
+ // An error occurred parsing the XML response
+ TQDomElement root = m_response.createElementNS( "DAV:", "error-report" );
+ m_response.appendChild( root );
+
+ TQDomElement el = m_response.createElementNS( "DAV:", "offending-response" );
+ TQDomText textnode = m_response.createTextNode( d->str_response );
+ el.appendChild( textnode );
+ root.appendChild( el );
+ delete d; // Should be in virtual destructor
+ d = 0;
+ } else {
+ delete d; // Should be in virtual destructor
+ d = 0;
+ }
+ // kdDebug(7113) << m_response.toString() << endl;
+ TransferJob::slotFinished();
+ if( d ) staticData = d->savedStaticData.copy(); // Need to send DAV request to this host too
+}
+
+/* Convenience methods */
+
+// KDE 4: Make it const TQString &
+DavJob* TDEIO::davPropFind( const KURL& url, const TQDomDocument& properties, TQString depth, bool showProgressInfo )
+{
+ DavJob *job = new DavJob( url, (int) TDEIO::DAV_PROPFIND, properties.toString(), showProgressInfo );
+ job->addMetaData( "davDepth", depth );
+ return job;
+}
+
+
+DavJob* TDEIO::davPropPatch( const KURL& url, const TQDomDocument& properties, bool showProgressInfo )
+{
+ return new DavJob( url, (int) TDEIO::DAV_PROPPATCH, properties.toString(), showProgressInfo );
+}
+
+DavJob* TDEIO::davSearch( const KURL& url, const TQString& nsURI, const TQString& qName, const TQString& query, bool showProgressInfo )
+{
+ TQDomDocument doc;
+ TQDomElement searchrequest = doc.createElementNS( "DAV:", "searchrequest" );
+ TQDomElement searchelement = doc.createElementNS( nsURI, qName );
+ TQDomText text = doc.createTextNode( query );
+ searchelement.appendChild( text );
+ searchrequest.appendChild( searchelement );
+ doc.appendChild( searchrequest );
+ return new DavJob( url, TDEIO::DAV_SEARCH, doc.toString(), showProgressInfo );
+}
+
+#include "davjob.moc"
diff --git a/tdeio/tdeio/davjob.h b/tdeio/tdeio/davjob.h
new file mode 100644
index 000000000..1bbb722d0
--- /dev/null
+++ b/tdeio/tdeio/davjob.h
@@ -0,0 +1,127 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Jan-Pascal van Best <janpascal@vanbest.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 __kio_davjob_h__
+#define __kio_davjob_h__
+
+#include <kurl.h>
+
+#include <tqobject.h>
+#include <tqptrlist.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqguardedptr.h>
+#include <tqdom.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <tdeio/jobclasses.h>
+#include <tdeio/global.h>
+
+class Observer;
+class TQTimer;
+
+namespace TDEIO {
+
+ class Slave;
+ class SlaveInterface;
+
+ /**
+ * The transfer job pumps data into and/or out of a Slave.
+ * Data is sent to the slave on request of the slave ( dataReq).
+ * If data coming from the slave can not be handled, the
+ * reading of data from the slave should be suspended.
+ * @see TDEIO::davPropFind()
+ * @see TDEIO::davPropPatch()
+ * @see TDEIO::davSearch()
+ * @since 3.1
+ */
+ class TDEIO_EXPORT DavJob : public TransferJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Use TDEIO::davPropFind(), TDEIO::davPropPatch() and
+ * TDEIO::davSearch() to create a new DavJob.
+ */
+ DavJob(const KURL& url, int method,
+ const TQString& request, bool showProgressInfo);
+ /**
+ * Returns the response as a TQDomDocument.
+ * @return the response document
+ */
+ TQDomDocument& response() { return m_response; }
+
+ protected slots:
+ virtual void slotFinished();
+ virtual void slotData( const TQByteArray &data);
+
+ protected:
+ bool m_suspended;
+ TransferJob *m_subJob;
+ private:
+ class DavJobPrivate;
+ DavJobPrivate *d;
+ TQString dummy; // kept around for BC reasons
+ TQDomDocument m_response;
+ };
+
+ /**
+ * Creates a new DavJob that issues a PROPFIND command. PROPFIND retrieves
+ * the properties of the resource identified by the given @p url.
+ *
+ * @param url the URL of the resource
+ * @param properties a propfind document that describes the properties that
+ * should be retrieved
+ * @param depth the depth of the request. Can be "0", "1" or "infinity"
+ * @param showProgressInfo true to show progress information
+ * @return the new DavJob
+ */
+ TDEIO_EXPORT DavJob* davPropFind( const KURL& url, const TQDomDocument& properties, TQString depth, bool showProgressInfo=true );
+
+ /**
+ * Creates a new DavJob that issues a PROPPATCH command. PROPPATCH sets
+ * the properties of the resource identified by the given @p url.
+ *
+ * @param url the URL of the resource
+ * @param properties a PROPPACTCH document that describes the properties that
+ * should be modified and its new values
+ * @param showProgressInfo true to show progress information
+ * @return the new DavJob
+ */
+ TDEIO_EXPORT DavJob* davPropPatch( const KURL& url, const TQDomDocument& properties, bool showProgressInfo=true );
+
+ /**
+ * Creates a new DavJob that issues a SEARCH command.
+ *
+ * @param url the URL of the resource
+ * @param nsURI the URI of the search method's qualified name
+ * @param qName the local part of the search method's qualified name
+ * @param query the search string
+ * @param showProgressInfo true to show progress information
+ * @return the new DavJob
+ */
+ TDEIO_EXPORT DavJob* davSearch( const KURL &url, const TQString& nsURI, const TQString& qName, const TQString& query, bool showProgressInfo=true );
+
+}
+
+#endif
+
diff --git a/tdeio/tdeio/defaultprogress.cpp b/tdeio/tdeio/defaultprogress.cpp
new file mode 100644
index 000000000..a4de9c31b
--- /dev/null
+++ b/tdeio/tdeio/defaultprogress.cpp
@@ -0,0 +1,507 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 <tqtimer.h>
+#include <tqlayout.h>
+#include <tqtooltip.h>
+#include <tqdatetime.h>
+#include <tqcheckbox.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kstringhandler.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kprocess.h>
+#include <kpushbutton.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+#include <klineedit.h>
+
+#ifdef Q_WS_X11
+#include <twin.h>
+#endif
+
+#include "jobclasses.h"
+#include "defaultprogress.h"
+
+namespace TDEIO {
+
+class DefaultProgress::DefaultProgressPrivate
+{
+public:
+ bool keepOpenChecked;
+ bool noCaptionYet;
+ KPushButton *cancelClose;
+ KPushButton *openFile;
+ KPushButton *openLocation;
+ TQCheckBox *keepOpen;
+ KURL location;
+ TQTime startTime;
+};
+
+DefaultProgress::DefaultProgress( bool showNow )
+ : ProgressBase( 0 ),
+ m_iTotalSize(0), m_iTotalFiles(0), m_iTotalDirs(0),
+ m_iProcessedSize(0), m_iProcessedDirs(0), m_iProcessedFiles(0)
+{
+ init();
+
+ if ( showNow ) {
+ show();
+ }
+}
+
+DefaultProgress::DefaultProgress( TQWidget* parent, const char* /*name*/ )
+ : ProgressBase( parent ),
+ m_iTotalSize(0), m_iTotalFiles(0), m_iTotalDirs(0),
+ m_iProcessedSize(0), m_iProcessedDirs(0), m_iProcessedFiles(0)
+{
+ init();
+}
+
+bool DefaultProgress::keepOpen() const
+{
+ return d->keepOpenChecked;
+}
+
+void DefaultProgress::init()
+{
+ d = new DefaultProgressPrivate;
+
+#ifdef Q_WS_X11 //FIXME(E): Remove once all the KWin::foo calls have been ported to QWS
+ // Set a useful icon for this window!
+ KWin::setIcons( winId(),
+ TDEGlobal::iconLoader()->loadIcon( "filesave", KIcon::NoGroup, 32 ),
+ TDEGlobal::iconLoader()->loadIcon( "filesave", KIcon::NoGroup, 16 ) );
+#endif
+
+ TQVBoxLayout *topLayout = new TQVBoxLayout( this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+ topLayout->addStrut( 360 ); // makes dlg at least that wide
+
+ TQGridLayout *grid = new TQGridLayout( 2, 3 );
+ topLayout->addLayout(TQT_TQLAYOUT(grid));
+ grid->addColSpacing(1, KDialog::spacingHint());
+ // filenames or action name
+ grid->addWidget(new TQLabel(i18n("Source:"), this), 0, 0);
+
+ sourceEdit = new KLineEdit(this);
+ sourceEdit->setReadOnly(true);
+ sourceEdit->setEnableSqueezedText(true);
+ grid->addWidget(sourceEdit, 0, 2);
+
+ destInvite = new TQLabel(i18n("Destination:"), this);
+ grid->addWidget(destInvite, 1, 0);
+
+ destEdit = new KLineEdit(this);
+ destEdit->setReadOnly (true);
+ destEdit->setEnableSqueezedText(true);
+ grid->addWidget(destEdit, 1, 2);
+
+ m_pProgressBar = new KProgress(this);
+ topLayout->addWidget( m_pProgressBar );
+
+ // processed info
+ TQHBoxLayout *hBox = new TQHBoxLayout();
+ topLayout->addLayout(hBox);
+
+ sizeLabel = new TQLabel(this);
+ hBox->addWidget(sizeLabel);
+
+ resumeLabel = new TQLabel(this);
+ hBox->addWidget(resumeLabel);
+
+ progressLabel = new TQLabel( this );
+/* progressLabel->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding,
+ TQSizePolicy::Preferred ) );*/
+ progressLabel->setAlignment( TQLabel::AlignRight );
+ hBox->addWidget( progressLabel );
+
+ hBox = new TQHBoxLayout();
+ topLayout->addLayout(hBox);
+
+ speedLabel = new TQLabel(this);
+ hBox->addWidget(speedLabel, 1);
+
+ TQFrame *line = new TQFrame( this );
+ line->setFrameShape( TQFrame::HLine );
+ line->setFrameShadow( TQFrame::Sunken );
+ topLayout->addWidget( line );
+
+ d->keepOpen = new TQCheckBox( i18n("&Keep this window open after transfer is complete"), this);
+ connect( d->keepOpen, TQT_SIGNAL( toggled(bool) ), TQT_SLOT( slotKeepOpenToggled(bool) ) );
+ topLayout->addWidget(d->keepOpen);
+ d->keepOpen->hide();
+
+ hBox = new TQHBoxLayout();
+ topLayout->addLayout(hBox);
+
+ d->openFile = new KPushButton( i18n("Open &File"), this );
+ connect( d->openFile, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOpenFile() ) );
+ hBox->addWidget( d->openFile );
+ d->openFile->setEnabled(false);
+ d->openFile->hide();
+
+ d->openLocation = new KPushButton( i18n("Open &Destination"), this );
+ connect( d->openLocation, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOpenLocation() ) );
+ hBox->addWidget( d->openLocation );
+ d->openLocation->hide();
+
+ hBox->addStretch(1);
+
+ d->cancelClose = new KPushButton( KStdGuiItem::cancel(), this );
+ connect( d->cancelClose, TQT_SIGNAL( clicked() ), TQT_SLOT( slotStop() ) );
+ hBox->addWidget( d->cancelClose );
+
+ resize( sizeHint() );
+ setMaximumHeight(sizeHint().height());
+
+ d->keepOpenChecked = false;
+ d->noCaptionYet = true;
+ setCaption(i18n("Progress Dialog")); // show something better than tdeio_uiserver
+}
+
+DefaultProgress::~DefaultProgress()
+{
+ delete d;
+}
+
+void DefaultProgress::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size )
+{
+ // size is measured in bytes
+ if ( m_iTotalSize == size )
+ return;
+ m_iTotalSize = size;
+ if (d->startTime.isNull())
+ d->startTime.start();
+}
+
+
+void DefaultProgress::slotTotalFiles( TDEIO::Job*, unsigned long files )
+{
+ if ( m_iTotalFiles == files )
+ return;
+ m_iTotalFiles = files;
+ showTotals();
+}
+
+
+void DefaultProgress::slotTotalDirs( TDEIO::Job*, unsigned long dirs )
+{
+ if ( m_iTotalDirs == dirs )
+ return;
+ m_iTotalDirs = dirs;
+ showTotals();
+}
+
+void DefaultProgress::showTotals()
+{
+ // Show the totals in the progress label, if we still haven't
+ // processed anything. This is useful when the stat'ing phase
+ // of CopyJob takes a long time (e.g. over networks).
+ if ( m_iProcessedFiles == 0 && m_iProcessedDirs == 0 )
+ {
+ TQString tmps;
+ if ( m_iTotalDirs > 1 )
+ // that we have a singular to translate looks weired but is only logical
+ // xgettext: no-c-format
+ tmps = i18n("%n folder", "%n folders", m_iTotalDirs) + " ";
+ // xgettext: no-c-format
+ tmps += i18n("%n file", "%n files", m_iTotalFiles);
+ progressLabel->setText( tmps );
+ }
+}
+
+//static
+TQString DefaultProgress::makePercentString( unsigned long percent,
+ TDEIO::filesize_t totalSize,
+ unsigned long totalFiles )
+{
+ if ( totalSize )
+ return i18n( "%1 % of %2 " ).arg( TQString::number(percent) , TDEIO::convertSize( totalSize ) );
+ else if ( totalFiles )
+ return i18n( "%1 % of 1 file", "%1 % of %n files", totalFiles ).arg( percent );
+ else
+ return i18n( "%1 %" ).arg( percent );
+}
+
+void DefaultProgress::slotPercent( TDEIO::Job*, unsigned long percent )
+{
+ TQString caption = makePercentString( percent, m_iTotalSize, m_iTotalFiles );
+ m_pProgressBar->setValue( percent );
+ switch(mode) {
+ case Copy:
+ caption.append(i18n(" (Copying)"));
+ break;
+ case Move:
+ caption.append(i18n(" (Moving)"));
+ break;
+ case Delete:
+ caption.append(i18n(" (Deleting)"));
+ break;
+ case Create:
+ caption.append(i18n(" (Creating)"));
+ break;
+ case Done:
+ caption.append(i18n(" (Done)"));
+ break;
+ }
+
+ setCaption( caption );
+ d->noCaptionYet = false;
+}
+
+
+void DefaultProgress::slotInfoMessage( TDEIO::Job*, const TQString & msg )
+{
+ speedLabel->setText( msg );
+ speedLabel->setAlignment( speedLabel->alignment() & ~TQt::WordBreak );
+}
+
+
+void DefaultProgress::slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t bytes ) {
+ if ( m_iProcessedSize == bytes )
+ return;
+ m_iProcessedSize = bytes;
+
+ TQString tmp = i18n( "%1 of %2 complete")
+ .arg( TDEIO::convertSize(bytes) )
+ .arg( TDEIO::convertSize(m_iTotalSize));
+ sizeLabel->setText( tmp );
+}
+
+
+void DefaultProgress::slotProcessedDirs( TDEIO::Job*, unsigned long dirs )
+{
+ if ( m_iProcessedDirs == dirs )
+ return;
+ m_iProcessedDirs = dirs;
+
+ TQString tmps;
+ tmps = i18n("%1 / %n folder", "%1 / %n folders", m_iTotalDirs).arg( m_iProcessedDirs );
+ tmps += " ";
+ tmps += i18n("%1 / %n file", "%1 / %n files", m_iTotalFiles).arg( m_iProcessedFiles );
+ progressLabel->setText( tmps );
+}
+
+
+void DefaultProgress::slotProcessedFiles( TDEIO::Job*, unsigned long files )
+{
+ if ( m_iProcessedFiles == files )
+ return;
+ m_iProcessedFiles = files;
+
+ TQString tmps;
+ if ( m_iTotalDirs > 1 ) {
+ tmps = i18n("%1 / %n folder", "%1 / %n folders", m_iTotalDirs).arg( m_iProcessedDirs );
+ tmps += " ";
+ }
+ tmps += i18n("%1 / %n file", "%1 / %n files", m_iTotalFiles).arg( m_iProcessedFiles );
+ progressLabel->setText( tmps );
+}
+
+
+void DefaultProgress::slotSpeed( TDEIO::Job*, unsigned long speed )
+{
+ if ( speed == 0 ) {
+ speedLabel->setText( i18n( "Stalled") );
+ } else {
+ speedLabel->setText( i18n( "%1/s ( %2 remaining )").arg( TDEIO::convertSize( speed ))
+ .arg( TDEIO::convertSeconds( TDEIO::calculateRemainingSeconds( m_iTotalSize, m_iProcessedSize, speed ))) );
+ }
+}
+
+
+void DefaultProgress::slotCopying( TDEIO::Job*, const KURL& from, const KURL& to )
+{
+ if ( d->noCaptionYet ) {
+ setCaption(i18n("Copy File(s) Progress"));
+ d->noCaptionYet = false;
+ }
+ mode = Copy;
+ sourceEdit->setText(from.prettyURL());
+ setDestVisible( true );
+ checkDestination( to );
+ destEdit->setText(to.prettyURL());
+}
+
+
+void DefaultProgress::slotMoving( TDEIO::Job*, const KURL& from, const KURL& to )
+{
+ if ( d->noCaptionYet ) {
+ setCaption(i18n("Move File(s) Progress"));
+ d->noCaptionYet = false;
+ }
+ mode = Move;
+ sourceEdit->setText(from.prettyURL());
+ setDestVisible( true );
+ checkDestination( to );
+ destEdit->setText(to.prettyURL());
+}
+
+
+void DefaultProgress::slotCreatingDir( TDEIO::Job*, const KURL& dir )
+{
+ if ( d->noCaptionYet ) {
+ setCaption(i18n("Creating Folder"));
+ d->noCaptionYet = false;
+ }
+ mode = Create;
+ sourceEdit->setText(dir.prettyURL());
+ setDestVisible( false );
+}
+
+
+void DefaultProgress::slotDeleting( TDEIO::Job*, const KURL& url )
+{
+ if ( d->noCaptionYet ) {
+ setCaption(i18n("Delete File(s) Progress"));
+ d->noCaptionYet = false;
+ }
+ mode = Delete;
+ sourceEdit->setText(url.prettyURL());
+ setDestVisible( false );
+}
+
+void DefaultProgress::slotTransferring( TDEIO::Job*, const KURL& url )
+{
+ if ( d->noCaptionYet ) {
+ setCaption(i18n("Loading Progress"));
+ d->noCaptionYet = false;
+ }
+ sourceEdit->setText(url.prettyURL());
+ setDestVisible( false );
+}
+
+void DefaultProgress::slotStating( TDEIO::Job*, const KURL& url )
+{
+ setCaption(i18n("Examining File Progress"));
+ sourceEdit->setText(url.prettyURL());
+ setDestVisible( false );
+}
+
+void DefaultProgress::slotMounting( TDEIO::Job*, const TQString & dev, const TQString & point )
+{
+ setCaption(i18n("Mounting %1").arg(dev));
+ sourceEdit->setText(point);
+ setDestVisible( false );
+}
+
+void DefaultProgress::slotUnmounting( TDEIO::Job*, const TQString & point )
+{
+ setCaption(i18n("Unmounting"));
+ sourceEdit->setText(point);
+ setDestVisible( false );
+}
+
+void DefaultProgress::slotCanResume( TDEIO::Job*, TDEIO::filesize_t resume )
+{
+ if ( resume ) {
+ resumeLabel->setText( i18n("Resuming from %1").arg(TDEIO::number(resume)) );
+ } else {
+ resumeLabel->setText( i18n("Not resumable") );
+ }
+}
+
+void DefaultProgress::setDestVisible( bool visible )
+{
+ // We can't hide the destInvite/destEdit labels,
+ // because it screws up the TQGridLayout.
+ if (visible)
+ {
+ destInvite->show();
+ destEdit->show();
+
+ destInvite->setText( i18n("Destination:") );
+ }
+ else
+ {
+ destInvite->hide();
+ destEdit->hide();
+ destInvite->setText( TQString::null );
+ destEdit->setText( TQString::null );
+ }
+}
+
+void DefaultProgress::slotClean() {
+ if (d->keepOpenChecked) {
+ mode = Done;
+ slotPercent(0, 100);
+ d->cancelClose->setGuiItem( KStdGuiItem::close() );
+ d->openFile->setEnabled(true);
+ slotProcessedSize(0, m_iTotalSize);
+ d->keepOpen->setEnabled(false);
+ if (!d->startTime.isNull()) {
+ int s = d->startTime.elapsed();
+ if (!s)
+ s = 1;
+ speedLabel->setText(i18n("%1/s (done)").arg(TDEIO::convertSize(1000 * m_iTotalSize / s)));
+ }
+ setOnlyClean(false);
+ }
+ else
+ hide();
+}
+
+void DefaultProgress::slotKeepOpenToggled(bool keepopen)
+{
+ d->keepOpenChecked=keepopen;
+}
+
+void DefaultProgress::checkDestination(const KURL& dest) {
+ bool ok = true;
+ if ( dest.isLocalFile() ) {
+ TQString path = dest.path( -1 );
+ TQStringList tmpDirs = TDEGlobal::dirs()->resourceDirs( "tmp" );
+ for ( TQStringList::Iterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it )
+ if ( path.contains( *it ) )
+ ok = false; // it's in the tmp resource
+ }
+
+ if ( ok ) {
+ d->openFile->show();
+ d->openLocation->show();
+ d->keepOpen->show();
+ d->location=dest;
+ }
+}
+
+void DefaultProgress::slotOpenFile()
+{
+ TDEProcess proc;
+ proc << "konqueror" << d->location.prettyURL();
+ proc.start(TDEProcess::DontCare);
+}
+
+void DefaultProgress::slotOpenLocation()
+{
+ TDEProcess proc;
+ d->location.setFileName("");
+ proc << "konqueror" << d->location.prettyURL();
+ proc.start(TDEProcess::DontCare);
+}
+
+void DefaultProgress::virtual_hook( int id, void* data )
+{ ProgressBase::virtual_hook( id, data ); }
+
+} /* namespace */
+
+#include "defaultprogress.moc"
diff --git a/tdeio/tdeio/defaultprogress.h b/tdeio/tdeio/defaultprogress.h
new file mode 100644
index 000000000..de0dfd093
--- /dev/null
+++ b/tdeio/tdeio/defaultprogress.h
@@ -0,0 +1,164 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 __defaultprogress_h__
+#define __defaultprogress_h__
+
+#include <tqlabel.h>
+
+#include <tdeio/global.h>
+
+#include <kprogress.h>
+
+#include "progressbase.h"
+
+class KLineEdit;
+
+namespace TDEIO {
+
+/*
+ * A default implementation of the progress dialog ProgressBase.
+ * ProgressBase
+ */
+class TDEIO_EXPORT DefaultProgress : public ProgressBase {
+
+ Q_OBJECT
+
+public:
+ /**
+ * Creates a new default progress dialog.
+ * @param showNow true to show immediately, false to show when
+ * needed
+ */
+ DefaultProgress( bool showNow = true );
+ /**
+ * Creates a new default progress dialog.
+ * @param parent the parent of the dialog (or 0 for top-level)
+ * @param name the name of the dialog, can be 0
+ * @since 3.1
+ */
+ DefaultProgress( TQWidget* parent, const char* name = 0 );
+ ~DefaultProgress();
+
+ bool keepOpen() const;
+
+ /// Shared with uiserver.cpp
+ static TQString makePercentString( unsigned long percent,
+ TDEIO::filesize_t totalSize,
+ unsigned long totalFiles );
+
+public slots:
+ virtual void slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size );
+ virtual void slotTotalFiles( TDEIO::Job *job, unsigned long files );
+ virtual void slotTotalDirs( TDEIO::Job *job, unsigned long dirs );
+
+ virtual void slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t bytes );
+ virtual void slotProcessedFiles( TDEIO::Job *job, unsigned long files );
+ virtual void slotProcessedDirs( TDEIO::Job *job, unsigned long dirs );
+
+ virtual void slotSpeed( TDEIO::Job *job, unsigned long speed );
+ virtual void slotPercent( TDEIO::Job *job, unsigned long percent );
+ /**
+ * Called to set an information message.
+ * @param job the TDEIO::Job
+ * @param msg the message to set
+ */
+ virtual void slotInfoMessage( TDEIO::Job *job, const TQString & msg );
+
+ virtual void slotCopying( TDEIO::Job* job, const KURL& src, const KURL& dest );
+ virtual void slotMoving( TDEIO::Job* job, const KURL& src, const KURL& dest );
+ virtual void slotDeleting( TDEIO::Job* job, const KURL& url );
+ /**
+ * Called when the job is transferring.
+ * @param job the TDEIO::Job
+ * @param url the url to transfer
+ * @since 3.1
+ */
+ void slotTransferring( TDEIO::Job* job, const KURL& url );
+ virtual void slotCreatingDir( TDEIO::Job* job, const KURL& dir );
+ /**
+ * Called when the job is requesting a stat.
+ * @param job the TDEIO::Job
+ * @param dir the dir to stat
+ * @since 3.1
+ */
+ virtual void slotStating( TDEIO::Job* job, const KURL& dir );
+ /**
+ * Called when the job is mounting.
+ * @param job the TDEIO::Job
+ * @param dev the device to mount
+ * @param point the mount point
+ */
+ virtual void slotMounting( TDEIO::Job* job, const TQString & dev, const TQString & point );
+ /**
+ * Called when the job is unmounting.
+ * @param job the TDEIO::Job
+ * @param point the mount point
+ */
+ virtual void slotUnmounting( TDEIO::Job* job, const TQString & point );
+ virtual void slotCanResume( TDEIO::Job* job, TDEIO::filesize_t from);
+
+ /**
+ * Called when the job is cleaned.
+ * @since 3.1
+ */
+ void slotClean();
+
+protected:
+ /// @since 3.1
+ void init();
+ void showTotals();
+ void setDestVisible( bool visible );
+ /// @since 3.1
+ void checkDestination( const KURL& dest);
+
+ KLineEdit* sourceEdit;
+ KLineEdit* destEdit;
+ TQLabel* progressLabel;
+ TQLabel* destInvite;
+ TQLabel* speedLabel;
+ TQLabel* sizeLabel;
+ TQLabel* resumeLabel;
+
+ KProgress* m_pProgressBar;
+
+ TDEIO::filesize_t m_iTotalSize;
+ unsigned long m_iTotalFiles;
+ unsigned long m_iTotalDirs;
+
+ TDEIO::filesize_t m_iProcessedSize;
+ unsigned long m_iProcessedDirs;
+ unsigned long m_iProcessedFiles;
+
+ enum ModeType { Copy, Move, Delete, Create, Done };
+ ModeType mode;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class DefaultProgressPrivate;
+ DefaultProgressPrivate* d;
+private slots:
+ void slotKeepOpenToggled(bool);
+ void slotOpenFile();
+ void slotOpenLocation();
+};
+
+} /* namespace */
+
+#endif // __defaultprogress_h__
+
diff --git a/tdeio/tdeio/forwardingslavebase.cpp b/tdeio/tdeio/forwardingslavebase.cpp
new file mode 100644
index 000000000..a55f68249
--- /dev/null
+++ b/tdeio/tdeio/forwardingslavebase.cpp
@@ -0,0 +1,475 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Kevin Ottens <ervin ipsquad 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.
+*/
+
+#include <kdebug.h>
+#include <tdeio/job.h>
+#include <kmimetype.h>
+#include <kprotocolinfo.h>
+
+#include <tqapplication.h>
+#include <tqeventloop.h>
+
+#include "forwardingslavebase.h"
+
+namespace TDEIO
+{
+
+class ForwardingSlaveBasePrivate
+{
+};
+
+ForwardingSlaveBase::ForwardingSlaveBase(const TQCString &protocol,
+ const TQCString &poolSocket,
+ const TQCString &appSocket)
+ : TQObject(), SlaveBase(protocol, poolSocket, appSocket)
+{
+}
+
+ForwardingSlaveBase::~ForwardingSlaveBase()
+{
+}
+
+bool ForwardingSlaveBase::internalRewriteURL(const KURL &url, KURL &newURL)
+{
+ bool result = true;
+
+ if ( url.protocol().ascii()==mProtocol )
+ {
+ result = rewriteURL(url, newURL);
+ }
+ else
+ {
+ newURL = url;
+ }
+
+ m_processedURL = newURL;
+ m_requestedURL = url;
+ return result;
+}
+
+void ForwardingSlaveBase::prepareUDSEntry(TDEIO::UDSEntry &entry,
+ bool listing) const
+{
+ kdDebug() << "ForwardingSlaveBase::prepareUDSEntry: listing=="
+ << listing << endl;
+
+ bool url_found = false;
+ TQString name;
+ KURL url;
+
+ TDEIO::UDSEntry::iterator it = entry.begin();
+ TDEIO::UDSEntry::iterator end = entry.end();
+
+ for(; it!=end; ++it)
+ {
+ KURL new_url = m_requestedURL;
+
+ switch( (*it).m_uds )
+ {
+ case TDEIO::UDS_NAME:
+ name = (*it).m_str;
+ kdDebug() << "Name = " << name << endl;
+ break;
+ case TDEIO::UDS_URL:
+ url_found = true;
+ url = (*it).m_str;
+ if (listing)
+ {
+ new_url.addPath(url.fileName());
+ }
+ (*it).m_str = new_url.url();
+ kdDebug() << "URL = " << url << endl;
+ kdDebug() << "New URL = " << (*it).m_str << endl;
+ break;
+ }
+ }
+
+ if ( m_processedURL.isLocalFile() )
+ {
+ KURL new_url = m_processedURL;
+ if (listing)
+ {
+ new_url.addPath( name );
+ }
+
+ TDEIO::UDSAtom atom;
+ atom.m_uds = TDEIO::UDS_LOCAL_PATH;
+ atom.m_long = 0;
+ atom.m_str = new_url.path();
+ entry.append(atom);
+ }
+}
+
+void ForwardingSlaveBase::get(const KURL &url)
+{
+ kdDebug() << "ForwardingSlaveBase::get: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::TransferJob *job = TDEIO::get(new_url, false, false);
+ connectTransferJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::put(const KURL &url, int permissions,
+ bool overwrite, bool resume )
+{
+ kdDebug() << "ForwardingSlaveBase::put: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::TransferJob *job = TDEIO::put(new_url, permissions, overwrite,
+ resume, false);
+ connectTransferJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::stat(const KURL &url)
+{
+ kdDebug() << "ForwardingSlaveBase::stat: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::SimpleJob *job = TDEIO::stat(new_url, false);
+ connectSimpleJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::mimetype(const KURL &url)
+{
+ kdDebug() << "ForwardingSlaveBase::mimetype: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::TransferJob *job = TDEIO::mimetype(new_url, false);
+ connectTransferJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::listDir(const KURL &url)
+{
+ kdDebug() << "ForwardingSlaveBase::listDir: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::ListJob *job = TDEIO::listDir(new_url, false);
+ connectListJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::mkdir(const KURL &url, int permissions)
+{
+ kdDebug() << "ForwardingSlaveBase::mkdir: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::SimpleJob *job = TDEIO::mkdir(new_url, permissions);
+ connectSimpleJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::rename(const KURL &src, const KURL &dest,
+ bool overwrite)
+{
+ kdDebug() << "ForwardingSlaveBase::rename: " << src << ", " << dest << endl;
+
+ KURL new_src, new_dest;
+ if ( internalRewriteURL(src, new_src) && internalRewriteURL(dest, new_dest) )
+ {
+ TDEIO::Job *job = TDEIO::rename(new_src, new_dest, overwrite);
+ connectJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::symlink(const TQString &target, const KURL &dest,
+ bool overwrite)
+{
+ kdDebug() << "ForwardingSlaveBase::symlink: " << target << ", " << dest << endl;
+
+ KURL new_dest;
+ if ( internalRewriteURL(dest, new_dest) )
+ {
+ TDEIO::SimpleJob *job = TDEIO::symlink(target, new_dest, overwrite, false);
+ connectSimpleJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::chmod(const KURL &url, int permissions)
+{
+ kdDebug() << "ForwardingSlaveBase::chmod: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ TDEIO::SimpleJob *job = TDEIO::chmod(new_url, permissions);
+ connectSimpleJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::copy(const KURL &src, const KURL &dest,
+ int permissions, bool overwrite)
+{
+ kdDebug() << "ForwardingSlaveBase::copy: " << src << ", " << dest << endl;
+
+ KURL new_src, new_dest;
+ if ( internalRewriteURL(src, new_src) && internalRewriteURL(dest, new_dest) )
+ {
+ TDEIO::Job *job = TDEIO::file_copy(new_src, new_dest, permissions,
+ overwrite, false);
+ connectJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::del(const KURL &url, bool isfile)
+{
+ kdDebug() << "ForwardingSlaveBase::del: " << url << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(url, new_url) )
+ {
+ if (isfile)
+ {
+ TDEIO::DeleteJob *job = TDEIO::del(new_url, false, false);
+ connectJob(job);
+ }
+ else
+ {
+ TDEIO::SimpleJob *job = TDEIO::rmdir(new_url);
+ connectSimpleJob(job);
+ }
+
+ tqApp->eventLoop()->enterLoop();
+ }
+}
+
+void ForwardingSlaveBase::localURL(const KURL& remoteURL)
+{
+ kdDebug() << "ForwardingSlaveBase::localURL: " << remoteURL << endl;
+
+ KURL new_url;
+ if ( internalRewriteURL(remoteURL, new_url) )
+ {
+ TDEIO::LocalURLJob *job = TDEIO::localURL(new_url);
+ connectLocalURLJob(job);
+
+ tqApp->eventLoop()->enterLoop();
+ }
+ else
+ {
+ // Let the slave base emit the required signals
+ SlaveBase::localURL(remoteURL);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ForwardingSlaveBase::connectJob(TDEIO::Job *job)
+{
+ // We will forward the warning message, no need to let the job
+ // display it itself
+ job->setInteractive(false);
+
+ // Forward metadata (e.g. modification time for put())
+ job->setMetaData( allMetaData() );
+#if 0 // debug code
+ kdDebug() << k_funcinfo << "transferring metadata:" << endl;
+ const MetaData md = allMetaData();
+ for ( MetaData::const_iterator it = md.begin(); it != md.end(); ++it )
+ kdDebug() << it.key() << " = " << it.data() << endl;
+#endif
+
+ connect( job, TQT_SIGNAL( result(TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult(TDEIO::Job *) ) );
+ connect( job, TQT_SIGNAL( warning(TDEIO::Job *, const TQString &) ),
+ this, TQT_SLOT( slotWarning(TDEIO::Job *, const TQString &) ) );
+ connect( job, TQT_SIGNAL( infoMessage(TDEIO::Job *, const TQString &) ),
+ this, TQT_SLOT( slotInfoMessage(TDEIO::Job *, const TQString &) ) );
+ connect( job, TQT_SIGNAL( totalSize(TDEIO::Job *, TDEIO::filesize_t) ),
+ this, TQT_SLOT( slotTotalSize(TDEIO::Job *, TDEIO::filesize_t) ) );
+ connect( job, TQT_SIGNAL( processedSize(TDEIO::Job *, TDEIO::filesize_t) ),
+ this, TQT_SLOT( slotProcessedSize(TDEIO::Job *, TDEIO::filesize_t) ) );
+ connect( job, TQT_SIGNAL( speed(TDEIO::Job *, unsigned long) ),
+ this, TQT_SLOT( slotSpeed(TDEIO::Job *, unsigned long) ) );
+}
+
+void ForwardingSlaveBase::connectSimpleJob(TDEIO::SimpleJob *job)
+{
+ connectJob(job);
+ connect( job, TQT_SIGNAL( redirection(TDEIO::Job *, const KURL &) ),
+ this, TQT_SLOT( slotRedirection(TDEIO::Job *, const KURL &) ) );
+}
+
+void ForwardingSlaveBase::connectListJob(TDEIO::ListJob *job)
+{
+ connectSimpleJob(job);
+ connect( job, TQT_SIGNAL( entries(TDEIO::Job *, const TDEIO::UDSEntryList &) ),
+ this, TQT_SLOT( slotEntries(TDEIO::Job *, const TDEIO::UDSEntryList &) ) );
+}
+
+void ForwardingSlaveBase::connectTransferJob(TDEIO::TransferJob *job)
+{
+ connectSimpleJob(job);
+ connect( job, TQT_SIGNAL( data(TDEIO::Job *, const TQByteArray &) ),
+ this, TQT_SLOT( slotData(TDEIO::Job *, const TQByteArray &) ) );
+ connect( job, TQT_SIGNAL( dataReq(TDEIO::Job *, TQByteArray &) ),
+ this, TQT_SLOT( slotDataReq(TDEIO::Job *, TQByteArray &) ) );
+ connect( job, TQT_SIGNAL( mimetype(TDEIO::Job *, const TQString &) ),
+ this, TQT_SLOT( slotMimetype(TDEIO::Job *, const TQString &) ) );
+ connect( job, TQT_SIGNAL( canResume(TDEIO::Job *, TDEIO::filesize_t) ),
+ this, TQT_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t) ) );
+}
+
+void ForwardingSlaveBase::connectLocalURLJob(TDEIO::LocalURLJob *job)
+{
+ connectJob(job);
+ connect( job, TQT_SIGNAL( localURL(TDEIO::Job *, const KURL&, bool) ),
+ this, TQT_SLOT( slotLocalURL(TDEIO::Job *, const KURL&, bool) ) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ForwardingSlaveBase::slotResult(TDEIO::Job *job)
+{
+ if ( job->error() != 0)
+ {
+ error( job->error(), job->errorText() );
+ }
+ else
+ {
+ TDEIO::StatJob *stat_job = dynamic_cast<TDEIO::StatJob *>(job);
+ if ( stat_job!=0L )
+ {
+ TDEIO::UDSEntry entry = stat_job->statResult();
+ prepareUDSEntry(entry);
+ statEntry( entry );
+ }
+ finished();
+ }
+
+ tqApp->eventLoop()->exitLoop();
+}
+
+void ForwardingSlaveBase::slotWarning(TDEIO::Job* /*job*/, const TQString &msg)
+{
+ warning(msg);
+}
+
+void ForwardingSlaveBase::slotInfoMessage(TDEIO::Job* /*job*/, const TQString &msg)
+{
+ infoMessage(msg);
+}
+
+void ForwardingSlaveBase::slotTotalSize(TDEIO::Job* /*job*/, TDEIO::filesize_t size)
+{
+ totalSize(size);
+}
+
+void ForwardingSlaveBase::slotProcessedSize(TDEIO::Job* /*job*/, TDEIO::filesize_t size)
+{
+ processedSize(size);
+}
+
+void ForwardingSlaveBase::slotSpeed(TDEIO::Job* /*job*/, unsigned long bytesPerSecond)
+{
+ speed(bytesPerSecond);
+}
+
+void ForwardingSlaveBase::slotRedirection(TDEIO::Job *job, const KURL &url)
+{
+ redirection(url);
+
+ // We've been redirected stop everything.
+ job->kill( true );
+ finished();
+
+ tqApp->eventLoop()->exitLoop();
+}
+
+void ForwardingSlaveBase::slotEntries(TDEIO::Job* /*job*/,
+ const TDEIO::UDSEntryList &entries)
+{
+ TDEIO::UDSEntryList final_entries = entries;
+
+ TDEIO::UDSEntryList::iterator it = final_entries.begin();
+ TDEIO::UDSEntryList::iterator end = final_entries.end();
+
+ for(; it!=end; ++it)
+ {
+ prepareUDSEntry(*it, true);
+ }
+
+ listEntries( final_entries );
+}
+
+void ForwardingSlaveBase::slotData(TDEIO::Job* /*job*/, const TQByteArray &d)
+{
+ data(d);
+}
+
+void ForwardingSlaveBase::slotDataReq(TDEIO::Job* /*job*/, TQByteArray &data)
+{
+ dataReq();
+ readData(data);
+}
+
+void ForwardingSlaveBase::slotMimetype (TDEIO::Job* /*job*/, const TQString &type)
+{
+ mimeType(type);
+}
+
+void ForwardingSlaveBase::slotCanResume (TDEIO::Job* /*job*/, TDEIO::filesize_t offset)
+{
+ canResume(offset);
+}
+
+void ForwardingSlaveBase::slotLocalURL(TDEIO::Job *, const KURL& url, bool)
+{
+ SlaveBase::localURL(url);
+}
+
+}
+
+#include "forwardingslavebase.moc"
+
diff --git a/tdeio/tdeio/forwardingslavebase.h b/tdeio/tdeio/forwardingslavebase.h
new file mode 100644
index 000000000..4d84089bf
--- /dev/null
+++ b/tdeio/tdeio/forwardingslavebase.h
@@ -0,0 +1,204 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Kevin Ottens <ervin ipsquad 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 _FORWARDING_SLAVE_BASE_H_
+#define _FORWARDING_SLAVE_BASE_H_
+
+#include <tdeio/slavebase.h>
+#include <tdeio/jobclasses.h>
+
+#include <tqobject.h>
+
+namespace TDEIO
+{
+
+class ForwardingSlaveBasePrivate;
+
+/**
+ * This class should be used as a base for ioslaves acting as a
+ * forwarder to other ioslaves. It has been designed to support only
+ * local filesystem like ioslaves.
+ *
+ * If the resulting ioslave should be a simple proxy, you only need
+ * to implement the ForwardingSlaveBase::rewriteURL() method.
+ *
+ * For more advanced behavior, the classic ioslave methods should
+ * be reimplemented, because their default behavior in this class
+ * is to forward using the ForwardingSlaveBase::rewriteURL() method.
+ *
+ * A possible code snippet for an advanced stat() behavior would look
+ * like this in the child class:
+ *
+ * \code
+ * void ChildProtocol::stat(const KURL &url)
+ * {
+ * bool is_special = false;
+ *
+ * // Process the URL to see if it should have
+ * // a special treatment
+ *
+ * if ( is_special )
+ * {
+ * // Handle the URL ourselves
+ * TDEIO::UDSEntry entry;
+ * // Fill entry with UDSAtom instances
+ * statEntry(entry);
+ * finished();
+ * }
+ * else
+ * {
+ * // Setup the ioslave internal state if
+ * // required by ChildProtocol::rewriteURL()
+ * ForwardingSlaveBase::stat(url);
+ * }
+ * }
+ * \endcode
+ *
+ * Of course in this case, you surely need to reimplement listDir()
+ * and get() accordingly.
+ *
+ * If you want view on directories to be correctly refreshed when
+ * something changes on a forwarded URL, you'll need a companion kded
+ * module to emit the KDirNotify Files*() DCOP signals.
+ *
+ * This class was initially used for media:/ ioslave. This ioslave code
+ * and the MediaDirNotify class of its companion kded module can be a
+ * good source of inspiration.
+ *
+ * @see ForwardingSlaveBase::rewriteURL()
+ * @since 3.4
+ * @author Kevin Ottens <ervin@ipsquad.net>
+ */
+class TDEIO_EXPORT ForwardingSlaveBase : public TQObject, public SlaveBase
+{
+Q_OBJECT
+public:
+ ForwardingSlaveBase(const TQCString &protocol,
+ const TQCString &poolSocket,
+ const TQCString &appSocket);
+ virtual ~ForwardingSlaveBase();
+
+ virtual void get(const KURL &url);
+
+ virtual void put(const KURL &url, int permissions,
+ bool overwrite, bool resume);
+
+ virtual void stat(const KURL &url);
+
+ virtual void mimetype(const KURL &url);
+
+ virtual void listDir(const KURL &url);
+
+ virtual void mkdir(const KURL &url, int permissions);
+
+ virtual void rename(const KURL &src, const KURL &dest, bool overwrite);
+
+ virtual void symlink(const TQString &target, const KURL &dest,
+ bool overwrite);
+
+ virtual void chmod(const KURL &url, int permissions);
+
+ virtual void copy(const KURL &src, const KURL &dest,
+ int permissions, bool overwrite);
+
+ virtual void del(const KURL &url, bool isfile);
+
+ virtual void localURL(const KURL& remoteURL);
+
+protected:
+ /**
+ * Rewrite an url to it's forwarded counterpart. It should return
+ * true if everything was ok, and false otherwise.
+ *
+ * If a problem is detected it's up to this method to trigger error()
+ * before returning. Returning false silently cancel the current
+ * slave operation.
+ *
+ * @param url The URL as given during the slave call
+ * @param newURL The new URL to forward the slave call to
+ * @return true if the given url could be correctly rewritten
+ */
+ virtual bool rewriteURL(const KURL &url, KURL &newURL)=0;
+
+ /**
+ * Allow to modify a UDSEntry before it's sent to the ioslave enpoint.
+ * This is the default implementation working in most case, but sometimes
+ * you could make use of more forwarding black magic (for example
+ * dynamically transform any desktop file into a fake directory...)
+ *
+ * @param entry the UDSEntry to post-process
+ * @param listing indicate if this entry it created during a listDir
+ * operation
+ */
+ virtual void prepareUDSEntry(TDEIO::UDSEntry &entry,
+ bool listing=false) const;
+
+ /**
+ * Return the URL being processed by the ioslave
+ * Only access it inside prepareUDSEntry()
+ */
+ KURL processedURL() const { return m_processedURL; }
+
+ /**
+ * Return the URL asked to the ioslave
+ * Only access it inside prepareUDSEntry()
+ */
+ KURL requestedURL() const { return m_requestedURL; }
+
+private:
+ KURL m_processedURL;
+ KURL m_requestedURL;
+ ForwardingSlaveBasePrivate *d;
+
+ bool internalRewriteURL(const KURL &url, KURL &newURL);
+
+ void connectJob(Job *job);
+ void connectSimpleJob(SimpleJob *job);
+ void connectListJob(ListJob *job);
+ void connectTransferJob(TransferJob *job);
+ void connectLocalURLJob(LocalURLJob *job);
+
+private slots:
+ // TDEIO::Job
+ void slotResult(TDEIO::Job *job);
+ void slotWarning(TDEIO::Job *job, const TQString &msg);
+ void slotInfoMessage(TDEIO::Job *job, const TQString &msg);
+ void slotTotalSize(TDEIO::Job *job, TDEIO::filesize_t size);
+ void slotProcessedSize(TDEIO::Job *job, TDEIO::filesize_t size);
+ void slotSpeed(TDEIO::Job *job, unsigned long bytesPerSecond);
+
+ // TDEIO::SimpleJob subclasses
+ void slotRedirection(TDEIO::Job *job, const KURL &url);
+
+ // TDEIO::ListJob
+ void slotEntries(TDEIO::Job *job, const TDEIO::UDSEntryList &entries);
+
+ // TDEIO::TransferJob
+ void slotData(TDEIO::Job *job, const TQByteArray &data);
+ void slotDataReq(TDEIO::Job *job, TQByteArray &data);
+ void slotMimetype (TDEIO::Job *job, const TQString &type);
+ void slotCanResume (TDEIO::Job *job, TDEIO::filesize_t offset);
+
+ // TDEIO::LocalURLJob
+ void slotLocalURL(TDEIO::Job *, const KURL&, bool);
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/global.cpp b/tdeio/tdeio/global.cpp
new file mode 100644
index 000000000..e4bfec5f6
--- /dev/null
+++ b/tdeio/tdeio/global.cpp
@@ -0,0 +1,2009 @@
+/* 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.
+*/
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "tdeio/global.h"
+#include "tdeio/job.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kprotocolmanager.h>
+#include <kde_file.h>
+
+#ifdef HAVE_VOLMGT
+#include <volmgt.h>
+#endif
+
+TDEIO_EXPORT TQString TDEIO::convertSizeWithBytes( TDEIO::filesize_t size )
+{
+ if ( size >= 1024 )
+ return convertSize( size ) + " (" + i18n( "%1 B" ).arg( TDEGlobal::locale()->formatNumber(size, 0) ) + ")";
+ else
+ return convertSize( size );
+}
+
+TDEIO_EXPORT TQString TDEIO::convertSize( TDEIO::filesize_t size )
+{
+ double fsize = size;
+ TQString s;
+ // Giga-byte
+ if ( size >= 1073741824 )
+ {
+ fsize /= 1073741824.0;
+ if ( fsize > 1024 ) // Tera-byte
+ s = i18n( "%1 TB" ).arg( TDEGlobal::locale()->formatNumber(fsize / 1024.0, 1));
+ else
+ s = i18n( "%1 GB" ).arg( TDEGlobal::locale()->formatNumber(fsize, 1));
+ }
+ // Mega-byte
+ else if ( size >= 1048576 )
+ {
+ fsize /= 1048576.0;
+ s = i18n( "%1 MB" ).arg( TDEGlobal::locale()->formatNumber(fsize, 1));
+ }
+ // Kilo-byte
+ else if ( size >= 1024 )
+ {
+ fsize /= 1024.0;
+ s = i18n( "%1 KB" ).arg( TDEGlobal::locale()->formatNumber(fsize, 1));
+ }
+ // Just byte
+ else if ( size > 0 )
+ {
+ s = i18n( "%1 B" ).arg( TDEGlobal::locale()->formatNumber(fsize, 0));
+ }
+ // Nothing
+ else
+ {
+ s = i18n( "0 B" );
+ }
+ return s;
+}
+
+TDEIO_EXPORT TQString TDEIO::convertSizeFromKB( TDEIO::filesize_t kbSize )
+{
+ return convertSize(kbSize * 1024);
+}
+
+TDEIO_EXPORT TQString TDEIO::number( TDEIO::filesize_t size )
+{
+ char charbuf[256];
+ sprintf(charbuf, "%lld", size);
+ return TQString::fromLatin1(charbuf);
+}
+
+TDEIO_EXPORT unsigned int TDEIO::calculateRemainingSeconds( TDEIO::filesize_t totalSize,
+ TDEIO::filesize_t processedSize, TDEIO::filesize_t speed )
+{
+ if ( (speed != 0) && (totalSize != 0) )
+ return ( totalSize - processedSize ) / speed;
+ else
+ return 0;
+}
+
+TDEIO_EXPORT TQString TDEIO::convertSeconds( unsigned int seconds )
+{
+ unsigned int days = seconds / 86400;
+ unsigned int hours = (seconds - (days * 86400)) / 3600;
+ unsigned int mins = (seconds - (days * 86400) - (hours * 3600)) / 60;
+ seconds = (seconds - (days * 86400) - (hours * 3600) - (mins * 60));
+
+ const TQTime time(hours, mins, seconds);
+ const TQString timeStr( TDEGlobal::locale()->formatTime(time, true /*with seconds*/, true /*duration*/) );
+ if ( days > 0 )
+ return i18n("1 day %1", "%n days %1", days).arg(timeStr);
+ else
+ return timeStr;
+}
+
+TDEIO_EXPORT TQTime TDEIO::calculateRemaining( TDEIO::filesize_t totalSize, TDEIO::filesize_t processedSize, TDEIO::filesize_t speed )
+{
+ TQTime remainingTime;
+
+ if ( speed != 0 ) {
+ TDEIO::filesize_t secs;
+ if ( totalSize == 0 ) {
+ secs = 0;
+ } else {
+ secs = ( totalSize - processedSize ) / speed;
+ }
+ if (secs >= (24*60*60)) // Limit to 23:59:59
+ secs = (24*60*60)-1;
+ int hr = secs / ( 60 * 60 );
+ int mn = ( secs - hr * 60 * 60 ) / 60;
+ int sc = ( secs - hr * 60 * 60 - mn * 60 );
+
+ remainingTime.setHMS( hr, mn, sc );
+ }
+
+ return remainingTime;
+}
+
+TDEIO_EXPORT TQString TDEIO::itemsSummaryString(uint items, uint files, uint dirs, TDEIO::filesize_t size, bool showSize)
+{
+ TQString text = items == 0 ? i18n( "No Items" ) : i18n( "One Item", "%n Items", items );
+ text += " - ";
+ text += files == 0 ? i18n( "No Files" ) : i18n( "One File", "%n Files", files );
+ if ( showSize && files > 0 )
+ {
+ text += " ";
+ text += i18n("(%1 Total)").arg(TDEIO::convertSize( size ) );
+ }
+ text += " - ";
+ text += dirs == 0 ? i18n( "No Folders" ) : i18n("One Folder", "%n Folders", dirs);
+ return text;
+}
+
+TDEIO_EXPORT TQString TDEIO::encodeFileName( const TQString & _str )
+{
+ TQString str( _str );
+
+ int i = 0;
+ while ( ( i = str.find( "%", i ) ) != -1 )
+ {
+ str.replace( i, 1, "%%");
+ i += 2;
+ }
+ while ( ( i = str.find( "/" ) ) != -1 )
+ str.replace( i, 1, "%2f");
+ return str;
+}
+
+TDEIO_EXPORT TQString TDEIO::decodeFileName( const TQString & _str )
+{
+ TQString str;
+
+ unsigned int i = 0;
+ for ( ; i < _str.length() ; ++i )
+ {
+ if ( _str[i]=='%' )
+ {
+ if ( _str[i+1]=='%' ) // %% -> %
+ {
+ str.append('%');
+ ++i;
+ }
+ else if ( _str[i+1]=='2' && (i+2<_str.length()) && _str[i+2].lower()=='f' ) // %2f -> /
+ {
+ str.append('/');
+ i += 2;
+ }
+ else
+ str.append('%');
+ } else
+ str.append(_str[i]);
+ }
+
+ return str;
+}
+
+TDEIO_EXPORT TQString TDEIO::Job::errorString() const
+{
+ return TDEIO::buildErrorString(m_error, m_errorText);
+}
+
+TDEIO_EXPORT TQString TDEIO::buildErrorString(int errorCode, const TQString &errorText)
+{
+ TQString result;
+
+ switch( errorCode )
+ {
+ case TDEIO::ERR_CANNOT_OPEN_FOR_READING:
+ result = i18n( "Could not read %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_OPEN_FOR_WRITING:
+ result = i18n( "Could not write to %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_LAUNCH_PROCESS:
+ result = i18n( "Could not start process %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_INTERNAL:
+ result = i18n( "Internal Error\nPlease send a full bug report at http://bugs.kde.org\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_MALFORMED_URL:
+ result = i18n( "Malformed URL %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_UNSUPPORTED_PROTOCOL:
+ result = i18n( "The protocol %1 is not supported." ).arg( errorText );
+ break;
+ case TDEIO::ERR_NO_SOURCE_PROTOCOL:
+ result = i18n( "The protocol %1 is only a filter protocol.").arg( errorText );
+ break;
+ case TDEIO::ERR_UNSUPPORTED_ACTION:
+ result = errorText;
+// result = i18n( "Unsupported action %1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_IS_DIRECTORY:
+ result = i18n( "%1 is a folder, but a file was expected." ).arg( errorText );
+ break;
+ case TDEIO::ERR_IS_FILE:
+ result = i18n( "%1 is a file, but a folder was expected." ).arg( errorText );
+ break;
+ case TDEIO::ERR_DOES_NOT_EXIST:
+ result = i18n( "The file or folder %1 does not exist." ).arg( errorText );
+ break;
+ case TDEIO::ERR_FILE_ALREADY_EXIST:
+ result = i18n( "A file named %1 already exists." ).arg( errorText );
+ break;
+ case TDEIO::ERR_DIR_ALREADY_EXIST:
+ result = i18n( "A folder named %1 already exists." ).arg( errorText );
+ break;
+ case TDEIO::ERR_UNKNOWN_HOST:
+ result = errorText.isEmpty() ? i18n( "No hostname specified." ) : i18n( "Unknown host %1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_ACCESS_DENIED:
+ result = i18n( "Access denied to %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_WRITE_ACCESS_DENIED:
+ result = i18n( "Access denied.\nCould not write to %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_ENTER_DIRECTORY:
+ result = i18n( "Could not enter folder %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_PROTOCOL_IS_NOT_A_FILESYSTEM:
+ result = i18n( "The protocol %1 does not implement a folder service." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CYCLIC_LINK:
+ result = i18n( "Found a cyclic link in %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_USER_CANCELED:
+ // Do nothing in this case. The user doesn't need to be told what he just did.
+ break;
+ case TDEIO::ERR_CYCLIC_COPY:
+ result = i18n( "Found a cyclic link while copying %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_CREATE_SOCKET:
+ result = i18n( "Could not create socket for accessing %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_CONNECT:
+ result = i18n( "Could not connect to host %1." ).arg( errorText.isEmpty() ? TQString::fromLatin1("localhost") : errorText );
+ break;
+ case TDEIO::ERR_CONNECTION_BROKEN:
+ result = i18n( "Connection to host %1 is broken." ).arg( errorText );
+ break;
+ case TDEIO::ERR_NOT_FILTER_PROTOCOL:
+ result = i18n( "The protocol %1 is not a filter protocol." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_MOUNT:
+ result = i18n( "Could not mount device.\nThe reported error was:\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_UNMOUNT:
+ result = i18n( "Could not unmount device.\nThe reported error was:\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_READ:
+ result = i18n( "Could not read file %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_WRITE:
+ result = i18n( "Could not write to file %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_BIND:
+ result = i18n( "Could not bind %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_LISTEN:
+ result = i18n( "Could not listen %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_ACCEPT:
+ result = i18n( "Could not accept %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_LOGIN:
+ result = errorText;
+ break;
+ case TDEIO::ERR_COULD_NOT_STAT:
+ result = i18n( "Could not access %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_CLOSEDIR:
+ result = i18n( "Could not terminate listing %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_MKDIR:
+ result = i18n( "Could not make folder %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_RMDIR:
+ result = i18n( "Could not remove folder %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_RESUME:
+ result = i18n( "Could not resume file %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_RENAME:
+ result = i18n( "Could not rename file %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_CHMOD:
+ result = i18n( "Could not change permissions for %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_DELETE:
+ result = i18n( "Could not delete file %1." ).arg( errorText );
+ break;
+ case TDEIO::ERR_SLAVE_DIED:
+ result = i18n( "The process for the %1 protocol died unexpectedly." ).arg( errorText );
+ break;
+ case TDEIO::ERR_OUT_OF_MEMORY:
+ result = i18n( "Error. Out of memory.\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_UNKNOWN_PROXY_HOST:
+ result = i18n( "Unknown proxy host\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_COULD_NOT_AUTHENTICATE:
+ result = i18n( "Authorization failed, %1 authentication not supported" ).arg( errorText );
+ break;
+ case TDEIO::ERR_ABORTED:
+ result = i18n( "User canceled action\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_INTERNAL_SERVER:
+ result = i18n( "Internal error in server\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_SERVER_TIMEOUT:
+ result = i18n( "Timeout on server\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_UNKNOWN:
+ result = i18n( "Unknown error\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_UNKNOWN_INTERRUPT:
+ result = i18n( "Unknown interrupt\n%1" ).arg( errorText );
+ break;
+/*
+ case TDEIO::ERR_CHECKSUM_MISMATCH:
+ if (errorText)
+ result = i18n( "Warning: MD5 Checksum for %1 does not match checksum returned from server" ).arg(errorText);
+ else
+ result = i18n( "Warning: MD5 Checksum for %1 does not match checksum returned from server" ).arg("document");
+ break;
+*/
+ case TDEIO::ERR_CANNOT_DELETE_ORIGINAL:
+ result = i18n( "Could not delete original file %1.\nPlease check permissions." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_DELETE_PARTIAL:
+ result = i18n( "Could not delete partial file %1.\nPlease check permissions." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_RENAME_ORIGINAL:
+ result = i18n( "Could not rename original file %1.\nPlease check permissions." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_RENAME_PARTIAL:
+ result = i18n( "Could not rename partial file %1.\nPlease check permissions." ).arg( errorText );
+ break;
+ case TDEIO::ERR_CANNOT_SYMLINK:
+ result = i18n( "Could not create symlink %1.\nPlease check permissions." ).arg( errorText );
+ break;
+ case TDEIO::ERR_NO_CONTENT:
+ result = errorText;
+ break;
+ case TDEIO::ERR_DISK_FULL:
+ result = i18n( "Could not write file %1.\nDisk full." ).arg( errorText );
+ break;
+ case TDEIO::ERR_IDENTICAL_FILES:
+ result = i18n( "The source and destination are the same file.\n%1" ).arg( errorText );
+ break;
+ case TDEIO::ERR_SLAVE_DEFINED:
+ result = errorText;
+ break;
+ case TDEIO::ERR_UPGRADE_REQUIRED:
+ result = i18n( "%1 is required by the server, but is not available." ).arg(errorText);
+ break;
+ case TDEIO::ERR_POST_DENIED:
+ result = i18n( "Access to restricted port in POST denied.");
+ break;
+ case TDEIO::ERR_OFFLINE_MODE:
+ result = i18n( "Could not access %1.\nOffline mode active.").arg( errorText );
+ break;
+ default:
+ result = i18n( "Unknown error code %1\n%2\nPlease send a full bug report at http://bugs.kde.org." ).arg( errorCode ).arg( errorText );
+ break;
+ }
+
+ return result;
+}
+
+TDEIO_EXPORT TQString TDEIO::unsupportedActionErrorString(const TQString &protocol, int cmd) {
+ switch (cmd) {
+ case CMD_CONNECT:
+ return i18n("Opening connections is not supported with the protocol %1." ).arg(protocol);
+ case CMD_DISCONNECT:
+ return i18n("Closing connections is not supported with the protocol %1." ).arg(protocol);
+ case CMD_STAT:
+ return i18n("Accessing files is not supported with the protocol %1.").arg(protocol);
+ case CMD_PUT:
+ return i18n("Writing to %1 is not supported.").arg(protocol);
+ case CMD_SPECIAL:
+ return i18n("There are no special actions available for protocol %1.").arg(protocol);
+ case CMD_LISTDIR:
+ return i18n("Listing folders is not supported for protocol %1.").arg(protocol);
+ case CMD_GET:
+ return i18n("Retrieving data from %1 is not supported.").arg(protocol);
+ case CMD_MIMETYPE:
+ return i18n("Retrieving mime type information from %1 is not supported.").arg(protocol);
+ case CMD_RENAME:
+ return i18n("Renaming or moving files within %1 is not supported.").arg(protocol);
+ case CMD_SYMLINK:
+ return i18n("Creating symlinks is not supported with protocol %1.").arg(protocol);
+ case CMD_COPY:
+ return i18n("Copying files within %1 is not supported.").arg(protocol);
+ case CMD_DEL:
+ return i18n("Deleting files from %1 is not supported.").arg(protocol);
+ case CMD_MKDIR:
+ return i18n("Creating folders is not supported with protocol %1.").arg(protocol);
+ case CMD_CHMOD:
+ return i18n("Changing the attributes of files is not supported with protocol %1.").arg(protocol);
+ case CMD_SUBURL:
+ return i18n("Using sub-URLs with %1 is not supported.").arg(protocol);
+ case CMD_MULTI_GET:
+ return i18n("Multiple get is not supported with protocol %1.").arg(protocol);
+ default:
+ return i18n("Protocol %1 does not support action %2.").arg(protocol).arg(cmd);
+ }/*end switch*/
+}
+
+TDEIO_EXPORT TQStringList TDEIO::Job::detailedErrorStrings( const KURL *reqUrl /*= 0L*/,
+ int method /*= -1*/ ) const
+{
+ TQString errorName, techName, description, ret2;
+ TQStringList causes, solutions, ret;
+
+ TQByteArray raw = rawErrorDetail( m_error, m_errorText, reqUrl, method );
+ TQDataStream stream(raw, IO_ReadOnly);
+
+ stream >> errorName >> techName >> description >> causes >> solutions;
+
+ TQString url, protocol, datetime;
+ if ( reqUrl ) {
+ url = reqUrl->htmlURL();
+ protocol = reqUrl->protocol();
+ } else {
+ url = i18n( "(unknown)" );
+ }
+
+ datetime = TDEGlobal::locale()->formatDateTime( TQDateTime::currentDateTime(),
+ false );
+
+ ret << errorName;
+ ret << TQString::fromLatin1( "<qt><p><b>" ) + errorName +
+ TQString::fromLatin1( "</b></p><p>" ) + description +
+ TQString::fromLatin1( "</p>" );
+ ret2 = TQString::fromLatin1( "<qt><p>" );
+ if ( !techName.isEmpty() )
+ ret2 += i18n( "<b>Technical reason</b>: " ) + techName + TQString::fromLatin1( "</p>" );
+ ret2 += i18n( "</p><p><b>Details of the request</b>:" );
+ ret2 += i18n( "</p><ul><li>URL: %1</li>" ).arg( url );
+ if ( !protocol.isEmpty() ) {
+ ret2 += i18n( "<li>Protocol: %1</li>" ).arg( protocol );
+ }
+ ret2 += i18n( "<li>Date and time: %1</li>" ).arg( datetime );
+ ret2 += i18n( "<li>Additional information: %1</li></ul>" ).arg( m_errorText );
+ if ( !causes.isEmpty() ) {
+ ret2 += i18n( "<p><b>Possible causes</b>:</p><ul><li>" );
+ ret2 += causes.join( "</li><li>" );
+ ret2 += TQString::fromLatin1( "</li></ul>" );
+ }
+ if ( !solutions.isEmpty() ) {
+ ret2 += i18n( "<p><b>Possible solutions</b>:</p><ul><li>" );
+ ret2 += solutions.join( "</li><li>" );
+ ret2 += TQString::fromLatin1( "</li></ul>" );
+ }
+ ret << ret2;
+ return ret;
+}
+
+TDEIO_EXPORT TQByteArray TDEIO::rawErrorDetail(int errorCode, const TQString &errorText,
+ const KURL *reqUrl /*= 0L*/, int /*method = -1*/ )
+{
+ TQString url, host, protocol, datetime, domain, path, dir, filename;
+ bool isSlaveNetwork = false;
+ if ( reqUrl ) {
+ url = reqUrl->prettyURL();
+ host = reqUrl->host();
+ protocol = reqUrl->protocol();
+
+ if ( host.left(4) == "www." )
+ domain = host.mid(4);
+ else
+ domain = host;
+
+ path = reqUrl->path(1);
+ filename = reqUrl->fileName();
+ dir = path + filename;
+
+ // detect if protocol is a network protocol...
+ // add your hacks here...
+ if ( protocol == "http" ||
+ protocol == "https" ||
+ protocol == "ftp" ||
+ protocol == "sftp" ||
+ protocol == "webdav" ||
+ protocol == "webdavs" ||
+ protocol == "finger" ||
+ protocol == "fish" ||
+ protocol == "gopher" ||
+ protocol == "imap" ||
+ protocol == "imaps" ||
+ protocol == "lan" ||
+ protocol == "ldap" ||
+ protocol == "mailto" ||
+ protocol == "news" ||
+ protocol == "nntp" ||
+ protocol == "pop3" ||
+ protocol == "pop3s" ||
+ protocol == "smtp" ||
+ protocol == "smtps" ||
+ protocol == "telnet"
+ ) {
+ isSlaveNetwork = false;
+ }
+ } else {
+ // assume that the errorText has the location we are interested in
+ url = host = domain = path = filename = dir = errorText;
+ protocol = i18n( "(unknown)" );
+ }
+
+ datetime = TDEGlobal::locale()->formatDateTime( TQDateTime::currentDateTime(),
+ false );
+
+ TQString errorName, techName, description;
+ TQStringList causes, solutions;
+
+ // c == cause, s == solution
+ TQString sSysadmin = i18n( "Contact your appropriate computer support system, "
+ "whether the system administrator, or technical support group for further "
+ "assistance." );
+ TQString sServeradmin = i18n( "Contact the administrator of the server "
+ "for further assistance." );
+ // FIXME active link to permissions dialog
+ TQString sAccess = i18n( "Check your access permissions on this resource." );
+ TQString cAccess = i18n( "Your access permissions may be inadequate to "
+ "perform the requested operation on this resource." );
+ TQString cLocked = i18n( "The file may be in use (and thus locked) by "
+ "another user or application." );
+ TQString sQuerylock = i18n( "Check to make sure that no other "
+ "application or user is using the file or has locked the file." );
+ TQString cHardware = i18n( "Although unlikely, a hardware error may have "
+ "occurred." );
+ TQString cBug = i18n( "You may have encountered a bug in the program." );
+ TQString cBuglikely = i18n( "This is most likely to be caused by a bug in the "
+ "program. Please consider submitting a full bug report as detailed below." );
+ TQString sUpdate = i18n( "Update your software to the latest version. "
+ "Your distribution should provide tools to update your software." );
+ TQString sBugreport = i18n( "When all else fails, please consider helping the "
+ "TDE team or the third party maintainer of this software by submitting a "
+ "high quality bug report. If the software is provided by a third party, "
+ "please contact them directly. Otherwise, first look to see if "
+ "the same bug has been submitted by someone else by searching at the "
+ "<a href=\"http://bugs.pearsoncomputing.net//\">TDE bug reporting website</a>. If not, take "
+ "note of the details given above, and include them in your bug report, along "
+ "with as many other details as you think might help." );
+ TQString cNetwork = i18n( "There may have been a problem with your network "
+ "connection." );
+ // FIXME netconf kcontrol link
+ TQString cNetconf = i18n( "There may have been a problem with your network "
+ "configuration. If you have been accessing the Internet with no problems "
+ "recently, this is unlikely." );
+ TQString cNetpath = i18n( "There may have been a problem at some point along "
+ "the network path between the server and this computer." );
+ TQString sTryagain = i18n( "Try again, either now or at a later time." );
+ TQString cProtocol = i18n( "A protocol error or incompatibility may have occurred." );
+ TQString sExists = i18n( "Ensure that the resource exists, and try again." );
+ TQString cExists = i18n( "The specified resource may not exist." );
+ TQString cTypo = i18n( "You may have incorrectly typed the location." );
+ TQString sTypo = i18n( "Double-check that you have entered the correct location "
+ "and try again." );
+ TQString sNetwork = i18n( "Check your network connection status." );
+
+ switch( errorCode ) {
+ case TDEIO::ERR_CANNOT_OPEN_FOR_READING:
+ errorName = i18n( "Cannot Open Resource For Reading" );
+ description = i18n( "This means that the contents of the requested file "
+ "or folder <strong>%1</strong> could not be retrieved, as read "
+ "access could not be obtained." ).arg( dir );
+ causes << i18n( "You may not have permissions to read the file or open "
+ "the folder.") << cLocked << cHardware;
+ solutions << sAccess << sQuerylock << sSysadmin;
+ break;
+
+ case TDEIO::ERR_CANNOT_OPEN_FOR_WRITING:
+ errorName = i18n( "Cannot Open Resource For Writing" );
+ description = i18n( "This means that the file, <strong>%1</strong>, could "
+ "not be written to as requested, because access with permission to "
+ "write could not be obtained." ).arg( filename );
+ causes << cAccess << cLocked << cHardware;
+ solutions << sAccess << sQuerylock << sSysadmin;
+ break;
+
+ case TDEIO::ERR_CANNOT_LAUNCH_PROCESS:
+ errorName = i18n( "Cannot Initiate the %1 Protocol" ).arg( protocol );
+ techName = i18n( "Unable to Launch Process" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol could not be started. This is "
+ "usually due to technical reasons." ).arg( protocol );
+ causes << i18n( "The program which provides compatibility with this "
+ "protocol may not have been updated with your last update of TDE. "
+ "This can cause the program to be incompatible with the current version "
+ "and thus not start." ) << cBug;
+ solutions << sUpdate << sSysadmin;
+ break;
+
+ case TDEIO::ERR_INTERNAL:
+ errorName = i18n( "Internal Error" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol has reported an internal error." )
+ .arg( protocol );
+ causes << cBuglikely;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_MALFORMED_URL:
+ errorName = i18n( "Improperly Formatted URL" );
+ description = i18n( "The <strong>U</strong>niform <strong>R</strong>esource "
+ "<strong>L</strong>ocator (URL) that you entered was not properly "
+ "formatted. The format of a URL is generally as follows:"
+ "<blockquote><strong>protocol://user:password@www.example.org:port/folder/"
+ "filename.extension?query=value</strong></blockquote>" );
+ solutions << sTypo;
+ break;
+
+ case TDEIO::ERR_UNSUPPORTED_PROTOCOL:
+ errorName = i18n( "Unsupported Protocol %1" ).arg( protocol );
+ description = i18n( "The protocol <strong>%1</strong> is not supported "
+ "by the TDE programs currently installed on this computer." )
+ .arg( protocol );
+ causes << i18n( "The requested protocol may not be supported." )
+ << i18n( "The versions of the %1 protocol supported by this computer and "
+ "the server may be incompatible." ).arg( protocol );
+ solutions << i18n( "You may perform a search on the Internet for a TDE "
+ "program (called a tdeioslave or ioslave) which supports this protocol. "
+ "Places to search include <a href=\"http://kde-apps.org/\">"
+ "http://kde-apps.org/</a> and <a href=\"http://freshmeat.net/\">"
+ "http://freshmeat.net/</a>." )
+ << sUpdate << sSysadmin;
+ break;
+
+ case TDEIO::ERR_NO_SOURCE_PROTOCOL:
+ errorName = i18n( "URL Does Not Refer to a Resource." );
+ techName = i18n( "Protocol is a Filter Protocol" );
+ description = i18n( "The <strong>U</strong>niform <strong>R</strong>esource "
+ "<strong>L</strong>ocator (URL) that you entered did not refer to a "
+ "specific resource." );
+ causes << i18n( "TDE is able to communicate through a protocol within a "
+ "protocol; the protocol specified is only for use in such situations, "
+ "however this is not one of these situations. This is a rare event, and "
+ "is likely to indicate a programming error." );
+ solutions << sTypo;
+ break;
+
+ case TDEIO::ERR_UNSUPPORTED_ACTION:
+ errorName = i18n( "Unsupported Action: %1" ).arg( errorText );
+ description = i18n( "The requested action is not supported by the TDE "
+ "program which is implementing the <strong>%1</strong> protocol." )
+ .arg( protocol );
+ causes << i18n( "This error is very much dependent on the TDE program. The "
+ "additional information should give you more information than is available "
+ "to the TDE input/output architecture." );
+ solutions << i18n( "Attempt to find another way to accomplish the same "
+ "outcome." );
+ break;
+
+ case TDEIO::ERR_IS_DIRECTORY:
+ errorName = i18n( "File Expected" );
+ description = i18n( "The request expected a file, however the "
+ "folder <strong>%1</strong> was found instead." ).arg( dir );
+ causes << i18n( "This may be an error on the server side." ) << cBug;
+ solutions << sUpdate << sSysadmin;
+ break;
+
+ case TDEIO::ERR_IS_FILE:
+ errorName = i18n( "Folder Expected" );
+ description = i18n( "The request expected a folder, however "
+ "the file <strong>%1</strong> was found instead." ).arg( filename );
+ causes << cBug;
+ solutions << sUpdate << sSysadmin;
+ break;
+
+ case TDEIO::ERR_DOES_NOT_EXIST:
+ errorName = i18n( "File or Folder Does Not Exist" );
+ description = i18n( "The specified file or folder <strong>%1</strong> "
+ "does not exist." ).arg( dir );
+ causes << cBug;
+ solutions << sUpdate << sSysadmin;
+ break;
+
+ case TDEIO::ERR_FILE_ALREADY_EXIST:
+ errorName = i18n( "File Already Exists" );
+ description = i18n( "The requested file could not be created because a "
+ "file with the same name already exists." );
+ solutions << i18n ( "Try moving the current file out of the way first, "
+ "and then try again." )
+ << i18n ( "Delete the current file and try again." )
+ << i18n( "Choose an alternate filename for the new file." );
+ break;
+
+ case TDEIO::ERR_DIR_ALREADY_EXIST:
+ errorName = i18n( "Folder Already Exists" );
+ description = i18n( "The requested folder could not be created because "
+ "a folder with the same name already exists." );
+ solutions << i18n( "Try moving the current folder out of the way first, "
+ "and then try again." )
+ << i18n( "Delete the current folder and try again." )
+ << i18n( "Choose an alternate name for the new folder." );
+ break;
+
+ case TDEIO::ERR_UNKNOWN_HOST:
+ errorName = i18n( "Unknown Host" );
+ description = i18n( "An unknown host error indicates that the server with "
+ "the requested name, <strong>%1</strong>, could not be "
+ "located on the Internet." ).arg( host );
+ causes << i18n( "The name that you typed, %1, may not exist: it may be "
+ "incorrectly typed." ).arg( host )
+ << cNetwork << cNetconf;
+ solutions << sNetwork << sSysadmin;
+ break;
+
+ case TDEIO::ERR_ACCESS_DENIED:
+ errorName = i18n( "Access Denied" );
+ description = i18n( "Access was denied to the specified resource, "
+ "<strong>%1</strong>." ).arg( url );
+ causes << i18n( "You may have supplied incorrect authentication details or "
+ "none at all." )
+ << i18n( "Your account may not have permission to access the "
+ "specified resource." );
+ solutions << i18n( "Retry the request and ensure your authentication details "
+ "are entered correctly." ) << sSysadmin;
+ if ( !isSlaveNetwork ) solutions << sServeradmin;
+ break;
+
+ case TDEIO::ERR_WRITE_ACCESS_DENIED:
+ errorName = i18n( "Write Access Denied" );
+ description = i18n( "This means that an attempt to write to the file "
+ "<strong>%1</strong> was rejected." ).arg( filename );
+ causes << cAccess << cLocked << cHardware;
+ solutions << sAccess << sQuerylock << sSysadmin;
+ break;
+
+ case TDEIO::ERR_CANNOT_ENTER_DIRECTORY:
+ errorName = i18n( "Unable to Enter Folder" );
+ description = i18n( "This means that an attempt to enter (in other words, "
+ "to open) the requested folder <strong>%1</strong> was rejected." )
+ .arg( dir );
+ causes << cAccess << cLocked;
+ solutions << sAccess << sQuerylock << sSysadmin;
+ break;
+
+ case TDEIO::ERR_PROTOCOL_IS_NOT_A_FILESYSTEM:
+ errorName = i18n( "Folder Listing Unavailable" );
+ techName = i18n( "Protocol %1 is not a Filesystem" ).arg( protocol );
+ description = i18n( "This means that a request was made which requires "
+ "determining the contents of the folder, and the TDE program supporting "
+ "this protocol is unable to do so." );
+ causes << cBug;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_CYCLIC_LINK:
+ errorName = i18n( "Cyclic Link Detected" );
+ description = i18n( "UNIX environments are commonly able to link a file or "
+ "folder to a separate name and/or location. TDE detected a link or "
+ "series of links that results in an infinite loop - i.e. the file was "
+ "(perhaps in a roundabout way) linked to itself." );
+ solutions << i18n( "Delete one part of the loop in order that it does not "
+ "cause an infinite loop, and try again." ) << sSysadmin;
+ break;
+
+ case TDEIO::ERR_USER_CANCELED:
+ // Do nothing in this case. The user doesn't need to be told what he just did.
+ // rodda: However, if we have been called, an application is about to display
+ // this information anyway. If we don't return sensible information, the
+ // user sees a blank dialog (I have seen this myself)
+ errorName = i18n( "Request Aborted By User" );
+ description = i18n( "The request was not completed because it was "
+ "aborted." );
+ solutions << i18n( "Retry the request." );
+ break;
+
+ case TDEIO::ERR_CYCLIC_COPY:
+ errorName = i18n( "Cyclic Link Detected During Copy" );
+ description = i18n( "UNIX environments are commonly able to link a file or "
+ "folder to a separate name and/or location. During the requested copy "
+ "operation, TDE detected a link or series of links that results in an "
+ "infinite loop - i.e. the file was (perhaps in a roundabout way) linked "
+ "to itself." );
+ solutions << i18n( "Delete one part of the loop in order that it does not "
+ "cause an infinite loop, and try again." ) << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_CREATE_SOCKET:
+ errorName = i18n( "Could Not Create Network Connection" );
+ techName = i18n( "Could Not Create Socket" );
+ description = i18n( "This is a fairly technical error in which a required "
+ "device for network communications (a socket) could not be created." );
+ causes << i18n( "The network connection may be incorrectly configured, or "
+ "the network interface may not be enabled." );
+ solutions << sNetwork << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_CONNECT:
+ errorName = i18n( "Connection to Server Refused" );
+ description = i18n( "The server <strong>%1</strong> refused to allow this "
+ "computer to make a connection." ).arg( host );
+ causes << i18n( "The server, while currently connected to the Internet, "
+ "may not be configured to allow requests." )
+ << i18n( "The server, while currently connected to the Internet, "
+ "may not be running the requested service (%1)." ).arg( protocol )
+ << i18n( "A network firewall (a device which restricts Internet "
+ "requests), either protecting your network or the network of the server, "
+ "may have intervened, preventing this request." );
+ solutions << sTryagain << sServeradmin << sSysadmin;
+ break;
+
+ case TDEIO::ERR_CONNECTION_BROKEN:
+ errorName = i18n( "Connection to Server Closed Unexpectedly" );
+ description = i18n( "Although a connection was established to "
+ "<strong>%1</strong>, the connection was closed at an unexpected point "
+ "in the communication." ).arg( host );
+ causes << cNetwork << cNetpath << i18n( "A protocol error may have occurred, "
+ "causing the server to close the connection as a response to the error." );
+ solutions << sTryagain << sServeradmin << sSysadmin;
+ break;
+
+ case TDEIO::ERR_NOT_FILTER_PROTOCOL:
+ errorName = i18n( "URL Resource Invalid" );
+ techName = i18n( "Protocol %1 is not a Filter Protocol" ).arg( protocol );
+ description = i18n( "The <strong>U</strong>niform <strong>R</strong>esource "
+ "<strong>L</strong>ocator (URL) that you entered did not refer to "
+ "a valid mechanism of accessing the specific resource, "
+ "<strong>%1%2</strong>." )
+ .arg( !host.isNull() ? host + '/' : TQString::null ).arg( dir );
+ causes << i18n( "TDE is able to communicate through a protocol within a "
+ "protocol. This request specified a protocol be used as such, however "
+ "this protocol is not capable of such an action. This is a rare event, "
+ "and is likely to indicate a programming error." );
+ solutions << sTypo << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_MOUNT:
+ errorName = i18n( "Unable to Initialize Input/Output Device" );
+ techName = i18n( "Could Not Mount Device" );
+ description = i18n( "The requested device could not be initialized "
+ "(\"mounted\"). The reported error was: <strong>%1</strong>" )
+ .arg( errorText );
+ causes << i18n( "The device may not be ready, for example there may be "
+ "no media in a removable media device (i.e. no CD-ROM in a CD drive), "
+ "or in the case of a peripheral/portable device, the device may not "
+ "be correctly connected." )
+ << i18n( "You may not have permissions to initialize (\"mount\") the "
+ "device. On UNIX systems, often system administrator privileges are "
+ "required to initialize a device." )
+ << cHardware;
+ solutions << i18n( "Check that the device is ready; removable drives "
+ "must contain media, and portable devices must be connected and powered "
+ "on.; and try again." ) << sAccess << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_UNMOUNT:
+ errorName = i18n( "Unable to Uninitialize Input/Output Device" );
+ techName = i18n( "Could Not Unmount Device" );
+ description = i18n( "The requested device could not be uninitialized "
+ "(\"unmounted\"). The reported error was: <strong>%1</strong>" )
+ .arg( errorText );
+ causes << i18n( "The device may be busy, that is, still in use by "
+ "another application or user. Even such things as having an open "
+ "browser window on a location on this device may cause the device to "
+ "remain in use." )
+ << i18n( "You may not have permissions to uninitialize (\"unmount\") "
+ "the device. On UNIX systems, system administrator privileges are "
+ "often required to uninitialize a device." )
+ << cHardware;
+ solutions << i18n( "Check that no applications are accessing the device, "
+ "and try again." ) << sAccess << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_READ:
+ errorName = i18n( "Cannot Read From Resource" );
+ description = i18n( "This means that although the resource, "
+ "<strong>%1</strong>, was able to be opened, an error occurred while "
+ "reading the contents of the resource." ).arg( url );
+ causes << i18n( "You may not have permissions to read from the resource." );
+ if ( !isSlaveNetwork ) causes << cNetwork;
+ causes << cHardware;
+ solutions << sAccess;
+ if ( !isSlaveNetwork ) solutions << sNetwork;
+ solutions << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_WRITE:
+ errorName = i18n( "Cannot Write to Resource" );
+ description = i18n( "This means that although the resource, <strong>%1</strong>"
+ ", was able to be opened, an error occurred while writing to the resource." )
+ .arg( url );
+ causes << i18n( "You may not have permissions to write to the resource." );
+ if ( !isSlaveNetwork ) causes << cNetwork;
+ causes << cHardware;
+ solutions << sAccess;
+ if ( !isSlaveNetwork ) solutions << sNetwork;
+ solutions << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_BIND:
+ errorName = i18n( "Could Not Listen for Network Connections" );
+ techName = i18n( "Could Not Bind" );
+ description = i18n( "This is a fairly technical error in which a required "
+ "device for network communications (a socket) could not be established "
+ "to listen for incoming network connections." );
+ causes << i18n( "The network connection may be incorrectly configured, or "
+ "the network interface may not be enabled." );
+ solutions << sNetwork << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_LISTEN:
+ errorName = i18n( "Could Not Listen for Network Connections" );
+ techName = i18n( "Could Not Listen" );
+ description = i18n( "This is a fairly technical error in which a required "
+ "device for network communications (a socket) could not be established "
+ "to listen for incoming network connections." );
+ causes << i18n( "The network connection may be incorrectly configured, or "
+ "the network interface may not be enabled." );
+ solutions << sNetwork << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_ACCEPT:
+ errorName = i18n( "Could Not Accept Network Connection" );
+ description = i18n( "This is a fairly technical error in which an error "
+ "occurred while attempting to accept an incoming network connection." );
+ causes << i18n( "The network connection may be incorrectly configured, or "
+ "the network interface may not be enabled." )
+ << i18n( "You may not have permissions to accept the connection." );
+ solutions << sNetwork << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_LOGIN:
+ errorName = i18n( "Could Not Login: %1" ).arg( errorText );
+ description = i18n( "An attempt to login to perform the requested "
+ "operation was unsuccessful." );
+ causes << i18n( "You may have supplied incorrect authentication details or "
+ "none at all." )
+ << i18n( "Your account may not have permission to access the "
+ "specified resource." ) << cProtocol;
+ solutions << i18n( "Retry the request and ensure your authentication details "
+ "are entered correctly." ) << sServeradmin << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_STAT:
+ errorName = i18n( "Could Not Determine Resource Status" );
+ techName = i18n( "Could Not Stat Resource" );
+ description = i18n( "An attempt to determine information about the status "
+ "of the resource <strong>%1</strong>, such as the resource name, type, "
+ "size, etc., was unsuccessful." ).arg( url );
+ causes << i18n( "The specified resource may not have existed or may "
+ "not be accessible." ) << cProtocol << cHardware;
+ solutions << i18n( "Retry the request and ensure your authentication details "
+ "are entered correctly." ) << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_CLOSEDIR:
+ //result = i18n( "Could not terminate listing %1" ).arg( errorText );
+ errorName = i18n( "Could Not Cancel Listing" );
+ techName = i18n( "FIXME: Document this" );
+ break;
+
+ case TDEIO::ERR_COULD_NOT_MKDIR:
+ errorName = i18n( "Could Not Create Folder" );
+ description = i18n( "An attempt to create the requested folder failed." );
+ causes << cAccess << i18n( "The location where the folder was to be created "
+ "may not exist." );
+ if ( !isSlaveNetwork ) causes << cProtocol;
+ solutions << i18n( "Retry the request." ) << sAccess;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_RMDIR:
+ errorName = i18n( "Could Not Remove Folder" );
+ description = i18n( "An attempt to remove the specified folder, "
+ "<strong>%1</strong>, failed." ).arg( dir );
+ causes << i18n( "The specified folder may not exist." )
+ << i18n( "The specified folder may not be empty." )
+ << cAccess;
+ if ( !isSlaveNetwork ) causes << cProtocol;
+ solutions << i18n( "Ensure that the folder exists and is empty, and try "
+ "again." ) << sAccess;
+ break;
+
+ case TDEIO::ERR_CANNOT_RESUME:
+ errorName = i18n( "Could Not Resume File Transfer" );
+ description = i18n( "The specified request asked that the transfer of "
+ "file <strong>%1</strong> be resumed at a certain point of the "
+ "transfer. This was not possible." ).arg( filename );
+ causes << i18n( "The protocol, or the server, may not support file "
+ "resuming." );
+ solutions << i18n( "Retry the request without attempting to resume "
+ "transfer." );
+ break;
+
+ case TDEIO::ERR_CANNOT_RENAME:
+ errorName = i18n( "Could Not Rename Resource" );
+ description = i18n( "An attempt to rename the specified resource "
+ "<strong>%1</strong> failed." ).arg( url );
+ causes << cAccess << cExists;
+ if ( !isSlaveNetwork ) causes << cProtocol;
+ solutions << sAccess << sExists;
+ break;
+
+ case TDEIO::ERR_CANNOT_CHMOD:
+ errorName = i18n( "Could Not Alter Permissions of Resource" );
+ description = i18n( "An attempt to alter the permissions on the specified "
+ "resource <strong>%1</strong> failed." ).arg( url );
+ causes << cAccess << cExists;
+ solutions << sAccess << sExists;
+ break;
+
+ case TDEIO::ERR_CANNOT_DELETE:
+ errorName = i18n( "Could Not Delete Resource" );
+ description = i18n( "An attempt to delete the specified resource "
+ "<strong>%1</strong> failed." ).arg( url );
+ causes << cAccess << cExists;
+ solutions << sAccess << sExists;
+ break;
+
+ case TDEIO::ERR_SLAVE_DIED:
+ errorName = i18n( "Unexpected Program Termination" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol has unexpectedly terminated." )
+ .arg( url );
+ causes << cBuglikely;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_OUT_OF_MEMORY:
+ errorName = i18n( "Out of Memory" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol could not obtain the memory "
+ "required to continue." ).arg( protocol );
+ causes << cBuglikely;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_UNKNOWN_PROXY_HOST:
+ errorName = i18n( "Unknown Proxy Host" );
+ description = i18n( "While retrieving information about the specified "
+ "proxy host, <strong>%1</strong>, an Unknown Host error was encountered. "
+ "An unknown host error indicates that the requested name could not be "
+ "located on the Internet." ).arg( errorText );
+ causes << i18n( "There may have been a problem with your network "
+ "configuration, specifically your proxy's hostname. If you have been "
+ "accessing the Internet with no problems recently, this is unlikely." )
+ << cNetwork;
+ solutions << i18n( "Double-check your proxy settings and try again." )
+ << sSysadmin;
+ break;
+
+ case TDEIO::ERR_COULD_NOT_AUTHENTICATE:
+ errorName = i18n( "Authentication Failed: Method %1 Not Supported" )
+ .arg( errorText );
+ description = i18n( "Although you may have supplied the correct "
+ "authentication details, the authentication failed because the "
+ "method that the server is using is not supported by the TDE "
+ "program implementing the protocol %1." ).arg( protocol );
+ solutions << i18n( "Please file a bug at <a href=\"http://bugs.kde.org/\">"
+ "http://bugs.pearsoncomputing.net/</a> to inform the TDE team of the unsupported "
+ "authentication method." ) << sSysadmin;
+ break;
+
+ case TDEIO::ERR_ABORTED:
+ errorName = i18n( "Request Aborted" );
+ description = i18n( "The request was not completed because it was "
+ "aborted." );
+ solutions << i18n( "Retry the request." );
+ break;
+
+ case TDEIO::ERR_INTERNAL_SERVER:
+ errorName = i18n( "Internal Error in Server" );
+ description = i18n( "The program on the server which provides access "
+ "to the <strong>%1</strong> protocol has reported an internal error: "
+ "%0." ).arg( protocol );
+ causes << i18n( "This is most likely to be caused by a bug in the "
+ "server program. Please consider submitting a full bug report as "
+ "detailed below." );
+ solutions << i18n( "Contact the administrator of the server "
+ "to advise them of the problem." )
+ << i18n( "If you know who the authors of the server software are, "
+ "submit the bug report directly to them." );
+ break;
+
+ case TDEIO::ERR_SERVER_TIMEOUT:
+ errorName = i18n( "Timeout Error" );
+ description = i18n( "Although contact was made with the server, a "
+ "response was not received within the amount of time allocated for "
+ "the request as follows:<ul>"
+ "<li>Timeout for establishing a connection: %1 seconds</li>"
+ "<li>Timeout for receiving a response: %2 seconds</li>"
+ "<li>Timeout for accessing proxy servers: %3 seconds</li></ul>"
+ "Please note that you can alter these timeout settings in the TDE "
+ "Control Center, by selecting Network -> Preferences." )
+ .arg( KProtocolManager::connectTimeout() )
+ .arg( KProtocolManager::responseTimeout() )
+ .arg( KProtocolManager::proxyConnectTimeout() );
+ causes << cNetpath << i18n( "The server was too busy responding to other "
+ "requests to respond." );
+ solutions << sTryagain << sServeradmin;
+ break;
+
+ case TDEIO::ERR_UNKNOWN:
+ errorName = i18n( "Unknown Error" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol has reported an unknown error: "
+ "%2." ).arg( protocol ).arg( errorText );
+ causes << cBug;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_UNKNOWN_INTERRUPT:
+ errorName = i18n( "Unknown Interruption" );
+ description = i18n( "The program on your computer which provides access "
+ "to the <strong>%1</strong> protocol has reported an interruption of "
+ "an unknown type: %2." ).arg( protocol ).arg( errorText );
+ causes << cBug;
+ solutions << sUpdate << sBugreport;
+ break;
+
+ case TDEIO::ERR_CANNOT_DELETE_ORIGINAL:
+ errorName = i18n( "Could Not Delete Original File" );
+ description = i18n( "The requested operation required the deleting of "
+ "the original file, most likely at the end of a file move operation. "
+ "The original file <strong>%1</strong> could not be deleted." )
+ .arg( errorText );
+ causes << cAccess;
+ solutions << sAccess;
+ break;
+
+ case TDEIO::ERR_CANNOT_DELETE_PARTIAL:
+ errorName = i18n( "Could Not Delete Temporary File" );
+ description = i18n( "The requested operation required the creation of "
+ "a temporary file in which to save the new file while being "
+ "downloaded. This temporary file <strong>%1</strong> could not be "
+ "deleted." ).arg( errorText );
+ causes << cAccess;
+ solutions << sAccess;
+ break;
+
+ case TDEIO::ERR_CANNOT_RENAME_ORIGINAL:
+ errorName = i18n( "Could Not Rename Original File" );
+ description = i18n( "The requested operation required the renaming of "
+ "the original file <strong>%1</strong>, however it could not be "
+ "renamed." ).arg( errorText );
+ causes << cAccess;
+ solutions << sAccess;
+ break;
+
+ case TDEIO::ERR_CANNOT_RENAME_PARTIAL:
+ errorName = i18n( "Could Not Rename Temporary File" );
+ description = i18n( "The requested operation required the creation of "
+ "a temporary file <strong>%1</strong>, however it could not be "
+ "created." ).arg( errorText );
+ causes << cAccess;
+ solutions << sAccess;
+ break;
+
+ case TDEIO::ERR_CANNOT_SYMLINK:
+ errorName = i18n( "Could Not Create Link" );
+ techName = i18n( "Could Not Create Symbolic Link" );
+ description = i18n( "The requested symbolic link %1 could not be created." )
+ .arg( errorText );
+ causes << cAccess;
+ solutions << sAccess;
+ break;
+
+ case TDEIO::ERR_NO_CONTENT:
+ errorName = i18n( "No Content" );
+ description = errorText;
+ break;
+
+ case TDEIO::ERR_DISK_FULL:
+ errorName = i18n( "Disk Full" );
+ description = i18n( "The requested file <strong>%1</strong> could not be "
+ "written to as there is inadequate disk space." ).arg( errorText );
+ solutions << i18n( "Free up enough disk space by 1) deleting unwanted and "
+ "temporary files; 2) archiving files to removable media storage such as "
+ "CD-Recordable discs; or 3) obtain more storage capacity." )
+ << sSysadmin;
+ break;
+
+ case TDEIO::ERR_IDENTICAL_FILES:
+ errorName = i18n( "Source and Destination Files Identical" );
+ description = i18n( "The operation could not be completed because the "
+ "source and destination files are the same file." );
+ solutions << i18n( "Choose a different filename for the destination file." );
+ break;
+
+ // We assume that the slave has all the details
+ case TDEIO::ERR_SLAVE_DEFINED:
+ errorName = TQString::null;
+ description = errorText;
+ break;
+
+ default:
+ // fall back to the plain error...
+ errorName = i18n( "Undocumented Error" );
+ description = buildErrorString( errorCode, errorText );
+ }
+
+ TQByteArray ret;
+ TQDataStream stream(ret, IO_WriteOnly);
+ stream << errorName << techName << description << causes << solutions;
+ return ret;
+}
+
+#ifdef Q_OS_UNIX
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <tqfile.h>
+
+#include <config.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <sys/param.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_SYS_MNTTAB_H
+#include <sys/mnttab.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#elif defined(HAVE_SYS_MNTENT_H)
+#include <sys/mntent.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_FSTAB_H
+#include <fstab.h>
+#endif
+#if defined(_AIX)
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <sys/vfs.h>
+
+/* AIX does not prototype mntctl anywhere that I can find */
+#ifndef mntctl
+extern "C" {
+int mntctl(int command, int size, void* buffer);
+}
+#endif
+extern "C" struct vfs_ent *getvfsbytype(int vfsType);
+extern "C" void endvfsent( );
+#endif
+
+/***************************************************************
+ *
+ * Utility functions
+ *
+ ***************************************************************/
+
+#ifndef HAVE_GETMNTINFO
+
+#ifdef _PATH_MOUNTED
+// On some Linux, MNTTAB points to /etc/fstab !
+# undef MNTTAB
+# define MNTTAB _PATH_MOUNTED
+#else
+# ifndef MNTTAB
+# ifdef MTAB_FILE
+# define MNTTAB MTAB_FILE
+# else
+# define MNTTAB "/etc/mnttab"
+# endif
+# endif
+#endif
+
+#ifndef FSTAB
+# ifdef _PATH_FSTAB
+# define FSTAB _PATH_FSTAB
+# else
+# define FSTAB "/etc/fstab"
+# endif
+#endif
+
+#ifdef __CYGWIN__
+#define hasmntopt(var,opt) (0)
+#endif
+
+// There are (at least) four kind of APIs:
+// setmntent + getmntent + struct mntent (linux...)
+// getmntent + struct mnttab
+// mntctl + struct vmount (AIX)
+// getmntinfo + struct statfs&flags (BSD 4.4 and friends)
+// getfsent + char* (BSD 4.3 and friends)
+
+#ifdef HAVE_SETMNTENT
+#define SETMNTENT setmntent
+#define ENDMNTENT endmntent
+#define STRUCT_MNTENT struct mntent *
+#define STRUCT_SETMNTENT FILE *
+#define GETMNTENT(file, var) ((var = getmntent(file)) != 0)
+#define MOUNTPOINT(var) var->mnt_dir
+#define MOUNTTYPE(var) var->mnt_type
+#define HASMNTOPT(var, opt) hasmntopt(var, opt)
+#define FSNAME(var) var->mnt_fsname
+#elif defined(_AIX)
+/* we don't need this stuff */
+#else
+#define SETMNTENT fopen
+#define ENDMNTENT fclose
+#define STRUCT_MNTENT struct mnttab
+#define STRUCT_SETMNTENT FILE *
+#define GETMNTENT(file, var) (getmntent(file, &var) == 0)
+#define MOUNTPOINT(var) var.mnt_mountp
+#define MOUNTTYPE(var) var.mnt_fstype
+#define HASMNTOPT(var, opt) hasmntopt(&var, opt)
+#define FSNAME(var) var.mnt_special
+#endif
+
+#endif /* HAVE_GETMNTINFO */
+
+TQString TDEIO::findDeviceMountPoint( const TQString& filename )
+{
+ TQString result;
+
+#ifdef HAVE_VOLMGT
+ /*
+ * support for Solaris volume management
+ */
+ const char *volpath;
+ FILE *mnttab;
+ struct mnttab mnt;
+ int len;
+ TQCString devname;
+
+ if( (volpath = volmgt_root()) == NULL ) {
+ kdDebug( 7007 ) << "findDeviceMountPoint: "
+ << "VOLMGT: can't find volmgt root dir" << endl;
+ return TQString::null;
+ }
+
+ if( (mnttab = fopen( MNTTAB, "r" )) == NULL ) {
+ kdDebug( 7007 ) << "findDeviceMountPoint: "
+ << "VOLMGT: can't open mnttab" << endl;
+ return TQString::null;
+ }
+
+ devname = volpath;
+ devname += TQFile::encodeName( filename );
+ devname += '/';
+ len = devname.length();
+// kdDebug( 7007 ) << "findDeviceMountPoint: "
+// << "VOLMGT: searching mountpoint for \"" << devname << "\""
+// << endl;
+
+ /*
+ * find the mountpoint
+ * floppies:
+ * /dev/disketteN => <volpath>/dev/disketteN
+ * CDROM, ZIP, and other media:
+ * /dev/dsk/cXtYdZs2 => <volpath>/dev/dsk/cXtYdZ (without slice#)
+ */
+ rewind( mnttab );
+ result = TQString::null;
+ while( getmntent( mnttab, &mnt ) == 0 ) {
+ /*
+ * either match the exact device name (floppies),
+ * or the device name without the slice#
+ */
+ if( strncmp( devname.data(), mnt.mnt_special, len ) == 0
+ || (strncmp( devname.data(), mnt.mnt_special, len - 3 ) == 0
+ && mnt.mnt_special[len - 3] == '/' )
+ || (strcmp(TQFile::encodeName(filename).data()
+ , mnt.mnt_special)==0)) {
+ result = mnt.mnt_mountp;
+ break;
+ }
+ }
+ fclose( mnttab );
+#else
+
+ char realpath_buffer[MAXPATHLEN];
+ TQCString realname;
+
+ realname = TQFile::encodeName(filename);
+ /* If the path contains symlinks, get the real name */
+ if (realpath(realname, realpath_buffer) != 0)
+ // succes, use result from realpath
+ realname = realpath_buffer;
+
+ //kdDebug(7007) << "findDeviceMountPoint realname=" << realname << endl;
+
+#ifdef HAVE_GETMNTINFO
+
+#ifdef GETMNTINFO_USES_STATVFS
+ struct statvfs *mounted;
+#else
+ struct statfs *mounted;
+#endif
+
+ int num_fs = getmntinfo(&mounted, MNT_NOWAIT);
+
+ for (int i=0;i<num_fs;i++) {
+
+ TQCString device_name = mounted[i].f_mntfromname;
+
+ // If the path contains symlinks, get
+ // the real name
+ if (realpath(device_name, realpath_buffer) != 0)
+ // succes, use result from realpath
+ device_name = realpath_buffer;
+
+ if (realname == device_name) {
+ result = mounted[i].f_mntonname;
+ break;
+ }
+ }
+
+#elif defined(_AIX)
+
+ struct vmount *mntctl_buffer;
+ struct vmount *vm;
+ char *mountedfrom;
+ char *mountedto;
+ int fsname_len, num;
+ int buf_sz = 4096;
+
+ /* mntctl can be used to query mounted file systems.
+ * mntctl takes only the command MCTL_QUERY so far.
+ * The buffer is filled with an array of vmount structures, but these
+ * vmount structures have variable size.
+ * mntctl return values:
+ * -1 error
+ * 0 look in first word of buffer for required bytes, 4096 may be
+ * a good starting size, but if tables grow too large, look here.
+ * >0 number of vmount structures
+ */
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ if (num == 0)
+ {
+ buf_sz = *(int*)mntctl_buffer;
+ free(mntctl_buffer);
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ }
+
+ if (num > 0)
+ {
+ /* iterate through items in the vmount structure: */
+ vm = mntctl_buffer;
+ for ( ; num > 0; num-- )
+ {
+ /* get the name of the mounted file systems: */
+ fsname_len = vmt2datasize(vm, VMT_STUB);
+ mountedto = (char*)malloc(fsname_len + 1);
+ mountedto[fsname_len] = '\0';
+ strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len);
+
+ /* get the mount-from information: */
+ fsname_len = vmt2datasize(vm, VMT_OBJECT);
+ mountedfrom = (char*)malloc(fsname_len + 1);
+ mountedfrom[fsname_len] = '\0';
+ strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len);
+
+ TQCString device_name = mountedfrom;
+
+ if (realpath(device_name, realpath_buffer) != 0)
+ // success, use result from realpath
+ device_name = realpath_buffer;
+
+ free(mountedfrom);
+
+ if (realname == device_name) {
+ result = mountedto;
+ free(mountedto);
+ break;
+ }
+
+ free(mountedto);
+
+ /* goto the next vmount structure: */
+ vm = (struct vmount *)((char *)vm + vm->vmt_length);
+ }
+ }
+
+ free( mntctl_buffer );
+
+#else
+
+ STRUCT_SETMNTENT mtab;
+
+ /* Get the list of mounted file systems */
+
+ if ((mtab = SETMNTENT(MNTTAB, "r")) == 0) {
+ perror("setmntent");
+ return TQString::null;
+ }
+
+ /* Loop over all file systems and see if we can find our
+ * mount point.
+ * Note that this is the mount point with the longest match.
+ * XXX: Fails if me->mnt_dir is not a realpath but goes
+ * through a symlink, e.g. /foo/bar where /foo is a symlink
+ * pointing to /local/foo.
+ *
+ * How kinky can you get with a filesystem?
+ */
+
+ STRUCT_MNTENT me;
+
+ while (GETMNTENT(mtab, me))
+ {
+ // There may be symbolic links into the /etc/mnttab
+ // So we have to find the real device name here as well!
+ TQCString device_name = FSNAME(me);
+ if (device_name.isEmpty() || (device_name == "none"))
+ continue;
+
+ //kdDebug( 7007 ) << "device_name=" << device_name << endl;
+
+ // If the path contains symlinks, get
+ // the real name
+ if (realpath(device_name, realpath_buffer) != 0)
+ // succes, use result from realpath
+ device_name = realpath_buffer;
+
+ //kdDebug( 7007 ) << "device_name after realpath =" << device_name << endl;
+
+ if (realname == device_name)
+ {
+ result = MOUNTPOINT(me);
+ break;
+ }
+ }
+
+ ENDMNTENT(mtab);
+
+#endif /* GET_MNTINFO */
+#endif /* HAVE_VOLMGT */
+
+ //kdDebug( 7007 ) << "Returning result " << result << endl;
+ return result;
+}
+
+// Don't just trust the return value, keep iterating to check for a better match (bigger max)
+static bool is_my_mountpoint( const char *mountpoint, const char *realname, int &max )
+{
+ int length = strlen(mountpoint);
+
+ if (!strncmp(mountpoint, realname, length)
+ && length > max) {
+ max = length;
+ if (length == 1 || realname[length] == '/' || realname[length] == '\0')
+ return true;
+ }
+ return false;
+}
+
+typedef enum { Unseen, Right, Wrong } MountState;
+
+/**
+ * Idea and code base by Olaf Kirch <okir@caldera.de>
+ **/
+static void check_mount_point(const char *mounttype,
+ const char *fsname,
+ MountState &isslow, MountState &isautofs)
+{
+ bool nfs = !strcmp(mounttype, "nfs");
+ bool autofs = !strcmp(mounttype, "autofs") || !strcmp(mounttype,"subfs");
+ bool pid = (strstr(fsname, ":(pid") != 0);
+
+ if (nfs && !pid)
+ isslow = Right;
+ else if (isslow == Right)
+ isslow = Wrong;
+
+ /* Does this look like automounted? */
+ if (autofs || (nfs && pid)) {
+ isautofs = Right;
+ isslow = Right;
+ }
+}
+
+// returns the mount point, checks the mount state.
+// if ismanual == Wrong this function does not check the manual mount state
+static TQString get_mount_info(const TQString& filename,
+ MountState& isautofs, MountState& isslow, MountState& ismanual,
+ TQString& fstype)
+{
+ static bool gotRoot = false;
+ static dev_t rootDevice;
+
+ struct cachedDevice_t
+ {
+ dev_t device;
+ TQString mountPoint;
+ MountState isautofs;
+ MountState isslow;
+ MountState ismanual;
+ TQString fstype;
+ };
+ static struct cachedDevice_t *cachedDevice = 0;
+
+ if (!gotRoot)
+ {
+ KDE_struct_stat stat_buf;
+ KDE_stat("/", &stat_buf);
+ gotRoot = true;
+ rootDevice = stat_buf.st_dev;
+ }
+
+ bool gotDevice = false;
+ KDE_struct_stat stat_buf;
+ if (KDE_stat(TQFile::encodeName(filename), &stat_buf) == 0)
+ {
+ gotDevice = true;
+ if (stat_buf.st_dev == rootDevice)
+ {
+ static const TQString &root = TDEGlobal::staticQString("/");
+ isautofs = Wrong;
+ isslow = Wrong;
+ ismanual = Wrong;
+ fstype = TQString::null; // ### do we need it?
+ return root;
+ }
+ if (cachedDevice && (stat_buf.st_dev == cachedDevice->device))
+ {
+ bool interestedInIsManual = ismanual != Wrong;
+ isautofs = cachedDevice->isautofs;
+ isslow = cachedDevice->isslow;
+ ismanual = cachedDevice->ismanual;
+ fstype = cachedDevice->fstype;
+ // Don't use the cache if it doesn't have the information we're looking for
+ if ( !interestedInIsManual || ismanual != Unseen )
+ return cachedDevice->mountPoint;
+ }
+ }
+
+ char realname[MAXPATHLEN];
+
+ memset(realname, 0, MAXPATHLEN);
+
+ /* If the path contains symlinks, get the real name */
+ if (realpath(TQFile::encodeName(filename), realname) == 0) {
+ if( strlcpy(realname, TQFile::encodeName(filename), MAXPATHLEN)>=MAXPATHLEN)
+ return TQString::null;
+ }
+
+ int max = 0;
+ TQString mountPoint;
+
+ /* Loop over all file systems and see if we can find our
+ * mount point.
+ * Note that this is the mount point with the longest match.
+ * XXX: Fails if me->mnt_dir is not a realpath but goes
+ * through a symlink, e.g. /foo/bar where /foo is a symlink
+ * pointing to /local/foo.
+ *
+ * How kinky can you get with a filesystem?
+ */
+
+#ifdef HAVE_GETMNTINFO
+
+#ifdef GETMNTINFO_USES_STATVFS
+ struct statvfs *mounted;
+#else
+ struct statfs *mounted;
+#endif
+
+ char realpath_buffer[MAXPATHLEN];
+
+ int num_fs = getmntinfo(&mounted, MNT_NOWAIT);
+
+ for (int i=0;i<num_fs;i++) {
+
+ TQCString device_name = mounted[i].f_mntfromname;
+
+ // If the path contains symlinks, get
+ // the real name
+ if (realpath(device_name, realpath_buffer) != 0)
+ // succes, use result from realpath
+ device_name = realpath_buffer;
+#ifdef __osf__
+ char * mounttype = mnt_names[mounted[i].f_type];
+#else
+ char * mounttype = mounted[i].f_fstypename;
+#endif
+ if ( is_my_mountpoint( mounted[i].f_mntonname, realname, max ) )
+ {
+ mountPoint = TQFile::decodeName(mounted[i].f_mntonname);
+ fstype = TQString::fromLatin1(mounttype);
+ check_mount_point( mounttype, mounted[i].f_mntfromname,
+ isautofs, isslow );
+ // keep going, looking for a potentially better one
+
+ if (ismanual == Unseen)
+ {
+ struct fstab *ft = getfsfile(mounted[i].f_mntonname);
+ if (!ft || strstr(ft->fs_mntops, "noauto"))
+ ismanual = Right;
+ }
+ }
+ }
+
+#elif defined(_AIX)
+
+ struct vmount *mntctl_buffer;
+ struct vmount *vm;
+ char *mountedfrom;
+ char *mountedto;
+ int fsname_len, num;
+ char realpath_buffer[MAXPATHLEN];
+ int buf_sz = 4096;
+
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ if (num == 0)
+ {
+ buf_sz = *(int*)mntctl_buffer;
+ free(mntctl_buffer);
+ mntctl_buffer = (struct vmount*)malloc(buf_sz);
+ num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer);
+ }
+
+ if (num > 0)
+ {
+ /* iterate through items in the vmount structure: */
+ vm = (struct vmount *)mntctl_buffer;
+ for ( ; num > 0; num-- )
+ {
+ /* get the name of the mounted file systems: */
+ fsname_len = vmt2datasize(vm, VMT_STUB);
+ mountedto = (char*)malloc(fsname_len + 1);
+ mountedto[fsname_len] = '\0';
+ strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len);
+
+ fsname_len = vmt2datasize(vm, VMT_OBJECT);
+ mountedfrom = (char*)malloc(fsname_len + 1);
+ mountedfrom[fsname_len] = '\0';
+ strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len);
+
+ /* get the mount-from information: */
+ TQCString device_name = mountedfrom;
+
+ if (realpath(device_name, realpath_buffer) != 0)
+ // success, use result from realpath
+ device_name = realpath_buffer;
+
+ /* Look up the string for the file system type,
+ * as listed in /etc/vfs.
+ * ex.: nfs,jfs,afs,cdrfs,sfs,cachefs,nfs3,autofs
+ */
+ struct vfs_ent* ent = getvfsbytype(vm->vmt_gfstype);
+
+ if ( is_my_mountpoint( mountedto, realname, max ) )
+ {
+ mountPoint = TQFile::decodeName(mountedto);
+ fstype = TQString::fromLatin1(ent->vfsent_name);
+ check_mount_point(ent->vfsent_name, device_name, isautofs, isslow);
+
+ if (ismanual == Unseen)
+ {
+ // TODO: add check for ismanual, I couldn't find any way
+ // how to get the mount attribute from /etc/filesystems
+ ismanual == Wrong;
+ }
+ }
+
+ free(mountedfrom);
+ free(mountedto);
+
+ /* goto the next vmount structure: */
+ vm = (struct vmount *)((char *)vm + vm->vmt_length);
+ }
+
+ endvfsent( );
+ }
+
+ free( mntctl_buffer );
+
+#else
+
+ STRUCT_SETMNTENT mtab;
+ /* Get the list of mounted file systems */
+
+ if ((mtab = SETMNTENT(MNTTAB, "r")) == 0) {
+ perror("setmntent");
+ return TQString::null;
+ }
+
+ STRUCT_MNTENT me;
+
+ while (true) {
+ if (!GETMNTENT(mtab, me))
+ break;
+
+ if ( is_my_mountpoint( MOUNTPOINT(me), realname, max ) )
+ {
+ mountPoint = TQFile::decodeName( MOUNTPOINT(me) );
+ fstype = MOUNTTYPE(me);
+ check_mount_point(MOUNTTYPE(me), FSNAME(me), isautofs, isslow);
+ // we don't check if ismanual is Right, if /a/b is manually
+ // mounted /a/b/c can't be automounted. At least IMO.
+ if (ismanual == Unseen)
+ {
+ // The next GETMNTENT call may destroy 'me'
+ // Copy out the info that we need
+ TQCString fsname_me = FSNAME(me);
+ TQCString mounttype_me = MOUNTTYPE(me);
+
+ STRUCT_SETMNTENT fstab;
+ if ((fstab = SETMNTENT(FSTAB, "r")) == 0) {
+ continue;
+ }
+
+ bool found = false;
+ STRUCT_MNTENT fe;
+ while (GETMNTENT(fstab, fe))
+ {
+ if (fsname_me == FSNAME(fe))
+ {
+ found = true;
+ if (HASMNTOPT(fe, "noauto") ||
+ !strcmp(MOUNTTYPE(fe), "supermount"))
+ ismanual = Right;
+ break;
+ }
+ }
+ if (!found || (mounttype_me == "supermount"))
+ ismanual = Right;
+
+ ENDMNTENT(fstab);
+ }
+ }
+ }
+
+ ENDMNTENT(mtab);
+
+#endif
+
+ if (isautofs == Right && isslow == Unseen)
+ isslow = Right;
+
+ if (gotDevice)
+ {
+ if (!cachedDevice)
+ cachedDevice = new cachedDevice_t;
+
+ cachedDevice->device = stat_buf.st_dev;
+ cachedDevice->mountPoint = mountPoint;
+ cachedDevice->isautofs = isautofs;
+ cachedDevice->isslow = isslow;
+ cachedDevice->ismanual = ismanual;
+ cachedDevice->fstype = fstype;
+ }
+
+ return mountPoint;
+}
+
+#else //!Q_OS_UNIX
+//dummy
+TQString TDEIO::findDeviceMountPoint( const TQString& filename )
+{
+ return TQString::null;
+}
+#endif
+
+TQString TDEIO::findPathMountPoint(const TQString& filename)
+{
+#ifdef Q_OS_UNIX
+ MountState isautofs = Unseen, isslow = Unseen, ismanual = Wrong;
+ TQString fstype;
+ return get_mount_info(filename, isautofs, isslow, ismanual, fstype);
+#else //!Q_OS_UNIX
+ return TQString::null;
+#endif
+}
+
+bool TDEIO::manually_mounted(const TQString& filename)
+{
+#ifdef Q_OS_UNIX
+ MountState isautofs = Unseen, isslow = Unseen, ismanual = Unseen;
+ TQString fstype;
+ TQString mountPoint = get_mount_info(filename, isautofs, isslow, ismanual, fstype);
+ return !mountPoint.isNull() && (ismanual == Right);
+#else //!Q_OS_UNIX
+ return false;
+#endif
+}
+
+bool TDEIO::probably_slow_mounted(const TQString& filename)
+{
+#ifdef Q_OS_UNIX
+ MountState isautofs = Unseen, isslow = Unseen, ismanual = Wrong;
+ TQString fstype;
+ TQString mountPoint = get_mount_info(filename, isautofs, isslow, ismanual, fstype);
+ return !mountPoint.isNull() && (isslow == Right);
+#else //!Q_OS_UNIX
+ return false;
+#endif
+}
+
+bool TDEIO::testFileSystemFlag(const TQString& filename, FileSystemFlag flag)
+{
+#ifdef Q_OS_UNIX
+ MountState isautofs = Unseen, isslow = Unseen, ismanual = Wrong;
+ TQString fstype;
+ TQString mountPoint = get_mount_info(filename, isautofs, isslow, ismanual, fstype);
+ kdDebug() << "testFileSystemFlag: fstype=" << fstype << endl;
+ if (mountPoint.isNull())
+ return false;
+ bool isMsDos = ( fstype == "msdos" || fstype == "fat" || fstype == "vfat" );
+ switch (flag) {
+ case SupportsChmod:
+ case SupportsChown:
+ case SupportsUTime:
+ case SupportsSymlinks:
+ return !isMsDos; // it's amazing the number of things FAT doesn't support :)
+ case CaseInsensitive:
+ return isMsDos;
+ }
+#endif
+ return false;
+}
+
+TDEIO::CacheControl TDEIO::parseCacheControl(const TQString &cacheControl)
+{
+ TQString tmp = cacheControl.lower();
+
+ if (tmp == "cacheonly")
+ return TDEIO::CC_CacheOnly;
+ if (tmp == "cache")
+ return TDEIO::CC_Cache;
+ if (tmp == "verify")
+ return TDEIO::CC_Verify;
+ if (tmp == "refresh")
+ return TDEIO::CC_Refresh;
+ if (tmp == "reload")
+ return TDEIO::CC_Reload;
+
+ kdDebug() << "unrecognized Cache control option:"<<cacheControl<<endl;
+ return TDEIO::CC_Verify;
+}
+
+TQString TDEIO::getCacheControlString(TDEIO::CacheControl cacheControl)
+{
+ if (cacheControl == TDEIO::CC_CacheOnly)
+ return "CacheOnly";
+ if (cacheControl == TDEIO::CC_Cache)
+ return "Cache";
+ if (cacheControl == TDEIO::CC_Verify)
+ return "Verify";
+ if (cacheControl == TDEIO::CC_Refresh)
+ return "Refresh";
+ if (cacheControl == TDEIO::CC_Reload)
+ return "Reload";
+ kdDebug() << "unrecognized Cache control enum value:"<<cacheControl<<endl;
+ return TQString::null;
+}
diff --git a/tdeio/tdeio/global.h b/tdeio/tdeio/global.h
new file mode 100644
index 000000000..44b9df616
--- /dev/null
+++ b/tdeio/tdeio/global.h
@@ -0,0 +1,547 @@
+/* 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 __kio_global_h__
+#define __kio_global_h__
+
+#include <tqstring.h>
+#include <tqvaluelist.h>
+#include <tqptrlist.h>
+#include <tqdatastream.h>
+#include <tqdatetime.h>
+#include <tqmap.h>
+
+#include <kurl.h>
+
+/**
+ * @short A namespace for KIO globals
+ *
+ */
+namespace TDEIO
+{
+ /// 64-bit file offset
+ typedef TQ_LLONG fileoffset_t;
+ /// 64-bit file size
+ typedef TQ_ULLONG filesize_t;
+
+ /**
+ * Converts @p size from bytes to the string representation.
+ *
+ * @param size size in bytes
+ * @return converted size as a string - e.g. 123.4 kB , 12.0 MB
+ */
+ TDEIO_EXPORT TQString convertSize( TDEIO::filesize_t size );
+
+ /**
+ * Converts @p size from bytes to a string representation with includes
+ * the size in bytes.
+ * e.g. 90 B, 240 B, 1.4 KB (1495 B), 2.6MB (2,734,344 B), 0 B
+ * @param size size in bytes
+ * @return converted size as a string - e.g. 1.4 KB (1495 B), 45 B
+ */
+ TDEIO_EXPORT TQString convertSizeWithBytes( TDEIO::filesize_t size );
+ /**
+ * Converts a size to a string representation
+ * Not unlike TQString::number(...)
+ *
+ * @param size size in bytes
+ * @return converted size as a string - e.g. 123456789
+ */
+ TDEIO_EXPORT TQString number( TDEIO::filesize_t size );
+
+ /**
+ * Converts size from kilo-bytes to the string representation.
+ *
+ * @param kbSize size in kilo-bytes
+ * @return converted size as a string - e.g. 123.4 kB , 12.0 MB
+ */
+ TDEIO_EXPORT TQString convertSizeFromKB( TDEIO::filesize_t kbSize );
+
+ /**
+ * Calculates remaining time in seconds from total size, processed size and speed.
+ *
+ * @param totalSize total size in bytes
+ * @param processedSize processed size in bytes
+ * @param speed speed in bytes per second
+ * @return calculated remaining time in seconds
+ *
+ * @since 3.4
+ */
+ TDEIO_EXPORT unsigned int calculateRemainingSeconds( TDEIO::filesize_t totalSize,
+ TDEIO::filesize_t processedSize, TDEIO::filesize_t speed );
+
+ /**
+ * Convert @p seconds to a string representing number of days, hours, minutes and seconds
+ *
+ * @param seconds number of seconds to convert
+ * @return string representation in a locale depending format
+ *
+ * @since 3.4
+ */
+ TDEIO_EXPORT TQString convertSeconds( unsigned int seconds );
+
+ /**
+ * Calculates remaining time from total size, processed size and speed.
+ * Warning: As TQTime is limited to 23:59:59, use calculateRemainingSeconds() instead
+ *
+ * @param totalSize total size in bytes
+ * @param processedSize processed size in bytes
+ * @param speed speed in bytes per second
+ * @return calculated remaining time
+ */
+ TDEIO_EXPORT TQTime calculateRemaining( TDEIO::filesize_t totalSize, TDEIO::filesize_t processedSize, TDEIO::filesize_t speed ) KDE_DEPRECATED;
+
+ /**
+ * Helper for showing information about a set of files and directories
+ * @param items the number of items (= @p files + @p dirs + number of symlinks :)
+ * @param files the number of files
+ * @param dirs the number of dirs
+ * @param size the sum of the size of the @p files
+ * @param showSize whether to show the size in the result
+ * @return the summary string
+ */
+ TDEIO_EXPORT TQString itemsSummaryString(uint items, uint files, uint dirs, TDEIO::filesize_t size, bool showSize);
+
+ /**
+ * Encodes (from the text displayed to the real filename)
+ * This translates % into %% and / into %2f
+ * Used by TDEIO::link, for instance.
+ * @param str the file name to encode
+ * @return the encoded file name
+ */
+ TDEIO_EXPORT TQString encodeFileName( const TQString & str );
+ /**
+ * Decodes (from the filename to the text displayed)
+ * This translates %2[fF] into / and %% into %
+ * @param str the file name to decode
+ * @return the decoded file name
+ */
+ TDEIO_EXPORT TQString decodeFileName( const TQString & str );
+
+ /**
+ * Commands that can be invoked by a job.
+ */
+ enum Command {
+ CMD_HOST = '0', // 48
+ CMD_CONNECT = '1', // 49
+ CMD_DISCONNECT = '2', // 50
+ CMD_SLAVE_STATUS = '3', // 51
+ CMD_SLAVE_CONNECT = '4', // 52
+ CMD_SLAVE_HOLD = '5', // 53
+ CMD_NONE = 'A', // 65
+ CMD_TESTDIR = 'B', // 66
+ CMD_GET = 'C', // 67
+ CMD_PUT = 'D', // 68
+ CMD_STAT = 'E', // 69
+ CMD_MIMETYPE = 'F', // 70
+ CMD_LISTDIR = 'G', // 71
+ CMD_MKDIR = 'H', // 72
+ CMD_RENAME = 'I', // 73
+ CMD_COPY = 'J', // 74
+ CMD_DEL = 'K', // 75
+ CMD_CHMOD = 'L', // 76
+ CMD_SPECIAL = 'M', // 77
+ CMD_USERPASS = 'N', // 78
+ CMD_REPARSECONFIGURATION = 'O', // 79
+ CMD_META_DATA = 'P', // 80
+ CMD_SYMLINK = 'Q', // 81
+ CMD_SUBURL = 'R', // 82 Inform the slave about the url it is streaming on.
+ CMD_MESSAGEBOXANSWER = 'S', // 83
+ CMD_RESUMEANSWER = 'T', // 84
+ CMD_CONFIG = 'U', // 85
+ CMD_MULTI_GET = 'V', // 86
+ CMD_LOCALURL = 'W' // 87
+ // Add new ones here once a release is done, to avoid breaking binary compatibility.
+ // Note that protocol-specific commands shouldn't be added here, but should use special.
+ };
+
+ /**
+ * Error codes that can be emitted by KIO.
+ */
+ enum Error {
+ ERR_CANNOT_OPEN_FOR_READING = 1,
+ ERR_CANNOT_OPEN_FOR_WRITING = 2,
+ ERR_CANNOT_LAUNCH_PROCESS = 3,
+ ERR_INTERNAL = 4,
+ ERR_MALFORMED_URL = 5,
+ ERR_UNSUPPORTED_PROTOCOL = 6,
+ ERR_NO_SOURCE_PROTOCOL = 7,
+ ERR_UNSUPPORTED_ACTION = 8,
+ ERR_IS_DIRECTORY = 9, // ... where a file was expected
+ ERR_IS_FILE = 10, // ... where a directory was expected (e.g. listing)
+ ERR_DOES_NOT_EXIST = 11,
+ ERR_FILE_ALREADY_EXIST = 12,
+ ERR_DIR_ALREADY_EXIST = 13,
+ ERR_UNKNOWN_HOST = 14,
+ ERR_ACCESS_DENIED = 15,
+ ERR_WRITE_ACCESS_DENIED = 16,
+ ERR_CANNOT_ENTER_DIRECTORY = 17,
+ ERR_PROTOCOL_IS_NOT_A_FILESYSTEM = 18,
+ ERR_CYCLIC_LINK = 19,
+ ERR_USER_CANCELED = 20,
+ ERR_CYCLIC_COPY = 21,
+ ERR_COULD_NOT_CREATE_SOCKET = 22, // KDE4: s/COULD_NOT/CANNOT/ or the other way round
+ ERR_COULD_NOT_CONNECT = 23,
+ ERR_CONNECTION_BROKEN = 24,
+ ERR_NOT_FILTER_PROTOCOL = 25,
+ ERR_COULD_NOT_MOUNT = 26,
+ ERR_COULD_NOT_UNMOUNT = 27,
+ ERR_COULD_NOT_READ = 28,
+ ERR_COULD_NOT_WRITE = 29,
+ ERR_COULD_NOT_BIND = 30,
+ ERR_COULD_NOT_LISTEN = 31,
+ ERR_COULD_NOT_ACCEPT = 32,
+ ERR_COULD_NOT_LOGIN = 33,
+ ERR_COULD_NOT_STAT = 34,
+ ERR_COULD_NOT_CLOSEDIR = 35,
+ ERR_COULD_NOT_MKDIR = 37,
+ ERR_COULD_NOT_RMDIR = 38,
+ ERR_CANNOT_RESUME = 39,
+ ERR_CANNOT_RENAME = 40,
+ ERR_CANNOT_CHMOD = 41,
+ ERR_CANNOT_DELETE = 42,
+ // The text argument is the protocol that the dead slave supported.
+ // This means for example: file, ftp, http, ...
+ ERR_SLAVE_DIED = 43,
+ ERR_OUT_OF_MEMORY = 44,
+ ERR_UNKNOWN_PROXY_HOST = 45,
+ ERR_COULD_NOT_AUTHENTICATE = 46,
+ ERR_ABORTED = 47, // Action got aborted from application side
+ ERR_INTERNAL_SERVER = 48,
+ ERR_SERVER_TIMEOUT = 49,
+ ERR_SERVICE_NOT_AVAILABLE = 50,
+ ERR_UNKNOWN = 51,
+ // (was a warning) ERR_CHECKSUM_MISMATCH = 52,
+ ERR_UNKNOWN_INTERRUPT = 53,
+ ERR_CANNOT_DELETE_ORIGINAL = 54,
+ ERR_CANNOT_DELETE_PARTIAL = 55,
+ ERR_CANNOT_RENAME_ORIGINAL = 56,
+ ERR_CANNOT_RENAME_PARTIAL = 57,
+ ERR_NEED_PASSWD = 58,
+ ERR_CANNOT_SYMLINK = 59,
+ ERR_NO_CONTENT = 60, // Action succeeded but no content will follow.
+ ERR_DISK_FULL = 61,
+ ERR_IDENTICAL_FILES = 62, // src==dest when moving/copying
+ ERR_SLAVE_DEFINED = 63, // for slave specified errors that can be
+ // rich text. Email links will be handled
+ // by the standard email app and all hrefs
+ // will be handled by the standard browser.
+ // <a href="exec:/khelpcenter ?" will be
+ // forked.
+ ERR_UPGRADE_REQUIRED = 64, // A transport upgrade is required to access this
+ // object. For instance, TLS is demanded by
+ // the server in order to continue.
+ ERR_POST_DENIED = 65, // Issued when trying to POST data to a certain Ports
+ // see job.cpp
+ ERR_OFFLINE_MODE = 66 // Used when an app is in offline mode and a
+ // requested document is unavailable.
+ };
+
+ /**
+ * Returns a translated error message for @p errorCode using the
+ * additional error information provided by @p errorText.
+ * @param errorCode the error code
+ * @param errorText the additional error text
+ * @return the created error string
+ */
+ TDEIO_EXPORT TQString buildErrorString(int errorCode, const TQString &errorText);
+
+ /**
+ * Returns a translated html error message for @p errorCode using the
+ * additional error information provided by @p errorText , @p reqUrl
+ * (the request URL), and the ioslave @p method .
+ * @param errorCode the error code
+ * @param errorText the additional error text
+ * @param reqUrl the request URL
+ * @param method the ioslave method
+ * @return the created error string
+ */
+ TDEIO_EXPORT TQString buildHTMLErrorString(int errorCode, const TQString &errorText,
+ const KURL *reqUrl = 0L, int method = -1 );
+
+ /**
+ * Returns translated error details for @p errorCode using the
+ * additional error information provided by @p errorText , @p reqUrl
+ * (the request URL), and the ioslave @p method .
+ *
+ * @param errorCode the error code
+ * @param errorText the additional error text
+ * @param reqUrl the request URL
+ * @param method the ioslave method
+ * @return the following data:
+ * @li TQString errorName - the name of the error
+ * @li TQString techName - if not null, the more technical name of the error
+ * @li TQString description - a description of the error
+ * @li TQStringList causes - a list of possible causes of the error
+ * @li TQStringList solutions - a liso of solutions for the error
+ */
+ TDEIO_EXPORT TQByteArray rawErrorDetail(int errorCode, const TQString &errorText,
+ const KURL *reqUrl = 0L, int method = -1 );
+
+ /**
+ * Returns an appropriate error message if the given command @p cmd
+ * is an unsupported action (ERR_UNSUPPORTED_ACTION).
+ * @param protocol name of the protocol
+ * @param cmd given command
+ * @see enum Command
+ * @since 3.2
+ */
+ TDEIO_EXPORT TQString unsupportedActionErrorString(const TQString &protocol, int cmd);
+
+ /**
+ * Constants used to specify the type of a KUDSAtom.
+ */
+ enum UDSAtomTypes {
+ /// First let's define the item types
+ UDS_STRING = 1,
+ UDS_LONG = 2,
+ UDS_TIME = 4 | UDS_LONG,
+
+ // To add new UDS entries below, you can use a step of 8
+ // (i.e. 8, 16, 24, 32, etc.) Only the last 3 bits are a bitfield,
+ // the rest isn't.
+
+ /// Size of the file
+ UDS_SIZE = 8 | UDS_LONG,
+ UDS_SIZE_LARGE = 32768 | UDS_LONG, // For internal use only
+ /// User ID of the file owner
+ UDS_USER = 16 | UDS_STRING,
+ /// Name of the icon, that should be used for displaying.
+ /// It overrides all other detection mechanisms
+ /// @since 3.2
+ UDS_ICON_NAME = 24 | UDS_STRING,
+ /// Group ID of the file owner
+ UDS_GROUP = 32 | UDS_STRING,
+ /// Extra data (used only if you specified Columns/ColumnsTypes)
+ /// This is the only UDS entry that can be repeated.
+ /// @since 3.2
+ UDS_EXTRA = 48 | UDS_STRING,
+ /// Filename - as displayed in directory listings etc.
+ /// "." has the usual special meaning of "current directory"
+ UDS_NAME = 64 | UDS_STRING,
+ /// A local file path if the ioslave display files sitting
+ /// on the local filesystem (but in another hierarchy, e.g. media:/)
+ UDS_LOCAL_PATH = 72 | UDS_STRING,
+ /// Treat the file as a hidden file or as a normal file,
+ /// regardless of (the absence of) a leading dot in the filename.
+ UDS_HIDDEN = 80 | UDS_LONG,
+ /// Indicates that the entry has extended ACL entries
+ /// @since 3.5
+ UDS_EXTENDED_ACL = 88 | UDS_LONG,
+ /// The access control list serialized into a single string.
+ /// @since 3.5
+ UDS_ACL_STRING = 96 | UDS_STRING,
+ /// The default access control list serialized into a single string.
+ /// Only available for directories.
+ /// @since 3.5
+ UDS_DEFAULT_ACL_STRING = 104 | UDS_STRING,
+
+ // available: 112, 120
+
+ /// Access permissions (part of the mode returned by stat)
+ UDS_ACCESS = 128 | UDS_LONG,
+ /// The last time the file was modified
+ UDS_MODIFICATION_TIME = 256 | UDS_TIME,
+ /// The last time the file was opened
+ UDS_ACCESS_TIME = 512 | UDS_TIME,
+ /// The time the file was created
+ UDS_CREATION_TIME = 1024 | UDS_TIME,
+ /// File type, part of the mode returned by stat
+ /// (for a link, this returns the file type of the pointed item)
+ /// check UDS_LINK_DEST to know if this is a link
+ UDS_FILE_TYPE = 2048 | UDS_LONG,
+ /// Name of the file where the link points to
+ /// Allows to check for a symlink (don't use S_ISLNK !)
+ UDS_LINK_DEST = 4096 | UDS_STRING,
+ /// An alternative URL (If different from the caption)
+ UDS_URL = 8192 | UDS_STRING,
+ /// A mime type; prevents guessing
+ UDS_MIME_TYPE = 16384 | UDS_STRING,
+ /// A mime type to be used for displaying only.
+ /// But when 'running' the file, the mimetype is re-determined
+ UDS_GUESSED_MIME_TYPE = 16392 | UDS_STRING,
+ /// XML properties, e.g. for WebDAV
+ /// @since 3.1
+ UDS_XML_PROPERTIES = 0x8000 | UDS_STRING
+ };
+
+ /**
+ * Specifies how to use the cache.
+ * @see parseCacheControl()
+ * @see getCacheControlString()
+ */
+ enum CacheControl
+ {
+ CC_CacheOnly, ///< Fail request if not in cache
+ CC_Cache, ///< Use cached entry if available
+ CC_Verify, ///< Validate cached entry with remote site if expired
+ CC_Refresh, ///< Always validate cached entry with remote site
+ ///< @since 3.1
+ CC_Reload ///< Always fetch from remote site.
+ };
+
+ /**
+ * Parses the string representation of the cache control option.
+ *
+ * @param cacheControl the string representation
+ * @return the cache control value
+ * @see getCacheControlString()
+ */
+ TDEIO_EXPORT TDEIO::CacheControl parseCacheControl(const TQString &cacheControl);
+
+ /**
+ * Returns a string representation of the given cache control method.
+ *
+ * @param cacheControl the cache control method
+ * @return the string representation
+ * @see parseCacheControl()
+ */
+ TDEIO_EXPORT TQString getCacheControlString(TDEIO::CacheControl cacheControl);
+
+ /**
+ * Returns the mount point where @p device is mounted
+ * right now. This means, it has to be mounted, not just
+ * defined in fstab.
+ */
+ TDEIO_EXPORT TQString findDeviceMountPoint( const TQString& device );
+
+ /**
+ * Returns the mount point on which resides @p filename.
+ * For instance if /home is a separate partition, findPathMountPoint("/home/user/blah")
+ * will return /home
+ * @param filename the file name to check
+ * @return the mount point of the given @p filename
+ */
+ TDEIO_EXPORT TQString findPathMountPoint( const TQString & filename );
+
+ /**
+ * Checks if the path belongs to a filesystem that is probably
+ * slow. It checks for NFS or for paths belonging to automounted
+ * paths not yet mounted
+ * @param filename the file name to check
+ * @return true if the filesystem is probably slow
+ */
+ TDEIO_EXPORT bool probably_slow_mounted(const TQString& filename);
+
+ /**
+ * Checks if the path belongs to a filesystem that is manually
+ * mounted.
+ * @param filename the file name to check
+ * @return true if the filesystem is manually mounted
+ */
+ TDEIO_EXPORT bool manually_mounted(const TQString& filename);
+
+ enum FileSystemFlag { SupportsChmod, SupportsChown, SupportsUTime,
+ SupportsSymlinks, CaseInsensitive };
+ /**
+ * Checks the capabilities of the filesystem to which a given file belongs.
+ * given feature (e.g. chmod).
+ * @param filename the file name to check
+ * @param flag the flag to check
+ * @return true if the filesystem has that flag, false if not (or some error occurred)
+ *
+ * The availables flags are:
+ * @li SupportsChmod: returns true if the filesystem supports chmod
+ * (e.g. msdos filesystems return false)
+ * @li SupportsChown: returns true if the filesystem supports chown
+ * (e.g. msdos filesystems return false)
+ * @li SupportsUtime: returns true if the filesystems supports utime
+ * (e.g. msdos filesystems return false)
+ * @li SupportsSymlinks: returns true if the filesystems supports symlinks
+ * (e.g. msdos filesystems return false)
+ * @li CaseInsensitive: returns true if the filesystem treats
+ * "foo" and "FOO" as being the same file (true for msdos systems)
+ *
+ */
+ TDEIO_EXPORT bool testFileSystemFlag(const TQString& filename, FileSystemFlag flag);
+
+
+/************
+ *
+ * Universal Directory Service
+ *
+ * Any file or URL can be represented by the UDSEntry type below
+ * A UDSEntry is a list of atoms
+ * Each atom contains a specific bit of information for the file
+ *
+ * The following UDS constants represent the different possible values
+ * for m_uds in the UDS atom structure below
+ *
+ * Each atom contains a specific bit of information for the file
+ */
+class TDEIO_EXPORT UDSAtom
+{
+public:
+ /**
+ * Whether 'm_str' or 'm_long' is used depends on the value of 'm_uds'.
+ */
+ TQString m_str;
+ /**
+ * Whether 'm_str' or 'm_long' is used depends on the value of 'm_uds'.
+ */
+ long long m_long;
+
+ /**
+ * Holds one of the UDS_XXX constants
+ */
+ unsigned int m_uds;
+};
+
+/**
+ * An entry is the list of atoms containing all the informations for a file or URL
+ */
+typedef TQValueList<UDSAtom> UDSEntry;
+typedef TQValueList<UDSEntry> UDSEntryList;
+typedef TQValueListIterator<UDSEntry> UDSEntryListIterator;
+typedef TQValueListConstIterator<UDSEntry> UDSEntryListConstIterator;
+
+/**
+ * MetaData is a simple map of key/value strings.
+ */
+class TDEIO_EXPORT MetaData : public TQMap<TQString, TQString>
+{
+public:
+ /**
+ * Creates an empty meta data map.
+ */
+ MetaData() : TQMap<TQString, TQString>() { };
+ /**
+ * Copy constructor.
+ */
+ MetaData(const TQMap<TQString, TQString>&metaData) :
+ TQMap<TQString, TQString>(metaData) { };
+
+ /**
+ * Adds the given meta data map to this map.
+ * @param metaData the map to add
+ * @return this map
+ */
+ MetaData & operator+= ( const TQMap<TQString,TQString> &metaData )
+ {
+ TQMap<TQString,TQString>::ConstIterator it;
+ for( it = metaData.begin();
+ it != metaData.end();
+ ++it)
+ {
+ replace(it.key(), it.data());
+ }
+ return *this;
+ }
+};
+
+}
+#endif
diff --git a/tdeio/tdeio/http_slave_defaults.h b/tdeio/tdeio/http_slave_defaults.h
new file mode 100644
index 000000000..e3247e39b
--- /dev/null
+++ b/tdeio/tdeio/http_slave_defaults.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE libraries
+ 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 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 _KIO_HTTP_SLAVE_DEFAULTS_H
+#define _KIO_HTTP_SLAVE_DEFAULTS_H
+
+// CONNECTION
+#define DEFAULT_KEEP_ALIVE_TIMEOUT 60 // 60 seconds
+
+// CACHE SETTINGS
+#define DEFAULT_MAX_CACHE_SIZE 5120 // 5 MB
+#define DEFAULT_MAX_CACHE_AGE 60*60*24*14 // 14 DAYS
+#define DEFAULT_CACHE_EXPIRE 3*60 // 3 MINS
+#define DEFAULT_CLEAN_CACHE_INTERVAL 30*60 // 30 MINS
+#define DEFAULT_CACHE_CONTROL TDEIO::CC_Refresh // Verify with remote
+#define CACHE_REVISION "7\n" // Cache version
+
+// DEFAULT USER AGENT KEY - ENABLES OS NAME
+#define DEFAULT_USER_AGENT_KEYS "o" // Show OS
+
+// MAXIMUM AMOUNT OF DATA THAT CAN BE SAFELY SENT OVER IPC
+#define MAX_IPC_SIZE 1024*8
+
+// AMOUNT OF DATA TO OBTAIN FROM THE SERVER BY DEFAULT
+#define DEFAULT_BUF_SIZE 1024*4
+
+// SOME DEFAULT HEADER VALUES
+#define DEFAULT_LANGUAGE_HEADER "en"
+#define DEFAULT_MIME_TYPE "text/html"
+#define DEFAULT_PARTIAL_CHARSET_HEADER ", utf-8;q=0.5, *;q=0.5"
+
+#define DEFAULT_ACCEPT_HEADER "text/html, image/jpeg, image/png, text/*, image/*, */*"
+
+#endif
diff --git a/tdeio/tdeio/ioslave_defaults.h b/tdeio/tdeio/ioslave_defaults.h
new file mode 100644
index 000000000..ddf5b6af5
--- /dev/null
+++ b/tdeio/tdeio/ioslave_defaults.h
@@ -0,0 +1,53 @@
+/* This file is part of the KDE libraries
+ 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 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 _KIO_IOSLAVE_DEFAULTS_H
+#define _KIO_IOSLAVE_DEFAULTS_H
+
+// TIMEOUT VALUES
+#define DEFAULT_RESPONSE_TIMEOUT 600 // 10 min.
+#define DEFAULT_CONNECT_TIMEOUT 20 // 20 secs.
+#define DEFAULT_READ_TIMEOUT 15 // 15 secs.
+#define DEFAULT_PROXY_CONNECT_TIMEOUT 10 // 10 secs.
+#define MIN_TIMEOUT_VALUE 2 // 2 secs.
+
+// MINMUM SIZE FOR ABORTED DOWNLOAD TO BE KEPT
+#define DEFAULT_MINIMUM_KEEP_SIZE 5120 // 5 Kbs
+
+// NORMAL PORT DEFAULTS
+#define DEFAULT_FTP_PORT 21
+#define DEFAULT_SMTP_PORT 25
+#define DEFAULT_HTTP_PORT 80
+#define DEFAULT_POP3_PORT 110
+#define DEFAULT_NNTP_PORT 119
+#define DEFAULT_IMAP_PORT 143
+#define DEFAULT_IMAP3_PORT 220
+#define DEFAULT_LDAP_PORT 389
+
+// SECURE PORT DEFAULTS
+#define DEFAULT_HTTPS_PORT 443
+#define DEFAULT_NNTPS_PORT 563
+#define DEFAULT_LDAPS_PORT 389
+#define DEFAULT_IMAPS_PORT 993
+#define DEFAULT_POP3S_PORT 995
+
+// OTHER GENERIC PORT DEFAULTS
+#define DEFAULT_PROXY_PORT 8080
+#define MAX_PORT_VALUE 65535
+
+#endif
diff --git a/tdeio/tdeio/job.cpp b/tdeio/tdeio/job.cpp
new file mode 100644
index 000000000..7bea676c5
--- /dev/null
+++ b/tdeio/tdeio/job.cpp
@@ -0,0 +1,4814 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ David Faure <faure@kde.org>
+ 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.
+*/
+
+#include "tdeio/job.h"
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+}
+#include <tqtimer.h>
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+#include <kdatastream.h>
+#include <kmainwindow.h>
+#include <kde_file.h>
+
+#include <errno.h>
+
+#include "kmimetype.h"
+#include "slave.h"
+#include "scheduler.h"
+#include "kdirwatch.h"
+#include "kmimemagic.h"
+#include "kprotocolinfo.h"
+#include "kprotocolmanager.h"
+
+#include "tdeio/observer.h"
+
+#include "kssl/ksslcsessioncache.h"
+
+#include <kdirnotify_stub.h>
+#include <ktempfile.h>
+#include <dcopclient.h>
+
+#ifdef Q_OS_UNIX
+#include <utime.h>
+#endif
+#if defined Q_WS_X11
+#include <netwm.h>
+#include <fixx11h.h>
+#endif
+
+using namespace TDEIO;
+template class TQPtrList<TDEIO::Job>;
+
+//this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
+#define REPORT_TIMEOUT 200
+
+#define KIO_ARGS TQByteArray packedArgs; TQDataStream stream( packedArgs, IO_WriteOnly ); stream
+
+class Job::JobPrivate
+{
+public:
+ JobPrivate() : m_autoErrorHandling( false ), m_autoWarningHandling( true ),
+ m_interactive( true ), m_parentJob( 0L ), m_extraFlags(0),
+ m_processedSize(0), m_userTimestamp(0)
+ {}
+
+ bool m_autoErrorHandling;
+ bool m_autoWarningHandling;
+ bool m_interactive;
+ TQGuardedPtr<TQWidget> m_errorParentWidget;
+ // Maybe we could use the TQObject parent/child mechanism instead
+ // (requires a new ctor, and moving the ctor code to some init()).
+ Job* m_parentJob;
+ int m_extraFlags;
+ TDEIO::filesize_t m_processedSize;
+ unsigned long m_userTimestamp;
+};
+
+Job::Job(bool showProgressInfo) : TQObject(0, "job"), m_error(0), m_percent(0)
+ , m_progressId(0), m_speedTimer(0), d( new JobPrivate )
+{
+ // All jobs delete themselves after emiting 'result'.
+
+ // Notify the UI Server and get a progress id
+ if ( showProgressInfo )
+ {
+ m_progressId = Observer::self()->newJob( this, true );
+ addMetaData("progress-id", TQString::number(m_progressId));
+ //kdDebug(7007) << "Created job " << this << " with progress info -- m_progressId=" << m_progressId << endl;
+ // Connect global progress info signals
+ connect( this, TQT_SIGNAL( percent( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) );
+ connect( this, TQT_SIGNAL( infoMessage( TDEIO::Job*, const TQString & ) ),
+ Observer::self(), TQT_SLOT( slotInfoMessage( TDEIO::Job*, const TQString & ) ) );
+ connect( this, TQT_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ Observer::self(), TQT_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( this, TQT_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ Observer::self(), TQT_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( this, TQT_SIGNAL( speed( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotSpeed( TDEIO::Job*, unsigned long ) ) );
+ }
+ // Don't exit while this job is running
+ if (kapp)
+ kapp->ref();
+ if (kapp)
+ updateUserTimestamp( kapp->userTimestamp());
+}
+
+Job::~Job()
+{
+ delete m_speedTimer;
+ delete d;
+ if (kapp)
+ kapp->deref();
+}
+
+int& Job::extraFlags()
+{
+ return d->m_extraFlags;
+}
+
+void Job::setProcessedSize(TDEIO::filesize_t size)
+{
+ d->m_processedSize = size;
+}
+
+TDEIO::filesize_t Job::getProcessedSize()
+{
+ return d->m_processedSize;
+}
+
+void Job::addSubjob(Job *job, bool inheritMetaData)
+{
+ //kdDebug(7007) << "addSubjob(" << job << ") this = " << this << endl;
+ subjobs.append(job);
+
+ connect( job, TQT_SIGNAL(result(TDEIO::Job*)),
+ TQT_SLOT(slotResult(TDEIO::Job*)) );
+
+ // Forward information from that subjob.
+ connect( job, TQT_SIGNAL(speed( TDEIO::Job*, unsigned long )),
+ TQT_SLOT(slotSpeed(TDEIO::Job*, unsigned long)) );
+
+ connect( job, TQT_SIGNAL(infoMessage( TDEIO::Job*, const TQString & )),
+ TQT_SLOT(slotInfoMessage(TDEIO::Job*, const TQString &)) );
+
+ if (inheritMetaData)
+ job->mergeMetaData(m_outgoingMetaData);
+
+ job->setWindow( m_window );
+ job->updateUserTimestamp( d->m_userTimestamp );
+}
+
+void Job::removeSubjob( Job *job )
+{
+ removeSubjob( job, false, true );
+}
+
+void Job::removeSubjob( Job *job, bool mergeMetaData, bool emitResultIfLast )
+{
+ //kdDebug(7007) << "removeSubjob(" << job << ") this = " << this << " subjobs = " << subjobs.count() << endl;
+ // Merge metadata from subjob
+ if ( mergeMetaData )
+ m_incomingMetaData += job->metaData();
+ subjobs.remove(job);
+ if ( subjobs.isEmpty() && emitResultIfLast )
+ emitResult();
+}
+
+void Job::emitPercent( TDEIO::filesize_t processedSize, TDEIO::filesize_t totalSize )
+{
+ // calculate percents
+ unsigned long ipercent = m_percent;
+
+ if ( totalSize == 0 )
+ m_percent = 100;
+ else
+ m_percent = (unsigned long)(( (float)(processedSize) / (float)(totalSize) ) * 100.0);
+
+ if ( m_percent != ipercent || m_percent == 100 /* for those buggy total sizes that grow */ ) {
+ emit percent( this, m_percent );
+ //kdDebug(7007) << "Job::emitPercent - percent = " << (unsigned int) m_percent << endl;
+ }
+}
+
+void Job::emitSpeed( unsigned long bytes_per_second )
+{
+ //kdDebug(7007) << "Job " << this << " emitSpeed " << bytes_per_second << endl;
+ if ( !m_speedTimer )
+ {
+ m_speedTimer = new TQTimer();
+ connect( m_speedTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotSpeedTimeout() ) );
+ }
+ emit speed( this, bytes_per_second );
+ m_speedTimer->start( 5000 ); // 5 seconds interval should be enough
+}
+
+void Job::emitResult()
+{
+ // If we are displaying a progress dialog, remove it first.
+ if ( m_progressId ) // Did we get an ID from the observer ?
+ Observer::self()->jobFinished( m_progressId );
+ if ( m_error && d->m_interactive && d->m_autoErrorHandling )
+ showErrorDialog( d->m_errorParentWidget );
+ emit result(this);
+ deleteLater();
+}
+
+void Job::kill( bool quietly )
+{
+ kdDebug(7007) << "Job::kill this=" << this << " " << className() << " m_progressId=" << m_progressId << " quietly=" << quietly << endl;
+ // kill all subjobs, without triggering their result slot
+ TQPtrListIterator<Job> it( subjobs );
+ for ( ; it.current() ; ++it )
+ (*it)->kill( true );
+ subjobs.clear();
+
+ if ( ! quietly ) {
+ m_error = ERR_USER_CANCELED;
+ emit canceled( this ); // Not very useful (deprecated)
+ emitResult();
+ } else
+ {
+ if ( m_progressId ) // in both cases we want to hide the progress window
+ Observer::self()->jobFinished( m_progressId );
+ deleteLater();
+ }
+}
+
+void Job::slotResult( Job *job )
+{
+ // Did job have an error ?
+ if ( job->error() && !m_error )
+ {
+ // Store it in the parent only if first error
+ m_error = job->error();
+ m_errorText = job->errorText();
+ }
+ removeSubjob(job);
+}
+
+void Job::slotSpeed( TDEIO::Job*, unsigned long speed )
+{
+ //kdDebug(7007) << "Job::slotSpeed " << speed << endl;
+ emitSpeed( speed );
+}
+
+void Job::slotInfoMessage( TDEIO::Job*, const TQString & msg )
+{
+ emit infoMessage( this, msg );
+}
+
+void Job::slotSpeedTimeout()
+{
+ //kdDebug(7007) << "slotSpeedTimeout()" << endl;
+ // send 0 and stop the timer
+ // timer will be restarted only when we receive another speed event
+ emit speed( this, 0 );
+ m_speedTimer->stop();
+}
+
+//Job::errorString is implemented in global.cpp
+
+void Job::showErrorDialog( TQWidget * parent )
+{
+ //kdDebug(7007) << "Job::showErrorDialog parent=" << parent << endl;
+ kapp->enableStyles();
+ // Show a message box, except for "user canceled" or "no content"
+ if ( (m_error != ERR_USER_CANCELED) && (m_error != ERR_NO_CONTENT) ) {
+ //old plain error message
+ //kdDebug(7007) << "Default language: " << TDEGlobal::locale()->defaultLanguage() << endl;
+ if ( 1 )
+ KMessageBox::queuedMessageBox( parent, KMessageBox::Error, errorString() );
+#if 0
+ } else {
+ TQStringList errors = detailedErrorStrings();
+ TQString caption, err, detail;
+ TQStringList::const_iterator it = errors.begin();
+ if ( it != errors.end() )
+ caption = *(it++);
+ if ( it != errors.end() )
+ err = *(it++);
+ if ( it != errors.end() )
+ detail = *it;
+ KMessageBox::queuedDetailedError( parent, err, detail, caption );
+ }
+#endif
+ }
+}
+
+void Job::setAutoErrorHandlingEnabled( bool enable, TQWidget *parentWidget )
+{
+ d->m_autoErrorHandling = enable;
+ d->m_errorParentWidget = parentWidget;
+}
+
+bool Job::isAutoErrorHandlingEnabled() const
+{
+ return d->m_autoErrorHandling;
+}
+
+void Job::setAutoWarningHandlingEnabled( bool enable )
+{
+ d->m_autoWarningHandling = enable;
+}
+
+bool Job::isAutoWarningHandlingEnabled() const
+{
+ return d->m_autoWarningHandling;
+}
+
+void Job::setInteractive(bool enable)
+{
+ d->m_interactive = enable;
+}
+
+bool Job::isInteractive() const
+{
+ return d->m_interactive;
+}
+
+void Job::setWindow(TQWidget *window)
+{
+ m_window = window;
+ TDEIO::Scheduler::registerWindow(window);
+}
+
+TQWidget *Job::window() const
+{
+ return m_window;
+}
+
+void Job::updateUserTimestamp( unsigned long time )
+{
+#if defined Q_WS_X11
+ if( d->m_userTimestamp == 0 || NET::timestampCompare( time, d->m_userTimestamp ) > 0 )
+ d->m_userTimestamp = time;
+#endif
+}
+
+unsigned long Job::userTimestamp() const
+{
+ return d->m_userTimestamp;
+}
+
+void Job::setParentJob(Job* job)
+{
+ Q_ASSERT(d->m_parentJob == 0L);
+ Q_ASSERT(job);
+ d->m_parentJob = job;
+}
+
+Job* Job::parentJob() const
+{
+ return d->m_parentJob;
+}
+
+MetaData Job::metaData() const
+{
+ return m_incomingMetaData;
+}
+
+TQString Job::queryMetaData(const TQString &key)
+{
+ if (!m_incomingMetaData.contains(key))
+ return TQString::null;
+ return m_incomingMetaData[key];
+}
+
+void Job::setMetaData( const TDEIO::MetaData &_metaData)
+{
+ m_outgoingMetaData = _metaData;
+}
+
+void Job::addMetaData( const TQString &key, const TQString &value)
+{
+ m_outgoingMetaData.insert(key, value);
+}
+
+void Job::addMetaData( const TQMap<TQString,TQString> &values)
+{
+ TQMapConstIterator<TQString,TQString> it = values.begin();
+ for(;it != values.end(); ++it)
+ m_outgoingMetaData.insert(it.key(), it.data());
+}
+
+void Job::mergeMetaData( const TQMap<TQString,TQString> &values)
+{
+ TQMapConstIterator<TQString,TQString> it = values.begin();
+ for(;it != values.end(); ++it)
+ m_outgoingMetaData.insert(it.key(), it.data(), false);
+}
+
+MetaData Job::outgoingMetaData() const
+{
+ return m_outgoingMetaData;
+}
+
+
+SimpleJob::SimpleJob(const KURL& url, int command, const TQByteArray &packedArgs,
+ bool showProgressInfo )
+ : Job(showProgressInfo), m_slave(0), m_packedArgs(packedArgs),
+ m_url(url), m_command(command), m_totalSize(0)
+{
+ if (m_url.hasSubURL())
+ {
+ KURL::List list = KURL::split(m_url);
+ KURL::List::Iterator it = list.fromLast();
+ list.remove(it);
+ m_subUrl = KURL::join(list);
+ //kdDebug(7007) << "New URL = " << m_url.url() << endl;
+ //kdDebug(7007) << "Sub URL = " << m_subUrl.url() << endl;
+ }
+
+ Scheduler::doJob(this);
+
+ if (!m_url.isValid())
+ {
+ kdDebug() << "ERR_MALFORMED_URL" << endl;
+ m_error = ERR_MALFORMED_URL;
+ m_errorText = m_url.url();
+ TQTimer::singleShot(0, this, TQT_SLOT(slotFinished()) );
+ return;
+ }
+}
+
+void SimpleJob::kill( bool quietly )
+{
+ Scheduler::cancelJob( this ); // deletes the slave if not 0
+ m_slave = 0; // -> set to 0
+ Job::kill( quietly );
+}
+
+void SimpleJob::putOnHold()
+{
+ Q_ASSERT( m_slave );
+ if ( m_slave )
+ {
+ Scheduler::putSlaveOnHold(this, m_url);
+ m_slave = 0;
+ }
+ kill(true);
+}
+
+void SimpleJob::removeOnHold()
+{
+ Scheduler::removeSlaveOnHold();
+}
+
+SimpleJob::~SimpleJob()
+{
+ if (m_slave) // was running
+ {
+ kdDebug(7007) << "SimpleJob::~SimpleJob: Killing running job in destructor!" << endl;
+#if 0
+ m_slave->kill();
+ Scheduler::jobFinished( this, m_slave ); // deletes the slave
+#endif
+ Scheduler::cancelJob( this );
+ m_slave = 0; // -> set to 0
+ }
+}
+
+void SimpleJob::start(Slave *slave)
+{
+ m_slave = slave;
+
+ connect( m_slave, TQT_SIGNAL( error( int , const TQString & ) ),
+ TQT_SLOT( slotError( int , const TQString & ) ) );
+
+ connect( m_slave, TQT_SIGNAL( warning( const TQString & ) ),
+ TQT_SLOT( slotWarning( const TQString & ) ) );
+
+ connect( m_slave, TQT_SIGNAL( infoMessage( const TQString & ) ),
+ TQT_SLOT( slotInfoMessage( const TQString & ) ) );
+
+ connect( m_slave, TQT_SIGNAL( connected() ),
+ TQT_SLOT( slotConnected() ) );
+
+ connect( m_slave, TQT_SIGNAL( finished() ),
+ TQT_SLOT( slotFinished() ) );
+
+ if ((extraFlags() & EF_TransferJobDataSent) == 0)
+ {
+ connect( m_slave, TQT_SIGNAL( totalSize( TDEIO::filesize_t ) ),
+ TQT_SLOT( slotTotalSize( TDEIO::filesize_t ) ) );
+
+ connect( m_slave, TQT_SIGNAL( processedSize( TDEIO::filesize_t ) ),
+ TQT_SLOT( slotProcessedSize( TDEIO::filesize_t ) ) );
+
+ connect( m_slave, TQT_SIGNAL( speed( unsigned long ) ),
+ TQT_SLOT( slotSpeed( unsigned long ) ) );
+ }
+
+ connect( slave, TQT_SIGNAL( needProgressId() ),
+ TQT_SLOT( slotNeedProgressId() ) );
+
+ connect( slave, TQT_SIGNAL(metaData( const TDEIO::MetaData& ) ),
+ TQT_SLOT( slotMetaData( const TDEIO::MetaData& ) ) );
+
+ if (m_window)
+ {
+ TQString id;
+ addMetaData("window-id", id.setNum((ulong)m_window->winId()));
+ }
+ if (userTimestamp())
+ {
+ TQString id;
+ addMetaData("user-timestamp", id.setNum(userTimestamp()));
+ }
+
+ TQString sslSession = KSSLCSessionCache::getSessionForURL(m_url);
+ if ( !sslSession.isNull() )
+ {
+ addMetaData("ssl_session_id", sslSession);
+ }
+
+ if (!isInteractive())
+ {
+ addMetaData("no-auth-prompt", "true");
+ }
+
+ if (!m_outgoingMetaData.isEmpty())
+ {
+ KIO_ARGS << m_outgoingMetaData;
+ slave->send( CMD_META_DATA, packedArgs );
+ }
+
+ if (!m_subUrl.isEmpty())
+ {
+ KIO_ARGS << m_subUrl;
+ m_slave->send( CMD_SUBURL, packedArgs );
+ }
+
+ m_slave->send( m_command, m_packedArgs );
+}
+
+void SimpleJob::slaveDone()
+{
+ if (!m_slave) return;
+ disconnect(m_slave); // Remove all signals between slave and job
+ Scheduler::jobFinished( this, m_slave );
+ m_slave = 0;
+}
+
+void SimpleJob::slotFinished( )
+{
+ // Return slave to the scheduler
+ slaveDone();
+
+ if (subjobs.isEmpty())
+ {
+ if ( !m_error && (m_command == CMD_MKDIR || m_command == CMD_RENAME ) )
+ {
+ KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
+ if ( m_command == CMD_MKDIR )
+ {
+ KURL urlDir( url() );
+ urlDir.setPath( urlDir.directory() );
+ allDirNotify.FilesAdded( urlDir );
+ }
+ else /*if ( m_command == CMD_RENAME )*/
+ {
+ KURL src, dst;
+ TQDataStream str( m_packedArgs, IO_ReadOnly );
+ str >> src >> dst;
+ if ( src.directory() == dst.directory() ) // For the user, moving isn't renaming. Only renaming is.
+ allDirNotify.FileRenamed( src, dst );
+ }
+ }
+ emitResult();
+ }
+}
+
+void SimpleJob::slotError( int error, const TQString & errorText )
+{
+ m_error = error;
+ m_errorText = errorText;
+ if ((m_error == ERR_UNKNOWN_HOST) && m_url.host().isEmpty())
+ m_errorText = TQString::null;
+ // error terminates the job
+ slotFinished();
+}
+
+void SimpleJob::slotWarning( const TQString & errorText )
+{
+ TQGuardedPtr<SimpleJob> guard( this );
+ if (isInteractive() && isAutoWarningHandlingEnabled())
+ {
+ static uint msgBoxDisplayed = 0;
+ if ( msgBoxDisplayed == 0 ) // don't bomb the user with message boxes, only one at a time
+ {
+ msgBoxDisplayed++;
+ KMessageBox::information( 0L, errorText );
+ msgBoxDisplayed--;
+ }
+ // otherwise just discard it.
+ }
+
+ if ( !guard.isNull() )
+ emit warning( this, errorText );
+}
+
+void SimpleJob::slotInfoMessage( const TQString & msg )
+{
+ emit infoMessage( this, msg );
+}
+
+void SimpleJob::slotConnected()
+{
+ emit connected( this );
+}
+
+void SimpleJob::slotNeedProgressId()
+{
+ if ( !m_progressId )
+ m_progressId = Observer::self()->newJob( this, false );
+ m_slave->setProgressId( m_progressId );
+}
+
+void SimpleJob::slotTotalSize( TDEIO::filesize_t size )
+{
+ if (size > m_totalSize)
+ {
+ m_totalSize = size;
+ emit totalSize( this, size );
+ }
+}
+
+void SimpleJob::slotProcessedSize( TDEIO::filesize_t size )
+{
+ //kdDebug(7007) << "SimpleJob::slotProcessedSize " << TDEIO::number(size) << endl;
+ setProcessedSize(size);
+ emit processedSize( this, size );
+ if ( size > m_totalSize ) {
+ slotTotalSize(size); // safety
+ }
+ emitPercent( size, m_totalSize );
+}
+
+void SimpleJob::slotSpeed( unsigned long speed )
+{
+ //kdDebug(7007) << "SimpleJob::slotSpeed( " << speed << " )" << endl;
+ emitSpeed( speed );
+}
+
+void SimpleJob::slotMetaData( const TDEIO::MetaData &_metaData)
+{
+ m_incomingMetaData += _metaData;
+}
+
+void SimpleJob::storeSSLSessionFromJob(const KURL &m_redirectionURL) {
+ TQString sslSession = queryMetaData("ssl_session_id");
+
+ if ( !sslSession.isNull() ) {
+ const KURL &queryURL = m_redirectionURL.isEmpty()?m_url:m_redirectionURL;
+ KSSLCSessionCache::putSessionForURL(queryURL, sslSession);
+ }
+}
+
+//////////
+MkdirJob::MkdirJob( const KURL& url, int command,
+ const TQByteArray &packedArgs, bool showProgressInfo )
+ : SimpleJob(url, command, packedArgs, showProgressInfo)
+{
+}
+
+void MkdirJob::start(Slave *slave)
+{
+ connect( slave, TQT_SIGNAL( redirection(const KURL &) ),
+ TQT_SLOT( slotRedirection(const KURL &) ) );
+
+ SimpleJob::start(slave);
+}
+
+// Slave got a redirection request
+void MkdirJob::slotRedirection( const KURL &url)
+{
+ kdDebug(7007) << "MkdirJob::slotRedirection(" << url << ")" << endl;
+ if (!kapp->authorizeURLAction("redirect", m_url, url))
+ {
+ kdWarning(7007) << "MkdirJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
+ m_error = ERR_ACCESS_DENIED;
+ m_errorText = url.prettyURL();
+ return;
+ }
+ m_redirectionURL = url; // We'll remember that when the job finishes
+ if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
+ m_redirectionURL.setUser(m_url.user()); // Preserve user
+ // Tell the user that we haven't finished yet
+ emit redirection(this, m_redirectionURL);
+}
+
+void MkdirJob::slotFinished()
+{
+ if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
+ {
+ // Return slave to the scheduler
+ SimpleJob::slotFinished();
+ } else {
+ //kdDebug(7007) << "MkdirJob: Redirection to " << m_redirectionURL << endl;
+ if (queryMetaData("permanent-redirect")=="true")
+ emit permanentRedirection(this, m_url, m_redirectionURL);
+ KURL dummyUrl;
+ int permissions;
+ TQDataStream istream( m_packedArgs, IO_ReadOnly );
+ istream >> dummyUrl >> permissions;
+
+ m_url = m_redirectionURL;
+ m_redirectionURL = KURL();
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url << permissions;
+
+ // Return slave to the scheduler
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+}
+
+SimpleJob *TDEIO::mkdir( const KURL& url, int permissions )
+{
+ //kdDebug(7007) << "mkdir " << url << endl;
+ KIO_ARGS << url << permissions;
+ return new MkdirJob(url, CMD_MKDIR, packedArgs, false);
+}
+
+SimpleJob *TDEIO::rmdir( const KURL& url )
+{
+ //kdDebug(7007) << "rmdir " << url << endl;
+ KIO_ARGS << url << TQ_INT8(false); // isFile is false
+ return new SimpleJob(url, CMD_DEL, packedArgs, false);
+}
+
+SimpleJob *TDEIO::chmod( const KURL& url, int permissions )
+{
+ //kdDebug(7007) << "chmod " << url << endl;
+ KIO_ARGS << url << permissions;
+ return new SimpleJob(url, CMD_CHMOD, packedArgs, false);
+}
+
+SimpleJob *TDEIO::rename( const KURL& src, const KURL & dest, bool overwrite )
+{
+ //kdDebug(7007) << "rename " << src << " " << dest << endl;
+ KIO_ARGS << src << dest << (TQ_INT8) overwrite;
+ return new SimpleJob(src, CMD_RENAME, packedArgs, false);
+}
+
+SimpleJob *TDEIO::symlink( const TQString& target, const KURL & dest, bool overwrite, bool showProgressInfo )
+{
+ //kdDebug(7007) << "symlink target=" << target << " " << dest << endl;
+ KIO_ARGS << target << dest << (TQ_INT8) overwrite;
+ return new SimpleJob(dest, CMD_SYMLINK, packedArgs, showProgressInfo);
+}
+
+SimpleJob *TDEIO::special(const KURL& url, const TQByteArray & data, bool showProgressInfo)
+{
+ //kdDebug(7007) << "special " << url << endl;
+ return new SimpleJob(url, CMD_SPECIAL, data, showProgressInfo);
+}
+
+SimpleJob *TDEIO::mount( bool ro, const char *fstype, const TQString& dev, const TQString& point, bool showProgressInfo )
+{
+ KIO_ARGS << int(1) << TQ_INT8( ro ? 1 : 0 )
+ << TQString::fromLatin1(fstype) << dev << point;
+ SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
+ if ( showProgressInfo )
+ Observer::self()->mounting( job, dev, point );
+ return job;
+}
+
+SimpleJob *TDEIO::unmount( const TQString& point, bool showProgressInfo )
+{
+ KIO_ARGS << int(2) << point;
+ SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
+ if ( showProgressInfo )
+ Observer::self()->unmounting( job, point );
+ return job;
+}
+
+//////////
+LocalURLJob::LocalURLJob( const KURL& url, int command,
+ const TQByteArray &packedArgs, bool showProgressInfo )
+ : SimpleJob(url, command, packedArgs, showProgressInfo)
+{
+
+}
+
+void LocalURLJob::start(Slave *slave)
+{
+ connect( slave, TQT_SIGNAL( localURL(const KURL &, bool) ),
+ TQT_SLOT( slotLocalURL(const KURL &, bool) ) );
+
+ SimpleJob::start(slave);
+}
+
+// Slave sent a response!
+void LocalURLJob::slotLocalURL(const KURL &url, bool isLocal)
+{
+ kdDebug(7007) << "LocalURLJob::slotLocalURL(" << url << ")" << endl;
+ emit localURL(this, url, isLocal);
+}
+
+void LocalURLJob::slotFinished()
+{
+ // Return slave to the scheduler
+ SimpleJob::slotFinished();
+}
+
+LocalURLJob *TDEIO::localURL( const KURL& remoteUrl )
+{
+ KIO_ARGS << remoteUrl;
+ return new LocalURLJob(remoteUrl, CMD_LOCALURL, packedArgs, false);
+}
+
+
+//////////
+
+StatJob::StatJob( const KURL& url, int command,
+ const TQByteArray &packedArgs, bool showProgressInfo )
+ : SimpleJob(url, command, packedArgs, showProgressInfo),
+ m_bSource(true), m_details(2)
+{
+}
+
+void StatJob::start(Slave *slave)
+{
+ m_outgoingMetaData.replace( "statSide", m_bSource ? "source" : "dest" );
+ m_outgoingMetaData.replace( "details", TQString::number(m_details) );
+
+ connect( slave, TQT_SIGNAL( statEntry( const TDEIO::UDSEntry& ) ),
+ TQT_SLOT( slotStatEntry( const TDEIO::UDSEntry & ) ) );
+ connect( slave, TQT_SIGNAL( redirection(const KURL &) ),
+ TQT_SLOT( slotRedirection(const KURL &) ) );
+
+ SimpleJob::start(slave);
+}
+
+void StatJob::slotStatEntry( const TDEIO::UDSEntry & entry )
+{
+ //kdDebug(7007) << "StatJob::slotStatEntry" << endl;
+ m_statResult = entry;
+}
+
+// Slave got a redirection request
+void StatJob::slotRedirection( const KURL &url)
+{
+ kdDebug(7007) << "StatJob::slotRedirection(" << url << ")" << endl;
+ if (!kapp->authorizeURLAction("redirect", m_url, url))
+ {
+ kdWarning(7007) << "StatJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
+ m_error = ERR_ACCESS_DENIED;
+ m_errorText = url.prettyURL();
+ return;
+ }
+ m_redirectionURL = url; // We'll remember that when the job finishes
+ if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
+ m_redirectionURL.setUser(m_url.user()); // Preserve user
+ // Tell the user that we haven't finished yet
+ emit redirection(this, m_redirectionURL);
+}
+
+void StatJob::slotFinished()
+{
+ if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
+ {
+ // Return slave to the scheduler
+ SimpleJob::slotFinished();
+ } else {
+ //kdDebug(7007) << "StatJob: Redirection to " << m_redirectionURL << endl;
+ if (queryMetaData("permanent-redirect")=="true")
+ emit permanentRedirection(this, m_url, m_redirectionURL);
+ m_url = m_redirectionURL;
+ m_redirectionURL = KURL();
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url;
+
+ // Return slave to the scheduler
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+}
+
+void StatJob::slotMetaData( const TDEIO::MetaData &_metaData) {
+ SimpleJob::slotMetaData(_metaData);
+ storeSSLSessionFromJob(m_redirectionURL);
+}
+
+StatJob *TDEIO::stat(const KURL& url, bool showProgressInfo)
+{
+ // Assume sideIsSource. Gets are more common than puts.
+ return stat( url, true, 2, showProgressInfo );
+}
+
+StatJob *TDEIO::stat(const KURL& url, bool sideIsSource, short int details, bool showProgressInfo)
+{
+ kdDebug(7007) << "stat " << url << endl;
+ KIO_ARGS << url;
+ StatJob * job = new StatJob(url, CMD_STAT, packedArgs, showProgressInfo );
+ job->setSide( sideIsSource );
+ job->setDetails( details );
+ if ( showProgressInfo )
+ Observer::self()->stating( job, url );
+ return job;
+}
+
+SimpleJob *TDEIO::http_update_cache( const KURL& url, bool no_cache, time_t expireDate)
+{
+ assert( (url.protocol() == "http") || (url.protocol() == "https") );
+ // Send http update_cache command (2)
+ KIO_ARGS << (int)2 << url << no_cache << expireDate;
+ SimpleJob * job = new SimpleJob( url, CMD_SPECIAL, packedArgs, false );
+ Scheduler::scheduleJob(job);
+ return job;
+}
+
+//////////
+
+TransferJob::TransferJob( const KURL& url, int command,
+ const TQByteArray &packedArgs,
+ const TQByteArray &_staticData,
+ bool showProgressInfo)
+ : SimpleJob(url, command, packedArgs, showProgressInfo), staticData( _staticData)
+{
+ m_suspended = false;
+ m_errorPage = false;
+ m_subJob = 0L;
+ if ( showProgressInfo )
+ Observer::self()->slotTransferring( this, url );
+}
+
+// Slave sends data
+void TransferJob::slotData( const TQByteArray &_data)
+{
+ if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
+ emit data( this, _data);
+}
+
+// Slave got a redirection request
+void TransferJob::slotRedirection( const KURL &url)
+{
+ kdDebug(7007) << "TransferJob::slotRedirection(" << url << ")" << endl;
+ if (!kapp->authorizeURLAction("redirect", m_url, url))
+ {
+ kdWarning(7007) << "TransferJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
+ return;
+ }
+
+ // Some websites keep redirecting to themselves where each redirection
+ // acts as the stage in a state-machine. We define "endless redirections"
+ // as 5 redirections to the same URL.
+ if (m_redirectionList.contains(url) > 5)
+ {
+ kdDebug(7007) << "TransferJob::slotRedirection: CYCLIC REDIRECTION!" << endl;
+ m_error = ERR_CYCLIC_LINK;
+ m_errorText = m_url.prettyURL();
+ }
+ else
+ {
+ m_redirectionURL = url; // We'll remember that when the job finishes
+ if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
+ m_redirectionURL.setUser(m_url.user()); // Preserve user
+ m_redirectionList.append(url);
+ m_outgoingMetaData["ssl_was_in_use"] = m_incomingMetaData["ssl_in_use"];
+ // Tell the user that we haven't finished yet
+ emit redirection(this, m_redirectionURL);
+ }
+}
+
+void TransferJob::slotFinished()
+{
+ //kdDebug(7007) << "TransferJob::slotFinished(" << this << ", " << m_url << ")" << endl;
+ if (m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
+ SimpleJob::slotFinished();
+ else {
+ //kdDebug(7007) << "TransferJob: Redirection to " << m_redirectionURL << endl;
+ if (queryMetaData("permanent-redirect")=="true")
+ emit permanentRedirection(this, m_url, m_redirectionURL);
+ // Honour the redirection
+ // We take the approach of "redirecting this same job"
+ // Another solution would be to create a subjob, but the same problem
+ // happens (unpacking+repacking)
+ staticData.truncate(0);
+ m_incomingMetaData.clear();
+ if (queryMetaData("cache") != "reload")
+ addMetaData("cache","refresh");
+ m_suspended = false;
+ m_url = m_redirectionURL;
+ m_redirectionURL = KURL();
+ // The very tricky part is the packed arguments business
+ TQString dummyStr;
+ KURL dummyUrl;
+ TQDataStream istream( m_packedArgs, IO_ReadOnly );
+ switch( m_command ) {
+ case CMD_GET: {
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url;
+ break;
+ }
+ case CMD_PUT: {
+ int permissions;
+ TQ_INT8 iOverwrite, iResume;
+ istream >> dummyUrl >> iOverwrite >> iResume >> permissions;
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url << iOverwrite << iResume << permissions;
+ break;
+ }
+ case CMD_SPECIAL: {
+ int specialcmd;
+ istream >> specialcmd;
+ if (specialcmd == 1) // HTTP POST
+ {
+ addMetaData("cache","reload");
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url;
+ m_command = CMD_GET;
+ }
+ break;
+ }
+ }
+
+ // Return slave to the scheduler
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+}
+
+void TransferJob::setAsyncDataEnabled(bool enabled)
+{
+ if (enabled)
+ extraFlags() |= EF_TransferJobAsync;
+ else
+ extraFlags() &= ~EF_TransferJobAsync;
+}
+
+void TransferJob::sendAsyncData(const TQByteArray &dataForSlave)
+{
+ if (extraFlags() & EF_TransferJobNeedData)
+ {
+ m_slave->send( MSG_DATA, dataForSlave );
+ if (extraFlags() & EF_TransferJobDataSent)
+ {
+ TDEIO::filesize_t size = getProcessedSize()+dataForSlave.size();
+ setProcessedSize(size);
+ emit processedSize( this, size );
+ if ( size > m_totalSize ) {
+ slotTotalSize(size); // safety
+ }
+ emitPercent( size, m_totalSize );
+ }
+ }
+
+ extraFlags() &= ~EF_TransferJobNeedData;
+}
+
+void TransferJob::setReportDataSent(bool enabled)
+{
+ if (enabled)
+ extraFlags() |= EF_TransferJobDataSent;
+ else
+ extraFlags() &= ~EF_TransferJobDataSent;
+}
+
+bool TransferJob::reportDataSent()
+{
+ return (extraFlags() & EF_TransferJobDataSent);
+}
+
+
+// Slave requests data
+void TransferJob::slotDataReq()
+{
+ TQByteArray dataForSlave;
+
+ extraFlags() |= EF_TransferJobNeedData;
+
+ if (!staticData.isEmpty())
+ {
+ dataForSlave = staticData;
+ staticData = TQByteArray();
+ }
+ else
+ {
+ emit dataReq( this, dataForSlave);
+
+ if (extraFlags() & EF_TransferJobAsync)
+ return;
+ }
+
+ static const size_t max_size = 14 * 1024 * 1024;
+ if (dataForSlave.size() > max_size)
+ {
+ kdDebug(7007) << "send " << dataForSlave.size() / 1024 / 1024 << "MB of data in TransferJob::dataReq. This needs to be splitted, which requires a copy. Fix the application.\n";
+ staticData.duplicate(dataForSlave.data() + max_size , dataForSlave.size() - max_size);
+ dataForSlave.truncate(max_size);
+ }
+
+ sendAsyncData(dataForSlave);
+
+ if (m_subJob)
+ {
+ // Bitburger protocol in action
+ suspend(); // Wait for more data from subJob.
+ m_subJob->resume(); // Ask for more!
+ }
+}
+
+void TransferJob::slotMimetype( const TQString& type )
+{
+ m_mimetype = type;
+ emit mimetype( this, m_mimetype);
+}
+
+
+void TransferJob::suspend()
+{
+ m_suspended = true;
+ if (m_slave)
+ m_slave->suspend();
+}
+
+void TransferJob::resume()
+{
+ m_suspended = false;
+ if (m_slave)
+ m_slave->resume();
+}
+
+void TransferJob::start(Slave *slave)
+{
+ assert(slave);
+ connect( slave, TQT_SIGNAL( data( const TQByteArray & ) ),
+ TQT_SLOT( slotData( const TQByteArray & ) ) );
+
+ connect( slave, TQT_SIGNAL( dataReq() ),
+ TQT_SLOT( slotDataReq() ) );
+
+ connect( slave, TQT_SIGNAL( redirection(const KURL &) ),
+ TQT_SLOT( slotRedirection(const KURL &) ) );
+
+ connect( slave, TQT_SIGNAL(mimeType( const TQString& ) ),
+ TQT_SLOT( slotMimetype( const TQString& ) ) );
+
+ connect( slave, TQT_SIGNAL(errorPage() ),
+ TQT_SLOT( slotErrorPage() ) );
+
+ connect( slave, TQT_SIGNAL( needSubURLData() ),
+ TQT_SLOT( slotNeedSubURLData() ) );
+
+ connect( slave, TQT_SIGNAL(canResume( TDEIO::filesize_t ) ),
+ TQT_SLOT( slotCanResume( TDEIO::filesize_t ) ) );
+
+ if (slave->suspended())
+ {
+ m_mimetype = "unknown";
+ // WABA: The slave was put on hold. Resume operation.
+ slave->resume();
+ }
+
+ SimpleJob::start(slave);
+ if (m_suspended)
+ slave->suspend();
+}
+
+void TransferJob::slotNeedSubURLData()
+{
+ // Job needs data from subURL.
+ m_subJob = TDEIO::get( m_subUrl, false, false);
+ suspend(); // Put job on hold until we have some data.
+ connect(m_subJob, TQT_SIGNAL( data(TDEIO::Job*,const TQByteArray &)),
+ TQT_SLOT( slotSubURLData(TDEIO::Job*,const TQByteArray &)));
+ addSubjob(m_subJob);
+}
+
+void TransferJob::slotSubURLData(TDEIO::Job*, const TQByteArray &data)
+{
+ // The Alternating Bitburg protocol in action again.
+ staticData = data;
+ m_subJob->suspend(); // Put job on hold until we have delivered the data.
+ resume(); // Activate ourselves again.
+}
+
+void TransferJob::slotMetaData( const TDEIO::MetaData &_metaData) {
+ SimpleJob::slotMetaData(_metaData);
+ storeSSLSessionFromJob(m_redirectionURL);
+}
+
+void TransferJob::slotErrorPage()
+{
+ m_errorPage = true;
+}
+
+void TransferJob::slotCanResume( TDEIO::filesize_t offset )
+{
+ emit canResume(this, offset);
+}
+
+void TransferJob::slotResult( TDEIO::Job *job)
+{
+ // This can only be our suburl.
+ assert(job == m_subJob);
+ // Did job have an error ?
+ if ( job->error() )
+ {
+ m_error = job->error();
+ m_errorText = job->errorText();
+
+ emitResult();
+ return;
+ }
+
+ if (job == m_subJob)
+ {
+ m_subJob = 0; // No action required
+ resume(); // Make sure we get the remaining data.
+ }
+ removeSubjob( job, false, false ); // Remove job, but don't kill this job.
+}
+
+TransferJob *TDEIO::get( const KURL& url, bool reload, bool showProgressInfo )
+{
+ // Send decoded path and encoded query
+ KIO_ARGS << url;
+ TransferJob * job = new TransferJob( url, CMD_GET, packedArgs, TQByteArray(), showProgressInfo );
+ if (reload)
+ job->addMetaData("cache", "reload");
+ return job;
+}
+
+class PostErrorJob : public TransferJob
+{
+public:
+
+ PostErrorJob(int _error, const TQString& url, const TQByteArray &packedArgs, const TQByteArray &postData, bool showProgressInfo)
+ : TransferJob(KURL(), CMD_SPECIAL, packedArgs, postData, showProgressInfo)
+ {
+ m_error = _error;
+ m_errorText = url;
+ }
+
+};
+
+TransferJob *TDEIO::http_post( const KURL& url, const TQByteArray &postData, bool showProgressInfo )
+{
+ int _error = 0;
+
+ // filter out some malicious ports
+ static const int bad_ports[] = {
+ 1, // tcpmux
+ 7, // echo
+ 9, // discard
+ 11, // systat
+ 13, // daytime
+ 15, // netstat
+ 17, // qotd
+ 19, // chargen
+ 20, // ftp-data
+ 21, // ftp-cntl
+ 22, // ssh
+ 23, // telnet
+ 25, // smtp
+ 37, // time
+ 42, // name
+ 43, // nicname
+ 53, // domain
+ 77, // priv-rjs
+ 79, // finger
+ 87, // ttylink
+ 95, // supdup
+ 101, // hostriame
+ 102, // iso-tsap
+ 103, // gppitnp
+ 104, // acr-nema
+ 109, // pop2
+ 110, // pop3
+ 111, // sunrpc
+ 113, // auth
+ 115, // sftp
+ 117, // uucp-path
+ 119, // nntp
+ 123, // NTP
+ 135, // loc-srv / epmap
+ 139, // netbios
+ 143, // imap2
+ 179, // BGP
+ 389, // ldap
+ 512, // print / exec
+ 513, // login
+ 514, // shell
+ 515, // printer
+ 526, // tempo
+ 530, // courier
+ 531, // Chat
+ 532, // netnews
+ 540, // uucp
+ 556, // remotefs
+ 587, // sendmail
+ 601, //
+ 989, // ftps data
+ 990, // ftps
+ 992, // telnets
+ 993, // imap/SSL
+ 995, // pop3/SSL
+ 1080, // SOCKS
+ 2049, // nfs
+ 4045, // lockd
+ 6000, // x11
+ 6667, // irc
+ 0};
+ for (int cnt=0; bad_ports[cnt]; ++cnt)
+ if (url.port() == bad_ports[cnt])
+ {
+ _error = TDEIO::ERR_POST_DENIED;
+ break;
+ }
+
+ if( _error )
+ {
+ static bool override_loaded = false;
+ static TQValueList< int >* overriden_ports = NULL;
+ if( !override_loaded )
+ {
+ TDEConfig cfg( "kio_httprc", true );
+ overriden_ports = new TQValueList< int >;
+ *overriden_ports = cfg.readIntListEntry( "OverriddenPorts" );
+ override_loaded = true;
+ }
+ for( TQValueList< int >::ConstIterator it = overriden_ports->begin();
+ it != overriden_ports->end();
+ ++it )
+ if( overriden_ports->contains( url.port()))
+ _error = 0;
+ }
+
+ // filter out non https? protocols
+ if ((url.protocol() != "http") && (url.protocol() != "https" ))
+ _error = TDEIO::ERR_POST_DENIED;
+
+ bool redirection = false;
+ KURL _url(url);
+ if (_url.path().isEmpty())
+ {
+ redirection = true;
+ _url.setPath("/");
+ }
+
+ if (!_error && !kapp->authorizeURLAction("open", KURL(), _url))
+ _error = TDEIO::ERR_ACCESS_DENIED;
+
+ // if request is not valid, return an invalid transfer job
+ if (_error)
+ {
+ KIO_ARGS << (int)1 << url;
+ TransferJob * job = new PostErrorJob(_error, url.prettyURL(), packedArgs, postData, showProgressInfo);
+ return job;
+ }
+
+ // Send http post command (1), decoded path and encoded query
+ KIO_ARGS << (int)1 << _url;
+ TransferJob * job = new TransferJob( _url, CMD_SPECIAL,
+ packedArgs, postData, showProgressInfo );
+
+ if (redirection)
+ TQTimer::singleShot(0, job, TQT_SLOT(slotPostRedirection()) );
+
+ return job;
+}
+
+// http post got redirected from http://host to http://host/ by TransferJob
+// We must do this redirection ourselves because redirections by the
+// slave change post jobs into get jobs.
+void TransferJob::slotPostRedirection()
+{
+ kdDebug(7007) << "TransferJob::slotPostRedirection(" << m_url << ")" << endl;
+ // Tell the user about the new url.
+ emit redirection(this, m_url);
+}
+
+
+TransferJob *TDEIO::put( const KURL& url, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo )
+{
+ KIO_ARGS << url << TQ_INT8( overwrite ? 1 : 0 ) << TQ_INT8( resume ? 1 : 0 ) << permissions;
+ TransferJob * job = new TransferJob( url, CMD_PUT, packedArgs, TQByteArray(), showProgressInfo );
+ return job;
+}
+
+//////////
+
+StoredTransferJob::StoredTransferJob(const KURL& url, int command,
+ const TQByteArray &packedArgs,
+ const TQByteArray &_staticData,
+ bool showProgressInfo)
+ : TransferJob( url, command, packedArgs, _staticData, showProgressInfo ),
+ m_uploadOffset( 0 )
+{
+ connect( this, TQT_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
+ TQT_SLOT( slotStoredData( TDEIO::Job *, const TQByteArray & ) ) );
+ connect( this, TQT_SIGNAL( dataReq( TDEIO::Job *, TQByteArray & ) ),
+ TQT_SLOT( slotStoredDataReq( TDEIO::Job *, TQByteArray & ) ) );
+}
+
+void StoredTransferJob::setData( const TQByteArray& arr )
+{
+ Q_ASSERT( m_data.isNull() ); // check that we're only called once
+ Q_ASSERT( m_uploadOffset == 0 ); // no upload started yet
+ m_data = arr;
+}
+
+void StoredTransferJob::slotStoredData( TDEIO::Job *, const TQByteArray &data )
+{
+ // check for end-of-data marker:
+ if ( data.size() == 0 )
+ return;
+ unsigned int oldSize = m_data.size();
+ m_data.resize( oldSize + data.size(), TQGArray::SpeedOptim );
+ memcpy( m_data.data() + oldSize, data.data(), data.size() );
+}
+
+void StoredTransferJob::slotStoredDataReq( TDEIO::Job *, TQByteArray &data )
+{
+ // Inspired from kmail's KMKernel::byteArrayToRemoteFile
+ // send the data in 64 KB chunks
+ const int MAX_CHUNK_SIZE = 64*1024;
+ int remainingBytes = m_data.size() - m_uploadOffset;
+ if( remainingBytes > MAX_CHUNK_SIZE ) {
+ // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
+ data.duplicate( m_data.data() + m_uploadOffset, MAX_CHUNK_SIZE );
+ m_uploadOffset += MAX_CHUNK_SIZE;
+ //kdDebug() << "Sending " << MAX_CHUNK_SIZE << " bytes ("
+ // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
+ } else {
+ // send the remaining bytes to the receiver (deep copy)
+ data.duplicate( m_data.data() + m_uploadOffset, remainingBytes );
+ m_data = TQByteArray();
+ m_uploadOffset = 0;
+ //kdDebug() << "Sending " << remainingBytes << " bytes\n";
+ }
+}
+
+StoredTransferJob *TDEIO::storedGet( const KURL& url, bool reload, bool showProgressInfo )
+{
+ // Send decoded path and encoded query
+ KIO_ARGS << url;
+ StoredTransferJob * job = new StoredTransferJob( url, CMD_GET, packedArgs, TQByteArray(), showProgressInfo );
+ if (reload)
+ job->addMetaData("cache", "reload");
+ return job;
+}
+
+StoredTransferJob *TDEIO::storedPut( const TQByteArray& arr, const KURL& url, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo )
+{
+ KIO_ARGS << url << TQ_INT8( overwrite ? 1 : 0 ) << TQ_INT8( resume ? 1 : 0 ) << permissions;
+ StoredTransferJob * job = new StoredTransferJob( url, CMD_PUT, packedArgs, TQByteArray(), showProgressInfo );
+ job->setData( arr );
+ return job;
+}
+
+//////////
+
+MimetypeJob::MimetypeJob( const KURL& url, int command,
+ const TQByteArray &packedArgs, bool showProgressInfo )
+ : TransferJob(url, command, packedArgs, TQByteArray(), showProgressInfo)
+{
+}
+
+void MimetypeJob::start(Slave *slave)
+{
+ TransferJob::start(slave);
+}
+
+
+void MimetypeJob::slotFinished( )
+{
+ //kdDebug(7007) << "MimetypeJob::slotFinished()" << endl;
+ if ( m_error == TDEIO::ERR_IS_DIRECTORY )
+ {
+ // It is in fact a directory. This happens when HTTP redirects to FTP.
+ // Due to the "protocol doesn't support listing" code in KRun, we
+ // assumed it was a file.
+ kdDebug(7007) << "It is in fact a directory!" << endl;
+ m_mimetype = TQString::fromLatin1("inode/directory");
+ emit TransferJob::mimetype( this, m_mimetype );
+ m_error = 0;
+ }
+ if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
+ {
+ // Return slave to the scheduler
+ TransferJob::slotFinished();
+ } else {
+ //kdDebug(7007) << "MimetypeJob: Redirection to " << m_redirectionURL << endl;
+ if (queryMetaData("permanent-redirect")=="true")
+ emit permanentRedirection(this, m_url, m_redirectionURL);
+ staticData.truncate(0);
+ m_suspended = false;
+ m_url = m_redirectionURL;
+ m_redirectionURL = KURL();
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url;
+
+ // Return slave to the scheduler
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+}
+
+MimetypeJob *TDEIO::mimetype(const KURL& url, bool showProgressInfo )
+{
+ KIO_ARGS << url;
+ MimetypeJob * job = new MimetypeJob(url, CMD_MIMETYPE, packedArgs, showProgressInfo);
+ if ( showProgressInfo )
+ Observer::self()->stating( job, url );
+ return job;
+}
+
+//////////////////////////
+
+DirectCopyJob::DirectCopyJob( const KURL& url, int command,
+ const TQByteArray &packedArgs, bool showProgressInfo )
+ : SimpleJob(url, command, packedArgs, showProgressInfo)
+{
+}
+
+void DirectCopyJob::start( Slave* slave )
+{
+ connect( slave, TQT_SIGNAL(canResume( TDEIO::filesize_t ) ),
+ TQT_SLOT( slotCanResume( TDEIO::filesize_t ) ) );
+ SimpleJob::start(slave);
+}
+
+void DirectCopyJob::slotCanResume( TDEIO::filesize_t offset )
+{
+ emit canResume(this, offset);
+}
+
+//////////////////////////
+
+
+class FileCopyJob::FileCopyJobPrivate
+{
+public:
+ TDEIO::filesize_t m_sourceSize;
+ time_t m_modificationTime;
+ SimpleJob *m_delJob;
+};
+
+/*
+ * The FileCopyJob works according to the famous Bayern
+ * 'Alternating Bitburger Protocol': we either drink a beer or we
+ * we order a beer, but never both at the same time.
+ * Tranlated to io-slaves: We alternate between receiving a block of data
+ * and sending it away.
+ */
+FileCopyJob::FileCopyJob( const KURL& src, const KURL& dest, int permissions,
+ bool move, bool overwrite, bool resume, bool showProgressInfo)
+ : Job(showProgressInfo), m_src(src), m_dest(dest),
+ m_permissions(permissions), m_move(move), m_overwrite(overwrite), m_resume(resume),
+ m_totalSize(0)
+{
+ if (showProgressInfo && !move)
+ Observer::self()->slotCopying( this, src, dest );
+ else if (showProgressInfo && move)
+ Observer::self()->slotMoving( this, src, dest );
+
+ //kdDebug(7007) << "FileCopyJob::FileCopyJob()" << endl;
+ m_moveJob = 0;
+ m_copyJob = 0;
+ m_getJob = 0;
+ m_putJob = 0;
+ d = new FileCopyJobPrivate;
+ d->m_delJob = 0;
+ d->m_sourceSize = (TDEIO::filesize_t) -1;
+ d->m_modificationTime = static_cast<time_t>( -1 );
+ TQTimer::singleShot(0, this, TQT_SLOT(slotStart()));
+}
+
+void FileCopyJob::slotStart()
+{
+ if ( m_move )
+ {
+ // The if() below must be the same as the one in startBestCopyMethod
+ if ((m_src.protocol() == m_dest.protocol()) &&
+ (m_src.host() == m_dest.host()) &&
+ (m_src.port() == m_dest.port()) &&
+ (m_src.user() == m_dest.user()) &&
+ (m_src.pass() == m_dest.pass()) &&
+ !m_src.hasSubURL() && !m_dest.hasSubURL())
+ {
+ startRenameJob(m_src);
+ return;
+ }
+ else if (m_src.isLocalFile() && KProtocolInfo::canRenameFromFile(m_dest))
+ {
+ startRenameJob(m_dest);
+ return;
+ }
+ else if (m_dest.isLocalFile() && KProtocolInfo::canRenameToFile(m_src))
+ {
+ startRenameJob(m_src);
+ return;
+ }
+ // No fast-move available, use copy + del.
+ }
+ startBestCopyMethod();
+}
+
+void FileCopyJob::startBestCopyMethod()
+{
+ if ((m_src.protocol() == m_dest.protocol()) &&
+ (m_src.host() == m_dest.host()) &&
+ (m_src.port() == m_dest.port()) &&
+ (m_src.user() == m_dest.user()) &&
+ (m_src.pass() == m_dest.pass()) &&
+ !m_src.hasSubURL() && !m_dest.hasSubURL())
+ {
+ startCopyJob();
+ }
+ else if (m_src.isLocalFile() && KProtocolInfo::canCopyFromFile(m_dest))
+ {
+ startCopyJob(m_dest);
+ }
+ else if (m_dest.isLocalFile() && KProtocolInfo::canCopyToFile(m_src))
+ {
+ startCopyJob(m_src);
+ }
+ else
+ {
+ startDataPump();
+ }
+}
+
+FileCopyJob::~FileCopyJob()
+{
+ delete d;
+}
+
+void FileCopyJob::setSourceSize( off_t size )
+{
+ d->m_sourceSize = size;
+ if (size != (off_t) -1)
+ m_totalSize = size;
+}
+
+void FileCopyJob::setSourceSize64( TDEIO::filesize_t size )
+{
+ d->m_sourceSize = size;
+ if (size != (TDEIO::filesize_t) -1)
+ m_totalSize = size;
+}
+
+void FileCopyJob::setModificationTime( time_t mtime )
+{
+ d->m_modificationTime = mtime;
+}
+
+void FileCopyJob::startCopyJob()
+{
+ startCopyJob(m_src);
+}
+
+void FileCopyJob::startCopyJob(const KURL &slave_url)
+{
+ //kdDebug(7007) << "FileCopyJob::startCopyJob()" << endl;
+ KIO_ARGS << m_src << m_dest << m_permissions << (TQ_INT8) m_overwrite;
+ m_copyJob = new DirectCopyJob(slave_url, CMD_COPY, packedArgs, false);
+ addSubjob( m_copyJob );
+ connectSubjob( m_copyJob );
+ connect( m_copyJob, TQT_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
+ TQT_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
+}
+
+void FileCopyJob::startRenameJob(const KURL &slave_url)
+{
+ KIO_ARGS << m_src << m_dest << (TQ_INT8) m_overwrite;
+ m_moveJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
+ addSubjob( m_moveJob );
+ connectSubjob( m_moveJob );
+}
+
+void FileCopyJob::connectSubjob( SimpleJob * job )
+{
+ connect( job, TQT_SIGNAL(totalSize( TDEIO::Job*, TDEIO::filesize_t )),
+ this, TQT_SLOT( slotTotalSize(TDEIO::Job*, TDEIO::filesize_t)) );
+
+ connect( job, TQT_SIGNAL(processedSize( TDEIO::Job*, TDEIO::filesize_t )),
+ this, TQT_SLOT( slotProcessedSize(TDEIO::Job*, TDEIO::filesize_t)) );
+
+ connect( job, TQT_SIGNAL(percent( TDEIO::Job*, unsigned long )),
+ this, TQT_SLOT( slotPercent(TDEIO::Job*, unsigned long)) );
+
+}
+
+void FileCopyJob::slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t size )
+{
+ setProcessedSize(size);
+ emit processedSize( this, size );
+ if ( size > m_totalSize ) {
+ slotTotalSize( this, size ); // safety
+ }
+ emitPercent( size, m_totalSize );
+}
+
+void FileCopyJob::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size )
+{
+ if (size > m_totalSize)
+ {
+ m_totalSize = size;
+ emit totalSize( this, m_totalSize );
+ }
+}
+
+void FileCopyJob::slotPercent( TDEIO::Job*, unsigned long pct )
+{
+ if ( pct > m_percent )
+ {
+ m_percent = pct;
+ emit percent( this, m_percent );
+ }
+}
+
+void FileCopyJob::startDataPump()
+{
+ //kdDebug(7007) << "FileCopyJob::startDataPump()" << endl;
+
+ m_canResume = false;
+ m_resumeAnswerSent = false;
+ m_getJob = 0L; // for now
+ m_putJob = put( m_dest, m_permissions, m_overwrite, m_resume, false /* no GUI */);
+ if ( d->m_modificationTime != static_cast<time_t>( -1 ) ) {
+ TQDateTime dt; dt.setTime_t( d->m_modificationTime );
+ m_putJob->addMetaData( "modified", dt.toString( Qt::ISODate ) );
+ }
+ //kdDebug(7007) << "FileCopyJob: m_putJob = " << m_putJob << " m_dest=" << m_dest << endl;
+
+ // The first thing the put job will tell us is whether we can
+ // resume or not (this is always emitted)
+ connect( m_putJob, TQT_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
+ TQT_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
+ connect( m_putJob, TQT_SIGNAL(dataReq(TDEIO::Job *, TQByteArray&)),
+ TQT_SLOT( slotDataReq(TDEIO::Job *, TQByteArray&)));
+ addSubjob( m_putJob );
+}
+
+void FileCopyJob::slotCanResume( TDEIO::Job* job, TDEIO::filesize_t offset )
+{
+ if ( job == m_putJob || job == m_copyJob )
+ {
+ //kdDebug(7007) << "FileCopyJob::slotCanResume from PUT job. offset=" << TDEIO::number(offset) << endl;
+ if (offset)
+ {
+ RenameDlg_Result res = R_RESUME;
+
+ if (!KProtocolManager::autoResume() && !m_overwrite)
+ {
+ TQString newPath;
+ TDEIO::Job* job = ( !m_progressId && parentJob() ) ? parentJob() : this;
+ // Ask confirmation about resuming previous transfer
+ res = Observer::self()->open_RenameDlg(
+ job, i18n("File Already Exists"),
+ m_src.url(),
+ m_dest.url(),
+ (RenameDlg_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
+ d->m_sourceSize, offset );
+ }
+
+ if ( res == R_OVERWRITE || m_overwrite )
+ offset = 0;
+ else if ( res == R_CANCEL )
+ {
+ if ( job == m_putJob )
+ m_putJob->kill(true);
+ else
+ m_copyJob->kill(true);
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ }
+ }
+ else
+ m_resumeAnswerSent = true; // No need for an answer
+
+ if ( job == m_putJob )
+ {
+ m_getJob = get( m_src, false, false /* no GUI */ );
+ //kdDebug(7007) << "FileCopyJob: m_getJob = " << m_getJob << endl;
+ m_getJob->addMetaData( "errorPage", "false" );
+ m_getJob->addMetaData( "AllowCompressedPage", "false" );
+ // Set size in subjob. This helps if the slave doesn't emit totalSize.
+ if ( d->m_sourceSize != (TDEIO::filesize_t)-1 )
+ m_getJob->slotTotalSize( d->m_sourceSize );
+ if (offset)
+ {
+ //kdDebug(7007) << "Setting metadata for resume to " << (unsigned long) offset << endl;
+ // TODO KDE4: rename to seek or offset and document it
+ // This isn't used only for resuming, but potentially also for extracting (#72302).
+ m_getJob->addMetaData( "resume", TDEIO::number(offset) );
+
+ // Might or might not get emitted
+ connect( m_getJob, TQT_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
+ TQT_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
+ }
+ m_putJob->slave()->setOffset( offset );
+
+ m_putJob->suspend();
+ addSubjob( m_getJob );
+ connectSubjob( m_getJob ); // Progress info depends on get
+ m_getJob->resume(); // Order a beer
+
+ connect( m_getJob, TQT_SIGNAL(data(TDEIO::Job*,const TQByteArray&)),
+ TQT_SLOT( slotData(TDEIO::Job*,const TQByteArray&)) );
+ connect( m_getJob, TQT_SIGNAL(mimetype(TDEIO::Job*,const TQString&) ),
+ TQT_SLOT(slotMimetype(TDEIO::Job*,const TQString&)) );
+ }
+ else // copyjob
+ {
+ m_copyJob->slave()->sendResumeAnswer( offset != 0 );
+ }
+ }
+ else if ( job == m_getJob )
+ {
+ // Cool, the get job said ok, we can resume
+ m_canResume = true;
+ //kdDebug(7007) << "FileCopyJob::slotCanResume from the GET job -> we can resume" << endl;
+
+ m_getJob->slave()->setOffset( m_putJob->slave()->offset() );
+ }
+ else
+ kdWarning(7007) << "FileCopyJob::slotCanResume from unknown job=" << job
+ << " m_getJob=" << m_getJob << " m_putJob=" << m_putJob << endl;
+}
+
+void FileCopyJob::slotData( TDEIO::Job * , const TQByteArray &data)
+{
+ //kdDebug(7007) << "FileCopyJob::slotData" << endl;
+ //kdDebug(7007) << " data size : " << data.size() << endl;
+ assert(m_putJob);
+ if (!m_putJob) return; // Don't crash
+ m_getJob->suspend();
+ m_putJob->resume(); // Drink the beer
+ m_buffer = data;
+
+ // On the first set of data incoming, we tell the "put" slave about our
+ // decision about resuming
+ if (!m_resumeAnswerSent)
+ {
+ m_resumeAnswerSent = true;
+ //kdDebug(7007) << "FileCopyJob::slotData (first time) -> send resume answer " << m_canResume << endl;
+ m_putJob->slave()->sendResumeAnswer( m_canResume );
+ }
+}
+
+void FileCopyJob::slotDataReq( TDEIO::Job * , TQByteArray &data)
+{
+ //kdDebug(7007) << "FileCopyJob::slotDataReq" << endl;
+ if (!m_resumeAnswerSent && !m_getJob)
+ {
+ // This can't happen (except as a migration bug on 12/10/2000)
+ m_error = ERR_INTERNAL;
+ m_errorText = "'Put' job didn't send canResume or 'Get' job didn't send data!";
+ m_putJob->kill(true);
+ emitResult();
+ return;
+ }
+ if (m_getJob)
+ {
+ m_getJob->resume(); // Order more beer
+ m_putJob->suspend();
+ }
+ data = m_buffer;
+ m_buffer = TQByteArray();
+}
+
+void FileCopyJob::slotMimetype( TDEIO::Job*, const TQString& type )
+{
+ emit mimetype( this, type );
+}
+
+void FileCopyJob::slotResult( TDEIO::Job *job)
+{
+ //kdDebug(7007) << "FileCopyJob this=" << this << " ::slotResult(" << job << ")" << endl;
+ // Did job have an error ?
+ if ( job->error() )
+ {
+ if ((job == m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
+ {
+ m_moveJob = 0;
+ startBestCopyMethod();
+ removeSubjob(job);
+ return;
+ }
+ else if ((job == m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
+ {
+ m_copyJob = 0;
+ startDataPump();
+ removeSubjob(job);
+ return;
+ }
+ else if (job == m_getJob)
+ {
+ m_getJob = 0L;
+ if (m_putJob)
+ m_putJob->kill(true);
+ }
+ else if (job == m_putJob)
+ {
+ m_putJob = 0L;
+ if (m_getJob)
+ m_getJob->kill(true);
+ }
+ m_error = job->error();
+ m_errorText = job->errorText();
+ emitResult();
+ return;
+ }
+
+ if (job == m_moveJob)
+ {
+ m_moveJob = 0; // Finished
+ }
+
+ if (job == m_copyJob)
+ {
+ m_copyJob = 0;
+ if (m_move)
+ {
+ d->m_delJob = file_delete( m_src, false/*no GUI*/ ); // Delete source
+ addSubjob(d->m_delJob);
+ }
+ }
+
+ if (job == m_getJob)
+ {
+ m_getJob = 0; // No action required
+ if (m_putJob)
+ m_putJob->resume();
+ }
+
+ if (job == m_putJob)
+ {
+ //kdDebug(7007) << "FileCopyJob: m_putJob finished " << endl;
+ m_putJob = 0;
+ if (m_getJob)
+ {
+ kdWarning(7007) << "WARNING ! Get still going on..." << endl;
+ m_getJob->resume();
+ }
+ if (m_move)
+ {
+ d->m_delJob = file_delete( m_src, false/*no GUI*/ ); // Delete source
+ addSubjob(d->m_delJob);
+ }
+ }
+
+ if (job == d->m_delJob)
+ {
+ d->m_delJob = 0; // Finished
+ }
+ removeSubjob(job);
+}
+
+FileCopyJob *TDEIO::file_copy( const KURL& src, const KURL& dest, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo)
+{
+ return new FileCopyJob( src, dest, permissions, false, overwrite, resume, showProgressInfo );
+}
+
+FileCopyJob *TDEIO::file_move( const KURL& src, const KURL& dest, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo)
+{
+ return new FileCopyJob( src, dest, permissions, true, overwrite, resume, showProgressInfo );
+}
+
+SimpleJob *TDEIO::file_delete( const KURL& src, bool showProgressInfo)
+{
+ KIO_ARGS << src << TQ_INT8(true); // isFile
+ return new SimpleJob(src, CMD_DEL, packedArgs, showProgressInfo );
+}
+
+//////////
+
+// KDE 4: Make it const TQString & _prefix
+ListJob::ListJob(const KURL& u, bool showProgressInfo, bool _recursive, TQString _prefix, bool _includeHidden) :
+ SimpleJob(u, CMD_LISTDIR, TQByteArray(), showProgressInfo),
+ recursive(_recursive), includeHidden(_includeHidden), prefix(_prefix), m_processedEntries(0)
+{
+ // We couldn't set the args when calling the parent constructor,
+ // so do it now.
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << u;
+}
+
+void ListJob::slotListEntries( const TDEIO::UDSEntryList& list )
+{
+ // Emit progress info (takes care of emit processedSize and percent)
+ m_processedEntries += list.count();
+ slotProcessedSize( m_processedEntries );
+
+ if (recursive) {
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+
+ for (; it != end; ++it) {
+ bool isDir = false;
+ bool isLink = false;
+ KURL itemURL;
+
+ UDSEntry::ConstIterator it2 = (*it).begin();
+ UDSEntry::ConstIterator end2 = (*it).end();
+ for( ; it2 != end2; it2++ ) {
+ switch( (*it2).m_uds ) {
+ case UDS_FILE_TYPE:
+ isDir = S_ISDIR((*it2).m_long);
+ break;
+ case UDS_NAME:
+ if( itemURL.isEmpty() ) {
+ itemURL = url();
+ itemURL.addPath( (*it2).m_str );
+ }
+ break;
+ case UDS_URL:
+ itemURL = (*it2).m_str;
+ break;
+ case UDS_LINK_DEST:
+ // This is a link !!! Don't follow !
+ isLink = !(*it2).m_str.isEmpty();
+ break;
+ default:
+ break;
+ }
+ }
+ if (isDir && !isLink) {
+ const TQString filename = itemURL.fileName();
+ // skip hidden dirs when listing if requested
+ if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
+ ListJob *job = new ListJob(itemURL,
+ false /*no progress info!*/,
+ true /*recursive*/,
+ prefix + filename + "/",
+ includeHidden);
+ Scheduler::scheduleJob(job);
+ connect(job, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( gotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob(job);
+ }
+ }
+ }
+ }
+
+ // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
+ // exclusion of hidden files also requires the full sweep, but the case for full-listing
+ // a single dir is probably common enough to justify the shortcut
+ if (prefix.isNull() && includeHidden) {
+ emit entries(this, list);
+ } else {
+ // cull the unwanted hidden dirs and/or parent dir references from the listing, then emit that
+ UDSEntryList newlist;
+
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+
+ UDSEntry newone = *it;
+ UDSEntry::Iterator it2 = newone.begin();
+ TQString filename;
+ for( ; it2 != newone.end(); it2++ ) {
+ if ((*it2).m_uds == UDS_NAME) {
+ filename = (*it2).m_str;
+ (*it2).m_str = prefix + filename;
+ }
+ }
+ // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
+ // the toplevel dir, and skip hidden files/dirs if that was requested
+ if ( (prefix.isNull() || (filename != ".." && filename != ".") )
+ && (includeHidden || (filename[0] != '.') ) )
+ newlist.append(newone);
+ }
+
+ emit entries(this, newlist);
+ }
+}
+
+void ListJob::gotEntries(TDEIO::Job *, const TDEIO::UDSEntryList& list )
+{
+ // Forward entries received by subjob - faking we received them ourselves
+ emit entries(this, list);
+}
+
+void ListJob::slotResult( TDEIO::Job * job )
+{
+ // If we can't list a subdir, the result is still ok
+ // This is why we override Job::slotResult() - to skip error checking
+ removeSubjob( job );
+}
+
+void ListJob::slotRedirection( const KURL & url )
+{
+ if (!kapp->authorizeURLAction("redirect", m_url, url))
+ {
+ kdWarning(7007) << "ListJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
+ return;
+ }
+ m_redirectionURL = url; // We'll remember that when the job finishes
+ if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
+ m_redirectionURL.setUser(m_url.user()); // Preserve user
+ emit redirection( this, m_redirectionURL );
+}
+
+void ListJob::slotFinished()
+{
+ // Support for listing archives as directories
+ if ( m_error == TDEIO::ERR_IS_FILE && m_url.isLocalFile() ) {
+ KMimeType::Ptr ptr = KMimeType::findByURL( m_url, 0, true, true );
+ if ( ptr ) {
+ TQString proto = ptr->property("X-TDE-LocalProtocol").toString();
+ if ( !proto.isEmpty() && KProtocolInfo::isKnownProtocol(proto) ) {
+ m_redirectionURL = m_url;
+ m_redirectionURL.setProtocol( proto );
+ m_error = 0;
+ emit redirection(this,m_redirectionURL);
+ }
+ }
+ }
+ if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error ) {
+ // Return slave to the scheduler
+ SimpleJob::slotFinished();
+ } else {
+
+ //kdDebug(7007) << "ListJob: Redirection to " << m_redirectionURL << endl;
+ if (queryMetaData("permanent-redirect")=="true")
+ emit permanentRedirection(this, m_url, m_redirectionURL);
+ m_url = m_redirectionURL;
+ m_redirectionURL = KURL();
+ m_packedArgs.truncate(0);
+ TQDataStream stream( m_packedArgs, IO_WriteOnly );
+ stream << m_url;
+
+ // Return slave to the scheduler
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+}
+
+void ListJob::slotMetaData( const TDEIO::MetaData &_metaData) {
+ SimpleJob::slotMetaData(_metaData);
+ storeSSLSessionFromJob(m_redirectionURL);
+}
+
+ListJob *TDEIO::listDir( const KURL& url, bool showProgressInfo, bool includeHidden )
+{
+ ListJob * job = new ListJob(url, showProgressInfo,false,TQString::null,includeHidden);
+ return job;
+}
+
+ListJob *TDEIO::listRecursive( const KURL& url, bool showProgressInfo, bool includeHidden )
+{
+ ListJob * job = new ListJob(url, showProgressInfo, true,TQString::null,includeHidden);
+ return job;
+}
+
+void ListJob::setUnrestricted(bool unrestricted)
+{
+ if (unrestricted)
+ extraFlags() |= EF_ListJobUnrestricted;
+ else
+ extraFlags() &= ~EF_ListJobUnrestricted;
+}
+
+void ListJob::start(Slave *slave)
+{
+ if (kapp && !kapp->authorizeURLAction("list", m_url, m_url) && !(extraFlags() & EF_ListJobUnrestricted))
+ {
+ m_error = ERR_ACCESS_DENIED;
+ m_errorText = m_url.url();
+ TQTimer::singleShot(0, this, TQT_SLOT(slotFinished()) );
+ return;
+ }
+ connect( slave, TQT_SIGNAL( listEntries( const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotListEntries( const TDEIO::UDSEntryList& )));
+ connect( slave, TQT_SIGNAL( totalSize( TDEIO::filesize_t ) ),
+ TQT_SLOT( slotTotalSize( TDEIO::filesize_t ) ) );
+ connect( slave, TQT_SIGNAL( redirection(const KURL &) ),
+ TQT_SLOT( slotRedirection(const KURL &) ) );
+
+ SimpleJob::start(slave);
+}
+
+class CopyJob::CopyJobPrivate
+{
+public:
+ CopyJobPrivate() {
+ m_defaultPermissions = false;
+ m_bURLDirty = false;
+ }
+ // This is the dest URL that was initially given to CopyJob
+ // It is copied into m_dest, which can be changed for a given src URL
+ // (when using the RENAME dialog in slotResult),
+ // and which will be reset for the next src URL.
+ KURL m_globalDest;
+ // The state info about that global dest
+ CopyJob::DestinationState m_globalDestinationState;
+ // See setDefaultPermissions
+ bool m_defaultPermissions;
+ // Whether URLs changed (and need to be emitted by the next slotReport call)
+ bool m_bURLDirty;
+ // Used after copying all the files into the dirs, to set mtime (TODO: and permissions?)
+ // after the copy is done
+ TQValueList<CopyInfo> m_directoriesCopied;
+};
+
+CopyJob::CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo )
+ : Job(showProgressInfo), m_mode(mode), m_asMethod(asMethod),
+ destinationState(DEST_NOT_STATED), state(STATE_STATING),
+ m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0),
+ m_processedFiles(0), m_processedDirs(0),
+ m_srcList(src), m_currentStatSrc(m_srcList.begin()),
+ m_bCurrentOperationIsLink(false), m_bSingleFileCopy(false), m_bOnlyRenames(mode==Move),
+ m_dest(dest), m_bAutoSkip( false ), m_bOverwriteAll( false ),
+ m_conflictError(0), m_reportTimer(0)
+{
+ d = new CopyJobPrivate;
+ d->m_globalDest = dest;
+ d->m_globalDestinationState = destinationState;
+
+ if ( showProgressInfo ) {
+ connect( this, TQT_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
+
+ connect( this, TQT_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
+ }
+ TQTimer::singleShot(0, this, TQT_SLOT(slotStart()));
+ /**
+ States:
+ STATE_STATING for the dest
+ STATE_STATING for each src url (statNextSrc)
+ for each: if dir -> STATE_LISTING (filling 'dirs' and 'files')
+ but if direct rename possible: STATE_RENAMING instead.
+ STATE_CREATING_DIRS (createNextDir, iterating over 'dirs')
+ if conflict: STATE_CONFLICT_CREATING_DIRS
+ STATE_COPYING_FILES (copyNextFile, iterating over 'files')
+ if conflict: STATE_CONFLICT_COPYING_FILES
+ STATE_DELETING_DIRS (deleteNextDir) (if moving)
+ STATE_SETTING_DIR_ATTRIBUTES (setNextDirAttribute, iterating over d->m_directoriesCopied)
+ done.
+ */
+}
+
+CopyJob::~CopyJob()
+{
+ delete d;
+}
+
+void CopyJob::slotStart()
+{
+ /**
+ We call the functions directly instead of using signals.
+ Calling a function via a signal takes approx. 65 times the time
+ compared to calling it directly (at least on my machine). aleXXX
+ */
+ m_reportTimer = new TQTimer(this);
+
+ connect(m_reportTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(slotReport()));
+ m_reportTimer->start(REPORT_TIMEOUT,false);
+
+ // Stat the dest
+ TDEIO::Job * job = TDEIO::stat( m_dest, false, 2, false );
+ //kdDebug(7007) << "CopyJob:stating the dest " << m_dest << endl;
+ addSubjob(job);
+}
+
+// For unit test purposes
+TDEIO_EXPORT bool kio_resolve_local_urls = true;
+
+void CopyJob::slotResultStating( Job *job )
+{
+ //kdDebug(7007) << "CopyJob::slotResultStating" << endl;
+ // Was there an error while stating the src ?
+ if (job->error() && destinationState != DEST_NOT_STATED )
+ {
+ KURL srcurl = ((SimpleJob*)job)->url();
+ if ( !srcurl.isLocalFile() )
+ {
+ // Probably : src doesn't exist. Well, over some protocols (e.g. FTP)
+ // this info isn't really reliable (thanks to MS FTP servers).
+ // We'll assume a file, and try to download anyway.
+ kdDebug(7007) << "Error while stating source. Activating hack" << endl;
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
+ struct CopyInfo info;
+ info.permissions = (mode_t) -1;
+ info.mtime = (time_t) -1;
+ info.ctime = (time_t) -1;
+ info.size = (TDEIO::filesize_t)-1;
+ info.uSource = srcurl;
+ info.uDest = m_dest;
+ // Append filename or dirname to destination URL, if allowed
+ if ( destinationState == DEST_IS_DIR && !m_asMethod )
+ info.uDest.addPath( srcurl.fileName() );
+
+ files.append( info );
+ statNextSrc();
+ return;
+ }
+ // Local file. If stat fails, the file definitely doesn't exist.
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+
+ // Is it a file or a dir ? Does it have a local path?
+ UDSEntry entry = ((StatJob*)job)->statResult();
+ bool bDir = false;
+ bool bLink = false;
+ TQString sName;
+ TQString sLocalPath;
+ UDSEntry::ConstIterator it2 = entry.begin();
+ for( ; it2 != entry.end(); it2++ ) {
+ if ( ((*it2).m_uds) == UDS_FILE_TYPE )
+ bDir = S_ISDIR( (mode_t)(*it2).m_long );
+ else if ( ((*it2).m_uds) == UDS_LINK_DEST )
+ bLink = !((*it2).m_str.isEmpty());
+ else if ( ((*it2).m_uds) == UDS_NAME )
+ sName = (*it2).m_str;
+ else if ( ((*it2).m_uds) == UDS_LOCAL_PATH )
+ sLocalPath = (*it2).m_str;
+ }
+
+ if ( destinationState == DEST_NOT_STATED )
+ // we were stating the dest
+ {
+ if (job->error())
+ destinationState = DEST_DOESNT_EXIST;
+ else {
+ // Treat symlinks to dirs as dirs here, so no test on bLink
+ destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
+ //kdDebug(7007) << "CopyJob::slotResultStating dest is dir:" << bDir << endl;
+ }
+ const bool isGlobalDest = m_dest == d->m_globalDest;
+ if ( isGlobalDest )
+ d->m_globalDestinationState = destinationState;
+
+ if ( !sLocalPath.isEmpty() && kio_resolve_local_urls ) {
+ m_dest = KURL();
+ m_dest.setPath(sLocalPath);
+ if ( isGlobalDest )
+ d->m_globalDest = m_dest;
+ }
+
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+
+ // After knowing what the dest is, we can start stat'ing the first src.
+ statCurrentSrc();
+ return;
+ }
+ // We were stating the current source URL
+ m_currentDest = m_dest; // used by slotEntries
+ // Create a dummy list with it, for slotEntries
+ UDSEntryList lst;
+ lst.append(entry);
+
+ // There 6 cases, and all end up calling slotEntries(job, lst) first :
+ // 1 - src is a dir, destination is a directory,
+ // slotEntries will append the source-dir-name to the destination
+ // 2 - src is a dir, destination is a file, ERROR (done later on)
+ // 3 - src is a dir, destination doesn't exist, then it's the destination dirname,
+ // so slotEntries will use it as destination.
+
+ // 4 - src is a file, destination is a directory,
+ // slotEntries will append the filename to the destination.
+ // 5 - src is a file, destination is a file, m_dest is the exact destination name
+ // 6 - src is a file, destination doesn't exist, m_dest is the exact destination name
+ // Tell slotEntries not to alter the src url
+ m_bCurrentSrcIsDir = false;
+ slotEntries(job, lst);
+
+ KURL srcurl;
+ if (!sLocalPath.isEmpty())
+ srcurl.setPath(sLocalPath);
+ else
+ srcurl = ((SimpleJob*)job)->url();
+
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
+
+ if ( bDir
+ && !bLink // treat symlinks as files (no recursion)
+ && m_mode != Link ) // No recursion in Link mode either.
+ {
+ //kdDebug(7007) << " Source is a directory " << endl;
+
+ m_bCurrentSrcIsDir = true; // used by slotEntries
+ if ( destinationState == DEST_IS_DIR ) // (case 1)
+ {
+ if ( !m_asMethod )
+ {
+ // Use <desturl>/<directory_copied> as destination, from now on
+ TQString directory = srcurl.fileName();
+ if ( !sName.isEmpty() && KProtocolInfo::fileNameUsedForCopying( srcurl ) == KProtocolInfo::Name )
+ {
+ directory = sName;
+ }
+ m_currentDest.addPath( directory );
+ }
+ }
+ else if ( destinationState == DEST_IS_FILE ) // (case 2)
+ {
+ m_error = ERR_IS_FILE;
+ m_errorText = m_dest.prettyURL();
+ emitResult();
+ return;
+ }
+ else // (case 3)
+ {
+ // otherwise dest is new name for toplevel dir
+ // so the destination exists, in fact, from now on.
+ // (This even works with other src urls in the list, since the
+ // dir has effectively been created)
+ destinationState = DEST_IS_DIR;
+ if ( m_dest == d->m_globalDest )
+ d->m_globalDestinationState = destinationState;
+ }
+
+ startListing( srcurl );
+ }
+ else
+ {
+ //kdDebug(7007) << " Source is a file (or a symlink), or we are linking -> no recursive listing " << endl;
+ statNextSrc();
+ }
+}
+
+void CopyJob::slotReport()
+{
+ // If showProgressInfo was set, m_progressId is > 0.
+ Observer * observer = m_progressId ? Observer::self() : 0L;
+ switch (state) {
+ case STATE_COPYING_FILES:
+ emit processedFiles( this, m_processedFiles );
+ if (observer) observer->slotProcessedFiles(this, m_processedFiles);
+ if (d->m_bURLDirty)
+ {
+ // Only emit urls when they changed. This saves time, and fixes #66281
+ d->m_bURLDirty = false;
+ if (m_mode==Move)
+ {
+ if (observer) observer->slotMoving( this, m_currentSrcURL, m_currentDestURL);
+ emit moving( this, m_currentSrcURL, m_currentDestURL);
+ }
+ else if (m_mode==Link)
+ {
+ if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL ); // we don't have a slotLinking
+ emit linking( this, m_currentSrcURL.path(), m_currentDestURL );
+ }
+ else
+ {
+ if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
+ emit copying( this, m_currentSrcURL, m_currentDestURL );
+ }
+ }
+ break;
+
+ case STATE_CREATING_DIRS:
+ if (observer) observer->slotProcessedDirs( this, m_processedDirs );
+ emit processedDirs( this, m_processedDirs );
+ if (d->m_bURLDirty)
+ {
+ d->m_bURLDirty = false;
+ emit creatingDir( this, m_currentDestURL );
+ if (observer) observer->slotCreatingDir( this, m_currentDestURL);
+ }
+ break;
+
+ case STATE_STATING:
+ case STATE_LISTING:
+ if (d->m_bURLDirty)
+ {
+ d->m_bURLDirty = false;
+ if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
+ }
+ emit totalSize( this, m_totalSize );
+ emit totalFiles( this, files.count() );
+ emit totalDirs( this, dirs.count() );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void CopyJob::slotEntries(TDEIO::Job* job, const UDSEntryList& list)
+{
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+ UDSEntry::ConstIterator it2 = (*it).begin();
+ struct CopyInfo info;
+ info.permissions = -1;
+ info.mtime = (time_t) -1;
+ info.ctime = (time_t) -1;
+ info.size = (TDEIO::filesize_t)-1;
+ TQString displayName;
+ KURL url;
+ TQString localPath;
+ bool isDir = false;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch ((*it2).m_uds) {
+ case UDS_FILE_TYPE:
+ //info.type = (mode_t)((*it2).m_long);
+ isDir = S_ISDIR( (mode_t)((*it2).m_long) );
+ break;
+ case UDS_NAME: // recursive listing, displayName can be a/b/c/d
+ displayName = (*it2).m_str;
+ break;
+ case UDS_URL: // optional
+ url = KURL((*it2).m_str);
+ break;
+ case UDS_LOCAL_PATH:
+ localPath = (*it2).m_str;
+ break;
+ case UDS_LINK_DEST:
+ info.linkDest = (*it2).m_str;
+ break;
+ case UDS_ACCESS:
+ info.permissions = ((*it2).m_long);
+ break;
+ case UDS_SIZE:
+ info.size = (TDEIO::filesize_t)((*it2).m_long);
+ m_totalSize += info.size;
+ break;
+ case UDS_MODIFICATION_TIME:
+ info.mtime = (time_t)((*it2).m_long);
+ break;
+ case UDS_CREATION_TIME:
+ info.ctime = (time_t)((*it2).m_long);
+ default:
+ break;
+ }
+ }
+ if (displayName != ".." && displayName != ".")
+ {
+ bool hasCustomURL = !url.isEmpty() || !localPath.isEmpty();
+ if( !hasCustomURL ) {
+ // Make URL from displayName
+ url = ((SimpleJob *)job)->url();
+ if ( m_bCurrentSrcIsDir ) { // Only if src is a directory. Otherwise uSource is fine as is
+ //kdDebug(7007) << "adding path " << displayName << endl;
+ url.addPath( displayName );
+ }
+ }
+ //kdDebug(7007) << "displayName=" << displayName << " url=" << url << endl;
+ if (!localPath.isEmpty() && kio_resolve_local_urls) {
+ url = KURL();
+ url.setPath(localPath);
+ }
+
+ info.uSource = url;
+ info.uDest = m_currentDest;
+ //kdDebug(7007) << " uSource=" << info.uSource << " uDest(1)=" << info.uDest << endl;
+ // Append filename or dirname to destination URL, if allowed
+ if ( destinationState == DEST_IS_DIR &&
+ // "copy/move as <foo>" means 'foo' is the dest for the base srcurl
+ // (passed here during stating) but not its children (during listing)
+ ( ! ( m_asMethod && state == STATE_STATING ) ) )
+ {
+ TQString destFileName;
+ if ( hasCustomURL &&
+ KProtocolInfo::fileNameUsedForCopying( url ) == KProtocolInfo::FromURL ) {
+ //destFileName = url.fileName(); // Doesn't work for recursive listing
+ // Count the number of prefixes used by the recursive listjob
+ int numberOfSlashes = displayName.contains( '/' ); // don't make this a find()!
+ TQString path = url.path();
+ int pos = 0;
+ for ( int n = 0; n < numberOfSlashes + 1; ++n ) {
+ pos = path.findRev( '/', pos - 1 );
+ if ( pos == -1 ) { // error
+ kdWarning(7007) << "tdeioslave bug: not enough slashes in UDS_URL " << path << " - looking for " << numberOfSlashes << " slashes" << endl;
+ break;
+ }
+ }
+ if ( pos >= 0 ) {
+ destFileName = path.mid( pos + 1 );
+ }
+
+ } else { // destination filename taken from UDS_NAME
+ destFileName = displayName;
+ }
+
+ // Here we _really_ have to add some filename to the dest.
+ // Otherwise, we end up with e.g. dest=..../Desktop/ itself.
+ // (This can happen when dropping a link to a webpage with no path)
+ if ( destFileName.isEmpty() )
+ destFileName = TDEIO::encodeFileName( info.uSource.prettyURL() );
+
+ //kdDebug(7007) << " adding destFileName=" << destFileName << endl;
+ info.uDest.addPath( destFileName );
+ }
+ //kdDebug(7007) << " uDest(2)=" << info.uDest << endl;
+ //kdDebug(7007) << " " << info.uSource << " -> " << info.uDest << endl;
+ if ( info.linkDest.isEmpty() && isDir && m_mode != Link ) // Dir
+ {
+ dirs.append( info ); // Directories
+ if (m_mode == Move)
+ dirsToRemove.append( info.uSource );
+ }
+ else {
+ files.append( info ); // Files and any symlinks
+ }
+ }
+ }
+}
+
+void CopyJob::skipSrc()
+{
+ m_dest = d->m_globalDest;
+ destinationState = d->m_globalDestinationState;
+ ++m_currentStatSrc;
+ skip( m_currentSrcURL );
+ statCurrentSrc();
+}
+
+void CopyJob::statNextSrc()
+{
+ /* Revert to the global destination, the one that applies to all source urls.
+ * Imagine you copy the items a b and c into /d, but /d/b exists so the user uses "Rename" to put it in /foo/b instead.
+ * m_dest is /foo/b for b, but we have to revert to /d for item c and following.
+ */
+ m_dest = d->m_globalDest;
+ destinationState = d->m_globalDestinationState;
+ ++m_currentStatSrc;
+ statCurrentSrc();
+}
+
+void CopyJob::statCurrentSrc()
+{
+ if ( m_currentStatSrc != m_srcList.end() )
+ {
+ m_currentSrcURL = (*m_currentStatSrc);
+ d->m_bURLDirty = true;
+ if ( m_mode == Link )
+ {
+ // Skip the "stating the source" stage, we don't need it for linking
+ m_currentDest = m_dest;
+ struct CopyInfo info;
+ info.permissions = -1;
+ info.mtime = (time_t) -1;
+ info.ctime = (time_t) -1;
+ info.size = (TDEIO::filesize_t)-1;
+ info.uSource = m_currentSrcURL;
+ info.uDest = m_currentDest;
+ // Append filename or dirname to destination URL, if allowed
+ if ( destinationState == DEST_IS_DIR && !m_asMethod )
+ {
+ if (
+ (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
+ (m_currentSrcURL.host() == info.uDest.host()) &&
+ (m_currentSrcURL.port() == info.uDest.port()) &&
+ (m_currentSrcURL.user() == info.uDest.user()) &&
+ (m_currentSrcURL.pass() == info.uDest.pass()) )
+ {
+ // This is the case of creating a real symlink
+ info.uDest.addPath( m_currentSrcURL.fileName() );
+ }
+ else
+ {
+ // Different protocols, we'll create a .desktop file
+ // We have to change the extension anyway, so while we're at it,
+ // name the file like the URL
+ info.uDest.addPath( TDEIO::encodeFileName( m_currentSrcURL.prettyURL() )+".desktop" );
+ }
+ }
+ files.append( info ); // Files and any symlinks
+ statNextSrc(); // we could use a loop instead of a recursive call :)
+ return;
+ }
+ else if ( m_mode == Move && (
+ // Don't go renaming right away if we need a stat() to find out the destination filename
+ KProtocolInfo::fileNameUsedForCopying( m_currentSrcURL ) == KProtocolInfo::FromURL ||
+ destinationState != DEST_IS_DIR || m_asMethod )
+ )
+ {
+ // If moving, before going for the full stat+[list+]copy+del thing, try to rename
+ // The logic is pretty similar to FileCopyJob::slotStart()
+ if ( (m_currentSrcURL.protocol() == m_dest.protocol()) &&
+ (m_currentSrcURL.host() == m_dest.host()) &&
+ (m_currentSrcURL.port() == m_dest.port()) &&
+ (m_currentSrcURL.user() == m_dest.user()) &&
+ (m_currentSrcURL.pass() == m_dest.pass()) )
+ {
+ startRenameJob( m_currentSrcURL );
+ return;
+ }
+ else if ( m_currentSrcURL.isLocalFile() && KProtocolInfo::canRenameFromFile( m_dest ) )
+ {
+ startRenameJob( m_dest );
+ return;
+ }
+ else if ( m_dest.isLocalFile() && KProtocolInfo::canRenameToFile( m_currentSrcURL ) )
+ {
+ startRenameJob( m_currentSrcURL );
+ return;
+ }
+ }
+
+ // if the file system doesn't support deleting, we do not even stat
+ if (m_mode == Move && !KProtocolInfo::supportsDeleting(m_currentSrcURL)) {
+ TQGuardedPtr<CopyJob> that = this;
+ if (isInteractive())
+ KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyURL()));
+ if (that)
+ statNextSrc(); // we could use a loop instead of a recursive call :)
+ return;
+ }
+
+ // Stat the next src url
+ Job * job = TDEIO::stat( m_currentSrcURL, true, 2, false );
+ //kdDebug(7007) << "TDEIO::stat on " << m_currentSrcURL << endl;
+ state = STATE_STATING;
+ addSubjob(job);
+ m_currentDestURL=m_dest;
+ m_bOnlyRenames = false;
+ d->m_bURLDirty = true;
+ }
+ else
+ {
+ // Finished the stat'ing phase
+ // First make sure that the totals were correctly emitted
+ state = STATE_STATING;
+ d->m_bURLDirty = true;
+ slotReport();
+ if (!dirs.isEmpty())
+ emit aboutToCreate( this, dirs );
+ if (!files.isEmpty())
+ emit aboutToCreate( this, files );
+ // Check if we are copying a single file
+ m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
+ // Then start copying things
+ state = STATE_CREATING_DIRS;
+ createNextDir();
+ }
+}
+
+void CopyJob::startRenameJob( const KURL& slave_url )
+{
+ KURL dest = m_dest;
+ // Append filename or dirname to destination URL, if allowed
+ if ( destinationState == DEST_IS_DIR && !m_asMethod )
+ dest.addPath( m_currentSrcURL.fileName() );
+ kdDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del" << endl;
+ state = STATE_RENAMING;
+
+ struct CopyInfo info;
+ info.permissions = -1;
+ info.mtime = (time_t) -1;
+ info.ctime = (time_t) -1;
+ info.size = (TDEIO::filesize_t)-1;
+ info.uSource = m_currentSrcURL;
+ info.uDest = dest;
+ TQValueList<CopyInfo> files;
+ files.append(info);
+ emit aboutToCreate( this, files );
+
+ KIO_ARGS << m_currentSrcURL << dest << (TQ_INT8) false /*no overwrite*/;
+ SimpleJob * newJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
+ Scheduler::scheduleJob(newJob);
+ addSubjob( newJob );
+ if ( m_currentSrcURL.directory() != dest.directory() ) // For the user, moving isn't renaming. Only renaming is.
+ m_bOnlyRenames = false;
+}
+
+void CopyJob::startListing( const KURL & src )
+{
+ state = STATE_LISTING;
+ d->m_bURLDirty = true;
+ ListJob * newjob = listRecursive( src, false );
+ newjob->setUnrestricted(true);
+ connect(newjob, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob( newjob );
+}
+
+void CopyJob::skip( const KURL & sourceUrl )
+{
+ // Check if this is one if toplevel sources
+ // If yes, remove it from m_srcList, for a correct FilesRemoved() signal
+ //kdDebug(7007) << "CopyJob::skip: looking for " << sourceUrl << endl;
+ KURL::List::Iterator sit = m_srcList.find( sourceUrl );
+ if ( sit != m_srcList.end() )
+ {
+ //kdDebug(7007) << "CopyJob::skip: removing " << sourceUrl << " from list" << endl;
+ m_srcList.remove( sit );
+ }
+ dirsToRemove.remove( sourceUrl );
+}
+
+bool CopyJob::shouldOverwrite( const TQString& path ) const
+{
+ if ( m_bOverwriteAll )
+ return true;
+ TQStringList::ConstIterator sit = m_overwriteList.begin();
+ for( ; sit != m_overwriteList.end(); ++sit )
+ if ( path.startsWith( *sit ) )
+ return true;
+ return false;
+}
+
+bool CopyJob::shouldSkip( const TQString& path ) const
+{
+ TQStringList::ConstIterator sit = m_skipList.begin();
+ for( ; sit != m_skipList.end(); ++sit )
+ if ( path.startsWith( *sit ) )
+ return true;
+ return false;
+}
+
+void CopyJob::slotResultCreatingDirs( Job * job )
+{
+ // The dir we are trying to create:
+ TQValueList<CopyInfo>::Iterator it = dirs.begin();
+ // Was there an error creating a dir ?
+ if ( job->error() )
+ {
+ m_conflictError = job->error();
+ if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
+ || (m_conflictError == ERR_FILE_ALREADY_EXIST) ) // can't happen?
+ {
+ KURL oldURL = ((SimpleJob*)job)->url();
+ // Should we skip automatically ?
+ if ( m_bAutoSkip ) {
+ // We don't want to copy files in this directory, so we put it on the skip list
+ m_skipList.append( oldURL.path( 1 ) );
+ skip( oldURL );
+ dirs.remove( it ); // Move on to next dir
+ } else {
+ // Did the user choose to overwrite already?
+ const TQString destFile = (*it).uDest.path();
+ if ( shouldOverwrite( destFile ) ) { // overwrite => just skip
+ emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
+ dirs.remove( it ); // Move on to next dir
+ } else {
+ if ( !isInteractive() ) {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+
+ assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
+
+ // We need to stat the existing dir, to get its last-modification time
+ KURL existingDest( (*it).uDest );
+ SimpleJob * newJob = TDEIO::stat( existingDest, false, 2, false );
+ Scheduler::scheduleJob(newJob);
+ kdDebug(7007) << "TDEIO::stat for resolving conflict on " << existingDest << endl;
+ state = STATE_CONFLICT_CREATING_DIRS;
+ addSubjob(newJob);
+ return; // Don't move to next dir yet !
+ }
+ }
+ }
+ else
+ {
+ // Severe error, abort
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ }
+ else // no error : remove from list, to move on to next dir
+ {
+ //this is required for the undo feature
+ emit copyingDone( this, (*it).uSource, (*it).uDest, true, false );
+ d->m_directoriesCopied.append( *it );
+ dirs.remove( it );
+ }
+
+ m_processedDirs++;
+ //emit processedDirs( this, m_processedDirs );
+ subjobs.remove( job );
+ assert( subjobs.isEmpty() ); // We should have only one job at a time ...
+ createNextDir();
+}
+
+void CopyJob::slotResultConflictCreatingDirs( TDEIO::Job * job )
+{
+ // We come here after a conflict has been detected and we've stated the existing dir
+
+ // The dir we were trying to create:
+ TQValueList<CopyInfo>::Iterator it = dirs.begin();
+ // Its modification time:
+ time_t destmtime = (time_t)-1;
+ time_t destctime = (time_t)-1;
+ TDEIO::filesize_t destsize = 0;
+ TQString linkDest;
+
+ UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
+ TDEIO::UDSEntry::ConstIterator it2 = entry.begin();
+ for( ; it2 != entry.end(); it2++ ) {
+ switch ((*it2).m_uds) {
+ case UDS_MODIFICATION_TIME:
+ destmtime = (time_t)((*it2).m_long);
+ break;
+ case UDS_CREATION_TIME:
+ destctime = (time_t)((*it2).m_long);
+ break;
+ case UDS_SIZE:
+ destsize = (*it2).m_long;
+ break;
+ case UDS_LINK_DEST:
+ linkDest = (*it2).m_str;
+ break;
+ }
+ }
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
+
+ // Always multi and skip (since there are files after that)
+ RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
+ // Overwrite only if the existing thing is a dir (no chance with a file)
+ if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
+ {
+ if( (*it).uSource == (*it).uDest ||
+ ((*it).uSource.protocol() == (*it).uDest.protocol() &&
+ (*it).uSource.path(-1) == linkDest) )
+ mode = (RenameDlg_Mode)( mode | M_OVERWRITE_ITSELF);
+ else
+ mode = (RenameDlg_Mode)( mode | M_OVERWRITE );
+ }
+
+ TQString existingDest = (*it).uDest.path();
+ TQString newPath;
+ if (m_reportTimer)
+ m_reportTimer->stop();
+ RenameDlg_Result r = Observer::self()->open_RenameDlg( this, i18n("Folder Already Exists"),
+ (*it).uSource.url(),
+ (*it).uDest.url(),
+ mode, newPath,
+ (*it).size, destsize,
+ (*it).ctime, destctime,
+ (*it).mtime, destmtime );
+ if (m_reportTimer)
+ m_reportTimer->start(REPORT_TIMEOUT,false);
+ switch ( r ) {
+ case R_CANCEL:
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ case R_RENAME:
+ {
+ TQString oldPath = (*it).uDest.path( 1 );
+ KURL newUrl( (*it).uDest );
+ newUrl.setPath( newPath );
+ emit renamed( this, (*it).uDest, newUrl ); // for e.g. kpropsdlg
+
+ // Change the current one and strip the trailing '/'
+ (*it).uDest.setPath( newUrl.path( -1 ) );
+ newPath = newUrl.path( 1 ); // With trailing slash
+ TQValueList<CopyInfo>::Iterator renamedirit = it;
+ ++renamedirit;
+ // Change the name of subdirectories inside the directory
+ for( ; renamedirit != dirs.end() ; ++renamedirit )
+ {
+ TQString path = (*renamedirit).uDest.path();
+ if ( path.left(oldPath.length()) == oldPath ) {
+ TQString n = path;
+ n.replace( 0, oldPath.length(), newPath );
+ kdDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
+ << " was going to be " << path
+ << ", changed into " << n << endl;
+ (*renamedirit).uDest.setPath( n );
+ }
+ }
+ // Change filenames inside the directory
+ TQValueList<CopyInfo>::Iterator renamefileit = files.begin();
+ for( ; renamefileit != files.end() ; ++renamefileit )
+ {
+ TQString path = (*renamefileit).uDest.path();
+ if ( path.left(oldPath.length()) == oldPath ) {
+ TQString n = path;
+ n.replace( 0, oldPath.length(), newPath );
+ kdDebug(7007) << "files list: " << (*renamefileit).uSource.path()
+ << " was going to be " << path
+ << ", changed into " << n << endl;
+ (*renamefileit).uDest.setPath( n );
+ }
+ }
+ if (!dirs.isEmpty())
+ emit aboutToCreate( this, dirs );
+ if (!files.isEmpty())
+ emit aboutToCreate( this, files );
+ }
+ break;
+ case R_AUTO_SKIP:
+ m_bAutoSkip = true;
+ // fall through
+ case R_SKIP:
+ m_skipList.append( existingDest );
+ skip( (*it).uSource );
+ // Move on to next dir
+ dirs.remove( it );
+ m_processedDirs++;
+ break;
+ case R_OVERWRITE:
+ m_overwriteList.append( existingDest );
+ emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
+ // Move on to next dir
+ dirs.remove( it );
+ m_processedDirs++;
+ break;
+ case R_OVERWRITE_ALL:
+ m_bOverwriteAll = true;
+ emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
+ // Move on to next dir
+ dirs.remove( it );
+ m_processedDirs++;
+ break;
+ default:
+ assert( 0 );
+ }
+ state = STATE_CREATING_DIRS;
+ //emit processedDirs( this, m_processedDirs );
+ createNextDir();
+}
+
+void CopyJob::createNextDir()
+{
+ KURL udir;
+ if ( !dirs.isEmpty() )
+ {
+ // Take first dir to create out of list
+ TQValueList<CopyInfo>::Iterator it = dirs.begin();
+ // Is this URL on the skip list or the overwrite list ?
+ while( it != dirs.end() && udir.isEmpty() )
+ {
+ const TQString dir = (*it).uDest.path();
+ if ( shouldSkip( dir ) ) {
+ dirs.remove( it );
+ it = dirs.begin();
+ } else
+ udir = (*it).uDest;
+ }
+ }
+ if ( !udir.isEmpty() ) // any dir to create, finally ?
+ {
+ // Create the directory - with default permissions so that we can put files into it
+ // TODO : change permissions once all is finished; but for stuff coming from CDROM it sucks...
+ TDEIO::SimpleJob *newjob = TDEIO::mkdir( udir, -1 );
+ Scheduler::scheduleJob(newjob);
+
+ m_currentDestURL = udir;
+ d->m_bURLDirty = true;
+
+ addSubjob(newjob);
+ return;
+ }
+ else // we have finished creating dirs
+ {
+ emit processedDirs( this, m_processedDirs ); // make sure final number appears
+ if (m_progressId) Observer::self()->slotProcessedDirs( this, m_processedDirs );
+
+ state = STATE_COPYING_FILES;
+ m_processedFiles++; // Ralf wants it to start at 1, not 0
+ copyNextFile();
+ }
+}
+
+void CopyJob::slotResultCopyingFiles( Job * job )
+{
+ // The file we were trying to copy:
+ TQValueList<CopyInfo>::Iterator it = files.begin();
+ if ( job->error() )
+ {
+ // Should we skip automatically ?
+ if ( m_bAutoSkip )
+ {
+ skip( (*it).uSource );
+ m_fileProcessedSize = (*it).size;
+ files.remove( it ); // Move on to next file
+ }
+ else
+ {
+ if ( !isInteractive() ) {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+
+ m_conflictError = job->error(); // save for later
+ // Existing dest ?
+ if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
+ || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
+ || ( m_conflictError == ERR_IDENTICAL_FILES ) )
+ {
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+ // We need to stat the existing file, to get its last-modification time
+ KURL existingFile( (*it).uDest );
+ SimpleJob * newJob = TDEIO::stat( existingFile, false, 2, false );
+ Scheduler::scheduleJob(newJob);
+ kdDebug(7007) << "TDEIO::stat for resolving conflict on " << existingFile << endl;
+ state = STATE_CONFLICT_COPYING_FILES;
+ addSubjob(newJob);
+ return; // Don't move to next file yet !
+ }
+ else
+ {
+ if ( m_bCurrentOperationIsLink && ::tqqt_cast<TDEIO::DeleteJob*>( job ) )
+ {
+ // Very special case, see a few lines below
+ // We are deleting the source of a symlink we successfully moved... ignore error
+ m_fileProcessedSize = (*it).size;
+ files.remove( it );
+ } else {
+ // Go directly to the conflict resolution, there is nothing to stat
+ slotResultConflictCopyingFiles( job );
+ return;
+ }
+ }
+ }
+ } else // no error
+ {
+ // Special case for moving links. That operation needs two jobs, unlike others.
+ if ( m_bCurrentOperationIsLink && m_mode == Move
+ && !::tqqt_cast<TDEIO::DeleteJob *>( job ) // Deleting source not already done
+ )
+ {
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+ // The only problem with this trick is that the error handling for this del operation
+ // is not going to be right... see 'Very special case' above.
+ TDEIO::Job * newjob = TDEIO::del( (*it).uSource, false /*don't shred*/, false /*no GUI*/ );
+ addSubjob( newjob );
+ return; // Don't move to next file yet !
+ }
+
+ if ( m_bCurrentOperationIsLink )
+ {
+ TQString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
+ //required for the undo feature
+ emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
+ }
+ else
+ //required for the undo feature
+ emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
+ // remove from list, to move on to next file
+ files.remove( it );
+ }
+ m_processedFiles++;
+
+ // clear processed size for last file and add it to overall processed size
+ m_processedSize += m_fileProcessedSize;
+ m_fileProcessedSize = 0;
+
+ //kdDebug(7007) << files.count() << " files remaining" << endl;
+
+ removeSubjob( job, true, false ); // merge metadata
+ assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
+ copyNextFile();
+}
+
+void CopyJob::slotResultConflictCopyingFiles( TDEIO::Job * job )
+{
+ // We come here after a conflict has been detected and we've stated the existing file
+ // The file we were trying to create:
+ TQValueList<CopyInfo>::Iterator it = files.begin();
+
+ RenameDlg_Result res;
+ TQString newPath;
+
+ if (m_reportTimer)
+ m_reportTimer->stop();
+
+ if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
+ || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
+ || ( m_conflictError == ERR_IDENTICAL_FILES ) )
+ {
+ // Its modification time:
+ time_t destmtime = (time_t)-1;
+ time_t destctime = (time_t)-1;
+ TDEIO::filesize_t destsize = 0;
+ TQString linkDest;
+ UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
+ TDEIO::UDSEntry::ConstIterator it2 = entry.begin();
+ for( ; it2 != entry.end(); it2++ ) {
+ switch ((*it2).m_uds) {
+ case UDS_MODIFICATION_TIME:
+ destmtime = (time_t)((*it2).m_long);
+ break;
+ case UDS_CREATION_TIME:
+ destctime = (time_t)((*it2).m_long);
+ break;
+ case UDS_SIZE:
+ destsize = (*it2).m_long;
+ break;
+ case UDS_LINK_DEST:
+ linkDest = (*it2).m_str;
+ break;
+ }
+ }
+
+ // Offer overwrite only if the existing thing is a file
+ // If src==dest, use "overwrite-itself"
+ RenameDlg_Mode mode;
+ bool isDir = true;
+
+ if( m_conflictError == ERR_DIR_ALREADY_EXIST )
+ mode = (RenameDlg_Mode) 0;
+ else
+ {
+ if ( (*it).uSource == (*it).uDest ||
+ ((*it).uSource.protocol() == (*it).uDest.protocol() &&
+ (*it).uSource.path(-1) == linkDest) )
+ mode = M_OVERWRITE_ITSELF;
+ else
+ mode = M_OVERWRITE;
+ isDir = false;
+ }
+
+ if ( m_bSingleFileCopy )
+ mode = (RenameDlg_Mode) ( mode | M_SINGLE );
+ else
+ mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
+
+ res = Observer::self()->open_RenameDlg( this, !isDir ?
+ i18n("File Already Exists") : i18n("Already Exists as Folder"),
+ (*it).uSource.url(),
+ (*it).uDest.url(),
+ mode, newPath,
+ (*it).size, destsize,
+ (*it).ctime, destctime,
+ (*it).mtime, destmtime );
+
+ }
+ else
+ {
+ if ( job->error() == ERR_USER_CANCELED )
+ res = R_CANCEL;
+ else if ( !isInteractive() ) {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ else
+ {
+ SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
+ job->errorString() );
+
+ // Convert the return code from SkipDlg into a RenameDlg code
+ res = ( skipResult == S_SKIP ) ? R_SKIP :
+ ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
+ R_CANCEL;
+ }
+ }
+
+ if (m_reportTimer)
+ m_reportTimer->start(REPORT_TIMEOUT,false);
+
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+ switch ( res ) {
+ case R_CANCEL:
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ case R_RENAME:
+ {
+ KURL newUrl( (*it).uDest );
+ newUrl.setPath( newPath );
+ emit renamed( this, (*it).uDest, newUrl ); // for e.g. kpropsdlg
+ (*it).uDest = newUrl;
+
+ TQValueList<CopyInfo> files;
+ files.append(*it);
+ emit aboutToCreate( this, files );
+ }
+ break;
+ case R_AUTO_SKIP:
+ m_bAutoSkip = true;
+ // fall through
+ case R_SKIP:
+ // Move on to next file
+ skip( (*it).uSource );
+ m_processedSize += (*it).size;
+ files.remove( it );
+ m_processedFiles++;
+ break;
+ case R_OVERWRITE_ALL:
+ m_bOverwriteAll = true;
+ break;
+ case R_OVERWRITE:
+ // Add to overwrite list, so that copyNextFile knows to overwrite
+ m_overwriteList.append( (*it).uDest.path() );
+ break;
+ default:
+ assert( 0 );
+ }
+ state = STATE_COPYING_FILES;
+ //emit processedFiles( this, m_processedFiles );
+ copyNextFile();
+}
+
+void CopyJob::copyNextFile()
+{
+ bool bCopyFile = false;
+ //kdDebug(7007) << "CopyJob::copyNextFile()" << endl;
+ // Take the first file in the list
+ TQValueList<CopyInfo>::Iterator it = files.begin();
+ // Is this URL on the skip list ?
+ while (it != files.end() && !bCopyFile)
+ {
+ const TQString destFile = (*it).uDest.path();
+ bCopyFile = !shouldSkip( destFile );
+ if ( !bCopyFile ) {
+ files.remove( it );
+ it = files.begin();
+ }
+ }
+
+ if (bCopyFile) // any file to create, finally ?
+ {
+ // Do we set overwrite ?
+ bool bOverwrite;
+ const TQString destFile = (*it).uDest.path();
+ kdDebug(7007) << "copying " << destFile << endl;
+ if ( (*it).uDest == (*it).uSource )
+ bOverwrite = false;
+ else
+ bOverwrite = shouldOverwrite( destFile );
+
+ m_bCurrentOperationIsLink = false;
+ TDEIO::Job * newjob = 0L;
+ if ( m_mode == Link )
+ {
+ //kdDebug(7007) << "Linking" << endl;
+ if (
+ ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
+ ((*it).uSource.host() == (*it).uDest.host()) &&
+ ((*it).uSource.port() == (*it).uDest.port()) &&
+ ((*it).uSource.user() == (*it).uDest.user()) &&
+ ((*it).uSource.pass() == (*it).uDest.pass()) )
+ {
+ // This is the case of creating a real symlink
+ TDEIO::SimpleJob *newJob = TDEIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false /*no GUI*/ );
+ newjob = newJob;
+ Scheduler::scheduleJob(newJob);
+ //kdDebug(7007) << "CopyJob::copyNextFile : Linking target=" << (*it).uSource.path() << " link=" << (*it).uDest << endl;
+ //emit linking( this, (*it).uSource.path(), (*it).uDest );
+ m_bCurrentOperationIsLink = true;
+ m_currentSrcURL=(*it).uSource;
+ m_currentDestURL=(*it).uDest;
+ d->m_bURLDirty = true;
+ //Observer::self()->slotCopying( this, (*it).uSource, (*it).uDest ); // should be slotLinking perhaps
+ } else {
+ //kdDebug(7007) << "CopyJob::copyNextFile : Linking URL=" << (*it).uSource << " link=" << (*it).uDest << endl;
+ if ( (*it).uDest.isLocalFile() )
+ {
+ bool devicesOk=false;
+
+ // if the source is a devices url, handle it a littlebit special
+ if ((*it).uSource.protocol()==TQString::fromLatin1("devices"))
+ {
+ TQByteArray data;
+ TQByteArray param;
+ TQCString retType;
+ TQDataStream streamout(param,IO_WriteOnly);
+ streamout<<(*it).uSource;
+ streamout<<(*it).uDest;
+ if ( kapp && kapp->dcopClient()->call( "kded",
+ "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
+ {
+ TQDataStream streamin(data,IO_ReadOnly);
+ streamin>>devicesOk;
+ }
+ if (devicesOk)
+ {
+ files.remove( it );
+ m_processedFiles++;
+ //emit processedFiles( this, m_processedFiles );
+ copyNextFile();
+ return;
+ }
+ }
+
+ if (!devicesOk)
+ {
+ TQString path = (*it).uDest.path();
+ //kdDebug(7007) << "CopyJob::copyNextFile path=" << path << endl;
+ TQFile f( path );
+ if ( f.open( IO_ReadWrite ) )
+ {
+ f.close();
+ KSimpleConfig config( path );
+ config.setDesktopGroup();
+ KURL url = (*it).uSource;
+ url.setPass( "" );
+ config.writePathEntry( TQString::fromLatin1("URL"), url.url() );
+ config.writeEntry( TQString::fromLatin1("Name"), url.url() );
+ config.writeEntry( TQString::fromLatin1("Type"), TQString::fromLatin1("Link") );
+ TQString protocol = (*it).uSource.protocol();
+ if ( protocol == TQString::fromLatin1("ftp") )
+ config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("ftp") );
+ else if ( protocol == TQString::fromLatin1("http") )
+ config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("www") );
+ else if ( protocol == TQString::fromLatin1("info") )
+ config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("info") );
+ else if ( protocol == TQString::fromLatin1("mailto") ) // sven:
+ config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("kmail") ); // added mailto: support
+ else
+ config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("unknown") );
+ config.sync();
+ files.remove( it );
+ m_processedFiles++;
+ //emit processedFiles( this, m_processedFiles );
+ copyNextFile();
+ return;
+ }
+ else
+ {
+ kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
+ m_error = ERR_CANNOT_OPEN_FOR_WRITING;
+ m_errorText = (*it).uDest.path();
+ emitResult();
+ return;
+ }
+ }
+ } else {
+ // Todo: not show "link" on remote dirs if the src urls are not from the same protocol+host+...
+ m_error = ERR_CANNOT_SYMLINK;
+ m_errorText = (*it).uDest.prettyURL();
+ emitResult();
+ return;
+ }
+ }
+ }
+ else if ( !(*it).linkDest.isEmpty() &&
+ ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
+ ((*it).uSource.host() == (*it).uDest.host()) &&
+ ((*it).uSource.port() == (*it).uDest.port()) &&
+ ((*it).uSource.user() == (*it).uDest.user()) &&
+ ((*it).uSource.pass() == (*it).uDest.pass()))
+ // Copying a symlink - only on the same protocol/host/etc. (#5601, downloading an FTP file through its link),
+ {
+ TDEIO::SimpleJob *newJob = TDEIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false /*no GUI*/ );
+ Scheduler::scheduleJob(newJob);
+ newjob = newJob;
+ //kdDebug(7007) << "CopyJob::copyNextFile : Linking target=" << (*it).linkDest << " link=" << (*it).uDest << endl;
+ //emit linking( this, (*it).linkDest, (*it).uDest );
+ m_currentSrcURL=(*it).linkDest;
+ m_currentDestURL=(*it).uDest;
+ d->m_bURLDirty = true;
+ //Observer::self()->slotCopying( this, (*it).linkDest, (*it).uDest ); // should be slotLinking perhaps
+ m_bCurrentOperationIsLink = true;
+ // NOTE: if we are moving stuff, the deletion of the source will be done in slotResultCopyingFiles
+ } else if (m_mode == Move) // Moving a file
+ {
+ TDEIO::FileCopyJob * moveJob = TDEIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false/*no GUI*/ );
+ moveJob->setSourceSize64( (*it).size );
+ newjob = moveJob;
+ //kdDebug(7007) << "CopyJob::copyNextFile : Moving " << (*it).uSource << " to " << (*it).uDest << endl;
+ //emit moving( this, (*it).uSource, (*it).uDest );
+ m_currentSrcURL=(*it).uSource;
+ m_currentDestURL=(*it).uDest;
+ d->m_bURLDirty = true;
+ //Observer::self()->slotMoving( this, (*it).uSource, (*it).uDest );
+ }
+ else // Copying a file
+ {
+ // If source isn't local and target is local, we ignore the original permissions
+ // Otherwise, files downloaded from HTTP end up with -r--r--r--
+ bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
+ int permissions = (*it).permissions;
+ if ( d->m_defaultPermissions || ( remoteSource && (*it).uDest.isLocalFile() ) )
+ permissions = -1;
+ TDEIO::FileCopyJob * copyJob = TDEIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false/*no GUI*/ );
+ copyJob->setParentJob( this ); // in case of rename dialog
+ copyJob->setSourceSize64( (*it).size );
+ copyJob->setModificationTime( (*it).mtime );
+ newjob = copyJob;
+ //kdDebug(7007) << "CopyJob::copyNextFile : Copying " << (*it).uSource << " to " << (*it).uDest << endl;
+ m_currentSrcURL=(*it).uSource;
+ m_currentDestURL=(*it).uDest;
+ d->m_bURLDirty = true;
+ }
+ addSubjob(newjob);
+ connect( newjob, TQT_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ this, TQT_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( newjob, TQT_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ this, TQT_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ }
+ else
+ {
+ // We're done
+ //kdDebug(7007) << "copyNextFile finished" << endl;
+ deleteNextDir();
+ }
+}
+
+void CopyJob::deleteNextDir()
+{
+ if ( m_mode == Move && !dirsToRemove.isEmpty() ) // some dirs to delete ?
+ {
+ state = STATE_DELETING_DIRS;
+ d->m_bURLDirty = true;
+ // Take first dir to delete out of list - last ones first !
+ KURL::List::Iterator it = dirsToRemove.fromLast();
+ SimpleJob *job = TDEIO::rmdir( *it );
+ Scheduler::scheduleJob(job);
+ dirsToRemove.remove(it);
+ addSubjob( job );
+ }
+ else
+ {
+ // This step is done, move on
+ setNextDirAttribute();
+ }
+}
+
+void CopyJob::setNextDirAttribute()
+{
+ if ( !d->m_directoriesCopied.isEmpty() )
+ {
+ state = STATE_SETTING_DIR_ATTRIBUTES;
+#ifdef Q_OS_UNIX
+ // TODO KDE4: this should use a SlaveBase method, but we have none yet in KDE3.
+ TQValueList<CopyInfo>::Iterator it = d->m_directoriesCopied.begin();
+ for ( ; it != d->m_directoriesCopied.end() ; ++it ) {
+ const KURL& url = (*it).uDest;
+ if ( url.isLocalFile() && (*it).mtime != (time_t)-1 ) {
+ const TQCString path = TQFile::encodeName( url.path() );
+ KDE_struct_stat statbuf;
+ if (KDE_lstat(path, &statbuf) == 0) {
+ struct utimbuf utbuf;
+ utbuf.actime = statbuf.st_atime; // access time, unchanged
+ utbuf.modtime = (*it).mtime; // modification time
+ utime( path, &utbuf );
+ }
+
+ }
+ }
+#endif
+ d->m_directoriesCopied.clear();
+ }
+
+ // No "else" here, since the above is a simple sync loop
+
+ {
+ // Finished - tell the world
+ if ( !m_bOnlyRenames )
+ {
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ KURL url( d->m_globalDest );
+ if ( d->m_globalDestinationState != DEST_IS_DIR || m_asMethod )
+ url.setPath( url.directory() );
+ //kdDebug(7007) << "KDirNotify'ing FilesAdded " << url << endl;
+ allDirNotify.FilesAdded( url );
+
+ if ( m_mode == Move && !m_srcList.isEmpty() ) {
+ //kdDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList() << endl;
+ allDirNotify.FilesRemoved( m_srcList );
+ }
+ }
+ if (m_reportTimer)
+ m_reportTimer->stop();
+ --m_processedFiles; // undo the "start at 1" hack
+ slotReport(); // display final numbers, important if progress dialog stays up
+
+ emitResult();
+ }
+}
+
+void CopyJob::slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size )
+{
+ //kdDebug(7007) << "CopyJob::slotProcessedSize " << data_size << endl;
+ m_fileProcessedSize = data_size;
+ setProcessedSize(m_processedSize + m_fileProcessedSize);
+
+ if ( m_processedSize + m_fileProcessedSize > m_totalSize )
+ {
+ m_totalSize = m_processedSize + m_fileProcessedSize;
+ //kdDebug(7007) << "Adjusting m_totalSize to " << m_totalSize << endl;
+ emit totalSize( this, m_totalSize ); // safety
+ }
+ //kdDebug(7007) << "emit processedSize " << (unsigned long) (m_processedSize + m_fileProcessedSize) << endl;
+ emit processedSize( this, m_processedSize + m_fileProcessedSize );
+ emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
+}
+
+void CopyJob::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size )
+{
+ //kdDebug(7007) << "slotTotalSize: " << size << endl;
+ // Special case for copying a single file
+ // This is because some protocols don't implement stat properly
+ // (e.g. HTTP), and don't give us a size in some cases (redirection)
+ // so we'd rather rely on the size given for the transfer
+ if ( m_bSingleFileCopy && size > m_totalSize)
+ {
+ //kdDebug(7007) << "slotTotalSize: updating totalsize to " << size << endl;
+ m_totalSize = size;
+ emit totalSize( this, size );
+ }
+}
+
+void CopyJob::slotResultDeletingDirs( Job * job )
+{
+ if (job->error())
+ {
+ // Couldn't remove directory. Well, perhaps it's not empty
+ // because the user pressed Skip for a given file in it.
+ // Let's not display "Could not remove dir ..." for each of those dir !
+ }
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+ deleteNextDir();
+}
+
+#if 0 // TODO KDE4
+void CopyJob::slotResultSettingDirAttributes( Job * job )
+{
+ if (job->error())
+ {
+ // Couldn't set directory attributes. Ignore the error, it can happen
+ // with inferior file systems like VFAT.
+ // Let's not display warnings for each dir like "cp -a" does.
+ }
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+ setNextDirAttribute();
+}
+#endif
+
+void CopyJob::slotResultRenaming( Job* job )
+{
+ int err = job->error();
+ const TQString errText = job->errorText();
+ removeSubjob( job, true, false ); // merge metadata
+ assert ( subjobs.isEmpty() );
+ // Determine dest again
+ KURL dest = m_dest;
+ if ( destinationState == DEST_IS_DIR && !m_asMethod )
+ dest.addPath( m_currentSrcURL.fileName() );
+ if ( err )
+ {
+ // Direct renaming didn't work. Try renaming to a temp name,
+ // this can help e.g. when renaming 'a' to 'A' on a VFAT partition.
+ // In that case it's the _same_ dir, we don't want to copy+del (data loss!)
+ if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
+ m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
+ ( err == ERR_FILE_ALREADY_EXIST ||
+ err == ERR_DIR_ALREADY_EXIST ||
+ err == ERR_IDENTICAL_FILES ) )
+ {
+ kdDebug(7007) << "Couldn't rename directly, dest already exists. Detected special case of lower/uppercase renaming in same dir, try with 2 rename calls" << endl;
+ TQCString _src( TQFile::encodeName(m_currentSrcURL.path()) );
+ TQCString _dest( TQFile::encodeName(dest.path()) );
+ KTempFile tmpFile( m_currentSrcURL.directory(false) );
+ TQCString _tmp( TQFile::encodeName(tmpFile.name()) );
+ kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
+ tmpFile.unlink();
+ if ( ::rename( _src, _tmp ) == 0 )
+ {
+ if ( !TQFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
+ {
+ kdDebug(7007) << "Success." << endl;
+ err = 0;
+ }
+ else
+ {
+ // Revert back to original name!
+ if ( ::rename( _tmp, _src ) != 0 ) {
+ kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
+ // Severe error, abort
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ }
+ }
+ }
+ }
+ if ( err )
+ {
+ // This code is similar to CopyJob::slotResultConflictCopyingFiles
+ // but here it's about the base src url being moved/renamed
+ // (*m_currentStatSrc) and its dest (m_dest), not about a single file.
+ // It also means we already stated the dest, here.
+ // On the other hand we haven't stated the src yet (we skipped doing it
+ // to save time, since it's not necessary to rename directly!)...
+
+ Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
+
+ // Existing dest?
+ if ( ( err == ERR_DIR_ALREADY_EXIST ||
+ err == ERR_FILE_ALREADY_EXIST ||
+ err == ERR_IDENTICAL_FILES )
+ && isInteractive() )
+ {
+ if (m_reportTimer)
+ m_reportTimer->stop();
+
+ // Should we skip automatically ?
+ if ( m_bAutoSkip ) {
+ // Move on to next file
+ skipSrc();
+ return;
+ } else if ( m_bOverwriteAll ) {
+ ; // nothing to do, stat+copy+del will overwrite
+ } else {
+ TQString newPath;
+ // If src==dest, use "overwrite-itself"
+ RenameDlg_Mode mode = (RenameDlg_Mode)
+ ( ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE );
+
+ if ( m_srcList.count() > 1 )
+ mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
+ else
+ mode = (RenameDlg_Mode) ( mode | M_SINGLE );
+
+ // we lack mtime info for both the src (not stated)
+ // and the dest (stated but this info wasn't stored)
+ // Let's do it for local files, at least
+ TDEIO::filesize_t sizeSrc = (TDEIO::filesize_t) -1;
+ TDEIO::filesize_t sizeDest = (TDEIO::filesize_t) -1;
+ time_t ctimeSrc = (time_t) -1;
+ time_t ctimeDest = (time_t) -1;
+ time_t mtimeSrc = (time_t) -1;
+ time_t mtimeDest = (time_t) -1;
+
+ KDE_struct_stat stat_buf;
+ if ( m_currentSrcURL.isLocalFile() &&
+ KDE_stat(TQFile::encodeName(m_currentSrcURL.path()), &stat_buf) == 0 ) {
+ sizeSrc = stat_buf.st_size;
+ ctimeSrc = stat_buf.st_ctime;
+ mtimeSrc = stat_buf.st_mtime;
+ }
+ if ( dest.isLocalFile() &&
+ KDE_stat(TQFile::encodeName(dest.path()), &stat_buf) == 0 ) {
+ sizeDest = stat_buf.st_size;
+ ctimeDest = stat_buf.st_ctime;
+ mtimeDest = stat_buf.st_mtime;
+ }
+
+ RenameDlg_Result r = Observer::self()->open_RenameDlg(
+ this,
+ err != ERR_DIR_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
+ m_currentSrcURL.url(),
+ dest.url(),
+ mode, newPath,
+ sizeSrc, sizeDest,
+ ctimeSrc, ctimeDest,
+ mtimeSrc, mtimeDest );
+ if (m_reportTimer)
+ m_reportTimer->start(REPORT_TIMEOUT,false);
+
+ switch ( r )
+ {
+ case R_CANCEL:
+ {
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ }
+ case R_RENAME:
+ {
+ // Set m_dest to the chosen destination
+ // This is only for this src url; the next one will revert to d->m_globalDest
+ m_dest.setPath( newPath );
+ TDEIO::Job* job = TDEIO::stat( m_dest, false, 2, false );
+ state = STATE_STATING;
+ destinationState = DEST_NOT_STATED;
+ addSubjob(job);
+ return;
+ }
+ case R_AUTO_SKIP:
+ m_bAutoSkip = true;
+ // fall through
+ case R_SKIP:
+ // Move on to next file
+ skipSrc();
+ return;
+ case R_OVERWRITE_ALL:
+ m_bOverwriteAll = true;
+ break;
+ case R_OVERWRITE:
+ // Add to overwrite list
+ // Note that we add dest, not m_dest.
+ // This ensures that when moving several urls into a dir (m_dest),
+ // we only overwrite for the current one, not for all.
+ // When renaming a single file (m_asMethod), it makes no difference.
+ kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
+ m_overwriteList.append( dest.path() );
+ break;
+ default:
+ //assert( 0 );
+ break;
+ }
+ }
+ } else if ( err != TDEIO::ERR_UNSUPPORTED_ACTION ) {
+ kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", aborting" << endl;
+ m_error = err;
+ m_errorText = errText;
+ emitResult();
+ return;
+ }
+ kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", reverting to normal way, starting with stat" << endl;
+ //kdDebug(7007) << "TDEIO::stat on " << m_currentSrcURL << endl;
+ TDEIO::Job* job = TDEIO::stat( m_currentSrcURL, true, 2, false );
+ state = STATE_STATING;
+ addSubjob(job);
+ m_bOnlyRenames = false;
+ }
+ else
+ {
+ //kdDebug(7007) << "Renaming succeeded, move on" << endl;
+ emit copyingDone( this, *m_currentStatSrc, dest, true, true );
+ statNextSrc();
+ }
+}
+
+void CopyJob::slotResult( Job *job )
+{
+ //kdDebug(7007) << "CopyJob::slotResult() state=" << (int) state << endl;
+ // In each case, what we have to do is :
+ // 1 - check for errors and treat them
+ // 2 - subjobs.remove(job);
+ // 3 - decide what to do next
+
+ switch ( state ) {
+ case STATE_STATING: // We were trying to stat a src url or the dest
+ slotResultStating( job );
+ break;
+ case STATE_RENAMING: // We were trying to do a direct renaming, before even stat'ing
+ {
+ slotResultRenaming( job );
+ break;
+ }
+ case STATE_LISTING: // recursive listing finished
+ //kdDebug(7007) << "totalSize: " << (unsigned int) m_totalSize << " files: " << files.count() << " dirs: " << dirs.count() << endl;
+ // Was there an error ?
+ if (job->error())
+ {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+
+ subjobs.remove( job );
+ assert ( subjobs.isEmpty() );
+
+ statNextSrc();
+ break;
+ case STATE_CREATING_DIRS:
+ slotResultCreatingDirs( job );
+ break;
+ case STATE_CONFLICT_CREATING_DIRS:
+ slotResultConflictCreatingDirs( job );
+ break;
+ case STATE_COPYING_FILES:
+ slotResultCopyingFiles( job );
+ break;
+ case STATE_CONFLICT_COPYING_FILES:
+ slotResultConflictCopyingFiles( job );
+ break;
+ case STATE_DELETING_DIRS:
+ slotResultDeletingDirs( job );
+ break;
+ case STATE_SETTING_DIR_ATTRIBUTES: // TODO KDE4
+ assert( 0 );
+ //slotResultSettingDirAttributes( job );
+ break;
+ default:
+ assert( 0 );
+ }
+}
+
+void TDEIO::CopyJob::setDefaultPermissions( bool b )
+{
+ d->m_defaultPermissions = b;
+}
+
+// KDE4: remove
+void TDEIO::CopyJob::setInteractive( bool b )
+{
+ Job::setInteractive( b );
+}
+
+CopyJob *TDEIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << "TDEIO::copy src=" << src << " dest=" << dest << endl;
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << "TDEIO::copyAs src=" << src << " dest=" << dest << endl;
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
+}
+
+CopyJob *TDEIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << src << " " << dest << endl;
+ return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << src << " " << dest << endl;
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << src << " " << dest << endl;
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
+}
+
+CopyJob *TDEIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
+{
+ //kdDebug(7007) << src << " " << dest << endl;
+ return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
+{
+ return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::trash(const KURL& src, bool showProgressInfo )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
+}
+
+CopyJob *TDEIO::trash(const KURL::List& srcList, bool showProgressInfo )
+{
+ return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
+}
+
+//////////
+
+DeleteJob::DeleteJob( const KURL::List& src, bool /*shred*/, bool showProgressInfo )
+: Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
+ m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
+ m_srcList(src), m_currentStat(m_srcList.begin()), m_reportTimer(0)
+{
+ if ( showProgressInfo ) {
+
+ connect( this, TQT_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
+
+ connect( this, TQT_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
+ Observer::self(), TQT_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
+
+ // See slotReport
+ /*connect( this, TQT_SIGNAL( processedFiles( TDEIO::Job*, unsigned long ) ),
+ m_observer, TQT_SLOT( slotProcessedFiles( TDEIO::Job*, unsigned long ) ) );
+
+ connect( this, TQT_SIGNAL( processedDirs( TDEIO::Job*, unsigned long ) ),
+ m_observer, TQT_SLOT( slotProcessedDirs( TDEIO::Job*, unsigned long ) ) );
+
+ connect( this, TQT_SIGNAL( deleting( TDEIO::Job*, const KURL& ) ),
+ m_observer, TQT_SLOT( slotDeleting( TDEIO::Job*, const KURL& ) ) );*/
+
+ m_reportTimer=new TQTimer(this);
+ connect(m_reportTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(slotReport()));
+ //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
+ m_reportTimer->start(REPORT_TIMEOUT,false);
+ }
+
+ TQTimer::singleShot(0, this, TQT_SLOT(slotStart()));
+}
+
+void DeleteJob::slotStart()
+{
+ statNextSrc();
+}
+
+//this is called often, so calling the functions
+//from Observer here directly might improve the performance a little bit
+//aleXXX
+void DeleteJob::slotReport()
+{
+ if (m_progressId==0)
+ return;
+
+ Observer * observer = Observer::self();
+
+ emit deleting( this, m_currentURL );
+ observer->slotDeleting(this,m_currentURL);
+
+ switch( state ) {
+ case STATE_STATING:
+ case STATE_LISTING:
+ emit totalSize( this, m_totalSize );
+ emit totalFiles( this, files.count() );
+ emit totalDirs( this, dirs.count() );
+ break;
+ case STATE_DELETING_DIRS:
+ emit processedDirs( this, m_processedDirs );
+ observer->slotProcessedDirs(this,m_processedDirs);
+ emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
+ break;
+ case STATE_DELETING_FILES:
+ observer->slotProcessedFiles(this,m_processedFiles);
+ emit processedFiles( this, m_processedFiles );
+ emitPercent( m_processedFiles, m_totalFilesDirs );
+ break;
+ }
+}
+
+
+void DeleteJob::slotEntries(TDEIO::Job* job, const UDSEntryList& list)
+{
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it)
+ {
+ UDSEntry::ConstIterator it2 = (*it).begin();
+ bool bDir = false;
+ bool bLink = false;
+ TQString displayName;
+ KURL url;
+ int atomsFound(0);
+ for( ; it2 != (*it).end(); it2++ )
+ {
+ switch ((*it2).m_uds)
+ {
+ case UDS_FILE_TYPE:
+ bDir = S_ISDIR((*it2).m_long);
+ atomsFound++;
+ break;
+ case UDS_NAME:
+ displayName = (*it2).m_str;
+ atomsFound++;
+ break;
+ case UDS_URL:
+ url = KURL((*it2).m_str);
+ atomsFound++;
+ break;
+ case UDS_LINK_DEST:
+ bLink = !(*it2).m_str.isEmpty();
+ atomsFound++;
+ break;
+ case UDS_SIZE:
+ m_totalSize += (TDEIO::filesize_t)((*it2).m_long);
+ atomsFound++;
+ break;
+ default:
+ break;
+ }
+ if (atomsFound==5) break;
+ }
+ assert(!displayName.isEmpty());
+ if (displayName != ".." && displayName != ".")
+ {
+ if( url.isEmpty() ) {
+ url = ((SimpleJob *)job)->url(); // assumed to be a dir
+ url.addPath( displayName );
+ }
+ //kdDebug(7007) << "DeleteJob::slotEntries " << displayName << " (" << url << ")" << endl;
+ if ( bLink )
+ symlinks.append( url );
+ else if ( bDir )
+ dirs.append( url );
+ else
+ files.append( url );
+ }
+ }
+}
+
+
+void DeleteJob::statNextSrc()
+{
+ //kdDebug(7007) << "statNextSrc" << endl;
+ if ( m_currentStat != m_srcList.end() )
+ {
+ m_currentURL = (*m_currentStat);
+
+ // if the file system doesn't support deleting, we do not even stat
+ if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
+ TQGuardedPtr<DeleteJob> that = this;
+ ++m_currentStat;
+ if (isInteractive())
+ KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
+ if (that)
+ statNextSrc();
+ return;
+ }
+ // Stat it
+ state = STATE_STATING;
+ TDEIO::SimpleJob * job = TDEIO::stat( m_currentURL, true, 1, false );
+ Scheduler::scheduleJob(job);
+ //kdDebug(7007) << "TDEIO::stat (DeleteJob) " << m_currentURL << endl;
+ addSubjob(job);
+ //if ( m_progressId ) // Did we get an ID from the observer ?
+ // Observer::self()->slotDeleting( this, *it ); // show asap
+ } else
+ {
+ m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
+ slotReport();
+ // Now we know which dirs hold the files we're going to delete.
+ // To speed things up and prevent double-notification, we disable KDirWatch
+ // on those dirs temporarily (using KDirWatch::self, that's the instanced
+ // used by e.g. kdirlister).
+ for ( TQStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
+ KDirWatch::self()->stopDirScan( *it );
+ state = STATE_DELETING_FILES;
+ deleteNextFile();
+ }
+}
+
+void DeleteJob::deleteNextFile()
+{
+ //kdDebug(7007) << "deleteNextFile" << endl;
+ if ( !files.isEmpty() || !symlinks.isEmpty() )
+ {
+ SimpleJob *job;
+ do {
+ // Take first file to delete out of list
+ KURL::List::Iterator it = files.begin();
+ bool isLink = false;
+ if ( it == files.end() ) // No more files
+ {
+ it = symlinks.begin(); // Pick up a symlink to delete
+ isLink = true;
+ }
+ // Normal deletion
+ // If local file, try do it directly
+ if ( (*it).isLocalFile() && unlink( TQFile::encodeName((*it).path()) ) == 0 ) {
+ //kdDebug(7007) << "DeleteJob deleted " << (*it).path() << endl;
+ job = 0;
+ m_processedFiles++;
+ if ( m_processedFiles % 300 == 0 || m_totalFilesDirs < 300) { // update progress info every 300 files
+ m_currentURL = *it;
+ slotReport();
+ }
+ } else
+ { // if remote - or if unlink() failed (we'll use the job's error handling in that case)
+ job = TDEIO::file_delete( *it, false /*no GUI*/);
+ Scheduler::scheduleJob(job);
+ m_currentURL=(*it);
+ }
+ if ( isLink )
+ symlinks.remove(it);
+ else
+ files.remove(it);
+ if ( job ) {
+ addSubjob(job);
+ return;
+ }
+ // loop only if direct deletion worked (job=0) and there is something else to delete
+ } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
+ }
+ state = STATE_DELETING_DIRS;
+ deleteNextDir();
+}
+
+void DeleteJob::deleteNextDir()
+{
+ if ( !dirs.isEmpty() ) // some dirs to delete ?
+ {
+ do {
+ // Take first dir to delete out of list - last ones first !
+ KURL::List::Iterator it = dirs.fromLast();
+ // If local dir, try to rmdir it directly
+ if ( (*it).isLocalFile() && ::rmdir( TQFile::encodeName((*it).path()) ) == 0 ) {
+
+ m_processedDirs++;
+ if ( m_processedDirs % 100 == 0 ) { // update progress info every 100 dirs
+ m_currentURL = *it;
+ slotReport();
+ }
+ } else {
+ SimpleJob* job;
+ if ( KProtocolInfo::canDeleteRecursive( *it ) ) {
+ // If the ioslave supports recursive deletion of a directory, then
+ // we only need to send a single CMD_DEL command, so we use file_delete :)
+ job = TDEIO::file_delete( *it, false /*no gui*/ );
+ } else {
+ job = TDEIO::rmdir( *it );
+ }
+ Scheduler::scheduleJob(job);
+ dirs.remove(it);
+ addSubjob( job );
+ return;
+ }
+ dirs.remove(it);
+ } while ( !dirs.isEmpty() );
+ }
+
+ // Re-enable watching on the dirs that held the deleted files
+ for ( TQStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
+ KDirWatch::self()->restartDirScan( *it );
+
+ // Finished - tell the world
+ if ( !m_srcList.isEmpty() )
+ {
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ //kdDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList() << endl;
+ allDirNotify.FilesRemoved( m_srcList );
+ }
+ if (m_reportTimer!=0)
+ m_reportTimer->stop();
+ emitResult();
+}
+
+void DeleteJob::slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size )
+{
+ // Note: this is the same implementation as CopyJob::slotProcessedSize but
+ // it's different from FileCopyJob::slotProcessedSize - which is why this
+ // is not in Job.
+
+ m_fileProcessedSize = data_size;
+ setProcessedSize(m_processedSize + m_fileProcessedSize);
+
+ //kdDebug(7007) << "DeleteJob::slotProcessedSize " << (unsigned int) (m_processedSize + m_fileProcessedSize) << endl;
+
+ emit processedSize( this, m_processedSize + m_fileProcessedSize );
+
+ // calculate percents
+ unsigned long ipercent = m_percent;
+
+ if ( m_totalSize == 0 )
+ m_percent = 100;
+ else
+ m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
+
+ if ( m_percent > ipercent )
+ {
+ emit percent( this, m_percent );
+ //kdDebug(7007) << "DeleteJob::slotProcessedSize - percent = " << (unsigned int) m_percent << endl;
+ }
+
+}
+
+void DeleteJob::slotResult( Job *job )
+{
+ switch ( state )
+ {
+ case STATE_STATING:
+ {
+ // Was there an error while stating ?
+ if (job->error() )
+ {
+ // Probably : doesn't exist
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+
+ // Is it a file or a dir ?
+ UDSEntry entry = ((StatJob*)job)->statResult();
+ bool bDir = false;
+ bool bLink = false;
+ TDEIO::filesize_t size = (TDEIO::filesize_t)-1;
+ UDSEntry::ConstIterator it2 = entry.begin();
+ int atomsFound(0);
+ for( ; it2 != entry.end(); it2++ )
+ {
+ if ( ((*it2).m_uds) == UDS_FILE_TYPE )
+ {
+ bDir = S_ISDIR( (mode_t)(*it2).m_long );
+ atomsFound++;
+ }
+ else if ( ((*it2).m_uds) == UDS_LINK_DEST )
+ {
+ bLink = !((*it2).m_str.isEmpty());
+ atomsFound++;
+ }
+ else if ( ((*it2).m_uds) == UDS_SIZE )
+ {
+ size = (*it2).m_long;
+ atomsFound++;
+ }
+ if (atomsFound==3) break;
+ }
+
+ KURL url = ((SimpleJob*)job)->url();
+
+ subjobs.remove( job );
+ assert( subjobs.isEmpty() );
+
+ if (bDir && !bLink)
+ {
+ // Add toplevel dir in list of dirs
+ dirs.append( url );
+ if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
+ m_parentDirs.append( url.path(-1) );
+
+ if ( !KProtocolInfo::canDeleteRecursive( url ) ) {
+ //kdDebug(7007) << " Target is a directory " << endl;
+ // List it
+ state = STATE_LISTING;
+ ListJob *newjob = listRecursive( url, false );
+ newjob->setUnrestricted(true); // No KIOSK restrictions
+ Scheduler::scheduleJob(newjob);
+ connect(newjob, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob(newjob);
+ } else {
+ ++m_currentStat;
+ statNextSrc();
+ }
+ }
+ else
+ {
+ if ( bLink ) {
+ //kdDebug(7007) << " Target is a symlink" << endl;
+ symlinks.append( url );
+ } else {
+ //kdDebug(7007) << " Target is a file" << endl;
+ files.append( url );
+ }
+ if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(false) ) )
+ m_parentDirs.append( url.directory(false) );
+ ++m_currentStat;
+ statNextSrc();
+ }
+ }
+ break;
+ case STATE_LISTING:
+ if ( job->error() )
+ {
+ // Try deleting nonetheless, it may be empty (and non-listable)
+ }
+ subjobs.remove( job );
+ assert( subjobs.isEmpty() );
+ ++m_currentStat;
+ statNextSrc();
+ break;
+ case STATE_DELETING_FILES:
+ if ( job->error() )
+ {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ assert( subjobs.isEmpty() );
+ m_processedFiles++;
+
+ deleteNextFile();
+ break;
+ case STATE_DELETING_DIRS:
+ if ( job->error() )
+ {
+ Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ assert( subjobs.isEmpty() );
+ m_processedDirs++;
+ //emit processedDirs( this, m_processedDirs );
+ //if (!m_shred)
+ //emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
+
+ deleteNextDir();
+ break;
+ default:
+ assert(0);
+ }
+}
+
+DeleteJob *TDEIO::del( const KURL& src, bool shred, bool showProgressInfo )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
+ return job;
+}
+
+DeleteJob *TDEIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
+{
+ DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
+ return job;
+}
+
+MultiGetJob::MultiGetJob(const KURL& url,
+ bool showProgressInfo)
+ : TransferJob(url, 0, TQByteArray(), TQByteArray(), showProgressInfo)
+{
+ m_waitQueue.setAutoDelete(true);
+ m_activeQueue.setAutoDelete(true);
+ m_currentEntry = 0;
+}
+
+void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
+{
+ GetRequest *entry = new GetRequest(id, url, metaData);
+ entry->metaData["request-id"] = TQString("%1").arg(id);
+ m_waitQueue.append(entry);
+}
+
+void MultiGetJob::flushQueue(TQPtrList<GetRequest> &queue)
+{
+ GetRequest *entry;
+ // Use multi-get
+ // Scan all jobs in m_waitQueue
+ for(entry = m_waitQueue.first(); entry; )
+ {
+ if ((m_url.protocol() == entry->url.protocol()) &&
+ (m_url.host() == entry->url.host()) &&
+ (m_url.port() == entry->url.port()) &&
+ (m_url.user() == entry->url.user()))
+ {
+ m_waitQueue.take();
+ queue.append(entry);
+ entry = m_waitQueue.current();
+ }
+ else
+ {
+ entry = m_waitQueue.next();
+ }
+ }
+ // Send number of URLs, (URL, metadata)*
+ KIO_ARGS << (TQ_INT32) queue.count();
+ for(entry = queue.first(); entry; entry = queue.next())
+ {
+ stream << entry->url << entry->metaData;
+ }
+ m_packedArgs = packedArgs;
+ m_command = CMD_MULTI_GET;
+ m_outgoingMetaData.clear();
+}
+
+void MultiGetJob::start(Slave *slave)
+{
+ // Add first job from m_waitQueue and add it to m_activeQueue
+ GetRequest *entry = m_waitQueue.take(0);
+ m_activeQueue.append(entry);
+
+ m_url = entry->url;
+
+ if (!entry->url.protocol().startsWith("http"))
+ {
+ // Use normal get
+ KIO_ARGS << entry->url;
+ m_packedArgs = packedArgs;
+ m_outgoingMetaData = entry->metaData;
+ m_command = CMD_GET;
+ b_multiGetActive = false;
+ }
+ else
+ {
+ flushQueue(m_activeQueue);
+ b_multiGetActive = true;
+ }
+
+ TransferJob::start(slave); // Anything else to do??
+}
+
+bool MultiGetJob::findCurrentEntry()
+{
+ if (b_multiGetActive)
+ {
+ long id = m_incomingMetaData["request-id"].toLong();
+ for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
+ {
+ if (entry->id == id)
+ {
+ m_currentEntry = entry;
+ return true;
+ }
+ }
+ m_currentEntry = 0;
+ return false;
+ }
+ else
+ {
+ m_currentEntry = m_activeQueue.first();
+ return (m_currentEntry != 0);
+ }
+}
+
+void MultiGetJob::slotRedirection( const KURL &url)
+{
+ if (!findCurrentEntry()) return; // Error
+ if (kapp && !kapp->authorizeURLAction("redirect", m_url, url))
+ {
+ kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
+ return;
+ }
+ m_redirectionURL = url;
+ if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
+ m_redirectionURL.setUser(m_currentEntry->url.user()); // Preserve user
+ get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData); // Try again
+}
+
+
+void MultiGetJob::slotFinished()
+{
+ if (!findCurrentEntry()) return;
+ if (m_redirectionURL.isEmpty())
+ {
+ // No redirection, tell the world that we are finished.
+ emit result(m_currentEntry->id);
+ }
+ m_redirectionURL = KURL();
+ m_error = 0;
+ m_incomingMetaData.clear();
+ m_activeQueue.removeRef(m_currentEntry);
+ if (m_activeQueue.count() == 0)
+ {
+ if (m_waitQueue.count() == 0)
+ {
+ // All done
+ TransferJob::slotFinished();
+ }
+ else
+ {
+ // return slave to pool
+ // fetch new slave for first entry in m_waitQueue and call start
+ // again.
+ GetRequest *entry = m_waitQueue.at(0);
+ m_url = entry->url;
+ slaveDone();
+ Scheduler::doJob(this);
+ }
+ }
+}
+
+void MultiGetJob::slotData( const TQByteArray &_data)
+{
+ if(!m_currentEntry) return;// Error, unknown request!
+ if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
+ emit data(m_currentEntry->id, _data);
+}
+
+void MultiGetJob::slotMimetype( const TQString &_mimetype )
+{
+ if (b_multiGetActive)
+ {
+ TQPtrList<GetRequest> newQueue;
+ flushQueue(newQueue);
+ if (!newQueue.isEmpty())
+ {
+ while(!newQueue.isEmpty())
+ m_activeQueue.append(newQueue.take(0));
+ m_slave->send( m_command, m_packedArgs );
+ }
+ }
+ if (!findCurrentEntry()) return; // Error, unknown request!
+ emit mimetype(m_currentEntry->id, _mimetype);
+}
+
+MultiGetJob *TDEIO::multi_get(long id, const KURL &url, const MetaData &metaData)
+{
+ MultiGetJob * job = new MultiGetJob( url, false );
+ job->get(id, url, metaData);
+ return job;
+}
+
+
+#ifdef CACHE_INFO
+CacheInfo::CacheInfo(const KURL &url)
+{
+ m_url = url;
+}
+
+TQString CacheInfo::cachedFileName()
+{
+ const TQChar separator = '_';
+
+ TQString CEF = m_url.path();
+
+ int p = CEF.find('/');
+
+ while(p != -1)
+ {
+ CEF[p] = separator;
+ p = CEF.find('/', p);
+ }
+
+ TQString host = m_url.host().lower();
+ CEF = host + CEF + '_';
+
+ TQString dir = KProtocolManager::cacheDir();
+ if (dir[dir.length()-1] != '/')
+ dir += "/";
+
+ int l = m_url.host().length();
+ for(int i = 0; i < l; i++)
+ {
+ if (host[i].isLetter() && (host[i] != 'w'))
+ {
+ dir += host[i];
+ break;
+ }
+ }
+ if (dir[dir.length()-1] == '/')
+ dir += "0";
+
+ unsigned long hash = 0x00000000;
+ TQCString u = m_url.url().latin1();
+ for(int i = u.length(); i--;)
+ {
+ hash = (hash * 12211 + u[i]) % 2147483563;
+ }
+
+ TQString hashString;
+ hashString.sprintf("%08lx", hash);
+
+ CEF = CEF + hashString;
+
+ CEF = dir + "/" + CEF;
+
+ return CEF;
+}
+
+TQFile *CacheInfo::cachedFile()
+{
+#ifdef Q_WS_WIN
+ const char *mode = (readWrite ? "rb+" : "rb");
+#else
+ const char *mode = (readWrite ? "r+" : "r");
+#endif
+
+ FILE *fs = fopen(TQFile::encodeName(CEF), mode); // Open for reading and writing
+ if (!fs)
+ return 0;
+
+ char buffer[401];
+ bool ok = true;
+
+ // CacheRevision
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
+ ok = false;
+
+ time_t date;
+ time_t currentDate = time(0);
+
+ // URL
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok)
+ {
+ int l = strlen(buffer);
+ if (l>0)
+ buffer[l-1] = 0; // Strip newline
+ if (m_.url.url() != buffer)
+ {
+ ok = false; // Hash collision
+ }
+ }
+
+ // Creation Date
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok)
+ {
+ date = (time_t) strtoul(buffer, 0, 10);
+ if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
+ {
+ m_bMustRevalidate = true;
+ m_expireDate = currentDate;
+ }
+ }
+
+ // Expiration Date
+ m_cacheExpireDateOffset = ftell(fs);
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok)
+ {
+ if (m_request.cache == CC_Verify)
+ {
+ date = (time_t) strtoul(buffer, 0, 10);
+ // After the expire date we need to revalidate.
+ if (!date || difftime(currentDate, date) >= 0)
+ m_bMustRevalidate = true;
+ m_expireDate = date;
+ }
+ }
+
+ // ETag
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok)
+ {
+ m_etag = TQString(buffer).stripWhiteSpace();
+ }
+
+ // Last-Modified
+ if (ok && (!fgets(buffer, 400, fs)))
+ ok = false;
+ if (ok)
+ {
+ m_lastModified = TQString(buffer).stripWhiteSpace();
+ }
+
+ fclose(fs);
+
+ if (ok)
+ return fs;
+
+ unlink( TQFile::encodeName(CEF) );
+ return 0;
+
+}
+
+void CacheInfo::flush()
+{
+ cachedFile().remove();
+}
+
+void CacheInfo::touch()
+{
+
+}
+void CacheInfo::setExpireDate(int);
+void CacheInfo::setExpireTimeout(int);
+
+
+int CacheInfo::creationDate();
+int CacheInfo::expireDate();
+int CacheInfo::expireTimeout();
+#endif
+
+void Job::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void SimpleJob::virtual_hook( int id, void* data )
+{ TDEIO::Job::virtual_hook( id, data ); }
+
+void MkdirJob::virtual_hook( int id, void* data )
+{ SimpleJob::virtual_hook( id, data ); }
+
+void StatJob::virtual_hook( int id, void* data )
+{ SimpleJob::virtual_hook( id, data ); }
+
+void TransferJob::virtual_hook( int id, void* data )
+{ SimpleJob::virtual_hook( id, data ); }
+
+void MultiGetJob::virtual_hook( int id, void* data )
+{ TransferJob::virtual_hook( id, data ); }
+
+void MimetypeJob::virtual_hook( int id, void* data )
+{ TransferJob::virtual_hook( id, data ); }
+
+void FileCopyJob::virtual_hook( int id, void* data )
+{ Job::virtual_hook( id, data ); }
+
+void ListJob::virtual_hook( int id, void* data )
+{ SimpleJob::virtual_hook( id, data ); }
+
+void CopyJob::virtual_hook( int id, void* data )
+{ Job::virtual_hook( id, data ); }
+
+void DeleteJob::virtual_hook( int id, void* data )
+{ Job::virtual_hook( id, data ); }
+
+void LocalURLJob::virtual_hook( int id, void* data )
+{ Job::virtual_hook( id, data ); }
+
+
+#include "jobclasses.moc"
diff --git a/tdeio/tdeio/job.h b/tdeio/tdeio/job.h
new file mode 100644
index 000000000..d4d7dd41d
--- /dev/null
+++ b/tdeio/tdeio/job.h
@@ -0,0 +1,532 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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 __kio_job_h__
+#define __kio_job_h__
+
+#include <tdeio/jobclasses.h>
+
+namespace TDEIO {
+
+
+ /**
+ * Creates a single directory.
+ *
+ *
+ *
+ *
+ * @param url The URL of the directory to create.
+ * @param permissions The permissions to set after creating the
+ * directory (unix-style), -1 for default permissions.
+ * @return A pointer to the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * mkdir( const KURL& url, int permissions = -1 );
+
+ /**
+ * Removes a single directory.
+ *
+ * The directory is assumed to be empty.
+ *
+ *
+ *
+ * @param url The URL of the directory to remove.
+ * @return A pointer to the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * rmdir( const KURL& url );
+
+ /**
+ * Changes permissions on a file or directory.
+ * See the other chmod below for changing many files
+ * or directories.
+ *
+ * @param url The URL of file or directory.
+ * @param permissions The permissions to set.
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * chmod( const KURL& url, int permissions );
+
+ /**
+ * Rename a file or directory.
+ * Warning: this operation fails if a direct renaming is not
+ * possible (like with files or dirs on separate partitions)
+ * Use move or file_move in this case.
+ *
+ * @param src The original URL
+ * @param dest The final URL
+ * @param overwrite whether to automatically overwrite if the dest exists
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * rename( const KURL& src, const KURL & dest, bool overwrite );
+
+ /**
+ * Create or move a symlink.
+ * This is the lowlevel operation, similar to file_copy and file_move.
+ * It doesn't do any check (other than those the slave does)
+ * and it doesn't show rename and skip dialogs - use TDEIO::link for that.
+ * @param target The string that will become the "target" of the link (can be relative)
+ * @param dest The symlink to create.
+ * @param overwrite whether to automatically overwrite if the dest exists
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * symlink( const TQString & target, const KURL& dest, bool overwrite, bool showProgressInfo = true );
+
+ /**
+ * Execute any command that is specific to one slave (protocol).
+ *
+ * Examples are : HTTP POST, mount and unmount (kio_file)
+ *
+ * @param url The URL isn't passed to the slave, but is used to know
+ * which slave to send it to :-)
+ * @param data Packed data. The meaning is completely dependent on the
+ * slave, but usually starts with an int for the command number.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob * special( const KURL& url, const TQByteArray & data, bool showProgressInfo = true );
+
+ /**
+ * Mount filesystem.
+ *
+ * Special job for @p kio_file.
+ *
+ * @param ro Mount read-only if @p true.
+ * @param fstype File system type (e.g. "ext2", can be 0L).
+ * @param dev Device (e.g. /dev/sda0).
+ * @param point Mount point, can be @p null.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob *mount( bool ro, const char *fstype, const TQString& dev, const TQString& point, bool showProgressInfo = true );
+
+ /**
+ * Unmount filesystem.
+ *
+ * Special job for @p kio_file.
+ *
+ * @param point Point to unmount.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob *unmount( const TQString & point, bool showProgressInfo = true );
+
+ /**
+ * Retrieve local URL if available
+ *
+ * @param remoteURL the remote URL to get the local URL for
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT LocalURLJob *localURL( const KURL& remoteUrl );
+
+ /**
+ * HTTP cache update
+ *
+ * @param url Url to update, protocol must be "http".
+ * @param no_cache If true, cache entry for @p url is deleted.
+ * @param expireDate Local machine time indicating when the entry is
+ * supposed to expire.
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob *http_update_cache( const KURL& url, bool no_cache, time_t expireDate);
+
+ /**
+ * Find all details for one file or directory.
+ *
+ * @param url the URL of the file
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT StatJob * stat( const KURL& url, bool showProgressInfo = true );
+ /**
+ * Find all details for one file or directory.
+ * This version of the call includes two additional booleans, @p sideIsSource and @p details.
+ *
+ * @param url the URL of the file
+ * @param sideIsSource is true when stating a source file (we will do a get on it if
+ * the stat works) and false when stating a destination file (target of a copy).
+ * The reason for this parameter is that in some cases the tdeioslave might not
+ * be able to determine a file's existence (e.g. HTTP doesn't allow it, FTP
+ * has issues with case-sensitivity on some systems).
+ * When the slave can't reliably determine the existence of a file, it will:
+ * @li be optimistic if sideIsSource=true, i.e. it will assume the file exists,
+ * and if it doesn't this will appear when actually trying to download it
+ * @li be pessimistic if sideIsSource=false, i.e. it will assume the file
+ * doesn't exist, to prevent showing "about to overwrite" errors to the user.
+ * If you simply want to check for existence without downloading/uploading afterwards,
+ * then you should use sideIsSource=false.
+ *
+ * @param details selects the level of details we want.
+ * By default this is 2 (all details wanted, including modification time, size, etc.),
+ * setDetails(1) is used when deleting: we don't need all the information if it takes
+ * too much time, no need to follow symlinks etc.
+ * setDetails(0) is used for very simple probing: we'll only get the answer
+ * "it's a file or a directory, or it doesn't exist". This is used by KRun.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT StatJob * stat( const KURL& url, bool sideIsSource, short int details, bool showProgressInfo = true );
+
+ /**
+ * Get (a.k.a. read).
+ *
+ * The slave emits the data through data().
+ * @param url the URL of the file
+ * @param reload true to reload the file, false if it can be taken from the cache
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT TransferJob *get( const KURL& url, bool reload=false, bool showProgressInfo = true );
+
+ /**
+ * Put (a.k.a. write)
+ *
+ * @param url Where to write data.
+ * @param permissions May be -1. In this case no special permission mode is set.
+ * @param overwrite If true, any existing file will be overwritten.
+ * @param resume true to resume an operation. Warning, setting this to true means
+ * that the data will be appended to @p dest if @p dest exists.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ * @see multi_get()
+ */
+ TDEIO_EXPORT TransferJob *put( const KURL& url, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo = true );
+
+ /**
+ * HTTP POST (for form data).
+ *
+ * Example:
+ * \code
+ * job = TDEIO::http_post( url, postData, false );
+ * job->addMetaData("content-type", contentType );
+ * job->addMetaData("referrer", referrerURL);
+ * \endcode
+ *
+ * @p postData is the data that you want to send and
+ * @p contentType is the complete HTTP header line that
+ * specifies the content's MIME type, for example
+ * "Content-Type: text/xml".
+ *
+ * You MUST specify content-type!
+ *
+ * Often @p contentType is
+ * "Content-Type: application/x-www-form-urlencoded" and
+ * the @p postData is then an ASCII string (without null-termination!)
+ * with characters like space, linefeed and percent escaped like %20,
+ * %0A and %25.
+ *
+ * @param url Where to write the data.
+ * @param postData Encoded data to post.
+ * @param showProgressInfo true to display
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT TransferJob *http_post( const KURL& url, const TQByteArray &postData,
+ bool showProgressInfo = true );
+
+ /**
+ * Get (a.k.a. read), into a single TQByteArray.
+ * @see StoredTransferJob
+ *
+ * @param url the URL of the file
+ * @param reload true to reload the file, false if it can be taken from the cache
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ * @since 3.3
+ */
+ TDEIO_EXPORT StoredTransferJob *storedGet( const KURL& url, bool reload=false, bool showProgressInfo = true );
+
+ /**
+ * Put (a.k.a. write) data from a single TQByteArray.
+ * @see StoredTransferJob
+ *
+ * @param arr The data to write
+ * @param url Where to write data.
+ * @param permissions May be -1. In this case no special permission mode is set.
+ * @param overwrite If true, any existing file will be overwritten.
+ * @param resume true to resume an operation. Warning, setting this to true means
+ * that the data will be appended to @p dest if @p dest exists.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ * @since 3.3
+ */
+ TDEIO_EXPORT StoredTransferJob *storedPut( const TQByteArray& arr, const KURL& url, int permissions,
+ bool overwrite, bool resume, bool showProgressInfo = true );
+
+ /**
+ * Creates a new multiple get job.
+ *
+ * @param id the id of the get operation
+ * @param url the URL of the file
+ * @param metaData the MetaData associated with the file
+ *
+ * @return the job handling the operation.
+ * @see get()
+ */
+ TDEIO_EXPORT MultiGetJob *multi_get( long id, const KURL &url, const MetaData &metaData);
+
+ /**
+ * Find mimetype for one file or directory.
+ *
+ * @param url the URL of the file
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT MimetypeJob * mimetype( const KURL& url,
+ bool showProgressInfo = true );
+
+ /**
+ * Copy a single file.
+ *
+ * Uses either SlaveBase::copy() if the slave supports that
+ * or get() and put() otherwise.
+ * @param src Where to get the file.
+ * @param dest Where to put the file.
+ * @param permissions May be -1. In this case no special permission mode is set.
+ * @param overwrite If true, any existing file will be overwritten.
+ * @param resume true to resume an operation. Warning, setting this to true means
+ * that @p src will be appended to @p dest if @p dest exists.
+ * You probably don't want that, so leave it to false :)
+ *
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT FileCopyJob *file_copy( const KURL& src, const KURL& dest, int permissions=-1,
+ bool overwrite=false, bool resume=false,
+ bool showProgressInfo = true);
+
+ /**
+ * Move a single file.
+ *
+ * Use either SlaveBase::rename() if the slave supports that,
+ * or copy() and del() otherwise, or eventually get() & put() & del()
+ * @param src Where to get the file.
+ * @param dest Where to put the file.
+ * @param permissions May be -1. In this case no special permission mode is set.
+ * @param overwrite If @p true, any existing file will be overwritten.
+ * @param resume true to resume an operation. Warning, setting this to true means
+ * that @p src will be appended to @p dest if @p dest exists.
+ * You probably don't want that, so leave it to false :)
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT FileCopyJob *file_move( const KURL& src, const KURL& dest, int permissions=-1,
+ bool overwrite=false, bool resume=false,
+ bool showProgressInfo = true);
+
+ /**
+ * Delete a single file.
+ *
+ * @param src File to delete.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT SimpleJob *file_delete( const KURL& src, bool showProgressInfo = true);
+
+ /**
+ * List the contents of @p url, which is assumed to be a directory.
+ *
+ * "." and ".." are returned, filter them out if you don't want them.
+ *
+ *
+ * @param url the url of the directory
+ * @param showProgressInfo true to show progress information
+ * @param includeHidden true for all files, false to cull out UNIX hidden
+ * files/dirs (whose names start with dot)
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT ListJob *listDir( const KURL& url, bool showProgressInfo = true,
+ bool includeHidden = true );
+
+ /**
+ * The same as the previous method, but recurses subdirectories.
+ * Directory links are not followed.
+ *
+ * "." and ".." are returned but only for the toplevel directory.
+ * Filter them out if you don't want them.
+ *
+ * @param url the url of the directory
+ * @param showProgressInfo true to show progress information
+ * @param includeHidden true for all files, false to cull out UNIX hidden
+ * files/dirs (whose names start with dot)
+ * @return the job handling the operation.
+ */
+ TDEIO_EXPORT ListJob *listRecursive( const KURL& url, bool showProgressInfo = true,
+ bool includeHidden = true );
+
+ /**
+ * Copy a file or directory @p src into the destination @p dest,
+ * which can be a file (including the final filename) or a directory
+ * (into which @p src will be copied).
+ *
+ * This emulates the cp command completely.
+ *
+ * @param src the file or directory to copy
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see copyAs()
+ */
+ TDEIO_EXPORT CopyJob *copy( const KURL& src, const KURL& dest, bool showProgressInfo = true );
+
+ /**
+ * Copy a file or directory @p src into the destination @p dest,
+ * which is the destination name in any case, even for a directory.
+ *
+ * As opposed to copy(), this doesn't emulate cp, but is the only
+ * way to copy a directory, giving it a new name and getting an error
+ * box if a directory already exists with the same name.
+ *
+ * @param src the file or directory to copy
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ */
+ TDEIO_EXPORT CopyJob *copyAs( const KURL& src, const KURL& dest, bool showProgressInfo = true );
+
+ /**
+ * Copy a list of file/dirs @p src into a destination directory @p dest.
+ *
+ * @param src the list of files and/or directories
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ */
+ TDEIO_EXPORT CopyJob *copy( const KURL::List& src, const KURL& dest, bool showProgressInfo = true );
+
+ /**
+ * Moves a file or directory @p src to the given destination @p dest.
+ *
+ * @param src the file or directory to copy
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see copy()
+ * @see moveAs()
+ */
+ TDEIO_EXPORT CopyJob *move( const KURL& src, const KURL& dest, bool showProgressInfo = true );
+ /**
+ * Moves a file or directory @p src to the given destination @p dest. Unlike move()
+ * this operation will fail when the directory already exists.
+ *
+ * @param src the file or directory to copy
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see copyAs()
+ */
+ TDEIO_EXPORT CopyJob *moveAs( const KURL& src, const KURL& dest, bool showProgressInfo = true );
+ /**
+ * Moves a list of files or directories @p src to the given destination @p dest.
+ *
+ * @param src the list of files or directories to copy
+ * @param dest the destination
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see copy()
+ */
+ TDEIO_EXPORT CopyJob *move( const KURL::List& src, const KURL& dest, bool showProgressInfo = true );
+
+ /**
+ * Create a link.
+ * If the protocols and hosts are the same, a Unix symlink will be created.
+ * Otherwise, a .desktop file of Type Link and pointing to the src URL will be created.
+ *
+ * @param src The existing file or directory, 'target' of the link.
+ * @param destDir Destination directory where the link will be created.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ */
+ TDEIO_EXPORT CopyJob *link( const KURL& src, const KURL& destDir, bool showProgressInfo = true );
+
+ /**
+ * Create several links
+ * If the protocols and hosts are the same, a Unix symlink will be created.
+ * Otherwise, a .desktop file of Type Link and pointing to the src URL will be created.
+ *
+ * @param src The existing files or directories, 'targets' of the link.
+ * @param destDir Destination directory where the links will be created.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see link()
+ */
+ TDEIO_EXPORT CopyJob *link( const KURL::List& src, const KURL& destDir, bool showProgressInfo = true );
+
+ /**
+ * Create a link. Unlike link() this operation will fail when the directory already
+ * exists.
+ * If the protocols and hosts are the same, a Unix symlink will be created.
+ * Otherwise, a .desktop file of Type Link and pointing to the src URL will be created.
+ *
+ * @param src The existing file or directory, 'target' of the link.
+ * @param dest Destination directory where the link will be created.
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @see link ()
+ * @see copyAs()
+ */
+ TDEIO_EXPORT CopyJob *linkAs( const KURL& src, const KURL& dest, bool showProgressInfo = true );
+
+ /**
+ * Trash a file or directory.
+ * This is currently only supported for local files and directories.
+ * Use "KURL src; src.setPath( path );" to create a URL from a path.
+ *
+ * @param src file to delete
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @since 3.4
+ */
+ TDEIO_EXPORT CopyJob *trash( const KURL& src, bool showProgressInfo = true );
+
+ /**
+ * Trash a list of files or directories.
+ * This is currently only supported for local files and directories.
+ *
+ * @param src the files to delete
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ * @since 3.4
+ */
+ TDEIO_EXPORT CopyJob *trash( const KURL::List& src, bool showProgressInfo = true );
+
+ /**
+ * Delete a file or directory.
+ *
+ * @param src file to delete
+ * @param shred obsolete (TODO remove in KDE4)
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ */
+ TDEIO_EXPORT DeleteJob *del( const KURL& src, bool shred = false, bool showProgressInfo = true );
+
+ /**
+ * Deletes a list of files or directories.
+ *
+ * @param src the files to delete
+ * @param shred obsolete (TODO remove in KDE4)
+ * @param showProgressInfo true to show progress information
+ * @return the job handling the operation
+ */
+ TDEIO_EXPORT DeleteJob *del( const KURL::List& src, bool shred = false, bool showProgressInfo = true );
+}
+
+#endif
+
diff --git a/tdeio/tdeio/jobclasses.h b/tdeio/tdeio/jobclasses.h
new file mode 100644
index 000000000..7f5ec1f85
--- /dev/null
+++ b/tdeio/tdeio/jobclasses.h
@@ -0,0 +1,1909 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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 __kio_jobclasses_h__
+#define __kio_jobclasses_h__
+
+#include <tqobject.h>
+#include <tqptrlist.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqguardedptr.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <kurl.h>
+#include <tdeio/global.h>
+
+class Observer;
+class TQTimer;
+
+#define KIO_COPYJOB_HAS_SETINTERACTIVE // new in 3.4. Used by kio_trash.
+
+namespace TDEIO {
+
+ class Slave;
+ class SlaveInterface;
+
+
+ /**
+ * The base class for all jobs.
+ * For all jobs created in an application, the code looks like
+ *
+ * \code
+ * TDEIO::Job * job = TDEIO::someoperation( some parameters );
+ * connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ * this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+ * \endcode
+ * (other connects, specific to the job)
+ *
+ * And slotResult is usually at least:
+ *
+ * \code
+ * if ( job->error() )
+ * job->showErrorDialog( this or 0L );
+ * \endcode
+ * @see TDEIO::Scheduler
+ * @see TDEIO::Slave
+ */
+ class TDEIO_EXPORT Job : public TQObject {
+ Q_OBJECT
+
+ protected:
+ Job( bool showProgressInfo );
+
+ public:
+ virtual ~Job();
+
+ /**
+ * Abort this job.
+ * This kills all subjobs and deletes the job.
+ *
+ * @param quietly if false, Job will emit signal result
+ * and ask tdeio_uiserver to close the progress window.
+ * @p quietly is set to true for subjobs. Whether applications
+ * should call with true or false depends on whether they rely
+ * on result being emitted or not.
+ */
+ virtual void kill( bool quietly = true );
+
+ /**
+ * Returns the error code, if there has been an error.
+ * Only call this method from the slot connected to result().
+ * @return the error code for this job, 0 if no error.
+ * Error codes are defined in TDEIO::Error.
+ */
+ int error() const { return m_error; }
+
+ /**
+ * Returns the progress id for this job.
+ * @return the progress id for this job, as returned by uiserver
+ */
+ int progressId() const { return m_progressId; }
+
+ /**
+ * Returns the error text if there has been an error.
+ * Only call if error is not 0.
+ * This is really internal, better use errorString() or errorDialog().
+ *
+ * @return a string to help understand the error, usually the url
+ * related to the error. Only valid if error() is not 0.
+ */
+ const TQString & errorText() const { return m_errorText; }
+
+ /**
+ * Converts an error code and a non-i18n error message into an
+ * error message in the current language. The low level (non-i18n)
+ * error message (usually a url) is put into the translated error
+ * message using %1.
+ *
+ * Example for errid == ERR_CANNOT_OPEN_FOR_READING:
+ * \code
+ * i18n( "Could not read\n%1" ).arg( errortext );
+ * \endcode
+ * Use this to display the error yourself, but for a dialog box
+ * use Job::showErrorDialog. Do not call it if error()
+ * is not 0.
+ * @return the error message and if there is no error, a message
+ * telling the user that the app is broken, so check with
+ * error() whether there is an error
+ */
+ TQString errorString() const;
+
+ /**
+ * Converts an error code and a non-i18n error message into i18n
+ * strings suitable for presentation in a detailed error message box.
+ *
+ * @param reqUrl the request URL that generated this error message
+ * @param method the method that generated this error message
+ * (unimplemented)
+ * @return the following strings: caption, error + description,
+ * causes+solutions
+ */
+ TQStringList detailedErrorStrings(const KURL *reqUrl = 0L,
+ int method = -1) const;
+
+ /**
+ * Display a dialog box to inform the user of the error given by
+ * this job.
+ * Only call if error is not 0, and only in the slot connected
+ * to result.
+ * @param parent the parent widget for the dialog box, can be 0 for
+ * top-level
+ */
+ void showErrorDialog( TQWidget * parent = 0L );
+
+ /**
+ * Enable or disable the automatic error handling. When automatic
+ * error handling is enabled and an error occurs, then showErrorDialog()
+ * is called with the specified @p parentWidget (if supplied) , right before
+ * the emission of the result signal.
+ *
+ * The default is false.
+ *
+ * @param enable enable or disable automatic error handling
+ * @param parentWidget the parent widget, passed to showErrorDialog.
+ * Can be 0 for top-level
+ * @see isAutoErrorHandlingEnabled(), showErrorDialog()
+ */
+ void setAutoErrorHandlingEnabled( bool enable, TQWidget *parentWidget = 0 );
+
+ /**
+ * Returns whether automatic error handling is enabled or disabled.
+ * @return true if automatic error handling is enabled
+ * @see setAutoErrorHandlingEnabled()
+ */
+ bool isAutoErrorHandlingEnabled() const;
+
+ /**
+ * Enable or disable the automatic warning handling. When automatic
+ * warning handling is enabled and an error occurs, then a message box
+ * is displayed with the warning message
+ *
+ * The default is true.
+ *
+ * See also isAutoWarningHandlingEnabled , showErrorDialog
+ *
+ * @param enable enable or disable automatic warning handling
+ * @see isAutoWarningHandlingEnabled()
+ * @since 3.5
+ */
+ void setAutoWarningHandlingEnabled( bool enable );
+
+ /**
+ * Returns whether automatic warning handling is enabled or disabled.
+ * See also setAutoWarningHandlingEnabled .
+ * @return true if automatic warning handling is enabled
+ * @see setAutoWarningHandlingEnabled()
+ * @since 3.5
+ */
+ bool isAutoWarningHandlingEnabled() const;
+
+ /**
+ * Enable or disable the message display from the job.
+ *
+ * The default is true.
+ * @param enable enable or disable message display
+ * @since 3.4.1
+ */
+ void setInteractive(bool enable);
+
+ /**
+ * Returns whether message display is enabled or disabled.
+ * @return true if message display is enabled
+ * @see setInteractive()
+ * @since 3.4.1
+ */
+ bool isInteractive() const;
+ /**
+ * Associate this job with a window given by @p window.
+ * @param window the window to associate to
+ * @see window()
+ */
+ void setWindow(TQWidget *window);
+
+ /**
+ * Returns the window this job is associated with.
+ * @return the associated window
+ * @see setWindow()
+ */
+ TQWidget *window() const;
+
+ /**
+ * Updates the last user action timestamp to the given time.
+ * See TDEApplication::updateUserTimestamp() .
+ * @since 3.5.6
+ */
+ void updateUserTimestamp( unsigned long time );
+
+ /**
+ * Set the parent Job.
+ * One example use of this is when FileCopyJob calls open_RenameDlg,
+ * it must pass the correct progress ID of the parent CopyJob
+ * (to hide the progress dialog).
+ * You can set the parent job only once. By default a job does not
+ * have a parent job.
+ * @param parentJob the new parent job
+ * @since 3.1
+ */
+ void setParentJob( Job* parentJob );
+
+ /**
+ * Returns the parent job, if there is one.
+ * @return the parent job, or 0 if there is none
+ * @see setParentJob
+ * @since 3.1
+ */
+ Job* parentJob() const;
+
+ /**
+ * Set meta data to be sent to the slave, replacing existing
+ * meta data.
+ * @param metaData the meta data to set
+ * @see addMetaData()
+ * @see mergeMetaData()
+ */
+ void setMetaData( const TDEIO::MetaData &metaData);
+
+ /**
+ * Add key/value pair to the meta data that is sent to the slave.
+ * @param key the key of the meta data
+ * @param value the value of the meta data
+ * @see setMetaData()
+ * @see mergeMetaData()
+ */
+ void addMetaData(const TQString &key, const TQString &value);
+
+ /**
+ * Add key/value pairs to the meta data that is sent to the slave.
+ * If a certain key already existed, it will be overridden.
+ * @param values the meta data to add
+ * @see setMetaData()
+ * @see mergeMetaData()
+ */
+ void addMetaData(const TQMap<TQString,TQString> &values);
+
+ /**
+ * Add key/value pairs to the meta data that is sent to the slave.
+ * If a certain key already existed, it will remain unchanged.
+ * @param values the meta data to merge
+ * @see setMetaData()
+ * @see addMetaData()
+ */
+ void mergeMetaData(const TQMap<TQString,TQString> &values);
+
+ /**
+ * @internal. For the scheduler. Do not use.
+ */
+ MetaData outgoingMetaData() const;
+
+ /**
+ * Get meta data received from the slave.
+ * (Valid when first data is received and/or slave is finished)
+ * @return the job's meta data
+ */
+ MetaData metaData() const;
+
+ /**
+ * Query meta data received from the slave.
+ * (Valid when first data is received and/or slave is finished)
+ * @param key the key of the meta data to retrieve
+ * @return the value of the meta data, or TQString::null if the
+ * @p key does not exist
+ */
+ TQString queryMetaData(const TQString &key);
+
+ /**
+ * Returns the processed size for this job.
+ * @see processedSize
+ * @since 3.2
+ */
+ TDEIO::filesize_t getProcessedSize();
+
+ signals:
+ /**
+ * Emitted when the job is finished, in any case (completed, canceled,
+ * failed...). Use error to know the result.
+ * @param job the job that emitted this signal
+ */
+ void result( TDEIO::Job *job );
+
+ /**
+ * @deprecated. Don't use !
+ * Emitted when the job is canceled.
+ * Signal result() is emitted as well, and error() is,
+ * in this case, ERR_USER_CANCELED.
+ * @param job the job that emitted this signal
+ */
+ void canceled( TDEIO::Job *job );
+
+ /**
+ * Emitted to display information about this job, as sent by the slave.
+ * Examples of message are "Resolving host", "Connecting to host...", etc.
+ * @param job the job that emitted this signal
+ * @param msg the info message
+ */
+ void infoMessage( TDEIO::Job *job, const TQString & msg );
+ // KDE4: Separate rich-text string from plain-text string, for different widgets.
+
+ /**
+ * Emitted to display a warning about this job, as sent by the slave.
+ * @param job the job that emitted this signal
+ * @param msg the info message
+ * @since 3.5
+ */
+ void warning( TDEIO::Job *job, const TQString & msg );
+ // KDE4: Separate rich-text string from plain-text string, for different widgets.
+
+ /**
+ * Emitted when the slave successfully connected to the host.
+ * There is no guarantee the slave will send this, and this is
+ * currently unused (in the applications).
+ * @param job the job that emitted this signal
+ */
+ void connected( TDEIO::Job *job );
+
+ /**
+ * Progress signal showing the overall progress of the job
+ * This is valid for any kind of job, and allows using a
+ * a progress bar very easily. (see KProgress).
+ * Note that this signal is not emitted for finished jobs.
+ * @param job the job that emitted this signal
+ * @param percent the percentage
+ */
+ void percent( TDEIO::Job *job, unsigned long percent );
+
+ /**
+ * Emitted when we know the size of this job (data size for transfers,
+ * number of entries for listings).
+ * @param job the job that emitted this signal
+ * @param size the total size in bytes
+ */
+ void totalSize( TDEIO::Job *job, TDEIO::filesize_t size );
+
+ /**
+ * Regularly emitted to show the progress of this job
+ * (current data size for transfers, entries listed).
+ * @param job the job that emitted this signal
+ * @param size the processed size in bytes
+ */
+ void processedSize( TDEIO::Job *job, TDEIO::filesize_t size );
+
+ /**
+ * Emitted to display information about the speed of this job.
+ * @param job the job that emitted this signal
+ * @param speed the speed in bytes/s
+ */
+ void speed( TDEIO::Job *job, unsigned long speed );
+
+ protected slots:
+ /**
+ * Called whenever a subjob finishes.
+ * Default implementation checks for errors and propagates
+ * to parent job, then calls removeSubjob.
+ * Override if you don't want subjobs errors to be propagated.
+ * @param job the subjob
+ * @see result()
+ */
+ virtual void slotResult( TDEIO::Job *job );
+
+ /**
+ * Forward signal from subjob.
+ * @param job the subjob
+ * @param speed the speed in bytes/s
+ * @see speed()
+ */
+ void slotSpeed( TDEIO::Job *job, unsigned long speed );
+ /**
+ * Forward signal from subjob.
+ * @param job the subjob
+ * @param msg the info message
+ * @see infoMessage()
+ */
+ void slotInfoMessage( TDEIO::Job *job, const TQString &msg );
+
+ /**
+ * Remove speed information.
+ */
+ void slotSpeedTimeout();
+
+ protected:
+ /**
+ * Add a job that has to be finished before a result
+ * is emitted. This has obviously to be called before
+ * the finish signal is emitted by the slave.
+ *
+ * @param job the subjob to add
+ * @param inheritMetaData if true, the subjob will
+ * inherit the meta data from this job.
+ */
+ virtual void addSubjob( Job *job, bool inheritMetaData=true );
+
+ /**
+ * Mark a sub job as being done. If it's the last to
+ * wait on the job will emit a result - jobs with
+ * two steps might want to override slotResult
+ * in order to avoid calling this method.
+ *
+ * @param job the subjob to add
+ */
+ virtual void removeSubjob( Job *job );
+ /**
+ * Overloaded version of removeSubjob
+ * @param job the subjob to remove
+ * @param mergeMetaData if set, the metadata received by the subjob is
+ * merged into this job.
+ * @param emitResultIfLast if this was the last subjob, emit result,
+ * i.e. terminate this job.
+ */
+ void removeSubjob( Job *job, bool mergeMetaData, bool emitResultIfLast ); // KDE4: merge with above, with =true to both
+
+ /**
+ * Utility function for inherited jobs.
+ * Emits the percent signal if bigger than m_percent,
+ * after calculating it from the parameters.
+ *
+ * @param processedSize the processed size in bytes
+ * @param totalSize the total size in bytes
+ */
+ void emitPercent( TDEIO::filesize_t processedSize, TDEIO::filesize_t totalSize );
+
+ /**
+ * Utility function for inherited jobs.
+ * Emits the speed signal and starts the timer for removing that info
+ *
+ * @param speed the speed in bytes/s
+ */
+ void emitSpeed( unsigned long speed );
+
+ /**
+ * Utility function to emit the result signal, and suicide this job.
+ * It first tells the observer to hide the progress dialog for this job.
+ */
+ void emitResult();
+
+ /**
+ * Set the processed size, does not emit processedSize
+ * @since 3.2
+ */
+ void setProcessedSize(TDEIO::filesize_t size);
+
+ /**
+ * @internal
+ */
+ unsigned long userTimestamp() const;
+
+ /**
+ * @internal
+ * Some extra storage space for jobs that don't have their own
+ * private d pointer.
+ */
+ enum { EF_TransferJobAsync = (1 << 0),
+ EF_TransferJobNeedData = (1 << 1),
+ EF_TransferJobDataSent = (1 << 2),
+ EF_ListJobUnrestricted = (1 << 3) };
+ int &extraFlags();
+
+ TQPtrList<Job> subjobs;
+ int m_error;
+ TQString m_errorText;
+ unsigned long m_percent;
+ int m_progressId; // for uiserver
+ TQTimer *m_speedTimer;
+ TQGuardedPtr<TQWidget> m_window;
+ MetaData m_outgoingMetaData;
+ MetaData m_incomingMetaData;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class JobPrivate;
+ JobPrivate *d;
+ };
+
+ /**
+ * A simple job (one url and one command).
+ * This is the base class for all jobs that are scheduled.
+ * Other jobs are high-level jobs (CopyJob, DeleteJob, FileCopyJob...)
+ * that manage subjobs but aren't scheduled directly.
+ */
+ class TDEIO_EXPORT SimpleJob : public TDEIO::Job {
+ Q_OBJECT
+
+ public:
+ /**
+ * Creates a new simple job. You don't need to use this constructor,
+ * unless you create a new job that inherits from SimpleJob.
+ * @param url the url of the job
+ * @param command the command of the job
+ * @param packedArgs the arguments
+ * @param showProgressInfo true to show progress information to the user
+ */
+ SimpleJob(const KURL& url, int command, const TQByteArray &packedArgs,
+ bool showProgressInfo);
+
+ ~SimpleJob();
+
+ /**
+ * Returns the SimpleJob's URL
+ * @return the url
+ */
+ const KURL& url() const { return m_url; }
+
+ /**
+ * Abort job.
+ * This kills all subjobs and deletes the job.
+ * @param quietly if true, Job will emit signal result
+ * Should only be set to false when the user kills the job
+ * (from tdeio_uiserver), not when you want to abort a job.
+ */
+ virtual void kill( bool quietly = true );
+
+ /**
+ * Abort job.
+ * Suspends slave to be reused by another job for the same request.
+ */
+ virtual void putOnHold();
+
+ /**
+ * Discard suspended slave.
+ */
+ static void removeOnHold();
+
+ /**
+ * @internal
+ * Called by the scheduler when a slave gets to
+ * work on this job.
+ **/
+ virtual void start( Slave *slave );
+
+ /**
+ * @internal
+ * Called to detach a slave from a job.
+ **/
+ void slaveDone();
+
+ /**
+ * @internal
+ * Slave in use by this job.
+ */
+ Slave *slave() const { return m_slave; }
+
+ /**
+ * @internal
+ */
+ int command() const { return m_command; }
+
+ public slots:
+ /**
+ * Forward signal from the slave
+ * Can also be called by the parent job, when it knows the size.
+ * @param data_size the total size
+ */
+ void slotTotalSize( TDEIO::filesize_t data_size );
+
+ protected slots:
+ /**
+ * Called when the slave marks the job
+ * as finished.
+ */
+ virtual void slotFinished( );
+
+ /**
+ * @internal
+ * Called on a slave's warning.
+ */
+ void slotWarning( const TQString & ); // KDE4: make virtual
+
+ /**
+ * Called on a slave's info message.
+ * @param s the info message
+ * @see infoMessage()
+ */
+ void slotInfoMessage( const TQString &s ); // KDE4: make virtual
+
+ /**
+ * Called on a slave's connected signal.
+ * @see connected()
+ */
+ void slotConnected();
+
+ /**
+ * Forward signal from the slave.
+ * @param data_size the processed size in bytes
+ * @see processedSize()
+ */
+ void slotProcessedSize( TDEIO::filesize_t data_size );
+ /**
+ * Forward signal from the slave.
+ * @param speed the speed in bytes/s
+ * @see speed()
+ */
+ void slotSpeed( unsigned long speed );
+
+ /**
+ * MetaData from the slave is received.
+ * @param _metaData the meta data
+ * @see metaData()
+ */
+ virtual void slotMetaData( const TDEIO::MetaData &_metaData);
+
+ public slots:
+ /**
+ * @internal
+ * Called on a slave's error.
+ * Made public for the scheduler.
+ */
+ virtual void slotError( int , const TQString & );
+
+ protected slots:
+ /**
+ * @internal
+ */
+ void slotNeedProgressId();
+
+ protected:
+ Slave * m_slave;
+ TQByteArray m_packedArgs;
+ KURL m_url;
+ KURL m_subUrl;
+ int m_command;
+ TDEIO::filesize_t m_totalSize;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ /*
+ * Allow jobs that inherit SimpleJob and are aware
+ * of redirections to store the SSL session used.
+ * Retrieval is handled by SimpleJob::start
+ * @param m_redirectionURL Reference to redirection URL,
+ * used instead of m_url if not empty
+ */
+ void storeSSLSessionFromJob(const KURL &m_redirectionURL);
+ private:
+ class SimpleJobPrivate* d;
+ };
+
+ /**
+ * A KIO job that retrieves information about a file or directory.
+ * @see TDEIO::stat()
+ */
+ class TDEIO_EXPORT StatJob : public SimpleJob {
+
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not use this constructor to create a StatJob, use TDEIO::stat() instead.
+ * @param url the url of the file or directory to check
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param showProgressInfo true to show progress information to the user
+ */
+ StatJob(const KURL& url, int command, const TQByteArray &packedArgs, bool showProgressInfo);
+
+ /**
+ * A stat() can have two meanings. Either we want to read from this URL,
+ * or to check if we can write to it. First case is "source", second is "dest".
+ * It is necessary to know what the StatJob is for, to tune the tdeioslave's behavior
+ * (e.g. with FTP).
+ * @param source true for "source" mode, false for "dest" mode
+ */
+ void setSide( bool source ) { m_bSource = source; }
+
+ /**
+ * Selects the level of @p details we want.
+ * By default this is 2 (all details wanted, including modification time, size, etc.),
+ * setDetails(1) is used when deleting: we don't need all the information if it takes
+ * too much time, no need to follow symlinks etc.
+ * setDetails(0) is used for very simple probing: we'll only get the answer
+ * "it's a file or a directory, or it doesn't exist". This is used by KRun.
+ * @param details 2 for all details, 1 for simple, 0 for very simple
+ */
+ void setDetails( short int details ) { m_details = details; }
+
+ /**
+ * Call this in the slot connected to result,
+ * and only after making sure no error happened.
+ * @return the result of the stat
+ */
+ const UDSEntry & statResult() const { return m_statResult; }
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start( Slave *slave );
+
+ signals:
+ /**
+ * Signals a redirection.
+ * Use to update the URL shown to the user.
+ * The redirection itself is handled internally.
+ * @param job the job that is redirected
+ * @param url the new url
+ */
+ void redirection( TDEIO::Job *job, const KURL &url );
+
+ /**
+ * Signals a permanent redirection.
+ * The redirection itself is handled internally.
+ * @param job the job that is redirected
+ * @param fromUrl the original URL
+ * @param toUrl the new URL
+ * @since 3.1
+ */
+ void permanentRedirection( TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl );
+
+ protected slots:
+ void slotStatEntry( const TDEIO::UDSEntry & entry );
+ void slotRedirection( const KURL &url);
+ virtual void slotFinished();
+ virtual void slotMetaData( const TDEIO::MetaData &_metaData);
+
+ protected:
+ UDSEntry m_statResult;
+ KURL m_redirectionURL;
+ bool m_bSource;
+ short int m_details;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class StatJobPrivate;
+ StatJobPrivate *d;
+ };
+
+ /**
+ * A KIO job that creates a directory
+ * @see TDEIO::mkdir()
+ * @since 3.3
+ */
+ class TDEIO_EXPORT MkdirJob : public SimpleJob {
+
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not use this constructor to create a MkdirJob, use TDEIO::mkdir() instead.
+ * @param url the url of the file or directory to check
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param showProgressInfo true to show progress information to the user
+ */
+ MkdirJob(const KURL& url, int command, const TQByteArray &packedArgs, bool showProgressInfo);
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start( Slave *slave );
+
+ signals:
+ /**
+ * Signals a redirection.
+ * Use to update the URL shown to the user.
+ * The redirection itself is handled internally.
+ * @param job the job that is redirected
+ * @param url the new url
+ */
+ void redirection( TDEIO::Job *job, const KURL &url );
+
+ /**
+ * Signals a permanent redirection.
+ * The redirection itself is handled internally.
+ * @param job the job that is redirected
+ * @param fromUrl the original URL
+ * @param toUrl the new URL
+ */
+ void permanentRedirection( TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl );
+
+ protected slots:
+ void slotRedirection( const KURL &url);
+ virtual void slotFinished();
+
+ protected:
+ KURL m_redirectionURL;
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class MkdirJobPrivate;
+ MkdirJobPrivate *d;
+ };
+
+ /**
+ * @internal
+ * Used for direct copy from or to the local filesystem (i.e. SlaveBase::copy())
+ */
+ class TDEIO_EXPORT DirectCopyJob : public SimpleJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a DirectCopyJob. Use TDEIO::copy() or TDEIO::file_copy() instead.
+ */
+ DirectCopyJob(const KURL& url, int command, const TQByteArray &packedArgs,
+ bool showProgressInfo);
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start(Slave *slave);
+
+ signals:
+ /**
+ * @internal
+ * Emitted if the job found an existing partial file
+ * and supports resuming. Used by FileCopyJob.
+ */
+ void canResume( TDEIO::Job *job, TDEIO::filesize_t offset );
+
+ private slots:
+ void slotCanResume( TDEIO::filesize_t offset );
+ };
+
+
+ /**
+ * The transfer job pumps data into and/or out of a Slave.
+ * Data is sent to the slave on request of the slave ( dataReq).
+ * If data coming from the slave can not be handled, the
+ * reading of data from the slave should be suspended.
+ */
+ class TDEIO_EXPORT TransferJob : public SimpleJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a TransferJob. Use TDEIO::get() or TDEIO::put()
+ * instead.
+ * @param url the url to get or put
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param _staticData additional data to transmit (e.g. in a HTTP Post)
+ * @param showProgressInfo true to show progress information to the user
+ */
+ TransferJob(const KURL& url, int command,
+ const TQByteArray &packedArgs,
+ const TQByteArray &_staticData,
+ bool showProgressInfo);
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start(Slave *slave);
+
+ /**
+ * Called when m_subJob finishes.
+ * @param job the job that finished
+ */
+ virtual void slotResult( TDEIO::Job *job );
+
+ /**
+ * Flow control. Suspend data processing from the slave.
+ */
+ void suspend();
+
+ /**
+ * Flow control. Resume data processing from the slave.
+ */
+ void resume();
+
+ /**
+ * Flow control.
+ * @return true if the job is suspended
+ */
+ bool isSuspended() const { return m_suspended; }
+
+
+ /**
+ * Checks whether we got an error page. This currently only happens
+ * with HTTP urls. Call this from your slot connected to result().
+ *
+ * @return true if we got an (HTML) error page from the server
+ * instead of what we asked for.
+ */
+ bool isErrorPage() const { return m_errorPage; }
+
+ /**
+ * Enable the async data mode.
+ * When async data is enabled, data should be provided to the job by
+ * calling sendAsyncData() instead of returning data in the
+ * dataReq() signal.
+ * @since 3.2
+ */
+ void setAsyncDataEnabled(bool enabled);
+
+ /**
+ * Provide data to the job when async data is enabled.
+ * Should be called exactly once after receiving a dataReq signal
+ * Sending an empty block indicates end of data.
+ * @since 3.2
+ */
+ void sendAsyncData(const TQByteArray &data);
+
+ /**
+ * When enabled, the job reports the amount of data that has been sent,
+ * instead of the amount of data that that has been received.
+ * @see slotProcessedSize
+ * @see slotSpeed
+ * @since 3.2
+ */
+ void setReportDataSent(bool enabled);
+
+ /**
+ * Returns whether the job reports the amount of data that has been
+ * sent (true), or whether the job reports the amount of data that
+ * has been received (false)
+ * @since 3.2
+ */
+ bool reportDataSent();
+
+ signals:
+ /**
+ * Data from the slave has arrived.
+ * @param job the job that emitted this signal
+ * @param data data received from the slave.
+ *
+ * End of data (EOD) has been reached if data.size() == 0, however, you
+ * should not be certain of data.size() == 0 ever happening (e.g. in case
+ * of an error), so you should rely on result() instead.
+ */
+ void data( TDEIO::Job *job, const TQByteArray &data );
+
+ /**
+ * Request for data.
+ * Please note, that you shouldn't put too large chunks
+ * of data in it as this requires copies within the frame
+ * work, so you should rather split the data you want
+ * to pass here in reasonable chunks (about 1MB maximum)
+ *
+ * @param job the job that emitted this signal
+ * @param data buffer to fill with data to send to the
+ * slave. An empty buffer indicates end of data. (EOD)
+ */
+ void dataReq( TDEIO::Job *job, TQByteArray &data );
+
+ /**
+ * Signals a redirection.
+ * Use to update the URL shown to the user.
+ * The redirection itself is handled internally.
+ * @param job the job that emitted this signal
+ * @param url the new URL
+ */
+ void redirection( TDEIO::Job *job, const KURL &url );
+
+ /**
+ * Signals a permanent redirection.
+ * The redirection itself is handled internally.
+ * @param job the job that emitted this signal
+ * @param fromUrl the original URL
+ * @param toUrl the new URL
+ * @since 3.1
+ */
+ void permanentRedirection( TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl );
+
+ /**
+ * Mimetype determined.
+ * @param job the job that emitted this signal
+ * @param type the mime type
+ */
+ void mimetype( TDEIO::Job *job, const TQString &type );
+
+ /**
+ * @internal
+ * Emitted if the "put" job found an existing partial file
+ * (in which case offset is the size of that file)
+ * and emitted by the "get" job if it supports resuming to
+ * the given offset - in this case @p offset is unused)
+ */
+ void canResume( TDEIO::Job *job, TDEIO::filesize_t offset );
+
+
+ protected slots:
+ virtual void slotRedirection( const KURL &url);
+ virtual void slotFinished();
+ virtual void slotData( const TQByteArray &data);
+ virtual void slotDataReq();
+ virtual void slotMimetype( const TQString &mimetype );
+ virtual void slotNeedSubURLData();
+ virtual void slotSubURLData(TDEIO::Job*, const TQByteArray &);
+ virtual void slotMetaData( const TDEIO::MetaData &_metaData);
+ void slotErrorPage();
+ void slotCanResume( TDEIO::filesize_t offset );
+ void slotPostRedirection();
+
+ protected:
+ bool m_suspended;
+ bool m_errorPage;
+ TQByteArray staticData;
+ KURL m_redirectionURL;
+ KURL::List m_redirectionList;
+ TQString m_mimetype;
+ TransferJob *m_subJob;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class TransferJobPrivate *d;
+ };
+
+ /**
+ * StoredTransferJob is a TransferJob (for downloading or uploading data) that
+ * also stores a TQByteArray with the data, making it simpler to use than the
+ * standard TransferJob.
+ *
+ * For TDEIO::storedGet it puts the data into the member TQByteArray, so the user
+ * of this class can get hold of the whole data at once by calling data()
+ * when the result signal is emitted.
+ * You should only use StoredTransferJob to download data if you cannot
+ * process the data by chunks while it's being downloaded, since storing
+ * everything in a TQByteArray can potentially require a lot of memory.
+ *
+ * For TDEIO::storedPut the user of this class simply provides the bytearray from
+ * the start, and the job takes care of uploading it.
+ * You should only use StoredTransferJob to upload data if you cannot
+ * provide the in chunks while it's being uploaded, since storing
+ * everything in a TQByteArray can potentially require a lot of memory.
+ *
+ * @since 3.3
+ */
+ class TDEIO_EXPORT StoredTransferJob : public TDEIO::TransferJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a StoredTransferJob. Use storedGet() or storedPut()
+ * instead.
+ * @param url the url to get or put
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param _staticData additional data to transmit (e.g. in a HTTP Post)
+ * @param showProgressInfo true to show progress information to the user
+ */
+ StoredTransferJob(const KURL& url, int command,
+ const TQByteArray &packedArgs,
+ const TQByteArray &_staticData,
+ bool showProgressInfo);
+
+ /**
+ * Set data to be uploaded. This is for put jobs.
+ * Automatically called by TDEIO::storedPut(const TQByteArray &, ...),
+ * do not call this yourself.
+ */
+ void setData( const TQByteArray& arr );
+
+ /**
+ * Get hold of the downloaded data. This is for get jobs.
+ * You're supposed to call this only from the slot connected to the result() signal.
+ */
+ TQByteArray data() const { return m_data; }
+
+ private slots:
+ void slotStoredData( TDEIO::Job *job, const TQByteArray &data );
+ void slotStoredDataReq( TDEIO::Job *job, TQByteArray &data );
+ private:
+ TQByteArray m_data;
+ int m_uploadOffset;
+ };
+
+ /**
+ * The MultiGetJob is a TransferJob that allows you to get
+ * several files from a single server. Don't create directly,
+ * but use TDEIO::multi_get() instead.
+ * @see TDEIO::multi_get()
+ */
+ class TDEIO_EXPORT MultiGetJob : public TransferJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a MultiGetJob directly, use TDEIO::multi_get()
+ * instead.
+ *
+ * @param url the first url to get
+ * @param showProgressInfo true to show progress information to the user
+ */
+ MultiGetJob(const KURL& url, bool showProgressInfo);
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start(Slave *slave);
+
+ /**
+ * Get an additional file.
+ *
+ * @param id the id of the file
+ * @param url the url of the file to get
+ * @param metaData the meta data for this request
+ */
+ void get(long id, const KURL &url, const MetaData &metaData);
+
+ signals:
+ /**
+ * Data from the slave has arrived.
+ * @param id the id of the request
+ * @param data data received from the slave.
+ * End of data (EOD) has been reached if data.size() == 0
+ */
+ void data( long id, const TQByteArray &data);
+
+ /**
+ * Mimetype determined
+ * @param id the id of the request
+ * @param type the mime type
+ */
+ void mimetype( long id, const TQString &type );
+
+ /**
+ * File transfer completed.
+ *
+ * When all files have been processed, result(TDEIO::Job *) gets
+ * emitted.
+ * @param id the id of the request
+ */
+ void result( long id);
+
+ protected slots:
+ virtual void slotRedirection( const KURL &url);
+ virtual void slotFinished();
+ virtual void slotData( const TQByteArray &data);
+ virtual void slotMimetype( const TQString &mimetype );
+ private:
+ struct GetRequest {
+ public:
+ GetRequest(long _id, const KURL &_url, const MetaData &_metaData)
+ : id(_id), url(_url), metaData(_metaData) { }
+ long id;
+ KURL url;
+ MetaData metaData;
+ };
+ bool findCurrentEntry();
+ void flushQueue(TQPtrList<GetRequest> &queue);
+
+ TQPtrList<GetRequest> m_waitQueue;
+ TQPtrList<GetRequest> m_activeQueue;
+ bool b_multiGetActive;
+ GetRequest *m_currentEntry;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class MultiGetJobPrivate* d;
+ };
+
+ /**
+ * A MimetypeJob is a TransferJob that allows you to get
+ * the mime type of an URL. Don't create directly,
+ * but use TDEIO::mimetype() instead.
+ * @see TDEIO::mimetype()
+ */
+ class TDEIO_EXPORT MimetypeJob : public TransferJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a MimetypeJob directly. Use TDEIO::mimetype()
+ * instead.
+ * @param url the url to get
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param showProgressInfo true to show progress information to the user
+ */
+ MimetypeJob(const KURL& url, int command, const TQByteArray &packedArgs, bool showProgressInfo);
+
+ /**
+ * Call this in the slot connected to result,
+ * and only after making sure no error happened.
+ * @return the mimetype of the URL
+ */
+ TQString mimetype() const { return m_mimetype; }
+
+ /**
+ * @internal
+ * Called by the scheduler when a slave gets to
+ * work on this job.
+ * @param slave the slave that works on the job
+ */
+ virtual void start( Slave *slave );
+
+ protected slots:
+ virtual void slotFinished( );
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class MimetypeJobPrivate* d;
+ };
+
+ /**
+ * The FileCopyJob copies data from one place to another.
+ * @see TDEIO::file_copy()
+ * @see TDEIO::file_move()
+ */
+ class TDEIO_EXPORT FileCopyJob : public Job {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a FileCopyJob directly. Use TDEIO::file_move()
+ * or TDEIO::file_copy() instead.
+ * @param src the source URL
+ * @param dest the destination URL
+ * @param permissions the permissions of the resulting resource
+ * @param move true to move, false to copy
+ * @param overwrite true to allow overwriting, false otherwise
+ * @param resume true to resume an operation, false otherwise
+ * @param showProgressInfo true to show progress information to the user
+ */
+ FileCopyJob( const KURL& src, const KURL& dest, int permissions,
+ bool move, bool overwrite, bool resume, bool showProgressInfo);
+
+ ~FileCopyJob();
+ /**
+ * If you know the size of the source file, call this method
+ * to inform this job. It will be displayed in the "resume" dialog.
+ * @param size the size of the source file
+ * @since 3.2
+ */
+ void setSourceSize64(TDEIO::filesize_t size);
+
+ /**
+ * Sets the modification time of the file
+ *
+ * Note that this is ignored if a direct copy (SlaveBase::copy) can be done,
+ * in which case the mtime of the source is applied to the destination (if the protocol
+ * supports the concept).
+ */
+ void setModificationTime( time_t mtime );
+
+ /**
+ * @deprecated
+ */
+ void setSourceSize( off_t size ) KDE_DEPRECATED;
+
+ /**
+ * Returns the source URL.
+ * @return the source URL
+ */
+ KURL srcURL() const { return m_src; }
+
+ /**
+ * Returns the destination URL.
+ * @return the destination URL
+ */
+ KURL destURL() const { return m_dest; }
+
+ signals:
+ /**
+ * Mimetype determined during a file copy.
+ * This is never emitted during a move, and might not be emitted during
+ * a copy, depending on the slave.
+ * @param job the job that emitted this signal
+ * @param type the mime type
+ *
+ * @since 3.5.7
+ */
+ void mimetype( TDEIO::Job *job, const TQString &type );
+
+ public slots:
+ void slotStart();
+ void slotData( TDEIO::Job *, const TQByteArray &data);
+ void slotDataReq( TDEIO::Job *, TQByteArray &data);
+ void slotMimetype( TDEIO::Job *, const TQString& type );
+
+ protected slots:
+ /**
+ * Called whenever a subjob finishes.
+ * @param job the job that emitted this signal
+ */
+ virtual void slotResult( TDEIO::Job *job );
+
+ /**
+ * Forward signal from subjob
+ * @param job the job that emitted this signal
+ * @param size the processed size in bytes
+ */
+ void slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size );
+ /**
+ * Forward signal from subjob
+ * @param job the job that emitted this signal
+ * @param size the total size
+ */
+ void slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size );
+ /**
+ * Forward signal from subjob
+ * @param job the job that emitted this signal
+ * @param pct the percentage
+ */
+ void slotPercent( TDEIO::Job *job, unsigned long pct );
+ /**
+ * Forward signal from subjob
+ * @param job the job that emitted this signal
+ * @param offset the offset to resume from
+ */
+ void slotCanResume( TDEIO::Job *job, TDEIO::filesize_t offset );
+
+ protected:
+ void startCopyJob();
+ void startCopyJob(const KURL &slave_url);
+ void startRenameJob(const KURL &slave_url);
+ void startDataPump();
+ void connectSubjob( SimpleJob * job );
+
+ private:
+ void startBestCopyMethod();
+
+ protected:
+ KURL m_src;
+ KURL m_dest;
+ int m_permissions;
+ bool m_move:1;
+ bool m_overwrite:1;
+ bool m_resume:1;
+ bool m_canResume:1;
+ bool m_resumeAnswerSent:1;
+ TQByteArray m_buffer;
+ SimpleJob *m_moveJob;
+ SimpleJob *m_copyJob;
+ TransferJob *m_getJob;
+ TransferJob *m_putJob;
+ TDEIO::filesize_t m_totalSize;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class FileCopyJobPrivate;
+ FileCopyJobPrivate* d;
+ };
+
+ /**
+ * A ListJob is allows you to get the get the content of a directory.
+ * Don't create the job directly, but use TDEIO::listRecursive() or
+ * TDEIO::listDir() instead.
+ * @see TDEIO::listRecursive()
+ * @see TDEIO::listDir()
+ */
+ class TDEIO_EXPORT ListJob : public SimpleJob {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a ListJob directly. Use TDEIO::listDir() or
+ * TDEIO::listRecursive() instead.
+ * @param url the url of the directory
+ * @param showProgressInfo true to show progress information to the user
+ * @param recursive true to get the data recursively from child directories,
+ * false to get only the content of the specified dir
+ * @param prefix the prefix of the files, or TQString::null for no prefix
+ * @param includeHidden true to include hidden files (those starting with '.')
+ */
+ ListJob(const KURL& url, bool showProgressInfo,
+ bool recursive = false, TQString prefix = TQString::null,
+ bool includeHidden = true);
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start( Slave *slave );
+
+ /**
+ * Returns the ListJob's redirection URL. This will be invalid if there
+ * was no redirection.
+ * @return the redirection url
+ * @since 3.4.1
+ */
+ const KURL& redirectionURL() const { return m_redirectionURL; }
+
+ /**
+ * Do not apply any KIOSK restrictions to this job.
+ * @since 3.2
+ */
+ void setUnrestricted(bool unrestricted);
+
+ signals:
+ /**
+ * This signal emits the entry found by the job while listing.
+ * The progress signals aren't specific to ListJob. It simply
+ * uses SimpleJob's processedSize (number of entries listed) and
+ * totalSize (total number of entries, if known),
+ * as well as percent.
+ * @param job the job that emitted this signal
+ * @param list the list of UDSEntries
+ */
+ void entries( TDEIO::Job *job, const TDEIO::UDSEntryList& list);
+
+ /**
+ * Signals a redirection.
+ * Use to update the URL shown to the user.
+ * The redirection itself is handled internally.
+ * @param job the job that is redirected
+ * @param url the new url
+ */
+ void redirection( TDEIO::Job *job, const KURL &url );
+
+ /**
+ * Signals a permanent redirection.
+ * The redirection itself is handled internally.
+ * @param job the job that emitted this signal
+ * @param fromUrl the original URL
+ * @param toUrl the new URL
+ * @since 3.1
+ */
+ void permanentRedirection( TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl );
+
+ protected slots:
+ virtual void slotFinished( );
+ virtual void slotMetaData( const TDEIO::MetaData &_metaData);
+ virtual void slotResult( TDEIO::Job *job );
+ void slotListEntries( const TDEIO::UDSEntryList& list );
+ void slotRedirection( const KURL &url );
+ void gotEntries( TDEIO::Job * subjob, const TDEIO::UDSEntryList& list );
+
+ private:
+ bool recursive;
+ bool includeHidden;
+ TQString prefix;
+ unsigned long m_processedEntries;
+ KURL m_redirectionURL;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class ListJobPrivate* d;
+ };
+
+ /// @internal
+ struct TDEIO_EXPORT CopyInfo
+ {
+ KURL uSource;
+ KURL uDest;
+ TQString linkDest; // for symlinks only
+ int permissions;
+ //mode_t type;
+ time_t ctime;
+ time_t mtime;
+ TDEIO::filesize_t size; // 0 for dirs
+ };
+
+ /**
+ * CopyJob is used to move, copy or symlink files and directories.
+ * Don't create the job directly, but use TDEIO::copy(),
+ * TDEIO::move(), TDEIO::link() and friends.
+ *
+ * @see TDEIO::copy()
+ * @see TDEIO::copyAs()
+ * @see TDEIO::move()
+ * @see TDEIO::moveAs()
+ * @see TDEIO::link()
+ * @see TDEIO::linkAs()
+ */
+ class TDEIO_EXPORT CopyJob : public Job {
+ Q_OBJECT
+
+ public:
+ /**
+ * Defines the mode of the operation
+ */
+ enum CopyMode{ Copy, Move, Link };
+
+ /**
+ * Do not create a CopyJob directly. Use TDEIO::copy(),
+ * TDEIO::move(), TDEIO::link() and friends instead.
+ *
+ * @param src the list of source URLs
+ * @param dest the destination URL
+ * @param mode specifies whether the job should copy, move or link
+ * @param asMethod if true, behaves like TDEIO::copyAs(),
+ * TDEIO::moveAs() or TDEIO::linkAs()
+ * @param showProgressInfo true to show progress information to the user
+ * @see TDEIO::copy()
+ * @see TDEIO::copyAs()
+ * @see TDEIO::move()
+ * @see TDEIO::moveAs()
+ * @see TDEIO::link()
+ * @see TDEIO::linkAs()
+ */
+ CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo );
+
+ virtual ~CopyJob();
+
+ /**
+ * Returns the list of source URLs.
+ * @return the list of source URLs.
+ */
+ KURL::List srcURLs() const { return m_srcList; }
+
+ /**
+ * Returns the destination URL.
+ * @return the destination URL
+ */
+ KURL destURL() const { return m_dest; }
+
+ /**
+ * By default the permissions of the copied files will be those of the source files.
+ *
+ * But when copying "template" files to "new" files, people prefer the umask
+ * to apply, rather than the template's permissions.
+ * For that case, call setDefaultPermissions(true)
+ *
+ * TODO KDE4: consider adding this as bool to copy/copyAs?
+ * @since 3.2.3
+ */
+ void setDefaultPermissions( bool b );
+
+ /**
+ * When an error happens while copying/moving a file, the user will be presented with
+ * a dialog for skipping the file that can't be copied/moved.
+ * Or if the error is that the destination file already exists, the standard
+ * rename dialog is shown.
+ * If the program doesn't want CopyJob to show dialogs, but to simply fail on error,
+ * call setInteractive( false ).
+ *
+ * KDE4: remove, already in Job
+ * @since 3.4
+ */
+ void setInteractive( bool b );
+
+ signals:
+
+ /**
+ * Emitted when the total number of files is known.
+ * @param job the job that emitted this signal
+ * @param files the total number of files
+ */
+ void totalFiles( TDEIO::Job *job, unsigned long files );
+ /**
+ * Emitted when the toal number of direcotries is known.
+ * @param job the job that emitted this signal
+ * @param dirs the total number of directories
+ */
+ void totalDirs( TDEIO::Job *job, unsigned long dirs );
+
+ /**
+ * Emitted when it is known which files / directories are going
+ * to be created. Note that this may still change e.g. when
+ * existing files with the same name are discovered.
+ * @param job the job that emitted this signal
+ * @param files a list of items that are about to be created.
+ */
+ void aboutToCreate( TDEIO::Job *job, const TQValueList<TDEIO::CopyInfo> &files);
+
+ /**
+ * Sends the number of processed files.
+ * @param job the job that emitted this signal
+ * @param files the number of processed files
+ */
+ void processedFiles( TDEIO::Job *job, unsigned long files );
+ /**
+ * Sends the number of processed directories.
+ * @param job the job that emitted this signal
+ * @param dirs the number of processed dirs
+ */
+ void processedDirs( TDEIO::Job *job, unsigned long dirs );
+
+ /**
+ * The job is copying a file or directory.
+ * @param job the job that emitted this signal
+ * @param from the URl of the file or directory that is currently
+ * being copied
+ * @param to the destination of the current operation
+ */
+ void copying( TDEIO::Job *job, const KURL& from, const KURL& to );
+ /**
+ * The job is creating a symbolic link.
+ * @param job the job that emitted this signal
+ * @param target the URl of the file or directory that is currently
+ * being linked
+ * @param to the destination of the current operation
+ */
+ void linking( TDEIO::Job *job, const TQString& target, const KURL& to );
+ /**
+ * The job is moving a file or directory.
+ * @param job the job that emitted this signal
+ * @param from the URl of the file or directory that is currently
+ * being moved
+ * @param to the destination of the current operation
+ */
+ void moving( TDEIO::Job *job, const KURL& from, const KURL& to );
+ /**
+ * The job is creating the directory @p dir.
+ * @param job the job that emitted this signal
+ * @param dir the directory that is currently being created
+ */
+ void creatingDir( TDEIO::Job *job, const KURL& dir );
+ /**
+ * The user chose to rename @p from to @p to.
+ * @param job the job that emitted this signal
+ * @param from the original name
+ * @param to the new name
+ */
+ void renamed( TDEIO::Job *job, const KURL& from, const KURL& to );
+
+ /**
+ * The job emits this signal when copying or moving a file or directory successfully finished.
+ * This signal is mainly for the Undo feature.
+ *
+ * @param job the job that emitted this signal
+ * @param from the source URL
+ * @param to the destination URL
+ * @param directory indicates whether a file or directory was successfully copied/moved.
+ * true for a directoy, false for file
+ * @param renamed indicates that the destination URL was created using a
+ * rename operation (i.e. fast directory moving). true if is has been renamed
+ */
+ void copyingDone( TDEIO::Job *job, const KURL &from, const KURL &to, bool directory, bool renamed );
+ /**
+ * The job is copying or moving a symbolic link, that points to target.
+ * The new link is created in @p to. The existing one is/was in @p from.
+ * This signal is mainly for the Undo feature.
+ * @param job the job that emitted this signal
+ * @param from the source URL
+ * @param target the target
+ * @param to the destination URL
+ */
+ void copyingLinkDone( TDEIO::Job *job, const KURL &from, const TQString& target, const KURL& to );
+
+ protected:
+ void statCurrentSrc();
+ void statNextSrc();
+
+ // Those aren't slots but submethods for slotResult.
+ void slotResultStating( TDEIO::Job * job );
+ void startListing( const KURL & src );
+ void slotResultCreatingDirs( TDEIO::Job * job );
+ void slotResultConflictCreatingDirs( TDEIO::Job * job );
+ void createNextDir();
+ void slotResultCopyingFiles( TDEIO::Job * job );
+ void slotResultConflictCopyingFiles( TDEIO::Job * job );
+ void copyNextFile();
+ void slotResultDeletingDirs( TDEIO::Job * job );
+ void deleteNextDir();
+ void skip( const KURL & sourceURL );
+ void slotResultRenaming( TDEIO::Job * job );
+ //void slotResultSettingDirAttributes( TDEIO::Job * job );
+ void setNextDirAttribute();
+ private:
+ void startRenameJob(const KURL &slave_url);
+ bool shouldOverwrite( const TQString& path ) const;
+ bool shouldSkip( const TQString& path ) const;
+ void skipSrc();
+
+ protected slots:
+ void slotStart();
+ void slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList& list );
+ virtual void slotResult( TDEIO::Job *job );
+ /**
+ * Forward signal from subjob
+ */
+ void slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size );
+ /**
+ * Forward signal from subjob
+ * @param size the total size
+ */
+ void slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size );
+
+ void slotReport();
+ private:
+ CopyMode m_mode;
+ bool m_asMethod;
+ enum DestinationState { DEST_NOT_STATED, DEST_IS_DIR, DEST_IS_FILE, DEST_DOESNT_EXIST };
+ DestinationState destinationState;
+ enum { STATE_STATING, STATE_RENAMING, STATE_LISTING, STATE_CREATING_DIRS,
+ STATE_CONFLICT_CREATING_DIRS, STATE_COPYING_FILES, STATE_CONFLICT_COPYING_FILES,
+ STATE_DELETING_DIRS, STATE_SETTING_DIR_ATTRIBUTES } state;
+ TDEIO::filesize_t m_totalSize;
+ TDEIO::filesize_t m_processedSize;
+ TDEIO::filesize_t m_fileProcessedSize;
+ int m_processedFiles;
+ int m_processedDirs;
+ TQValueList<CopyInfo> files;
+ TQValueList<CopyInfo> dirs;
+ KURL::List dirsToRemove;
+ KURL::List m_srcList;
+ KURL::List::Iterator m_currentStatSrc;
+ bool m_bCurrentSrcIsDir;
+ bool m_bCurrentOperationIsLink;
+ bool m_bSingleFileCopy;
+ bool m_bOnlyRenames;
+ KURL m_dest;
+ KURL m_currentDest;
+ //
+ TQStringList m_skipList;
+ TQStringList m_overwriteList;
+ bool m_bAutoSkip;
+ bool m_bOverwriteAll;
+ int m_conflictError;
+
+ TQTimer *m_reportTimer;
+ //these both are used for progress dialog reporting
+ KURL m_currentSrcURL;
+ KURL m_currentDestURL;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class CopyJobPrivate;
+ CopyJobPrivate* d;
+ friend class CopyJobPrivate; // for DestinationState
+ };
+
+ /**
+ * A more complex Job to delete files and directories.
+ * Don't create the job directly, but use TDEIO::del() instead.
+ *
+ * @see TDEIO::del()
+ */
+ class TDEIO_EXPORT DeleteJob : public Job {
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not create a DeleteJob directly. Use TDEIO::del()
+ * instead.
+ *
+ * @param src the list of URLs to delete
+ * @param shred true to shred (make sure that data is not recoverable)a
+ * @param showProgressInfo true to show progress information to the user
+ * @see TDEIO::del()
+ */
+ DeleteJob( const KURL::List& src, bool shred, bool showProgressInfo );
+
+ /**
+ * Returns the list of URLs.
+ * @return the list of URLs.
+ */
+ KURL::List urls() const { return m_srcList; }
+
+ signals:
+
+ /**
+ * Emitted when the total number of files is known.
+ * @param job the job that emitted this signal
+ * @param files the total number of files
+ */
+ void totalFiles( TDEIO::Job *job, unsigned long files );
+ /**
+ * Emitted when the toal number of direcotries is known.
+ * @param job the job that emitted this signal
+ * @param dirs the total number of directories
+ */
+ void totalDirs( TDEIO::Job *job, unsigned long dirs );
+
+ /**
+ * Sends the number of processed files.
+ * @param job the job that emitted this signal
+ * @param files the number of processed files
+ */
+ void processedFiles( TDEIO::Job *job, unsigned long files );
+ /**
+ * Sends the number of processed directories.
+ * @param job the job that emitted this signal
+ * @param dirs the number of processed dirs
+ */
+ void processedDirs( TDEIO::Job *job, unsigned long dirs );
+
+ /**
+ * Sends the URL of the file that is currently being deleted.
+ * @param job the job that emitted this signal
+ * @param file the URL of the file or directory that is being
+ * deleted
+ */
+ void deleting( TDEIO::Job *job, const KURL& file );
+
+ protected slots:
+ void slotStart();
+ void slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList& list );
+ virtual void slotResult( TDEIO::Job *job );
+
+ /**
+ * Forward signal from subjob
+ */
+ void slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size );
+ void slotReport();
+
+ private:
+ void statNextSrc();
+ void deleteNextFile();
+ void deleteNextDir();
+
+ private:
+ enum { STATE_STATING, STATE_LISTING,
+ STATE_DELETING_FILES, STATE_DELETING_DIRS } state;
+ TDEIO::filesize_t m_totalSize;
+ TDEIO::filesize_t m_processedSize;
+ TDEIO::filesize_t m_fileProcessedSize;
+ int m_processedFiles;
+ int m_processedDirs;
+ int m_totalFilesDirs;
+ KURL m_currentURL;
+ KURL::List files;
+ KURL::List symlinks;
+ KURL::List dirs;
+ KURL::List m_srcList;
+ KURL::List::Iterator m_currentStat;
+ TQStringList m_parentDirs;
+ bool m_shred; // BIC: remove in KDE4
+ TQTimer *m_reportTimer;
+ protected:
+ /** \internal */
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class DeleteJobPrivate* d;
+ };
+
+ /**
+ * A KIO job that finds a local URL
+ * @see TDEIO::localURL()
+ * @since R14.0.0
+ */
+ class TDEIO_EXPORT LocalURLJob : public SimpleJob {
+
+ Q_OBJECT
+
+ public:
+ /**
+ * Do not use this constructor to create a LocalURLJob, use TDEIO::localURL() instead.
+ * @param url the url of the file or directory to check
+ * @param command the command to issue
+ * @param packedArgs the arguments
+ * @param showProgressInfo true to show progress information to the user
+ */
+ LocalURLJob(const KURL& url, int command, const TQByteArray &packedArgs, bool showProgressInfo);
+
+ /**
+ * @internal
+ * Called by the scheduler when a @p slave gets to
+ * work on this job.
+ * @param slave the slave that starts working on this job
+ */
+ virtual void start( Slave *slave );
+
+ signals:
+ /**
+ * @param job the job that emitted this signal
+ * @param url the local url
+ * @param isLocal true if the returned URL is local, false if not
+ */
+ void localURL( TDEIO::Job *job, const KURL &url, bool isLocal );
+
+ protected slots:
+ void slotLocalURL( const KURL &url, bool isLocal );
+ virtual void slotFinished();
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class LocalURLJobPrivate;
+ LocalURLJobPrivate *d;
+ };
+
+}
+
+#endif
diff --git a/tdeio/tdeio/kacl.cpp b/tdeio/tdeio/kacl.cpp
new file mode 100644
index 000000000..432a50d31
--- /dev/null
+++ b/tdeio/tdeio/kacl.cpp
@@ -0,0 +1,682 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Till Adam <adam@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.
+*/
+// $Id: kacl.cpp 424977 2005-06-13 15:13:22Z tilladam $
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#ifdef USE_POSIX_ACL
+#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
+#include <acl/libacl.h>
+#else
+#include <posixacladdons.h>
+#endif
+#endif
+#include <tqintdict.h>
+
+#include <kdebug.h>
+
+#include "kacl.h"
+
+
+#ifdef USE_POSIX_ACL
+static void printACL( acl_t acl, const TQString &comment );
+static TQString aclAsString(const acl_t acl);
+#endif
+
+class KACL::KACLPrivate {
+public:
+ KACLPrivate() : m_acl( 0 ) { init(); }
+#ifdef USE_POSIX_ACL
+ KACLPrivate( acl_t acl )
+ : m_acl( acl ) { init(); }
+ ~KACLPrivate() { if ( m_acl ) acl_free( m_acl ); }
+#endif
+ void init() {
+ m_usercache.setAutoDelete( true );
+ m_groupcache.setAutoDelete( true );
+ }
+ // helpers
+#ifdef USE_POSIX_ACL
+ bool setMaskPermissions( unsigned short v );
+ TQString getUserName( uid_t uid ) const;
+ TQString getGroupName( gid_t gid ) const;
+ bool setAllUsersOrGroups( const TQValueList< QPair<TQString, unsigned short> > &list, acl_tag_t type );
+ bool setNamedUserOrGroupPermissions( const TQString& name, unsigned short permissions, acl_tag_t type );
+
+ acl_t m_acl;
+#else
+ int m_acl;
+#endif
+ mutable TQIntDict<TQString> m_usercache;
+ mutable TQIntDict<TQString> m_groupcache;
+};
+
+KACL::KACL( const TQString &aclString )
+ : d( new KACLPrivate )
+{
+ setACL( aclString );
+}
+
+KACL::KACL( mode_t basePermissions )
+#ifdef USE_POSIX_ACL
+ : d( new KACLPrivate( acl_from_mode( basePermissions ) ) )
+#else
+ : d( new KACLPrivate )
+#endif
+{
+#ifndef USE_POSIX_ACL
+ Q_UNUSED( basePermissions );
+#endif
+}
+
+KACL::KACL()
+ : d( new KACLPrivate )
+{
+}
+
+KACL::KACL( const KACL& rhs )
+ : d( new KACLPrivate )
+{
+ setACL( rhs.asString() );
+}
+
+KACL::~KACL()
+{
+ delete d;
+}
+
+bool KACL::operator==( const KACL& rhs ) const {
+#ifdef USE_POSIX_ACL
+ return ( acl_cmp( d->m_acl, rhs.d->m_acl ) == 0 );
+#else
+ Q_UNUSED( rhs );
+ return true;
+#endif
+}
+
+bool KACL::isValid() const
+{
+ bool valid = false;
+#ifdef USE_POSIX_ACL
+ if ( d->m_acl ) {
+ valid = ( acl_valid( d->m_acl ) == 0 );
+ }
+#endif
+ return valid;
+}
+
+bool KACL::isExtended() const
+{
+#ifdef USE_POSIX_ACL
+ return ( acl_equiv_mode( d->m_acl, NULL ) != 0 );
+#else
+ return false;
+#endif
+}
+
+#ifdef USE_POSIX_ACL
+static acl_entry_t entryForTag( acl_t acl, acl_tag_t tag )
+{
+ acl_entry_t entry;
+ int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == tag )
+ return entry;
+ ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry );
+ }
+ return 0;
+}
+
+static unsigned short entryToPermissions( acl_entry_t entry )
+{
+ if ( entry == 0 ) return 0;
+ acl_permset_t permset;
+ if ( acl_get_permset( entry, &permset ) != 0 ) return 0;
+ return( acl_get_perm( permset, ACL_READ ) << 2 |
+ acl_get_perm( permset, ACL_WRITE ) << 1 |
+ acl_get_perm( permset, ACL_EXECUTE ) );
+}
+
+static void permissionsToEntry( acl_entry_t entry, unsigned short v )
+{
+ if ( entry == 0 ) return;
+ acl_permset_t permset;
+ if ( acl_get_permset( entry, &permset ) != 0 ) return;
+ acl_clear_perms( permset );
+ if ( v & 4 ) acl_add_perm( permset, ACL_READ );
+ if ( v & 2 ) acl_add_perm( permset, ACL_WRITE );
+ if ( v & 1 ) acl_add_perm( permset, ACL_EXECUTE );
+}
+
+static void printACL( acl_t acl, const TQString &comment )
+{
+ kdDebug() << comment << aclAsString( acl ) << endl;
+}
+
+static int getUidForName( const TQString& name )
+{
+ struct passwd *user = getpwnam( name.latin1() );
+ if ( user )
+ return user->pw_uid;
+ else
+ return -1;
+}
+
+static int getGidForName( const TQString& name )
+{
+ struct group *group = getgrnam( name.latin1() );
+ if ( group )
+ return group->gr_gid;
+ else
+ return -1;
+}
+#endif
+// ------------------ begin API implementation ------------
+
+unsigned short KACL::ownerPermissions() const
+{
+#ifdef USE_POSIX_ACL
+ return entryToPermissions( entryForTag( d->m_acl, ACL_USER_OBJ ) );
+#else
+ return 0;
+#endif
+}
+
+bool KACL::setOwnerPermissions( unsigned short v )
+{
+#ifdef USE_POSIX_ACL
+ permissionsToEntry( entryForTag( d->m_acl, ACL_USER_OBJ ), v );
+#else
+ Q_UNUSED( v );
+#endif
+ return true;
+}
+
+unsigned short KACL::owningGroupPermissions() const
+{
+#ifdef USE_POSIX_ACL
+ return entryToPermissions( entryForTag( d->m_acl, ACL_GROUP_OBJ ) );
+#else
+ return 0;
+#endif
+}
+
+bool KACL::setOwningGroupPermissions( unsigned short v )
+{
+#ifdef USE_POSIX_ACL
+ permissionsToEntry( entryForTag( d->m_acl, ACL_GROUP_OBJ ), v );
+#else
+ Q_UNUSED( v );
+#endif
+ return true;
+}
+
+unsigned short KACL::othersPermissions() const
+{
+#ifdef USE_POSIX_ACL
+ return entryToPermissions( entryForTag( d->m_acl, ACL_OTHER ) );
+#else
+ return 0;
+#endif
+}
+
+bool KACL::setOthersPermissions( unsigned short v )
+{
+#ifdef USE_POSIX_ACL
+ permissionsToEntry( entryForTag( d->m_acl, ACL_OTHER ), v );
+#else
+ Q_UNUSED( v );
+#endif
+ return true;
+}
+
+mode_t KACL::basePermissions() const
+{
+ mode_t perms( 0 );
+#ifdef USE_POSIX_ACL
+ if ( ownerPermissions() & ACL_READ ) perms |= S_IRUSR;
+ if ( ownerPermissions() & ACL_WRITE ) perms |= S_IWUSR;
+ if ( ownerPermissions() & ACL_EXECUTE ) perms |= S_IXUSR;
+ if ( owningGroupPermissions() & ACL_READ ) perms |= S_IRGRP;
+ if ( owningGroupPermissions() & ACL_WRITE ) perms |= S_IWGRP;
+ if ( owningGroupPermissions() & ACL_EXECUTE ) perms |= S_IXGRP;
+ if ( othersPermissions() & ACL_READ ) perms |= S_IROTH;
+ if ( othersPermissions() & ACL_WRITE ) perms |= S_IWOTH;
+ if ( othersPermissions() & ACL_EXECUTE ) perms |= S_IXOTH;
+#endif
+ return perms;
+}
+
+unsigned short KACL::maskPermissions( bool &exists ) const
+{
+ exists = true;
+#ifdef USE_POSIX_ACL
+ acl_entry_t entry = entryForTag( d->m_acl, ACL_MASK );
+ if ( entry == 0 ) {
+ exists = false;
+ return 0;
+ }
+ return entryToPermissions( entry );
+#else
+ return 0;
+#endif
+}
+
+#ifdef USE_POSIX_ACL
+bool KACL::KACLPrivate::setMaskPermissions( unsigned short v )
+{
+ acl_entry_t entry = entryForTag( m_acl, ACL_MASK );
+ if ( entry == 0 ) {
+ acl_create_entry( &m_acl, &entry );
+ acl_set_tag_type( entry, ACL_MASK );
+ }
+ permissionsToEntry( entry, v );
+ return true;
+}
+#endif
+
+bool KACL::setMaskPermissions( unsigned short v )
+{
+#ifdef USE_POSIX_ACL
+ return d->setMaskPermissions( v );
+#else
+ Q_UNUSED( v );
+ return true;
+#endif
+}
+
+/**************************
+ * Deal with named users *
+ **************************/
+unsigned short KACL::namedUserPermissions( const TQString& name, bool *exists ) const
+{
+#ifdef USE_POSIX_ACL
+ acl_entry_t entry;
+ uid_t id;
+ *exists = false;
+ int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == ACL_USER ) {
+ id = *( (uid_t*) acl_get_qualifier( entry ) );
+ if ( d->getUserName( id ) == name ) {
+ *exists = true;
+ return entryToPermissions( entry );
+ }
+ }
+ ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
+ }
+#else
+ Q_UNUSED( name );
+ Q_UNUSED( exists );
+#endif
+ return 0;
+}
+
+#ifdef USE_POSIX_ACL
+bool KACL::KACLPrivate::setNamedUserOrGroupPermissions( const TQString& name, unsigned short permissions, acl_tag_t type )
+{
+ bool allIsWell = true;
+ acl_t newACL = acl_dup( m_acl );
+ acl_entry_t entry;
+ bool createdNewEntry = false;
+ bool found = false;
+ int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == type ) {
+ int id = * (int*)acl_get_qualifier( entry );
+ const TQString entryName = type == ACL_USER? getUserName( id ): getGroupName( id );
+ if ( entryName == name ) {
+ // found him, update
+ permissionsToEntry( entry, permissions );
+ found = true;
+ break;
+ }
+ }
+ ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
+ }
+ if ( !found ) {
+ acl_create_entry( &newACL, &entry );
+ acl_set_tag_type( entry, type );
+ int id = type == ACL_USER? getUidForName( name ): getGidForName( name );
+ if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
+ acl_delete_entry( newACL, entry );
+ allIsWell = false;
+ } else {
+ permissionsToEntry( entry, permissions );
+ createdNewEntry = true;
+ }
+ }
+ if ( allIsWell && createdNewEntry ) {
+ // 23.1.1 of 1003.1e states that as soon as there is a named user or
+ // named group entry, there needs to be a mask entry as well, so add
+ // one, if the user hasn't explicitely set one.
+ if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
+ acl_calc_mask( &newACL );
+ }
+ }
+
+ if ( !allIsWell || acl_valid( newACL ) != 0 ) {
+ acl_free( newACL );
+ allIsWell = false;
+ } else {
+ acl_free( m_acl );
+ m_acl = newACL;
+ }
+ return allIsWell;
+}
+#endif
+
+bool KACL::setNamedUserPermissions( const TQString& name, unsigned short permissions )
+{
+#ifdef USE_POSIX_ACL
+ return d->setNamedUserOrGroupPermissions( name, permissions, ACL_USER );
+#else
+ Q_UNUSED( name );
+ Q_UNUSED( permissions );
+ return true;
+#endif
+}
+
+ACLUserPermissionsList KACL::allUserPermissions() const
+{
+ ACLUserPermissionsList list;
+#ifdef USE_POSIX_ACL
+ acl_entry_t entry;
+ uid_t id;
+ int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == ACL_USER ) {
+ id = *( (uid_t*) acl_get_qualifier( entry ) );
+ TQString name = d->getUserName( id );
+ unsigned short permissions = entryToPermissions( entry );
+ ACLUserPermissions pair = qMakePair( name, permissions );
+ list.append( pair );
+ }
+ ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
+ }
+#endif
+ return list;
+}
+
+#ifdef USE_POSIX_ACL
+bool KACL::KACLPrivate::setAllUsersOrGroups( const TQValueList< QPair<TQString, unsigned short> > &list, acl_tag_t type )
+{
+ bool allIsWell = true;
+ bool atLeastOneUserOrGroup = false;
+
+ // make working copy, in case something goes wrong
+ acl_t newACL = acl_dup( m_acl );
+ acl_entry_t entry;
+
+//printACL( newACL, "Before cleaning: " );
+ // clear user entries
+ int ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == type ) {
+ acl_delete_entry( newACL, entry );
+ // we have to start from the beginning, the iterator is
+ // invalidated, on deletion
+ ret = acl_get_entry( newACL, ACL_FIRST_ENTRY, &entry );
+ } else {
+ ret = acl_get_entry( newACL, ACL_NEXT_ENTRY, &entry );
+ }
+ }
+//printACL( newACL, "After cleaning out entries: " );
+
+ // now add the entries from the list
+ TQValueList< QPair<TQString, unsigned short> >::const_iterator it = list.constBegin();
+ while ( it != list.constEnd() ) {
+ acl_create_entry( &newACL, &entry );
+ acl_set_tag_type( entry, type );
+ int id = type == ACL_USER? getUidForName( (*it).first):getGidForName( (*it).first );
+ if ( id == -1 || acl_set_qualifier( entry, &id ) != 0 ) {
+ // user or group doesn't exist => error
+ acl_delete_entry( newACL, entry );
+ allIsWell = false;
+ break;
+ } else {
+ permissionsToEntry( entry, (*it).second );
+ atLeastOneUserOrGroup = true;
+ }
+ ++it;
+ }
+//printACL( newACL, "After adding entries: " );
+ if ( allIsWell && atLeastOneUserOrGroup ) {
+ // 23.1.1 of 1003.1e states that as soon as there is a named user or
+ // named group entry, there needs to be a mask entry as well, so add
+ // one, if the user hasn't explicitely set one.
+ if ( entryForTag( newACL, ACL_MASK ) == 0 ) {
+ acl_calc_mask( &newACL );
+ }
+ }
+ if ( allIsWell && ( acl_valid( newACL ) == 0 ) ) {
+ acl_free( m_acl );
+ m_acl = newACL;
+ } else {
+ acl_free( newACL );
+ }
+ return allIsWell;
+}
+#endif
+
+bool KACL::setAllUserPermissions( const ACLUserPermissionsList &users )
+{
+#ifdef USE_POSIX_ACL
+ return d->setAllUsersOrGroups( users, ACL_USER );
+#else
+ Q_UNUSED( users );
+ return true;
+#endif
+}
+
+
+/**************************
+ * Deal with named groups *
+ **************************/
+
+unsigned short KACL::namedGroupPermissions( const TQString& name, bool *exists ) const
+{
+ *exists = false;
+#ifdef USE_POSIX_ACL
+ acl_entry_t entry;
+ gid_t id;
+ int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == ACL_GROUP ) {
+ id = *( (gid_t*) acl_get_qualifier( entry ) );
+ if ( d->getGroupName( id ) == name ) {
+ *exists = true;
+ return entryToPermissions( entry );
+ }
+ }
+ ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
+ }
+#else
+ Q_UNUSED( name );
+#endif
+ return 0;
+}
+
+bool KACL::setNamedGroupPermissions( const TQString& name, unsigned short permissions )
+{
+#ifdef USE_POSIX_ACL
+ return d->setNamedUserOrGroupPermissions( name, permissions, ACL_GROUP );
+#else
+ Q_UNUSED( name );
+ Q_UNUSED( permissions );
+ return true;
+#endif
+}
+
+
+ACLGroupPermissionsList KACL::allGroupPermissions() const
+{
+ ACLGroupPermissionsList list;
+#ifdef USE_POSIX_ACL
+ acl_entry_t entry;
+ gid_t id;
+ int ret = acl_get_entry( d->m_acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_tag_t currentTag;
+ acl_get_tag_type( entry, &currentTag );
+ if ( currentTag == ACL_GROUP ) {
+ id = *( (gid_t*) acl_get_qualifier( entry ) );
+ TQString name = d->getGroupName( id );
+ unsigned short permissions = entryToPermissions( entry );
+ ACLGroupPermissions pair = qMakePair( name, permissions );
+ list.append( pair );
+ }
+ ret = acl_get_entry( d->m_acl, ACL_NEXT_ENTRY, &entry );
+ }
+#endif
+ return list;
+}
+
+bool KACL::setAllGroupPermissions( const ACLGroupPermissionsList &groups )
+{
+#ifdef USE_POSIX_ACL
+ return d->setAllUsersOrGroups( groups, ACL_GROUP );
+#else
+ Q_UNUSED( groups );
+ return true;
+#endif
+}
+
+/**************************
+ * from and to string *
+ **************************/
+
+bool KACL::setACL( const TQString &aclStr )
+{
+ bool ret = false;
+#ifdef USE_POSIX_ACL
+ if ( aclStr.isEmpty() )
+ return false;
+
+ acl_t temp = acl_from_text( aclStr.latin1() );
+ if ( acl_valid( temp ) != 0 ) {
+ // TODO errno is set, what to do with it here?
+ acl_free( temp );
+ } else {
+ if ( d->m_acl )
+ acl_free( d->m_acl );
+ d->m_acl = temp;
+ ret = true;
+ }
+#else
+ Q_UNUSED( aclStr );
+#endif
+ return ret;
+}
+
+TQString KACL::asString() const
+{
+#ifdef USE_POSIX_ACL
+ return aclAsString( d->m_acl );
+#else
+ return TQString::null;
+#endif
+}
+
+
+// helpers
+
+#ifdef USE_POSIX_ACL
+TQString KACL::KACLPrivate::getUserName( uid_t uid ) const
+{
+ TQString *temp;
+ temp = m_usercache.find( uid );
+ if ( !temp ) {
+ struct passwd *user = getpwuid( uid );
+ if ( user ) {
+ m_usercache.insert( uid, new TQString(TQString::fromLatin1(user->pw_name)) );
+ return TQString::fromLatin1( user->pw_name );
+ }
+ else
+ return TQString::number( uid );
+ }
+ else
+ return *temp;
+}
+
+
+TQString KACL::KACLPrivate::getGroupName( gid_t gid ) const
+{
+ TQString *temp;
+ temp = m_groupcache.find( gid );
+ if ( !temp ) {
+ struct group *grp = getgrgid( gid );
+ if ( grp ) {
+ m_groupcache.insert( gid, new TQString(TQString::fromLatin1(grp->gr_name)) );
+ return TQString::fromLatin1( grp->gr_name );
+ }
+ else
+ return TQString::number( gid );
+ }
+ else
+ return *temp;
+}
+
+static TQString aclAsString(const acl_t acl)
+{
+ char *aclString = acl_to_text( acl, 0 );
+ TQString ret = TQString::fromLatin1( aclString );
+ acl_free( (void*)aclString );
+ return ret;
+}
+
+
+#endif
+
+void KACL::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+TQDataStream & operator<< ( TQDataStream & s, const KACL & a )
+{
+ s << a.asString();
+ return s;
+}
+
+TQDataStream & operator>> ( TQDataStream & s, KACL & a )
+{
+ TQString str;
+ s >> str;
+ a.setACL( str );
+ return s;
+}
+
+// vim:set ts=8 sw=4:
diff --git a/tdeio/tdeio/kacl.h b/tdeio/tdeio/kacl.h
new file mode 100644
index 000000000..f581f7a8e
--- /dev/null
+++ b/tdeio/tdeio/kacl.h
@@ -0,0 +1,207 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Till Adam <adam@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 __kacl_h__
+#define __kacl_h__
+
+#include <sys/types.h>
+#include <tdeio/global.h>
+
+typedef QPair<TQString, unsigned short> ACLUserPermissions;
+typedef TQValueList<ACLUserPermissions> ACLUserPermissionsList;
+typedef TQValueListIterator<ACLUserPermissions> ACLUserPermissionsIterator;
+typedef TQValueListConstIterator<ACLUserPermissions> ACLUserPermissionsConstIterator;
+
+typedef QPair<TQString, unsigned short> ACLGroupPermissions;
+typedef TQValueList<ACLGroupPermissions> ACLGroupPermissionsList;
+typedef TQValueListIterator<ACLGroupPermissions> ACLGroupPermissionsIterator;
+typedef TQValueListConstIterator<ACLGroupPermissions> ACLGroupPermissionsConstIterator;
+
+/**
+ * The KCAL class encapsulates a POSIX Access Control List. It follows the
+ * little standard that couldn't, 1003.1e/1003.2c, which died in draft status.
+ * @short a POSIX ACL encapsulation
+ * @author Till Adam <adam@kde.org>
+ */
+class TDEIO_EXPORT KACL
+{
+public:
+ /**
+ * Creates a new KACL from @p aclString. If the string is a valid acl
+ * string, isValid() will afterwards return true.
+ */
+ KACL( const TQString & aclString );
+
+ /** Copy ctor */
+ KACL( const KACL& rhs );
+
+ /**
+ * Creates a new KACL from the basic permissions passed in @p basicPermissions.
+ * isValid() will return true, afterwards.
+ */
+ KACL( mode_t basicPermissions );
+
+ /**
+ * Creates an empty KACL. Until a valid acl string is set via setACL,
+ * isValid() will return false.
+ */
+ KACL();
+
+ virtual ~KACL();
+
+ KACL& operator=( const KACL& rhs ) {
+ if ( this != &rhs )
+ setACL( rhs.asString() );
+ return *this;
+ }
+
+ bool operator==( const KACL& rhs ) const;
+
+ bool operator!=( const KACL& rhs ) const {
+ return !operator==( rhs );
+ }
+
+ /**
+ * Returns whether the KACL object represents a valid acl.
+ * @return whether the KACL object represents a valid acl.
+ */
+ bool isValid() const;
+
+ /** The standard (non-extended) part of an ACL. These map directly to
+ * standard unix file permissions. Setting them will never make a valid
+ * ACL invalid. */
+
+ /** @return the owner's premissions entry */
+ unsigned short ownerPermissions() const;
+
+ /** Set the owner's permissions entry.
+ * @return success or failure */
+ bool setOwnerPermissions( unsigned short );
+
+ /** @return the owning group's premissions entry */
+ unsigned short owningGroupPermissions() const;
+
+ /** Set the owning group's permissions entry.
+ * @return success or failure */
+ bool setOwningGroupPermissions( unsigned short );
+
+ /** @return the premissions entry for others */
+ unsigned short othersPermissions() const;
+
+ /** Set the permissions entry for others.
+ * @return success or failure */
+ bool setOthersPermissions( unsigned short );
+
+ /** @return the basic (owner/group/others) part of the ACL as a mode_t */
+ mode_t basePermissions() const;
+
+ /** The interface to the extended ACL. This is a mask, permissions for
+ * n named users and permissions for m named groups. */
+
+ /**
+ * Return whether the ACL contains extended entries or can be expressed
+ * using only basic file permissions.
+ * @return whether the ACL contains extended entries */
+ bool isExtended() const;
+
+ /**
+ * Return the entry for the permissions mask if there is one and sets
+ * @p exists to true. If there is no such entry, @p exists is set to false.
+ * @return the permissions mask entry */
+ unsigned short maskPermissions( bool &exists ) const;
+
+ /** Set the permissions mask for the ACL. Permissions set for individual
+ * entries will be masked with this, such that their effective permissions
+ * are the result of the logical and of their entry and the mask.
+ * @return success or failure */
+ bool setMaskPermissions( unsigned short );
+
+ /**
+ * Access to the permissions entry for a named user, if such an entry
+ * exists. @p exists is set to true if a matching entry exists and
+ * to false otherwise.
+ * @return the permissions for a user entry with the name in @p name */
+ unsigned short namedUserPermissions( const TQString& name, bool *exists ) const;
+
+
+ /** Set the permissions for a user with the name @p name. Will fail
+ * if the user doesn't exist, in which case the ACL will be unchanged.
+ * @return success or failure. */
+ bool setNamedUserPermissions( const TQString& name, unsigned short );
+
+ /** Returns the list of all group permission entries. Each entry consists
+ * of a name/permissions pair. This is a QPair, therefore access is provided
+ * via the .first and .next members.
+ * @return the list of all group permission entries. */
+ ACLUserPermissionsList allUserPermissions() const;
+
+ /** Replace the list of all user permissions with @p list. If one
+ * of the entries in the list does not exists, or setting of the ACL
+ * entry fails for any reason, the ACL will be left unchanged.
+ * @return success or failure */
+ bool setAllUserPermissions( const ACLUserPermissionsList &list );
+
+ /**
+ * Access to the permissions entry for a named group, if such an entry
+ * exists. @p exists is set to true if a matching entry exists and
+ * to false otherwise.
+ * @return the permissions for a group with the name in @p name */
+ unsigned short namedGroupPermissions( const TQString& name, bool *exists ) const;
+
+ /** Set the permissions for a group with the name @p name. Will fail
+ * if the group doesn't exist, in which case the ACL be unchanged.
+ * @return success or failure. */
+ bool setNamedGroupPermissions( const TQString& name, unsigned short );
+
+ /** Returns the list of all group permission entries. Each entry consists
+ * of a name/permissions pair. This is a QPair, therefor access is provided
+ * via the .first and .next members.
+ * @return the list of all group permission entries. */
+
+ ACLGroupPermissionsList allGroupPermissions() const;
+ /** Replace the list of all user permissions with @p list. If one
+ * of the entries in the list does not exists, or setting of the ACL
+ * entry fails for any reason, the ACL will be left unchanged.
+ * @return success or failure */
+ bool setAllGroupPermissions( const ACLGroupPermissionsList & );
+
+ /** Sets the whole list from a string. If the string in @p aclStr represents
+ * a valid ACL, it will be set, otherwise the ACL remains unchanged.
+ * @return whether setting the ACL was successful. */
+ bool setACL( const TQString &aclStr );
+
+ /** Return a string representation of the ACL.
+ * @return a string version of the ACL in the format compatible with libacl and
+ * POSIX 1003.1e. Implementations conforming to that standard should be able
+ * to take such strings as input. */
+ TQString asString() const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KACLPrivate;
+ KACLPrivate * d;
+ TDEIO_EXPORT friend TQDataStream & operator<< ( TQDataStream & s, const KACL & a );
+ TDEIO_EXPORT friend TQDataStream & operator>> ( TQDataStream & s, KACL & a );
+};
+
+TDEIO_EXPORT TQDataStream & operator<< ( TQDataStream & s, const KACL & a );
+TDEIO_EXPORT TQDataStream & operator>> ( TQDataStream & s, KACL & a );
+
+#endif
diff --git a/tdeio/tdeio/kar.cpp b/tdeio/tdeio/kar.cpp
new file mode 100644
index 000000000..07072d0c6
--- /dev/null
+++ b/tdeio/tdeio/kar.cpp
@@ -0,0 +1,170 @@
+
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+
+ 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 <tqfile.h>
+#include <tqdir.h>
+#include <time.h>
+#include <kdebug.h>
+#include <tqptrlist.h>
+#include <kmimetype.h>
+#include <tqregexp.h>
+
+#include "kfilterdev.h"
+#include "kar.h"
+//#include "klimitediodevice.h"
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KAr ///////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KAr::KArPrivate
+{
+public:
+ KArPrivate() {}
+};
+
+KAr::KAr( const TQString& filename )
+ : KArchive( 0L )
+{
+ //kdDebug(7042) << "KAr(filename) reached." << endl;
+ m_filename = filename;
+ d = new KArPrivate;
+ setDevice( TQT_TQIODEVICE(new TQFile( filename )) );
+}
+
+KAr::KAr( TQIODevice * dev )
+ : KArchive( dev )
+{
+ //kdDebug(7042) << "KAr::KAr( TQIODevice * dev) reached." << endl;
+ d = new KArPrivate;
+}
+
+KAr::~KAr()
+{
+ // mjarrett: Closes to prevent ~KArchive from aborting w/o device
+ //kdDebug(7042) << "~KAr reached." << endl;
+ if( isOpened() )
+ close();
+ if ( !m_filename.isEmpty() )
+ delete device(); // we created it ourselves
+ delete d;
+}
+
+bool KAr::openArchive( int mode )
+{
+ // Open archive
+
+ //kdDebug(7042) << "openarchive reached." << endl;
+
+ if ( mode == IO_WriteOnly )
+ return true;
+ if ( mode != IO_ReadOnly && mode != IO_ReadWrite )
+ {
+ kdWarning(7042) << "Unsupported mode " << mode << endl;
+ return false;
+ }
+
+ TQIODevice* dev = device();
+ if ( !dev )
+ return false;
+
+ char magic[8];
+ dev->readBlock (magic, 8);
+ if (tqstrncmp(magic, "!<arch>", 7) != 0) {
+ kdWarning(7042) << "Invalid main magic" << endl;
+ return false;
+ }
+
+ char *ar_longnames = 0;
+ while (! dev->atEnd()) {
+ TQCString ar_header;
+ ar_header.resize(61);
+ TQCString name;
+ int date, uid, gid, mode, size;
+
+ dev->at( dev->at() + (2 - (dev->at() % 2)) % 2 ); // Ar headers are padded to byte boundary
+
+ if ( dev->readBlock (ar_header.data(), 60) != 60 ) { // Read ar header
+ kdWarning(7042) << "Couldn't read header" << endl;
+ delete[] ar_longnames;
+ //return false;
+ return true; // Probably EOF / trailing junk
+ }
+
+ if (ar_header.right(2) != "`\n") { // Check header magic
+ kdWarning(7042) << "Invalid magic" << endl;
+ delete[] ar_longnames;
+ return false;
+ }
+
+ name = ar_header.mid( 0, 16 ); // Process header
+ date = ar_header.mid( 16, 12 ).toInt();
+ uid = ar_header.mid( 28, 6 ).toInt();
+ gid = ar_header.mid( 34, 6 ).toInt();
+ mode = ar_header.mid( 40, 8 ).toInt();
+ size = ar_header.mid( 48, 10 ).toInt();
+
+ bool skip_entry = false; // Deal with special entries
+ if (name.mid(0, 1) == "/") {
+ if (name.mid(1, 1) == "/") { // Longfilename table entry
+ delete[] ar_longnames;
+ ar_longnames = new char[size + 1];
+ ar_longnames[size] = '\0';
+ dev->readBlock (ar_longnames, size);
+ skip_entry = true;
+ kdDebug(7042) << "Read in longnames entry" << endl;
+ } else if (name.mid(1, 1) == " ") { // Symbol table entry
+ kdDebug(7042) << "Skipped symbol entry" << endl;
+ dev->at( dev->at() + size );
+ skip_entry = true;
+ } else { // Longfilename
+ kdDebug(7042) << "Longfilename #" << name.mid(1, 15).toInt() << endl;
+ if (! ar_longnames) {
+ kdWarning(7042) << "Invalid longfilename reference" << endl;
+ return false;
+ }
+ name = &ar_longnames[name.mid(1, 15).toInt()];
+ name = name.left(name.find("/"));
+ }
+ }
+ if (skip_entry) continue;
+
+ name = name.stripWhiteSpace(); // Process filename
+ name.replace( "/", "" );
+ kdDebug(7042) << "Filename: " << name << " Size: " << size << endl;
+
+ KArchiveEntry* entry;
+ entry = new KArchiveFile(this, name, mode, date, /*uid*/ 0, /*gid*/ 0, 0, dev->at(), size);
+ rootDir()->addEntry(entry); // Ar files don't support directorys, so everything in root
+
+ dev->at( dev->at() + size ); // Skip contents
+ }
+ delete[] ar_longnames;
+
+ return true;
+}
+
+bool KAr::closeArchive()
+{
+ // Close the archive
+ return true;
+}
+
+void KAr::virtual_hook( int id, void* data )
+{ KArchive::virtual_hook( id, data ); }
diff --git a/tdeio/tdeio/kar.h b/tdeio/tdeio/kar.h
new file mode 100644
index 000000000..83d94e75c
--- /dev/null
+++ b/tdeio/tdeio/kar.h
@@ -0,0 +1,103 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+
+ 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 __kar_h
+#define __kar_h
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdict.h>
+
+#include <karchive.h>
+
+/**
+ * KAr is a class for reading archives in ar format. Writing
+ * is not supported.
+ * @short A class for reading ar archives.
+ * @author Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ * @since 3.1
+ */
+class TDEIO_EXPORT KAr : public KArchive
+{
+public:
+ /**
+ * Creates an instance that operates on the given filename.
+ *
+ * @param filename is a local path (e.g. "/home/holger/myfile.ar")
+ */
+ KAr( const TQString& filename );
+
+ /**
+ * Creates an instance that operates on the given device.
+ * The device can be compressed (KFilterDev) or not (TQFile, etc.).
+ * @param dev the device to read from
+ */
+ KAr( TQIODevice * dev );
+
+ /**
+ * If the ar file is still opened, then it will be
+ * closed automatically by the destructor.
+ */
+ virtual ~KAr();
+
+ /**
+ * The name of the ar file, as passed to the constructor.
+ * @return the filename. Null if you used the TQIODevice constructor
+ */
+ TQString fileName() { return m_filename; }
+
+ /*
+ * Writing not supported by this class, will always fail.
+ * @return always false
+ */
+ virtual bool prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size ) { Q_UNUSED(name); Q_UNUSED(user); Q_UNUSED(group); Q_UNUSED(size); return false; }
+
+ /*
+ * Writing not supported by this class, will always fail.
+ * @return always false
+ */
+ virtual bool doneWriting( uint size ) { Q_UNUSED(size); return false; }
+
+ /*
+ * Writing not supported by this class, will always fail.
+ * @return always false
+ */
+ virtual bool writeDir( const TQString& name, const TQString& user, const TQString& group ) { Q_UNUSED(name); Q_UNUSED(user); Q_UNUSED(group); return false; }
+
+protected:
+ /**
+ * Opens the archive for reading.
+ * Parses the directory listing of the archive
+ * and creates the KArchiveDirectory/KArchiveFile entries.
+ *
+ */
+ virtual bool openArchive( int mode );
+ virtual bool closeArchive();
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ TQString m_filename;
+ class KArPrivate;
+ KArPrivate * d;
+};
+
+#endif
diff --git a/tdeio/tdeio/karchive.cpp b/tdeio/tdeio/karchive.cpp
new file mode 100644
index 000000000..0e8d6789d
--- /dev/null
+++ b/tdeio/tdeio/karchive.cpp
@@ -0,0 +1,717 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
+
+ Moved from ktar.cpp by Roberto Teixeira <maragato@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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <tqptrlist.h>
+#include <tqptrstack.h>
+#include <tqvaluestack.h>
+#include <tqmap.h>
+#include <tqcstring.h>
+#include <tqdir.h>
+#include <tqfile.h>
+
+#include <kdebug.h>
+#include <kfilterdev.h>
+#include <kfilterbase.h>
+#include <kde_file.h>
+
+#include "karchive.h"
+#include "klimitediodevice.h"
+
+template class TQDict<KArchiveEntry>;
+
+
+class KArchive::KArchivePrivate
+{
+public:
+ KArchiveDirectory* rootDir;
+ bool closeSucceeded;
+};
+
+class PosSortedPtrList : public TQPtrList<KArchiveFile> {
+protected:
+ int compareItems( TQPtrCollection::Item i1,
+ TQPtrCollection::Item i2 )
+ {
+ int pos1 = static_cast<KArchiveFile*>( i1 )->position();
+ int pos2 = static_cast<KArchiveFile*>( i2 )->position();
+ return ( pos1 - pos2 );
+ }
+};
+
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KArchive ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+KArchive::KArchive( TQIODevice * dev )
+{
+ d = new KArchivePrivate;
+ d->rootDir = 0;
+ m_dev = dev;
+ m_open = false;
+}
+
+KArchive::~KArchive()
+{
+ if ( m_open )
+ close();
+ delete d->rootDir;
+ delete d;
+}
+
+bool KArchive::open( int mode )
+{
+ if ( m_dev && !m_dev->open( mode ) )
+ return false;
+
+ if ( m_open )
+ close();
+
+ m_mode = mode;
+ m_open = true;
+
+ Q_ASSERT( d->rootDir == 0L );
+ d->rootDir = 0L;
+
+ return openArchive( mode );
+}
+
+void KArchive::close()
+{
+ if ( !m_open )
+ return;
+ // moved by holger to allow kzip to write the zip central dir
+ // to the file in closeArchive()
+ d->closeSucceeded = closeArchive();
+
+ if ( m_dev )
+ m_dev->close();
+
+ delete d->rootDir;
+ d->rootDir = 0;
+ m_open = false;
+}
+
+bool KArchive::closeSucceeded() const
+{
+ return d->closeSucceeded;
+}
+
+const KArchiveDirectory* KArchive::directory() const
+{
+ // rootDir isn't const so that parsing-on-demand is possible
+ return const_cast<KArchive *>(this)->rootDir();
+}
+
+
+bool KArchive::addLocalFile( const TQString& fileName, const TQString& destName )
+{
+ TQFileInfo fileInfo( fileName );
+ if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
+ {
+ kdWarning() << "KArchive::addLocalFile " << fileName << " doesn't exist or is not a regular file." << endl;
+ return false;
+ }
+
+ KDE_struct_stat fi;
+ if (KDE_lstat(TQFile::encodeName(fileName),&fi) == -1) {
+ kdWarning() << "KArchive::addLocalFile stating " << fileName
+ << " failed: " << strerror(errno) << endl;
+ return false;
+ }
+
+ if (fileInfo.isSymLink()) {
+ return writeSymLink(destName, fileInfo.readLink(), fileInfo.owner(),
+ fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
+ fi.st_ctime);
+ }/*end if*/
+
+ uint size = fileInfo.size();
+
+ // the file must be opened before prepareWriting is called, otherwise
+ // if the opening fails, no content will follow the already written
+ // header and the tar file is effectively f*cked up
+ TQFile file( fileName );
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ kdWarning() << "KArchive::addLocalFile couldn't open file " << fileName << endl;
+ return false;
+ }
+
+ if ( !prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
+ fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
+ {
+ kdWarning() << "KArchive::addLocalFile prepareWriting " << destName << " failed" << endl;
+ return false;
+ }
+
+ // Read and write data in chunks to minimize memory usage
+ TQByteArray array(8*1024);
+ int n;
+ uint total = 0;
+ while ( ( n = file.readBlock( array.data(), array.size() ) ) > 0 )
+ {
+ if ( !writeData( array.data(), n ) )
+ {
+ kdWarning() << "KArchive::addLocalFile writeData failed" << endl;
+ return false;
+ }
+ total += n;
+ }
+ Q_ASSERT( total == size );
+
+ if ( !doneWriting( size ) )
+ {
+ kdWarning() << "KArchive::addLocalFile doneWriting failed" << endl;
+ return false;
+ }
+ return true;
+}
+
+bool KArchive::addLocalDirectory( const TQString& path, const TQString& destName )
+{
+ TQString dot = ".";
+ TQString dotdot = "..";
+ TQDir dir( path );
+ if ( !dir.exists() )
+ return false;
+ dir.setFilter(dir.filter() | TQDir::Hidden);
+ TQStringList files = dir.entryList();
+ for ( TQStringList::Iterator it = files.begin(); it != files.end(); ++it )
+ {
+ if ( *it != dot && *it != dotdot )
+ {
+ TQString fileName = path + "/" + *it;
+// kdDebug() << "storing " << fileName << endl;
+ TQString dest = destName.isEmpty() ? *it : (destName + "/" + *it);
+ TQFileInfo fileInfo( fileName );
+
+ if ( fileInfo.isFile() || fileInfo.isSymLink() )
+ addLocalFile( fileName, dest );
+ else if ( fileInfo.isDir() )
+ addLocalDirectory( fileName, dest );
+ // We omit sockets
+ }
+ }
+ return true;
+}
+
+bool KArchive::writeFile( const TQString& name, const TQString& user, const TQString& group, uint size, const char* data )
+{
+ mode_t perm = 0100644;
+ time_t the_time = time(0);
+ return writeFile(name,user,group,size,perm,the_time,the_time,the_time,data);
+}
+
+bool KArchive::prepareWriting( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime ) {
+ PrepareWritingParams params;
+ params.name = &name;
+ params.user = &user;
+ params.group = &group;
+ params.size = size;
+ params.perm = perm;
+ params.atime = atime;
+ params.mtime = mtime;
+ params.ctime = ctime;
+ virtual_hook(VIRTUAL_PREPARE_WRITING,&params);
+ return params.retval;
+}
+
+bool KArchive::prepareWriting_impl(const TQString &name, const TQString &user,
+ const TQString &group, uint size, mode_t /*perm*/,
+ time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
+ kdWarning(7040) << "New prepareWriting API not implemented in this class." << endl
+ << "Falling back to old API (metadata information will be lost)" << endl;
+ return prepareWriting(name,user,group,size);
+}
+
+bool KArchive::writeFile( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime,
+ const char* data ) {
+ WriteFileParams params;
+ params.name = &name;
+ params.user = &user;
+ params.group = &group;
+ params.size = size;
+ params.perm = perm;
+ params.atime = atime;
+ params.mtime = mtime;
+ params.ctime = ctime;
+ params.data = data;
+ virtual_hook(VIRTUAL_WRITE_FILE,&params);
+ return params.retval;
+}
+
+bool KArchive::writeFile_impl( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime,
+ const char* data ) {
+
+ if ( !prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
+ {
+ kdWarning() << "KArchive::writeFile prepareWriting failed" << endl;
+ return false;
+ }
+
+ // Write data
+ // Note: if data is 0L, don't call writeBlock, it would terminate the KFilterDev
+ if ( data && size && !writeData( data, size ) )
+ {
+ kdWarning() << "KArchive::writeFile writeData failed" << endl;
+ return false;
+ }
+
+ if ( !doneWriting( size ) )
+ {
+ kdWarning() << "KArchive::writeFile doneWriting failed" << endl;
+ return false;
+ }
+ return true;
+}
+
+bool KArchive::writeDir(const TQString& name, const TQString& user,
+ const TQString& group, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime) {
+ WriteDirParams params;
+ params.name = &name;
+ params.user = &user;
+ params.group = &group;
+ params.perm = perm;
+ params.atime = atime;
+ params.mtime = mtime;
+ params.ctime = ctime;
+ virtual_hook(VIRTUAL_WRITE_DIR,&params);
+ return params.retval;
+}
+
+bool KArchive::writeDir_impl(const TQString &name, const TQString &user,
+ const TQString &group, mode_t /*perm*/,
+ time_t /*atime*/, time_t /*mtime*/, time_t /*ctime*/ ) {
+ kdWarning(7040) << "New writeDir API not implemented in this class." << endl
+ << "Falling back to old API (metadata information will be lost)" << endl;
+ return writeDir(name,user,group);
+}
+
+bool KArchive::writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime) {
+ WriteSymlinkParams params;
+ params.name = &name;
+ params.target = &target;
+ params.user = &user;
+ params.group = &group;
+ params.perm = perm;
+ params.atime = atime;
+ params.mtime = mtime;
+ params.ctime = ctime;
+ virtual_hook(VIRTUAL_WRITE_SYMLINK,&params);
+ return params.retval;
+}
+
+bool KArchive::writeSymLink_impl(const TQString &/*name*/,const TQString &/*target*/,
+ const TQString &/*user*/, const TQString &/*group*/,
+ mode_t /*perm*/, time_t /*atime*/, time_t /*mtime*/,
+ time_t /*ctime*/) {
+ kdWarning(7040) << "writeSymLink not implemented in this class." << endl
+ << "No fallback available." << endl;
+ // FIXME: better return true here for compatibility with KDE < 3.2
+ return false;
+}
+
+bool KArchive::writeData( const char* data, uint size )
+{
+ WriteDataParams params;
+ params.data = data;
+ params.size = size;
+ virtual_hook( VIRTUAL_WRITE_DATA, &params );
+ return params.retval;
+}
+
+bool KArchive::writeData_impl( const char* data, uint size )
+{
+ Q_ASSERT( device() );
+ return device()->writeBlock( data, size ) == (TQ_LONG)size;
+}
+
+KArchiveDirectory * KArchive::rootDir()
+{
+ if ( !d->rootDir )
+ {
+ //kdDebug() << "Making root dir " << endl;
+ struct passwd* pw = getpwuid( getuid() );
+ struct group* grp = getgrgid( getgid() );
+ TQString username = pw ? TQFile::decodeName(pw->pw_name) : TQString::number( getuid() );
+ TQString groupname = grp ? TQFile::decodeName(grp->gr_name) : TQString::number( getgid() );
+
+ d->rootDir = new KArchiveDirectory( this, TQString::fromLatin1("/"), (int)(0777 + S_IFDIR), 0, username, groupname, TQString::null );
+ }
+ return d->rootDir;
+}
+
+KArchiveDirectory * KArchive::findOrCreate( const TQString & path )
+{
+ //kdDebug() << "KArchive::findOrCreate " << path << endl;
+ if ( path.isEmpty() || path == "/" || path == "." ) // root dir => found
+ {
+ //kdDebug() << "KArchive::findOrCreate returning rootdir" << endl;
+ return rootDir();
+ }
+ // Important note : for tar files containing absolute paths
+ // (i.e. beginning with "/"), this means the leading "/" will
+ // be removed (no KDirectory for it), which is exactly the way
+ // the "tar" program works (though it displays a warning about it)
+ // See also KArchiveDirectory::entry().
+
+ // Already created ? => found
+ KArchiveEntry* ent = rootDir()->entry( path );
+ if ( ent )
+ {
+ if ( ent->isDirectory() )
+ //kdDebug() << "KArchive::findOrCreate found it" << endl;
+ return (KArchiveDirectory *) ent;
+ else
+ kdWarning() << "Found " << path << " but it's not a directory" << endl;
+ }
+
+ // Otherwise go up and try again
+ int pos = path.findRev( '/' );
+ KArchiveDirectory * parent;
+ TQString dirname;
+ if ( pos == -1 ) // no more slash => create in root dir
+ {
+ parent = rootDir();
+ dirname = path;
+ }
+ else
+ {
+ TQString left = path.left( pos );
+ dirname = path.mid( pos + 1 );
+ parent = findOrCreate( left ); // recursive call... until we find an existing dir.
+ }
+
+ //kdDebug() << "KTar : found parent " << parent->name() << " adding " << dirname << " to ensure " << path << endl;
+ // Found -> add the missing piece
+ KArchiveDirectory * e = new KArchiveDirectory( this, dirname, d->rootDir->permissions(),
+ d->rootDir->date(), d->rootDir->user(),
+ d->rootDir->group(), TQString::null );
+ parent->addEntry( e );
+ return e; // now a directory to <path> exists
+}
+
+void KArchive::setDevice( TQIODevice * dev )
+{
+ m_dev = dev;
+}
+
+void KArchive::setRootDir( KArchiveDirectory *rootDir )
+{
+ Q_ASSERT( !d->rootDir ); // Call setRootDir only once during parsing please ;)
+ d->rootDir = rootDir;
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////// KArchiveEntry //////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+KArchiveEntry::KArchiveEntry( KArchive* t, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group, const
+ TQString& symlink)
+{
+ m_name = name;
+ m_access = access;
+ m_date = date;
+ m_user = user;
+ m_group = group;
+ m_symlink = symlink;
+ m_archive = t;
+
+}
+
+TQDateTime KArchiveEntry::datetime() const
+{
+ TQDateTime d;
+ d.setTime_t( m_date );
+ return d;
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////// KArchiveFile ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+KArchiveFile::KArchiveFile( KArchive* t, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group,
+ const TQString & symlink,
+ int pos, int size )
+ : KArchiveEntry( t, name, access, date, user, group, symlink )
+{
+ m_pos = pos;
+ m_size = size;
+}
+
+int KArchiveFile::position() const
+{
+ return m_pos;
+}
+
+int KArchiveFile::size() const
+{
+ return m_size;
+}
+
+TQByteArray KArchiveFile::data() const
+{
+ archive()->device()->at( m_pos );
+
+ // Read content
+ TQByteArray arr( m_size );
+ if ( m_size )
+ {
+ assert( arr.data() );
+ int n = archive()->device()->readBlock( arr.data(), m_size );
+ if ( n != m_size )
+ arr.resize( n );
+ }
+ return arr;
+}
+
+// ** This should be a virtual method, and this code should be in ktar.cpp
+TQIODevice *KArchiveFile::device() const
+{
+ return new KLimitedIODevice( archive()->device(), m_pos, m_size );
+}
+
+void KArchiveFile::copyTo(const TQString& dest) const
+{
+ TQFile f( dest + "/" + name() );
+ f.open( IO_ReadWrite | IO_Truncate );
+ f.writeBlock( data() );
+ f.close();
+}
+
+////////////////////////////////////////////////////////////////////////
+//////////////////////// KArchiveDirectory /////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+
+KArchiveDirectory::KArchiveDirectory( KArchive* t, const TQString& name, int access,
+ int date,
+ const TQString& user, const TQString& group,
+ const TQString &symlink)
+ : KArchiveEntry( t, name, access, date, user, group, symlink )
+{
+ m_entries.setAutoDelete( true );
+}
+
+TQStringList KArchiveDirectory::entries() const
+{
+ TQStringList l;
+
+ TQDictIterator<KArchiveEntry> it( m_entries );
+ for( ; it.current(); ++it )
+ l.append( it.currentKey() );
+
+ return l;
+}
+
+KArchiveEntry* KArchiveDirectory::entry( TQString name )
+ // not "const TQString & name" since we want a local copy
+ // (to remove leading slash if any)
+{
+ int pos = name.find( '/' );
+ if ( pos == 0 ) // ouch absolute path (see also KArchive::findOrCreate)
+ {
+ if (name.length()>1)
+ {
+ name = name.mid( 1 ); // remove leading slash
+ pos = name.find( '/' ); // look again
+ }
+ else // "/"
+ return this;
+ }
+ // trailing slash ? -> remove
+ if ( pos != -1 && pos == (int)name.length()-1 )
+ {
+ name = name.left( pos );
+ pos = name.find( '/' ); // look again
+ }
+ if ( pos != -1 )
+ {
+ TQString left = name.left( pos );
+ TQString right = name.mid( pos + 1 );
+
+ //kdDebug() << "KArchiveDirectory::entry left=" << left << " right=" << right << endl;
+
+ KArchiveEntry* e = m_entries[ left ];
+ if ( !e || !e->isDirectory() )
+ return 0;
+ return ((KArchiveDirectory*)e)->entry( right );
+ }
+
+ return m_entries[ name ];
+}
+
+const KArchiveEntry* KArchiveDirectory::entry( TQString name ) const
+{
+ return ((KArchiveDirectory*)this)->entry( name );
+}
+
+void KArchiveDirectory::addEntry( KArchiveEntry* entry )
+{
+ Q_ASSERT( !entry->name().isEmpty() );
+ if( m_entries[ entry->name() ] ) {
+ kdWarning() << "KArchiveDirectory::addEntry: directory " << name()
+ << " has entry " << entry->name() << " already" << endl;
+ }
+ m_entries.insert( entry->name(), entry );
+}
+
+void KArchiveDirectory::copyTo(const TQString& dest, bool recursiveCopy ) const
+{
+ TQDir root;
+
+ PosSortedPtrList fileList;
+ TQMap<int, TQString> fileToDir;
+
+ TQStringList::Iterator it;
+
+ // placeholders for iterated items
+ KArchiveDirectory* curDir;
+ TQString curDirName;
+
+ TQStringList dirEntries;
+ KArchiveEntry* curEntry;
+ KArchiveFile* curFile;
+
+
+ TQPtrStack<KArchiveDirectory> dirStack;
+ TQValueStack<TQString> dirNameStack;
+
+ dirStack.push( this ); // init stack at current directory
+ dirNameStack.push( dest ); // ... with given path
+ do {
+ curDir = dirStack.pop();
+ curDirName = dirNameStack.pop();
+ root.mkdir(curDirName);
+
+ dirEntries = curDir->entries();
+ for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
+ curEntry = curDir->entry(*it);
+ if (!curEntry->symlink().isEmpty()) {
+ const TQString linkName = curDirName+'/'+curEntry->name();
+ kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ')';
+#ifdef Q_OS_UNIX
+ if (!::symlink(curEntry->symlink().local8Bit(), linkName.local8Bit())) {
+ kdDebug() << "symlink(" << curEntry->symlink() << ',' << linkName << ") failed:" << strerror(errno);
+ }
+#endif
+ } else {
+ if ( curEntry->isFile() ) {
+ curFile = dynamic_cast<KArchiveFile*>( curEntry );
+ if (curFile) {
+ fileList.append( curFile );
+ fileToDir.insert( curFile->position(), curDirName );
+ }
+ }
+
+ if ( curEntry->isDirectory() )
+ if ( recursiveCopy ) {
+ KArchiveDirectory *ad = dynamic_cast<KArchiveDirectory*>( curEntry );
+ if (ad) {
+ dirStack.push( ad );
+ dirNameStack.push( curDirName + "/" + curEntry->name() );
+ }
+ }
+ }
+ }
+ } while (!dirStack.isEmpty());
+
+ fileList.sort(); // sort on m_pos, so we have a linear access
+
+ KArchiveFile* f;
+ for ( f = fileList.first(); f; f = fileList.next() ) {
+ int pos = f->position();
+ f->copyTo( fileToDir[pos] );
+ }
+}
+
+void KArchive::virtual_hook( int id, void* data )
+{
+ switch (id) {
+ case VIRTUAL_WRITE_DATA: {
+ WriteDataParams* params = reinterpret_cast<WriteDataParams *>(data);
+ params->retval = writeData_impl( params->data, params->size );
+ break;
+ }
+ case VIRTUAL_WRITE_SYMLINK: {
+ WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
+ params->retval = writeSymLink_impl(*params->name,*params->target,
+ *params->user,*params->group,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ case VIRTUAL_WRITE_DIR: {
+ WriteDirParams *params = reinterpret_cast<WriteDirParams *>(data);
+ params->retval = writeDir_impl(*params->name,*params->user,
+ *params->group,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ case VIRTUAL_WRITE_FILE: {
+ WriteFileParams *params = reinterpret_cast<WriteFileParams *>(data);
+ params->retval = writeFile_impl(*params->name,*params->user,
+ *params->group,params->size,params->perm,
+ params->atime,params->mtime,params->ctime,
+ params->data);
+ break;
+ }
+ case VIRTUAL_PREPARE_WRITING: {
+ PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
+ params->retval = prepareWriting_impl(*params->name,*params->user,
+ *params->group,params->size,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ default:
+ /*BASE::virtual_hook( id, data )*/;
+ }/*end switch*/
+}
+
+void KArchiveEntry::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KArchiveFile::virtual_hook( int id, void* data )
+{ KArchiveEntry::virtual_hook( id, data ); }
+
+void KArchiveDirectory::virtual_hook( int id, void* data )
+{ KArchiveEntry::virtual_hook( id, data ); }
diff --git a/tdeio/tdeio/karchive.h b/tdeio/tdeio/karchive.h
new file mode 100644
index 000000000..840c560b7
--- /dev/null
+++ b/tdeio/tdeio/karchive.h
@@ -0,0 +1,639 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
+
+ Moved from ktar.h by Roberto Teixeira <maragato@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 __karchive_h
+#define __karchive_h
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdict.h>
+
+#include <tdelibs_export.h>
+
+class KArchiveDirectory;
+class KArchiveFile;
+
+/**
+ * KArchive is a base class for reading and writing archives.
+ * @short generic class for reading/writing archives
+ * @author David Faure <faure@kde.org>
+ */
+class TDEIO_EXPORT KArchive
+{
+protected:
+ /**
+ * Base constructor (protected since this is a pure virtual class).
+ * @param dev the I/O device where the archive reads its data
+ * Note that this can be a file, but also a data buffer, a compression filter, etc.
+ */
+ KArchive( TQIODevice * dev );
+
+public:
+ virtual ~KArchive();
+
+ /**
+ * Opens the archive for reading or writing.
+ * Inherited classes might want to reimplement openArchive instead.
+ * @param mode may be IO_ReadOnly or IO_WriteOnly
+ * @see close
+ */
+ virtual bool open( int mode );
+
+ /**
+ * Closes the archive.
+ * Inherited classes might want to reimplement closeArchive instead.
+ *
+ * @see open
+ */
+ virtual void close();
+
+ /**
+ * Use to check if close had any problem
+ * @return true if close succeded without problems
+ * @since 3.5
+ */
+ // TODO KDE4 merge with above
+ bool closeSucceeded() const;
+
+ /**
+ * Checks whether the archive is open.
+ * @return true if the archive is opened
+ */
+ bool isOpened() const { return m_open; }
+
+ /**
+ * Returns the mode in which the archive was opened
+ * @return the mode in which the archive was opened (IO_ReadOnly or IO_WriteOnly)
+ * @see open()
+ */
+ int mode() const { return m_mode; }
+
+ /**
+ * The underlying device.
+ * @return the underlying device.
+ */
+ TQIODevice * device() const { return m_dev; }
+
+ /**
+ * If an archive is opened for reading, then the contents
+ * of the archive can be accessed via this function.
+ * @return the directory of the archive
+ */
+ const KArchiveDirectory* directory() const;
+
+ /**
+ * Writes a local file into the archive. The main difference with writeFile,
+ * is that this method minimizes memory usage, by not loading the whole file
+ * into memory in one go.
+ *
+ * If @p fileName is a symbolic link, it will be written as is, i. e.
+ * it will not be resolved before.
+ * @param fileName full path to an existing local file, to be added to the archive.
+ * @param destName the resulting name (or relative path) of the file in the archive.
+ */
+ bool addLocalFile( const TQString& fileName, const TQString& destName );
+
+ /**
+ * Writes a local directory into the archive, including all its contents, recursively.
+ * Calls addLocalFile for each file to be added.
+ *
+ * Since KDE 3.2 it will also add a @p path that is a symbolic link to a
+ * directory. The symbolic link will be dereferenced and the content of the
+ * directory it is pointing to added recursively. However, symbolic links
+ * *under* @p path will be stored as is.
+ * @param path full path to an existing local directory, to be added to the archive.
+ * @param destName the resulting name (or relative path) of the file in the archive.
+ */
+ bool addLocalDirectory( const TQString& path, const TQString& destName );
+
+ /**
+ * If an archive is opened for writing then you can add new directories
+ * using this function. KArchive won't write one directory twice.
+ *
+ * @param name the name of the directory
+ * @param user the user that owns the directory
+ * @param group the group that owns the directory
+ *
+ * @todo TODO(BIC): make this a thin wrapper around
+ * writeDir(name,user,group,perm,atime,mtime,ctime)
+ * or eliminate it
+ */
+ virtual bool writeDir( const TQString& name, const TQString& user, const TQString& group ) = 0;
+
+ /**
+ * If an archive is opened for writing then you can add new directories
+ * using this function. KArchive won't write one directory twice.
+ *
+ * This method also allows some file metadata to be
+ * set. However, depending on the archive type not all metadata might be
+ * regarded.
+ * @param name the name of the directory
+ * @param user the user that owns the directory
+ * @param group the group that owns the directory
+ * @param perm permissions of the directory
+ * @param atime time the file was last accessed
+ * @param mtime modification time of the file
+ * @param ctime creation time of the file
+ * @since 3.2
+ * @todo TODO(BIC): make this virtual. For now use virtual hook
+ */
+ bool writeDir( const TQString& name, const TQString& user, const TQString& group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime );
+
+ /**
+ * Writes a symbolic link to the archive if the archive must be opened for
+ * writing.
+ * @param name name of symbolic link
+ * @param target target of symbolic link
+ * @param user the user that owns the directory
+ * @param group the group that owns the directory
+ * @param perm permissions of the directory
+ * @param atime time the file was last accessed
+ * @param mtime modification time of the file
+ * @param ctime creation time of the file
+ * @since 3.2
+ * @todo TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ */
+ bool writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+
+ /**
+ * If an archive is opened for writing then you can add a new file
+ * using this function. If the file name is for example "mydir/test1" then
+ * the directory "mydir" is automatically appended first if that did not
+ * happen yet.
+ * @param name the name of the file
+ * @param user the user that owns the file
+ * @param group the group that owns the file
+ * @param size the size of the file
+ * @param data the data to write (@p size bytes)
+ * @todo TODO(BIC): make this a thin non-virtual wrapper around
+ * writeFile(name,user,group,size,perm,atime,mtime,ctime,data)
+ */
+ virtual bool writeFile( const TQString& name, const TQString& user, const TQString& group, uint size, const char* data );
+
+ /**
+ * If an archive is opened for writing then you can add a new file
+ * using this function. If the file name is for example "mydir/test1" then
+ * the directory "mydir" is automatically appended first if that did not
+ * happen yet.
+ *
+ * This method also allows some file metadata to be
+ * set. However, depending on the archive type not all metadata might be
+ * regarded.
+ * @param name the name of the file
+ * @param user the user that owns the file
+ * @param group the group that owns the file
+ * @param size the size of the file
+ * @param perm permissions of the file
+ * @param atime time the file was last accessed
+ * @param mtime modification time of the file
+ * @param ctime creation time of the file
+ * @param data the data to write (@p size bytes)
+ * @since 3.2
+ * @todo TODO(BIC): make virtual. For now use virtual hook
+ */
+ bool writeFile( const TQString& name, const TQString& user, const TQString& group,
+ uint size, mode_t perm, time_t atime, time_t mtime,
+ time_t ctime, const char* data );
+
+ /**
+ * Here's another way of writing a file into an archive:
+ * Call prepareWriting, then call writeData()
+ * as many times as wanted then call doneWriting( totalSize ).
+ * For tar.gz files, you need to know the size before hand, since it is needed in the header.
+ * For zip files, size isn't used.
+ *
+ * @param name the name of the file
+ * @param user the user that owns the file
+ * @param group the group that owns the file
+ * @param size the size of the file
+ *
+ * @todo TODO(BIC): make this a thin non-virtual wrapper around
+ * prepareWriting(name,user,group,size,perm,atime,mtime,ctime)
+ * or eliminate it.
+ */
+ virtual bool prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size ) = 0;
+
+ /**
+ * Here's another way of writing a file into an archive:
+ * Call prepareWriting, then call writeData()
+ * as many times as wanted then call doneWriting( totalSize ).
+ * For tar.gz files, you need to know the size before hand, it is needed in the header!
+ * For zip files, size isn't used.
+ *
+ * This method also allows some file metadata to be
+ * set. However, depending on the archive type not all metadata might be
+ * regarded.
+ * @param name the name of the file
+ * @param user the user that owns the file
+ * @param group the group that owns the file
+ * @param size the size of the file
+ * @param perm permissions of the file
+ * @param atime time the file was last accessed
+ * @param mtime modification time of the file
+ * @param ctime creation time of the file
+ * @since 3.2
+ * @todo TODO(BIC): make this virtual. For now use virtual hook.
+ */
+ bool prepareWriting( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime );
+
+ /**
+ * Write data into the current file - to be called after calling prepareWriting
+ * @todo TODO(BIC) make virtual. For now virtual_hook allows reimplementing it.
+ */
+ bool writeData( const char* data, uint size );
+
+ /**
+ * Call doneWriting after writing the data.
+ * @param size the size of the file
+ * @see prepareWriting()
+ */
+ virtual bool doneWriting( uint size ) = 0;
+
+protected:
+ /**
+ * Opens an archive for reading or writing.
+ * Called by open.
+ * @param mode may be IO_ReadOnly or IO_WriteOnly
+ */
+ virtual bool openArchive( int mode ) = 0;
+
+ /**
+ * Closes the archive.
+ * Called by close.
+ */
+ virtual bool closeArchive() = 0;
+
+ /**
+ * Retrieves or create the root directory.
+ * The default implementation assumes that openArchive() did the parsing,
+ * so it creates a dummy rootdir if none was set (write mode, or no '/' in the archive).
+ * Reimplement this to provide parsing/listing on demand.
+ * @return the root directory
+ */
+ virtual KArchiveDirectory* rootDir();
+
+ /**
+ * Ensures that @p path exists, create otherwise.
+ * This handles e.g. tar files missing directory entries, like mico-2.3.0.tar.gz :)
+ * @param path the path of the directory
+ * @return the directory with the given @p path
+ */
+ KArchiveDirectory * findOrCreate( const TQString & path );
+
+ /**
+ * @internal for inherited constructors
+ */
+ void setDevice( TQIODevice *dev );
+
+ /**
+ * @internal for inherited classes
+ */
+ void setRootDir( KArchiveDirectory *rootDir );
+
+private:
+ TQIODevice * m_dev;
+ bool m_open;
+ char m_mode;
+protected:
+ virtual void virtual_hook( int id, void* data );
+ /* @internal for virtual_hook */
+ enum { VIRTUAL_WRITE_DATA = 1, VIRTUAL_WRITE_SYMLINK, VIRTUAL_WRITE_DIR,
+ VIRTUAL_WRITE_FILE, VIRTUAL_PREPARE_WRITING };
+ bool prepareWriting_impl( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime );
+ struct PrepareWritingParams {
+ const TQString *name;
+ const TQString *user;
+ const TQString *group;
+ uint size;
+ mode_t perm;
+ time_t atime, mtime, ctime;
+ bool retval;
+ };
+ bool writeFile_impl( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime,
+ const char* data );
+ struct WriteFileParams {
+ const TQString *name;
+ const TQString *user;
+ const TQString *group;
+ uint size;
+ mode_t perm;
+ time_t atime, mtime, ctime;
+ const char *data;
+ bool retval;
+ };
+ bool writeDir_impl(const TQString& name, const TQString& user,
+ const TQString& group, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime);
+ struct WriteDirParams {
+ const TQString *name;
+ const TQString *user;
+ const TQString *group;
+ mode_t perm;
+ time_t atime, mtime, ctime;
+ bool retval;
+ };
+ bool writeSymLink_impl(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+ struct WriteSymlinkParams {
+ const TQString *name;
+ const TQString *target;
+ const TQString *user;
+ const TQString *group;
+ mode_t perm;
+ time_t atime, mtime, ctime;
+ bool retval;
+ };
+ bool writeData_impl( const char* data, uint size );
+ struct WriteDataParams {
+ const char* data;
+ uint size;
+ bool retval;
+ };
+private:
+ class KArchivePrivate;
+ KArchivePrivate * d;
+};
+
+/**
+ * A base class for entries in an KArchive.
+ * @short Base class for the archive-file's directory structure.
+ *
+ * @see KArchiveFile
+ * @see KArchiveDirectory
+ */
+class TDEIO_EXPORT KArchiveEntry
+{
+public:
+ /**
+ * Creates a new entry.
+ * @param archive the entries archive
+ * @param name the name of the entry
+ * @param access the permissions in unix format
+ * @param date the date (in seconds since 1970)
+ * @param user the user that owns the entry
+ * @param group the group that owns the entry
+ * @param symlink the symlink, or TQString::null
+ */
+ KArchiveEntry( KArchive* archive, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group,
+ const TQString &symlink );
+
+ virtual ~KArchiveEntry() { }
+
+ /**
+ * Creation date of the file.
+ * @return the creation date
+ */
+ TQDateTime datetime() const;
+
+ /**
+ * Creation date of the file.
+ * @return the creation date in seconds since 1970
+ */
+ int date() const { return m_date; }
+
+ /**
+ * Name of the file without path.
+ * @return the file name without path
+ */
+ TQString name() const { return m_name; }
+ /**
+ * The permissions and mode flags as returned by the stat() function
+ * in st_mode.
+ * @return the permissions
+ */
+ mode_t permissions() const { return m_access; }
+ /**
+ * User who created the file.
+ * @return the owner of the file
+ */
+ TQString user() const { return m_user; }
+ /**
+ * Group of the user who created the file.
+ * @return the group of the file
+ */
+ TQString group() const { return m_group; }
+
+ /**
+ * Symlink if there is one.
+ * @return the symlink, or TQString::null
+ */
+ TQString symlink() const { return m_symlink; }
+
+ /**
+ * Checks whether the entry is a file.
+ * @return true if this entry is a file
+ */
+ virtual bool isFile() const { return false; }
+
+ /**
+ * Checks whether the entry is a directory.
+ * @return true if this entry is a directory
+ */
+ virtual bool isDirectory() const { return false; }
+
+protected:
+ KArchive* archive() const { return m_archive; }
+
+private:
+ TQString m_name;
+ int m_date;
+ mode_t m_access;
+ TQString m_user;
+ TQString m_group;
+ TQString m_symlink;
+ KArchive* m_archive;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KArchiveEntryPrivate* d;
+};
+
+/**
+ * Represents a file entry in a KArchive.
+ * @short A file in an archive.
+ *
+ * @see KArchive
+ * @see KArchiveDirectory
+ */
+class TDEIO_EXPORT KArchiveFile : public KArchiveEntry
+{
+public:
+ /**
+ * Creates a new file entry.
+ * @param archive the entries archive
+ * @param name the name of the entry
+ * @param access the permissions in unix format
+ * @param date the date (in seconds since 1970)
+ * @param user the user that owns the entry
+ * @param group the group that owns the entry
+ * @param symlink the symlink, or TQString::null
+ * @param pos the position of the file in the directory
+ * @param size the size of the file
+ */
+ KArchiveFile( KArchive* archive, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group, const TQString &symlink,
+ int pos, int size );
+
+ virtual ~KArchiveFile() { }
+
+ /**
+ * Position of the data in the [uncompressed] archive.
+ * @return the position of the file
+ */
+ int position() const; // TODO use TQ_LONG in KDE-4.0
+ /**
+ * Size of the data.
+ * @return the size of the file
+ */
+ int size() const; // TODO use TQ_LONG in KDE-4.0
+ /**
+ * Set size of data, usually after writing the file.
+ * @param s the new size of the file
+ */
+ void setSize( int s ) { m_size = s; }
+
+ /**
+ * Returns the data of the file.
+ * Call data() with care (only once per file), this data isn't cached.
+ * @return the content of this file.
+ */
+ virtual TQByteArray data() const;
+
+ /**
+ * This method returns TQIODevice (internal class: KLimitedIODevice)
+ * on top of the underlying TQIODevice. This is obviously for reading only.
+ * Note that the ownership of the device is being transferred to the caller,
+ * who will have to delete it.
+ * The returned device auto-opens (in readonly mode), no need to open it.
+ * @return the TQIODevice of the file
+ */
+ TQIODevice *device() const; // TODO make virtual
+
+ /**
+ * Checks whether this entry is a file.
+ * @return true, since this entry is a file
+ */
+ virtual bool isFile() const { return true; }
+
+ /**
+ * Extracts the file to the directory @p dest
+ * @param dest the directory to extract to
+ * @since 3.1
+ */
+ void copyTo(const TQString& dest) const;
+
+private:
+ int m_pos; // TODO use TQ_LONG in KDE-4.0
+ int m_size; // TODO use TQ_LONG in KDE-4.0
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KArchiveFilePrivate* d;
+};
+
+/**
+ * Represents a directory entry in a KArchive.
+ * @short A directory in an archive.
+ *
+ * @see KArchive
+ * @see KArchiveFile
+ */
+class TDEIO_EXPORT KArchiveDirectory : public KArchiveEntry
+{
+public:
+ /**
+ * Creates a new directory entry.
+ * @param archive the entries archive
+ * @param name the name of the entry
+ * @param access the permissions in unix format
+ * @param date the date (in seconds since 1970)
+ * @param user the user that owns the entry
+ * @param group the group that owns the entry
+ * @param symlink the symlink, or TQString::null
+ */
+ KArchiveDirectory( KArchive* archive, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group,
+ const TQString& symlink);
+
+ virtual ~KArchiveDirectory() { }
+
+ /**
+ * Returns a list of sub-entries.
+ * @return the names of all entries in this directory (filenames, no path).
+ */
+ TQStringList entries() const;
+ /**
+ * Returns the entry with the given name.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ KArchiveEntry* entry( TQString name );
+ /**
+ * Returns the entry with the given name.
+ * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+ * @return a pointer to the entry in the directory.
+ */
+ const KArchiveEntry* entry( TQString name ) const;
+
+ /**
+ * @internal
+ * Adds a new entry to the directory.
+ */
+ void addEntry( KArchiveEntry* );
+
+ /**
+ * Checks whether this entry is a directory.
+ * @return true, since this entry is a directory
+ */
+ virtual bool isDirectory() const { return true; }
+
+ /**
+ * Extracts all entries in this archive directory to the directory
+ * @p dest.
+ * @param dest the directory to extract to
+ * @param recursive if set to true, subdirectories are extracted as well
+ * @since 3.1
+ */
+ void copyTo(const TQString& dest, bool recursive = true) const;
+
+private:
+ TQDict<KArchiveEntry> m_entries;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KArchiveDirectoryPrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kautomount.cpp b/tdeio/tdeio/kautomount.cpp
new file mode 100644
index 000000000..f167a6ccb
--- /dev/null
+++ b/tdeio/tdeio/kautomount.cpp
@@ -0,0 +1,117 @@
+/* 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.
+*/
+
+#include "kautomount.h"
+#include "krun.h"
+#include "kdirwatch.h"
+#include "tdeio/job.h"
+#include <kdirnotify_stub.h>
+#include <kdebug.h>
+
+/***********************************************************************
+ *
+ * Utility classes
+ *
+ ***********************************************************************/
+
+KAutoMount::KAutoMount( bool _readonly, const TQString& _format, const TQString& _device,
+ const TQString& _mountpoint, const TQString & _desktopFile,
+ bool _show_filemanager_window )
+ : m_strDevice( _device ),
+ m_desktopFile( _desktopFile )
+{
+ //kdDebug(7015) << "KAutoMount device=" << _device << " mountpoint=" << _mountpoint << endl;
+ m_bShowFilemanagerWindow = _show_filemanager_window;
+
+ TDEIO::Job* job = TDEIO::mount( _readonly, _format.ascii(), _device, _mountpoint );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+}
+
+void KAutoMount::slotResult( TDEIO::Job * job )
+{
+ if ( job->error() ) {
+ emit error();
+ job->showErrorDialog();
+ }
+ else
+ {
+ KURL mountpoint;
+ mountpoint.setPath( TDEIO::findDeviceMountPoint( m_strDevice ) );
+ //kdDebug(7015) << "KAutoMount: m_strDevice=" << m_strDevice << " -> mountpoint=" << mountpoint << endl;
+ Q_ASSERT( mountpoint.isValid() );
+
+ if ( mountpoint.path().isEmpty() )
+ kdWarning(7015) << m_strDevice << " was correctly mounted, but TDEIO::findDeviceMountPoint didn't find it. "
+ << "This looks like a bug, please report it on http://bugs.kde.org, together with your /etc/fstab line" << endl;
+ else if ( m_bShowFilemanagerWindow )
+ KRun::runURL( mountpoint, "inode/directory" );
+
+ // Notify about the new stuff in that dir, in case of opened windows showing it
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesAdded( mountpoint );
+
+ // Update the desktop file which is used for mount/unmount (icon change)
+ kdDebug(7015) << " mount finished : updating " << m_desktopFile << endl;
+ KURL dfURL;
+ dfURL.setPath( m_desktopFile );
+ allDirNotify.FilesChanged( dfURL );
+ //KDirWatch::self()->setFileDirty( m_desktopFile );
+
+ emit finished();
+ }
+ delete this;
+}
+
+KAutoUnmount::KAutoUnmount( const TQString & _mountpoint, const TQString & _desktopFile )
+ : m_desktopFile( _desktopFile ), m_mountpoint( _mountpoint )
+{
+ TDEIO::Job * job = TDEIO::unmount( m_mountpoint );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+}
+
+void KAutoUnmount::slotResult( TDEIO::Job * job )
+{
+ if ( job->error() ) {
+ emit error();
+ job->showErrorDialog();
+ }
+ else
+ {
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ // Update the desktop file which is used for mount/unmount (icon change)
+ kdDebug(7015) << "unmount finished : updating " << m_desktopFile << endl;
+ KURL dfURL;
+ dfURL.setPath( m_desktopFile );
+ allDirNotify.FilesChanged( dfURL );
+ //KDirWatch::self()->setFileDirty( m_desktopFile );
+
+ // Notify about the new stuff in that dir, in case of opened windows showing it
+ // You may think we removed files, but this may have also readded some
+ // (if the mountpoint wasn't empty). The only possible behavior on FilesAdded
+ // is to relist the directory anyway.
+ KURL mp;
+ mp.setPath( m_mountpoint );
+ allDirNotify.FilesAdded( mp );
+
+ emit finished();
+ }
+
+ delete this;
+}
+
+#include "kautomount.moc"
diff --git a/tdeio/tdeio/kautomount.h b/tdeio/tdeio/kautomount.h
new file mode 100644
index 000000000..203c037d9
--- /dev/null
+++ b/tdeio/tdeio/kautomount.h
@@ -0,0 +1,122 @@
+/* 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 __auto_mount_h__
+#define __auto_mount_h__
+
+#include <tqobject.h>
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+#ifdef Q_MOC_RUN
+#define Q_OS_UNIX
+#endif // Q_MOC_RUN
+
+#ifdef Q_OS_UNIX
+
+namespace TDEIO {
+class Job;
+}
+
+/**
+ * This class implements synchronous mounting of devices,
+ * as well as showing a file-manager window after mounting a device, optionally.
+ * It is a wrapper around the asychronous TDEIO::special() call for mount,
+ * used by KMimeType.
+ *
+ * @short This class implements synchronous mounting of devices.
+ */
+class TDEIO_EXPORT KAutoMount : public TQObject
+{
+ Q_OBJECT
+ friend class gcc_gives_a_warning_without_this;
+public:
+ /**
+ * Mounts a device.
+ * @param readonly if true, the device is mounted read-only
+ * @param format the file system (e.g. vfat, ext2...) [optional, fstab is used otherwise]
+ * @param device the path to the device (e.g. /dev/fd0)
+ * @param mountpoint the directory where to mount the device [optional, fstab is used otherwise]
+ * @param desktopFile the file the user clicked on - to notify KDirWatch of the fact that
+ * it should emit fileDirty for it (to have the icon change)
+ * @param show_filemanager_window if true, a file-manager window for that mountpoint is shown after
+ * the mount, if successful.
+ */
+ KAutoMount( bool readonly, const TQString& format, const TQString& device, const TQString& mountpoint,
+ const TQString & desktopFile, bool show_filemanager_window = true );
+
+signals:
+ /** Emitted when the directory has been mounted */
+ void finished();
+ /** Emitted in case the directory could not been mounted */
+ void error();
+
+protected slots:
+ void slotResult( TDEIO::Job * );
+
+protected:
+ TQString m_strDevice;
+ bool m_bShowFilemanagerWindow;
+ TQString m_desktopFile;
+private:
+ /** KAutoMount deletes itself. Don't delete it manually. */
+ ~KAutoMount() {}
+ class KAutoMountPrivate* d;
+};
+
+/**
+ * This class implements synchronous unmounting of devices,
+ * It is a wrapper around the asychronous TDEIO::special() call for unmount,
+ * used by KMimeType.
+ *
+ * @short This class implements synchronous unmounting of devices,
+ */
+class TDEIO_EXPORT KAutoUnmount : public TQObject
+{
+ Q_OBJECT
+ friend class gcc_gives_a_warning_without_this;
+public:
+ /**
+ * Unmounts a device.
+ * @param mountpoint the mount point - KAutoUnmount finds the device from that
+ * @param desktopFile the file the user clicked on - to notify KDirWatch of the fact that
+ * it should emit fileDirty for it (to have the icon change)
+ */
+ KAutoUnmount( const TQString & mountpoint, const TQString & desktopFile );
+
+signals:
+ /** Emitted when the directory has been unmounted */
+ void finished();
+ /** Emitted in case the directory could not been unmounted */
+ void error();
+
+protected slots:
+ void slotResult( TDEIO::Job * );
+private:
+ TQString m_desktopFile;
+ TQString m_mountpoint;
+private:
+ /** KAutoUnmount deletes itself. Don't delete it manually. */
+ ~KAutoUnmount() {}
+ class KAutoUnmountPrivate* d;
+};
+
+#endif //Q_OS_UNIX
+
+#endif
diff --git a/tdeio/tdeio/kdatatool.cpp b/tdeio/tdeio/kdatatool.cpp
new file mode 100644
index 000000000..08630d110
--- /dev/null
+++ b/tdeio/tdeio/kdatatool.cpp
@@ -0,0 +1,285 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
+ Copyright (C) 2001 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 "kdatatool.h"
+
+#include <kstandarddirs.h>
+#include <klibloader.h>
+#include <kdebug.h>
+#include <kinstance.h>
+
+#include <ktrader.h>
+#include <tdeparts/componentfactory.h>
+
+#include <tqpixmap.h>
+#include <tqfile.h>
+
+/*************************************************
+ *
+ * KDataToolInfo
+ *
+ *************************************************/
+
+KDataToolInfo::KDataToolInfo()
+{
+ m_service = 0;
+}
+
+KDataToolInfo::KDataToolInfo( const KService::Ptr& service, TDEInstance* instance )
+{
+ m_service = service;
+ m_instance = instance;
+
+ if ( !!m_service && !m_service->serviceTypes().contains( "KDataTool" ) )
+ {
+ kdDebug(30003) << "The service " << m_service->name().latin1()
+ << " does not feature the service type KDataTool" << endl;
+ m_service = 0;
+ }
+}
+
+KDataToolInfo::KDataToolInfo( const KDataToolInfo& info )
+{
+ m_service = info.service();
+ m_instance = info.instance();
+}
+
+KDataToolInfo& KDataToolInfo::operator= ( const KDataToolInfo& info )
+{
+ m_service = info.service();
+ m_instance = info.instance();
+ return *this;
+}
+
+TQString KDataToolInfo::dataType() const
+{
+ if ( !m_service )
+ return TQString::null;
+
+ return m_service->property( "DataType" ).toString();
+}
+
+TQStringList KDataToolInfo::mimeTypes() const
+{
+ if ( !m_service )
+ return TQStringList();
+
+ return m_service->property( "DataMimeTypes" ).toStringList();
+}
+
+bool KDataToolInfo::isReadOnly() const
+{
+ if ( !m_service )
+ return true;
+
+ return m_service->property( "ReadOnly" ).toBool();
+}
+
+TQPixmap KDataToolInfo::icon() const
+{
+ if ( !m_service )
+ return TQPixmap();
+
+ TQPixmap pix;
+ TQStringList lst = TDEGlobal::dirs()->resourceDirs("icon");
+ TQStringList::ConstIterator it = lst.begin();
+ while (!pix.load( *it + "/" + m_service->icon() ) && it != lst.end() )
+ it++;
+
+ return pix;
+}
+
+TQPixmap KDataToolInfo::miniIcon() const
+{
+ if ( !m_service )
+ return TQPixmap();
+
+ TQPixmap pix;
+ TQStringList lst = TDEGlobal::dirs()->resourceDirs("mini");
+ TQStringList::ConstIterator it = lst.begin();
+ while (!pix.load( *it + "/" + m_service->icon() ) && it != lst.end() )
+ it++;
+
+ return pix;
+}
+
+TQString KDataToolInfo::iconName() const
+{
+ if ( !m_service )
+ return TQString::null;
+ return m_service->icon();
+}
+
+TQStringList KDataToolInfo::commands() const
+{
+ if ( !m_service )
+ return TQString();
+
+ return m_service->property( "Commands" ).toStringList();
+}
+
+TQStringList KDataToolInfo::userCommands() const
+{
+ if ( !m_service )
+ return TQString();
+
+ return TQStringList::split( ',', m_service->comment() );
+}
+
+KDataTool* KDataToolInfo::createTool( TQObject* parent, const char* name ) const
+{
+ if ( !m_service )
+ return 0;
+
+ KDataTool* tool = KParts::ComponentFactory::createInstanceFromService<KDataTool>( m_service, parent, name );
+ if ( tool )
+ tool->setInstance( m_instance );
+ return tool;
+}
+
+KService::Ptr KDataToolInfo::service() const
+{
+ return m_service;
+}
+
+TQValueList<KDataToolInfo> KDataToolInfo::query( const TQString& datatype, const TQString& mimetype, TDEInstance* instance )
+{
+ TQValueList<KDataToolInfo> lst;
+
+ TQString constr;
+
+ if ( !datatype.isEmpty() )
+ {
+ constr = TQString::fromLatin1( "DataType == '%1'" ).arg( datatype );
+ }
+ if ( !mimetype.isEmpty() )
+ {
+ TQString tmp = TQString::fromLatin1( "'%1' in DataMimeTypes" ).arg( mimetype );
+ if ( constr.isEmpty() )
+ constr = tmp;
+ else
+ constr = constr + " and " + tmp;
+ }
+/* Bug in KTrader ? Test with HEAD-tdelibs!
+ if ( instance )
+ {
+ TQString tmp = TQString::fromLatin1( "not ('%1' in ExcludeFrom)" ).arg( instance->instanceName() );
+ if ( constr.isEmpty() )
+ constr = tmp;
+ else
+ constr = constr + " and " + tmp;
+ } */
+
+ // Query the trader
+ //kdDebug() << "KDataToolInfo::query " << constr << endl;
+ KTrader::OfferList offers = KTrader::self()->query( "KDataTool", constr );
+
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ for( ; it != offers.end(); ++it )
+ {
+ // Temporary replacement for the non-working trader query above
+ if ( !instance || !(*it)->property("ExcludeFrom").toStringList()
+ .contains( instance->instanceName() ) )
+ lst.append( KDataToolInfo( *it, instance ) );
+ else
+ kdDebug() << (*it)->entryPath() << " excluded." << endl;
+ }
+
+ return lst;
+}
+
+bool KDataToolInfo::isValid() const
+{
+ return( m_service );
+}
+
+/*************************************************
+ *
+ * KDataToolAction
+ *
+ *************************************************/
+KDataToolAction::KDataToolAction( const TQString & text, const KDataToolInfo & info, const TQString & command,
+ TQObject * parent, const char * name )
+ : KAction( text, info.iconName(), 0, parent, name ),
+ m_command( command ),
+ m_info( info )
+{
+}
+
+void KDataToolAction::slotActivated()
+{
+ emit toolActivated( m_info, m_command );
+}
+
+TQPtrList<KAction> KDataToolAction::dataToolActionList( const TQValueList<KDataToolInfo> & tools, const TQObject *receiver, const char* slot )
+{
+ TQPtrList<KAction> actionList;
+ if ( tools.isEmpty() )
+ return actionList;
+
+ actionList.append( new KActionSeparator() );
+ TQValueList<KDataToolInfo>::ConstIterator entry = tools.begin();
+ for( ; entry != tools.end(); ++entry )
+ {
+ TQStringList userCommands = (*entry).userCommands();
+ TQStringList commands = (*entry).commands();
+ Q_ASSERT(!commands.isEmpty());
+ if ( commands.count() != userCommands.count() )
+ kdWarning() << "KDataTool desktop file error (" << (*entry).service()->entryPath()
+ << "). " << commands.count() << " commands and "
+ << userCommands.count() << " descriptions." << endl;
+ TQStringList::ConstIterator uit = userCommands.begin();
+ TQStringList::ConstIterator cit = commands.begin();
+ for (; uit != userCommands.end() && cit != commands.end(); ++uit, ++cit )
+ {
+ //kdDebug() << "creating action " << *uit << " " << *cit << endl;
+ KDataToolAction * action = new KDataToolAction( *uit, *entry, *cit );
+ connect( action, TQT_SIGNAL( toolActivated( const KDataToolInfo &, const TQString & ) ),
+ receiver, slot );
+ actionList.append( action );
+ }
+ }
+
+ return actionList;
+}
+
+/*************************************************
+ *
+ * KDataTool
+ *
+ *************************************************/
+
+KDataTool::KDataTool( TQObject* parent, const char* name )
+ : TQObject( parent, name ), m_instance( 0L )
+{
+}
+
+TDEInstance* KDataTool::instance() const
+{
+ return m_instance;
+}
+
+void KDataToolAction::virtual_hook( int id, void* data )
+{ KAction::virtual_hook( id, data ); }
+
+void KDataTool::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kdatatool.moc"
diff --git a/tdeio/tdeio/kdatatool.h b/tdeio/tdeio/kdatatool.h
new file mode 100644
index 000000000..1258767fc
--- /dev/null
+++ b/tdeio/tdeio/kdatatool.h
@@ -0,0 +1,303 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
+ Copyright (C) 2001 David Faure <david@mandrakesoft.com>
+
+ 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 KDATATOOL_H
+#define KDATATOOL_H
+
+#include <tqobject.h>
+#include <tqvaluelist.h>
+
+#include <kaction.h>
+#include <kservice.h>
+
+class KDataTool;
+class TQPixmap;
+class TQStringList;
+class TDEInstance;
+
+// If you're only looking at implementing a data-tool, skip directly to the last
+// class definition, KDataTool.
+
+/**
+ * This is a convenience class for KService. You can use it if you have
+ * a KService describing a KDataTool. In this case the KDataToolInfo class
+ * is more convenient to work with.
+ *
+ * Especially useful is the method createTool which creates the datatool
+ * described by the service.
+ * @see KDataTool
+ */
+class TDEIO_EXPORT KDataToolInfo
+{
+public:
+ /**
+ * Create an invalid KDataToolInfo.
+ */
+ KDataToolInfo();
+ /**
+ * Create a valid KDataToolInfo.
+ * @param service the corresponding service
+ * @param instance the instance to use
+ */
+ KDataToolInfo( const KService::Ptr& service, TDEInstance* instance );
+ /**
+ * Copy constructor.
+ */
+ KDataToolInfo( const KDataToolInfo& info );
+ /**
+ * Assignment operator.
+ */
+ KDataToolInfo& operator= ( const KDataToolInfo& info );
+
+ /**
+ * Returns the data type that the DataTool can accept.
+ * @return the C++ data type that this DataTool accepts.
+ * For example "TQString" or "TQImage" or something more
+ * complicated.
+ */
+ TQString dataType() const;
+ /**
+ * Returns a list of mime type that will be accepted by the DataTool.
+ * The mimetypes are only used if the dataType can be used to store
+ * different mimetypes. For example in a "TQString" you could save "text/plain"
+ * or "text/html" or "text/xml".
+ *
+ * @return the mime types accepted by this DataTool. For example
+ * "image/gif" or "text/plain". In some cases the dataType
+ * determines the accepted type of data perfectly. In this cases
+ * this list may be empty.
+ */
+ TQStringList mimeTypes() const;
+
+ /**
+ * Checks whether the DataTool is read-only.
+ * @return true if the DataTool does not modify the data passed to it by KDataTool::run.
+ */
+ bool isReadOnly() const;
+
+ /**
+ * Returns the icon of this data tool.
+ * @return a large pixmap for the DataTool.
+ * @deprecated, use iconName()
+ */
+ TQPixmap icon() const KDE_DEPRECATED;
+ /**
+ * Returns the mini icon of this data tool.
+ * @return a mini pixmap for the DataTool.
+ * @deprecated, use iconName()
+ */
+ TQPixmap miniIcon() const KDE_DEPRECATED;
+ /**
+ * Returns the icon name for this DataTool.
+ * @return the name of the icon for the DataTool
+ */
+ TQString iconName() const;
+ /**
+ * Returns a list of strings that you can put in a TQPopupMenu item, for example to
+ * offer the DataTools services to the user. The returned value
+ * is usually something like "Spell checking", "Shrink Image", "Rotate Image"
+ * or something like that.
+ * This list comes from the Comment field of the tool's desktop file
+ * (so that it can be translated).
+ *
+ * Each of the strings returned corresponds to a string in the list returned by
+ * commands.
+ *
+ * @return a list of strings that you can put in a TQPopupMenu item
+ */
+ TQStringList userCommands() const;
+ /**
+ * Returns the list of commands the DataTool can execute. The application
+ * passes the command to the KDataTool::run method.
+ *
+ * This list comes from the Commands field of the tool's desktop file.
+ *
+ * Each of the strings returned corresponds to a string in the list returned by
+ * userCommands.
+ * @return the list of commands the DataTool can execute, suitable for
+ * the KDataTool::run method.
+ */
+ TQStringList commands() const;
+
+ /**
+ * Creates the data tool described by this KDataToolInfo.
+ * @param parent the parent of the TQObject (or 0 for parent-less KDataTools)
+ * @param name the name of the TQObject, can be 0
+ * @return a pointer to the created data tool or 0 on error.
+ */
+ KDataTool* createTool( TQObject* parent = 0, const char* name = 0 ) const;
+
+ /**
+ * The KDataToolInfo's service that is represented by this class.
+ * @return the service
+ */
+ KService::Ptr service() const;
+
+ /**
+ * The instance of the service.
+ * @return the instance
+ */
+ TDEInstance* instance() const { return m_instance; }
+
+ /**
+ * A DataToolInfo may be invalid if the KService passed to its constructor does
+ * not feature the service type "KDataTool".
+ * @return true if valid, false otherwise
+ */
+ bool isValid() const;
+
+ /**
+ * Queries the KTrader about installed KDataTool implementations.
+ * @param datatype a type that the application can 'export' to the tools (e.g. TQString)
+ * @param mimetype the mimetype of the data (e.g. text/plain)
+ * @param instance the application (or the part)'s instance (to check if a tool is excluded from this part,
+ * and also used if the tool wants to read its configuration in the app's config file).
+ * @return the list of results
+ */
+ static TQValueList<KDataToolInfo> query( const TQString& datatype, const TQString& mimetype, TDEInstance * instance );
+
+private:
+ KService::Ptr m_service;
+ TDEInstance* m_instance;
+private:
+ class KDataToolInfoPrivate* d;
+};
+
+
+/**
+ * This class helps applications implement support for KDataTool.
+ * The steps to follow are simple:
+ * @li query for the available tools using KDataToolInfo::query
+ * @li pass the result to KDataToolAction::dataToolActionList (with a slot)
+ * @li plug the resulting actions, either using KXMLGUIClient::plugActionList, or by hand.
+ *
+ * The slot defined for step 2 is called when the action is activated, and
+ * that's where the tool should be created and run.
+ */
+class TDEIO_EXPORT KDataToolAction : public KAction
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a new KDataToolAction.
+ *
+ * @param text The text that will be displayed.
+ * @param info the corresponding KDataToolInfo
+ * @param command the command of the action
+ * @param parent This action's parent.
+ * @param name An internal name for this action.
+ */
+ KDataToolAction( const TQString & text, const KDataToolInfo & info, const TQString & command, TQObject * parent = 0, const char * name = 0);
+
+ /**
+ * Creates a list of actions from a list of information about data-tools.
+ * The slot must have a signature corresponding to the toolActivated signal.
+ *
+ * Note that it's the caller's responsibility to delete the actions when they're not needed anymore.
+ * @param tools the list of data tool descriptions
+ * @param receiver the receiver for toolActivated() signals
+ * @param slot the slot that will receive the toolActivated() signals
+ * @return the KActions
+ */
+ static TQPtrList<KAction> dataToolActionList( const TQValueList<KDataToolInfo> & tools, const TQObject *receiver, const char* slot );
+
+signals:
+ /**
+ * Emitted when a tool has been activated.
+ * @param info a description of the activated tools
+ * @param command the command for the tool
+ */
+ void toolActivated( const KDataToolInfo & info, const TQString & command );
+
+protected:
+ virtual void slotActivated();
+
+private:
+ TQString m_command;
+ KDataToolInfo m_info;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDataToolActionPrivate* d;
+
+};
+
+/**
+ * A generic tool that processes data.
+ *
+ * A data-tool is a "plugin" for an application, that acts (reads/modifies)
+ * on a portion of the data present in the document (e.g. a text document,
+ * a single word or paragraph, a KSpread cell, an image, etc.)
+ *
+ * The application has some generic code for presenting the tools in a popupmenu
+ * @see KDataToolAction, and for activating a tool, passing it the data
+ * (and possibly getting modified data from it).
+ */
+class TDEIO_EXPORT KDataTool : public TQObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ * The data-tool is only created when a menu-item, that relates to it, is activated.
+ * @param parent the parent of the TQObject (or 0 for parent-less KDataTools)
+ * @param name the name of the TQObject, can be 0
+ */
+ KDataTool( TQObject* parent = 0, const char* name = 0 );
+
+ /**
+ * @internal. Do not use under any circumstance (including bad weather).
+ */
+ void setInstance( TDEInstance* instance ) { m_instance = instance; }
+
+ /**
+ * Returns the instance of the part that created this tool.
+ * Usually used if the tool wants to read its configuration in the app's config file.
+ * @return the instance of the part that created this tool.
+ */
+ TDEInstance* instance() const;
+
+ /**
+ * Interface for 'running' this tool.
+ * This is the method that the data-tool must implement.
+ *
+ * @param command is the command that was selected (see KDataToolInfo::commands())
+ * @param data the data provided by the application, on which to run the tool.
+ * The application is responsible for setting that data before running the tool,
+ * and for getting it back and updating itself with it, after the tool ran.
+ * @param datatype defines the type of @p data.
+ * @param mimetype defines the mimetype of the data (for instance datatype may be
+ * TQString, but the mimetype can be text/plain, text/html etc.)
+ * @return true if successful, false otherwise
+ */
+ virtual bool run( const TQString& command, void* data, const TQString& datatype, const TQString& mimetype) = 0;
+
+private:
+ TDEInstance * m_instance;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KDataToolPrivate;
+ KDataToolPrivate * d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kdcopservicestarter.cpp b/tdeio/tdeio/kdcopservicestarter.cpp
new file mode 100644
index 000000000..3c9b55501
--- /dev/null
+++ b/tdeio/tdeio/kdcopservicestarter.cpp
@@ -0,0 +1,97 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 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 "kdcopservicestarter.h"
+#include "ktrader.h"
+#include <kapplication.h>
+#include "kservice.h"
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <dcopclient.h>
+
+static KStaticDeleter<KDCOPServiceStarter> dss_sd;
+KDCOPServiceStarter* KDCOPServiceStarter::s_self;
+
+KDCOPServiceStarter* KDCOPServiceStarter::self()
+{
+ if ( !s_self )
+ dss_sd.setObject( s_self, new KDCOPServiceStarter );
+ return s_self;
+}
+
+KDCOPServiceStarter::KDCOPServiceStarter()
+{
+ // Set the singleton instance - useful when a derived KDCOPServiceStarter
+ // was created (before self() was called)
+ s_self = this;
+}
+
+KDCOPServiceStarter::~KDCOPServiceStarter()
+{
+}
+
+int KDCOPServiceStarter::findServiceFor( const TQString& serviceType,
+ const TQString& _constraint,
+ const TQString& preferences,
+ TQString *error, TQCString* pDcopService,
+ int flags )
+{
+ // Ask the trader which service is preferred for this servicetype
+ // We want one that provides a DCOP interface
+ TQString constraint = _constraint;
+ if ( !constraint.isEmpty() )
+ constraint += " and ";
+ constraint += "exist [X-DCOP-ServiceName]";
+ KTrader::OfferList offers = KTrader::self()->query(serviceType, "Application", constraint, preferences);
+ if ( offers.isEmpty() ) {
+ if ( error )
+ *error = i18n("No service implementing %1").arg( serviceType );
+ kdWarning() << "KDCOPServiceStarter: No service implementing " << serviceType << endl;
+ return -1;
+ }
+ KService::Ptr ptr = offers.first();
+ TQCString dcopService = ptr->property("X-DCOP-ServiceName").toString().latin1();
+
+ if ( !kapp->dcopClient()->isApplicationRegistered( dcopService ) )
+ {
+ TQString error;
+ if ( startServiceFor( serviceType, constraint, preferences, &error, &dcopService, flags ) != 0 )
+ {
+ kdDebug() << "KDCOPServiceStarter: Couldn't start service: " << error << endl;
+ return -2;
+ }
+ }
+ kdDebug() << "KDCOPServiceStarter: DCOP service is available now, as " << dcopService << endl;
+ if ( pDcopService )
+ *pDcopService = dcopService;
+ return 0;
+}
+
+int KDCOPServiceStarter::startServiceFor( const TQString& serviceType,
+ const TQString& constraint,
+ const TQString& preferences,
+ TQString *error, TQCString* dcopService, int /*flags*/ )
+{
+ KTrader::OfferList offers = KTrader::self()->query(serviceType, "Application", constraint, preferences);
+ if ( offers.isEmpty() )
+ return -1;
+ KService::Ptr ptr = offers.first();
+ kdDebug() << "KDCOPServiceStarter: starting " << ptr->desktopEntryPath() << endl;
+ return kapp->startServiceByDesktopPath( ptr->desktopEntryPath(), TQStringList(), error, dcopService );
+}
diff --git a/tdeio/tdeio/kdcopservicestarter.h b/tdeio/tdeio/kdcopservicestarter.h
new file mode 100644
index 000000000..f70f0173e
--- /dev/null
+++ b/tdeio/tdeio/kdcopservicestarter.h
@@ -0,0 +1,103 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 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 KDCOPSERVICESTARTER_H
+#define KDCOPSERVICESTARTER_H
+
+#include <tqstring.h>
+#include <kstaticdeleter.h>
+
+class KDCOPServiceStarter;
+class TQCString;
+
+/**
+ * A generic DCOP service starter, using KTrader.
+ * The default implementation starts new processes, but this interface can
+ * also be reimplemented by specific applications to provide dlopened in-process DCOP objects.
+ * @author David Faure <faure@kde.org>
+ */
+class TDEIO_EXPORT KDCOPServiceStarter {
+ friend class KStaticDeleter<KDCOPServiceStarter>;
+public:
+
+ static KDCOPServiceStarter* self();
+
+ /**
+ * Check if a given DCOP interface is available - from the serviceType it's supposed to implement.
+ *
+ * The trader is queried to find the preferred application for this serviceType,
+ * with the constraint that its X-DCOP-ServiceName property must be defined.
+ * Then the DCOP server is checked. If the service is not available,
+ * this method will call startServiceFor to start it.
+ *
+ * @param serviceType the type of service we're looking for
+ * @param constraint see KTrader
+ * @param preferences see KTrader
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If the pointer is 0 the argument
+ * will be ignored
+ * @param flags for future extensions (currently unused)
+ *
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ int findServiceFor( const TQString& serviceType,
+ const TQString& constraint = TQString::null,
+ const TQString& preferences = TQString::null,
+ TQString *error=0, TQCString* dcopService=0,
+ int flags=0 );
+
+ /**
+ * Find an implementation of the given @p serviceType,
+ * and start it, to use its DCOP interface.
+ * The default implementation uses KTrader to find the preferred Application,
+ * and then starts it using kapp->startService...
+ *
+ * However applications (like kontact) can reimplement this method, to provide
+ * an in-process way of loading the implementation for this service type.
+ *
+ * @param serviceType the type of service we're looking for
+ * @param constraint see KTrader
+ * @param preferences see KTrader
+ * @param error On failure, @p error contains a description of the error
+ * that occurred. If the pointer is 0, the argument will be
+ * ignored
+ * @param dcopService On success, @p dcopService contains the DCOP name
+ * under which this service is available. If the pointer is 0 the argument
+ * will be ignored
+ * @param flags for future extensions (currently unused)
+ *
+ * @return an error code indicating success (== 0) or failure (> 0).
+ */
+ virtual int startServiceFor( const TQString& serviceType,
+ const TQString& constraint = TQString::null,
+ const TQString& preferences = TQString::null,
+ TQString *error=0, TQCString* dcopService=0,
+ int flags=0 );
+protected:
+ KDCOPServiceStarter();
+ virtual ~KDCOPServiceStarter();
+
+private:
+ static KDCOPServiceStarter* s_self;
+};
+
+#endif
+
diff --git a/tdeio/tdeio/kdirlister.cpp b/tdeio/tdeio/kdirlister.cpp
new file mode 100644
index 000000000..0d3498aa7
--- /dev/null
+++ b/tdeio/tdeio/kdirlister.cpp
@@ -0,0 +1,2538 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001-2005 Michael Brade <brade@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 "kdirlister.h"
+
+#include <tqregexp.h>
+#include <tqptrlist.h>
+#include <tqtimer.h>
+#include <tqeventloop.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <tdeio/job.h>
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kstaticdeleter.h>
+#include <kprotocolinfo.h>
+
+#include "kdirlister_p.h"
+
+#include <assert.h>
+#include <unistd.h>
+
+KDirListerCache* KDirListerCache::s_pSelf = 0;
+static KStaticDeleter<KDirListerCache> sd_KDirListerCache;
+
+// Enable this to get printDebug() called often, to see the contents of the cache
+//#define DEBUG_CACHE
+
+// Make really sure it doesn't get activated in the final build
+#ifdef NDEBUG
+#undef DEBUG_CACHE
+#endif
+
+KDirListerCache::KDirListerCache( int maxCount )
+ : itemsCached( maxCount )
+{
+ kdDebug(7004) << "+KDirListerCache" << endl;
+
+ itemsInUse.setAutoDelete( false );
+ itemsCached.setAutoDelete( true );
+ urlsCurrentlyListed.setAutoDelete( true );
+ urlsCurrentlyHeld.setAutoDelete( true );
+ pendingUpdates.setAutoDelete( true );
+
+ connect( kdirwatch, TQT_SIGNAL( dirty( const TQString& ) ),
+ this, TQT_SLOT( slotFileDirty( const TQString& ) ) );
+ connect( kdirwatch, TQT_SIGNAL( created( const TQString& ) ),
+ this, TQT_SLOT( slotFileCreated( const TQString& ) ) );
+ connect( kdirwatch, TQT_SIGNAL( deleted( const TQString& ) ),
+ this, TQT_SLOT( slotFileDeleted( const TQString& ) ) );
+}
+
+KDirListerCache::~KDirListerCache()
+{
+ kdDebug(7004) << "-KDirListerCache" << endl;
+
+ itemsInUse.setAutoDelete( true );
+ itemsInUse.clear();
+ itemsCached.clear();
+ urlsCurrentlyListed.clear();
+ urlsCurrentlyHeld.clear();
+
+ if ( KDirWatch::exists() )
+ kdirwatch->disconnect( this );
+}
+
+// setting _reload to true will emit the old files and
+// call updateDirectory
+bool KDirListerCache::listDir( KDirLister *lister, const KURL& _u,
+ bool _keep, bool _reload )
+{
+ // like this we don't have to worry about trailing slashes any further
+ KURL _url = _u;
+ _url.cleanPath(); // kill consecutive slashes
+ _url.adjustPath(-1);
+ TQString urlStr = _url.url();
+
+ if ( !lister->validURL( _url ) )
+ return false;
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ kdDebug(7004) << k_funcinfo << lister << " url=" << _url
+ << " keep=" << _keep << " reload=" << _reload << endl;
+
+ if ( !_keep )
+ {
+ // stop any running jobs for lister
+ stop( lister );
+
+ // clear our internal list for lister
+ forgetDirs( lister );
+
+ lister->d->rootFileItem = 0;
+ }
+ else if ( lister->d->lstDirs.find( _url ) != lister->d->lstDirs.end() )
+ {
+ // stop the job listing _url for this lister
+ stop( lister, _url );
+
+ // clear _url for lister
+ forgetDirs( lister, _url, true );
+
+ if ( lister->d->url == _url )
+ lister->d->rootFileItem = 0;
+ }
+
+ lister->d->lstDirs.append( _url );
+
+ if ( lister->d->url.isEmpty() || !_keep ) // set toplevel URL only if not set yet
+ lister->d->url = _url;
+
+ DirItem *itemU = itemsInUse[urlStr];
+ DirItem *itemC;
+
+ if ( !urlsCurrentlyListed[urlStr] )
+ {
+ // if there is an update running for _url already we get into
+ // the following case - it will just be restarted by updateDirectory().
+
+ if ( itemU )
+ {
+ kdDebug(7004) << "listDir: Entry already in use: " << _url << endl;
+
+ bool oldState = lister->d->complete;
+ lister->d->complete = false;
+
+ emit lister->started( _url );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemU->rootItem;
+
+ lister->addNewItems( *(itemU->lstItems) );
+ lister->emitItems();
+
+ // _url is already in use, so there is already an entry in urlsCurrentlyHeld
+ assert( urlsCurrentlyHeld[urlStr] );
+ urlsCurrentlyHeld[urlStr]->append( lister );
+
+ lister->d->complete = oldState;
+
+ emit lister->completed( _url );
+ if ( lister->d->complete )
+ emit lister->completed();
+
+ if ( _reload || !itemU->complete )
+ updateDirectory( _url );
+ }
+ else if ( !_reload && (itemC = itemsCached.take( urlStr )) )
+ {
+ kdDebug(7004) << "listDir: Entry in cache: " << _url << endl;
+
+ itemC->decAutoUpdate();
+ itemsInUse.insert( urlStr, itemC );
+ itemU = itemC;
+
+ bool oldState = lister->d->complete;
+ lister->d->complete = false;
+
+ emit lister->started( _url );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemC->rootItem;
+
+ lister->addNewItems( *(itemC->lstItems) );
+ lister->emitItems();
+
+ Q_ASSERT( !urlsCurrentlyHeld[urlStr] );
+ TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
+ list->append( lister );
+ urlsCurrentlyHeld.insert( urlStr, list );
+
+ lister->d->complete = oldState;
+
+ emit lister->completed( _url );
+ if ( lister->d->complete )
+ emit lister->completed();
+
+ if ( !itemC->complete )
+ updateDirectory( _url );
+ }
+ else // dir not in cache or _reload is true
+ {
+ kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl;
+
+ TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
+ list->append( lister );
+ urlsCurrentlyListed.insert( urlStr, list );
+
+ itemsCached.remove( urlStr );
+ itemU = new DirItem( _url );
+ itemsInUse.insert( urlStr, itemU );
+
+// // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs
+// if ( lister->numJobs() >= MAX_JOBS_PER_LISTER )
+// {
+// lstPendingUpdates.append( _url );
+// }
+// else
+// {
+
+ if ( lister->d->url == _url )
+ lister->d->rootFileItem = 0;
+
+ TDEIO::ListJob* job = TDEIO::listDir( _url, false /* no default GUI */ );
+ jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
+
+ lister->jobStarted( job );
+ lister->connectJob( job );
+
+ if ( lister->d->window )
+ job->setWindow( lister->d->window );
+
+ connect( job, TQT_SIGNAL( entries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ),
+ this, TQT_SLOT( slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ) );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+ connect( job, TQT_SIGNAL( redirection( TDEIO::Job *, const KURL & ) ),
+ this, TQT_SLOT( slotRedirection( TDEIO::Job *, const KURL & ) ) );
+
+ emit lister->started( _url );
+
+// }
+ }
+ }
+ else
+ {
+ kdDebug(7004) << "listDir: Entry currently being listed: " << _url << endl;
+
+ emit lister->started( _url );
+
+ urlsCurrentlyListed[urlStr]->append( lister );
+
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ Q_ASSERT( job );
+
+ lister->jobStarted( job );
+ lister->connectJob( job );
+
+ Q_ASSERT( itemU );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemU->rootItem;
+
+ lister->addNewItems( *(itemU->lstItems) );
+ lister->emitItems();
+ }
+
+ // automatic updating of directories
+ if ( lister->d->autoUpdate )
+ itemU->incAutoUpdate();
+
+ return true;
+}
+
+bool KDirListerCache::validURL( const KDirLister *lister, const KURL& url ) const
+{
+ if ( !url.isValid() )
+ {
+ if ( lister->d->autoErrorHandling )
+ {
+ TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
+ KMessageBox::error( lister->d->errorParent, tmp );
+ }
+ return false;
+ }
+
+ if ( !KProtocolInfo::supportsListing( url ) )
+ {
+ if ( lister->d->autoErrorHandling )
+ {
+ // TODO: this message should be changed during next string unfreeze!
+ TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
+ KMessageBox::error( lister->d->errorParent, tmp );
+ }
+ return false;
+ }
+
+ return true;
+}
+
+void KDirListerCache::stop( KDirLister *lister )
+{
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ kdDebug(7004) << k_funcinfo << "lister: " << lister << endl;
+ bool stopped = false;
+
+ TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyListed );
+ TQPtrList<KDirLister> *listers;
+ while ( (listers = it.current()) )
+ {
+ if ( listers->findRef( lister ) > -1 )
+ {
+ // lister is listing url
+ TQString url = it.currentKey();
+
+ //kdDebug(7004) << k_funcinfo << " found lister in list - for " << url << endl;
+ bool ret = listers->removeRef( lister );
+ Q_ASSERT( ret );
+
+ TDEIO::ListJob *job = jobForUrl( url );
+ if ( job )
+ lister->jobDone( job );
+
+ // move lister to urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[url];
+ if ( !holders )
+ {
+ holders = new TQPtrList<KDirLister>;
+ urlsCurrentlyHeld.insert( url, holders );
+ }
+
+ holders->append( lister );
+
+ emit lister->canceled( KURL( url ) );
+
+ //kdDebug(7004) << k_funcinfo << "remaining list: " << listers->count() << " listers" << endl;
+
+ if ( listers->isEmpty() )
+ {
+ // kill the job since it isn't used any more
+ if ( job )
+ killJob( job );
+
+ urlsCurrentlyListed.remove( url );
+ }
+
+ stopped = true;
+ }
+ else
+ ++it;
+ }
+
+ if ( stopped )
+ {
+ emit lister->canceled();
+ lister->d->complete = true;
+ }
+
+ // this is wrong if there is still an update running!
+ //Q_ASSERT( lister->d->complete );
+}
+
+void KDirListerCache::stop( KDirLister *lister, const KURL& _u )
+{
+ TQString urlStr( _u.url(-1) );
+ KURL _url( urlStr );
+
+ // TODO: consider to stop all the "child jobs" of _url as well
+ kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl;
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ if ( !listers || !listers->removeRef( lister ) )
+ return;
+
+ // move lister to urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+ if ( !holders )
+ {
+ holders = new TQPtrList<KDirLister>;
+ urlsCurrentlyHeld.insert( urlStr, holders );
+ }
+
+ holders->append( lister );
+
+
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ lister->jobDone( job );
+
+ emit lister->canceled( _url );
+
+ if ( listers->isEmpty() )
+ {
+ // kill the job since it isn't used any more
+ if ( job )
+ killJob( job );
+
+ urlsCurrentlyListed.remove( urlStr );
+ }
+
+ if ( lister->numJobs() == 0 )
+ {
+ lister->d->complete = true;
+
+ // we killed the last job for lister
+ emit lister->canceled();
+ }
+}
+
+void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
+{
+ // IMPORTANT: this method does not check for the current autoUpdate state!
+
+ for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
+ it != lister->d->lstDirs.end(); ++it )
+ {
+ if ( enable )
+ itemsInUse[(*it).url()]->incAutoUpdate();
+ else
+ itemsInUse[(*it).url()]->decAutoUpdate();
+ }
+}
+
+void KDirListerCache::forgetDirs( KDirLister *lister )
+{
+ kdDebug(7004) << k_funcinfo << lister << endl;
+
+ emit lister->clear();
+
+ // forgetDirs() will modify lstDirs, make a copy first
+ KURL::List lstDirsCopy = lister->d->lstDirs;
+ for ( KURL::List::Iterator it = lstDirsCopy.begin();
+ it != lstDirsCopy.end(); ++it )
+ {
+ forgetDirs( lister, *it, false );
+ }
+}
+
+void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify )
+{
+ kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl;
+
+ KURL url( _url );
+ url.adjustPath( -1 );
+ TQString urlStr = url.url();
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+ //Q_ASSERT( holders );
+ if ( holders )
+ {
+ holders->removeRef( lister );
+ }
+
+ // remove the dir from lister->d->lstDirs so that it doesn't contain things
+ // that itemsInUse doesn't. When emitting the canceled signals lstDirs must
+ // not contain anything that itemsInUse does not contain. (otherwise it
+ // might crash in findByName()).
+ lister->d->lstDirs.remove( lister->d->lstDirs.find( url ) );
+
+ DirItem *item = itemsInUse[urlStr];
+
+ if ( holders && holders->isEmpty() )
+ {
+ urlsCurrentlyHeld.remove( urlStr ); // this deletes the (empty) holders list
+ if ( !urlsCurrentlyListed[urlStr] )
+ {
+ // item not in use anymore -> move into cache if complete
+ itemsInUse.remove( urlStr );
+
+ // this job is a running update
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ {
+ lister->jobDone( job );
+ killJob( job );
+ kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl;
+
+ emit lister->canceled( url );
+ if ( lister->numJobs() == 0 )
+ {
+ lister->d->complete = true;
+ emit lister->canceled();
+ }
+ }
+
+ if ( notify )
+ emit lister->clear( url );
+
+ if ( item && item->complete )
+ {
+ kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl;
+ itemsCached.insert( urlStr, item ); // TODO: may return false!!
+
+ // Should we forget the dir for good, or keep a watch on it?
+ // Generally keep a watch, except when it would prevent
+ // unmounting a removable device (#37780)
+ const bool isLocal = item->url.isLocalFile();
+ const bool isManuallyMounted = isLocal && TDEIO::manually_mounted( item->url.path() );
+ bool containsManuallyMounted = false;
+ if ( !isManuallyMounted && item->lstItems && isLocal )
+ {
+ // Look for a manually-mounted directory inside
+ // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM
+ // I hope this isn't too slow (manually_mounted caches the last device so most
+ // of the time this is just a stat per subdir)
+ KFileItemListIterator kit( *item->lstItems );
+ for ( ; kit.current() && !containsManuallyMounted; ++kit )
+ if ( (*kit)->isDir() && TDEIO::manually_mounted( (*kit)->url().path() ) )
+ containsManuallyMounted = true;
+ }
+
+ if ( isManuallyMounted || containsManuallyMounted )
+ {
+ kdDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
+ ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" ) << endl;
+ item->complete = false; // set to "dirty"
+ }
+ else
+ item->incAutoUpdate(); // keep watch
+ }
+ else
+ {
+ delete item;
+ item = 0;
+ }
+ }
+ }
+
+ if ( item && lister->d->autoUpdate )
+ item->decAutoUpdate();
+}
+
+void KDirListerCache::updateDirectory( const KURL& _dir )
+{
+ kdDebug(7004) << k_funcinfo << _dir << endl;
+
+ TQString urlStr = _dir.url(-1);
+ if ( !checkUpdate( urlStr ) )
+ return;
+
+ // A job can be running to
+ // - only list a new directory: the listers are in urlsCurrentlyListed
+ // - only update a directory: the listers are in urlsCurrentlyHeld
+ // - update a currently running listing: the listers are in urlsCurrentlyListed
+ // and urlsCurrentlyHeld
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+
+ // restart the job for _dir if it is running already
+ bool killed = false;
+ TQWidget *window = 0;
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ {
+ window = job->window();
+
+ killJob( job );
+ killed = true;
+
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->jobDone( job );
+
+ if ( holders )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobDone( job );
+ }
+ kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl;
+
+ // we don't need to emit canceled signals since we only replaced the job,
+ // the listing is continuing.
+
+ Q_ASSERT( !listers || (listers && killed) );
+
+ job = TDEIO::listDir( _dir, false /* no default GUI */ );
+ jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
+
+ connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
+ this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
+ connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
+ this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
+
+ kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl;
+
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->jobStarted( job );
+
+ if ( holders )
+ {
+ if ( !killed )
+ {
+ bool first = true;
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ kdl->jobStarted( job );
+ if ( first && kdl->d->window )
+ {
+ first = false;
+ job->setWindow( kdl->d->window );
+ }
+ emit kdl->started( _dir );
+ }
+ }
+ else
+ {
+ job->setWindow( window );
+
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobStarted( job );
+ }
+ }
+}
+
+bool KDirListerCache::checkUpdate( const TQString& _dir )
+{
+ if ( !itemsInUse[_dir] )
+ {
+ DirItem *item = itemsCached[_dir];
+ if ( item && item->complete )
+ {
+ item->complete = false;
+ item->decAutoUpdate();
+ // Hmm, this debug output might include login/password from the _dir URL.
+ //kdDebug(7004) << k_funcinfo << "directory " << _dir << " not in use, marked dirty." << endl;
+ }
+ //else
+ //kdDebug(7004) << k_funcinfo << "aborted, directory " << _dir << " not in cache." << endl;
+
+ return false;
+ }
+ else
+ return true;
+}
+
+KFileItemList *KDirListerCache::itemsForDir( const KURL &_dir ) const
+{
+ TQString urlStr = _dir.url(-1);
+ DirItem *item = itemsInUse[ urlStr ];
+ if ( !item )
+ item = itemsCached[ urlStr ];
+ return item ? item->lstItems : 0;
+}
+
+KFileItem *KDirListerCache::findByName( const KDirLister *lister, const TQString& _name ) const
+{
+ Q_ASSERT( lister );
+
+ for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
+ it != lister->d->lstDirs.end(); ++it )
+ {
+ KFileItemListIterator kit( *itemsInUse[(*it).url()]->lstItems );
+ for ( ; kit.current(); ++kit )
+ if ( (*kit)->name() == _name )
+ return (*kit);
+ }
+
+ return 0L;
+}
+
+KFileItem *KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const
+{
+ KURL _url = _u;
+ _url.adjustPath(-1);
+
+ KURL parentDir( _url );
+ parentDir.setPath( parentDir.directory() );
+
+ // If lister is set, check that it contains this dir
+ if ( lister && !lister->d->lstDirs.contains( parentDir ) )
+ return 0L;
+
+ KFileItemList *itemList = itemsForDir( parentDir );
+ if ( itemList )
+ {
+ KFileItemListIterator kit( *itemList );
+ for ( ; kit.current(); ++kit )
+ if ( (*kit)->url() == _url )
+ return (*kit);
+ }
+ return 0L;
+}
+
+void KDirListerCache::FilesAdded( const KURL &dir )
+{
+ kdDebug(7004) << k_funcinfo << dir << endl;
+ updateDirectory( dir );
+}
+
+void KDirListerCache::FilesRemoved( const KURL::List &fileList )
+{
+ kdDebug(7004) << k_funcinfo << endl;
+ KURL::List::ConstIterator it = fileList.begin();
+ for ( ; it != fileList.end() ; ++it )
+ {
+ // emit the deleteItem signal if this file was shown in any view
+ KFileItem *fileitem = 0L;
+ KURL parentDir( *it );
+ parentDir.setPath( parentDir.directory() );
+ KFileItemList *lstItems = itemsForDir( parentDir );
+ if ( lstItems )
+ {
+ KFileItem *fit = lstItems->first();
+ for ( ; fit; fit = lstItems->next() )
+ if ( fit->url() == *it ) {
+ fileitem = fit;
+ lstItems->take(); // remove fileitem from list
+ break;
+ }
+ }
+
+ // Tell the views about it before deleting the KFileItems. They might need the subdirs'
+ // file items (see the dirtree).
+ if ( fileitem )
+ {
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url()];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitDeleteItem( fileitem );
+ }
+
+ // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case.
+ if ( !fileitem || fileitem->isDir() )
+ {
+ // in case of a dir, check if we have any known children, there's much to do in that case
+ // (stopping jobs, removing dirs from cache etc.)
+ deleteDir( *it );
+ }
+
+ // now remove the item itself
+ delete fileitem;
+ }
+}
+
+void KDirListerCache::FilesChanged( const KURL::List &fileList )
+{
+ KURL::List dirsToUpdate;
+ kdDebug(7004) << k_funcinfo << "only half implemented" << endl;
+ KURL::List::ConstIterator it = fileList.begin();
+ for ( ; it != fileList.end() ; ++it )
+ {
+ if ( ( *it ).isLocalFile() )
+ {
+ kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl;
+ KFileItem *fileitem = findByURL( 0, *it );
+ if ( fileitem )
+ {
+ // we need to refresh the item, because e.g. the permissions can have changed.
+ aboutToRefreshItem( fileitem );
+ fileitem->refresh();
+ emitRefreshItem( fileitem );
+ }
+ else
+ kdDebug(7004) << "item not found" << endl;
+ } else {
+ // For remote files, refresh() won't be able to figure out the new information.
+ // Let's update the dir.
+ KURL dir( *it );
+ dir.setPath( dir.directory( true ) );
+ if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() )
+ dirsToUpdate.prepend( dir );
+ }
+ }
+
+ KURL::List::ConstIterator itdir = dirsToUpdate.begin();
+ for ( ; itdir != dirsToUpdate.end() ; ++itdir )
+ updateDirectory( *itdir );
+ // ## TODO problems with current jobs listing/updating that dir
+ // ( see kde-2.2.2's kdirlister )
+}
+
+void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst )
+{
+ kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl;
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ // Somehow this should only be called if src is a dir. But how could we know if it is?
+ // (Note that looking into itemsInUse isn't good enough. One could rename a subdir in a view.)
+ renameDir( src, dst );
+
+ // Now update the KFileItem representing that file or dir (not exclusive with the above!)
+ KURL oldurl( src );
+ oldurl.adjustPath( -1 );
+ KFileItem *fileitem = findByURL( 0, oldurl );
+ if ( fileitem )
+ {
+ if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() ) // it uses UDS_LOCAL_PATH? ouch, needs an update then
+ FilesChanged( src );
+ else
+ {
+ aboutToRefreshItem( fileitem );
+ fileitem->setURL( dst );
+ fileitem->refreshMimeType();
+ emitRefreshItem( fileitem );
+ }
+ }
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::aboutToRefreshItem( KFileItem *fileitem )
+{
+ // Look whether this item was shown in any view, i.e. held by any dirlister
+ KURL parentDir( fileitem->url() );
+ parentDir.setPath( parentDir.directory() );
+ TQString parentDirURL = parentDir.url();
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( fileitem );
+
+ // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
+ listers = urlsCurrentlyListed[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( fileitem );
+}
+
+void KDirListerCache::emitRefreshItem( KFileItem *fileitem )
+{
+ // Look whether this item was shown in any view, i.e. held by any dirlister
+ KURL parentDir( fileitem->url() );
+ parentDir.setPath( parentDir.directory() );
+ TQString parentDirURL = parentDir.url();
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->addRefreshItem( fileitem );
+ kdl->emitItems();
+ }
+
+ // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
+ listers = urlsCurrentlyListed[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->addRefreshItem( fileitem );
+ kdl->emitItems();
+ }
+}
+
+KDirListerCache* KDirListerCache::self()
+{
+ if ( !s_pSelf )
+ s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache );
+
+ return s_pSelf;
+}
+
+bool KDirListerCache::exists()
+{
+ return s_pSelf != 0;
+}
+
+
+// private slots
+
+// _file can also be a directory being currently held!
+void KDirListerCache::slotFileDirty( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+
+ if ( !pendingUpdates[_file] )
+ {
+ KURL dir;
+ dir.setPath( _file );
+ if ( checkUpdate( dir.url(-1) ) )
+ updateDirectory( dir );
+
+ // the parent directory of _file
+ dir.setPath( dir.directory() );
+ if ( checkUpdate( dir.url() ) )
+ {
+ // Nice hack to save memory: use the qt object name to store the filename
+ TQTimer *timer = new TQTimer( this, _file.utf8() );
+ connect( timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotFileDirtyDelayed()) );
+ pendingUpdates.insert( _file, timer );
+ timer->start( 500, true );
+ }
+ }
+}
+
+// delayed updating of files, FAM is flooding us with events
+void KDirListerCache::slotFileDirtyDelayed()
+{
+ TQString file = TQString::fromUtf8( TQT_TQOBJECT_CONST(sender())->name() );
+
+ kdDebug(7004) << k_funcinfo << file << endl;
+
+ // TODO: do it better: don't always create/delete the TQTimer but reuse it.
+ // Delete the timer after the parent directory is removed from the cache.
+ pendingUpdates.remove( file );
+
+ KURL u;
+ u.setPath( file );
+ KFileItem *item = findByURL( 0, u ); // search all items
+ if ( item )
+ {
+ // we need to refresh the item, because e.g. the permissions can have changed.
+ aboutToRefreshItem( item );
+ item->refresh();
+ emitRefreshItem( item );
+ }
+}
+
+void KDirListerCache::slotFileCreated( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+ // XXX: how to avoid a complete rescan here?
+ KURL u;
+ u.setPath( _file );
+ u.setPath( u.directory() );
+ FilesAdded( u );
+}
+
+void KDirListerCache::slotFileDeleted( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+ KURL u;
+ u.setPath( _file );
+ FilesRemoved( u );
+}
+
+void KDirListerCache::slotEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries )
+{
+ KURL url = joburl( static_cast<TDEIO::ListJob *>(job) );
+ url.adjustPath(-1);
+ TQString urlStr = url.url();
+
+ kdDebug(7004) << k_funcinfo << "new entries for " << url << endl;
+
+ DirItem *dir = itemsInUse[urlStr];
+ Q_ASSERT( dir );
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ Q_ASSERT( listers );
+ Q_ASSERT( !listers->isEmpty() );
+
+ // check if anyone wants the mimetypes immediately
+ bool delayedMimeTypes = true;
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
+
+ // avoid creating these QStrings again and again
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ TDEIO::UDSEntryListConstIterator it = entries.begin();
+ TDEIO::UDSEntryListConstIterator end = entries.end();
+
+ for ( ; it != end; ++it )
+ {
+ TQString name;
+
+ // find out about the name
+ TDEIO::UDSEntry::ConstIterator entit = (*it).begin();
+ for( ; entit != (*it).end(); ++entit )
+ if ( (*entit).m_uds == TDEIO::UDS_NAME )
+ {
+ name = (*entit).m_str;
+ break;
+ }
+
+ Q_ASSERT( !name.isEmpty() );
+ if ( name.isEmpty() )
+ continue;
+
+ if ( name == dot )
+ {
+ Q_ASSERT( !dir->rootItem );
+ dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ if ( !kdl->d->rootFileItem && kdl->d->url == url )
+ kdl->d->rootFileItem = dir->rootItem;
+ }
+ else if ( name != dotdot )
+ {
+ KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
+ Q_ASSERT( item );
+
+ //kdDebug(7004)<< "Adding item: " << item->url() << endl;
+ dir->lstItems->append( item );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addNewItem( item );
+ }
+ }
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitItems();
+}
+
+void KDirListerCache::slotResult( TDEIO::Job *j )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+ jobs.remove( job );
+
+ KURL jobUrl = joburl( job );
+ jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections
+ TQString jobUrlStr = jobUrl.url();
+
+ kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr );
+ Q_ASSERT( listers );
+
+ // move the directory to the held directories, do it before emitting
+ // the signals to make sure it exists in KDirListerCache in case someone
+ // calls listDir during the signal emission
+ Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr] );
+ urlsCurrentlyHeld.insert( jobUrlStr, listers );
+
+ KDirLister *kdl;
+
+ if ( job->error() )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+ kdl->handleError( job );
+ emit kdl->canceled( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->canceled();
+ }
+ }
+ }
+ else
+ {
+ DirItem *dir = itemsInUse[jobUrlStr];
+ Q_ASSERT( dir );
+ dir->complete = true;
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+ emit kdl->completed( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->completed();
+ }
+ }
+ }
+
+ // TODO: hmm, if there was an error and job is a parent of one or more
+ // of the pending urls we should cancel it/them as well
+ processPendingUpdates();
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::slotRedirection( TDEIO::Job *j, const KURL& url )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+
+ KURL oldUrl = job->url(); // here we really need the old url!
+ KURL newUrl = url;
+
+ // strip trailing slashes
+ oldUrl.adjustPath(-1);
+ newUrl.adjustPath(-1);
+
+ if ( oldUrl == newUrl )
+ {
+ kdDebug(7004) << k_funcinfo << "New redirection url same as old, giving up." << endl;
+ return;
+ }
+
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ // I don't think there can be dirItems that are childs of oldUrl.
+ // Am I wrong here? And even if so, we don't need to delete them, right?
+ // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
+
+ // oldUrl cannot be in itemsCached because only completed items are moved there
+ DirItem *dir = itemsInUse.take( oldUrl.url() );
+ Q_ASSERT( dir );
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() );
+ Q_ASSERT( listers );
+ Q_ASSERT( !listers->isEmpty() );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ // TODO: put in own method?
+ if ( kdl->d->url.equals( oldUrl, true ) )
+ {
+ kdl->d->rootFileItem = 0;
+ kdl->d->url = newUrl;
+ }
+
+ *kdl->d->lstDirs.find( oldUrl ) = newUrl;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ {
+ emit kdl->clear();
+ emit kdl->redirection( newUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ else
+ {
+ emit kdl->clear( oldUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ }
+
+ // when a lister was stopped before the job emits the redirection signal, the old url will
+ // also be in urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrl.url() );
+ if ( holders )
+ {
+ Q_ASSERT( !holders->isEmpty() );
+
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ kdl->jobStarted( job );
+
+ // do it like when starting a new list-job that will redirect later
+ emit kdl->started( oldUrl );
+
+ // TODO: maybe don't emit started if there's an update running for newUrl already?
+
+ if ( kdl->d->url.equals( oldUrl, true ) )
+ {
+ kdl->d->rootFileItem = 0;
+ kdl->d->url = newUrl;
+ }
+
+ *kdl->d->lstDirs.find( oldUrl ) = newUrl;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ {
+ emit kdl->clear();
+ emit kdl->redirection( newUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ else
+ {
+ emit kdl->clear( oldUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ }
+ }
+
+ DirItem *newDir = itemsInUse[newUrl.url()];
+ if ( newDir )
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " already in use" << endl;
+
+ // only in this case there can newUrl already be in urlsCurrentlyListed or urlsCurrentlyHeld
+ delete dir;
+
+ // get the job if one's running for newUrl already (can be a list-job or an update-job), but
+ // do not return this 'job', which would happen because of the use of redirectionURL()
+ TDEIO::ListJob *oldJob = jobForUrl( newUrl.url(), job );
+
+ // listers of newUrl with oldJob: forget about the oldJob and use the already running one
+ // which will be converted to an updateJob
+ TQPtrList<KDirLister> *curListers = urlsCurrentlyListed[newUrl.url()];
+ if ( curListers )
+ {
+ kdDebug(7004) << "slotRedirection: and it is currently listed" << endl;
+
+ Q_ASSERT( oldJob ); // ?!
+
+ for ( KDirLister *kdl = curListers->first(); kdl; kdl = curListers->next() ) // listers of newUrl
+ {
+ kdl->jobDone( oldJob );
+
+ kdl->jobStarted( job );
+ kdl->connectJob( job );
+ }
+
+ // append listers of oldUrl with newJob to listers of newUrl with oldJob
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ curListers->append( kdl );
+ }
+ else
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+
+ if ( oldJob ) // kill the old job, be it a list-job or an update-job
+ killJob( oldJob );
+
+ // holders of newUrl: use the already running job which will be converted to an updateJob
+ TQPtrList<KDirLister> *curHolders = urlsCurrentlyHeld[newUrl.url()];
+ if ( curHolders )
+ {
+ kdDebug(7004) << "slotRedirection: and it is currently held." << endl;
+
+ for ( KDirLister *kdl = curHolders->first(); kdl; kdl = curHolders->next() ) // holders of newUrl
+ {
+ kdl->jobStarted( job );
+ emit kdl->started( newUrl );
+ }
+
+ // append holders of oldUrl to holders of newUrl
+ if ( holders )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ curHolders->append( kdl );
+ }
+ else if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+
+
+ // emit old items: listers, holders. NOT: newUrlListers/newUrlHolders, they already have them listed
+ // TODO: make this a separate method?
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+
+ if ( holders )
+ {
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+ }
+ }
+ else if ( (newDir = itemsCached.take( newUrl.url() )) )
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " is unused, but already in the cache." << endl;
+
+ delete dir;
+ itemsInUse.insert( newUrl.url(), newDir );
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+ if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+
+ // emit old items: listers, holders
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+
+ if ( holders )
+ {
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+ }
+ }
+ else
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " has not been listed yet." << endl;
+
+ delete dir->rootItem;
+ dir->rootItem = 0;
+ dir->lstItems->clear();
+ dir->redirect( newUrl );
+ itemsInUse.insert( newUrl.url(), dir );
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+
+ if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+ else
+ {
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ return; // only in this case the job doesn't need to be converted,
+ }
+ }
+
+ // make the job an update job
+ job->disconnect( this );
+
+ connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
+ this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
+ connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
+ this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
+
+ // FIXME: autoUpdate-Counts!!
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
+{
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
+ TQString oldUrlStr = oldUrl.url(-1);
+ TQString newUrlStr = newUrl.url(-1);
+
+ // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
+ //DirItem *dir = itemsInUse.take( oldUrlStr );
+ //emitRedirections( oldUrl, url );
+
+ // Look at all dirs being listed/shown
+ TQDictIterator<DirItem> itu( itemsInUse );
+ bool goNext;
+ while ( itu.current() )
+ {
+ goNext = true;
+ DirItem *dir = itu.current();
+ KURL oldDirUrl ( itu.currentKey() );
+ //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl;
+ // Check if this dir is oldUrl, or a subfolder of it
+ if ( oldUrl.isParentOf( oldDirUrl ) )
+ {
+ // TODO should use KURL::cleanpath like isParentOf does
+ TQString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
+
+ KURL newDirUrl( newUrl ); // take new base
+ if ( !relPath.isEmpty() )
+ newDirUrl.addPath( relPath ); // add unchanged relative path
+ //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl;
+
+ // Update URL in dir item and in itemsInUse
+ dir->redirect( newDirUrl );
+ itemsInUse.remove( itu.currentKey() ); // implies ++itu
+ itemsInUse.insert( newDirUrl.url(-1), dir );
+ goNext = false; // because of the implied ++itu above
+ if ( dir->lstItems )
+ {
+ // Rename all items under that dir
+ KFileItemListIterator kit( *dir->lstItems );
+ for ( ; kit.current(); ++kit )
+ {
+ KURL oldItemUrl = (*kit)->url();
+ TQString oldItemUrlStr( oldItemUrl.url(-1) );
+ KURL newItemUrl( oldItemUrl );
+ newItemUrl.setPath( newDirUrl.path() );
+ newItemUrl.addPath( oldItemUrl.fileName() );
+ kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
+ (*kit)->setURL( newItemUrl );
+ }
+ }
+ emitRedirections( oldDirUrl, newDirUrl );
+ }
+ if ( goNext )
+ ++itu;
+ }
+
+ // Is oldUrl a directory in the cache?
+ // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
+ removeDirFromCache( oldUrl );
+ // TODO rename, instead.
+}
+
+void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
+{
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
+ TQString oldUrlStr = oldUrl.url(-1);
+ TQString urlStr = url.url(-1);
+
+ TDEIO::ListJob *job = jobForUrl( oldUrlStr );
+ if ( job )
+ killJob( job );
+
+ // Check if we were listing this dir. Need to abort and restart with new name in that case.
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr );
+ if ( listers )
+ {
+ // Tell the world that the job listing the old url is dead.
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( job )
+ kdl->jobDone( job );
+
+ emit kdl->canceled( oldUrl );
+ }
+
+ urlsCurrentlyListed.insert( urlStr, listers );
+ }
+
+ // Check if we are currently displaying this directory (odds opposite wrt above)
+ // Update urlsCurrentlyHeld dict with new URL
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr );
+ if ( holders )
+ {
+ if ( job )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobDone( job );
+
+ urlsCurrentlyHeld.insert( urlStr, holders );
+ }
+
+ if ( listers )
+ {
+ updateDirectory( url );
+
+ // Tell the world about the new url
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ emit kdl->started( url );
+ }
+
+ if ( holders )
+ {
+ // And notify the dirlisters of the redirection
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ *kdl->d->lstDirs.find( oldUrl ) = url;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ emit kdl->redirection( url );
+
+ emit kdl->redirection( oldUrl, url );
+ }
+ }
+}
+
+void KDirListerCache::removeDirFromCache( const KURL& dir )
+{
+ kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
+ TQCacheIterator<DirItem> itc( itemsCached );
+ while ( itc.current() )
+ {
+ if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
+ itemsCached.remove( itc.currentKey() );
+ else
+ ++itc;
+ }
+}
+
+void KDirListerCache::slotUpdateEntries( TDEIO::Job* job, const TDEIO::UDSEntryList& list )
+{
+ jobs[static_cast<TDEIO::ListJob*>(job)] += list;
+}
+
+void KDirListerCache::slotUpdateResult( TDEIO::Job * j )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+
+ KURL jobUrl = joburl( job );
+ jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections
+ TQString jobUrlStr = jobUrl.url();
+
+ kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
+
+ KDirLister *kdl;
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr];
+ TQPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr );
+
+ if ( tmpLst )
+ {
+ if ( listers )
+ for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
+ {
+ Q_ASSERT( listers->containsRef( kdl ) == 0 );
+ listers->append( kdl );
+ }
+ else
+ {
+ listers = tmpLst;
+ urlsCurrentlyHeld.insert( jobUrlStr, listers );
+ }
+ }
+
+ // once we are updating dirs that are only in the cache this will fail!
+ Q_ASSERT( listers );
+
+ if ( job->error() )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+
+ //don't bother the user
+ //kdl->handleError( job );
+
+ emit kdl->canceled( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->canceled();
+ }
+ }
+
+ jobs.remove( job );
+
+ // TODO: if job is a parent of one or more
+ // of the pending urls we should cancel them
+ processPendingUpdates();
+ return;
+ }
+
+ DirItem *dir = itemsInUse[jobUrlStr];
+ dir->complete = true;
+
+
+ // check if anyone wants the mimetypes immediately
+ bool delayedMimeTypes = true;
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
+
+ // should be enough to get reasonable speed in most cases
+ TQDict<KFileItem> fileItems( 9973 );
+
+ KFileItemListIterator kit ( *(dir->lstItems) );
+
+ // Unmark all items in url
+ for ( ; kit.current(); ++kit )
+ {
+ (*kit)->unmark();
+ fileItems.insert( (*kit)->url().url(), *kit );
+ }
+
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ KFileItem *item = 0, *tmp;
+
+ TQValueList<TDEIO::UDSEntry> buf = jobs[job];
+ TQValueListIterator<TDEIO::UDSEntry> it = buf.begin();
+ for ( ; it != buf.end(); ++it )
+ {
+ // Form the complete url
+ if ( !item )
+ item = new KFileItem( *it, jobUrl, delayedMimeTypes, true );
+ else
+ item->setUDSEntry( *it, jobUrl, delayedMimeTypes, true );
+
+ // Find out about the name
+ TQString name = item->name();
+ Q_ASSERT( !name.isEmpty() );
+
+ // we duplicate the check for dotdot here, to avoid iterating over
+ // all items again and checking in matchesFilter() that way.
+ if ( name.isEmpty() || name == dotdot )
+ continue;
+
+ if ( name == dot )
+ {
+ // if the update was started before finishing the original listing
+ // there is no root item yet
+ if ( !dir->rootItem )
+ {
+ dir->rootItem = item;
+ item = 0;
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl )
+ kdl->d->rootFileItem = dir->rootItem;
+ }
+
+ continue;
+ }
+
+ // Find this item
+ if ( (tmp = fileItems[item->url().url()]) )
+ {
+ tmp->mark();
+
+ // check if something changed for this file
+ if ( !tmp->cmp( *item ) )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( tmp );
+
+ //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl;
+ tmp->assign( *item );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addRefreshItem( tmp );
+ }
+ }
+ else // this is a new file
+ {
+ //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl;
+
+ item->mark();
+ dir->lstItems->append( item );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addNewItem( item );
+
+ // item used, we need a new one for the next iteration
+ item = 0;
+ }
+ }
+
+ if ( item )
+ delete item;
+
+ jobs.remove( job );
+
+ deleteUnmarkedItems( listers, dir->lstItems );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->emitItems();
+
+ kdl->jobDone( job );
+
+ emit kdl->completed( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->completed();
+ }
+ }
+
+ // TODO: hmm, if there was an error and job is a parent of one or more
+ // of the pending urls we should cancel it/them as well
+ processPendingUpdates();
+}
+
+// private
+
+TDEIO::ListJob *KDirListerCache::jobForUrl( const TQString& url, TDEIO::ListJob *not_job )
+{
+ TDEIO::ListJob *job;
+ TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator it = jobs.begin();
+ while ( it != jobs.end() )
+ {
+ job = it.key();
+ if ( joburl( job ).url(-1) == url && job != not_job )
+ return job;
+ ++it;
+ }
+ return 0;
+}
+
+const KURL& KDirListerCache::joburl( TDEIO::ListJob *job )
+{
+ if ( job->redirectionURL().isValid() )
+ return job->redirectionURL();
+ else
+ return job->url();
+}
+
+void KDirListerCache::killJob( TDEIO::ListJob *job )
+{
+ jobs.remove( job );
+ job->disconnect( this );
+ job->kill();
+}
+
+void KDirListerCache::deleteUnmarkedItems( TQPtrList<KDirLister> *listers, KFileItemList *lstItems )
+{
+ // Find all unmarked items and delete them
+ KFileItem* item;
+ lstItems->first();
+ while ( (item = lstItems->current()) )
+ if ( !item->isMarked() )
+ {
+ //kdDebug() << k_funcinfo << item->name() << endl;
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitDeleteItem( item );
+
+ if ( item->isDir() )
+ deleteDir( item->url() );
+
+ // finally actually delete the item
+ lstItems->take();
+ delete item;
+ }
+ else
+ lstItems->next();
+}
+
+void KDirListerCache::deleteDir( const KURL& dirUrl )
+{
+ //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl;
+ // unregister and remove the childs of the deleted item.
+ // Idea: tell all the KDirListers that they should forget the dir
+ // and then remove it from the cache.
+
+ TQDictIterator<DirItem> itu( itemsInUse );
+ while ( itu.current() )
+ {
+ KURL deletedUrl( itu.currentKey() );
+ if ( dirUrl.isParentOf( deletedUrl ) )
+ {
+ // stop all jobs for deletedUrl
+
+ TQPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url()];
+ if ( kdls ) // yeah, I lack good names
+ {
+ // we need a copy because stop modifies the list
+ kdls = new TQPtrList<KDirLister>( *kdls );
+ for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
+ stop( kdl, deletedUrl );
+
+ delete kdls;
+ }
+
+ // tell listers holding deletedUrl to forget about it
+ // this will stop running updates for deletedUrl as well
+
+ kdls = urlsCurrentlyHeld[deletedUrl.url()];
+ if ( kdls )
+ {
+ // we need a copy because forgetDirs modifies the list
+ kdls = new TQPtrList<KDirLister>( *kdls );
+
+ for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
+ {
+ // lister's root is the deleted item
+ if ( kdl->d->url == deletedUrl )
+ {
+ // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
+ if ( kdl->d->rootFileItem )
+ emit kdl->deleteItem( kdl->d->rootFileItem );
+ forgetDirs( kdl );
+ kdl->d->rootFileItem = 0;
+ }
+ else
+ {
+ bool treeview = kdl->d->lstDirs.count() > 1;
+ if ( !treeview )
+ emit kdl->clear();
+
+ forgetDirs( kdl, deletedUrl, treeview );
+ }
+ }
+
+ delete kdls;
+ }
+
+ // delete the entry for deletedUrl - should not be needed, it's in
+ // items cached now
+
+ DirItem *dir = itemsInUse.take( deletedUrl.url() );
+ Q_ASSERT( !dir );
+ if ( !dir ) // take didn't find it - move on
+ ++itu;
+ }
+ else
+ ++itu;
+ }
+
+ // remove the children from the cache
+ removeDirFromCache( dirUrl );
+}
+
+void KDirListerCache::processPendingUpdates()
+{
+ // TODO
+}
+
+#ifndef NDEBUG
+void KDirListerCache::printDebug()
+{
+ kdDebug(7004) << "Items in use: " << endl;
+ TQDictIterator<DirItem> itu( itemsInUse );
+ for ( ; itu.current() ; ++itu ) {
+ kdDebug(7004) << " " << itu.currentKey() << " URL: " << itu.current()->url
+ << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() )
+ << " autoUpdates refcount: " << itu.current()->autoUpdates
+ << " complete: " << itu.current()->complete
+ << ( itu.current()->lstItems ? TQString(" with %1 items.").arg(itu.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
+ }
+
+ kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
+ TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyHeld );
+ for ( ; it.current() ; ++it )
+ {
+ TQString list;
+ for ( TQPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
+ list += " 0x" + TQString::number( (long)listit.current(), 16 );
+ kdDebug(7004) << " " << it.currentKey() << " " << it.current()->count() << " listers: " << list << endl;
+ }
+
+ kdDebug(7004) << "urlsCurrentlyListed: " << endl;
+ TQDictIterator< TQPtrList<KDirLister> > it2( urlsCurrentlyListed );
+ for ( ; it2.current() ; ++it2 )
+ {
+ TQString list;
+ for ( TQPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
+ list += " 0x" + TQString::number( (long)listit.current(), 16 );
+ kdDebug(7004) << " " << it2.currentKey() << " " << it2.current()->count() << " listers: " << list << endl;
+ }
+
+ TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator jit = jobs.begin();
+ kdDebug(7004) << "Jobs: " << endl;
+ for ( ; jit != jobs.end() ; ++jit )
+ kdDebug(7004) << " " << jit.key() << " listing " << joburl( jit.key() ).prettyURL() << ": " << (*jit).count() << " entries." << endl;
+
+ kdDebug(7004) << "Items in cache: " << endl;
+ TQCacheIterator<DirItem> itc( itemsCached );
+ for ( ; itc.current() ; ++itc )
+ kdDebug(7004) << " " << itc.currentKey() << " rootItem: "
+ << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : TQString("NULL") )
+ << ( itc.current()->lstItems ? TQString(" with %1 items.").arg(itc.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
+}
+#endif
+
+/*********************** -- The new KDirLister -- ************************/
+
+
+KDirLister::KDirLister( bool _delayedMimeTypes )
+{
+ kdDebug(7003) << "+KDirLister" << endl;
+
+ d = new KDirListerPrivate;
+
+ d->complete = true;
+ d->delayedMimeTypes = _delayedMimeTypes;
+
+ setAutoUpdate( true );
+ setDirOnlyMode( false );
+ setShowingDotFiles( false );
+
+ setAutoErrorHandlingEnabled( true, 0 );
+}
+
+KDirLister::~KDirLister()
+{
+ kdDebug(7003) << "-KDirLister" << endl;
+
+ if ( KDirListerCache::exists() )
+ {
+ // Stop all running jobs
+ stop();
+ s_pCache->forgetDirs( this );
+ }
+
+ delete d;
+}
+
+bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
+{
+ kdDebug(7003) << k_funcinfo << _url.prettyURL()
+ << " keep=" << _keep << " reload=" << _reload << endl;
+
+ // emit the current changes made to avoid an inconsistent treeview
+ if ( d->changes != NONE && _keep )
+ emitChanges();
+
+ d->changes = NONE;
+
+ // If a local path is available, monitor that instead of the given remote URL...
+ KURL realURL = _url;
+ if (!realURL.isLocalFile()) {
+ TDEIO::LocalURLJob* localURLJob = TDEIO::localURL(_url);
+ if (localURLJob) {
+ connect(localURLJob, TQT_SIGNAL(localURL(TDEIO::Job*, const KURL&, bool)), this, TQT_SLOT(slotLocalURL(TDEIO::Job*, const KURL&, bool)));
+ connect(localURLJob, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotLocalURLKIODestroyed()));
+ d->localURLSlotFired = false;
+ while (!d->localURLSlotFired) {
+ tqApp->eventLoop()->processEvents(TQEventLoop::ExcludeUserInput);
+ usleep(1000);
+ }
+ if (d->localURLResultIsLocal) {
+ realURL = d->localURLResultURL;
+ }
+ }
+ }
+
+ return s_pCache->listDir( this, realURL, _keep, _reload );
+}
+
+void KDirLister::slotLocalURL(TDEIO::Job *job, const KURL& url, bool isLocal) {
+ d->localURLSlotFired = true;
+ d->localURLResultURL = url;
+ d->localURLResultIsLocal = isLocal;
+}
+
+void KDirLister::slotLocalURLKIODestroyed() {
+ if (!d->localURLSlotFired) {
+ d->localURLSlotFired = true;
+ d->localURLResultURL = KURL();
+ d->localURLResultIsLocal = false;
+ }
+}
+
+void KDirLister::stop()
+{
+ kdDebug(7003) << k_funcinfo << endl;
+ s_pCache->stop( this );
+}
+
+void KDirLister::stop( const KURL& _url )
+{
+ kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
+ s_pCache->stop( this, _url );
+}
+
+bool KDirLister::autoUpdate() const
+{
+ return d->autoUpdate;
+}
+
+void KDirLister::setAutoUpdate( bool _enable )
+{
+ if ( d->autoUpdate == _enable )
+ return;
+
+ d->autoUpdate = _enable;
+ s_pCache->setAutoUpdate( this, _enable );
+}
+
+bool KDirLister::showingDotFiles() const
+{
+ return d->isShowingDotFiles;
+}
+
+void KDirLister::setShowingDotFiles( bool _showDotFiles )
+{
+ if ( d->isShowingDotFiles == _showDotFiles )
+ return;
+
+ d->isShowingDotFiles = _showDotFiles;
+ d->changes ^= DOT_FILES;
+}
+
+bool KDirLister::dirOnlyMode() const
+{
+ return d->dirOnlyMode;
+}
+
+void KDirLister::setDirOnlyMode( bool _dirsOnly )
+{
+ if ( d->dirOnlyMode == _dirsOnly )
+ return;
+
+ d->dirOnlyMode = _dirsOnly;
+ d->changes ^= DIR_ONLY_MODE;
+}
+
+bool KDirLister::autoErrorHandlingEnabled() const
+{
+ return d->autoErrorHandling;
+}
+
+void KDirLister::setAutoErrorHandlingEnabled( bool enable, TQWidget* parent )
+{
+ d->autoErrorHandling = enable;
+ d->errorParent = parent;
+}
+
+const KURL& KDirLister::url() const
+{
+ return d->url;
+}
+
+const KURL::List& KDirLister::directories() const
+{
+ return d->lstDirs;
+}
+
+void KDirLister::emitChanges()
+{
+ if ( d->changes == NONE )
+ return;
+
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ for ( KURL::List::Iterator it = d->lstDirs.begin();
+ it != d->lstDirs.end(); ++it )
+ {
+ KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
+ for ( ; kit.current(); ++kit )
+ {
+ if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
+ continue;
+
+ bool oldMime = true, newMime = true;
+
+ if ( d->changes & MIME_FILTER )
+ {
+ oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
+ && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
+ newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
+ && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
+
+ if ( oldMime && !newMime )
+ {
+ emit deleteItem( *kit );
+ continue;
+ }
+ }
+
+ if ( d->changes & DIR_ONLY_MODE )
+ {
+ // the lister switched to dirOnlyMode
+ if ( d->dirOnlyMode )
+ {
+ if ( !(*kit)->isDir() )
+ emit deleteItem( *kit );
+ }
+ else if ( !(*kit)->isDir() )
+ addNewItem( *kit );
+
+ continue;
+ }
+
+ if ( (*kit)->isHidden() )
+ {
+ if ( d->changes & DOT_FILES )
+ {
+ // the lister switched to dot files mode
+ if ( d->isShowingDotFiles )
+ addNewItem( *kit );
+ else
+ emit deleteItem( *kit );
+
+ continue;
+ }
+ }
+ else if ( d->changes & NAME_FILTER )
+ {
+ bool oldName = (*kit)->isDir() ||
+ d->oldFilters.isEmpty() ||
+ doNameFilter( (*kit)->text(), d->oldFilters );
+
+ bool newName = (*kit)->isDir() ||
+ d->lstFilters.isEmpty() ||
+ doNameFilter( (*kit)->text(), d->lstFilters );
+
+ if ( oldName && !newName )
+ {
+ emit deleteItem( *kit );
+ continue;
+ }
+ else if ( !oldName && newName )
+ addNewItem( *kit );
+ }
+
+ if ( (d->changes & MIME_FILTER) && !oldMime && newMime )
+ addNewItem( *kit );
+ }
+
+ emitItems();
+ }
+
+ d->changes = NONE;
+}
+
+void KDirLister::updateDirectory( const KURL& _u )
+{
+ s_pCache->updateDirectory( _u );
+}
+
+bool KDirLister::isFinished() const
+{
+ return d->complete;
+}
+
+KFileItem *KDirLister::rootItem() const
+{
+ return d->rootFileItem;
+}
+
+KFileItem *KDirLister::findByURL( const KURL& _url ) const
+{
+ return s_pCache->findByURL( this, _url );
+}
+
+KFileItem *KDirLister::findByName( const TQString& _name ) const
+{
+ return s_pCache->findByName( this, _name );
+}
+
+#ifndef KDE_NO_COMPAT
+KFileItem *KDirLister::find( const KURL& _url ) const
+{
+ return findByURL( _url );
+}
+#endif
+
+
+// ================ public filter methods ================ //
+
+void KDirLister::setNameFilter( const TQString& nameFilter )
+{
+ if ( !(d->changes & NAME_FILTER) )
+ {
+ d->oldFilters = d->lstFilters;
+ d->lstFilters.setAutoDelete( false );
+ }
+
+ d->lstFilters.clear();
+ d->lstFilters.setAutoDelete( true );
+
+ d->nameFilter = nameFilter;
+
+ // Split on white space
+ TQStringList list = TQStringList::split( ' ', nameFilter );
+ for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ d->lstFilters.append( new TQRegExp(*it, false, true ) );
+
+ d->changes |= NAME_FILTER;
+}
+
+const TQString& KDirLister::nameFilter() const
+{
+ return d->nameFilter;
+}
+
+void KDirLister::setMimeFilter( const TQStringList& mimeFilter )
+{
+ if ( !(d->changes & MIME_FILTER) )
+ d->oldMimeFilter = d->mimeFilter;
+
+ if ( mimeFilter.find("all/allfiles") != mimeFilter.end() ||
+ mimeFilter.find("all/all") != mimeFilter.end() )
+ d->mimeFilter.clear();
+ else
+ d->mimeFilter = mimeFilter;
+
+ d->changes |= MIME_FILTER;
+}
+
+void KDirLister::setMimeExcludeFilter( const TQStringList& mimeExcludeFilter )
+{
+ if ( !(d->changes & MIME_FILTER) )
+ d->oldMimeExcludeFilter = d->mimeExcludeFilter;
+
+ d->mimeExcludeFilter = mimeExcludeFilter;
+ d->changes |= MIME_FILTER;
+}
+
+
+void KDirLister::clearMimeFilter()
+{
+ if ( !(d->changes & MIME_FILTER) )
+ {
+ d->oldMimeFilter = d->mimeFilter;
+ d->oldMimeExcludeFilter = d->mimeExcludeFilter;
+ }
+ d->mimeFilter.clear();
+ d->mimeExcludeFilter.clear();
+ d->changes |= MIME_FILTER;
+}
+
+const TQStringList& KDirLister::mimeFilters() const
+{
+ return d->mimeFilter;
+}
+
+bool KDirLister::matchesFilter( const TQString& name ) const
+{
+ return doNameFilter( name, d->lstFilters );
+}
+
+bool KDirLister::matchesMimeFilter( const TQString& mime ) const
+{
+ return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
+}
+
+// ================ protected methods ================ //
+
+bool KDirLister::matchesFilter( const KFileItem *item ) const
+{
+ Q_ASSERT( item );
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ if ( item->text() == dotdot )
+ return false;
+
+ if ( !d->isShowingDotFiles && item->isHidden() )
+ return false;
+
+ if ( item->isDir() || d->lstFilters.isEmpty() )
+ return true;
+
+ return matchesFilter( item->text() );
+}
+
+bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
+{
+ Q_ASSERT( item );
+ // Don't lose time determining the mimetype if there is no filter
+ if ( d->mimeFilter.isEmpty() && d->mimeExcludeFilter.isEmpty() )
+ return true;
+ return matchesMimeFilter( item->mimetype() );
+}
+
+bool KDirLister::doNameFilter( const TQString& name, const TQPtrList<TQRegExp>& filters ) const
+{
+ for ( TQPtrListIterator<TQRegExp> it( filters ); it.current(); ++it )
+ if ( it.current()->exactMatch( name ) )
+ return true;
+
+ return false;
+}
+
+bool KDirLister::doMimeFilter( const TQString& mime, const TQStringList& filters ) const
+{
+ if ( filters.isEmpty() )
+ return true;
+
+ KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
+ //kdDebug(7004) << "doMimeFilter: investigating: "<<mimeptr->name()<<endl;
+ TQStringList::ConstIterator it = filters.begin();
+ for ( ; it != filters.end(); ++it )
+ if ( mimeptr->is(*it) )
+ return true;
+ //else kdDebug(7004) << "doMimeFilter: compared without result to "<<*it<<endl;
+
+
+ return false;
+}
+
+bool KDirLister::doMimeExcludeFilter( const TQString& mime, const TQStringList& filters ) const
+{
+ if ( filters.isEmpty() )
+ return true;
+
+ TQStringList::ConstIterator it = filters.begin();
+ for ( ; it != filters.end(); ++it )
+ if ( (*it) == mime )
+ return false;
+
+ return true;
+}
+
+
+bool KDirLister::validURL( const KURL& _url ) const
+{
+ return s_pCache->validURL( this, _url );
+}
+
+void KDirLister::handleError( TDEIO::Job *job )
+{
+ if ( d->autoErrorHandling )
+ job->showErrorDialog( d->errorParent );
+}
+
+
+// ================= private methods ================= //
+
+void KDirLister::addNewItem( const KFileItem *item )
+{
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ return; // No reason to continue... bailing out here prevents a mimetype scan.
+
+ if ( matchesMimeFilter( item ) )
+ {
+ if ( !d->lstNewItems )
+ d->lstNewItems = new KFileItemList;
+
+ d->lstNewItems->append( item ); // items not filtered
+ }
+ else
+ {
+ if ( !d->lstMimeFilteredItems )
+ d->lstMimeFilteredItems = new KFileItemList;
+
+ d->lstMimeFilteredItems->append( item ); // only filtered by mime
+ }
+}
+
+void KDirLister::addNewItems( const KFileItemList& items )
+{
+ // TODO: make this faster - test if we have a filter at all first
+ // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters...
+ // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good.
+ // But that's for Qt4, not possible with TQPtrList.
+ for ( KFileItemListIterator kit( items ); kit.current(); ++kit )
+ addNewItem( *kit );
+}
+
+void KDirLister::aboutToRefreshItem( const KFileItem *item )
+{
+ // The code here follows the logic in addNewItem
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ d->refreshItemWasFiltered = true;
+ else if ( !matchesMimeFilter( item ) )
+ d->refreshItemWasFiltered = true;
+ else
+ d->refreshItemWasFiltered = false;
+}
+
+void KDirLister::addRefreshItem( const KFileItem *item )
+{
+ bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
+
+ if ( !isExcluded && matchesMimeFilter( item ) )
+ {
+ if ( d->refreshItemWasFiltered )
+ {
+ if ( !d->lstNewItems )
+ d->lstNewItems = new KFileItemList;
+
+ d->lstNewItems->append( item );
+ }
+ else
+ {
+ if ( !d->lstRefreshItems )
+ d->lstRefreshItems = new KFileItemList;
+
+ d->lstRefreshItems->append( item );
+ }
+ }
+ else if ( !d->refreshItemWasFiltered )
+ {
+ if ( !d->lstRemoveItems )
+ d->lstRemoveItems = new KFileItemList;
+
+ // notify the user that the mimetype of a file changed that doesn't match
+ // a filter or does match an exclude filter
+ d->lstRemoveItems->append( item );
+ }
+}
+
+void KDirLister::emitItems()
+{
+ KFileItemList *tmpNew = d->lstNewItems;
+ d->lstNewItems = 0;
+
+ KFileItemList *tmpMime = d->lstMimeFilteredItems;
+ d->lstMimeFilteredItems = 0;
+
+ KFileItemList *tmpRefresh = d->lstRefreshItems;
+ d->lstRefreshItems = 0;
+
+ KFileItemList *tmpRemove = d->lstRemoveItems;
+ d->lstRemoveItems = 0;
+
+ if ( tmpNew )
+ {
+ emit newItems( *tmpNew );
+ delete tmpNew;
+ }
+
+ if ( tmpMime )
+ {
+ emit itemsFilteredByMime( *tmpMime );
+ delete tmpMime;
+ }
+
+ if ( tmpRefresh )
+ {
+ emit refreshItems( *tmpRefresh );
+ delete tmpRefresh;
+ }
+
+ if ( tmpRemove )
+ {
+ for ( KFileItem *tmp = tmpRemove->first(); tmp; tmp = tmpRemove->next() )
+ emit deleteItem( tmp );
+ delete tmpRemove;
+ }
+}
+
+void KDirLister::emitDeleteItem( KFileItem *item )
+{
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ return; // No reason to continue... bailing out here prevents a mimetype scan.
+ if ( matchesMimeFilter( item ) )
+ emit deleteItem( item );
+}
+
+
+// ================ private slots ================ //
+
+void KDirLister::slotInfoMessage( TDEIO::Job *, const TQString& message )
+{
+ emit infoMessage( message );
+}
+
+void KDirLister::slotPercent( TDEIO::Job *job, unsigned long pcnt )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].percent = pcnt;
+
+ int result = 0;
+
+ TDEIO::filesize_t size = 0;
+
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).percent * (*dataIt).totalSize;
+ size += (*dataIt).totalSize;
+ ++dataIt;
+ }
+
+ if ( size != 0 )
+ result /= size;
+ else
+ result = 100;
+ emit percent( result );
+}
+
+void KDirLister::slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].totalSize = size;
+
+ TDEIO::filesize_t result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).totalSize;
+ ++dataIt;
+ }
+
+ emit totalSize( result );
+}
+
+void KDirLister::slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].processedSize = size;
+
+ TDEIO::filesize_t result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).processedSize;
+ ++dataIt;
+ }
+
+ emit processedSize( result );
+}
+
+void KDirLister::slotSpeed( TDEIO::Job *job, unsigned long spd )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].speed = spd;
+
+ int result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).speed;
+ ++dataIt;
+ }
+
+ emit speed( result );
+}
+
+uint KDirLister::numJobs()
+{
+ return d->jobData.count();
+}
+
+void KDirLister::jobDone( TDEIO::ListJob *job )
+{
+ d->jobData.remove( job );
+}
+
+void KDirLister::jobStarted( TDEIO::ListJob *job )
+{
+ KDirListerPrivate::JobData jobData;
+ jobData.speed = 0;
+ jobData.percent = 0;
+ jobData.processedSize = 0;
+ jobData.totalSize = 0;
+
+ d->jobData.insert( job, jobData );
+ d->complete = false;
+}
+
+void KDirLister::connectJob( TDEIO::ListJob *job )
+{
+ connect( job, TQT_SIGNAL(infoMessage( TDEIO::Job *, const TQString& )),
+ this, TQT_SLOT(slotInfoMessage( TDEIO::Job *, const TQString& )) );
+ connect( job, TQT_SIGNAL(percent( TDEIO::Job *, unsigned long )),
+ this, TQT_SLOT(slotPercent( TDEIO::Job *, unsigned long )) );
+ connect( job, TQT_SIGNAL(totalSize( TDEIO::Job *, TDEIO::filesize_t )),
+ this, TQT_SLOT(slotTotalSize( TDEIO::Job *, TDEIO::filesize_t )) );
+ connect( job, TQT_SIGNAL(processedSize( TDEIO::Job *, TDEIO::filesize_t )),
+ this, TQT_SLOT(slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t )) );
+ connect( job, TQT_SIGNAL(speed( TDEIO::Job *, unsigned long )),
+ this, TQT_SLOT(slotSpeed( TDEIO::Job *, unsigned long )) );
+}
+
+void KDirLister::setMainWindow( TQWidget *window )
+{
+ d->window = window;
+}
+
+TQWidget *KDirLister::mainWindow()
+{
+ return d->window;
+}
+
+KFileItemList KDirLister::items( WhichItems which ) const
+{
+ return itemsForDir( url(), which );
+}
+
+KFileItemList KDirLister::itemsForDir( const KURL& dir, WhichItems which ) const
+{
+ KFileItemList result;
+ KFileItemList *allItems = s_pCache->itemsForDir( dir );
+ if ( !allItems )
+ return result;
+
+ if ( which == AllItems )
+ result = *allItems; // shallow copy
+ else // only items passing the filters
+ {
+ for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
+ {
+ KFileItem *item = *kit;
+ bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
+ if ( !isExcluded && matchesMimeFilter( item ) )
+ result.append( item );
+ }
+ }
+
+ return result;
+}
+
+// to keep BC changes
+
+void KDirLister::virtual_hook( int, void * )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kdirlister.moc"
+#include "kdirlister_p.moc"
diff --git a/tdeio/tdeio/kdirlister.h b/tdeio/tdeio/kdirlister.h
new file mode 100644
index 000000000..188f9ea7a
--- /dev/null
+++ b/tdeio/tdeio/kdirlister.h
@@ -0,0 +1,634 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ 2001, 2002, 2004, 2005 Michael Brade <brade@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 kdirlister_h
+#define kdirlister_h
+
+#include "tdefileitem.h"
+#include "kdirnotify.h"
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+#include <kurl.h>
+
+namespace TDEIO { class Job; class ListJob; }
+
+/**
+ * The dir lister deals with the kiojob used to list and update a directory
+ * and has signals for the user of this class (e.g. konqueror view or
+ * kdesktop) to create/destroy its items when asked.
+ *
+ * This class is independent from the graphical representation of the dir
+ * (icon container, tree view, ...) and it stores the items (as KFileItems).
+ *
+ * Typical usage :
+ * @li Create an instance.
+ * @li Connect to at least update, clear, newItem, and deleteItem.
+ * @li Call openURL - the signals will be called.
+ * @li Reuse the instance when opening a new url (openURL).
+ * @li Destroy the instance when not needed anymore (usually destructor).
+ *
+ * Advanced usage : call openURL with _keep = true to list directories
+ * without forgetting the ones previously read (e.g. for a tree view)
+ *
+ * @short Helper class for the kiojob used to list and update a directory.
+ * @author Michael Brade <brade@kde.org>
+ */
+class TDEIO_EXPORT KDirLister : public TQObject
+{
+ class KDirListerPrivate;
+ friend class KDirListerPrivate;
+ friend class KDirListerCache;
+
+ Q_OBJECT
+ TQ_PROPERTY( bool autoUpdate READ autoUpdate WRITE setAutoUpdate )
+ TQ_PROPERTY( bool showingDotFiles READ showingDotFiles WRITE setShowingDotFiles )
+ TQ_PROPERTY( bool dirOnlyMode READ dirOnlyMode WRITE setDirOnlyMode )
+ TQ_PROPERTY( bool autoErrorHandlingEnabled READ autoErrorHandlingEnabled )
+ TQ_PROPERTY( TQString nameFilter READ nameFilter WRITE setNameFilter )
+ TQ_PROPERTY( TQStringList mimeFilter READ mimeFilters WRITE setMimeFilter RESET clearMimeFilter )
+
+public:
+ /**
+ * Create a directory lister.
+ * @param _delayedMimeTypes if true, mime types will be fetched on demand. If false,
+ * they will always be fetched immediately
+ */
+ KDirLister( bool _delayedMimeTypes = false );
+
+ /**
+ * Destroy the directory lister.
+ */
+ virtual ~KDirLister();
+
+ /**
+ * Run the directory lister on the given url.
+ *
+ * This method causes KDirLister to emit _all_ the items of @p _url, in any case.
+ * Depending on @p _keep either clear() or clear(const KURL &) will be
+ * emitted first.
+ *
+ * The newItems() signal may be emitted more than once to supply you
+ * with KFileItems, up until the signal completed() is emitted
+ * (and isFinished() returns true).
+ *
+ * @param _url the directory URL.
+ * @param _keep if true the previous directories aren't forgotten
+ * (they are still watched by kdirwatch and their items
+ * are kept for this KDirLister). This is useful for e.g.
+ * a treeview.
+ * @param _reload indicates wether to use the cache (false) or to reread the
+ * directory from the disk.
+ * Use only when opening a dir not yet listed by this lister
+ * without using the cache. Otherwise use updateDirectory.
+ * @return true if successful,
+ * false otherwise (e.g. invalid @p _url)
+ */
+ virtual bool openURL( const KURL& _url, bool _keep = false, bool _reload = false );
+
+ /**
+ * Stop listing all directories currently being listed.
+ *
+ * Emits canceled() if there was at least one job running.
+ * Emits canceled( const KURL& ) for each stopped job if
+ * there are at least two dirctories being watched by KDirLister.
+ */
+ virtual void stop();
+
+ /**
+ * Stop listing the given directory.
+ *
+ * Emits canceled() if the killed job was the last running one.
+ * Emits canceled( const KURL& ) for the killed job if
+ * there are at least two directories being watched by KDirLister.
+ * No signal is emitted if there was no job running for @p _url.
+ * @param _url the directory URL
+ */
+ virtual void stop( const KURL& _url );
+
+ /**
+ * Checks whether KDirWatch will automatically update directories. This is
+ * enabled by default.
+ * @return true if KDirWatch is used to automatically update directories.
+ */
+ bool autoUpdate() const;
+
+ /**
+ * Enable/disable automatic directory updating, when a directory changes
+ * (using KDirWatch).
+ * @param enable true to enable, false to disable
+ */
+ virtual void setAutoUpdate( bool enable );
+
+ /**
+ * Check whether auto error handling is enabled.
+ * If enabled, it will show an error dialog to the user when an
+ * error occurs. It is turned on by default.
+ * @return true if auto error handling is enabled, false otherwise
+ * @see setAutoErrorHandlingEnabled()
+ */
+ bool autoErrorHandlingEnabled() const;
+
+ /**
+ * Enable or disable auto error handling is enabled.
+ * If enabled, it will show an error dialog to the user when an
+ * error occurs. It is turned on by default.
+ * @param enable true to enable auto error handling, false to disable
+ * @param parent the parent widget for the error dialogs, can be 0 for
+ * top-level
+ * @see autoErrorHandlingEnabled()
+ */
+ void setAutoErrorHandlingEnabled( bool enable, TQWidget *parent );
+
+ /**
+ * Checks whether hidden files (files beginning with a dot) will be
+ * shown.
+ * By default this option is disabled (hidden files will be not shown).
+ * @return true if dot files are shown, false otherwise
+ * @see setShowingDotFiles()
+ */
+ bool showingDotFiles() const;
+
+ /**
+ * Changes the "is viewing dot files" setting.
+ * Calls updateDirectory() if setting changed.
+ * By default this option is disabled (hidden files will not be shown).
+ * @param _showDotFiles true to enable showing hidden files, false to
+ * disable
+ * @see showingDotFiles()
+ */
+ virtual void setShowingDotFiles( bool _showDotFiles );
+
+ /**
+ * Checks whether the KDirLister only lists directories or all
+ * files.
+ * By default this option is disabled (all files will be shown).
+ * @return true if setDirOnlyMode(true) was called
+ */
+ bool dirOnlyMode() const;
+
+ /**
+ * Call this to list only directories.
+ * By default this option is disabled (all files will be shown).
+ * @param dirsOnly true to list only directories
+ */
+ virtual void setDirOnlyMode( bool dirsOnly );
+
+ /**
+ * Returns the top level URL that is listed by this KDirLister.
+ * It might be different from the one given with openURL() if there was a
+ * redirection. If you called openURL() with @p _keep == true this is the
+ * first url opened (e.g. in a treeview this is the root).
+ *
+ * @return the url used by this instance to list the files.
+ */
+ const KURL& url() const;
+
+ /**
+ * Returns all URLs that are listed by this KDirLister. This is only
+ * useful if you called openURL() with @p _keep == true, as it happens in a
+ * treeview, for example. (Note that the base url is included in the list
+ * as well, of course.)
+ *
+ * @return the list of all listed URLs
+ * @since 3.4
+ */
+ const KURL::List& directories() const;
+
+ /**
+ * Actually emit the changes made with setShowingDotFiles, setDirOnlyMode,
+ * setNameFilter and setMimeFilter.
+ */
+ virtual void emitChanges();
+
+ /**
+ * Update the directory @p _dir. This method causes KDirLister to _only_ emit
+ * the items of @p _dir that actually changed compared to the current state in the
+ * cache and updates the cache.
+ *
+ * The current implementation calls updateDirectory automatically for
+ * local files, using KDirWatch (if autoUpdate() is true), but it might be
+ * useful to force an update manually.
+ *
+ * @param _dir the directory URL
+ */
+ virtual void updateDirectory( const KURL& _dir );
+
+ /**
+ * Returns true if no io operation is currently in progress.
+ * @return true if finished, false otherwise
+ */
+ bool isFinished() const;
+
+ /**
+ * Returns the file item of the URL.
+ * @return the file item for url() itself (".")
+ */
+ KFileItem *rootItem() const;
+
+ /**
+ * Find an item by its URL.
+ * @param _url the item URL
+ * @return the pointer to the KFileItem
+ */
+ virtual KFileItem *findByURL( const KURL& _url ) const;
+#ifndef KDE_NO_COMPAT
+ KFileItem *find( const KURL& _url ) const;
+#endif
+
+ /**
+ * Find an item by its name.
+ * @param name the item name
+ * @return the pointer to the KFileItem
+ */
+ virtual KFileItem *findByName( const TQString& name ) const;
+
+ /**
+ * Set a name filter to only list items matching this name, e.g. "*.cpp".
+ *
+ * You can set more than one filter by separating them with whitespace, e.g
+ * "*.cpp *.h".
+ * Note: the direcory is not automatically reloaded.
+ *
+ * @param filter the new filter, TQString::null to disable filtering
+ * @see matchesFilter
+ */
+ virtual void setNameFilter( const TQString &filter );
+
+ /**
+ * Returns the current name filter, as set via setNameFilter()
+ * @return the current name filter, can be TQString::null if filtering
+ * is turned off
+ */
+ const TQString& nameFilter() const;
+
+ /**
+ * Set mime-based filter to only list items matching the given mimetypes.
+ *
+ * NOTE: setting the filter does not automatically reload direcory.
+ * Also calling this function will not affect any named filter already set.
+ *
+ * @param mimeList a list of mime-types.
+ *
+ * @see clearMimeFilter
+ * @see matchesMimeFilter
+ */
+ virtual void setMimeFilter( const TQStringList &mimeList );
+
+ /**
+ * Filtering should be done with KFileFilter. This will be implemented in a later
+ * revision of KDirLister. This method may be removed then.
+ *
+ * Set mime-based exclude filter to only list items not matching the given mimetypes
+ *
+ * NOTE: setting the filter does not automatically reload direcory.
+ * Also calling this function will not affect any named filter already set.
+ *
+ * @param mimeList a list of mime-types.
+ * @see clearMimeFilter
+ * @see matchesMimeFilter
+ * @since 3.1
+ * @internal
+ */
+ void setMimeExcludeFilter(const TQStringList &mimeList );
+
+
+ /**
+ * Clears the mime based filter.
+ *
+ * @see setMimeFilter
+ */
+ virtual void clearMimeFilter();
+
+ /**
+ * Returns the list of mime based filters, as set via setMimeFilter().
+ * @return the list of mime based filters. Empty, when no mime filter is set.
+ */
+ const TQStringList& mimeFilters() const;
+
+ /**
+ * Checks whether @p name matches a filter in the list of name filters.
+ * @return true if @p name matches a filter in the list,
+ * otherwise false.
+ * @see setNameFilter
+ */
+ bool matchesFilter( const TQString& name ) const;
+
+ /**
+ * Checks whether @p mime matches a filter in the list of mime types
+ * @param mime the mimetype to find in the filter list.
+ * @return true if @p name matches a filter in the list,
+ * otherwise false.
+ * @see setMimeFilter.
+ */
+ bool matchesMimeFilter( const TQString& mime ) const;
+
+ /**
+ * Pass the main window this object is associated with
+ * this is used for caching authentication data
+ * @param window the window to associate with, 0 to disassociate
+ * @since 3.1
+ */
+ void setMainWindow( TQWidget *window );
+
+ /**
+ * Returns the main window associated with this object.
+ * @return the associated main window, or 0 if there is none
+ * @since 3.1
+ */
+ TQWidget *mainWindow();
+
+ /**
+ * Used by items() and itemsForDir() to specify whether you want
+ * all items for a directory or just the filtered ones.
+ */
+ enum WhichItems
+ {
+ AllItems = 0,
+ FilteredItems = 1
+ };
+
+ /**
+ * Returns the items listed for the current url().
+ * This method will NOT start listing a directory, you should only call
+ * this when receiving the finished() signal.
+ *
+ * The items in the KFileItemList are references to the items used
+ * by KDirLister, so e.g. an item gets destroyed when the deleteItem()
+ * signal is emitted.
+ *
+ * @param which specifies whether the returned list will contain all entries
+ * or only the ones that passed the nameFilter(), mimeFilter(),
+ * etc. Note that the latter causes iteration over all the
+ * items, filtering them. If this is too slow for you, use the
+ * newItems() signal, sending out filtered items in chunks.
+ * @return the items listed for the current url().
+ * @since 3.1
+ */
+ KFileItemList items( WhichItems which = FilteredItems ) const;
+
+ /**
+ * Returns the items listed for the given @p dir.
+ * This method will NOT start listing @p dir, you should only call
+ * this when receiving the finished() signal.
+ *
+ * The items in the KFileItemList are references to the items used
+ * by KDirLister, so e.g. an item gets destroyed when the deleteItem()
+ * signal is emitted.
+ *
+ * @param dir specifies the url for which the items should be returned. This
+ * is only useful if you use KDirLister with multiple URLs
+ * i.e. using bool keep = true in openURL().
+ * @param which specifies whether the returned list will contain all entries
+ * or only the ones that passed the nameFilter, mimeFilter, etc.
+ * Note that the latter causes iteration over all the items,
+ * filtering them. If this is too slow for you, use the
+ * newItems() signal, sending out filtered items in chunks.
+ * @return the items listed for @p dir.
+ * @since 3.1
+ */
+ KFileItemList itemsForDir( const KURL& dir,
+ WhichItems which = FilteredItems ) const;
+
+signals:
+ /**
+ * Tell the view that we started to list @p _url. NOTE: this does _not_ imply that there
+ * is really a job running! I.e. KDirLister::jobs() may return an empty list. In this case
+ * the items are taken from the cache.
+ *
+ * The view knows that openURL should start it, so it might seem useless,
+ * but the view also needs to know when an automatic update happens.
+ * @param _url the URL to list
+ */
+ void started( const KURL& _url );
+
+ /**
+ * Tell the view that listing is finished. There are no jobs running anymore.
+ */
+ void completed();
+
+ /**
+ * Tell the view that the listing of the directory @p _url is finished.
+ * There might be other running jobs left.
+ * @param _url the directory URL
+ */
+ void completed( const KURL& _url );
+
+ /**
+ * Tell the view that the user canceled the listing. No running jobs are left.
+ */
+ void canceled();
+
+ /**
+ * Tell the view that the listing of the directory @p _url was canceled.
+ * There might be other running jobs left.
+ * @param _url the directory URL
+ */
+ void canceled( const KURL& _url );
+
+ /**
+ * Signal a redirection.
+ * Only emitted if there's just one directory to list, i.e. most
+ * probably openURL() has been called with @p _keep == @p false.
+ * @param _url the new URL
+ */
+ void redirection( const KURL& _url );
+
+ /**
+ * Signal a redirection.
+ * @param oldUrl the original URL
+ * @param newUrl the new URL
+ */
+ void redirection( const KURL& oldUrl, const KURL& newUrl );
+
+ /**
+ * Signal to clear all items.
+ * It must always be connected to this signal to avoid doubled items!
+ */
+ void clear();
+
+ /**
+ * Signal to empty the directory @p _url.
+ * It is only emitted if the lister is holding more than one directory.
+ * @param _url the directory that will be emptied
+ */
+ void clear( const KURL& _url );
+
+ /**
+ * Signal new items.
+ * @param items a list of new items
+ */
+ void newItems( const KFileItemList& items );
+
+ /**
+ * Send a list of items filtered-out by mime-type.
+ * @param items the list of filtered items
+ */
+ void itemsFilteredByMime( const KFileItemList& items );
+
+ /**
+ * Signal an item to remove.
+ *
+ * ATTENTION: if @p _fileItem == rootItem() the directory this lister
+ * is holding was deleted and you HAVE to release especially the
+ * rootItem() of this lister, otherwise your app will CRASH!!
+ * The clear() signals have been emitted already.
+ * @param _fileItem the fileItem to delete
+ */
+ void deleteItem( KFileItem *_fileItem );
+
+ /**
+ * Signal an item to refresh (its mimetype/icon/name has changed).
+ * Note: KFileItem::refresh has already been called on those items.
+ * @param items the items to refresh
+ */
+ void refreshItems( const KFileItemList& items );
+
+ /**
+ * Emitted to display information about running jobs.
+ * Examples of message are "Resolving host", "Connecting to host...", etc.
+ * @param msg the info message
+ */
+ void infoMessage( const TQString& msg );
+
+ /**
+ * Progress signal showing the overall progress of the KDirLister.
+ * This allows using a progress bar very easily. (see KProgress)
+ * @param percent the progress in percent
+ */
+ void percent( int percent );
+
+ /**
+ * Emitted when we know the size of the jobs.
+ * @param size the total size in bytes
+ */
+ void totalSize( TDEIO::filesize_t size );
+
+ /**
+ * Regularly emitted to show the progress of this KDirLister.
+ * @param size the processed size in bytes
+ */
+ void processedSize( TDEIO::filesize_t size );
+
+ /**
+ * Emitted to display information about the speed of the jobs.
+ * @param bytes_per_second the speed in bytes/s
+ */
+ void speed( int bytes_per_second );
+
+protected:
+ enum Changes {
+ NONE=0, NAME_FILTER=1, MIME_FILTER=2, DOT_FILES=4, DIR_ONLY_MODE=8
+ };
+
+ /**
+ * Called for every new item before emitting newItems().
+ * You may reimplement this method in a subclass to implement your own
+ * filtering.
+ * The default implementation filters out ".." and everything not matching
+ * the name filter(s)
+ * @return true if the item is "ok".
+ * false if the item shall not be shown in a view, e.g.
+ * files not matching a pattern *.cpp ( KFileItem::isHidden())
+ * @see matchesFilter
+ * @see setNameFilter
+ */
+ virtual bool matchesFilter( const KFileItem * ) const;
+
+ /**
+ * Called for every new item before emitting newItems().
+ * You may reimplement this method in a subclass to implement your own
+ * filtering.
+ * The default implementation filters out ".." and everything not matching
+ * the name filter(s)
+ * @return true if the item is "ok".
+ * false if the item shall not be shown in a view, e.g.
+ * files not matching a pattern *.cpp ( KFileItem::isHidden())
+ * @see matchesMimeFilter
+ * @see setMimeFilter
+ */
+ virtual bool matchesMimeFilter( const KFileItem * ) const;
+
+ /**
+ * Called by the public matchesFilter() to do the
+ * actual filtering. Those methods may be reimplemented to customize
+ * filtering.
+ * @param name the name to filter
+ * @param filters a list of regular expressions for filtering
+ */
+ virtual bool doNameFilter( const TQString& name, const TQPtrList<TQRegExp>& filters ) const;
+
+ /**
+ * Called by the public matchesMimeFilter() to do the
+ * actual filtering. Those methods may be reimplemented to customize
+ * filtering.
+ * @param mime the mime type to filter
+ * @param filters the list of mime types to filter
+ */
+ virtual bool doMimeFilter( const TQString& mime, const TQStringList& filters ) const;
+
+ /**
+ * @internal
+ */
+ bool doMimeExcludeFilter( const TQString& mimeExclude, const TQStringList& filters ) const;
+
+ /**
+ * Checks if an url is malformed or not and displays an error message
+ * if it is and autoErrorHandling is set to true.
+ * @return true if url is valid, otherwise false.
+ */
+ virtual bool validURL( const KURL& ) const;
+
+ /** Reimplement to customize error handling */
+ virtual void handleError( TDEIO::Job * );
+
+protected:
+ virtual void virtual_hook( int id, void *data );
+
+private slots:
+ void slotInfoMessage( TDEIO::Job *, const TQString& );
+ void slotPercent( TDEIO::Job *, unsigned long );
+ void slotTotalSize( TDEIO::Job *, TDEIO::filesize_t );
+ void slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t );
+ void slotSpeed( TDEIO::Job *, unsigned long );
+ void slotLocalURL( TDEIO::Job *, const KURL&, bool );
+ void slotLocalURLKIODestroyed( );
+
+private:
+ void jobStarted( TDEIO::ListJob * );
+ void connectJob( TDEIO::ListJob * );
+ void jobDone( TDEIO::ListJob * );
+
+ uint numJobs();
+
+private:
+ virtual void addNewItem( const KFileItem *item );
+ virtual void addNewItems( const KFileItemList& items );
+ /*virtual*/ void aboutToRefreshItem( const KFileItem *item ); // TODO: KDE 4.0 make virtual
+ virtual void addRefreshItem( const KFileItem *item );
+ virtual void emitItems();
+ virtual void emitDeleteItem( KFileItem *item );
+
+ KDirListerPrivate *d;
+};
+
+#endif
+
diff --git a/tdeio/tdeio/kdirlister_p.h b/tdeio/tdeio/kdirlister_p.h
new file mode 100644
index 000000000..d6dff7bcf
--- /dev/null
+++ b/tdeio/tdeio/kdirlister_p.h
@@ -0,0 +1,358 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Michael Brade <brade@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 kdirlister_p_h
+#define kdirlister_p_h
+
+#include "tdefileitem.h"
+
+#include <tqmap.h>
+#include <tqdict.h>
+#include <tqcache.h>
+#include <tqwidget.h>
+
+#include <kurl.h>
+#include <tdeio/global.h>
+#include <kdirwatch.h>
+#include <dcopclient.h>
+
+class TQTimer;
+class KDirLister;
+namespace TDEIO { class Job; class ListJob; }
+
+
+class KDirLister::KDirListerPrivate
+{
+public:
+ KDirListerPrivate()
+ {
+ complete = false;
+
+ autoUpdate = false;
+ isShowingDotFiles = false;
+ dirOnlyMode = false;
+
+ autoErrorHandling = false;
+ errorParent = 0;
+
+ delayedMimeTypes = false;
+
+ rootFileItem = 0;
+ lstNewItems = 0;
+ lstRefreshItems = 0;
+ lstMimeFilteredItems = 0;
+ lstRemoveItems = 0;
+ refreshItemWasFiltered = false;
+
+ changes = NONE;
+
+ window = 0;
+
+ lstFilters.setAutoDelete( true );
+ oldFilters.setAutoDelete( true );
+ }
+
+ /**
+ * List of dirs handled by this dirlister. The first entry is the base URL.
+ * For a tree view, it contains all the dirs shown.
+ */
+ KURL::List lstDirs;
+
+ // toplevel URL
+ KURL url;
+
+ bool complete;
+
+ bool autoUpdate;
+ bool isShowingDotFiles;
+ bool dirOnlyMode;
+
+ bool autoErrorHandling;
+ TQWidget *errorParent;
+
+ bool delayedMimeTypes;
+
+ struct JobData {
+ long unsigned int percent, speed;
+ TDEIO::filesize_t processedSize, totalSize;
+ };
+
+ TQMap<TDEIO::ListJob *, JobData> jobData;
+
+ // file item for the root itself (".")
+ KFileItem *rootFileItem;
+
+ KFileItemList *lstNewItems, *lstRefreshItems;
+ KFileItemList *lstMimeFilteredItems, *lstRemoveItems;
+
+ bool refreshItemWasFiltered;
+
+ int changes;
+
+ TQWidget *window; // Main window ths lister is associated with
+
+ TQString nameFilter;
+ TQPtrList<TQRegExp> lstFilters, oldFilters;
+ TQStringList mimeFilter, oldMimeFilter;
+ TQStringList mimeExcludeFilter, oldMimeExcludeFilter;
+
+ bool localURLSlotFired;
+ KURL localURLResultURL;
+ bool localURLResultIsLocal;
+};
+
+/**
+ * Design of the cache:
+ * There is a single KDirListerCache for the whole process.
+ * It holds all the items used by the dir listers (itemsInUse)
+ * as well as a cache of the recently used items (itemsCached).
+ * Those items are grouped by directory (a DirItem represents a whole directory).
+ *
+ * KDirListerCache also runs all the jobs for listing directories, whether they are for
+ * normal listing or for updates.
+ * For faster lookups, it also stores two dicts:
+ * a URL -> dirlister holding that URL (urlsCurrentlyHeld)
+ * a URL -> dirlister currently listing that URL (urlsCurrentlyListed)
+ */
+class KDirListerCache : public TQObject, KDirNotify
+{
+ Q_OBJECT
+public:
+ KDirListerCache( int maxCount = 10 );
+ ~KDirListerCache();
+
+ bool listDir( KDirLister *lister, const KURL& _url, bool _keep, bool _reload );
+ bool validURL( const KDirLister *lister, const KURL& _url ) const;
+
+ // stop all running jobs for lister
+ void stop( KDirLister *lister );
+ // stop just the job listing url for lister
+ void stop( KDirLister *lister, const KURL &_url );
+
+ void setAutoUpdate( KDirLister *lister, bool enable );
+
+ void forgetDirs( KDirLister *lister );
+ void forgetDirs( KDirLister *lister, const KURL &_url, bool notify );
+
+ void updateDirectory( const KURL &_dir );
+
+ KFileItemList *itemsForDir( const KURL &_dir ) const;
+
+ KFileItem *findByName( const KDirLister *lister, const TQString &_name ) const;
+ // if lister is set, it is checked that the url is held by the lister
+ KFileItem *findByURL( const KDirLister *lister, const KURL &_url ) const;
+
+ /**
+ * Notify that files have been added in @p directory
+ * The receiver will list that directory again to find
+ * the new items (since it needs more than just the names anyway).
+ * Reimplemented from KDirNotify.
+ */
+ virtual void FilesAdded( const KURL &directory );
+
+ /**
+ * Notify that files have been deleted.
+ * This call passes the exact urls of the deleted files
+ * so that any view showing them can simply remove them
+ * or be closed (if its current dir was deleted)
+ * Reimplemented from KDirNotify.
+ */
+ virtual void FilesRemoved( const KURL::List &fileList );
+
+ /**
+ * Notify that files have been changed.
+ * At the moment, this is only used for new icon, but it could be
+ * used for size etc. as well.
+ * Note: this is ASYNC so that it can be used with a broadcast
+ */
+ virtual void FilesChanged( const KURL::List &fileList );
+ virtual void FileRenamed( const KURL &src, const KURL &dst );
+
+ static KDirListerCache *self();
+
+ static bool exists();
+
+private slots:
+ void slotFileDirty( const TQString &_file );
+ void slotFileCreated( const TQString &_file );
+ void slotFileDeleted( const TQString &_file );
+
+ void slotFileDirtyDelayed();
+
+ void slotEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries );
+ void slotResult( TDEIO::Job *j );
+ void slotRedirection( TDEIO::Job *job, const KURL &url );
+
+ void slotUpdateEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries );
+ void slotUpdateResult( TDEIO::Job *job );
+
+private:
+ TDEIO::ListJob *jobForUrl( const TQString& url, TDEIO::ListJob *not_job = 0 );
+ const KURL& joburl( TDEIO::ListJob *job );
+
+ void killJob( TDEIO::ListJob *job );
+
+ // check if _url is held by some lister and return true,
+ // otherwise schedule a delayed update and return false
+ bool checkUpdate( const TQString& _url );
+ // when there were items deleted from the filesystem all the listers holding
+ // the parent directory need to be notified, the unmarked items have to be deleted
+ // and removed from the cache including all the childs.
+ void deleteUnmarkedItems( TQPtrList<KDirLister> *, KFileItemList * );
+ void processPendingUpdates();
+ // common for slotRedirection and FileRenamed
+ void renameDir( const KURL &oldUrl, const KURL &url );
+ // common for deleteUnmarkedItems and FilesRemoved
+ void deleteDir( const KURL& dirUrl );
+ // remove directory from cache (itemsCached), including all child dirs
+ void removeDirFromCache( const KURL& dir );
+ // helper for renameDir
+ void emitRedirections( const KURL &oldUrl, const KURL &url );
+
+ void aboutToRefreshItem( KFileItem *fileitem );
+ void emitRefreshItem( KFileItem *fileitem );
+
+#ifndef NDEBUG
+ void printDebug();
+#endif
+
+ struct DirItem
+ {
+ DirItem( const KURL &dir )
+ : url(dir), rootItem(0), lstItems(new KFileItemList)
+ {
+ autoUpdates = 0;
+ complete = false;
+ lstItems->setAutoDelete( true );
+ }
+
+ ~DirItem()
+ {
+ if ( autoUpdates )
+ {
+ if ( KDirWatch::exists() && url.isLocalFile() )
+ kdirwatch->removeDir( url.path() );
+ sendSignal( false, url );
+ }
+ delete rootItem;
+ delete lstItems;
+ }
+
+ void sendSignal( bool entering, const KURL& url )
+ {
+ DCOPClient *client = DCOPClient::mainClient();
+ if ( !client )
+ return;
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << url;
+ client->emitDCOPSignal( "KDirNotify", entering ? "enteredDirectory(KURL)" : "leftDirectory(KURL)", data );
+ }
+
+ void redirect( const KURL& newUrl )
+ {
+ if ( autoUpdates )
+ {
+ if ( url.isLocalFile() )
+ kdirwatch->removeDir( url.path() );
+ sendSignal( false, url );
+
+ if ( newUrl.isLocalFile() )
+ kdirwatch->addDir( newUrl.path() );
+ sendSignal( true, newUrl );
+ }
+
+ url = newUrl;
+
+ if ( rootItem )
+ rootItem->setURL( newUrl );
+ }
+
+ void incAutoUpdate()
+ {
+ if ( autoUpdates++ == 0 )
+ {
+ if ( url.isLocalFile() )
+ kdirwatch->addDir( url.path() );
+ sendSignal( true, url );
+ }
+ }
+
+ void decAutoUpdate()
+ {
+ if ( --autoUpdates == 0 )
+ {
+ if ( url.isLocalFile() )
+ kdirwatch->removeDir( url.path() );
+ sendSignal( false, url );
+ }
+
+ else if ( autoUpdates < 0 )
+ autoUpdates = 0;
+ }
+
+ // number of KDirListers using autoUpdate for this dir
+ short autoUpdates;
+
+ // this directory is up-to-date
+ bool complete;
+
+ // the complete url of this directory
+ KURL url;
+
+ // KFileItem representing the root of this directory.
+ // Remember that this is optional. FTP sites don't return '.' in
+ // the list, so they give no root item
+ KFileItem *rootItem;
+ KFileItemList *lstItems;
+ };
+
+ static const unsigned short MAX_JOBS_PER_LISTER;
+ TQMap<TDEIO::ListJob *, TDEIO::UDSEntryList> jobs;
+
+ // an item is a complete directory
+ TQDict<DirItem> itemsInUse;
+ TQCache<DirItem> itemsCached;
+
+ // A lister can be EITHER in urlsCurrentlyListed OR urlsCurrentlyHeld but NOT
+ // in both at the same time.
+ // On the other hand there can be some listers in urlsCurrentlyHeld
+ // and some in urlsCurrentlyListed for the same url!
+ // Or differently said, there can be an entry for url in urlsCurrentlyListed
+ // and urlsCurrentlyHeld. This happens if more listers are requesting url at
+ // the same time and one lister was stopped during the listing of files.
+
+ // saves all urls that are currently being listed and maps them
+ // to their KDirListers
+ TQDict< TQPtrList<KDirLister> > urlsCurrentlyListed;
+
+ // saves all KDirListers that are just holding url
+ TQDict< TQPtrList<KDirLister> > urlsCurrentlyHeld;
+
+ // running timers for the delayed update
+ TQDict<TQTimer> pendingUpdates;
+
+ static KDirListerCache *s_pSelf;
+};
+
+const unsigned short KDirListerCache::MAX_JOBS_PER_LISTER = 5;
+
+#define s_pCache KDirListerCache::self()
+
+#endif
diff --git a/tdeio/tdeio/kdirnotify.cpp b/tdeio/tdeio/kdirnotify.cpp
new file mode 100644
index 000000000..fb98196f5
--- /dev/null
+++ b/tdeio/tdeio/kdirnotify.cpp
@@ -0,0 +1,40 @@
+/* This file is part of the KDE project
+ 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.
+*/
+
+#include "kdirnotify.h"
+
+// Needed since DCOP enforces object id uniqueness.
+int KDirNotify::s_serial = 0;
+
+KDirNotify::KDirNotify()
+ : DCOPObject( TQCString().sprintf("KDirNotify-%d", ++s_serial) )
+{
+ connectDCOPSignal(0, "KDirNotify", "FilesAdded(KURL)", "FilesAdded(KURL)", false);
+ connectDCOPSignal(0, "KDirNotify", "FilesRemoved(KURL::List)", "FilesRemoved(KURL::List)", false);
+ connectDCOPSignal(0, "KDirNotify", "FilesChanged(KURL::List)", "FilesChanged(KURL::List)", false);
+ connectDCOPSignal(0, "KDirNotify", "FileRenamed(KURL,KURL)", "FileRenamed(KURL,KURL)", false);
+}
+
+void KDirNotify::FileRenamed( const KURL &, const KURL & )
+{
+}
+
+void KDirNotify::virtual_hook( int id, void* data )
+{ DCOPObject::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/kdirnotify.h b/tdeio/tdeio/kdirnotify.h
new file mode 100644
index 000000000..14d864609
--- /dev/null
+++ b/tdeio/tdeio/kdirnotify.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ 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 __kdirnotify_h__
+#define __kdirnotify_h__
+
+#include <dcopobject.h>
+#include <kurl.h>
+
+/**
+ * An abstract class that receives notifications of added and removed files
+ * in any directory, local or remote.
+ * The information comes from the konqueror/kdesktop instance where the
+ * operation was done, and can interest KDirListers, bookmark handlers, etc.
+ */
+class TDEIO_EXPORT KDirNotify : public DCOPObject
+{
+ K_DCOP
+protected:
+ KDirNotify();
+ virtual ~KDirNotify() {}
+
+public:
+k_dcop:
+ /**
+ * Notify that files have been added in @p directory
+ * Note: this is ASYNC so that it can be used with a broadcast.
+ * @param directory the directory that contains the new files
+ */
+ virtual ASYNC FilesAdded( const KURL & directory ) = 0;
+
+ /**
+ * Notify that files have been deleted.
+ * Note: this is ASYNC so that it can be used with a broadcast
+ * @param fileList the files that have been deleted
+ */
+ virtual ASYNC FilesRemoved( const KURL::List & fileList ) = 0;
+
+ /**
+ * Notify that files have been changed.
+ * At the moment, this is only used for new icon, but it could be
+ * used for size etc. as well.
+ * Note: this is ASYNC so that it can be used with a broadcast.
+ * @param fileList the list of changed files
+ */
+ virtual ASYNC FilesChanged( const KURL::List & fileList ) = 0;
+
+ /**
+ * Notify that a file has been renamed.
+ * Note: this is ASYNC so that it can be used with a broadcast
+ * @param src a list containing original names of the renamed files
+ * @param dst a list of original names of the renamed files
+ */
+ virtual ASYNC FileRenamed( const KURL &src, const KURL &dst );
+
+ // WARNING: When adding new methods, make sure to update
+ // kdirnotify_stub.cpp and kdirnotify_stub.h manually.
+ // They are not automatically generated since they contain
+ // handcoded changes.
+
+private:
+ // @internal
+ static int s_serial;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+#endif
diff --git a/tdeio/tdeio/kdirnotify_stub.cpp b/tdeio/tdeio/kdirnotify_stub.cpp
new file mode 100644
index 000000000..66988d6c9
--- /dev/null
+++ b/tdeio/tdeio/kdirnotify_stub.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** DCOP Stub Implementation based on output of dcopidl2cpp from kdirnotify.kidl
+** but with hand coded changes!!
+**
+*****************************************************************************/
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 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.
+*/
+
+#include "kdirnotify_stub.h"
+#include <dcopclient.h>
+
+#include <kdatastream.h>
+
+
+KDirNotify_stub::KDirNotify_stub( const TQCString& app, const TQCString& obj )
+ : DCOPStub( app, obj )
+{
+}
+
+KDirNotify_stub::KDirNotify_stub( DCOPClient* client, const TQCString& app, const TQCString& obj )
+ : DCOPStub( client, app, obj )
+{
+}
+
+KDirNotify_stub::KDirNotify_stub( const DCOPRef& ref )
+ : DCOPStub( ref )
+{
+}
+
+void KDirNotify_stub::FilesAdded( const KURL& arg0 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ dcopClient()->emitDCOPSignal( "KDirNotify", "FilesAdded(KURL)", data );
+ setStatus( CallSucceeded );
+}
+
+void KDirNotify_stub::FilesRemoved( const KURL::List& arg0 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ dcopClient()->emitDCOPSignal( "KDirNotify", "FilesRemoved(KURL::List)", data );
+ setStatus( CallSucceeded );
+}
+
+void KDirNotify_stub::FilesChanged( const KURL::List& arg0 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ dcopClient()->emitDCOPSignal( "KDirNotify", "FilesChanged(KURL::List)", data );
+ setStatus( CallSucceeded );
+}
+
+void KDirNotify_stub::FileRenamed( const KURL& arg0, const KURL& arg1 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ dcopClient()->emitDCOPSignal( "KDirNotify", "FileRenamed(KURL,KURL)", data );
+ setStatus( CallSucceeded );
+}
+
+
diff --git a/tdeio/tdeio/kdirnotify_stub.h b/tdeio/tdeio/kdirnotify_stub.h
new file mode 100644
index 000000000..56ab168c4
--- /dev/null
+++ b/tdeio/tdeio/kdirnotify_stub.h
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** DCOP Stub Definition created by dcopidl2cpp from kdirnotify.kidl
+**
+** WARNING! All changes made in this file will be lost!
+**
+*****************************************************************************/
+
+#ifndef __KDIRNOTIFY_STUB__
+#define __KDIRNOTIFY_STUB__
+
+#include <dcopstub.h>
+#include <dcopobject.h>
+#include <kurl.h>
+
+
+class TDEIO_EXPORT KDirNotify_stub : virtual public DCOPStub
+{
+public:
+ KDirNotify_stub( const TQCString& app, const TQCString& id );
+ KDirNotify_stub( DCOPClient* client, const TQCString& app, const TQCString& id );
+ explicit KDirNotify_stub( const DCOPRef& ref );
+ virtual ASYNC FilesAdded( const KURL& directory );
+ virtual ASYNC FilesRemoved( const KURL::List& fileList );
+ virtual ASYNC FilesChanged( const KURL::List& fileList );
+ virtual ASYNC FileRenamed( const KURL& src, const KURL& dst );
+protected:
+ KDirNotify_stub() : DCOPStub( never_use ) {};
+};
+
+
+#endif
diff --git a/tdeio/tdeio/kdirwatch.cpp b/tdeio/tdeio/kdirwatch.cpp
new file mode 100644
index 000000000..c4057264b
--- /dev/null
+++ b/tdeio/tdeio/kdirwatch.cpp
@@ -0,0 +1,1774 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Sven Radej <sven@lisa.exp.univie.ac.at>
+
+ 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.
+*/
+
+
+// CHANGES:
+// Oct 4, 2005 - Inotify support (Dirk Mueller)
+// Februar 2002 - Add file watching and remote mount check for STAT
+// Mar 30, 2001 - Native support for Linux dir change notification.
+// Jan 28, 2000 - Usage of FAM service on IRIX (Josef.Weidendorfer@in.tum.de)
+// May 24. 1998 - List of times introduced, and some bugs are fixed. (sven)1
+// May 23. 1998 - Removed static pointer - you can have more instances.
+// It was Needed for KRegistry. KDirWatch now emits signals and doesn't
+// call (or need) KFM. No more URL's - just plain paths. (sven)
+// Mar 29. 1998 - added docs, stop/restart for particular Dirs and
+// deep copies for list of dirs. (sven)
+// Mar 28. 1998 - Created. (sven)
+
+
+#include <config.h>
+#include <errno.h>
+
+#ifdef HAVE_DNOTIFY
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#endif
+
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqintdict.h>
+#include <tqptrlist.h>
+#include <tqsocketnotifier.h>
+#include <tqstringlist.h>
+#include <tqtimer.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <tdeconfig.h>
+#include <kglobal.h>
+#include <kstaticdeleter.h>
+#include <kde_file.h>
+
+// debug
+#include <sys/ioctl.h>
+
+#ifdef HAVE_INOTIFY
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <linux/types.h>
+// Linux kernel headers are documented to not compile
+#define _S390_BITOPS_H
+#include <sys/inotify.h>
+
+#ifndef __NR_inotify_init
+#if defined(__i386__)
+#define __NR_inotify_init 291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch 293
+#endif
+#if defined(__PPC__)
+#define __NR_inotify_init 275
+#define __NR_inotify_add_watch 276
+#define __NR_inotify_rm_watch 277
+#endif
+#if defined(__x86_64__)
+#define __NR_inotify_init 253
+#define __NR_inotify_add_watch 254
+#define __NR_inotify_rm_watch 255
+#endif
+#endif
+
+#ifndef IN_ONLYDIR
+#define IN_ONLYDIR 0x01000000
+#endif
+
+#ifndef IN_DONT_FOLLOW
+#define IN_DONT_FOLLOW 0x02000000
+#endif
+
+#ifndef IN_MOVE_SELF
+#define IN_MOVE_SELF 0x00000800
+#endif
+
+#endif
+
+#include <sys/utsname.h>
+
+#include "kdirwatch.h"
+#include "kdirwatch_p.h"
+#include "global.h" // TDEIO::probably_slow_mounted
+
+#define NO_NOTIFY (time_t) 0
+
+static KDirWatchPrivate* dwp_self = 0;
+
+#ifdef HAVE_DNOTIFY
+
+static int dnotify_signal = 0;
+
+/* DNOTIFY signal handler
+ *
+ * As this is called asynchronously, only a flag is set and
+ * a rescan is requested.
+ * This is done by writing into a pipe to trigger a TQSocketNotifier
+ * watching on this pipe: a timer is started and after a timeout,
+ * the rescan is done.
+ */
+void KDirWatchPrivate::dnotify_handler(int, siginfo_t *si, void *)
+{
+ if (!dwp_self) return;
+
+ // write might change errno, we have to save it and restore it
+ // (Richard Stevens, Advanced programming in the Unix Environment)
+ int saved_errno = errno;
+
+ Entry* e = dwp_self->fd_Entry.find(si->si_fd);
+
+// kdDebug(7001) << "DNOTIFY Handler: fd " << si->si_fd << " path "
+// << TQString(e ? e->path:"unknown") << endl;
+
+ if(e && e->dn_fd == si->si_fd)
+ e->dirty = true;
+
+ char c = 0;
+ write(dwp_self->mPipe[1], &c, 1);
+ errno = saved_errno;
+}
+
+static struct sigaction old_sigio_act;
+/* DNOTIFY SIGIO signal handler
+ *
+ * When the kernel queue for the dnotify_signal overflows, a SIGIO is send.
+ */
+void KDirWatchPrivate::dnotify_sigio_handler(int sig, siginfo_t *si, void *p)
+{
+ if (dwp_self)
+ {
+ // write might change errno, we have to save it and restore it
+ // (Richard Stevens, Advanced programming in the Unix Environment)
+ int saved_errno = errno;
+
+ dwp_self->rescan_all = true;
+ char c = 0;
+ write(dwp_self->mPipe[1], &c, 1);
+
+ errno = saved_errno;
+ }
+
+ // Call previous signal handler
+ if (old_sigio_act.sa_flags & SA_SIGINFO)
+ {
+ if (old_sigio_act.sa_sigaction)
+ (*old_sigio_act.sa_sigaction)(sig, si, p);
+ }
+ else
+ {
+ if ((old_sigio_act.sa_handler != SIG_DFL) &&
+ (old_sigio_act.sa_handler != SIG_IGN))
+ (*old_sigio_act.sa_handler)(sig);
+ }
+}
+#endif
+
+
+//
+// Class KDirWatchPrivate (singleton)
+//
+
+/* All entries (files/directories) to be watched in the
+ * application (coming from multiple KDirWatch instances)
+ * are registered in a single KDirWatchPrivate instance.
+ *
+ * At the moment, the following methods for file watching
+ * are supported:
+ * - Polling: All files to be watched are polled regularly
+ * using stat (more precise: TQFileInfo.lastModified()).
+ * The polling frequency is determined from global tdeconfig
+ * settings, defaulting to 500 ms for local directories
+ * and 5000 ms for remote mounts
+ * - FAM (File Alternation Monitor): first used on IRIX, SGI
+ * has ported this method to LINUX. It uses a kernel part
+ * (IMON, sending change events to /dev/imon) and a user
+ * level damon (fam), to which applications connect for
+ * notification of file changes. For NFS, the fam damon
+ * on the NFS server machine is used; if IMON is not built
+ * into the kernel, fam uses polling for local files.
+ * - DNOTIFY: In late LINUX 2.3.x, directory notification was
+ * introduced. By opening a directory, you can request for
+ * UNIX signals to be sent to the process when a directory
+ * is changed.
+ * - INOTIFY: In LINUX 2.6.13, inode change notification was
+ * introduced. You're now able to watch arbitrary inode's
+ * for changes, and even get notification when they're
+ * unmounted.
+ */
+
+KDirWatchPrivate::KDirWatchPrivate()
+ : rescan_timer(0, "KDirWatchPrivate::rescan_timer")
+{
+ timer = new TQTimer(this, "KDirWatchPrivate::timer");
+ connect (timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotRescan()));
+ freq = 3600000; // 1 hour as upper bound
+ statEntries = 0;
+ delayRemove = false;
+ m_ref = 0;
+
+ TDEConfigGroup config(TDEGlobal::config(), TQCString("DirWatch"));
+ m_nfsPollInterval = config.readNumEntry("NFSPollInterval", 5000);
+ m_PollInterval = config.readNumEntry("PollInterval", 500);
+
+ TQString available("Stat");
+
+ // used for FAM and DNOTIFY
+ rescan_all = false;
+ connect(&rescan_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotRescan()));
+
+#ifdef HAVE_FAM
+ // It's possible that FAM server can't be started
+ if (FAMOpen(&fc) ==0) {
+ available += ", FAM";
+ use_fam=true;
+ sn = new TQSocketNotifier( FAMCONNECTION_GETFD(&fc),
+ TQSocketNotifier::Read, this);
+ connect( sn, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(famEventReceived()) );
+ }
+ else {
+ kdDebug(7001) << "Can't use FAM (fam daemon not running?)" << endl;
+ use_fam=false;
+ }
+#endif
+
+#ifdef HAVE_INOTIFY
+ supports_inotify = true;
+
+ m_inotify_fd = inotify_init();
+
+ if ( m_inotify_fd <= 0 ) {
+ kdDebug(7001) << "Can't use Inotify, kernel doesn't support it" << endl;
+ supports_inotify = false;
+ }
+
+ {
+ struct utsname uts;
+ int major, minor, patch;
+ if (uname(&uts) < 0)
+ supports_inotify = false; // *shrug*
+ else if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3)
+ supports_inotify = false; // *shrug*
+ else if( major * 1000000 + minor * 1000 + patch < 2006014 ) { // <2.6.14
+ kdDebug(7001) << "Can't use INotify, Linux kernel too old" << endl;
+ supports_inotify = false;
+ }
+ }
+
+ if ( supports_inotify ) {
+ available += ", Inotify";
+ fcntl(m_inotify_fd, F_SETFD, FD_CLOEXEC);
+
+ mSn = new TQSocketNotifier( m_inotify_fd, TQSocketNotifier::Read, this );
+ connect( mSn, TQT_SIGNAL(activated( int )), this, TQT_SLOT( slotActivated() ) );
+ }
+#endif
+
+#ifdef HAVE_DNOTIFY
+
+ // if we have inotify, disable dnotify.
+#ifdef HAVE_INOTIFY
+ supports_dnotify = !supports_inotify;
+#else
+ // otherwise, not guilty until proven guilty.
+ supports_dnotify = true;
+#endif
+
+ struct utsname uts;
+ int major, minor, patch;
+ if (uname(&uts) < 0)
+ supports_dnotify = false; // *shrug*
+ else if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3)
+ supports_dnotify = false; // *shrug*
+ else if( major * 1000000 + minor * 1000 + patch < 2004019 ) { // <2.4.19
+ kdDebug(7001) << "Can't use DNotify, Linux kernel too old" << endl;
+ supports_dnotify = false;
+ }
+
+ if( supports_dnotify ) {
+ available += ", DNotify";
+
+ pipe(mPipe);
+ fcntl(mPipe[0], F_SETFD, FD_CLOEXEC);
+ fcntl(mPipe[1], F_SETFD, FD_CLOEXEC);
+ fcntl(mPipe[0], F_SETFL, O_NONBLOCK | fcntl(mPipe[0], F_GETFL));
+ fcntl(mPipe[1], F_SETFL, O_NONBLOCK | fcntl(mPipe[1], F_GETFL));
+ mSn = new TQSocketNotifier( mPipe[0], TQSocketNotifier::Read, this);
+ connect(mSn, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotActivated()));
+ // Install the signal handler only once
+ if ( dnotify_signal == 0 )
+ {
+ dnotify_signal = SIGRTMIN + 8;
+
+ struct sigaction act;
+ act.sa_sigaction = KDirWatchPrivate::dnotify_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+ sigaction(dnotify_signal, &act, NULL);
+
+ act.sa_sigaction = KDirWatchPrivate::dnotify_sigio_handler;
+ sigaction(SIGIO, &act, &old_sigio_act);
+ }
+ }
+ else
+ {
+ mPipe[0] = -1;
+ mPipe[1] = -1;
+ }
+#endif
+
+ kdDebug(7001) << "Available methods: " << available << endl;
+}
+
+/* This is called on app exit (KStaticDeleter) */
+KDirWatchPrivate::~KDirWatchPrivate()
+{
+ timer->stop();
+
+ /* remove all entries being watched */
+ removeEntries(0);
+
+#ifdef HAVE_FAM
+ if (use_fam) {
+ FAMClose(&fc);
+ kdDebug(7001) << "KDirWatch deleted (FAM closed)" << endl;
+ }
+#endif
+#ifdef HAVE_INOTIFY
+ if ( supports_inotify )
+ ::close( m_inotify_fd );
+#endif
+#ifdef HAVE_DNOTIFY
+ close(mPipe[0]);
+ close(mPipe[1]);
+#endif
+}
+
+#include <stdlib.h>
+
+void KDirWatchPrivate::slotActivated()
+{
+#ifdef HAVE_DNOTIFY
+ if ( supports_dnotify )
+ {
+ char dummy_buf[4096];
+ read(mPipe[0], &dummy_buf, 4096);
+
+ if (!rescan_timer.isActive())
+ rescan_timer.start(m_PollInterval, true /* singleshot */);
+
+ return;
+ }
+#endif
+
+#ifdef HAVE_INOTIFY
+ if ( !supports_inotify )
+ return;
+
+ int pending = -1;
+ int offset = 0;
+ char buf[4096];
+ assert( m_inotify_fd > -1 );
+ ioctl( m_inotify_fd, FIONREAD, &pending );
+
+ while ( pending > 0 ) {
+
+ if ( pending > (int)sizeof( buf ) )
+ pending = sizeof( buf );
+
+ pending = read( m_inotify_fd, buf, pending);
+
+ while ( pending > 0 ) {
+ struct inotify_event *event = (struct inotify_event *) &buf[offset];
+ pending -= sizeof( struct inotify_event ) + event->len;
+ offset += sizeof( struct inotify_event ) + event->len;
+
+ TQString path;
+ if ( event->len )
+ path = TQFile::decodeName( TQCString( event->name, event->len ) );
+
+ if ( path.length() && isNoisyFile( path.latin1() ) )
+ continue;
+
+ kdDebug(7001) << "ev wd: " << event->wd << " mask " << event->mask << " path: " << path << endl;
+
+ // now we're in deep trouble of finding the
+ // associated entries
+ // for now, we suck and iterate
+ for ( EntryMap::Iterator it = m_mapEntries.begin();
+ it != m_mapEntries.end(); ++it ) {
+ Entry* e = &( *it );
+ if ( e->wd == event->wd ) {
+ e->dirty = true;
+
+ if ( 1 || e->isDir) {
+ if( event->mask & IN_DELETE_SELF) {
+ kdDebug(7001) << "-->got deleteself signal for " << e->path << endl;
+ e->m_status = NonExistent;
+ if (e->isDir)
+ addEntry(0, TQDir::cleanDirPath(e->path+"/.."), e, true);
+ else
+ addEntry(0, TQFileInfo(e->path).dirPath(true), e, true);
+ }
+ if ( event->mask & IN_IGNORED ) {
+ e->wd = 0;
+ }
+ if ( event->mask & (IN_CREATE|IN_MOVED_TO) ) {
+ Entry *sub_entry = e->m_entries.first();
+ for(;sub_entry; sub_entry = e->m_entries.next())
+ if (sub_entry->path == e->path + "/" + path) break;
+
+ if (sub_entry /*&& sub_entry->isDir*/) {
+ removeEntry(0,e->path, sub_entry);
+ KDE_struct_stat stat_buf;
+ TQCString tpath = TQFile::encodeName(path);
+ KDE_stat(tpath, &stat_buf);
+
+ //sub_entry->isDir = S_ISDIR(stat_buf.st_mode);
+ //sub_entry->m_ctime = stat_buf.st_ctime;
+ //sub_entry->m_status = Normal;
+ //sub_entry->m_nlink = stat_buf.st_nlink;
+
+ if(!useINotify(sub_entry))
+ useStat(sub_entry);
+ sub_entry->dirty = true;
+ }
+ }
+ }
+
+ if (!rescan_timer.isActive())
+ rescan_timer.start(m_PollInterval, true /* singleshot */);
+
+ break; // there really should be only one matching wd
+ }
+ }
+
+ }
+ }
+#endif
+}
+
+/* In DNOTIFY/FAM mode, only entries which are marked dirty are scanned.
+ * We first need to mark all yet nonexistent, but possible created
+ * entries as dirty...
+ */
+void KDirWatchPrivate::Entry::propagate_dirty()
+{
+ for (TQPtrListIterator<Entry> sub_entry (m_entries);
+ sub_entry.current(); ++sub_entry)
+ {
+ if (!sub_entry.current()->dirty)
+ {
+ sub_entry.current()->dirty = true;
+ sub_entry.current()->propagate_dirty();
+ }
+ }
+}
+
+
+/* A KDirWatch instance is interested in getting events for
+ * this file/Dir entry.
+ */
+void KDirWatchPrivate::Entry::addClient(KDirWatch* instance)
+{
+ Client* client = m_clients.first();
+ for(;client; client = m_clients.next())
+ if (client->instance == instance) break;
+
+ if (client) {
+ client->count++;
+ return;
+ }
+
+ client = new Client;
+ client->instance = instance;
+ client->count = 1;
+ client->watchingStopped = instance->isStopped();
+ client->pending = NoChange;
+
+ m_clients.append(client);
+}
+
+void KDirWatchPrivate::Entry::removeClient(KDirWatch* instance)
+{
+ Client* client = m_clients.first();
+ for(;client; client = m_clients.next())
+ if (client->instance == instance) break;
+
+ if (client) {
+ client->count--;
+ if (client->count == 0) {
+ m_clients.removeRef(client);
+ delete client;
+ }
+ }
+}
+
+/* get number of clients */
+int KDirWatchPrivate::Entry::clients()
+{
+ int clients = 0;
+ Client* client = m_clients.first();
+ for(;client; client = m_clients.next())
+ clients += client->count;
+
+ return clients;
+}
+
+
+KDirWatchPrivate::Entry* KDirWatchPrivate::entry(const TQString& _path)
+{
+// we only support absolute paths
+ if (TQDir::isRelativePath(_path)) {
+ return 0;
+ }
+
+ TQString path = _path;
+
+ if ( path.length() > 1 && path.right(1) == "/" )
+ path.truncate( path.length() - 1 );
+
+ EntryMap::Iterator it = m_mapEntries.find( path );
+ if ( it == m_mapEntries.end() )
+ return 0;
+ else
+ return &(*it);
+}
+
+// set polling frequency for a entry and adjust global freq if needed
+void KDirWatchPrivate::useFreq(Entry* e, int newFreq)
+{
+ e->freq = newFreq;
+
+ // a reasonable frequency for the global polling timer
+ if (e->freq < freq) {
+ freq = e->freq;
+ if (timer->isActive()) timer->changeInterval(freq);
+ kdDebug(7001) << "Global Poll Freq is now " << freq << " msec" << endl;
+ }
+}
+
+
+#ifdef HAVE_FAM
+// setup FAM notification, returns false if not possible
+bool KDirWatchPrivate::useFAM(Entry* e)
+{
+ if (!use_fam) return false;
+
+ // handle FAM events to avoid deadlock
+ // (FAM sends back all files in a directory when monitoring)
+ famEventReceived();
+
+ e->m_mode = FAMMode;
+ e->dirty = false;
+
+ if (e->isDir) {
+ if (e->m_status == NonExistent) {
+ // If the directory does not exist we watch the parent directory
+ addEntry(0, TQDir::cleanDirPath(e->path+"/.."), e, true);
+ }
+ else {
+ int res =FAMMonitorDirectory(&fc, TQFile::encodeName(e->path),
+ &(e->fr), e);
+ if (res<0) {
+ e->m_mode = UnknownMode;
+ use_fam=false;
+ return false;
+ }
+ kdDebug(7001) << " Setup FAM (Req "
+ << FAMREQUEST_GETREQNUM(&(e->fr))
+ << ") for " << e->path << endl;
+ }
+ }
+ else {
+ if (e->m_status == NonExistent) {
+ // If the file does not exist we watch the directory
+ addEntry(0, TQFileInfo(e->path).dirPath(true), e, true);
+ }
+ else {
+ int res = FAMMonitorFile(&fc, TQFile::encodeName(e->path),
+ &(e->fr), e);
+ if (res<0) {
+ e->m_mode = UnknownMode;
+ use_fam=false;
+ return false;
+ }
+
+ kdDebug(7001) << " Setup FAM (Req "
+ << FAMREQUEST_GETREQNUM(&(e->fr))
+ << ") for " << e->path << endl;
+ }
+ }
+
+ // handle FAM events to avoid deadlock
+ // (FAM sends back all files in a directory when monitoring)
+ famEventReceived();
+
+ return true;
+}
+#endif
+
+
+#ifdef HAVE_DNOTIFY
+// setup DNotify notification, returns false if not possible
+bool KDirWatchPrivate::useDNotify(Entry* e)
+{
+ e->dn_fd = 0;
+ e->dirty = false;
+ if (!supports_dnotify) return false;
+
+ e->m_mode = DNotifyMode;
+
+ if (e->isDir) {
+ if (e->m_status == Normal) {
+ int fd = KDE_open(TQFile::encodeName(e->path).data(), O_RDONLY);
+ // Migrate fd to somewhere above 128. Some libraries have
+ // constructs like:
+ // fd = socket(...)
+ // if (fd > ARBITRARY_LIMIT)
+ // return error;
+ //
+ // Since programs might end up using a lot of KDirWatch objects
+ // for a rather long time the above braindamage could get
+ // triggered.
+ //
+ // By moving the kdirwatch fd's to > 128, calls like socket() will keep
+ // returning fd's < ARBITRARY_LIMIT for a bit longer.
+ int fd2 = fcntl(fd, F_DUPFD, 128);
+ if (fd2 >= 0)
+ {
+ close(fd);
+ fd = fd2;
+ }
+ if (fd<0) {
+ e->m_mode = UnknownMode;
+ return false;
+ }
+
+ int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT;
+ // if dependant is a file watch, we check for MODIFY & ATTRIB too
+ for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next())
+ if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; }
+
+ if(fcntl(fd, F_SETSIG, dnotify_signal) < 0 ||
+ fcntl(fd, F_NOTIFY, mask) < 0) {
+
+ kdDebug(7001) << "Not using Linux Directory Notifications."
+ << endl;
+ supports_dnotify = false;
+ ::close(fd);
+ e->m_mode = UnknownMode;
+ return false;
+ }
+
+ fd_Entry.replace(fd, e);
+ e->dn_fd = fd;
+
+ kdDebug(7001) << " Setup DNotify (fd " << fd
+ << ") for " << e->path << endl;
+ }
+ else { // NotExisting
+ addEntry(0, TQDir::cleanDirPath(e->path+"/.."), e, true);
+ }
+ }
+ else { // File
+ // we always watch the directory (DNOTIFY can't watch files alone)
+ // this notifies us about changes of files therein
+ addEntry(0, TQFileInfo(e->path).dirPath(true), e, true);
+ }
+
+ return true;
+}
+#endif
+
+#ifdef HAVE_INOTIFY
+// setup INotify notification, returns false if not possible
+bool KDirWatchPrivate::useINotify( Entry* e )
+{
+ e->wd = 0;
+ e->dirty = false;
+ if (!supports_inotify) return false;
+
+ e->m_mode = INotifyMode;
+
+ int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF|IN_DONT_FOLLOW;
+ if(!e->isDir)
+ mask |= IN_MODIFY|IN_ATTRIB;
+ else
+ mask |= IN_ONLYDIR;
+
+ // if dependant is a file watch, we check for MODIFY & ATTRIB too
+ for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next()) {
+ if (!dep->isDir) { mask |= IN_MODIFY|IN_ATTRIB; break; }
+ }
+
+ if ( ( e->wd = inotify_add_watch( m_inotify_fd,
+ TQFile::encodeName( e->path ), mask) ) > 0 )
+ return true;
+
+ if ( e->m_status == NonExistent ) {
+ if (e->isDir)
+ addEntry(0, TQDir::cleanDirPath(e->path+"/.."), e, true);
+ else
+ addEntry(0, TQFileInfo(e->path).dirPath(true), e, true);
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+bool KDirWatchPrivate::useStat(Entry* e)
+{
+ if ( e->path.startsWith("/media/") || (e->path == "/media")
+ || (TDEIO::probably_slow_mounted(e->path)) )
+ useFreq(e, m_nfsPollInterval);
+ else
+ useFreq(e, m_PollInterval);
+
+ if (e->m_mode != StatMode) {
+ e->m_mode = StatMode;
+ statEntries++;
+
+ if ( statEntries == 1 ) {
+ // if this was first STAT entry (=timer was stopped)
+ timer->start(freq); // then start the timer
+ kdDebug(7001) << " Started Polling Timer, freq " << freq << endl;
+ }
+ }
+
+ kdDebug(7001) << " Setup Stat (freq " << e->freq
+ << ") for " << e->path << endl;
+
+ return true;
+}
+
+
+/* If <instance> !=0, this KDirWatch instance wants to watch at <_path>,
+ * providing in <isDir> the type of the entry to be watched.
+ * Sometimes, entries are dependant on each other: if <sub_entry> !=0,
+ * this entry needs another entry to watch himself (when notExistent).
+ */
+void KDirWatchPrivate::addEntry(KDirWatch* instance, const TQString& _path,
+ Entry* sub_entry, bool isDir)
+{
+ TQString path = _path;
+ if (path.startsWith("/dev/") || (path == "/dev"))
+ return; // Don't even go there.
+
+ if ( path.length() > 1 && path.right(1) == "/" )
+ path.truncate( path.length() - 1 );
+
+ EntryMap::Iterator it = m_mapEntries.find( path );
+ if ( it != m_mapEntries.end() )
+ {
+ if (sub_entry) {
+ (*it).m_entries.append(sub_entry);
+ kdDebug(7001) << "Added already watched Entry " << path
+ << " (for " << sub_entry->path << ")" << endl;
+
+#ifdef HAVE_DNOTIFY
+ {
+ Entry* e = &(*it);
+ if( (e->m_mode == DNotifyMode) && (e->dn_fd > 0) ) {
+ int mask = DN_DELETE|DN_CREATE|DN_RENAME|DN_MULTISHOT;
+ // if dependant is a file watch, we check for MODIFY & ATTRIB too
+ for(Entry* dep=e->m_entries.first();dep;dep=e->m_entries.next())
+ if (!dep->isDir) { mask |= DN_MODIFY|DN_ATTRIB; break; }
+ if( fcntl(e->dn_fd, F_NOTIFY, mask) < 0) { // shouldn't happen
+ ::close(e->dn_fd);
+ e->m_mode = UnknownMode;
+ fd_Entry.remove(e->dn_fd);
+ e->dn_fd = 0;
+ useStat( e );
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_INOTIFY
+ {
+ Entry* e = &(*it);
+ if( (e->m_mode == INotifyMode) && (e->wd > 0) ) {
+ int mask = IN_DELETE|IN_DELETE_SELF|IN_CREATE|IN_MOVE|IN_MOVE_SELF|IN_DONT_FOLLOW;
+ if(!e->isDir)
+ mask |= IN_MODIFY|IN_ATTRIB;
+ else
+ mask |= IN_ONLYDIR;
+
+ inotify_rm_watch (m_inotify_fd, e->wd);
+ e->wd = inotify_add_watch( m_inotify_fd, TQFile::encodeName( e->path ), mask);
+ }
+ }
+#endif
+
+ }
+ else {
+ (*it).addClient(instance);
+ kdDebug(7001) << "Added already watched Entry " << path
+ << " (now " << (*it).clients() << " clients)"
+ << TQString(TQString(" [%1]").arg(instance->name())) << endl;
+ }
+ return;
+ }
+
+ // we have a new path to watch
+
+ KDE_struct_stat stat_buf;
+ TQCString tpath = TQFile::encodeName(path);
+ bool exists = (KDE_stat(tpath, &stat_buf) == 0);
+
+ Entry newEntry;
+ m_mapEntries.insert( path, newEntry );
+ // the insert does a copy, so we have to use <e> now
+ Entry* e = &(m_mapEntries[path]);
+
+ if (exists) {
+ e->isDir = S_ISDIR(stat_buf.st_mode);
+
+ if (e->isDir && !isDir)
+ kdWarning() << "KDirWatch: " << path << " is a directory. Use addDir!" << endl;
+ else if (!e->isDir && isDir)
+ kdWarning() << "KDirWatch: " << path << " is a file. Use addFile!" << endl;
+
+ e->m_ctime = stat_buf.st_ctime;
+ e->m_status = Normal;
+ e->m_nlink = stat_buf.st_nlink;
+ }
+ else {
+ e->isDir = isDir;
+ e->m_ctime = invalid_ctime;
+ e->m_status = NonExistent;
+ e->m_nlink = 0;
+ }
+
+ e->path = path;
+ if (sub_entry)
+ e->m_entries.append(sub_entry);
+ else
+ e->addClient(instance);
+
+ kdDebug(7001) << "Added " << (e->isDir ? "Dir ":"File ") << path
+ << (e->m_status == NonExistent ? " NotExisting" : "")
+ << (sub_entry ? TQString(TQString(" for %1").arg(sub_entry->path)) : TQString(""))
+ << (instance ? TQString(TQString(" [%1]").arg(instance->name())) : TQString(""))
+ << endl;
+
+
+ // now setup the notification method
+ e->m_mode = UnknownMode;
+ e->msecLeft = 0;
+
+ if ( isNoisyFile( tpath ) )
+ return;
+
+#ifdef HAVE_FAM
+ if (useFAM(e)) return;
+#endif
+
+#ifdef HAVE_INOTIFY
+ if (useINotify(e)) return;
+#endif
+
+#ifdef HAVE_DNOTIFY
+ if (useDNotify(e)) return;
+#endif
+
+ useStat(e);
+}
+
+
+void KDirWatchPrivate::removeEntry( KDirWatch* instance,
+ const TQString& _path, Entry* sub_entry )
+{
+ kdDebug(7001) << "KDirWatchPrivate::removeEntry for '" << _path << "' sub_entry: " << sub_entry << endl;
+ Entry* e = entry(_path);
+ if (!e) {
+ kdDebug(7001) << "KDirWatchPrivate::removeEntry can't handle '" << _path << "'" << endl;
+ return;
+ }
+
+ if (sub_entry)
+ e->m_entries.removeRef(sub_entry);
+ else
+ e->removeClient(instance);
+
+ if (e->m_clients.count() || e->m_entries.count()) {
+ kdDebug(7001) << "removeEntry: unwatched " << e->path << " " << _path << endl;
+ return;
+ }
+
+ if (delayRemove) {
+ // removeList is allowed to contain any entry at most once
+ if (removeList.findRef(e)==-1)
+ removeList.append(e);
+ // now e->isValid() is false
+ return;
+ }
+
+#ifdef HAVE_FAM
+ if (e->m_mode == FAMMode) {
+ if ( e->m_status == Normal) {
+ FAMCancelMonitor(&fc, &(e->fr) );
+ kdDebug(7001) << "Cancelled FAM (Req "
+ << FAMREQUEST_GETREQNUM(&(e->fr))
+ << ") for " << e->path << endl;
+ }
+ else {
+ if (e->isDir)
+ removeEntry(0, TQDir::cleanDirPath(e->path+"/.."), e);
+ else
+ removeEntry(0, TQFileInfo(e->path).dirPath(true), e);
+ }
+ }
+#endif
+
+#ifdef HAVE_INOTIFY
+ kdDebug(7001) << "inotify remove " << ( e->m_mode == INotifyMode ) << " " << ( e->m_status == Normal ) << endl;
+ if (e->m_mode == INotifyMode) {
+ if ( e->m_status == Normal ) {
+ (void) inotify_rm_watch( m_inotify_fd, e->wd );
+ kdDebug(7001) << "Cancelled INotify (fd " <<
+ m_inotify_fd << ", " << e->wd <<
+ ") for " << e->path << endl;
+ }
+ else {
+ if (e->isDir)
+ removeEntry(0, TQDir::cleanDirPath(e->path+"/.."), e);
+ else
+ removeEntry(0, TQFileInfo(e->path).dirPath(true), e);
+ }
+ }
+#endif
+
+#ifdef HAVE_DNOTIFY
+ if (e->m_mode == DNotifyMode) {
+ if (!e->isDir) {
+ removeEntry(0, TQFileInfo(e->path).dirPath(true), e);
+ }
+ else { // isDir
+ // must close the FD.
+ if ( e->m_status == Normal) {
+ if (e->dn_fd) {
+ ::close(e->dn_fd);
+ fd_Entry.remove(e->dn_fd);
+
+ kdDebug(7001) << "Cancelled DNotify (fd " << e->dn_fd
+ << ") for " << e->path << endl;
+ e->dn_fd = 0;
+
+ }
+ }
+ else {
+ removeEntry(0, TQDir::cleanDirPath(e->path+"/.."), e);
+ }
+ }
+ }
+#endif
+
+ if (e->m_mode == StatMode) {
+ statEntries--;
+ if ( statEntries == 0 ) {
+ timer->stop(); // stop timer if lists are empty
+ kdDebug(7001) << " Stopped Polling Timer" << endl;
+ }
+ }
+
+ kdDebug(7001) << "Removed " << (e->isDir ? "Dir ":"File ") << e->path
+ << (sub_entry ? TQString(TQString(" for %1").arg(sub_entry->path)) : TQString(""))
+ << (instance ? TQString(TQString(" [%1]").arg(instance->name())) : TQString(""))
+ << endl;
+ m_mapEntries.remove( e->path ); // <e> not valid any more
+}
+
+
+/* Called from KDirWatch destructor:
+ * remove <instance> as client from all entries
+ */
+void KDirWatchPrivate::removeEntries( KDirWatch* instance )
+{
+ TQPtrList<Entry> list;
+ int minfreq = 3600000;
+
+ // put all entries where instance is a client in list
+ EntryMap::Iterator it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it ) {
+ Client* c = (*it).m_clients.first();
+ for(;c;c=(*it).m_clients.next())
+ if (c->instance == instance) break;
+ if (c) {
+ c->count = 1; // forces deletion of instance as client
+ list.append(&(*it));
+ }
+ else if ( (*it).m_mode == StatMode && (*it).freq < minfreq )
+ minfreq = (*it).freq;
+ }
+
+ for(Entry* e=list.first();e;e=list.next())
+ removeEntry(instance, e->path, 0);
+
+ if (minfreq > freq) {
+ // we can decrease the global polling frequency
+ freq = minfreq;
+ if (timer->isActive()) timer->changeInterval(freq);
+ kdDebug(7001) << "Poll Freq now " << freq << " msec" << endl;
+ }
+}
+
+// instance ==0: stop scanning for all instances
+bool KDirWatchPrivate::stopEntryScan( KDirWatch* instance, Entry* e)
+{
+ int stillWatching = 0;
+ Client* c = e->m_clients.first();
+ for(;c;c=e->m_clients.next()) {
+ if (!instance || instance == c->instance)
+ c->watchingStopped = true;
+ else if (!c->watchingStopped)
+ stillWatching += c->count;
+ }
+
+ kdDebug(7001) << instance->name() << " stopped scanning " << e->path
+ << " (now " << stillWatching << " watchers)" << endl;
+
+ if (stillWatching == 0) {
+ // if nobody is interested, we don't watch
+ e->m_ctime = invalid_ctime; // invalid
+ e->m_status = NonExistent;
+ // e->m_status = Normal;
+ }
+ return true;
+}
+
+// instance ==0: start scanning for all instances
+bool KDirWatchPrivate::restartEntryScan( KDirWatch* instance, Entry* e,
+ bool notify)
+{
+ int wasWatching = 0, newWatching = 0;
+ Client* c = e->m_clients.first();
+ for(;c;c=e->m_clients.next()) {
+ if (!c->watchingStopped)
+ wasWatching += c->count;
+ else if (!instance || instance == c->instance) {
+ c->watchingStopped = false;
+ newWatching += c->count;
+ }
+ }
+ if (newWatching == 0)
+ return false;
+
+ kdDebug(7001) << (instance ? instance->name() : "all") << " restarted scanning " << e->path
+ << " (now " << wasWatching+newWatching << " watchers)" << endl;
+
+ // restart watching and emit pending events
+
+ int ev = NoChange;
+ if (wasWatching == 0) {
+ if (!notify) {
+ KDE_struct_stat stat_buf;
+ bool exists = (KDE_stat(TQFile::encodeName(e->path), &stat_buf) == 0);
+ if (exists) {
+ e->m_ctime = stat_buf.st_ctime;
+ e->m_status = Normal;
+ e->m_nlink = stat_buf.st_nlink;
+ }
+ else {
+ e->m_ctime = invalid_ctime;
+ e->m_status = NonExistent;
+ e->m_nlink = 0;
+ }
+ }
+ e->msecLeft = 0;
+ ev = scanEntry(e);
+ }
+ emitEvent(e,ev);
+
+ return true;
+}
+
+// instance ==0: stop scanning for all instances
+void KDirWatchPrivate::stopScan(KDirWatch* instance)
+{
+ EntryMap::Iterator it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ stopEntryScan(instance, &(*it));
+}
+
+
+void KDirWatchPrivate::startScan(KDirWatch* instance,
+ bool notify, bool skippedToo )
+{
+ if (!notify)
+ resetList(instance,skippedToo);
+
+ EntryMap::Iterator it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ restartEntryScan(instance, &(*it), notify);
+
+ // timer should still be running when in polling mode
+}
+
+
+// clear all pending events, also from stopped
+void KDirWatchPrivate::resetList( KDirWatch* /*instance*/,
+ bool skippedToo )
+{
+ EntryMap::Iterator it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it ) {
+
+ Client* c = (*it).m_clients.first();
+ for(;c;c=(*it).m_clients.next())
+ if (!c->watchingStopped || skippedToo)
+ c->pending = NoChange;
+ }
+}
+
+// Return event happened on <e>
+//
+int KDirWatchPrivate::scanEntry(Entry* e)
+{
+#ifdef HAVE_FAM
+ if (e->m_mode == FAMMode) {
+ // we know nothing has changed, no need to stat
+ if(!e->dirty) return NoChange;
+ e->dirty = false;
+ }
+ if (e->isDir) return Changed;
+#endif
+
+ // Shouldn't happen: Ignore "unknown" notification method
+ if (e->m_mode == UnknownMode) return NoChange;
+
+#if defined ( HAVE_DNOTIFY ) || defined( HAVE_INOTIFY )
+ if (e->m_mode == DNotifyMode || e->m_mode == INotifyMode ) {
+ // we know nothing has changed, no need to stat
+ if(!e->dirty) return NoChange;
+ kdDebug(7001) << "scanning " << e->path << " " << e->m_status << " " << e->m_ctime << endl;
+ e->dirty = false;
+ }
+#endif
+
+ if (e->m_mode == StatMode) {
+ // only scan if timeout on entry timer happens;
+ // e.g. when using 500msec global timer, a entry
+ // with freq=5000 is only watched every 10th time
+
+ e->msecLeft -= freq;
+ if (e->msecLeft>0) return NoChange;
+ e->msecLeft += e->freq;
+ }
+
+ KDE_struct_stat stat_buf;
+ bool exists = (KDE_stat(TQFile::encodeName(e->path), &stat_buf) == 0);
+ if (exists) {
+
+ if (e->m_status == NonExistent) {
+ // ctime is the 'creation time' on windows, but with qMax
+ // we get the latest change of any kind, on any platform.
+ e->m_ctime = stat_buf.st_ctime;
+ e->m_status = Normal;
+ e->m_nlink = stat_buf.st_nlink;
+ return Created;
+ }
+
+ if ( (e->m_ctime != invalid_ctime) &&
+ ((stat_buf.st_ctime != e->m_ctime) ||
+ (stat_buf.st_nlink != (nlink_t) e->m_nlink)) ) {
+ e->m_ctime = stat_buf.st_ctime;
+ e->m_nlink = stat_buf.st_nlink;
+ return Changed;
+ }
+
+ return NoChange;
+ }
+
+ // dir/file doesn't exist
+
+ if (e->m_ctime == invalid_ctime && e->m_status == NonExistent) {
+ e->m_nlink = 0;
+ e->m_status = NonExistent;
+ return NoChange;
+ }
+
+ e->m_ctime = invalid_ctime;
+ e->m_nlink = 0;
+ e->m_status = NonExistent;
+
+ return Deleted;
+}
+
+/* Notify all interested KDirWatch instances about a given event on an entry
+ * and stored pending events. When watching is stopped, the event is
+ * added to the pending events.
+ */
+void KDirWatchPrivate::emitEvent(Entry* e, int event, const TQString &fileName)
+{
+ TQString path = e->path;
+ if (!fileName.isEmpty()) {
+ if (!TQDir::isRelativePath(fileName))
+ path = fileName;
+ else
+#ifdef Q_OS_UNIX
+ path += "/" + fileName;
+#elif defined(Q_WS_WIN)
+ //current drive is passed instead of /
+ path += TQDir::currentDirPath().left(2) + "/" + fileName;
+#endif
+ }
+
+ TQPtrListIterator<Client> cit( e->m_clients );
+ for ( ; cit.current(); ++cit )
+ {
+ Client* c = cit.current();
+
+ if (c->instance==0 || c->count==0) continue;
+
+ if (c->watchingStopped) {
+ // add event to pending...
+ if (event == Changed)
+ c->pending |= event;
+ else if (event == Created || event == Deleted)
+ c->pending = event;
+ continue;
+ }
+ // not stopped
+ if (event == NoChange || event == Changed)
+ event |= c->pending;
+ c->pending = NoChange;
+ if (event == NoChange) continue;
+
+ if (event & Deleted) {
+ c->instance->setDeleted(path);
+ // emit only Deleted event...
+ continue;
+ }
+
+ if (event & Created) {
+ c->instance->setCreated(path);
+ // possible emit Change event after creation
+ }
+
+ if (event & Changed)
+ c->instance->setDirty(path);
+ }
+}
+
+// Remove entries which were marked to be removed
+void KDirWatchPrivate::slotRemoveDelayed()
+{
+ Entry* e;
+ delayRemove = false;
+ for(e=removeList.first();e;e=removeList.next())
+ removeEntry(0, e->path, 0);
+ removeList.clear();
+}
+
+/* Scan all entries to be watched for changes. This is done regularly
+ * when polling and once after a DNOTIFY signal. This is NOT used by FAM.
+ */
+void KDirWatchPrivate::slotRescan()
+{
+ EntryMap::Iterator it;
+
+ // People can do very long things in the slot connected to dirty(),
+ // like showing a message box. We don't want to keep polling during
+ // that time, otherwise the value of 'delayRemove' will be reset.
+ bool timerRunning = timer->isActive();
+ if ( timerRunning )
+ timer->stop();
+
+ // We delay deletions of entries this way.
+ // removeDir(), when called in slotDirty(), can cause a crash otherwise
+ delayRemove = true;
+
+#if defined(HAVE_DNOTIFY) || defined(HAVE_INOTIFY)
+ TQPtrList<Entry> dList, cList;
+#endif
+
+ if (rescan_all)
+ {
+ // mark all as dirty
+ it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ (*it).dirty = true;
+ rescan_all = false;
+ }
+ else
+ {
+ // progate dirty flag to dependant entries (e.g. file watches)
+ it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ if (((*it).m_mode == INotifyMode || (*it).m_mode == DNotifyMode) && (*it).dirty )
+ (*it).propagate_dirty();
+ }
+
+ it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it ) {
+ // we don't check invalid entries (i.e. remove delayed)
+ if (!(*it).isValid()) continue;
+
+ int ev = scanEntry( &(*it) );
+
+
+#ifdef HAVE_INOTIFY
+ if ((*it).m_mode == INotifyMode && ev == Created && (*it).wd == 0) {
+ cList.append( &(*it) );
+ if (! useINotify( &(*it) )) {
+ useStat( &(*it) );
+ }
+ }
+#endif
+
+#ifdef HAVE_DNOTIFY
+ if ((*it).m_mode == DNotifyMode) {
+ if ((*it).isDir && (ev == Deleted)) {
+ dList.append( &(*it) );
+
+ // must close the FD.
+ if ((*it).dn_fd) {
+ ::close((*it).dn_fd);
+ fd_Entry.remove((*it).dn_fd);
+ (*it).dn_fd = 0;
+ }
+ }
+
+ else if ((*it).isDir && (ev == Created)) {
+ // For created, but yet without DNOTIFYing ...
+ if ( (*it).dn_fd == 0) {
+ cList.append( &(*it) );
+ if (! useDNotify( &(*it) )) {
+ // if DNotify setup fails...
+ useStat( &(*it) );
+ }
+ }
+ }
+ }
+#endif
+
+ if ( ev != NoChange )
+ emitEvent( &(*it), ev);
+ }
+
+
+#if defined(HAVE_DNOTIFY) || defined(HAVE_INOTIFY)
+ // Scan parent of deleted directories for new creation
+ Entry* e;
+ for(e=dList.first();e;e=dList.next())
+ addEntry(0, TQDir::cleanDirPath( e->path+"/.."), e, true);
+
+ // Remove watch of parent of new created directories
+ for(e=cList.first();e;e=cList.next())
+ removeEntry(0, TQDir::cleanDirPath( e->path+"/.."), e);
+#endif
+
+ if ( timerRunning )
+ timer->start(freq);
+
+ TQTimer::singleShot(0, this, TQT_SLOT(slotRemoveDelayed()));
+}
+
+bool KDirWatchPrivate::isNoisyFile( const char * filename )
+{
+ // $HOME/.X.err grows with debug output, so don't notify change
+ if ( *filename == '.') {
+ if (strncmp(filename, ".X.err", 6) == 0) return true;
+ if (strncmp(filename, ".xsession-errors", 16) == 0) return true;
+ // fontconfig updates the cache on every KDE app start
+ // (inclusive kio_thumbnail slaves)
+ if (strncmp(filename, ".fonts.cache", 12) == 0) return true;
+ }
+
+ return false;
+}
+
+#ifdef HAVE_FAM
+void KDirWatchPrivate::famEventReceived()
+{
+ static FAMEvent fe;
+
+ delayRemove = true;
+
+ while(use_fam && FAMPending(&fc)) {
+ if (FAMNextEvent(&fc, &fe) == -1) {
+ kdWarning(7001) << "FAM connection problem, switching to polling."
+ << endl;
+ use_fam = false;
+ delete sn; sn = 0;
+
+ // Replace all FAMMode entries with DNotify/Stat
+ EntryMap::Iterator it;
+ it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ if ((*it).m_mode == FAMMode && (*it).m_clients.count()>0) {
+#ifdef HAVE_INOTIFY
+ if (useINotify( &(*it) )) continue;
+#endif
+#ifdef HAVE_DNOTIFY
+ if (useDNotify( &(*it) )) continue;
+#endif
+ useStat( &(*it) );
+ }
+ }
+ else
+ checkFAMEvent(&fe);
+ }
+
+ TQTimer::singleShot(0, this, TQT_SLOT(slotRemoveDelayed()));
+}
+
+void KDirWatchPrivate::checkFAMEvent(FAMEvent* fe)
+{
+ // Don't be too verbose ;-)
+ if ((fe->code == FAMExists) ||
+ (fe->code == FAMEndExist) ||
+ (fe->code == FAMAcknowledge)) return;
+
+ if ( isNoisyFile( fe->filename ) )
+ return;
+
+ Entry* e = 0;
+ EntryMap::Iterator it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it )
+ if (FAMREQUEST_GETREQNUM(&( (*it).fr )) ==
+ FAMREQUEST_GETREQNUM(&(fe->fr)) ) {
+ e = &(*it);
+ break;
+ }
+
+ // Entry* e = static_cast<Entry*>(fe->userdata);
+
+#if 0 // #88538
+ kdDebug(7001) << "Processing FAM event ("
+ << ((fe->code == FAMChanged) ? "FAMChanged" :
+ (fe->code == FAMDeleted) ? "FAMDeleted" :
+ (fe->code == FAMStartExecuting) ? "FAMStartExecuting" :
+ (fe->code == FAMStopExecuting) ? "FAMStopExecuting" :
+ (fe->code == FAMCreated) ? "FAMCreated" :
+ (fe->code == FAMMoved) ? "FAMMoved" :
+ (fe->code == FAMAcknowledge) ? "FAMAcknowledge" :
+ (fe->code == FAMExists) ? "FAMExists" :
+ (fe->code == FAMEndExist) ? "FAMEndExist" : "Unknown Code")
+ << ", " << fe->filename
+ << ", Req " << FAMREQUEST_GETREQNUM(&(fe->fr))
+ << ")" << endl;
+#endif
+
+ if (!e) {
+ // this happens e.g. for FAMAcknowledge after deleting a dir...
+ // kdDebug(7001) << "No entry for FAM event ?!" << endl;
+ return;
+ }
+
+ if (e->m_status == NonExistent) {
+ kdDebug(7001) << "FAM event for nonExistent entry " << e->path << endl;
+ return;
+ }
+
+ // Delayed handling. This rechecks changes with own stat calls.
+ e->dirty = true;
+ if (!rescan_timer.isActive())
+ rescan_timer.start(m_PollInterval, true);
+
+ // needed FAM control actions on FAM events
+ if (e->isDir)
+ switch (fe->code)
+ {
+ case FAMDeleted:
+ // file absolute: watched dir
+ if (!TQDir::isRelativePath(fe->filename))
+ {
+ // a watched directory was deleted
+
+ e->m_status = NonExistent;
+ FAMCancelMonitor(&fc, &(e->fr) ); // needed ?
+ kdDebug(7001) << "Cancelled FAMReq "
+ << FAMREQUEST_GETREQNUM(&(e->fr))
+ << " for " << e->path << endl;
+ // Scan parent for a new creation
+ addEntry(0, TQDir::cleanDirPath( e->path+"/.."), e, true);
+ }
+ break;
+
+ case FAMCreated: {
+ // check for creation of a directory we have to watch
+ Entry *sub_entry = e->m_entries.first();
+ for(;sub_entry; sub_entry = e->m_entries.next())
+ if (sub_entry->path == e->path + "/" + fe->filename) break;
+ if (sub_entry && sub_entry->isDir) {
+ TQString path = e->path;
+ removeEntry(0,e->path,sub_entry); // <e> can be invalid here!!
+ sub_entry->m_status = Normal;
+ if (!useFAM(sub_entry))
+#ifdef HAVE_INOTIFY
+ if (!useINotify(sub_entry ))
+#endif
+ useStat(sub_entry);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+#else
+void KDirWatchPrivate::famEventReceived() {}
+#endif
+
+
+void KDirWatchPrivate::statistics()
+{
+ EntryMap::Iterator it;
+
+ kdDebug(7001) << "Entries watched:" << endl;
+ if (m_mapEntries.count()==0) {
+ kdDebug(7001) << " None." << endl;
+ }
+ else {
+ it = m_mapEntries.begin();
+ for( ; it != m_mapEntries.end(); ++it ) {
+ Entry* e = &(*it);
+ kdDebug(7001) << " " << e->path << " ("
+ << ((e->m_status==Normal)?"":"Nonexistent ")
+ << (e->isDir ? "Dir":"File") << ", using "
+ << ((e->m_mode == FAMMode) ? "FAM" :
+ (e->m_mode == INotifyMode) ? "INotify" :
+ (e->m_mode == DNotifyMode) ? "DNotify" :
+ (e->m_mode == StatMode) ? "Stat" : "Unknown Method")
+ << ")" << endl;
+
+ Client* c = e->m_clients.first();
+ for(;c; c = e->m_clients.next()) {
+ TQString pending;
+ if (c->watchingStopped) {
+ if (c->pending & Deleted) pending += "deleted ";
+ if (c->pending & Created) pending += "created ";
+ if (c->pending & Changed) pending += "changed ";
+ if (!pending.isEmpty()) pending = " (pending: " + pending + ")";
+ pending = ", stopped" + pending;
+ }
+ kdDebug(7001) << " by " << c->instance->name()
+ << " (" << c->count << " times)"
+ << pending << endl;
+ }
+ if (e->m_entries.count()>0) {
+ kdDebug(7001) << " dependent entries:" << endl;
+ Entry* d = e->m_entries.first();
+ for(;d; d = e->m_entries.next()) {
+ kdDebug(7001) << " " << d << endl;
+ kdDebug(7001) << " " << d->path << " (" << d << ") " << endl;
+ }
+ }
+ }
+ }
+}
+
+
+//
+// Class KDirWatch
+//
+
+static KStaticDeleter<KDirWatch> sd_dw;
+KDirWatch* KDirWatch::s_pSelf = 0L;
+
+KDirWatch* KDirWatch::self()
+{
+ if ( !s_pSelf ) {
+ sd_dw.setObject( s_pSelf, new KDirWatch );
+ }
+
+ return s_pSelf;
+}
+
+bool KDirWatch::exists()
+{
+ return s_pSelf != 0;
+}
+
+KDirWatch::KDirWatch (TQObject* parent, const char* name)
+ : TQObject(parent,name)
+{
+ if (!name) {
+ static int nameCounter = 0;
+
+ nameCounter++;
+ setName(TQString(TQString("KDirWatch-%1").arg(nameCounter)).ascii());
+ }
+
+ if (!dwp_self)
+ dwp_self = new KDirWatchPrivate;
+ d = dwp_self;
+ d->ref();
+
+ _isStopped = false;
+}
+
+KDirWatch::~KDirWatch()
+{
+ d->removeEntries(this);
+ if ( d->deref() )
+ {
+ // delete it if it's the last one
+ delete d;
+ dwp_self = 0L;
+ }
+}
+
+
+// TODO: add watchFiles/recursive support
+void KDirWatch::addDir( const TQString& _path,
+ bool watchFiles, bool recursive)
+{
+ if (watchFiles || recursive) {
+ kdDebug(7001) << "addDir - recursive/watchFiles not supported yet in KDE 3.x" << endl;
+ }
+ if (d) d->addEntry(this, _path, 0, true);
+}
+
+void KDirWatch::addFile( const TQString& _path )
+{
+ if (d) d->addEntry(this, _path, 0, false);
+}
+
+TQDateTime KDirWatch::ctime( const TQString &_path )
+{
+ KDirWatchPrivate::Entry* e = d->entry(_path);
+
+ if (!e)
+ return TQDateTime();
+
+ TQDateTime result;
+ result.setTime_t(e->m_ctime);
+ return result;
+}
+
+void KDirWatch::removeDir( const TQString& _path )
+{
+ if (d) d->removeEntry(this, _path, 0);
+}
+
+void KDirWatch::removeFile( const TQString& _path )
+{
+ if (d) d->removeEntry(this, _path, 0);
+}
+
+bool KDirWatch::stopDirScan( const TQString& _path )
+{
+ if (d) {
+ KDirWatchPrivate::Entry *e = d->entry(_path);
+ if (e && e->isDir) return d->stopEntryScan(this, e);
+ }
+ return false;
+}
+
+bool KDirWatch::restartDirScan( const TQString& _path )
+{
+ if (d) {
+ KDirWatchPrivate::Entry *e = d->entry(_path);
+ if (e && e->isDir)
+ // restart without notifying pending events
+ return d->restartEntryScan(this, e, false);
+ }
+ return false;
+}
+
+void KDirWatch::stopScan()
+{
+ if (d) d->stopScan(this);
+ _isStopped = true;
+}
+
+void KDirWatch::startScan( bool notify, bool skippedToo )
+{
+ _isStopped = false;
+ if (d) d->startScan(this, notify, skippedToo);
+}
+
+
+bool KDirWatch::contains( const TQString& _path ) const
+{
+ KDirWatchPrivate::Entry* e = d->entry(_path);
+ if (!e)
+ return false;
+
+ KDirWatchPrivate::Client* c = e->m_clients.first();
+ for(;c;c=e->m_clients.next())
+ if (c->instance == this) return true;
+
+ return false;
+}
+
+void KDirWatch::statistics()
+{
+ if (!dwp_self) {
+ kdDebug(7001) << "KDirWatch not used" << endl;
+ return;
+ }
+ dwp_self->statistics();
+}
+
+
+void KDirWatch::setCreated( const TQString & _file )
+{
+ kdDebug(7001) << name() << " emitting created " << _file << endl;
+ emit created( _file );
+}
+
+void KDirWatch::setDirty( const TQString & _file )
+{
+ kdDebug(7001) << name() << " emitting dirty " << _file << endl;
+ emit dirty( _file );
+}
+
+void KDirWatch::setDeleted( const TQString & _file )
+{
+ kdDebug(7001) << name() << " emitting deleted " << _file << endl;
+ emit deleted( _file );
+}
+
+KDirWatch::Method KDirWatch::internalMethod()
+{
+#ifdef HAVE_FAM
+ if (d->use_fam)
+ return KDirWatch::FAM;
+#endif
+#ifdef HAVE_INOTIFY
+ if (d->supports_inotify)
+ return KDirWatch::INotify;
+#endif
+#ifdef HAVE_DNOTIFY
+ if (d->supports_dnotify)
+ return KDirWatch::DNotify;
+#endif
+ return KDirWatch::Stat;
+}
+
+
+#include "kdirwatch.moc"
+#include "kdirwatch_p.moc"
+
+//sven
+
+// vim: sw=2 ts=8 et
diff --git a/tdeio/tdeio/kdirwatch.h b/tdeio/tdeio/kdirwatch.h
new file mode 100644
index 000000000..4abaa302e
--- /dev/null
+++ b/tdeio/tdeio/kdirwatch.h
@@ -0,0 +1,290 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1998 Sven Radej <sven@lisa.exp.univie.ac.at>
+
+ 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 _KDIRWATCH_H
+#define _KDIRWATCH_H
+
+#include <tqtimer.h>
+#include <tqdatetime.h>
+#include <tqmap.h>
+
+#include <tdelibs_export.h>
+
+#define kdirwatch KDirWatch::self()
+
+class KDirWatchPrivate;
+
+ /**
+ * Watch directories and files for changes.
+ * The watched directories or files don't have to exist yet.
+ *
+ * When a watched directory is changed, i.e. when files therein are
+ * created or deleted, KDirWatch will emit the signal dirty().
+ *
+ * When a watched, but previously not existing directory gets created,
+ * KDirWatch will emit the signal created().
+ *
+ * When a watched directory gets deleted, KDirWatch will emit the
+ * signal deleted(). The directory is still watched for new
+ * creation.
+ *
+ * When a watched file is changed, i.e. attributes changed or written
+ * to, KDirWatch will emit the signal dirty().
+ *
+ * Scanning of particular directories or files can be stopped temporarily
+ * and restarted. The whole class can be stopped and restarted.
+ * Directories and files can be added/removed from the list in any state.
+ *
+ * The implementation uses the FAM service when available;
+ * if FAM is not available, the DNOTIFY functionality is used on LINUX.
+ * As a last resort, a regular polling for change of modification times
+ * is done; the polling interval is a global config option:
+ * DirWatch/PollInterval and DirWatch/NFSPollInterval for NFS mounted
+ * directories.
+ *
+ * @see self()
+ * @short Class for watching directory and file changes.
+ * @author Sven Radej <sven@lisa.exp.univie.ac.at>
+ */
+class TDEIO_EXPORT KDirWatch : public TQObject
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor.
+ *
+ * Scanning begins immediately when a dir/file watch
+ * is added.
+ * @param parent the parent of the TQObject (or 0 for parent-less KDataTools)
+ * @param name the name of the TQObject, can be 0
+ */
+ KDirWatch (TQObject* parent = 0, const char* name = 0);
+
+ /**
+ * Destructor.
+ *
+ * Stops scanning and cleans up.
+ */
+ ~KDirWatch();
+
+ /**
+ * Adds a directory to be watched.
+ *
+ * The directory does not have to exist. When @p watchFiles is
+ * false (the default), the signals dirty(), created(), deleted()
+ * can be emitted, all for the watched directory.
+ * When @p watchFiles is true, all files in the watched directory
+ * are watched for changes, too. Thus, the signals dirty(),
+ * created(), deleted() can be emitted.
+ *
+ * @param path the path to watch
+ * @param watchFiles if true, the KDirWatch will also watch files - NOT IMPLEMENTED YET
+ * @param recursive if true, all sub directories are also watched - NOT IMPLEMENTED YET
+ */
+ void addDir(const TQString& path,
+ bool watchFiles = false, bool recursive = false);
+
+ /**
+ * Adds a file to be watched.
+ * @param file the file to watch
+ */
+ void addFile(const TQString& file);
+
+ /**
+ * Returns the time the directory/file was last changed.
+ * @param path the file to check
+ * @return the date of the last modification
+ */
+ TQDateTime ctime(const TQString& path);
+
+ /**
+ * Removes a directory from the list of scanned directories.
+ *
+ * If specified path is not in the list this does nothing.
+ * @param path the path of the dir to be removed from the list
+ */
+ void removeDir(const TQString& path);
+
+ /**
+ * Removes a file from the list of watched files.
+ *
+ * If specified path is not in the list this does nothing.
+ * @param file the file to be removed from the list
+ */
+ void removeFile(const TQString& file);
+
+ /**
+ * Stops scanning the specified path.
+ *
+ * The @p path is not deleted from the interal just, it is just skipped.
+ * Call this function when you perform an huge operation
+ * on this directory (copy/move big files or many files). When finished,
+ * call restartDirScan(path).
+ *
+ * @param path the path to skip
+ * @return true if the @p path is being watched, otherwise false
+ * @see restartDirScanning()
+ */
+ bool stopDirScan(const TQString& path);
+
+ /**
+ * Restarts scanning for specified path.
+ *
+ * Resets ctime. It doesn't notify
+ * the change (by emitted a signal), since the ctime value is reset.
+ *
+ * Call it when you are finished with big operations on that path,
+ * @em and when @em you have refreshed that path.
+ *
+ * @param path the path to restart scanning
+ * @return true if the @p path is being watched, otherwise false
+ * @see stopDirScanning()
+ */
+ bool restartDirScan(const TQString& path);
+
+ /**
+ * Starts scanning of all dirs in list.
+ *
+ * @param notify If true, all changed directories (since
+ * stopScan() call) will be notified for refresh. If notify is
+ * false, all ctimes will be reset (except those who are stopped,
+ * but only if @p skippedToo is false) and changed dirs won't be
+ * notified. You can start scanning even if the list is
+ * empty. First call should be called with @p false or else all
+ * directories
+ * in list will be notified.
+ * @param skippedToo if true, the skipped directoris (scanning of which was
+ * stopped with stopDirScan() ) will be reset and notified
+ * for change. Otherwise, stopped directories will continue to be
+ * unnotified.
+ */
+ void startScan( bool notify=false, bool skippedToo=false );
+
+ /**
+ * Stops scanning of all directories in internal list.
+ *
+ * The timer is stopped, but the list is not cleared.
+ */
+ void stopScan();
+
+ /**
+ * Is scanning stopped?
+ * After creation of a KDirWatch instance, this is false.
+ * @return true when scanning stopped
+ */
+ bool isStopped() { return _isStopped; }
+
+ /**
+ * Check if a directory is being watched by this KDirWatch instance
+ * @param path the directory to check
+ * @return true if the directory is being watched
+ */
+ bool contains( const TQString& path ) const;
+
+ /**
+ * Dump statistic information about all KDirWatch instances.
+ * This checks for consistency, too.
+ */
+ static void statistics();
+
+ /**
+ * Emits created().
+ * @param path the path of the file or directory
+ */
+ void setCreated( const TQString &path );
+ /**
+ * Emits dirty().
+ * @param path the path of the file or directory
+ */
+ void setDirty( const TQString &path );
+ /**
+ * Emits deleted().
+ * @param path the path of the file or directory
+ */
+ void setDeleted( const TQString &path );
+
+ enum Method { FAM, DNotify, Stat, INotify };
+ /**
+ * Returns the preferred internal method to
+ * watch for changes.
+ * @since 3.2
+ */
+ Method internalMethod();
+
+ /**
+ * The KDirWatch instance usually globally used in an application.
+ * It is automatically deleted when the application exits.
+ *
+ * However, you can create an arbitrary number of KDirWatch instances
+ * aside from this one - for those you have to take care of memory management.
+ *
+ * This function returns an instance of KDirWatch. If there is none, it
+ * will be created.
+ *
+ * @return a KDirWatch instance
+ */
+ static KDirWatch* self();
+ /**
+ * Returns true if there is an instance of KDirWatch.
+ * @return true if there is an instance of KDirWatch.
+ * @see KDirWatch::self()
+ * @since 3.1
+ */
+ static bool exists();
+
+ signals:
+
+ /**
+ * Emitted when a watched object is changed.
+ * For a directory this signal is emitted when files
+ * therein are created or deleted.
+ * For a file this signal is emitted when its size or attributes change.
+ *
+ * When you watch a directory, changes in the size or attributes of
+ * contained files may or may not trigger this signal to be emitted
+ * depending on which backend is used by KDirWatch.
+ *
+ * The new ctime is set before the signal is emitted.
+ * @param path the path of the file or directory
+ */
+ void dirty (const TQString &path);
+
+ /**
+ * Emitted when a file or directory is created.
+ * @param path the path of the file or directory
+ */
+ void created (const TQString &path );
+
+ /**
+ * Emitted when a file or directory is deleted.
+ *
+ * The object is still watched for new creation.
+ * @param path the path of the file or directory
+ */
+ void deleted (const TQString &path );
+
+ private:
+ bool _isStopped;
+
+ KDirWatchPrivate *d;
+ static KDirWatch* s_pSelf;
+};
+
+#endif
+
+// vim: sw=3 et
diff --git a/tdeio/tdeio/kdirwatch_p.h b/tdeio/tdeio/kdirwatch_p.h
new file mode 100644
index 000000000..8777f56b2
--- /dev/null
+++ b/tdeio/tdeio/kdirwatch_p.h
@@ -0,0 +1,158 @@
+/* Private Header for class of KDirWatchPrivate
+ *
+ * this separate header file is needed for MOC processing
+ * because KDirWatchPrivate has signals and slots
+ */
+
+#ifndef _KDIRWATCH_P_H
+#define _KDIRWATCH_P_H
+
+#ifdef HAVE_FAM
+#include <fam.h>
+#endif
+
+#include <ctime>
+
+#define invalid_ctime ((time_t)-1)
+
+/* KDirWatchPrivate is a singleton and does the watching
+ * for every KDirWatch instance in the application.
+ */
+class KDirWatchPrivate : public TQObject
+{
+ Q_OBJECT
+public:
+
+ enum entryStatus { Normal = 0, NonExistent };
+ enum entryMode { UnknownMode = 0, StatMode, DNotifyMode, INotifyMode, FAMMode };
+ enum { NoChange=0, Changed=1, Created=2, Deleted=4 };
+
+ struct Client {
+ KDirWatch* instance;
+ int count;
+ // did the instance stop watching
+ bool watchingStopped;
+ // events blocked when stopped
+ int pending;
+ };
+
+ class Entry
+ {
+ public:
+ // the last observed modification time
+ time_t m_ctime;
+ // the last observed link count
+ int m_nlink;
+ entryStatus m_status;
+ entryMode m_mode;
+ bool isDir;
+ // instances interested in events
+ TQPtrList<Client> m_clients;
+ // nonexistent entries of this directory
+ TQPtrList<Entry> m_entries;
+ TQString path;
+
+ int msecLeft, freq;
+
+ void addClient(KDirWatch*);
+ void removeClient(KDirWatch*);
+ int clients();
+ bool isValid() { return m_clients.count() || m_entries.count(); }
+
+ bool dirty;
+ void propagate_dirty();
+
+#ifdef HAVE_FAM
+ FAMRequest fr;
+#endif
+
+#ifdef HAVE_DNOTIFY
+ int dn_fd;
+#endif
+#ifdef HAVE_INOTIFY
+ int wd;
+#endif
+ };
+
+ typedef TQMap<TQString,Entry> EntryMap;
+
+ KDirWatchPrivate();
+ ~KDirWatchPrivate();
+
+ void resetList (KDirWatch*,bool);
+ void useFreq(Entry* e, int newFreq);
+ void addEntry(KDirWatch*,const TQString&, Entry*, bool);
+ void removeEntry(KDirWatch*,const TQString&, Entry*);
+ bool stopEntryScan(KDirWatch*, Entry*);
+ bool restartEntryScan(KDirWatch*, Entry*, bool );
+ void stopScan(KDirWatch*);
+ void startScan(KDirWatch*, bool, bool);
+
+ void removeEntries(KDirWatch*);
+ void statistics();
+
+ Entry* entry(const TQString&);
+ int scanEntry(Entry* e);
+ void emitEvent(Entry* e, int event, const TQString &fileName = TQString::null);
+
+ // Memory management - delete when last KDirWatch gets deleted
+ void ref() { m_ref++; }
+ bool deref() { return ( --m_ref == 0 ); }
+
+ static bool isNoisyFile( const char *filename );
+
+public slots:
+ void slotRescan();
+ void famEventReceived(); // for FAM
+ void slotActivated(); // for DNOTIFY
+ void slotRemoveDelayed();
+
+public:
+ TQTimer *timer;
+ EntryMap m_mapEntries;
+
+ int freq;
+ int statEntries;
+ int m_nfsPollInterval, m_PollInterval;
+ int m_ref;
+ bool useStat(Entry*);
+
+ bool delayRemove;
+ TQPtrList<Entry> removeList;
+
+ bool rescan_all;
+ TQTimer rescan_timer;
+
+#ifdef HAVE_FAM
+ TQSocketNotifier *sn;
+ FAMConnection fc;
+ bool use_fam;
+
+ void checkFAMEvent(FAMEvent*);
+ bool useFAM(Entry*);
+#endif
+
+#if defined(HAVE_DNOTIFY) || defined(HAVE_INOTIFY)
+ TQSocketNotifier *mSn;
+#endif
+
+#ifdef HAVE_DNOTIFY
+ bool supports_dnotify;
+ int mPipe[2];
+ TQIntDict<Entry> fd_Entry;
+
+ static void dnotify_handler(int, siginfo_t *si, void *);
+ static void dnotify_sigio_handler(int, siginfo_t *si, void *);
+ bool useDNotify(Entry*);
+#endif
+
+#ifdef HAVE_INOTIFY
+ bool supports_inotify;
+ int m_inotify_fd;
+
+ bool useINotify(Entry*);
+#endif
+};
+
+#endif // KDIRWATCH_P_H
+
diff --git a/tdeio/tdeio/kemailsettings.cpp b/tdeio/tdeio/kemailsettings.cpp
new file mode 100644
index 000000000..296455253
--- /dev/null
+++ b/tdeio/tdeio/kemailsettings.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2000 Alex Zepeda <zipzippy@sonic.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "kemailsettings.h"
+
+#include <tdeconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+class KEMailSettingsPrivate {
+public:
+ KEMailSettingsPrivate() : m_pConfig( 0 ) {}
+ ~KEMailSettingsPrivate() { delete m_pConfig; }
+ TDEConfig *m_pConfig;
+ TQStringList profiles;
+ TQString m_sDefaultProfile, m_sCurrentProfile;
+};
+
+TQString KEMailSettings::defaultProfileName() const
+{
+ return p->m_sDefaultProfile;
+}
+
+TQString KEMailSettings::getSetting(KEMailSettings::Setting s)
+{
+ p->m_pConfig->setGroup(TQString("PROFILE_")+p->m_sCurrentProfile);
+ switch (s) {
+ case ClientProgram: {
+ return p->m_pConfig->readEntry("EmailClient");
+ break;
+ }
+ case ClientTerminal: {
+ return ((p->m_pConfig->readBoolEntry("TerminalClient")) ? TQString("true") : TQString("false") );
+ break;
+ }
+ case RealName: {
+ return p->m_pConfig->readEntry("FullName");
+ break;
+ }
+ case EmailAddress: {
+ return p->m_pConfig->readEntry("EmailAddress");
+ break;
+ }
+ case ReplyToAddress: {
+ return p->m_pConfig->readEntry("ReplyAddr");
+ break;
+ }
+ case Organization: {
+ return p->m_pConfig->readEntry("Organization");
+ break;
+ }
+ case OutServer: {
+ return p->m_pConfig->readEntry("OutgoingServer");
+ break;
+ }
+ case OutServerLogin: {
+ return p->m_pConfig->readEntry("OutgoingUserName");
+ break;
+ }
+ case OutServerPass: {
+ return p->m_pConfig->readEntry("OutgoingPassword");
+ break;
+ }
+ case OutServerType: {
+ return p->m_pConfig->readEntry("OutgoingServerType");
+ break;
+ }
+ case OutServerCommand: {
+ return p->m_pConfig->readEntry("OutgoingCommand");
+ break;
+ }
+ case OutServerTLS: {
+ return ((p->m_pConfig->readBoolEntry("OutgoingServerTLS")) ? TQString("true") : TQString("false") );
+ break;
+ }
+ case InServer: {
+ return p->m_pConfig->readEntry("IncomingServer");
+ break;
+ }
+ case InServerLogin: {
+ return p->m_pConfig->readEntry("IncomingUserName");
+ break;
+ }
+ case InServerPass: {
+ return p->m_pConfig->readEntry("IncomingPassword");
+ break;
+ }
+ case InServerType: {
+ return p->m_pConfig->readEntry("IncomingServerType");
+ break;
+ }
+ case InServerMBXType: {
+ return p->m_pConfig->readEntry("IncomingServerMBXType");
+ break;
+ }
+ case InServerTLS: {
+ return ((p->m_pConfig->readBoolEntry("IncomingServerTLS")) ? TQString("true") : TQString("false") );
+ break;
+ }
+ };
+ return TQString::null;
+}
+void KEMailSettings::setSetting(KEMailSettings::Setting s, const TQString &v)
+{
+ p->m_pConfig->setGroup(TQString("PROFILE_")+p->m_sCurrentProfile);
+ switch (s) {
+ case ClientProgram: {
+ p->m_pConfig->writePathEntry("EmailClient", v);
+ break;
+ }
+ case ClientTerminal: {
+ p->m_pConfig->writeEntry("TerminalClient", (v == "true") ? true : false );
+ break;
+ }
+ case RealName: {
+ p->m_pConfig->writeEntry("FullName", v);
+ break;
+ }
+ case EmailAddress: {
+ p->m_pConfig->writeEntry("EmailAddress", v);
+ break;
+ }
+ case ReplyToAddress: {
+ p->m_pConfig->writeEntry("ReplyAddr", v);
+ break;
+ }
+ case Organization: {
+ p->m_pConfig->writeEntry("Organization", v);
+ break;
+ }
+ case OutServer: {
+ p->m_pConfig->writeEntry("OutgoingServer", v);
+ break;
+ }
+ case OutServerLogin: {
+ p->m_pConfig->writeEntry("OutgoingUserName", v);
+ break;
+ }
+ case OutServerPass: {
+ p->m_pConfig->writeEntry("OutgoingPassword", v);
+ break;
+ }
+ case OutServerType: {
+ p->m_pConfig->writeEntry("OutgoingServerType", v);
+ break;
+ }
+ case OutServerCommand: {
+ p->m_pConfig->writeEntry("OutgoingCommand", v);
+ break;
+ }
+ case OutServerTLS: {
+ p->m_pConfig->writeEntry("OutgoingServerTLS", (v == "true") ? true : false );
+ break;
+ }
+ case InServer: {
+ p->m_pConfig->writeEntry("IncomingServer", v);
+ break;
+ }
+ case InServerLogin: {
+ p->m_pConfig->writeEntry("IncomingUserName", v);
+ break;
+ }
+ case InServerPass: {
+ p->m_pConfig->writeEntry("IncomingPassword", v);
+ break;
+ }
+ case InServerType: {
+ p->m_pConfig->writeEntry("IncomingServerType", v);
+ break;
+ }
+ case InServerMBXType: {
+ p->m_pConfig->writeEntry("IncomingServerMBXType", v);
+ break;
+ }
+ case InServerTLS: {
+ p->m_pConfig->writeEntry("IncomingServerTLS", (v == "true") ? true : false );
+ break;
+ }
+ };
+ p->m_pConfig->sync();
+}
+
+void KEMailSettings::setDefault(const TQString &s)
+{
+ p->m_pConfig->setGroup("Defaults");
+ p->m_pConfig->writeEntry("Profile", s);
+ p->m_pConfig->sync();
+ p->m_sDefaultProfile=s;
+
+}
+
+void KEMailSettings::setProfile (const TQString &s)
+{
+ TQString groupname="PROFILE_";
+ groupname.append(s);
+ p->m_sCurrentProfile=s;
+ if (!p->m_pConfig->hasGroup(groupname)) { // Create a group if it doesn't exist
+ p->m_pConfig->setGroup(groupname);
+ p->m_pConfig->writeEntry("ServerType", TQString::null);
+ p->m_pConfig->sync();
+ p->profiles+=s;
+ }
+}
+
+TQString KEMailSettings::currentProfileName() const
+{
+ return p->m_sCurrentProfile;
+}
+
+TQStringList KEMailSettings::profiles() const
+{
+ return p->profiles;
+}
+
+KEMailSettings::KEMailSettings()
+{
+ p = new KEMailSettingsPrivate();
+ p->m_sCurrentProfile=TQString::null;
+
+ p->m_pConfig = new TDEConfig("emaildefaults");
+
+ TQStringList groups = p->m_pConfig->groupList();
+ for (TQStringList::Iterator it = groups.begin(); it != groups.end(); ++it) {
+ if ( (*it).left(8) == "PROFILE_" )
+ p->profiles+= (*it).mid(8, (*it).length());
+ }
+
+ p->m_pConfig->setGroup("Defaults");
+ p->m_sDefaultProfile=p->m_pConfig->readEntry("Profile", i18n("Default"));
+ if (!p->m_sDefaultProfile.isNull()) {
+ if (!p->m_pConfig->hasGroup(TQString("PROFILE_")+p->m_sDefaultProfile))
+ setDefault(i18n("Default"));
+ else
+ setDefault(p->m_sDefaultProfile);
+ } else {
+ if (p->profiles.count()) {
+ setDefault(p->profiles[0]);
+ } else
+ setDefault(i18n("Default"));
+ }
+ setProfile(defaultProfileName());
+}
+
+KEMailSettings::~KEMailSettings()
+{
+ delete p;
+}
diff --git a/tdeio/tdeio/kemailsettings.h b/tdeio/tdeio/kemailsettings.h
new file mode 100644
index 000000000..0ade4520e
--- /dev/null
+++ b/tdeio/tdeio/kemailsettings.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2000 Alex Zepeda <zipzippy@sonic.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _KEMAILSETTINGS_H
+#define _KEMAILSETTINGS_H
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+#include <tdelibs_export.h>
+
+class KEMailSettingsPrivate;
+
+
+/**
+ * This is just a small class to facilitate accessing e-mail settings in
+ * a sane way, and allowing any program to manage multiple e-mail
+ * profiles effortlessly
+ *
+ * @author Alex Zepeda zipzippy@sonic.net
+ **/
+class TDEIO_EXPORT KEMailSettings {
+public:
+ /**
+ * The list of settings that I thought of when I wrote this
+ * class. Any extra settings thought of later can be accessed
+ * easily with getExtendedSetting and setExtendedSetting.
+ * @see getSetting()
+ * @see setSetting()
+ * @see getExtendedSetting()
+ * @see setExtendedSetting()
+ **/
+ enum Setting {
+ ClientProgram,
+ ClientTerminal,
+ RealName,
+ EmailAddress,
+ ReplyToAddress,
+ Organization,
+ OutServer,
+ OutServerLogin,
+ OutServerPass,
+ OutServerType,
+ OutServerCommand,
+ OutServerTLS,
+ InServer,
+ InServerLogin,
+ InServerPass,
+ InServerType,
+ InServerMBXType,
+ InServerTLS
+ };
+
+ /**
+ * The various extensions allowed.
+ **/
+ enum Extension {
+ POP3,
+ SMTP,
+ OTHER
+ };
+
+ /**
+ * Default constructor, just sets things up.
+ **/
+ KEMailSettings();
+
+ /**
+ * Default destructor, nothing to see here.
+ **/
+ ~KEMailSettings();
+
+ /**
+ * List of profiles available.
+ * @return the list of profiles
+ **/
+ TQStringList profiles() const;
+
+ /**
+ * Returns the name of the current profile.
+ * @returns what profile we're currently using
+ **/
+ TQString currentProfileName() const;
+
+ /**
+ * Change the current profile.
+ * @param s the name of the new profile
+ **/
+ void setProfile (const TQString &s);
+
+ /**
+ * Returns the name of the default profile.
+ * @returns the name of the one that's currently default TQString::null if none
+ **/
+ TQString defaultProfileName() const;
+
+ /**
+ * Sets a new default.
+ * @param def the new default
+ **/
+ void setDefault(const TQString &def);
+
+ /**
+ * Get one of the predefined "basic" settings.
+ * @param s the setting to get
+ * @return the value of the setting, or TQString::null if not
+ * set
+ **/
+ TQString getSetting(KEMailSettings::Setting s);
+
+ /**
+ * Set one of the predefined "basic" settings.
+ * @param s the setting to set
+ * @param v the new value of the setting, or TQString::null to
+ * unset
+ **/
+ void setSetting(KEMailSettings::Setting s, const TQString &v);
+
+private:
+ KEMailSettingsPrivate *p;
+};
+
+#endif
diff --git a/tdeio/tdeio/kfilterbase.cpp b/tdeio/tdeio/kfilterbase.cpp
new file mode 100644
index 000000000..f9250cfe9
--- /dev/null
+++ b/tdeio/tdeio/kfilterbase.cpp
@@ -0,0 +1,76 @@
+/* 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.
+*/
+
+#include "kfilterbase.h"
+#include <klibloader.h>
+#include <kmimetype.h>
+#include <ktrader.h>
+#include <kdebug.h>
+
+KFilterBase::KFilterBase()
+ : m_dev( 0L ), m_bAutoDel( false )
+{
+}
+
+KFilterBase::~KFilterBase()
+{
+ if ( m_bAutoDel )
+ delete m_dev;
+}
+
+void KFilterBase::setDevice( TQIODevice * dev, bool autodelete )
+{
+ m_dev = dev;
+ m_bAutoDel = autodelete;
+}
+
+KFilterBase * KFilterBase::findFilterByFileName( const TQString & fileName )
+{
+ KMimeType::Ptr mime = KMimeType::findByPath( fileName );
+ kdDebug(7005) << "KFilterBase::findFilterByFileName mime=" << mime->name() << endl;
+ return findFilterByMimeType(mime->name());
+}
+
+KFilterBase * KFilterBase::findFilterByMimeType( const TQString & mimeType )
+{
+ KTrader::OfferList offers = KTrader::self()->query( "TDECompressionFilter",
+ TQString("'") + mimeType + "' in ServiceTypes" );
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+
+ kdDebug(7005) << "KFilterBase::findFilterByMimeType(" << mimeType << ") got " << offers.count() << " offers" << endl;
+ for (; it != end; ++it )
+ {
+ if ((*it)->library().isEmpty()) { continue; }
+ KLibFactory *factory = KLibLoader::self()->factory((*it)->library().latin1());
+ if (!factory) { continue; }
+ KFilterBase *filter = static_cast<KFilterBase*>( factory->create(0, (*it)->desktopEntryName().latin1() ) );
+ if ( filter )
+ return filter;
+ }
+
+ if ( mimeType == "application/x-bzip2" || mimeType == "application/x-gzip" ) // #88574
+ kdWarning(7005) << "KFilterBase::findFilterByMimeType : no filter found for " << mimeType << endl;
+
+ return 0L;
+}
+
+void KFilterBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kfilterbase.moc"
diff --git a/tdeio/tdeio/kfilterbase.h b/tdeio/tdeio/kfilterbase.h
new file mode 100644
index 000000000..25613c101
--- /dev/null
+++ b/tdeio/tdeio/kfilterbase.h
@@ -0,0 +1,116 @@
+/* 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 __kfilterbase__h
+#define __kfilterbase__h
+
+#include <tqobject.h>
+#include <tqstring.h>
+
+#include <tdelibs_export.h>
+
+#ifdef Q_WS_WIN
+#undef ERROR //avoid conflicts
+#endif
+
+class TQIODevice;
+
+/**
+ * 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.
+ */
+class TDEIO_EXPORT KFilterBase : public TQObject // needs to inherit TQObject for KLibFactory::create
+{
+ Q_OBJECT
+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( TQIODevice * 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
+ */
+ TQIODevice * device() { return m_dev; }
+ /** \internal */
+ virtual void init( int mode ) = 0;
+ /** \internal */
+ virtual int mode() const = 0;
+ /** \internal */
+ virtual void terminate() {}
+ /** \internal */
+ virtual void reset() {}
+ /** \internal */
+ virtual bool readHeader() = 0;
+ /** \internal */
+ virtual bool writeHeader( const TQCString & 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 { return inBufferAvailable() == 0; }
+ /** \internal */
+ virtual int inBufferAvailable() const = 0;
+ /** \internal */
+ virtual bool outBufferFull() const { return outBufferAvailable() == 0; }
+ /** \internal */
+ virtual int outBufferAvailable() const = 0;
+
+ /** \internal */
+ enum Result { OK, END, ERROR };
+ /** \internal */
+ virtual Result uncompress() = 0;
+ /** \internal */
+ virtual Result compress( bool finish ) = 0;
+
+ /**
+ * 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 TQString & 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 TQString & mimeType );
+
+protected:
+ TQIODevice * m_dev;
+ bool m_bAutoDel;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFilterBasePrivate;
+};
+
+#endif
diff --git a/tdeio/tdeio/kfilterdev.cpp b/tdeio/tdeio/kfilterdev.cpp
new file mode 100644
index 000000000..87d54f5e3
--- /dev/null
+++ b/tdeio/tdeio/kfilterdev.cpp
@@ -0,0 +1,484 @@
+/* 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.
+*/
+
+#include "kfilterdev.h"
+#include "kfilterbase.h"
+#include <kdebug.h>
+#include <stdio.h> // for EOF
+#include <stdlib.h>
+#include <assert.h>
+#include <tqfile.h>
+
+#define BUFFER_SIZE 8*1024
+
+class KFilterDev::KFilterDevPrivate
+{
+public:
+ KFilterDevPrivate() : bNeedHeader(true), bSkipHeaders(false),
+ autoDeleteFilterBase(false), bOpenedUnderlyingDevice(false),
+ bIgnoreData(false){}
+ bool bNeedHeader;
+ bool bSkipHeaders;
+ bool autoDeleteFilterBase;
+ bool bOpenedUnderlyingDevice;
+ bool bIgnoreData;
+ TQByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
+ TQCString ungetchBuffer;
+ TQCString origFileName;
+ KFilterBase::Result result;
+};
+
+KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
+ : filter(_filter)
+{
+ assert(filter);
+ d = new KFilterDevPrivate;
+ d->autoDeleteFilterBase = autoDeleteFilterBase;
+}
+
+KFilterDev::~KFilterDev()
+{
+ if ( isOpen() )
+ close();
+ if ( d->autoDeleteFilterBase )
+ delete filter;
+ delete d;
+}
+
+#ifndef KDE_NO_COMPAT
+//this one is static
+// Cumbersome API. To be removed in KDE 3.0.
+TQIODevice* KFilterDev::createFilterDevice(KFilterBase* base, TQFile* file)
+{
+ if (file==0)
+ return 0;
+
+ //we don't need a filter
+ if (base==0)
+ return TQT_TQIODEVICE(new TQFile(file->name())); // A bit strange IMHO. We ask for a TQFile but we create another one !?! (DF)
+
+ base->setDevice(TQT_TQIODEVICE(file));
+ return new KFilterDev(base);
+}
+#endif
+
+//static
+TQIODevice * KFilterDev::deviceForFile( const TQString & fileName, const TQString & mimetype,
+ bool forceFilter )
+{
+ TQFile * f = new TQFile( fileName );
+ KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
+ : KFilterBase::findFilterByMimeType( mimetype );
+ if ( base )
+ {
+ base->setDevice(TQT_TQIODEVICE(f), true);
+ return new KFilterDev(base, true);
+ }
+ if(!forceFilter)
+ return TQT_TQIODEVICE(f);
+ else
+ {
+ delete f;
+ return 0L;
+ }
+}
+
+TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & mimetype)
+{
+ return device( inDevice, mimetype, true );
+}
+
+TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & 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( TQ_OpenMode mode )
+{
+ //kdDebug(7005) << "KFilterDev::open " << mode << endl;
+ if ( mode == IO_ReadOnly )
+ {
+ d->buffer.resize(0);
+ d->ungetchBuffer.resize(0);
+ }
+ else
+ {
+ d->buffer.resize( BUFFER_SIZE );
+ filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
+ }
+ d->bNeedHeader = !d->bSkipHeaders;
+ filter->init( mode );
+ d->bOpenedUnderlyingDevice = !filter->device()->isOpen();
+ bool ret = d->bOpenedUnderlyingDevice ? filter->device()->open( (TQ_OpenMode)mode ) : true;
+ d->result = KFilterBase::OK;
+
+ if ( !ret )
+ kdWarning(7005) << "KFilterDev::open: Couldn't open underlying device" << endl;
+ else
+ {
+ setState( IO_Open );
+ setMode( mode );
+ }
+ TQIODevice::at(0);
+ return ret;
+}
+
+void KFilterDev::close()
+{
+ if ( !isOpen() )
+ return;
+ //kdDebug(7005) << "KFilterDev::close" << endl;
+ if ( filter->mode() == IO_WriteOnly )
+ writeBlock( 0L, 0 ); // finish writing
+ //kdDebug(7005) << "KFilterDev::close. Calling terminate()." << endl;
+
+ filter->terminate();
+ if ( d->bOpenedUnderlyingDevice )
+ filter->device()->close();
+
+ setState( 0 ); // not IO_Open
+}
+
+void KFilterDev::flush()
+{
+ //kdDebug(7005) << "KFilterDev::flush" << endl;
+ filter->device()->flush();
+ // Hmm, might not be enough...
+}
+
+#ifdef USE_QT4
+qint64 KFilterDev::size() const
+#else // USE_QT4
+TQIODevice::Offset KFilterDev::size() const
+#endif // USE_QT4
+{
+ // Well, hmm, Houston, we have a problem.
+ // We can't know the size of the uncompressed data
+ // before uncompressing it.......
+
+ // But readAll, which is not virtual, needs the size.........
+
+ kdWarning(7005) << "KFilterDev::size - can't be implemented !!!!!!!! Returning -1 " << endl;
+ //abort();
+ return (uint)-1;
+}
+
+TQIODevice::Offset KFilterDev::at() const
+{
+ return TQIODevice::at();
+}
+
+bool KFilterDev::at( TQIODevice::Offset pos )
+{
+ //kdDebug(7005) << "KFilterDev::at " << pos << " currently at " << TQIODevice::at() << endl;
+
+ if ( TQIODevice::at() == pos )
+ return true;
+
+ Q_ASSERT ( filter->mode() == IO_ReadOnly );
+
+ if ( pos == 0 )
+ {
+ TQIODevice::at(0);
+ // We can forget about the cached data
+ d->ungetchBuffer.resize(0);
+ d->bNeedHeader = !d->bSkipHeaders;
+ d->result = KFilterBase::OK;
+ filter->setInBuffer(0L,0);
+ filter->reset();
+ return filter->device()->reset();
+ }
+
+ if ( TQIODevice::at() < pos ) // we can start from here
+ pos = pos - TQIODevice::at();
+ else
+ {
+ // we have to start from 0 ! Ugly and slow, but better than the previous
+ // solution (KTarGz was allocating everything into memory)
+ if (!at(0)) // sets ioIndex to 0
+ return false;
+ }
+
+ //kdDebug(7005) << "KFilterDev::at : reading " << pos << " dummy bytes" << endl;
+ TQByteArray dummy( TQMIN( pos, 3*BUFFER_SIZE ) );
+ d->bIgnoreData = true;
+ bool result = ( (TQIODevice::Offset)readBlock( dummy.data(), pos ) == pos );
+ d->bIgnoreData = false;
+ return result;
+}
+
+bool KFilterDev::atEnd() const
+{
+ return filter->device()->atEnd() && (d->result == KFilterBase::END)
+ && d->ungetchBuffer.isEmpty();
+}
+
+TQT_TQIO_LONG KFilterDev::tqreadBlock( char *data, TQT_TQIO_ULONG maxlen )
+{
+ Q_ASSERT ( filter->mode() == IO_ReadOnly );
+ //kdDebug(7005) << "KFilterDev::readBlock maxlen=" << maxlen << endl;
+
+ uint dataReceived = 0;
+ if ( !d->ungetchBuffer.isEmpty() )
+ {
+ uint len = d->ungetchBuffer.length();
+ if ( !d->bIgnoreData )
+ {
+ while ( ( dataReceived < len ) && ( dataReceived < maxlen ) )
+ {
+ *data = d->ungetchBuffer[ len - dataReceived - 1 ];
+ data++;
+ dataReceived++;
+ }
+ }
+ else
+ {
+ dataReceived = TQMIN( len, maxlen );
+ }
+ d->ungetchBuffer.truncate( len - dataReceived );
+ TQIODevice::at(TQIODevice::at() + dataReceived);
+ }
+
+ // If we came to the end of the stream
+ // return what we got from the ungetchBuffer.
+ if ( d->result == KFilterBase::END )
+ return dataReceived;
+
+ // If we had an error, return -1.
+ if ( d->result != KFilterBase::OK )
+ return -1;
+
+
+ TQ_ULONG outBufferSize;
+ if ( d->bIgnoreData )
+ {
+ outBufferSize = TQMIN( maxlen, 3*BUFFER_SIZE );
+ }
+ else
+ {
+ outBufferSize = maxlen;
+ }
+ outBufferSize -= dataReceived;
+ TQ_ULONG availOut = outBufferSize;
+ filter->setOutBuffer( data, outBufferSize );
+
+ bool decompressedAll = false;
+ 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()->readBlock( d->buffer.data(),
+ d->buffer.size() );
+ if ( size )
+ filter->setInBuffer( d->buffer.data(), size );
+ else {
+ if ( decompressedAll )
+ {
+ // We decoded everything there was to decode. So -> done.
+ //kdDebug(7005) << "Seems we're done. dataReceived=" << dataReceived << endl;
+ d->result = KFilterBase::END;
+ break;
+ }
+ }
+ //kdDebug(7005) << "KFilterDev::readBlock got " << size << " bytes from device" << endl;
+ }
+ if (d->bNeedHeader)
+ {
+ (void) filter->readHeader();
+ d->bNeedHeader = false;
+ }
+
+ d->result = filter->uncompress();
+
+ if (d->result == KFilterBase::ERROR)
+ {
+ kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
+ break;
+ }
+
+ // We got that much data since the last time we went here
+ uint outReceived = availOut - filter->outBufferAvailable();
+ //kdDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived << endl;
+ if( availOut < (uint)filter->outBufferAvailable() )
+ kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
+
+ dataReceived += outReceived;
+ if ( !d->bIgnoreData ) // Move on in the output buffer
+ {
+ data += outReceived;
+ availOut = maxlen - dataReceived;
+ }
+ else if ( maxlen - dataReceived < outBufferSize )
+ {
+ availOut = maxlen - dataReceived;
+ }
+ TQIODevice::at(TQIODevice::at() + outReceived);
+ if (d->result == KFilterBase::END)
+ {
+ //kdDebug(7005) << "KFilterDev::readBlock got END. dataReceived=" << dataReceived << endl;
+ break; // Finished.
+ }
+ if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
+ {
+ decompressedAll = true;
+ }
+ filter->setOutBuffer( data, availOut );
+ }
+
+ return dataReceived;
+}
+
+TQT_TQIO_LONG KFilterDev::tqwriteBlock( const char *data /*0 to finish*/, TQT_TQIO_ULONG len )
+{
+ Q_ASSERT ( filter->mode() == IO_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)
+ {
+ kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
+ // 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();
+
+ //kdDebug(7005) << " Wrote everything for now. avail_in = " << filter->inBufferAvailable() << " result=" << d->result << " wrote=" << wrote << endl;
+
+ // Move on in the input buffer
+ data += wrote;
+ dataWritten += wrote;
+ TQIODevice::at(TQIODevice::at() + wrote);
+
+ availIn = len - dataWritten;
+ //kdDebug(7005) << " KFilterDev::writeBlock availIn=" << availIn << " dataWritten=" << dataWritten << " ioIndex=" << ioIndex << endl;
+ if ( availIn > 0 ) // Not sure this will ever happen
+ filter->setInBuffer( data, availIn );
+ }
+
+ if (filter->outBufferFull() || (d->result == KFilterBase::END))
+ {
+ //kdDebug(7005) << " KFilterDev::writeBlock writing to underlying. avail_out=" << filter->outBufferAvailable() << endl;
+ int towrite = d->buffer.size() - filter->outBufferAvailable();
+ if ( towrite > 0 )
+ {
+ // Write compressed data to underlying device
+ int size = filter->device()->writeBlock( d->buffer.data(), towrite );
+ if ( size != towrite ) {
+ kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
+ return 0; // indicate an error (happens on disk full)
+ }
+ //else
+ //kdDebug(7005) << " KFilterDev::writeBlock wrote " << size << " bytes" << endl;
+ }
+ d->buffer.resize( 8*1024 );
+ filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
+ if (d->result == KFilterBase::END)
+ {
+ //kdDebug(7005) << " KFilterDev::writeBlock END" << endl;
+ Q_ASSERT(finish); // hopefully we don't get end before finishing
+ break;
+ }
+ }
+ }
+
+ return dataWritten;
+}
+
+int KFilterDev::getch()
+{
+ Q_ASSERT ( filter->mode() == IO_ReadOnly );
+ //kdDebug(7005) << "KFilterDev::getch" << endl;
+ if ( !d->ungetchBuffer.isEmpty() ) {
+ int len = d->ungetchBuffer.length();
+ int ch = d->ungetchBuffer[ len-1 ];
+ d->ungetchBuffer.truncate( len - 1 );
+ TQIODevice::at(TQIODevice::at() + 1);
+ //kdDebug(7005) << "KFilterDev::getch from ungetch: " << TQString(TQChar(ch)) << endl;
+ return ch;
+ }
+ char buf[1];
+ int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
+ //kdDebug(7005) << "KFilterDev::getch ret=" << TQString(TQChar(ret)) << endl;
+ return ret;
+}
+
+int KFilterDev::putch( int c )
+{
+ //kdDebug(7005) << "KFilterDev::putch" << endl;
+ char buf[1];
+ buf[0] = c;
+ return writeBlock( buf, 1 ) == 1 ? c : -1;
+}
+
+int KFilterDev::ungetch( int ch )
+{
+ //kdDebug(7005) << "KFilterDev::ungetch " << TQString(TQChar(ch)) << endl;
+ if ( ch == EOF ) // cannot unget EOF
+ return ch;
+
+ // pipe or similar => we cannot ungetch, so do it manually
+ d->ungetchBuffer +=ch;
+ TQIODevice::at(TQIODevice::at() - 1);
+ return ch;
+}
+
+void KFilterDev::setOrigFileName( const TQCString & fileName )
+{
+ d->origFileName = fileName;
+}
+
+void KFilterDev::setSkipHeaders()
+{
+ d->bSkipHeaders = true;
+}
diff --git a/tdeio/tdeio/kfilterdev.h b/tdeio/tdeio/kfilterdev.h
new file mode 100644
index 000000000..8dd0999a9
--- /dev/null
+++ b/tdeio/tdeio/kfilterdev.h
@@ -0,0 +1,204 @@
+/* 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 <tqiodevice.h>
+#include <tqstring.h>
+#include <tdelibs_export.h>
+
+class TQFile;
+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 TDEIO_EXPORT KFilterDev : public TQIODevice
+{
+public:
+ /**
+ * 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.
+ */
+ KFilterDev( KFilterBase * filter, bool autoDeleteFilterBase = false );
+ /**
+ * 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.
+ */
+#ifdef qdoc
+#else
+ virtual bool open( TQ_OpenMode mode );
+#endif
+ /**
+ * Close after reading or writing.
+ * If the KFilterBase's device was opened by open(), it will be closed.
+ */
+ virtual void close();
+ virtual void flush();
+
+ /**
+ * 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 TQCString & 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.
+ * @since 3.1
+ */
+ void setSkipHeaders();
+
+ // Not implemented
+#ifdef qdoc
+#else
+#ifdef USE_QT4
+ virtual qint64 size() const;
+#else // USE_QT4
+ virtual TQIODevice::Offset size() const;
+#endif // USE_QT4
+#endif
+
+ virtual TQIODevice::Offset at() const;
+ /**
+ * That one can be quite slow, when going back. Use with care.
+ */
+ virtual bool at( TQIODevice::Offset );
+
+ virtual bool atEnd() const;
+
+#ifdef qdoc
+#else
+ virtual TQT_TQIO_LONG tqreadBlock( char *data, TQT_TQIO_ULONG maxlen );
+ virtual TQT_TQIO_LONG tqwriteBlock( const char *data, TQT_TQIO_ULONG len );
+#endif
+ //int readLine( char *data, uint maxlen );
+
+ virtual int getch();
+ virtual int putch( int );
+ virtual int ungetch( int );
+
+#ifdef KDE_NO_COMPAT
+private:
+#endif
+ /**
+ * Call this to create the appropriate filter device for @p base
+ * working on @p file . The returned TQIODevice has to be deleted
+ * after using.
+ * @deprecated. Use deviceForFile instead.
+ * To be removed in KDE 3.0
+ */
+ static TQIODevice* createFilterDevice(KFilterBase* base, TQFile* file) KDE_DEPRECATED;
+public:
+
+ /**
+ * 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-bzip2"
+ * to force the corresponding decompression filter, if available.
+ *
+ * Warning: application/x-bzip2 may not be available.
+ * In that case a TQFile 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 TQIODevice 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 TQString::null if unknown
+ * @param forceFilter if true, the function will either find a compression filter, or return 0.
+ * If false, it will always return a TQIODevice. If no
+ * filter is available it will return a simple TQFile.
+ * This can be useful if the file is usable without a filter.
+ * @return if a filter has been found, the TQIODevice for the filter. If the
+ * filter does not exist, the return value depends on @p forceFilter.
+ * The returned TQIODevice has to be deleted after using.
+ */
+ static TQIODevice * deviceForFile( const TQString & fileName, const TQString & mimetype = TQString::null,
+ bool forceFilter = false );
+
+ /**
+ * Creates an i/o device that is able to read from the TQIODevice @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-bzip2"
+ * to use the corresponding decompression filter.
+ *
+ * Warning: application/x-bzip2 may not be available.
+ * In that case 0 will be returned !
+ *
+ * The returned TQIODevice has to be deleted after using.
+ * @param inDevice input device, becomes owned by this device! Automatically deleted!
+ * @param mimetype the mime type for the filter
+ * @return a TQIODevice that filters the original stream. Must be deleted after
+ * using
+ */
+ static TQIODevice * device( TQIODevice* inDevice, const TQString & mimetype);
+ // BIC: merge with device() method below, using default value for autoDeleteInDevice
+
+ /**
+ * Creates an i/o device that is able to read from the TQIODevice @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-bzip2"
+ * to use the corresponding decompression filter.
+ *
+ * Warning: application/x-bzip2 may not be available.
+ * In that case 0 will be returned !
+ *
+ * The returned TQIODevice 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 TQIODevice that filters the original stream. Must be deleted after
+ * using
+ * @since 3.1
+ */
+ static TQIODevice * device( TQIODevice* inDevice, const TQString & mimetype, bool autoDeleteInDevice );
+
+private:
+ KFilterBase *filter;
+ class KFilterDevPrivate;
+ KFilterDevPrivate * d;
+};
+
+
+#endif
+
diff --git a/tdeio/tdeio/kimageio.cpp b/tdeio/tdeio/kimageio.cpp
new file mode 100644
index 000000000..e983cb945
--- /dev/null
+++ b/tdeio/tdeio/kimageio.cpp
@@ -0,0 +1,566 @@
+
+/**
+* kimgio.h -- Implementation of interface to the KDE Image IO library.
+* Sirtaj Singh Kang <taj@kde.org>, 23 Sep 1998.
+*
+* $Id$
+*
+* This library is distributed under the conditions of the GNU LGPL.
+*/
+
+#include"config.h"
+
+#include <tqdir.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <tqstring.h>
+#include <tqregexp.h>
+#include <tqvaluelist.h>
+
+#include <ltdl.h>
+#include "kimageio.h"
+#include "kimageiofactory.h"
+#include <klocale.h>
+#include <klibloader.h>
+#include <kglobal.h>
+#include <kmimetype.h>
+#include <tdesycocaentry.h>
+#include <tdesycoca.h>
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+
+#include <tqimage.h>
+
+KImageIOFormat::KImageIOFormat( const TQString &path)
+ : KSycocaEntry(path)
+{
+ bLibLoaded = false;
+ mReadFunc = 0;
+ mWriteFunc = 0;
+ TDEConfig config(path, true, false);
+
+ config.setGroup("Image Format");
+ mType = config.readEntry("Type");
+ mHeader = KURL::decode_string(config.readEntry("Header"), 4); // Latin1
+ mFlags = config.readEntry("Flags");
+ bRead = config.readBoolEntry("Read");
+ bWrite = config.readBoolEntry("Write");
+ mSuffices = config.readListEntry("Suffices");
+ mPattern = config.readEntry("Name");
+ mMimetype = config.readEntry("Mimetype");
+ mLib = config.readPathEntry("Library");
+ rPaths = config.readPathListEntry("rPaths");
+}
+
+KImageIOFormat::KImageIOFormat( TQDataStream& _str, int offset) :
+ KSycocaEntry( _str, offset)
+{
+ bLibLoaded = false;
+ mReadFunc = 0;
+ mWriteFunc = 0;
+ load( _str );
+}
+
+KImageIOFormat::~KImageIOFormat()
+{
+}
+
+void
+KImageIOFormat::load( TQDataStream& _str)
+{
+ TQ_INT8 iRead, iWrite;
+ KSycocaEntry::read(_str, mType);
+ KSycocaEntry::read(_str, mHeader);
+ KSycocaEntry::read(_str, mFlags);
+ _str >> iRead >> iWrite;
+ KSycocaEntry::read(_str, mSuffices);
+ KSycocaEntry::read(_str, mMimetype);
+ KSycocaEntry::read(_str, mLib);
+ KSycocaEntry::read(_str, mPattern);
+ KSycocaEntry::read(_str, rPaths);
+ bRead = (iRead != 0);
+ bWrite = (iWrite != 0);
+}
+
+void
+KImageIOFormat::save( TQDataStream& _str)
+{
+ KSycocaEntry::save( _str );
+ TQ_INT8 iRead = bRead ? 1 : 0;
+ TQ_INT8 iWrite = bWrite ? 1 : 0;
+
+ _str << mType << mHeader << mFlags << iRead << iWrite
+ << mSuffices << mMimetype << mLib << mPattern << rPaths;
+}
+
+void
+KImageIOFormat::callLibFunc( bool read, TQImageIO *iio)
+{
+ if (!bLibLoaded)
+ {
+ if (mLib.isEmpty())
+ {
+ iio->setStatus(1); // Error
+ return;
+ }
+ TQString libpath = KLibLoader::findLibrary(mLib.ascii());
+ if ( libpath.isEmpty())
+ {
+ iio->setStatus(1); // Error
+ return;
+ }
+ lt_dlhandle libhandle = lt_dlopen( TQFile::encodeName(libpath) );
+ if (libhandle == 0) {
+ iio->setStatus(1); // error
+ kdWarning() << "KImageIOFormat::callLibFunc: couldn't dlopen " << mLib << "(" << lt_dlerror() << ")" << endl;
+ return;
+ }
+ bLibLoaded = true;
+ TQString funcName;
+ if (bRead)
+ {
+ funcName = "kimgio_"+mType.lower()+"_read";
+ lt_ptr func = lt_dlsym(libhandle, funcName.ascii());
+
+ if (func == NULL) {
+ iio->setStatus(1); // error
+ kdWarning() << "couln't find " << funcName << " (" << lt_dlerror() << ")" << endl;
+ }
+ mReadFunc = (void (*)(TQImageIO *))func;
+ }
+ if (bWrite)
+ {
+ funcName = "kimgio_"+mType.lower()+"_write";
+ lt_ptr func = lt_dlsym(libhandle, funcName.ascii());
+
+ if (func == NULL) {
+ iio->setStatus(1); // error
+ kdWarning() << "couln't find " << funcName << " (" << lt_dlerror() << ")" << endl;
+ }
+ mWriteFunc = (void (*)(TQImageIO *))func;
+ }
+
+ }
+ if (read)
+ if (mReadFunc)
+ mReadFunc(iio);
+ else
+ iio->setStatus(1); // Error
+ else
+ if (mWriteFunc)
+ mWriteFunc(iio);
+ else
+ iio->setStatus(1); // Error
+}
+
+
+KImageIOFactory *KImageIOFactory::_self = 0;
+KImageIOFormatList *KImageIOFactory::formatList = 0;
+
+static KStaticDeleter<KImageIOFormatList> kiioflsd;
+
+KImageIOFactory::KImageIOFactory() : KSycocaFactory( KST_KImageIO )
+{
+ _self = this;
+ if (m_str)
+ {
+ // read from database
+ KSycocaEntry::read(*m_str, mReadPattern);
+ KSycocaEntry::read(*m_str, mWritePattern);
+ KSycocaEntry::read(*m_str, rPath);
+ if (!formatList)
+ {
+ kiioflsd.setObject( formatList, new KImageIOFormatList());
+ lt_dlinit(); // Do this only once!
+ // Add rPaths.
+ for(TQStringList::Iterator it = rPath.begin();
+ it != rPath.end(); ++it)
+ lt_dladdsearchdir( TQFile::encodeName(*it) );
+ }
+ load();
+ }
+ else
+ if (KSycoca::self()->isBuilding())
+ {
+ // Build database
+ if (!formatList)
+ {
+ formatList = new KImageIOFormatList();
+ }
+ } else
+ {
+ // We have no database at all.. uh-oh
+ }
+}
+
+TQString
+KImageIOFactory::createPattern( KImageIO::Mode _mode)
+{
+ TQStringList patterns;
+ TQString allPatterns;
+ TQString wildCard("*.");
+ TQString separator("|");
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (((_mode == KImageIO::Reading) && format->bRead) ||
+ ((_mode == KImageIO::Writing) && format->bWrite))
+ {
+ TQString pattern;
+ TQStringList suffices = format->mSuffices;
+ for( TQStringList::ConstIterator it = suffices.begin();
+ it != suffices.end();
+ ++it)
+ {
+ if (!pattern.isEmpty())
+ pattern += " ";
+ pattern = pattern + wildCard+(*it);
+ if (!allPatterns.isEmpty())
+ allPatterns += " ";
+ allPatterns = allPatterns + wildCard +(*it);
+ }
+ if (!pattern.isEmpty())
+ {
+ pattern = pattern + separator + format->mPattern;
+ patterns.append(pattern);
+ }
+ }
+ }
+ allPatterns = allPatterns + separator + i18n("All Pictures");
+ patterns.sort();
+ patterns.prepend(allPatterns);
+
+ TQString pattern = patterns.join(TQString::fromLatin1("\n"));
+ return pattern;
+}
+
+void
+KImageIOFactory::readImage( TQImageIO *iio)
+{
+ (void) self(); // Make sure we exist
+ const char *fm = iio->format();
+ if (!fm)
+ fm = TQImageIO::imageFormat( iio->ioDevice());
+ kdDebug() << "KImageIO: readImage() format = " << fm << endl;
+
+ KImageIOFormat *format = 0;
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ format = (*it);
+ if (format->mType == fm)
+ break;
+ }
+ if (!format || !format->bRead)
+ {
+ iio->setStatus(1); // error
+ return;
+ }
+
+ format->callLibFunc( true, iio);
+}
+
+void
+KImageIOFactory::writeImage( TQImageIO *iio)
+{
+ (void) self(); // Make sure we exist
+ const char *fm = iio->format();
+ if (!fm)
+ fm = TQImageIO::imageFormat( iio->ioDevice());
+ kdDebug () << "KImageIO: writeImage() format = "<< fm << endl;
+
+ KImageIOFormat *format = 0;
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ format = (*it);
+ if (format->mType == fm)
+ break;
+ }
+ if (!format || !format->bWrite)
+ {
+ iio->setStatus(1); // error
+ return;
+ }
+
+ format->callLibFunc( false, iio);
+}
+
+void
+KImageIOFactory::load()
+{
+ KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::Iterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ KSycocaEntry *entry = static_cast<KSycocaEntry *>(*it);
+ KImageIOFormat *format = static_cast<KImageIOFormat *>(entry);
+
+ // Since Qt doesn't allow us to unregister image formats
+ // we have to make sure not to add them a second time.
+ // This typically happens when the sycoca database was updated
+ // we need to reread it.
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *_format = (*it);
+ if (format->mType == _format->mType)
+ {
+ // Already in list
+ format = 0;
+ break;
+ }
+ }
+ if (!format)
+ continue;
+ if (!format->mHeader.isEmpty() && !format->mLib.isEmpty())
+ {
+ void (*readFunc)(TQImageIO *);
+ void (*writeFunc)(TQImageIO *);
+ if (format->bRead)
+ readFunc = readImage;
+ else
+ readFunc = 0;
+ if (format->bWrite)
+ writeFunc = writeImage;
+ else
+ writeFunc = 0;
+ TQImageIO::defineIOHandler( format->mType.ascii(),
+ format->mHeader.ascii(),
+ format->mFlags.ascii(),
+ readFunc, writeFunc);
+ }
+ formatList->append( format );
+ }
+}
+
+KImageIOFactory::~KImageIOFactory()
+{
+ _self = 0;
+
+ // We would like to:
+ // * Free all KImageIOFormats.
+ // * Unload libs
+ // * Remove Qt IO handlers.
+ // But we can't remove IO handlers, so we better keep all KImageIOFormats
+ // in memory so that we can make sure not register IO handlers again whenever
+ // the sycoca database updates (Such event deletes this factory)
+}
+
+KSycocaEntry*
+KImageIOFactory::createEntry(int offset)
+{
+ KImageIOFormat *format = 0;
+ KSycocaType type;
+ TQDataStream *str = KSycoca::self()->findEntry(offset, type);
+ switch (type)
+ {
+ case KST_KImageIOFormat:
+ format = new KImageIOFormat(*str, offset);
+ break;
+ default:
+ return 0;
+ }
+ if (!format->isValid())
+ {
+ delete format;
+ format = 0;
+ }
+ return format;
+}
+
+void KImageIO::registerFormats()
+{
+ (void) KImageIOFactory::self();
+}
+
+TQString
+KImageIO::pattern(Mode _mode)
+{
+ if (_mode == Reading)
+ return KImageIOFactory::self()->mReadPattern;
+ else
+ return KImageIOFactory::self()->mWritePattern;
+}
+
+bool KImageIO::canWrite(const TQString& type)
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mType == type)
+ return format->bWrite;
+ }
+ }
+
+ return false;
+}
+
+bool KImageIO::canRead(const TQString& type)
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mType == type)
+ return format->bRead;
+ }
+ }
+
+ return false;
+}
+
+TQStringList KImageIO::types(Mode _mode ) {
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+ TQStringList types;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (((_mode == Reading) && format->bRead) ||
+ ((_mode == Writing) && format->bWrite))
+ types.append(format->mType);
+ }
+ }
+
+ return types;
+}
+
+TQString KImageIO::suffix(const TQString& type)
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mType == type)
+ return format->mSuffices[0];
+ }
+ }
+
+ return TQString::null;
+}
+
+TQString KImageIO::typeForMime(const TQString& mimeType)
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mMimetype == mimeType)
+ return format->mType;
+ }
+ }
+
+ return TQString::null;
+}
+
+TQString KImageIO::type(const TQString& filename)
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+ TQString suffix = filename;
+ int dot = suffix.findRev('.');
+ if (dot >= 0)
+ suffix = suffix.mid(dot + 1);
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mSuffices.contains(suffix))
+ return format->mType;
+ }
+ }
+
+ return TQString::null;
+}
+
+TQStringList KImageIO::mimeTypes( Mode _mode )
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+ TQStringList mimeList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (((_mode == Reading) && format->bRead) ||
+ ((_mode == Writing) && format->bWrite))
+ if ( !format->mMimetype.isEmpty() )
+ mimeList.append ( format->mMimetype );
+ }
+ }
+
+ return mimeList;
+}
+
+bool KImageIO::isSupported( const TQString& _mimeType, Mode _mode )
+{
+ KImageIOFormatList *formatList = KImageIOFactory::self()->formatList;
+
+ if(formatList)
+ {
+ for( KImageIOFormatList::ConstIterator it = formatList->begin();
+ it != formatList->end();
+ ++it )
+ {
+ KImageIOFormat *format = (*it);
+ if (format->mMimetype == _mimeType)
+ {
+ if (((_mode == Reading) && format->bRead) ||
+ ((_mode == Writing) && format->bWrite))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+TQString KImageIO::mimeType( const TQString& _filename )
+{
+ return KMimeType::findByURL( KURL( _filename ) )->name();
+}
+
+void KImageIOFormat::virtual_hook( int id, void* data )
+{ KSycocaEntry::virtual_hook( id, data ); }
+
+void KImageIOFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/kimageio.h b/tdeio/tdeio/kimageio.h
new file mode 100644
index 000000000..671fb5f61
--- /dev/null
+++ b/tdeio/tdeio/kimageio.h
@@ -0,0 +1,170 @@
+/*
+* kimageio.h -- Declaration of interface to the KDE Image IO library.
+* Sirtaj Singh Kang <taj@kde.org>, 23 Sep 1998.
+*
+* This library is distributed under the conditions of the GNU LGPL.
+*/
+
+#ifndef SSK_KIMGIO_H
+#define SSK_KIMGIO_H
+
+#include <tqstringlist.h>
+
+#include <tdelibs_export.h>
+
+/**
+ * Interface to the KDE Image IO plugin architecture.
+ *
+ * This library allows KDE applications to read and write images in a
+ * variety of formats, transparently via the TQImage and TQPixmap load
+ * and save methods.
+ *
+ * The image processing backends are written as image handlers compatible
+ * with the TQImageIO handler format. The backends are loaded on demand
+ * when a particular format is requested. Each format can be identified
+ * by a unique type id string.
+ *
+ * \b Formats:
+ *
+ * Currently supported formats include:
+ * @li BMP \<read\> \<write\>
+ * @li EPS \<read\> \<write\>
+ * @li EXR \<read\>
+ * @li G3 \<read\>
+ * @li GIF \<read\>
+ * @li ICO \<read\>
+ * @li JP2 \<read\> \<write\>
+ * @li JPEG \<read\> \<write\>
+ * @li NETPBM \<read\> \<write\>
+ * @li PCX \<read\> \<write\>
+ * @li PNG \<read\> \<write, only with newer libraries\>
+ * @li TGA \<read\> \<write\>
+ * @li TIFF \<read\>
+ * @li XBM \<read\> \<write\>
+ * @li XPM \<read\> \<write\>
+ * @li XV \<read\> \<write\>
+ *
+ * \b Usage:
+ *
+ * Simply call the KImageIO::registerFormats() static method declared
+ * in kimageio.h.
+ *
+ * \b Example:
+ *
+ * \code
+ * #include<tqpixmap.h>
+ * #include<kimageio.h>
+ *
+ * int main( int argc, char **argv )
+ * {
+ * ....
+ * KImageIO::registerFormats();
+ * ... // start main program
+ * }
+ * \endcode
+ *
+ * @see KImageIO, TQPixmap, TQImage, QImageIO
+ * @author Sirtaj Singh Kang
+ */
+class TDEIO_EXPORT KImageIO
+{
+public:
+ /**
+ * Possible image file access modes.
+ *
+ * Used in various KImageIO static function.
+ **/
+ enum Mode { Reading, Writing };
+
+ /**
+ * Registers all KImageIO supported formats.
+ */
+ static void registerFormats();
+
+ /**
+ * Checks if a special type is supported for writing.
+ * @param type the type id of the image type
+ * @return true if the image format can be written
+ */
+ static bool canWrite(const TQString& type);
+
+ /**
+ * Checks if a special type is supported for reading.
+ * @param type the type id of the image type
+ * @return true if the image format can be read
+ */
+ static bool canRead(const TQString& type);
+
+ /**
+ * Returns a list of all KImageIO supported formats.
+ *
+ * @param mode Tells whether to retrieve modes that can be read or written.
+ * @return a list of the type ids
+ */
+ static TQStringList types(Mode mode = Writing);
+
+
+ /**
+ * Returns a list of patterns of all KImageIO supported formats.
+ *
+ * These patterns can be passed to KFileDialog::getOpenFileName()
+ * or KFileDialog::getSaveFileName(), for example.
+ *
+ * @param mode Tells whether to retrieve modes that can be read or written.
+ * @return a space-separated list of file globs that describe the
+ * supported formats
+ */
+ static TQString pattern(Mode mode = Reading);
+
+ /**
+ * Returns the suffix of an image type.
+ * @param type the type id of the file format
+ * @return the suffix of the file format or TQString::null if it does not
+ * exist
+ */
+ static TQString suffix(const TQString& type);
+
+ /**
+ * Returns the type of a MIME type.
+ * @param mimeType the MIME type to search
+ * @return type id of the MIME type or TQString::null if the MIME type
+ * is not supported
+ * @since 3.1
+ */
+ static TQString typeForMime(const TQString& mimeType);
+
+ /**
+ * Returns the type of given filename.
+ * @param filename the filename to check
+ * @return if the file name's suffix is known the type id of the
+ * file type, otherwise TQString::null
+ */
+ static TQString type(const TQString& filename);
+
+ /**
+ * Returns a list of MIME types for all KImageIO supported formats.
+ *
+ * @param mode Tells whether to retrieve modes that can be read or written.
+ * @return a list if MIME types of the supported formats
+ */
+ static TQStringList mimeTypes( Mode mode = Writing );
+
+ /**
+ * Test to see whether a MIME type is supported to reading/writing.
+ * @param _mimeType the MIME type to check
+ * @param _mode Tells whether to check for reading or writing capabilities
+ * @return true if the type is supported
+ **/
+ static bool isSupported( const TQString& _mimeType, Mode _mode = Writing );
+
+ /**
+ * Returns the MIME type of @p _filename.
+ * @param _filename the filename to check
+ * @return the MIME type of the file, or TQString::null
+ **/
+ static TQString mimeType( const TQString& _filename );
+};
+
+
+#endif
+
diff --git a/tdeio/tdeio/kimageiofactory.h b/tdeio/tdeio/kimageiofactory.h
new file mode 100644
index 000000000..6d2d15940
--- /dev/null
+++ b/tdeio/tdeio/kimageiofactory.h
@@ -0,0 +1,142 @@
+/*
+* kimgio.h -- Declaration of interface to the KDE Image IO library.
+* Sirtaj Singh Kang <taj@kde.org>, 23 Sep 1998.
+*
+* This library is distributed under the conditions of the GNU LGPL.
+*/
+
+#ifndef SSK_KIMGIOFACTORY_H
+#define SSK_KIMGIOFACTORY_H
+
+#include "tdesycocafactory.h"
+#include "kimageio.h"
+
+class KImageIOFormat;
+class KImageIOFormatList;
+
+/** \internal */
+class TDEIO_EXPORT KImageIOFormat : public KSycocaEntry
+{
+ K_SYCOCATYPE( KST_KImageIOFormat, KSycocaEntry )
+
+public:
+ typedef KSharedPtr<KImageIOFormat> Ptr;
+ typedef TQValueList<Ptr> List;
+public: // KDoc seems to barf on those typedefs and generates no docs after them
+ /**
+ * Read a KImageIOFormat description file
+ */
+ KImageIOFormat( const TQString & path);
+
+ /**
+ * @internal construct a ImageIOFormat from a stream
+ */
+ KImageIOFormat( TQDataStream& _str, int offset);
+
+ virtual ~KImageIOFormat();
+
+ virtual TQString name() const { return mType; }
+
+ virtual bool isValid() const { return true; }
+
+ /**
+ * @internal
+ * Load the image format from a stream.
+ */
+ virtual void load(TQDataStream& );
+
+ /**
+ * @internal
+ * Save the image format to a stream.
+ */
+ virtual void save(TQDataStream& );
+
+ /**
+ * @internal
+ * Calls image IO function
+ */
+ void callLibFunc( bool read, TQImageIO *);
+
+public:
+ TQString mType;
+ TQString mHeader;
+ TQString mFlags;
+ bool bRead;
+ bool bWrite;
+ TQStringList mSuffices;
+ TQString mPattern;
+ TQString mMimetype;
+ TQString mLib;
+ TQStringList rPaths;
+ bool bLibLoaded;
+ void (*mReadFunc)(TQImageIO *);
+ void (*mWriteFunc)(TQImageIO *);
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/** \internal */
+class TDEIO_EXPORT KImageIOFormatList : public KImageIOFormat::List
+{
+public:
+ KImageIOFormatList() { }
+};
+
+
+/** \internal */
+class TDEIO_EXPORT KImageIOFactory : public KSycocaFactory
+{
+ friend class KImageIO;
+ K_SYCOCAFACTORY( KST_KImageIO )
+public:
+ static KImageIOFactory *self()
+ { if (!_self) new KImageIOFactory(); return _self; }
+ KImageIOFactory();
+ virtual ~KImageIOFactory();
+
+protected: // Internal stuff
+ /**
+ * @internal
+ *
+ * Load information from database
+ */
+ void load();
+
+ /**
+ * @internal Create pattern string
+ **/
+ TQString createPattern( KImageIO::Mode _mode);
+
+ /**
+ * @internal Not used.
+ */
+ virtual KSycocaEntry *createEntry(const TQString &, const char *)
+ { return 0; }
+
+ /**
+ * @internal
+ */
+ virtual KSycocaEntry *createEntry(int offset);
+
+ /**
+ * @internal Read an image
+ **/
+ static void readImage( TQImageIO *iio);
+
+ /**
+ * @internal Write an image
+ **/
+ static void writeImage( TQImageIO *iio);
+
+protected:
+ static KImageIOFactory *_self;
+ static KImageIOFormatList *formatList;
+ TQString mReadPattern;
+ TQString mWritePattern;
+ TQStringList rPath;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+#endif
+
diff --git a/tdeio/tdeio/klimitediodevice.h b/tdeio/tdeio/klimitediodevice.h
new file mode 100644
index 000000000..602ba45a0
--- /dev/null
+++ b/tdeio/tdeio/klimitediodevice.h
@@ -0,0 +1,105 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001, 2002 David Faure <david@mandrakesoft.com>
+
+ 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 klimitediodevice_h
+#define klimitediodevice_h
+
+#include <kdebug.h>
+#include <tqiodevice.h>
+/**
+ * A readonly device that reads from an underlying device
+ * from a given point to another (e.g. to give access to a single
+ * file inside an archive).
+ * @author David Faure <david@mandrakesoft.com>
+ * @since 3.1
+ */
+class TDEIO_EXPORT KLimitedIODevice : public TQIODevice
+{
+public:
+ /**
+ * Creates a new KLimitedIODevice.
+ * @param dev the underlying device, opened or not
+ * This device itself auto-opens (in readonly mode), no need to open it.
+ * @param start where to start reading (position in bytes)
+ * @param length the length of the data to read (in bytes)
+ */
+ KLimitedIODevice( TQIODevice *dev, int start, int length )
+ : m_dev( dev ), m_start( start ), m_length( length )
+ {
+ //kdDebug(7005) << "KLimitedIODevice::KLimitedIODevice start=" << start << " length=" << length << endl;
+ setType( IO_Direct ); // we support sequential too, but then atEnd() tries getch/ungetch !
+ open( IO_ReadOnly );
+ }
+ virtual ~KLimitedIODevice() {}
+
+ virtual bool open( TQ_OpenMode m ) {
+ //kdDebug(7005) << "KLimitedIODevice::open m=" << m << endl;
+ if ( m & IO_ReadOnly ) {
+ /*bool ok = false;
+ if ( m_dev->isOpen() )
+ ok = ( m_dev->mode() == IO_ReadOnly );
+ else
+ ok = m_dev->open( m );
+ if ( ok )*/
+ m_dev->at( m_start ); // No concurrent access !
+ }
+ else
+ kdWarning(7005) << "KLimitedIODevice::open only supports IO_ReadOnly!" << endl;
+ setState( IO_Open );
+ setMode( m );
+ return true;
+ }
+ virtual void close() {}
+ virtual void flush() {}
+
+#ifdef USE_QT4
+ virtual qint64 size() const { return m_length; }
+#else // USE_QT4
+ virtual Offset size() const { return m_length; }
+#endif // USE_QT4
+
+ virtual TQT_TQIO_LONG tqreadBlock ( char * data, TQT_TQIO_ULONG maxlen )
+ {
+ maxlen = TQMIN( maxlen, m_length - at() ); // Apply upper limit
+ return m_dev->readBlock( data, maxlen );
+ }
+ virtual TQT_TQIO_LONG tqwriteBlock ( const char *, TQT_TQIO_ULONG ) { return -1; } // unsupported
+ virtual int putch( int ) { return -1; } // unsupported
+
+ virtual int getch() {
+ char c[2];
+ if ( tqreadBlock(c, 1) == -1)
+ return -1;
+ else
+ return c[0];
+ }
+ virtual int ungetch( int c ) { return m_dev->ungetch(c); } // ## apply lower limit ?
+ virtual Offset at() const { return m_dev->at() - m_start; }
+ virtual bool at( Offset pos ) {
+ Q_ASSERT( pos <= m_length );
+ pos = QMIN( pos, m_length ); // Apply upper limit
+ return m_dev->at( m_start + pos );
+ }
+ virtual bool atEnd() const { return m_dev->atEnd() || m_dev->at() >= m_start + m_length; }
+private:
+ TQIODevice* m_dev;
+ TQ_ULONG m_start;
+ TQ_ULONG m_length;
+};
+
+#endif
diff --git a/tdeio/tdeio/kmdbase.h b/tdeio/tdeio/kmdbase.h
new file mode 100644
index 000000000..b0c8f8b7d
--- /dev/null
+++ b/tdeio/tdeio/kmdbase.h
@@ -0,0 +1,6 @@
+// kmdbase.h is the old name. Use #include <kmdcodec.h> from now on
+#ifdef KDE_NO_COMPAT
+#error include <kmdcodec.h> instead of <kmdbase.h>
+#else
+#include <kmdcodec.h>
+#endif
diff --git a/tdeio/tdeio/kmessageboxwrapper.h b/tdeio/tdeio/kmessageboxwrapper.h
new file mode 100644
index 000000000..3590b5e89
--- /dev/null
+++ b/tdeio/tdeio/kmessageboxwrapper.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 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 KMESSAGEBOXWRAPPER_H
+#define KMESSAGEBOXWRAPPER_H
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kdebug.h>
+
+/**
+ * @internal
+ * Allows KIO classes to display dialog boxes with the correct
+ * theme/style even in non-GUI apps like kded and kfmclient
+ */
+class TDEIO_EXPORT KMessageBoxWrapper : public KMessageBox
+{
+public:
+ static void error(TQWidget *parent,
+ const TQString &text,
+ const TQString &caption = TQString::null)
+ {
+ if (TDEApplication::guiEnabled()) {
+ kapp->enableStyles();
+ KMessageBox::error( parent, text, caption );
+ } else
+ kdWarning() << text << endl;
+ }
+
+ static void sorry(TQWidget *parent,
+ const TQString &text,
+ const TQString &caption = TQString::null)
+ {
+ if (TDEApplication::guiEnabled()) {
+ kapp->enableStyles();
+ KMessageBox::sorry( parent, text, caption );
+ } else
+ kdWarning() << text << endl;
+ }
+
+};
+#endif
diff --git a/tdeio/tdeio/kmimemagic.cpp b/tdeio/tdeio/kmimemagic.cpp
new file mode 100644
index 000000000..f639a7049
--- /dev/null
+++ b/tdeio/tdeio/kmimemagic.cpp
@@ -0,0 +1,2317 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Fritz Elfert <fritz@kde.org>
+ Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>
+
+ 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 "kmimemagic.h"
+#include <kdebug.h>
+#include <kapplication.h>
+#include <tqfile.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kstaticdeleter.h>
+#include <klargefile.h>
+#include <assert.h>
+
+static int fsmagic(struct config_rec* conf, const char *fn, KDE_struct_stat *sb);
+static void process(struct config_rec* conf, const TQString &);
+static int ascmagic(struct config_rec* conf, unsigned char *buf, int nbytes);
+static int tagmagic(unsigned char *buf, int nbytes);
+static int textmagic(struct config_rec* conf, unsigned char *, int);
+
+static void tryit(struct config_rec* conf, unsigned char *buf, int nb);
+static int match(struct config_rec* conf, unsigned char *, int);
+
+KMimeMagic* KMimeMagic::s_pSelf;
+static KStaticDeleter<KMimeMagic> kmimemagicsd;
+
+KMimeMagic* KMimeMagic::self()
+{
+ if( !s_pSelf )
+ initStatic();
+ return s_pSelf;
+}
+
+void KMimeMagic::initStatic()
+{
+ s_pSelf = kmimemagicsd.setObject( s_pSelf, new KMimeMagic() );
+ s_pSelf->setFollowLinks( true );
+}
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <utime.h>
+#include <stdarg.h>
+#include <tqregexp.h>
+#include <tqstring.h>
+
+//#define MIME_MAGIC_DEBUG_TABLE // untested
+
+// Uncomment to debug the config-file parsing phase
+//#define DEBUG_APPRENTICE
+// Uncomment to debug the matching phase
+//#define DEBUG_MIMEMAGIC
+
+#if (defined DEBUG_MIMEMAGIC || defined DEBUG_APPRENTICE)
+#define DEBUG_LINENUMBERS
+#endif
+
+/*
+ * Buitltin Mime types
+ */
+#define MIME_BINARY_UNKNOWN "application/octet-stream"
+#define MIME_BINARY_UNREADABLE "application/x-unreadable"
+#define MIME_BINARY_ZEROSIZE "application/x-zerosize"
+#define MIME_TEXT_UNKNOWN "text/plain"
+#define MIME_TEXT_PLAIN "text/plain"
+#define MIME_INODE_DIR "inode/directory"
+#define MIME_INODE_CDEV "inode/chardevice"
+#define MIME_INODE_BDEV "inode/blockdevice"
+#define MIME_INODE_FIFO "inode/fifo"
+#define MIME_INODE_LINK "inode/link"
+#define MIME_INODE_SOCK "inode/socket"
+// Following should go in magic-file - Fritz
+#define MIME_APPL_TROFF "application/x-troff"
+#define MIME_APPL_TAR "application/x-tar"
+#define MIME_TEXT_FORTRAN "text/x-fortran"
+
+#define MAXMIMESTRING 256
+
+#define HOWMANY 4000 /* big enough to recognize most WWW files, and skip GPL-headers */
+#define MAXDESC 50 /* max leng of text description */
+#define MAXstring 64 /* max leng of "string" types */
+
+typedef union VALUETYPE {
+ unsigned char b;
+ unsigned short h;
+ unsigned long l;
+ char s[MAXstring];
+ unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
+ unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
+} VALUETYPE;
+
+struct magic {
+ struct magic *next; /* link to next entry */
+#ifdef DEBUG_LINENUMBERS
+ int lineno; /* line number from magic file - doesn't say from which one ;) */
+#endif
+
+ short flag;
+#define INDIR 1 /* if '>(...)' appears, */
+#define UNSIGNED 2 /* comparison is unsigned */
+ short cont_level; /* level of ">" */
+ struct {
+ char type; /* byte short long */
+ long offset; /* offset from indirection */
+ } in;
+ long offset; /* offset to magic number */
+ unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
+ char type; /* int, short, long or string. */
+ char vallen; /* length of string value, if any */
+#define BYTE 1
+#define SHORT 2
+#define LONG 4
+#define STRING 5
+#define DATE 6
+#define BESHORT 7
+#define BELONG 8
+#define BEDATE 9
+#define LESHORT 10
+#define LELONG 11
+#define LEDATE 12
+ VALUETYPE value; /* either number or string */
+ unsigned long mask; /* mask before comparison with value */
+ char nospflag; /* suppress space character */
+
+ /* NOTE: this string is suspected of overrunning - find it! */
+ char desc[MAXDESC]; /* description */
+};
+
+/*
+ * data structures for tar file recognition
+ * --------------------------------------------------------------------------
+ * Header file for public domain tar (tape archive) program.
+ *
+ * @(#)tar.h 1.20 86/10/29 Public Domain. Created 25 August 1985 by John
+ * Gilmore, ihnp4!hoptoad!gnu.
+ *
+ * Header block on tape.
+ *
+ * I'm going to use traditional DP naming conventions here. A "block" is a big
+ * chunk of stuff that we do I/O on. A "record" is a piece of info that we
+ * care about. Typically many "record"s fit into a "block".
+ */
+#define RECORDSIZE 512
+#define NAMSIZ 100
+#define TUNMLEN 32
+#define TGNMLEN 32
+
+union record {
+ char charptr[RECORDSIZE];
+ struct header {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ char magic[8];
+ char uname[TUNMLEN];
+ char gname[TGNMLEN];
+ char devmajor[8];
+ char devminor[8];
+ } header;
+};
+
+/* The magic field is filled with this if uname and gname are valid. */
+#define TMAGIC "ustar " /* 7 chars and a null */
+
+/*
+ * file-function prototypes
+ */
+static int is_tar(unsigned char *, int);
+static unsigned long signextend(struct magic *, unsigned long);
+static int getvalue(struct magic *, char **);
+static int hextoint(int);
+static char *getstr(char *, char *, int, int *);
+static int mget(union VALUETYPE *, unsigned char *, struct magic *, int);
+static int mcheck(union VALUETYPE *, struct magic *);
+static int mconvert(union VALUETYPE *, struct magic *);
+static long from_oct(int, char *);
+
+/*
+ * includes for ASCII substring recognition formerly "names.h" in file
+ * command
+ *
+ * Original notes: names and types used by ascmagic in file(1).
+ * These tokens are
+ * here because they can appear anywhere in the first HOWMANY bytes, while
+ * tokens in /etc/magic must appear at fixed offsets into the file. Don't
+ * make HOWMANY too high unless you have a very fast CPU.
+ */
+
+/* these types are used calculate index to 'types': keep em in sync! */
+/* HTML inserted in first because this is a web server module now */
+/* ENG removed because stupid */
+#define L_HTML 0x001 /* HTML */
+#define L_C 0x002 /* first and foremost on UNIX */
+#define L_MAKE 0x004 /* Makefiles */
+#define L_PLI 0x008 /* PL/1 */
+#define L_MACH 0x010 /* some kinda assembler */
+#define L_PAS 0x020 /* Pascal */
+#define L_JAVA 0x040 /* Java source */
+#define L_CPP 0x080 /* C++ */
+#define L_MAIL 0x100 /* Electronic mail */
+#define L_NEWS 0x200 /* Usenet Netnews */
+#define L_DIFF 0x400 /* Output of diff */
+#define L_OBJC 0x800 /* Objective C */
+
+// Note: this is not a type, it's just used to mark items that should count more
+#define FLAG_STRONG 0x1000
+
+#define P_HTML 0 /* HTML */
+#define P_C 1 /* first and foremost on UNIX */
+#define P_MAKE 2 /* Makefiles */
+#define P_PLI 3 /* PL/1 */
+#define P_MACH 4 /* some kinda assembler */
+#define P_PAS 5 /* Pascal */
+#define P_JAVA 6 /* Java source */
+#define P_CPP 7 /* C++ */
+#define P_MAIL 8 /* Electronic mail */
+#define P_NEWS 9 /* Usenet Netnews */
+#define P_DIFF 10 /* Output of diff */
+#define P_OBJC 11 /* Objective C */
+
+typedef struct asc_type {
+ const char *type;
+ int kwords;
+ double weight;
+} asc_type;
+
+static const asc_type types[] = {
+ { "text/html", 19, 2 }, // 10 items but 10 different words only
+ { "text/x-c", 13, 1 },
+ { "text/x-makefile", 4, 1.9 },
+ { "text/x-pli", 1, 3 },
+ { "text/x-assembler", 6, 2.1 },
+ { "text/x-pascal", 1, 1 },
+ { "text/x-java", 12, 1 },
+ { "text/x-c++", 19, 1 },
+ { "message/rfc822", 4, 1.9 },
+ { "message/news", 3, 2 },
+ { "text/x-diff", 4, 2 },
+ { "text/x-objc", 10, 1 }
+};
+
+#define NTYPES (sizeof(types)/sizeof(asc_type))
+
+static struct names {
+ const char *name;
+ short type;
+} const names[] = {
+ {
+ "<html", L_HTML | FLAG_STRONG
+ },
+ {
+ "<HTML", L_HTML | FLAG_STRONG
+ },
+ {
+ "<head", L_HTML
+ },
+ {
+ "<HEAD", L_HTML
+ },
+ {
+ "<body", L_HTML
+ },
+ {
+ "<BODY", L_HTML
+ },
+ {
+ "<title", L_HTML
+ },
+ {
+ "<TITLE", L_HTML
+ },
+ {
+ "<h1", L_HTML
+ },
+ {
+ "<H1", L_HTML
+ },
+ {
+ "<a", L_HTML
+ },
+ {
+ "<A", L_HTML
+ },
+ {
+ "<img", L_HTML
+ },
+ {
+ "<IMG", L_HTML
+ },
+ {
+ "<!--", L_HTML
+ },
+ {
+ "<!doctype", L_HTML
+ },
+ {
+ "<!DOCTYPE", L_HTML
+ },
+ {
+ "<div", L_HTML
+ },
+ {
+ "<DIV", L_HTML
+ },
+ {
+ "<frame", L_HTML
+ },
+ {
+ "<FRAME", L_HTML
+ },
+ {
+ "<frameset", L_HTML
+ },
+ {
+ "<FRAMESET", L_HTML
+ },
+ {
+ "<script", L_HTML | FLAG_STRONG
+ },
+ {
+ "<SCRIPT", L_HTML | FLAG_STRONG
+ },
+ {
+ "/*", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "//", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "#include", L_C|L_CPP
+ },
+ {
+ "#ifdef", L_C|L_CPP
+ },
+ {
+ "#ifndef", L_C|L_CPP
+ },
+ {
+ "bool", L_C|L_CPP
+ },
+ {
+ "char", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "int", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "float", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "void", L_C|L_CPP|L_JAVA|L_OBJC
+ },
+ {
+ "extern", L_C|L_CPP
+ },
+ {
+ "struct", L_C|L_CPP
+ },
+ {
+ "union", L_C|L_CPP
+ },
+ {
+ "implements", L_JAVA
+ },
+ {
+ "super", L_JAVA
+ },
+ {
+ "import", L_JAVA
+ },
+ {
+ "class", L_CPP|L_JAVA
+ },
+ {
+ "public", L_CPP|L_JAVA
+ },
+ {
+ "private", L_CPP|L_JAVA
+ },
+ {
+ "explicit", L_CPP
+ },
+ {
+ "virtual", L_CPP
+ },
+ {
+ "namespace", L_CPP
+ },
+ {
+ "#import", L_OBJC
+ },
+ {
+ "@interface", L_OBJC
+ },
+ {
+ "@implementation", L_OBJC
+ },
+ {
+ "@protocol", L_OBJC
+ },
+ {
+ "CFLAGS", L_MAKE
+ },
+ {
+ "LDFLAGS", L_MAKE
+ },
+ {
+ "all:", L_MAKE
+ },
+ {
+ ".PHONY:", L_MAKE
+ },
+ {
+ "srcdir", L_MAKE
+ },
+ {
+ "exec_prefix", L_MAKE
+ },
+ /*
+ * Too many files of text have these words in them. Find another way
+ * to recognize Fortrash.
+ */
+ {
+ ".ascii", L_MACH
+ },
+ {
+ ".asciiz", L_MACH
+ },
+ {
+ ".byte", L_MACH
+ },
+ {
+ ".even", L_MACH
+ },
+ {
+ ".globl", L_MACH
+ },
+ {
+ "clr", L_MACH
+ },
+ {
+ "(input", L_PAS
+ },
+ {
+ "dcl", L_PLI
+ },
+ {
+ "Received:", L_MAIL
+ },
+ /* we now stop at '>' for tokens, so this one won't work {
+ ">From", L_MAIL
+ },*/
+ {
+ "Return-Path:", L_MAIL
+ },
+ {
+ "Cc:", L_MAIL
+ },
+ {
+ "Newsgroups:", L_NEWS
+ },
+ {
+ "Path:", L_NEWS
+ },
+ {
+ "Organization:", L_NEWS
+ },
+ {
+ "---", L_DIFF
+ },
+ {
+ "+++", L_DIFF
+ },
+ {
+ "***", L_DIFF
+ },
+ {
+ "@@", L_DIFF
+ },
+ {
+ NULL, 0
+ }
+};
+
+/**
+ * Configuration for the utime() problem.
+ * Here's the problem:
+ * By looking into a file to determine its mimetype, we change its "last access"
+ * time (atime) and this can have side effects, like files in /tmp never being
+ * cleaned up because of that. So in temp directories, we restore the atime.
+ * Since this changes the ctime (last change of attributes), we don't do that
+ * anywhere else, because that breaks archiving programs, that check the ctime.
+ * Hence this class, to configure the directories where the atime should be restored.
+ */
+class KMimeMagicUtimeConf
+{
+public:
+ KMimeMagicUtimeConf()
+ {
+ tmpDirs << TQString::fromLatin1("/tmp"); // default value
+
+ // The trick is that we also don't want the user to override globally set
+ // directories. So we have to misuse KStandardDirs :}
+ TQStringList confDirs = TDEGlobal::dirs()->resourceDirs( "config" );
+ if ( !confDirs.isEmpty() )
+ {
+ TQString globalConf = confDirs.last() + "kmimemagicrc";
+ if ( TQFile::exists( globalConf ) )
+ {
+ KSimpleConfig cfg( globalConf );
+ cfg.setGroup( "Settings" );
+ tmpDirs = cfg.readListEntry( "atimeDirs" );
+ }
+ if ( confDirs.count() > 1 )
+ {
+ TQString localConf = confDirs.first() + "kmimemagicrc";
+ if ( TQFile::exists( localConf ) )
+ {
+ KSimpleConfig cfg( localConf );
+ cfg.setGroup( "Settings" );
+ tmpDirs += cfg.readListEntry( "atimeDirs" );
+ }
+ }
+ for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it )
+ {
+ TQString dir = *it;
+ if ( !dir.isEmpty() && dir[ dir.length()-1 ] != '/' )
+ (*it) += '/';
+ }
+ }
+#if 0
+ // debug code
+ for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it )
+ kdDebug(7018) << " atimeDir: " << *it << endl;
+#endif
+ }
+
+ bool restoreAccessTime( const TQString & file ) const
+ {
+ TQString dir = file.left( file.findRev( '/' ) );
+ bool res = tmpDirs.contains( dir );
+ //kdDebug(7018) << "restoreAccessTime " << file << " dir=" << dir << " result=" << res << endl;
+ return res;
+ }
+ TQStringList tmpDirs;
+};
+
+/* current config */
+struct config_rec {
+ bool followLinks;
+ TQString resultBuf;
+ int accuracy;
+
+ struct magic *magic, /* head of magic config list */
+ *last;
+ KMimeMagicUtimeConf * utimeConf;
+};
+
+#ifdef MIME_MAGIC_DEBUG_TABLE
+static void
+test_table()
+{
+ struct magic *m;
+ struct magic *prevm = NULL;
+
+ kdDebug(7018) << "test_table : started" << endl;
+ for (m = conf->magic; m; m = m->next) {
+ if (isprint((((unsigned long) m) >> 24) & 255) &&
+ isprint((((unsigned long) m) >> 16) & 255) &&
+ isprint((((unsigned long) m) >> 8) & 255) &&
+ isprint(((unsigned long) m) & 255)) {
+ //debug("test_table: POINTER CLOBBERED! "
+ //"m=\"%c%c%c%c\" line=%d",
+ (((unsigned long) m) >> 24) & 255,
+ (((unsigned long) m) >> 16) & 255,
+ (((unsigned long) m) >> 8) & 255,
+ ((unsigned long) m) & 255,
+ prevm ? prevm->lineno : -1);
+ break;
+ }
+ prevm = m;
+ }
+}
+#endif
+
+#define EATAB {while (isascii((unsigned char) *l) && \
+ isspace((unsigned char) *l)) ++l;}
+
+int KMimeMagic::parse_line(char *line, int *rule, int lineno)
+{
+ int ws_offset;
+
+ /* delete newline */
+ if (line[0]) {
+ line[strlen(line) - 1] = '\0';
+ }
+ /* skip leading whitespace */
+ ws_offset = 0;
+ while (line[ws_offset] && isspace(line[ws_offset])) {
+ ws_offset++;
+ }
+
+ /* skip blank lines */
+ if (line[ws_offset] == 0) {
+ return 0;
+ }
+ /* comment, do not parse */
+ if (line[ws_offset] == '#')
+ return 0;
+
+ /* if we get here, we're going to use it so count it */
+ (*rule)++;
+
+ /* parse it */
+ return (parse(line + ws_offset, lineno) != 0);
+}
+
+/*
+ * apprentice - load configuration from the magic file.
+ */
+int KMimeMagic::apprentice( const TQString& magicfile )
+{
+ FILE *f;
+ char line[BUFSIZ + 1];
+ int errs = 0;
+ int lineno;
+ int rule = 0;
+ TQCString fname;
+
+ if (magicfile.isEmpty())
+ return -1;
+ fname = TQFile::encodeName(magicfile);
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ kdError(7018) << "can't read magic file " << fname.data() << ": " << strerror(errno) << endl;
+ return -1;
+ }
+
+ /* parse it */
+ for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++)
+ if (parse_line(line, &rule, lineno))
+ errs++;
+
+ fclose(f);
+
+#ifdef DEBUG_APPRENTICE
+ kdDebug(7018) << "apprentice: conf=" << conf << " file=" << magicfile << " m=" << (conf->magic ? "set" : "NULL") << " m->next=" << ((conf->magic && conf->magic->next) ? "set" : "NULL") << " last=" << (conf->last ? "set" : "NULL") << endl;
+ kdDebug(7018) << "apprentice: read " << lineno << " lines, " << rule << " rules, " << errs << " errors" << endl;
+#endif
+
+#ifdef MIME_MAGIC_DEBUG_TABLE
+ test_table();
+#endif
+
+ return (errs ? -1 : 0);
+}
+
+int KMimeMagic::buff_apprentice(char *buff)
+{
+ char line[BUFSIZ + 2];
+ int errs = 0;
+ int lineno = 1;
+ char *start = buff;
+ char *end;
+ int count = 0;
+ int rule = 0;
+ int len = strlen(buff) + 1;
+
+ /* parse it */
+ do {
+ count = (len > BUFSIZ-1)?BUFSIZ-1:len;
+ strncpy(line, start, count);
+ line[count] = '\0';
+ if ((end = strchr(line, '\n'))) {
+ *(++end) = '\0';
+ count = strlen(line);
+ } else
+ strcat(line, "\n");
+ start += count;
+ len -= count;
+ if (parse_line(line, &rule, lineno))
+ errs++;
+ lineno++;
+ } while (len > 0);
+
+#ifdef DEBUG_APPRENTICE
+ kdDebug(7018) << "buff_apprentice: conf=" << conf << " m=" << (conf->magic ? "set" : "NULL") << " m->next=" << ((conf->magic && conf->magic->next) ? "set" : "NULL") << " last=" << (conf->last ? "set" : "NULL") << endl;
+ kdDebug(7018) << "buff_apprentice: read " << lineno << " lines, " << rule << " rules, " << errs << " errors" << endl;
+#endif
+
+#ifdef MIME_MAGIC_DEBUG_TABLE
+ test_table();
+#endif
+
+ return (errs ? -1 : 0);
+}
+
+/*
+ * extend the sign bit if the comparison is to be signed
+ */
+static unsigned long
+signextend(struct magic *m, unsigned long v)
+{
+ if (!(m->flag & UNSIGNED))
+ switch (m->type) {
+ /*
+ * Do not remove the casts below. They are vital.
+ * When later compared with the data, the sign
+ * extension must have happened.
+ */
+ case BYTE:
+ v = (char) v;
+ break;
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = (short) v;
+ break;
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ case LONG:
+ case BELONG:
+ case LELONG:
+ v = (long) v;
+ break;
+ case STRING:
+ break;
+ default:
+ kdError(7018) << "" << "signextend" << ": can't happen: m->type=" << m->type << endl;
+ return 998; //good value
+ }
+ return v;
+}
+
+/*
+ * parse one line from magic file, put into magic[index++] if valid
+ */
+int KMimeMagic::parse(char *l, int
+#ifdef DEBUG_LINENUMBERS
+ lineno
+#endif
+ )
+{
+ int i = 0;
+ struct magic *m;
+ char *t,
+ *s;
+ /* allocate magic structure entry */
+ if ((m = (struct magic *) calloc(1, sizeof(struct magic))) == NULL) {
+ kdError(7018) << "parse: Out of memory." << endl;
+ return -1;
+ }
+ /* append to linked list */
+ m->next = NULL;
+ if (!conf->magic || !conf->last) {
+ conf->magic = conf->last = m;
+ } else {
+ conf->last->next = m;
+ conf->last = m;
+ }
+
+ /* set values in magic structure */
+ m->flag = 0;
+ m->cont_level = 0;
+#ifdef DEBUG_LINENUMBERS
+ m->lineno = lineno;
+#endif
+
+ while (*l == '>') {
+ ++l; /* step over */
+ m->cont_level++;
+ }
+
+ if (m->cont_level != 0 && *l == '(') {
+ ++l; /* step over */
+ m->flag |= INDIR;
+ }
+ /* get offset, then skip over it */
+ m->offset = (int) strtol(l, &t, 0);
+ if (l == t) {
+ kdError(7018) << "parse: offset " << l << " invalid" << endl;
+ }
+ l = t;
+
+ if (m->flag & INDIR) {
+ m->in.type = LONG;
+ m->in.offset = 0;
+ /*
+ * read [.lbs][+-]nnnnn)
+ */
+ if (*l == '.') {
+ switch (*++l) {
+ case 'l':
+ m->in.type = LONG;
+ break;
+ case 's':
+ m->in.type = SHORT;
+ break;
+ case 'b':
+ m->in.type = BYTE;
+ break;
+ default:
+ kdError(7018) << "parse: indirect offset type " << *l << " invalid" << endl;
+ break;
+ }
+ l++;
+ }
+ s = l;
+ if (*l == '+' || *l == '-')
+ l++;
+ if (isdigit((unsigned char) *l)) {
+ m->in.offset = strtol(l, &t, 0);
+ if (*s == '-')
+ m->in.offset = -m->in.offset;
+ } else
+ t = l;
+ if (*t++ != ')') {
+ kdError(7018) << "parse: missing ')' in indirect offset" << endl;
+ }
+ l = t;
+ }
+ while (isascii((unsigned char) *l) && isdigit((unsigned char) *l))
+ ++l;
+ EATAB;
+
+#define NBYTE 4
+#define NSHORT 5
+#define NLONG 4
+#define NSTRING 6
+#define NDATE 4
+#define NBESHORT 7
+#define NBELONG 6
+#define NBEDATE 6
+#define NLESHORT 7
+#define NLELONG 6
+#define NLEDATE 6
+
+ if (*l == 'u') {
+ ++l;
+ m->flag |= UNSIGNED;
+ }
+ /* get type, skip it */
+ if (strncmp(l, "byte", NBYTE) == 0) {
+ m->type = BYTE;
+ l += NBYTE;
+ } else if (strncmp(l, "short", NSHORT) == 0) {
+ m->type = SHORT;
+ l += NSHORT;
+ } else if (strncmp(l, "long", NLONG) == 0) {
+ m->type = LONG;
+ l += NLONG;
+ } else if (strncmp(l, "string", NSTRING) == 0) {
+ m->type = STRING;
+ l += NSTRING;
+ } else if (strncmp(l, "date", NDATE) == 0) {
+ m->type = DATE;
+ l += NDATE;
+ } else if (strncmp(l, "beshort", NBESHORT) == 0) {
+ m->type = BESHORT;
+ l += NBESHORT;
+ } else if (strncmp(l, "belong", NBELONG) == 0) {
+ m->type = BELONG;
+ l += NBELONG;
+ } else if (strncmp(l, "bedate", NBEDATE) == 0) {
+ m->type = BEDATE;
+ l += NBEDATE;
+ } else if (strncmp(l, "leshort", NLESHORT) == 0) {
+ m->type = LESHORT;
+ l += NLESHORT;
+ } else if (strncmp(l, "lelong", NLELONG) == 0) {
+ m->type = LELONG;
+ l += NLELONG;
+ } else if (strncmp(l, "ledate", NLEDATE) == 0) {
+ m->type = LEDATE;
+ l += NLEDATE;
+ } else {
+ kdError(7018) << "parse: type " << l << " invalid" << endl;
+ return -1;
+ }
+ /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
+ if (*l == '&') {
+ ++l;
+ m->mask = signextend(m, strtol(l, &l, 0));
+ } else
+ m->mask = (unsigned long) ~0L;
+ EATAB;
+
+ switch (*l) {
+ case '>':
+ case '<':
+ /* Old-style anding: "0 byte &0x80 dynamically linked" */
+ case '&':
+ case '^':
+ case '=':
+ m->reln = *l;
+ ++l;
+ break;
+ case '!':
+ if (m->type != STRING) {
+ m->reln = *l;
+ ++l;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ if (*l == 'x' && isascii((unsigned char) l[1]) &&
+ isspace((unsigned char) l[1])) {
+ m->reln = *l;
+ ++l;
+ goto GetDesc; /* Bill The Cat */
+ }
+ m->reln = '=';
+ break;
+ }
+ EATAB;
+
+ if (getvalue(m, &l))
+ return -1;
+ /*
+ * now get last part - the description
+ */
+ GetDesc:
+ EATAB;
+ if (l[0] == '\b') {
+ ++l;
+ m->nospflag = 1;
+ } else if ((l[0] == '\\') && (l[1] == 'b')) {
+ ++l;
+ ++l;
+ m->nospflag = 1;
+ } else
+ m->nospflag = 0;
+ // Copy description - until EOL or '#' (for comments)
+ while (*l != '\0' && *l != '#' && i < MAXDESC-1)
+ m->desc[i++] = *l++;
+ m->desc[i] = '\0';
+ // Remove trailing spaces
+ while (--i>0 && isspace( m->desc[i] ))
+ m->desc[i] = '\0';
+
+ // old code
+ //while ((m->desc[i++] = *l++) != '\0' && i < MAXDESC) /* NULLBODY */ ;
+
+#ifdef DEBUG_APPRENTICE
+ kdDebug(7018) << "parse: line=" << lineno << " m=" << m << " next=" << m->next << " cont=" << m->cont_level << " desc=" << (m->desc ? m->desc : "NULL") << endl;
+#endif
+ return 0;
+}
+
+/*
+ * Read a numeric value from a pointer, into the value union of a magic
+ * pointer, according to the magic type. Update the string pointer to point
+ * just after the number read. Return 0 for success, non-zero for failure.
+ */
+static int
+getvalue(struct magic *m, char **p)
+{
+ int slen;
+
+ if (m->type == STRING) {
+ *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
+ m->vallen = slen;
+ } else if (m->reln != 'x')
+ m->value.l = signextend(m, strtol(*p, p, 0));
+ return 0;
+}
+
+/*
+ * Convert a string containing C character escapes. Stop at an unescaped
+ * space or tab. Copy the converted version to "p", returning its length in
+ * *slen. Return updated scan pointer as function result.
+ */
+static char *
+getstr(register char *s, register char *p, int plen, int *slen)
+{
+ char *origs = s,
+ *origp = p;
+ char *pmax = p + plen - 1;
+ register int c;
+ register int val;
+
+ while ((c = *s++) != '\0') {
+ if (isspace((unsigned char) c))
+ break;
+ if (p >= pmax) {
+ kdError(7018) << "String too long: " << origs << endl;
+ break;
+ }
+ if (c == '\\') {
+ switch (c = *s++) {
+
+ case '\0':
+ goto out;
+
+ default:
+ *p++ = (char) c;
+ break;
+
+ case 'n':
+ *p++ = '\n';
+ break;
+
+ case 'r':
+ *p++ = '\r';
+ break;
+
+ case 'b':
+ *p++ = '\b';
+ break;
+
+ case 't':
+ *p++ = '\t';
+ break;
+
+ case 'f':
+ *p++ = '\f';
+ break;
+
+ case 'v':
+ *p++ = '\v';
+ break;
+
+ /* \ and up to 3 octal digits */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = c - '0';
+ c = *s++; /* try for 2 */
+ if (c >= '0' && c <= '7') {
+ val = (val << 3) | (c - '0');
+ c = *s++; /* try for 3 */
+ if (c >= '0' && c <= '7')
+ val = (val << 3) | (c - '0');
+ else
+ --s;
+ } else
+ --s;
+ *p++ = (char) val;
+ break;
+
+ /* \x and up to 3 hex digits */
+ case 'x':
+ val = 'x'; /* Default if no digits */
+ c = hextoint(*s++); /* Get next char */
+ if (c >= 0) {
+ val = c;
+ c = hextoint(*s++);
+ if (c >= 0) {
+ val = (val << 4) + c;
+ c = hextoint(*s++);
+ if (c >= 0) {
+ val = (val << 4) + c;
+ } else
+ --s;
+ } else
+ --s;
+ } else
+ --s;
+ *p++ = (char) val;
+ break;
+ }
+ } else
+ *p++ = (char) c;
+ }
+ out:
+ *p = '\0';
+ *slen = p - origp;
+ //for ( char* foo = origp; foo < p ; ++foo )
+ // kdDebug(7018) << " " << *foo << endl;
+ return s;
+}
+
+
+/* Single hex char to int; -1 if not a hex char. */
+static int
+hextoint(int c)
+{
+ if (!isascii((unsigned char) c))
+ return -1;
+ if (isdigit((unsigned char) c))
+ return c - '0';
+ if ((c >= 'a') && (c <= 'f'))
+ return c + 10 - 'a';
+ if ((c >= 'A') && (c <= 'F'))
+ return c + 10 - 'A';
+ return -1;
+}
+
+/*
+ * Convert the byte order of the data we are looking at
+ */
+static int
+mconvert(union VALUETYPE *p, struct magic *m)
+{
+ switch (m->type) {
+ case BYTE:
+ return 1;
+ case STRING:
+ /* Null terminate */
+ p->s[sizeof(p->s) - 1] = '\0';
+ return 1;
+#ifndef WORDS_BIGENDIAN
+ case SHORT:
+#endif
+ case BESHORT:
+ p->h = (short) ((p->hs[0] << 8) | (p->hs[1]));
+ return 1;
+#ifndef WORDS_BIGENDIAN
+ case LONG:
+ case DATE:
+#endif
+ case BELONG:
+ case BEDATE:
+ p->l = (long)
+ ((p->hl[0] << 24) | (p->hl[1] << 16) | (p->hl[2] << 8) | (p->hl[3]));
+ return 1;
+#ifdef WORDS_BIGENDIAN
+ case SHORT:
+#endif
+ case LESHORT:
+ p->h = (short) ((p->hs[1] << 8) | (p->hs[0]));
+ return 1;
+#ifdef WORDS_BIGENDIAN
+ case LONG:
+ case DATE:
+#endif
+ case LELONG:
+ case LEDATE:
+ p->l = (long)
+ ((p->hl[3] << 24) | (p->hl[2] << 16) | (p->hl[1] << 8) | (p->hl[0]));
+ return 1;
+ default:
+ kdError(7018) << "mconvert: invalid type " << m->type << endl;
+ return 0;
+ }
+}
+
+
+static int
+mget(union VALUETYPE *p, unsigned char *s, struct magic *m,
+ int nbytes)
+{
+ long offset = m->offset;
+ switch ( m->type )
+ {
+ case BYTE:
+ if ( offset + 1 > nbytes-1 ) // nbytes = (size of file) + 1
+ return 0;
+ break;
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ if ( offset + 2 > nbytes-1 )
+ return 0;
+ break;
+ case LONG:
+ case BELONG:
+ case LELONG:
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ if ( offset + 4 > nbytes-1 )
+ return 0;
+ break;
+ case STRING:
+ break;
+ }
+
+// The file length might be < sizeof(union VALUETYPE) (David)
+// -> pad with zeros (the 'file' command does it this way)
+// Thanks to Stan Covington <stan@calderasystems.com> for detailed report
+ if (offset + (int)sizeof(union VALUETYPE) > nbytes)
+ {
+ int have = nbytes - offset;
+ memset(p, 0, sizeof(union VALUETYPE));
+ if (have > 0)
+ memcpy(p, s + offset, have);
+ } else
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+
+ if (!mconvert(p, m))
+ return 0;
+
+ if (m->flag & INDIR) {
+
+ switch (m->in.type) {
+ case BYTE:
+ offset = p->b + m->in.offset;
+ break;
+ case SHORT:
+ offset = p->h + m->in.offset;
+ break;
+ case LONG:
+ offset = p->l + m->in.offset;
+ break;
+ }
+
+ if (offset + (int)sizeof(union VALUETYPE) > nbytes)
+ return 0;
+
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+
+ if (!mconvert(p, m))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+mcheck(union VALUETYPE *p, struct magic *m)
+{
+ register unsigned long l = m->value.l;
+ register unsigned long v;
+ int matched;
+
+ if ((m->value.s[0] == 'x') && (m->value.s[1] == '\0')) {
+ kdError(7018) << "BOINK" << endl;
+ return 1;
+ }
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ v = p->l;
+ break;
+
+ case STRING:
+ l = 0;
+ /*
+ * What we want here is: v = strncmp(m->value.s, p->s,
+ * m->vallen); but ignoring any nulls. bcmp doesn't give
+ * -/+/0 and isn't universally available anyway.
+ */
+ v = 0;
+ {
+ register unsigned char *a = (unsigned char *) m->value.s;
+ register unsigned char *b = (unsigned char *) p->s;
+ register int len = m->vallen;
+ Q_ASSERT(len);
+
+ while (--len >= 0)
+ if ((v = *b++ - *a++) != 0)
+ break;
+ }
+ break;
+ default:
+ kdError(7018) << "mcheck: invalid type " << m->type << endl;
+ return 0; /* NOTREACHED */
+ }
+#if 0
+ tqDebug("Before signextend %08x", v);
+#endif
+ v = signextend(m, v) & m->mask;
+#if 0
+ tqDebug("After signextend %08x", v);
+#endif
+
+ switch (m->reln) {
+ case 'x':
+ matched = 1;
+ break;
+
+ case '!':
+ matched = v != l;
+ break;
+
+ case '=':
+ matched = v == l;
+ break;
+
+ case '>':
+ if (m->flag & UNSIGNED)
+ matched = v > l;
+ else
+ matched = (long) v > (long) l;
+ break;
+
+ case '<':
+ if (m->flag & UNSIGNED)
+ matched = v < l;
+ else
+ matched = (long) v < (long) l;
+ break;
+
+ case '&':
+ matched = (v & l) == l;
+ break;
+
+ case '^':
+ matched = (v & l) != l;
+ break;
+
+ default:
+ matched = 0;
+ kdError(7018) << "mcheck: can't happen: invalid relation " << m->reln << "." << endl;
+ break; /* NOTREACHED */
+ }
+
+ return matched;
+}
+
+/*
+ * magic_process - process input file fn. Opens the file and reads a
+ * fixed-size buffer to begin processing the contents.
+ */
+
+void process(struct config_rec* conf, const TQString & fn)
+{
+ int fd = 0;
+ unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */
+ KDE_struct_stat sb;
+ int nbytes = 0; /* number of bytes read from a datafile */
+ int tagbytes = 0; /* size of prefixed tag */
+ TQCString fileName = TQFile::encodeName( fn );
+
+ /*
+ * first try judging the file based on its filesystem status
+ */
+ if (fsmagic(conf, fileName, &sb) != 0) {
+ //resultBuf += "\n";
+ return;
+ }
+ if ((fd = KDE_open(fileName, O_RDONLY)) < 0) {
+ /* We can't open it, but we were able to stat it. */
+ /*
+ * if (sb.st_mode & 0002) addResult("writable, ");
+ * if (sb.st_mode & 0111) addResult("executable, ");
+ */
+ //kdDebug(7018) << "can't read `" << fn << "' (" << strerror(errno) << ")." << endl;
+ conf->resultBuf = MIME_BINARY_UNREADABLE;
+ return;
+ }
+ /*
+ * try looking at the first HOWMANY bytes
+ */
+ if ((nbytes = read(fd, (char *) buf, HOWMANY)) == -1) {
+ kdError(7018) << "" << fn << " read failed (" << strerror(errno) << ")." << endl;
+ conf->resultBuf = MIME_BINARY_UNREADABLE;
+ (void)close(fd);
+ return;
+ }
+ if ((tagbytes = tagmagic(buf, nbytes))) {
+ // Read buffer at new position
+ lseek(fd, tagbytes, SEEK_SET);
+ nbytes = read(fd, (char*)buf, HOWMANY);
+ if (nbytes < 0) {
+ conf->resultBuf = MIME_BINARY_UNREADABLE;
+ (void)close(fd);
+ return;
+ }
+ }
+ if (nbytes == 0) {
+ conf->resultBuf = MIME_BINARY_ZEROSIZE;
+ } else {
+ buf[nbytes++] = '\0'; /* null-terminate it */
+ tryit(conf, buf, nbytes);
+ }
+
+ if ( conf->utimeConf && conf->utimeConf->restoreAccessTime( fn ) )
+ {
+ /*
+ * Try to restore access, modification times if read it.
+ * This changes the "change" time (ctime), but we can't do anything
+ * about that.
+ */
+ struct utimbuf utbuf;
+ utbuf.actime = sb.st_atime;
+ utbuf.modtime = sb.st_mtime;
+ (void) utime(fileName, &utbuf);
+ }
+ (void) close(fd);
+}
+
+
+static void tryit(struct config_rec* conf, unsigned char *buf, int nb)
+{
+ /* try tests in /etc/magic (or surrogate magic file) */
+ if (match(conf, buf, nb))
+ return;
+
+ /* try known keywords, check for ascii-ness too. */
+ if (ascmagic(conf, buf, nb) == 1)
+ return;
+
+ /* see if it's plain text */
+ if (textmagic(conf, buf, nb))
+ return;
+
+ /* abandon hope, all ye who remain here */
+ conf->resultBuf = MIME_BINARY_UNKNOWN;
+ conf->accuracy = 0;
+}
+
+static int
+fsmagic(struct config_rec* conf, const char *fn, KDE_struct_stat *sb)
+{
+ int ret = 0;
+
+ /*
+ * Fstat is cheaper but fails for files you don't have read perms on.
+ * On 4.2BSD and similar systems, use lstat() to identify symlinks.
+ */
+ ret = KDE_lstat(fn, sb); /* don't merge into if; see "ret =" above */
+
+ if (ret) {
+ return 1;
+
+ }
+ /*
+ * if (sb->st_mode & S_ISUID) resultBuf += "setuid ";
+ * if (sb->st_mode & S_ISGID) resultBuf += "setgid ";
+ * if (sb->st_mode & S_ISVTX) resultBuf += "sticky ";
+ */
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFDIR:
+ conf->resultBuf = MIME_INODE_DIR;
+ return 1;
+ case S_IFCHR:
+ conf->resultBuf = MIME_INODE_CDEV;
+ return 1;
+ case S_IFBLK:
+ conf->resultBuf = MIME_INODE_BDEV;
+ return 1;
+ /* TODO add code to handle V7 MUX and Blit MUX files */
+#ifdef S_IFIFO
+ case S_IFIFO:
+ conf->resultBuf = MIME_INODE_FIFO;
+ return 1;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ {
+ char buf[BUFSIZ + BUFSIZ + 4];
+ register int nch;
+ KDE_struct_stat tstatbuf;
+
+ if ((nch = readlink(fn, buf, BUFSIZ - 1)) <= 0) {
+ conf->resultBuf = MIME_INODE_LINK;
+ //conf->resultBuf += "\nunreadable";
+ return 1;
+ }
+ buf[nch] = '\0'; /* readlink(2) forgets this */
+ /* If broken symlink, say so and quit early. */
+ if (*buf == '/') {
+ if (KDE_stat(buf, &tstatbuf) < 0) {
+ conf->resultBuf = MIME_INODE_LINK;
+ //conf->resultBuf += "\nbroken";
+ return 1;
+ }
+ } else {
+ char *tmp;
+ char buf2[BUFSIZ + BUFSIZ + 4];
+
+ strncpy(buf2, fn, BUFSIZ);
+ buf2[BUFSIZ] = 0;
+
+ if ((tmp = strrchr(buf2, '/')) == NULL) {
+ tmp = buf; /* in current dir */
+ } else {
+ /* dir part plus (rel.) link */
+ *++tmp = '\0';
+ strcat(buf2, buf);
+ tmp = buf2;
+ }
+ if (KDE_stat(tmp, &tstatbuf) < 0) {
+ conf->resultBuf = MIME_INODE_LINK;
+ //conf->resultBuf += "\nbroken";
+ return 1;
+ } else
+ strcpy(buf, tmp);
+ }
+ if (conf->followLinks)
+ process( conf, TQFile::decodeName( buf ) );
+ else
+ conf->resultBuf = MIME_INODE_LINK;
+ return 1;
+ }
+ return 1;
+#endif
+#ifdef S_IFSOCK
+#ifndef __COHERENT__
+ case S_IFSOCK:
+ conf->resultBuf = MIME_INODE_SOCK;
+ return 1;
+#endif
+#endif
+ case S_IFREG:
+ break;
+ default:
+ kdError(7018) << "KMimeMagic::fsmagic: invalid mode 0" << sb->st_mode << "." << endl;
+ /* NOTREACHED */
+ }
+
+ /*
+ * regular file, check next possibility
+ */
+ if (sb->st_size == 0) {
+ conf->resultBuf = MIME_BINARY_ZEROSIZE;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Go through the whole list, stopping if you find a match. Process all the
+ * continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ * At any time when processing a successful top-level match, there is a current
+ * continuation level; it represents the level of the last successfully
+ * matched continuation.
+ *
+ * Continuations above that level are skipped as, if we see one, it means that
+ * the continuation that controls them - i.e, the lower-level continuation
+ * preceding them - failed to match.
+ *
+ * Continuations below that level are processed as, if we see one, it means
+ * we've finished processing or skipping higher-level continuations under the
+ * control of a successful or unsuccessful lower-level continuation, and are
+ * now seeing the next lower-level continuation and should process it. The
+ * current continuation level reverts to the level of the one we're seeing.
+ *
+ * Continuations at the current level are processed as, if we see one, there's
+ * no lower-level continuation that may have failed.
+ *
+ * If a continuation matches, we bump the current continuation level so that
+ * higher-level continuations are processed.
+ */
+static int
+match(struct config_rec* conf, unsigned char *s, int nbytes)
+{
+ int cont_level = 0;
+ union VALUETYPE p;
+ struct magic *m;
+
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: conf=" << conf << " m=" << (conf->magic ? "set" : "NULL") << " m->next=" << ((conf->magic && conf->magic->next) ? "set" : "NULL") << " last=" << (conf->last ? "set" : "NULL") << endl;
+ for (m = conf->magic; m; m = m->next) {
+ if (isprint((((unsigned long) m) >> 24) & 255) &&
+ isprint((((unsigned long) m) >> 16) & 255) &&
+ isprint((((unsigned long) m) >> 8) & 255) &&
+ isprint(((unsigned long) m) & 255)) {
+ kdDebug(7018) << "match: POINTER CLOBBERED! " << endl;
+ break;
+ }
+ }
+#endif
+
+ for (m = conf->magic; m; m = m->next) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: line=" << m->lineno << " desc=" << m->desc << endl;
+#endif
+ memset(&p, 0, sizeof(union VALUETYPE));
+
+ /* check if main entry matches */
+ if (!mget(&p, s, m, nbytes) ||
+ !mcheck(&p, m)) {
+ struct magic *m_cont;
+
+ /*
+ * main entry didn't match, flush its continuations
+ */
+ if (!m->next || (m->next->cont_level == 0)) {
+ continue;
+ }
+ m_cont = m->next;
+ while (m_cont && (m_cont->cont_level != 0)) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: line=" << m->lineno << " cont=" << m_cont->cont_level << " mc=" << m_cont->lineno << " mc->next=" << m_cont << " " << endl;
+#endif
+ /*
+ * this trick allows us to keep *m in sync
+ * when the continue advances the pointer
+ */
+ m = m_cont;
+ m_cont = m_cont->next;
+ }
+ continue;
+ }
+ /* if we get here, the main entry rule was a match */
+ /* this will be the last run through the loop */
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: rule matched, line=" << m->lineno << " type=" << m->type << " " << ((m->type == STRING) ? m->value.s : "") << endl;
+#endif
+
+ /* remember the match */
+ conf->resultBuf = m->desc;
+
+ cont_level++;
+ /*
+ * while (m && m->next && m->next->cont_level != 0 && ( m =
+ * m->next ))
+ */
+ m = m->next;
+ while (m && (m->cont_level != 0)) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: line=" << m->lineno << " cont=" << m->cont_level << " type=" << m->type << " " << ((m->type == STRING) ? m->value.s : "") << endl;
+#endif
+ if (cont_level >= m->cont_level) {
+ if (cont_level > m->cont_level) {
+ /*
+ * We're at the end of the level
+ * "cont_level" continuations.
+ */
+ cont_level = m->cont_level;
+ }
+ if (mget(&p, s, m, nbytes) &&
+ mcheck(&p, m)) {
+ /*
+ * This continuation matched. Print
+ * its message, with a blank before
+ * it if the previous item printed
+ * and this item isn't empty.
+ */
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "continuation matched" << endl;
+#endif
+ conf->resultBuf = m->desc;
+ cont_level++;
+ }
+ }
+ /* move to next continuation record */
+ m = m->next;
+ }
+ // KDE-specific: need an actual mimetype for a real match
+ // If we only matched a rule with continuations but no mimetype, it's not a match
+ if ( !conf->resultBuf.isEmpty() )
+ {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: matched" << endl;
+#endif
+ return 1; /* all through */
+ }
+ }
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "match: failed" << endl;
+#endif
+ return 0; /* no match at all */
+}
+
+// Try to parse prefixed tags before matching on content
+// Sofar only ID3v2 tags (<=.4) are handled
+static int tagmagic(unsigned char *buf, int nbytes)
+{
+ if(nbytes<40) return 0;
+ if(buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') {
+ int size = 10;
+ // Sanity (known version, no unknown flags)
+ if(buf[3] > 4) return 0;
+ if(buf[5] & 0x0F) return 0;
+ // Tag has v4 footer
+ if(buf[5] & 0x10) size += 10;
+ // Calculated syncsafe size
+ size += buf[9];
+ size += buf[8] << 7;
+ size += buf[7] << 14;
+ size += buf[6] << 21;
+ return size;
+ }
+ return 0;
+}
+
+struct Token {
+ char *data;
+ int length;
+};
+
+struct Tokenizer
+{
+ Tokenizer(char* buf, int nbytes) {
+ data = buf;
+ length = nbytes;
+ pos = 0;
+ }
+ bool isNewLine() {
+ return newline;
+ }
+ Token* nextToken() {
+ if (pos == 0)
+ newline = true;
+ else
+ newline = false;
+ token.data = data+pos;
+ token.length = 0;
+ while(pos<length) {
+ switch (data[pos]) {
+ case '\n':
+ newline = true;
+ case '\0':
+ case '\t':
+ case ' ':
+ case '\r':
+ case '\f':
+ case ',':
+ case ';':
+ case '>':
+ if (token.length == 0) token.data++;
+ else
+ return &token;
+ break;
+ default:
+ token.length++;
+ }
+ pos++;
+ }
+ return &token;
+ }
+
+private:
+ Token token;
+ char* data;
+ int length;
+ int pos;
+ bool newline;
+};
+
+
+/* an optimization over plain strcmp() */
+//#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+static inline bool STREQ(const Token *token, const char *b) {
+ const char *a = token->data;
+ int len = token->length;
+ if (a == b) return true;
+ while(*a && *b && len > 0) {
+ if (*a != *b) return false;
+ a++; b++; len--;
+ }
+ return (len == 0 && *b == 0);
+}
+
+static int ascmagic(struct config_rec* conf, unsigned char *buf, int nbytes)
+{
+ int i;
+ double pct, maxpct, pctsum;
+ double pcts[NTYPES];
+ int mostaccurate, tokencount;
+ int typeset, jonly, conly, jconly, objconly, cpponly;
+ int has_escapes = 0;
+ //unsigned char *s;
+ //char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */
+
+ /* these are easy, do them first */
+ conf->accuracy = 70;
+
+ /*
+ * for troff, look for . + letter + letter or .\"; this must be done
+ * to disambiguate tar archives' ./file and other trash from real
+ * troff input.
+ */
+ if (*buf == '.') {
+ unsigned char *tp = buf + 1;
+
+ while (isascii(*tp) && isspace(*tp))
+ ++tp; /* skip leading whitespace */
+ if ((isascii(*tp) && (isalnum(*tp) || *tp == '\\') &&
+ isascii(*(tp + 1)) && (isalnum(*(tp + 1)) || *tp == '"'))) {
+ conf->resultBuf = MIME_APPL_TROFF;
+ return 1;
+ }
+ }
+ if ((*buf == 'c' || *buf == 'C') &&
+ isascii(*(buf + 1)) && isspace(*(buf + 1))) {
+ /* Fortran */
+ conf->resultBuf = MIME_TEXT_FORTRAN;
+ return 1;
+ }
+ assert(nbytes-1 < HOWMANY + 1);
+ /* look for tokens - this is expensive! */
+ has_escapes = (memchr(buf, '\033', nbytes) != NULL);
+ Tokenizer tokenizer((char*)buf, nbytes);
+ const Token* token;
+ bool linecomment = false, blockcomment = false;
+ const struct names *p;
+ int typecount[NTYPES];
+/*
+ * Fritz:
+ * Try a little harder on C/C++/Java.
+ */
+ memset(&typecount, 0, sizeof(typecount));
+ typeset = 0;
+ jonly = 0;
+ conly = 0;
+ jconly = 0;
+ objconly = 0;
+ cpponly = 0;
+ tokencount = 0;
+ bool foundClass = false; // mandatory for java
+ // first collect all possible types and count matches
+ // we stop at '>' too, because of "<title>blah</title>" on HTML pages
+ while ((token = tokenizer.nextToken())->length > 0) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "KMimeMagic::ascmagic token=" << token << endl;
+#endif
+ if (linecomment && tokenizer.isNewLine())
+ linecomment = false;
+ if (blockcomment && STREQ(token, "*/")) {
+ blockcomment = false;
+ continue;
+ }
+ for (p = names; p->name ; p++) {
+ if (STREQ(token, p->name)) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "KMimeMagic::ascmagic token matches ! name=" << p->name << " type=" << p->type << endl;
+#endif
+ tokencount++;
+ typeset |= p->type;
+ if(p->type & (L_C|L_CPP|L_JAVA|L_OBJC)) {
+ if (linecomment || blockcomment) {
+ continue;
+ }
+ else {
+ switch(p->type & (L_C|L_CPP|L_JAVA|L_OBJC))
+ {
+ case L_JAVA:
+ jonly++;
+ break;
+ case L_OBJC:
+ objconly++;
+ break;
+ case L_CPP:
+ cpponly++;
+ break;
+ case (L_CPP|L_JAVA):
+ jconly++;
+ if ( !foundClass && STREQ(token, "class") )
+ foundClass = true;
+ break;
+ case (L_C|L_CPP):
+ conly++;
+ break;
+ default:
+ if (STREQ(token, "//")) linecomment = true;
+ if (STREQ(token, "/*")) blockcomment = true;
+ }
+ }
+ }
+ for (i = 0; i < (int)NTYPES; i++) {
+ if ((1 << i) & p->type) typecount[i]+= p->type & FLAG_STRONG ? 2 : 1;
+ }
+ }
+ }
+ }
+
+ if (typeset & (L_C|L_CPP|L_JAVA|L_OBJC)) {
+ conf->accuracy = 60;
+ if (!(typeset & ~(L_C|L_CPP|L_JAVA|L_OBJC))) {
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "C/C++/Java/ObjC: jonly=" << jonly << " conly=" << conly << " jconly=" << jconly << " objconly=" << objconly << endl;
+#endif
+ if (jonly > 1 && foundClass) {
+ // At least two java-only tokens have matched, including "class"
+ conf->resultBuf = TQString(types[P_JAVA].type);
+ return 1;
+ }
+ if (jconly > 1) {
+ // At least two non-C (only C++ or Java) token have matched.
+ if (typecount[P_JAVA] < typecount[P_CPP])
+ conf->resultBuf = TQString(types[P_CPP].type);
+ else
+ conf->resultBuf = TQString(types[P_JAVA].type);
+ return 1;
+ }
+ if (conly + cpponly > 1) {
+ // Either C or C++.
+ if (cpponly > 0)
+ conf->resultBuf = TQString(types[P_CPP].type);
+ else
+ conf->resultBuf = TQString(types[P_C].type);
+ return 1;
+ }
+ if (objconly > 0) {
+ conf->resultBuf = TQString(types[P_OBJC].type);
+ return 1;
+ }
+ }
+ }
+
+ /* Neither C, C++ or Java (or all of them without able to distinguish):
+ * Simply take the token-class with the highest
+ * matchcount > 0
+ */
+ mostaccurate = -1;
+ maxpct = pctsum = 0.0;
+ for (i = 0; i < (int)NTYPES; i++) {
+ if (typecount[i] > 1) { // one word is not enough, we need at least two
+ pct = (double)typecount[i] / (double)types[i].kwords *
+ (double)types[i].weight;
+ pcts[i] = pct;
+ pctsum += pct;
+ if (pct > maxpct) {
+ maxpct = pct;
+ mostaccurate = i;
+ }
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "" << types[i].type << " has " << typecount[i] << " hits, " << types[i].kwords << " kw, weight " << types[i].weight << ", " << pct << " -> max = " << maxpct << "\n" << endl;
+#endif
+ }
+ }
+ if (mostaccurate >= 0) {
+ if ( mostaccurate != P_JAVA || foundClass ) // 'class' mandatory for java
+ {
+ conf->accuracy = (int)(pcts[mostaccurate] / pctsum * 60);
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "mostaccurate=" << mostaccurate << " pcts=" << pcts[mostaccurate] << " pctsum=" << pctsum << " accuracy=" << conf->accuracy << endl;
+#endif
+ conf->resultBuf = TQString(types[mostaccurate].type);
+ return 1;
+ }
+ }
+
+ switch (is_tar(buf, nbytes)) {
+ case 1:
+ /* V7 tar archive */
+ conf->resultBuf = MIME_APPL_TAR;
+ conf->accuracy = 90;
+ return 1;
+ case 2:
+ /* POSIX tar archive */
+ conf->resultBuf = MIME_APPL_TAR;
+ conf->accuracy = 90;
+ return 1;
+ }
+
+ for (i = 0; i < nbytes; i++) {
+ if (!isascii(*(buf + i)))
+ return 0; /* not all ascii */
+ }
+
+ /* all else fails, but it is ascii... */
+ conf->accuracy = 90;
+ if (has_escapes) {
+ /* text with escape sequences */
+ /* we leave this open for further differentiation later */
+ conf->resultBuf = MIME_TEXT_UNKNOWN;
+ } else {
+ /* plain text */
+ conf->resultBuf = MIME_TEXT_PLAIN;
+ }
+ return 1;
+}
+
+/* Maximal length of a line we consider "reasonable". */
+#define TEXT_MAXLINELEN 300
+
+// This code is taken from the "file" command, where it is licensed
+// in the "beer-ware license" :-)
+// Original author: <joerg@FreeBSD.ORG>
+// Simplified by David Faure to avoid the static array char[256].
+static int textmagic(struct config_rec* conf, unsigned char * buf, int nbytes)
+{
+ int i;
+ unsigned char *cp;
+
+ nbytes--;
+
+ /* First, look whether there are "unreasonable" characters. */
+ for (i = 0, cp = buf; i < nbytes; i++, cp++)
+ if ((*cp < 8) || (*cp>13 && *cp<32 && *cp!=27 ) || (*cp==0x7F))
+ return 0;
+
+ /* Now, look whether the file consists of lines of
+ * "reasonable" length. */
+
+ for (i = 0; i < nbytes;) {
+ cp = (unsigned char *) memchr(buf, '\n', nbytes - i);
+ if (cp == NULL) {
+ /* Don't fail if we hit the end of buffer. */
+ if (i + TEXT_MAXLINELEN >= nbytes)
+ break;
+ else
+ return 0;
+ }
+ if (cp - buf > TEXT_MAXLINELEN)
+ return 0;
+ i += (cp - buf + 1);
+ buf = cp + 1;
+ }
+ conf->resultBuf = MIME_TEXT_PLAIN;
+ return 1;
+}
+
+
+/*
+ * is_tar() -- figure out whether file is a tar archive.
+ *
+ * Stolen (by author of file utility) from the public domain tar program: Public
+ * Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
+ *
+ * @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7
+ * 1997/06/24 00:41:02 ikluft Exp ikluft $
+ *
+ * Comments changed and some code/comments reformatted for file command by Ian
+ * Darwin.
+ */
+
+#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
+
+/*
+ * Return 0 if the checksum is bad (i.e., probably not a tar archive), 1 for
+ * old UNIX tar file, 2 for Unix Std (POSIX) tar file.
+ */
+
+static int
+is_tar(unsigned char *buf, int nbytes)
+{
+ register union record *header = (union record *) buf;
+ register int i;
+ register long sum,
+ recsum;
+ register char *p;
+
+ if (nbytes < (int)sizeof(union record))
+ return 0;
+
+ recsum = from_oct(8, header->header.chksum);
+
+ sum = 0;
+ p = header->charptr;
+ for (i = sizeof(union record); --i >= 0;) {
+ /*
+ * We can't use unsigned char here because of old compilers,
+ * e.g. V7.
+ */
+ sum += 0xFF & *p++;
+ }
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+ for (i = sizeof(header->header.chksum); --i >= 0;)
+ sum -= 0xFF & header->header.chksum[i];
+ sum += ' ' * sizeof header->header.chksum;
+
+ if (sum != recsum)
+ return 0; /* Not a tar archive */
+
+ if (0 == strcmp(header->header.magic, TMAGIC))
+ return 2; /* Unix Standard tar archive */
+
+ return 1; /* Old fashioned tar archive */
+}
+
+
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or nonoctal).
+ */
+static long
+from_oct(int digs, char *where)
+{
+ register long value;
+
+ while (isspace(*where)) { /* Skip spaces */
+ where++;
+ if (--digs <= 0)
+ return -1; /* All blank field */
+ }
+ value = 0;
+ while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
+ value = (value << 3) | (*where++ - '0');
+ --digs;
+ }
+
+ if (digs > 0 && *where && !isspace(*where))
+ return -1; /* Ended on non-space/nul */
+
+ return value;
+}
+
+KMimeMagic::KMimeMagic()
+{
+ // Magic file detection init
+ TQString mimefile = locate( "mime", "magic" );
+ init( mimefile );
+ // Add snippets from share/config/magic/*
+ TQStringList snippets = TDEGlobal::dirs()->findAllResources( "config", "magic/*.magic", true );
+ for ( TQStringList::Iterator it = snippets.begin() ; it != snippets.end() ; ++it )
+ if ( !mergeConfig( *it ) )
+ kdWarning() << k_funcinfo << "Failed to parse " << *it << endl;
+}
+
+KMimeMagic::KMimeMagic(const TQString & _configfile)
+{
+ init( _configfile );
+}
+
+void KMimeMagic::init( const TQString& _configfile )
+{
+ int result;
+ conf = new config_rec;
+
+ /* set up the magic list (empty) */
+ conf->magic = conf->last = NULL;
+ magicResult = NULL;
+ conf->followLinks = false;
+
+ conf->utimeConf = 0L; // created on demand
+ /* on the first time through we read the magic file */
+ result = apprentice(_configfile);
+ if (result == -1)
+ return;
+#ifdef MIME_MAGIC_DEBUG_TABLE
+ test_table();
+#endif
+}
+
+/*
+ * The destructor.
+ * Free the magic-table and other resources.
+ */
+KMimeMagic::~KMimeMagic()
+{
+ if (conf) {
+ struct magic *p = conf->magic;
+ struct magic *q;
+ while (p) {
+ q = p;
+ p = p->next;
+ free(q);
+ }
+ delete conf->utimeConf;
+ delete conf;
+ }
+ delete magicResult;
+}
+
+bool
+KMimeMagic::mergeConfig(const TQString & _configfile)
+{
+ kdDebug(7018) << k_funcinfo << _configfile << endl;
+ int result;
+
+ if (_configfile.isEmpty())
+ return false;
+ result = apprentice(_configfile);
+ if (result == -1) {
+ return false;
+ }
+#ifdef MIME_MAGIC_DEBUG_TABLE
+ test_table();
+#endif
+ return true;
+}
+
+bool
+KMimeMagic::mergeBufConfig(char * _configbuf)
+{
+ int result;
+
+ if (conf) {
+ result = buff_apprentice(_configbuf);
+ if (result == -1)
+ return false;
+#ifdef MIME_MAGIC_DEBUG_TABLE
+ test_table();
+#endif
+ return true;
+ }
+ return false;
+}
+
+void
+KMimeMagic::setFollowLinks( bool _enable )
+{
+ conf->followLinks = _enable;
+}
+
+KMimeMagicResult *
+KMimeMagic::findBufferType(const TQByteArray &array)
+{
+ unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */
+
+ conf->resultBuf = TQString::null;
+ if ( !magicResult )
+ magicResult = new KMimeMagicResult();
+ magicResult->setInvalid();
+ conf->accuracy = 100;
+
+ int nbytes = array.size();
+
+ if (nbytes > HOWMANY)
+ nbytes = HOWMANY;
+ memcpy(buf, array.data(), nbytes);
+ if (nbytes == 0) {
+ conf->resultBuf = MIME_BINARY_ZEROSIZE;
+ } else {
+ buf[nbytes++] = '\0'; /* null-terminate it */
+ tryit(conf, buf, nbytes);
+ }
+ /* if we have any results, put them in the request structure */
+ magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
+ magicResult->setAccuracy(conf->accuracy);
+ return magicResult;
+}
+
+static void
+refineResult(KMimeMagicResult *r, const TQString & _filename)
+{
+ TQString tmp = r->mimeType();
+ if (tmp.isEmpty())
+ return;
+ if ( tmp == "text/x-c" || tmp == "text/x-objc" )
+ {
+ if ( _filename.right(2) == ".h" )
+ tmp += "hdr";
+ else
+ tmp += "src";
+ r->setMimeType(tmp);
+ }
+ else
+ if ( tmp == "text/x-c++" )
+ {
+ if ( _filename.endsWith(".h")
+ || _filename.endsWith(".hh")
+ || _filename.endsWith(".H")
+ || !_filename.right(4).contains('.'))
+ tmp += "hdr";
+ else
+ tmp += "src";
+ r->setMimeType(tmp);
+ }
+ else
+ if ( tmp == "application/x-sharedlib" )
+ {
+ if ( _filename.find( ".so" ) == -1 )
+ {
+ tmp = "application/x-executable";
+ r->setMimeType( tmp );
+ }
+ }
+}
+
+KMimeMagicResult *
+KMimeMagic::findBufferFileType( const TQByteArray &data,
+ const TQString &fn)
+{
+ KMimeMagicResult * r = findBufferType( data );
+ refineResult(r, fn);
+ return r;
+}
+
+/*
+ * Find the content-type of the given file.
+ */
+KMimeMagicResult* KMimeMagic::findFileType(const TQString & fn)
+{
+#ifdef DEBUG_MIMEMAGIC
+ kdDebug(7018) << "KMimeMagic::findFileType " << fn << endl;
+#endif
+ conf->resultBuf = TQString::null;
+
+ if ( !magicResult )
+ magicResult = new KMimeMagicResult();
+ magicResult->setInvalid();
+ conf->accuracy = 100;
+
+ if ( !conf->utimeConf )
+ conf->utimeConf = new KMimeMagicUtimeConf();
+
+ /* process it based on the file contents */
+ process(conf, fn );
+
+ /* if we have any results, put them in the request structure */
+ //finishResult();
+ magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
+ magicResult->setAccuracy(conf->accuracy);
+ refineResult(magicResult, fn);
+ return magicResult;
+}
diff --git a/tdeio/tdeio/kmimemagic.h b/tdeio/tdeio/kmimemagic.h
new file mode 100644
index 000000000..f5430a219
--- /dev/null
+++ b/tdeio/tdeio/kmimemagic.h
@@ -0,0 +1,218 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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.
+*/
+
+/*
+ * KMimeMagic is inspired by the code of the
+ * Apache Web Server.
+ *
+ * Rewritten for KDE by Fritz Elfert
+ * fritz@kde.org
+ * Adaptations by Torben Weis <weis@kde.org>
+ * Fixes and documentation by David Faure <faure@kde.org>
+ */
+
+#ifndef KMIMEMAGIC_H
+#define KMIMEMAGIC_H
+
+#include <tqstring.h>
+#include <tdelibs_export.h>
+
+class KMimeMagic; // see below (read this one first)
+
+/**
+ * @deprecated Use KMimeType::findByContent() instead
+ * May be removed in KDE 4.0.
+ * Returned by KMimeMagic @p find...Type methods.
+ *
+ * It contains the mimetype and the encoding of
+ * the file or buffer read.
+ */
+class TDEIO_EXPORT_DEPRECATED KMimeMagicResult
+{
+public:
+ KMimeMagicResult() { m_iAccuracy = 100; }
+ ~KMimeMagicResult() { }
+
+ /**
+ * Retrieve the mimetype (e.g. "text/html") of the file or buffer parsed.
+ */
+ TQString mimeType() const { return m_strMimeType; }
+ /**
+ * Retrieve the accuracy of the matching.
+ */
+ int accuracy() const { return m_iAccuracy; }
+ /**
+ * Returns whether the result is valid (i.e. mimetype not empty).
+ */
+ bool isValid() const { return !m_strMimeType.isEmpty(); }
+
+ /////////////////
+ // Internal functions only
+ /////////////////
+ void setMimeType( const TQString& _mime ) { m_strMimeType = _mime; }
+ void setAccuracy( int _accuracy ) { m_iAccuracy = _accuracy; }
+ void setInvalid() { m_strMimeType = TQString::null; }
+
+protected:
+ TQString m_strMimeType;
+ int m_iAccuracy;
+};
+
+/**
+ * @deprecated Use KMimeType::findByContent() instead
+ * May be removed in KDE 4.0.
+ * Determine auto-magically the type of file,
+ * not only by using its extension, but also by reading its contents.
+ *
+ *
+ * Unless specified otherwise, KMimeMagic uses
+ * $TDEDIR/share/mimelnk/magic for this purpose.
+ *
+ * To make KMimeMagic restore the 'atime' of a file after it opened it,
+ * add its directory in kmimemagicrc like:
+ * [Settings]
+ * atimeDirs=/tmp,/var/tmp,/home/dfaure/tmp
+ * This isn't done by default because it changes the 'ctime'.
+ * See kmimemagic.cpp for a full discussion on this issue.
+ *
+ * The basic usage of KMimeMagic is :
+ * @li Get a pointer to it, using KMimeMagic::self().
+ * @li Use it for any file or buffer you want, using one of the three
+ * @p find...Type() methods.
+ *
+ * The result is contained in the class KMimeMagicResult.
+ */
+class TDEIO_EXPORT_DEPRECATED KMimeMagic
+{
+public:
+ /**
+ * Create a parser and initialize it with the KDE-global data:
+ * the "magic" config file as well as the snippets from share/config/magic.
+ * @since 3.1
+ */
+ KMimeMagic();
+
+ /**
+ * Create a parser and initialize it with the given config file.
+ */
+ KMimeMagic( const TQString & configFile );
+
+ /**
+ * Destroy the parser.
+ */
+ ~KMimeMagic();
+
+ /**
+ * Merge an existing parse table with the data from the
+ * given file.
+ *
+ * @return @p true on success.
+ */
+ bool mergeConfig( const TQString & configFile );
+
+ /**
+ * Merge an existing parse table with the data from the
+ * given buffer.
+ *
+ * @return @p true on success.
+ */
+ bool mergeBufConfig(char *);
+
+ /**
+ * Enable/Disable follow-links.
+ *
+ * (Default is disabled.)
+ */
+ void setFollowLinks( bool _enable );
+
+ /**
+ * Try to find a MimeType for the given file.
+ *
+ * If no special
+ * MimeType is found, the default MimeType is returned.
+ * This function looks at the content of the file.
+ *
+ * @return A pointer to the result object. Do @em not delete the
+ * result object. After another call to KMimeMagic
+ * the returned result object changes its value
+ * since it is reused by KMimeMagic.
+ */
+ KMimeMagicResult* findFileType( const TQString & _filename );
+
+ /**
+ * Same functionality as above, except data is not
+ * read from a file.
+ *
+ * Instead a buffer can be supplied which
+ * is examined.
+ *
+ * @return A pointer to the result object. Do @em not delete the
+ * result object. After another call to KMimeMagic
+ * the returned result object changes its value
+ * since it is reused by KMimeMagic.
+ */
+ KMimeMagicResult* findBufferType( const TQByteArray &p );
+
+ /**
+ * Same functionality as findBufferType() but with
+ * additional capability of distinguishing between
+ * C-headers and C-Source.
+ *
+ * For this purpose this function looks
+ * at the extension of the filename. This means that 'filename'
+ * can be a filename on some FTP server, too.
+ *
+ * @return A pointer to the result object. Do @em not delete the
+ * result object. After another call to KMimeMagic
+ * the returned result object changes its value
+ * since it is reused by KMimeMagic.
+ */
+ KMimeMagicResult * findBufferFileType( const TQByteArray &, const TQString & filename );
+
+ /**
+ * Returns a pointer to the unique KMimeMagic instance in this process.
+ */
+ static KMimeMagic* self();
+
+protected:
+ /**
+ * The result type.
+ */
+ KMimeMagicResult * magicResult;
+
+ static void initStatic();
+ static KMimeMagic* s_pSelf;
+
+private:
+ void init( const TQString& configFile );
+
+ bool bunused;
+ TQString sunused;
+
+ int parse_line(char *line, int *rule, int lineno);
+ int parse(char *, int);
+ int buff_apprentice(char*buff);
+ int apprentice(const TQString &configFile);
+
+ struct config_rec *conf; // this is also our "d pointer"
+ int iunused;
+};
+
+#endif
+
diff --git a/tdeio/tdeio/kmimetype.cpp b/tdeio/tdeio/kmimetype.cpp
new file mode 100644
index 000000000..344be793a
--- /dev/null
+++ b/tdeio/tdeio/kmimetype.cpp
@@ -0,0 +1,1172 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ * 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.
+ **/
+// $Id$
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <kprotocolinfo.h>
+#include <tdeio/global.h>
+#include "kmimetype.h"
+#include "kservicetypefactory.h"
+#include "kmimemagic.h"
+#include "kservice.h"
+#include "krun.h"
+#include "kautomount.h"
+#include <kdirnotify_stub.h>
+
+#include <tqstring.h>
+#include <tqfile.h>
+#include <kmessageboxwrapper.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kdirwatch.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <tdesycoca.h>
+#include <kde_file.h>
+
+template class KSharedPtr<KMimeType>;
+template class TQValueList<KMimeType::Ptr>;
+
+KMimeType::Ptr KMimeType::s_pDefaultType = 0L;
+bool KMimeType::s_bChecked = false;
+
+void KMimeType::buildDefaultType()
+{
+ assert ( !s_pDefaultType );
+ // Try to find the default type
+ KServiceType * mime = KServiceTypeFactory::self()->
+ findServiceTypeByName( defaultMimeType() );
+
+ if (mime && mime->isType( KST_KMimeType ))
+ {
+ s_pDefaultType = KMimeType::Ptr((KMimeType *) mime);
+ }
+ else
+ {
+ errorMissingMimeType( defaultMimeType() );
+ KStandardDirs stdDirs;
+ TQString sDefaultMimeType = stdDirs.resourceDirs("mime").first()+defaultMimeType()+".desktop";
+ s_pDefaultType = new KMimeType( sDefaultMimeType, defaultMimeType(),
+ "unknown", "mime", TQStringList() );
+ }
+}
+
+KMimeType::Ptr KMimeType::defaultMimeTypePtr()
+{
+ if ( !s_pDefaultType ) // we need a default type first
+ buildDefaultType();
+ return s_pDefaultType;
+}
+
+// Check for essential mimetypes
+void KMimeType::checkEssentialMimeTypes()
+{
+ if ( s_bChecked ) // already done
+ return;
+ if ( !s_pDefaultType ) // we need a default type first
+ buildDefaultType();
+
+ s_bChecked = true; // must be done before building mimetypes
+
+ // No Mime-Types installed ?
+ // Lets do some rescue here.
+ if ( !KServiceTypeFactory::self()->checkMimeTypes() )
+ {
+ KMessageBoxWrapper::error( 0L, i18n( "No mime types installed." ) );
+ return; // no point in going any further
+ }
+
+ if ( KMimeType::mimeType( "inode/directory" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/directory" );
+ if ( KMimeType::mimeType( "inode/directory-locked" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/directory-locked" );
+ if ( KMimeType::mimeType( "inode/blockdevice" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/blockdevice" );
+ if ( KMimeType::mimeType( "inode/chardevice" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/chardevice" );
+ if ( KMimeType::mimeType( "inode/socket" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/socket" );
+ if ( KMimeType::mimeType( "inode/fifo" ) == s_pDefaultType )
+ errorMissingMimeType( "inode/fifo" );
+ if ( KMimeType::mimeType( "application/x-shellscript" ) == s_pDefaultType )
+ errorMissingMimeType( "application/x-shellscript" );
+ if ( KMimeType::mimeType( "application/x-executable" ) == s_pDefaultType )
+ errorMissingMimeType( "application/x-executable" );
+ if ( KMimeType::mimeType( "application/x-desktop" ) == s_pDefaultType )
+ errorMissingMimeType( "application/x-desktop" );
+}
+
+void KMimeType::errorMissingMimeType( const TQString& _type )
+{
+ TQString tmp = i18n( "Could not find mime type\n%1" ).arg( _type );
+
+ KMessageBoxWrapper::sorry( 0, tmp );
+}
+
+KMimeType::Ptr KMimeType::mimeType( const TQString& _name )
+{
+ KServiceType * mime = KServiceTypeFactory::self()->findServiceTypeByName( _name );
+
+ if ( !mime || !mime->isType( KST_KMimeType ) )
+ {
+ // When building tdesycoca, findServiceTypeByName doesn't create an object
+ // but returns one from a dict.
+ if ( !KSycoca::self()->isBuilding() )
+ delete mime;
+ if ( !s_pDefaultType )
+ buildDefaultType();
+ return s_pDefaultType;
+ }
+
+ // We got a mimetype
+ return KMimeType::Ptr((KMimeType *) mime);
+}
+
+KMimeType::List KMimeType::allMimeTypes()
+{
+ return KServiceTypeFactory::self()->allMimeTypes();
+}
+
+KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
+ bool _is_local_file, bool _fast_mode )
+{
+ checkEssentialMimeTypes();
+ TQString path = _url.path();
+
+ if ( !_fast_mode && !_is_local_file && _url.isLocalFile() )
+ _is_local_file = true;
+
+ if ( !_fast_mode && _is_local_file && (_mode == 0 || _mode == (mode_t)-1) )
+ {
+ KDE_struct_stat buff;
+ if ( KDE_stat( TQFile::encodeName(path), &buff ) != -1 )
+ _mode = buff.st_mode;
+ }
+
+ // Look at mode_t first
+ if ( S_ISDIR( _mode ) )
+ {
+ // Special hack for local files. We want to see whether we
+ // are allowed to enter the directory
+ if ( _is_local_file )
+ {
+ if ( access( TQFile::encodeName(path), R_OK ) == -1 )
+ return mimeType( "inode/directory-locked" );
+ }
+ return mimeType( "inode/directory" );
+ }
+ if ( S_ISCHR( _mode ) )
+ return mimeType( "inode/chardevice" );
+ if ( S_ISBLK( _mode ) )
+ return mimeType( "inode/blockdevice" );
+ if ( S_ISFIFO( _mode ) )
+ return mimeType( "inode/fifo" );
+ if ( S_ISSOCK( _mode ) )
+ return mimeType( "inode/socket" );
+ // KMimeMagic can do that better for local files
+ if ( !_is_local_file && S_ISREG( _mode ) && ( _mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
+ return mimeType( "application/x-executable" );
+
+ TQString fileName ( _url.fileName() );
+
+ static const TQString& slash = TDEGlobal::staticQString("/");
+ if ( ! fileName.isNull() && !path.endsWith( slash ) )
+ {
+ // Try to find it out by looking at the filename
+ KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName );
+ if ( mime )
+ {
+ // Found something - can we trust it ? (e.g. don't trust *.pl over HTTP, could be anything)
+ if ( _is_local_file || _url.hasSubURL() || // Explicitly trust suburls
+ KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) )
+ {
+ if ( _is_local_file && !_fast_mode ) {
+ if ( mime->patternsAccuracy()<100 )
+ {
+ KMimeMagicResult* result =
+ KMimeMagic::self()->findFileType( path );
+
+ if ( result && result->isValid() && result->accuracy() > 0 )
+ return mimeType( result->mimeType() );
+ }
+ }
+
+ return mime;
+ }
+ }
+
+ static const TQString& dotdesktop = TDEGlobal::staticQString(".desktop");
+ static const TQString& dotkdelnk = TDEGlobal::staticQString(".kdelnk");
+ static const TQString& dotdirectory = TDEGlobal::staticQString(".directory");
+
+ // Another filename binding, hardcoded, is .desktop:
+ if ( fileName.endsWith( dotdesktop ) )
+ return mimeType( "application/x-desktop" );
+ // Another filename binding, hardcoded, is .kdelnk;
+ // this is preserved for backwards compatibility
+ if ( fileName.endsWith( dotkdelnk ) )
+ return mimeType( "application/x-desktop" );
+ // .directory files are detected as x-desktop by mimemagic
+ // but don't have a Type= entry. Better cheat and say they are text files
+ if ( fileName == dotdirectory )
+ return mimeType( "text/plain" );
+ }
+
+ if ( !_is_local_file || _fast_mode )
+ {
+ TQString def = KProtocolInfo::defaultMimetype( _url );
+ if ( !def.isEmpty() && def != defaultMimeType() )
+ {
+ // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
+ return mimeType( def );
+ }
+ if ( path.endsWith( slash ) || path.isEmpty() )
+ {
+ // We have no filename at all. Maybe the protocol has a setting for
+ // which mimetype this means (e.g. directory).
+ // For HTTP (def==defaultMimeType()) we don't assume anything,
+ // because of redirections (e.g. freshmeat downloads).
+ if ( def.isEmpty() )
+ {
+ // Assume inode/directory, if the protocol supports listing.
+ if ( KProtocolInfo::supportsListing( _url ) )
+ return mimeType( TQString::fromLatin1("inode/directory") );
+ else
+ return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
+ }
+ }
+
+ // No more chances for non local URLs
+ return defaultMimeTypePtr();
+ }
+
+ // Do some magic for local files
+ //kdDebug(7009) << TQString("Mime Type finding for '%1'").arg(path) << endl;
+ KMimeMagicResult* result = KMimeMagic::self()->findFileType( path );
+
+ // If we still did not find it, we must assume the default mime type
+ if ( !result || !result->isValid() )
+ return defaultMimeTypePtr();
+
+ // The mimemagic stuff was successful
+ return mimeType( result->mimeType() );
+}
+
+KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
+ bool _is_local_file, bool _fast_mode,
+ bool *accurate)
+{
+ KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode);
+ if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr());
+ return mime;
+}
+
+KMimeType::Ptr KMimeType::diagnoseFileName(const TQString &fileName, TQString &pattern)
+{
+ return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern );
+}
+
+KMimeType::Ptr KMimeType::findByPath( const TQString& path, mode_t mode, bool fast_mode )
+{
+ KURL u;
+ u.setPath(path);
+ return findByURL( u, mode, true, fast_mode );
+}
+
+KMimeType::Ptr KMimeType::findByContent( const TQByteArray &data, int *accuracy )
+{
+ KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data);
+ if (accuracy)
+ *accuracy = result->accuracy();
+ return mimeType( result->mimeType() );
+}
+
+KMimeType::Ptr KMimeType::findByFileContent( const TQString &fileName, int *accuracy )
+{
+ KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName);
+ if (accuracy)
+ *accuracy = result->accuracy();
+ return mimeType( result->mimeType() );
+}
+
+#define GZIP_MAGIC1 0x1f
+#define GZIP_MAGIC2 0x8b
+
+KMimeType::Format KMimeType::findFormatByFileContent( const TQString &fileName )
+{
+ KMimeType::Format result;
+ result.compression = Format::NoCompression;
+ KMimeType::Ptr mime = findByPath(fileName);
+
+ result.text = mime->name().startsWith("text/");
+ TQVariant v = mime->property("X-TDE-text");
+ if (v.isValid())
+ result.text = v.toBool();
+
+ if (mime->name().startsWith("inode/"))
+ return result;
+
+ TQFile f(fileName);
+ if (f.open(IO_ReadOnly))
+ {
+ unsigned char buf[10+1];
+ int l = f.readBlock((char *)buf, 10);
+ if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2))
+ result.compression = Format::GZipCompression;
+ }
+ return result;
+}
+
+KMimeType::KMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
+ const TQString& _comment, const TQStringList& _patterns )
+ : KServiceType( _fullpath, _type, _icon, _comment )
+{
+ m_lstPatterns = _patterns;
+}
+
+KMimeType::KMimeType( const TQString & _fullpath ) : KServiceType( _fullpath )
+{
+ KDesktopFile _cfg( _fullpath, true );
+ init ( &_cfg );
+
+ if ( !isValid() )
+ kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
+}
+
+KMimeType::KMimeType( KDesktopFile *config ) : KServiceType( config )
+{
+ init( config );
+
+ if ( !isValid() )
+ kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
+}
+
+void KMimeType::init( KDesktopFile * config )
+{
+ config->setDesktopGroup();
+ m_lstPatterns = config->readListEntry( "Patterns", ';' );
+
+ // Read the X-TDE-AutoEmbed setting and store it in the properties map
+ TQString XKDEAutoEmbed = TQString::fromLatin1("X-TDE-AutoEmbed");
+ if ( config->hasKey( XKDEAutoEmbed ) )
+ m_mapProps.insert( XKDEAutoEmbed, TQVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) );
+
+ TQString XKDEText = TQString::fromLatin1("X-TDE-text");
+ if ( config->hasKey( XKDEText ) )
+ m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) );
+
+ TQString XKDEIsAlso = TQString::fromLatin1("X-TDE-IsAlso");
+ if ( config->hasKey( XKDEIsAlso ) ) {
+ TQString inherits = config->readEntry( XKDEIsAlso );
+ if ( inherits != name() )
+ m_mapProps.insert( XKDEIsAlso, inherits );
+ else
+ kdWarning(7009) << "Error: " << inherits << " inherits from itself!!!!" << endl;
+ }
+
+ TQString XKDEPatternsAccuracy = TQString::fromLatin1("X-TDE-PatternsAccuracy");
+ if ( config->hasKey( XKDEPatternsAccuracy ) )
+ m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) );
+
+}
+
+KMimeType::KMimeType( TQDataStream& _str, int offset ) : KServiceType( _str, offset )
+{
+ loadInternal( _str ); // load our specific stuff
+}
+
+void KMimeType::load( TQDataStream& _str )
+{
+ KServiceType::load( _str );
+ loadInternal( _str );
+}
+
+void KMimeType::loadInternal( TQDataStream& _str )
+{
+ // kdDebug(7009) << "KMimeType::load( TQDataStream& ) : loading list of patterns" << endl;
+ _str >> m_lstPatterns;
+}
+
+void KMimeType::save( TQDataStream& _str )
+{
+ KServiceType::save( _str );
+ // Warning adding/removing fields here involves a binary incompatible change - update version
+ // number in tdesycoca.h
+ _str << m_lstPatterns;
+}
+
+TQVariant KMimeType::property( const TQString& _name ) const
+{
+ if ( _name == "Patterns" )
+ return TQVariant( m_lstPatterns );
+
+ return KServiceType::property( _name );
+}
+
+TQStringList KMimeType::propertyNames() const
+{
+ TQStringList res = KServiceType::propertyNames();
+ res.append( "Patterns" );
+
+ return res;
+}
+
+KMimeType::~KMimeType()
+{
+}
+
+TQPixmap KMimeType::pixmap( KIcon::Group _group, int _force_size, int _state,
+ TQString * _path ) const
+{
+ KIconLoader *iconLoader=TDEGlobal::iconLoader();
+ TQString iconName=icon( TQString::null, false );
+ if (!iconLoader->extraDesktopThemesAdded())
+ {
+ TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
+ if (!pixmap.isNull() ) return pixmap;
+
+ iconLoader->addExtraDesktopThemes();
+ }
+
+ return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
+}
+
+TQPixmap KMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
+ int _state, TQString * _path ) const
+{
+ KIconLoader *iconLoader=TDEGlobal::iconLoader();
+ TQString iconName=icon( _url, _url.isLocalFile() );
+ if (!iconLoader->extraDesktopThemesAdded())
+ {
+ TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
+ if (!pixmap.isNull() ) return pixmap;
+
+ iconLoader->addExtraDesktopThemes();
+ }
+
+ return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
+}
+
+TQPixmap KMimeType::pixmapForURL( const KURL & _url, mode_t _mode, KIcon::Group _group,
+ int _force_size, int _state, TQString * _path )
+{
+ KIconLoader *iconLoader=TDEGlobal::iconLoader();
+ TQString iconName = iconForURL( _url, _mode );
+
+ if (!iconLoader->extraDesktopThemesAdded())
+ {
+ TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
+ if (!pixmap.isNull() ) return pixmap;
+
+ iconLoader->addExtraDesktopThemes();
+ }
+
+ return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
+
+}
+
+TQString KMimeType::iconForURL( const KURL & _url, mode_t _mode )
+{
+ const KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(),
+ false /*HACK*/);
+ static const TQString& unknown = TDEGlobal::staticQString("unknown");
+ const TQString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() );
+ TQString i = mimeTypeIcon;
+
+ // if we don't find an icon, maybe we can use the one for the protocol
+ if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr()
+ // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
+ || _url.path().length() <= 1 )
+ {
+ i = favIconForURL( _url ); // maybe there is a favicon?
+
+ if ( i.isEmpty() )
+ i = KProtocolInfo::icon( _url.protocol() );
+
+ // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
+ if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
+ i = mimeTypeIcon;
+ }
+ return i;
+}
+
+TQString KMimeType::favIconForURL( const KURL& url )
+{
+ // this method will be called quite often, so better not read the config
+ // again and again.
+ static bool useFavIcons = true;
+ static bool check = true;
+ if ( check ) {
+ check = false;
+ TDEConfig *config = TDEGlobal::config();
+ TDEConfigGroupSaver cs( config, "HTML Settings" );
+ useFavIcons = config->readBoolEntry( "EnableFavicon", true );
+ }
+
+ if ( url.isLocalFile() || !url.protocol().startsWith("http")
+ || !useFavIcons )
+ return TQString::null;
+
+ DCOPRef kded( "kded", "favicons" );
+ DCOPReply result = kded.call( "iconForURL(KURL)", url );
+ if ( result.isValid() )
+ return result;
+
+ return TQString::null;
+}
+
+TQString KMimeType::parentMimeType() const
+{
+ TQVariant v = property("X-TDE-IsAlso");
+ return v.toString();
+}
+
+bool KMimeType::is( const TQString& mimeTypeName ) const
+{
+ if ( name() == mimeTypeName )
+ return true;
+ TQString st = parentMimeType();
+ //if (st.isEmpty()) kdDebug(7009)<<"Parent mimetype is empty"<<endl;
+ while ( !st.isEmpty() )
+ {
+ //kdDebug(7009)<<"Checking parent mime type: "<<st<<endl;
+ KMimeType::Ptr ptr = KMimeType::mimeType( st );
+ if (!ptr) return false; //error
+ if ( ptr->name() == mimeTypeName )
+ return true;
+ st = ptr->parentMimeType();
+ }
+ return false;
+}
+
+int KMimeType::patternsAccuracy() const {
+ TQVariant v = property("X-TDE-PatternsAccuracy");
+ if (!v.isValid()) return 100;
+ else
+ return v.toInt();
+}
+
+
+/*******************************************************
+ *
+ * KFolderType
+ *
+ ******************************************************/
+
+TQString KFolderType::icon( const TQString& _url, bool _is_local ) const
+{
+ if ( !_is_local || _url.isEmpty() )
+ return KMimeType::icon( _url, _is_local );
+
+ return KFolderType::icon( KURL(_url), _is_local );
+}
+
+TQString KFolderType::icon( const KURL& _url, bool _is_local ) const
+{
+ if ( !_is_local )
+ return KMimeType::icon( _url, _is_local );
+
+ KURL u( _url );
+ u.addPath( ".directory" );
+
+ TQString icon;
+ // using KStandardDirs as this one checks for path being
+ // a file instead of a directory
+ if ( KStandardDirs::exists( u.path() ) )
+ {
+ KSimpleConfig cfg( u.path(), true );
+ cfg.setDesktopGroup();
+ icon = cfg.readEntry( "Icon" );
+ TQString empty_icon = cfg.readEntry( "EmptyIcon" );
+
+ if ( !empty_icon.isEmpty() )
+ {
+ bool isempty = false;
+ DIR *dp = 0L;
+ struct dirent *ep;
+ dp = opendir( TQFile::encodeName(_url.path()) );
+ if ( dp )
+ {
+ TQValueList<TQCString> entries;
+ // Note that readdir isn't guaranteed to return "." and ".." first (#79826)
+ ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
+ ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
+ if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory
+ isempty = true;
+ else {
+ entries.append( ep->d_name );
+ if ( readdir( dp ) == 0 ) { // only three
+ // check if we got "." ".." and ".directory"
+ isempty = entries.find( "." ) != entries.end() &&
+ entries.find( ".." ) != entries.end() &&
+ entries.find( ".directory" ) != entries.end();
+ }
+ }
+ if (!isempty && !strcmp(ep->d_name, ".directory"))
+ isempty = (readdir(dp) == 0L);
+ closedir( dp );
+ }
+
+ if ( isempty )
+ return empty_icon;
+ }
+ }
+
+ if ( icon.isEmpty() )
+ return KMimeType::icon( _url, _is_local );
+
+ if ( icon.startsWith( "./" ) ) {
+ // path is relative with respect to the location
+ // of the .directory file (#73463)
+ KURL v( _url );
+ v.addPath( icon.mid( 2 ) );
+ icon = v.path();
+ }
+
+ return icon;
+}
+
+TQString KFolderType::comment( const TQString& _url, bool _is_local ) const
+{
+ if ( !_is_local || _url.isEmpty() )
+ return KMimeType::comment( _url, _is_local );
+
+ return KFolderType::comment( KURL(_url), _is_local );
+}
+
+TQString KFolderType::comment( const KURL& _url, bool _is_local ) const
+{
+ if ( !_is_local )
+ return KMimeType::comment( _url, _is_local );
+
+ KURL u( _url );
+ u.addPath( ".directory" );
+
+ KDesktopFile cfg( u.path(), true );
+ TQString comment = cfg.readComment();
+ if ( comment.isEmpty() )
+ return KMimeType::comment( _url, _is_local );
+
+ return comment;
+}
+
+/*******************************************************
+ *
+ * KDEDesktopMimeType
+ *
+ ******************************************************/
+
+TQString KDEDesktopMimeType::icon( const TQString& _url, bool _is_local ) const
+{
+ if ( !_is_local || _url.isEmpty() )
+ return KMimeType::icon( _url, _is_local );
+
+ KURL u( _url );
+ return icon( u, _is_local );
+}
+
+TQString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const
+{
+ if ( !_is_local )
+ return KMimeType::icon( _url, _is_local );
+
+ KSimpleConfig cfg( _url.path(), true );
+ cfg.setDesktopGroup();
+ TQString icon = cfg.readEntry( "Icon" );
+ TQString type = cfg.readEntry( "Type" );
+
+ if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for
+ // backwards compatibility
+ {
+ TQString unmount_icon = cfg.readEntry( "UnmountIcon" );
+ TQString dev = cfg.readEntry( "Dev" );
+ if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
+ {
+ TQString mp = TDEIO::findDeviceMountPoint( dev );
+ // Is the device not mounted ?
+ if ( mp.isNull() )
+ return unmount_icon;
+ }
+ } else if ( type == "Link" ) {
+ const TQString emptyIcon = cfg.readEntry( "EmptyIcon" );
+ if ( !emptyIcon.isEmpty() ) {
+ const TQString u = cfg.readPathEntry( "URL" );
+ const KURL url( u );
+ if ( url.protocol() == "trash" ) {
+ // We need to find if the trash is empty, preferrably without using a KIO job.
+ // So instead kio_trash leaves an entry in its config file for us.
+ KSimpleConfig trashConfig( "trashrc", true );
+ trashConfig.setGroup( "Status" );
+ if ( trashConfig.readBoolEntry( "Empty", true ) ) {
+ return emptyIcon;
+ }
+ }
+ }
+ }
+
+ if ( icon.isEmpty() )
+ return KMimeType::icon( _url, _is_local );
+
+ return icon;
+}
+
+TQPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
+ int _state, TQString * _path ) const
+{
+ TQString _icon = icon( _url, _url.isLocalFile() );
+ TQPixmap pix = TDEGlobal::iconLoader()->loadIcon( _icon, _group,
+ _force_size, _state, _path, false );
+ if ( pix.isNull() )
+ pix = TDEGlobal::iconLoader()->loadIcon( "unknown", _group,
+ _force_size, _state, _path, false );
+ return pix;
+}
+
+TQString KDEDesktopMimeType::comment( const TQString& _url, bool _is_local ) const
+{
+ if ( !_is_local || _url.isEmpty() )
+ return KMimeType::comment( _url, _is_local );
+
+ KURL u( _url );
+ return comment( u, _is_local );
+}
+
+TQString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const
+{
+ if ( !_is_local )
+ return KMimeType::comment( _url, _is_local );
+
+ KDesktopFile cfg( _url.path(), true );
+ TQString comment = cfg.readComment();
+ if ( comment.isEmpty() )
+ return KMimeType::comment( _url, _is_local );
+
+ return comment;
+}
+
+pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local )
+{
+ // It might be a security problem to run external untrusted desktop
+ // entry files
+ if ( !_is_local )
+ return 0;
+
+ KSimpleConfig cfg( u.path(), true );
+ cfg.setDesktopGroup();
+ TQString type = cfg.readEntry( "Type" );
+ if ( type.isEmpty() )
+ {
+ TQString tmp = i18n("The desktop entry file %1 "
+ "has no Type=... entry.").arg(u.path() );
+ KMessageBoxWrapper::error( 0, tmp);
+ return 0;
+ }
+
+ //kdDebug(7009) << "TYPE = " << type.data() << endl;
+
+ if ( type == "FSDevice" )
+ return runFSDevice( u, cfg );
+ else if ( type == "Application" )
+ return runApplication( u, u.path() );
+ else if ( type == "Link" )
+ {
+ cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon)
+ return runLink( u, cfg );
+ }
+ else if ( type == "MimeType" )
+ return runMimeType( u, cfg );
+
+
+ TQString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type );
+ KMessageBoxWrapper::error( 0, tmp);
+
+ return 0;
+}
+
+pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg )
+{
+ pid_t retval = 0;
+
+ TQString dev = cfg.readEntry( "Dev" );
+
+ if ( dev.isEmpty() )
+ {
+ TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
+ KMessageBoxWrapper::error( 0, tmp);
+ return retval;
+ }
+
+ TQString mp = TDEIO::findDeviceMountPoint( dev );
+ // Is the device already mounted ?
+ if ( !mp.isNull() )
+ {
+ KURL mpURL;
+ mpURL.setPath( mp );
+ // Open a new window
+ retval = KRun::runURL( mpURL, TQString::fromLatin1("inode/directory") );
+ }
+ else
+ {
+ bool ro = cfg.readBoolEntry( "ReadOnly", false );
+ TQString fstype = cfg.readEntry( "FSType" );
+ if ( fstype == "Default" ) // KDE-1 thing
+ fstype = TQString::null;
+ TQString point = cfg.readEntry( "MountPoint" );
+#ifndef Q_WS_WIN
+ (void) new KAutoMount( ro, fstype, dev, point, _url.path() );
+#endif
+ retval = -1; // we don't want to return 0, but we don't want to return a pid
+ }
+
+ return retval;
+}
+
+pid_t KDEDesktopMimeType::runApplication( const KURL& , const TQString & _serviceFile )
+{
+ KService s( _serviceFile );
+ if ( !s.isValid() )
+ // The error message was already displayed, so we can just quit here
+ return 0;
+
+ KURL::List lst;
+ return KRun::run( s, lst );
+}
+
+pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg )
+{
+ TQString u = cfg.readPathEntry( "URL" );
+ if ( u.isEmpty() )
+ {
+ TQString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
+ KMessageBoxWrapper::error( 0, tmp );
+ return 0;
+ }
+
+ KURL url ( u );
+ KRun* run = new KRun(url);
+
+ // X-TDE-LastOpenedWith holds the service desktop entry name that
+ // was should be preferred for opening this URL if possible.
+ // This is used by the Recent Documents menu for instance.
+ TQString lastOpenedWidth = cfg.readEntry( "X-TDE-LastOpenedWith" );
+ if ( !lastOpenedWidth.isEmpty() )
+ run->setPreferredService( lastOpenedWidth );
+
+ return -1; // we don't want to return 0, but we don't want to return a pid
+}
+
+pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & )
+{
+ // Hmm, can't really use keditfiletype since we might be looking
+ // at the global file, or at a file not in share/mimelnk...
+
+ TQStringList args;
+ args << "openProperties";
+ args << url.path();
+
+ int pid;
+ if ( !TDEApplication::tdeinitExec("kfmclient", args, 0, &pid) )
+ return pid;
+
+ TDEProcess p;
+ p << "kfmclient" << args;
+ p.start(TDEProcess::DontCare);
+ return p.pid();
+}
+
+TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url )
+{
+ TQValueList<Service> result;
+
+ if ( !_url.isLocalFile() )
+ return result;
+
+ KSimpleConfig cfg( _url.path(), true );
+ cfg.setDesktopGroup();
+ TQString type = cfg.readEntry( "Type" );
+
+ if ( type.isEmpty() )
+ return result;
+
+ if ( type == "FSDevice" )
+ {
+ TQString dev = cfg.readEntry( "Dev" );
+ if ( dev.isEmpty() )
+ {
+ TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
+ KMessageBoxWrapper::error( 0, tmp);
+ }
+ else
+ {
+ TQString mp = TDEIO::findDeviceMountPoint( dev );
+ // not mounted ?
+ if ( mp.isEmpty() )
+ {
+ Service mount;
+ mount.m_strName = i18n("Mount");
+ mount.m_type = ST_MOUNT;
+ result.append( mount );
+ }
+ else
+ {
+ Service unmount;
+#ifdef HAVE_VOLMGT
+ /*
+ * Solaris' volume management can only umount+eject
+ */
+ unmount.m_strName = i18n("Eject");
+#else
+ unmount.m_strName = i18n("Unmount");
+#endif
+ unmount.m_type = ST_UNMOUNT;
+ result.append( unmount );
+ }
+ }
+ }
+
+ return result;
+}
+
+TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, bool bLocalFiles )
+{
+ KSimpleConfig cfg( path, true );
+ return userDefinedServices( path, cfg, bLocalFiles );
+}
+
+TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, TDEConfig& cfg, bool bLocalFiles )
+{
+ return userDefinedServices( path, cfg, bLocalFiles, KURL::List() );
+}
+
+TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, TDEConfig& cfg, bool bLocalFiles, const KURL::List & file_list )
+{
+ TQValueList<Service> result;
+
+ cfg.setDesktopGroup();
+
+ if ( !cfg.hasKey( "Actions" ) && !cfg.hasKey( "X-TDE-GetActionMenu") )
+ return result;
+
+ if ( cfg.hasKey( "TryExec" ) )
+ {
+ TQString tryexec = cfg.readPathEntry( "TryExec" );
+ TQString exe = KStandardDirs::findExe( tryexec );
+ if (exe.isEmpty()) {
+ return result;
+ }
+ }
+
+ TQStringList keys;
+
+ if( cfg.hasKey( "X-TDE-GetActionMenu" )) {
+ TQString dcopcall = cfg.readEntry( "X-TDE-GetActionMenu" );
+ const TQCString app = TQString(dcopcall.section(' ', 0,0)).utf8();
+
+ TQByteArray dataToSend;
+ TQDataStream dataStream(dataToSend, IO_WriteOnly);
+ dataStream << file_list;
+ TQCString replyType;
+ TQByteArray replyData;
+ TQCString object = TQString(dcopcall.section(' ', 1,-2)).utf8();
+ TQString function = dcopcall.section(' ', -1);
+ if(!function.endsWith("(KURL::List)")) {
+ kdWarning() << "Desktop file " << path << " contains an invalid X-TDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
+ } else {
+ if(kapp->dcopClient()->call( app, object,
+ function.utf8(),
+ dataToSend, replyType, replyData, true, -1)
+ && replyType == "TQStringList" ) {
+
+ TQDataStream dataStreamIn(replyData, IO_ReadOnly);
+ dataStreamIn >> keys;
+ }
+ }
+ }
+
+ keys += cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator!
+
+ if ( keys.count() == 0 )
+ return result;
+
+ TQStringList::ConstIterator it = keys.begin();
+ TQStringList::ConstIterator end = keys.end();
+ for ( ; it != end; ++it )
+ {
+ //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl;
+
+ TQString group = *it;
+
+ if (group == "_SEPARATOR_")
+ {
+ Service s;
+ result.append(s);
+ continue;
+ }
+
+ group.prepend( "Desktop Action " );
+
+ bool bInvalidMenu = false;
+
+ if ( cfg.hasGroup( group ) )
+ {
+ cfg.setGroup( group );
+
+ if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) )
+ bInvalidMenu = true;
+ else
+ {
+ TQString exec = cfg.readPathEntry( "Exec" );
+ if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") )
+ {
+ Service s;
+ s.m_strName = cfg.readEntry( "Name" );
+ s.m_strIcon = cfg.readEntry( "Icon" );
+ s.m_strExec = exec;
+ s.m_type = ST_USER_DEFINED;
+ s.m_display = !cfg.readBoolEntry( "NoDisplay" );
+ result.append( s );
+ }
+ }
+ }
+ else
+ bInvalidMenu = true;
+
+ if ( bInvalidMenu )
+ {
+ TQString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
+ KMessageBoxWrapper::error( 0, tmp );
+ }
+ }
+
+ return result;
+}
+
+void KDEDesktopMimeType::executeService( const TQString& _url, KDEDesktopMimeType::Service& _service )
+{
+ KURL u;
+ u.setPath(_url);
+ KURL::List lst;
+ lst.append( u );
+ executeService( lst, _service );
+}
+
+void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service )
+{
+ //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl;
+
+ if ( _service.m_type == ST_USER_DEFINED )
+ {
+ kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName
+ << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl;
+ KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
+ // The action may update the desktop file. Example: eject unmounts (#5129).
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesChanged( urls );
+ return;
+ }
+ else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
+ {
+ Q_ASSERT( urls.count() == 1 );
+ TQString path = urls.first().path();
+ //kdDebug(7009) << "MOUNT&UNMOUNT" << endl;
+
+ KSimpleConfig cfg( path, true );
+ cfg.setDesktopGroup();
+ TQString dev = cfg.readEntry( "Dev" );
+ if ( dev.isEmpty() )
+ {
+ TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
+ KMessageBoxWrapper::error( 0, tmp );
+ return;
+ }
+ TQString mp = TDEIO::findDeviceMountPoint( dev );
+
+ if ( _service.m_type == ST_MOUNT )
+ {
+ // Already mounted? Strange, but who knows ...
+ if ( !mp.isEmpty() )
+ {
+ kdDebug(7009) << "ALREADY Mounted" << endl;
+ return;
+ }
+
+ bool ro = cfg.readBoolEntry( "ReadOnly", false );
+ TQString fstype = cfg.readEntry( "FSType" );
+ if ( fstype == "Default" ) // KDE-1 thing
+ fstype = TQString::null;
+ TQString point = cfg.readEntry( "MountPoint" );
+#ifndef Q_WS_WIN
+ (void)new KAutoMount( ro, fstype, dev, point, path, false );
+#endif
+ }
+ else if ( _service.m_type == ST_UNMOUNT )
+ {
+ // Not mounted? Strange, but who knows ...
+ if ( mp.isEmpty() )
+ return;
+
+#ifndef Q_WS_WIN
+ (void)new KAutoUnmount( mp, path );
+#endif
+ }
+ }
+ else
+ assert( 0 );
+}
+
+const TQString & KMimeType::defaultMimeType()
+{
+ static const TQString & s_strDefaultMimeType =
+ TDEGlobal::staticQString( "application/octet-stream" );
+ return s_strDefaultMimeType;
+}
+
+void KMimeType::virtual_hook( int id, void* data )
+{ KServiceType::virtual_hook( id, data ); }
+
+void KFolderType::virtual_hook( int id, void* data )
+{ KMimeType::virtual_hook( id, data ); }
+
+void KDEDesktopMimeType::virtual_hook( int id, void* data )
+{ KMimeType::virtual_hook( id, data ); }
+
+void KExecMimeType::virtual_hook( int id, void* data )
+{ KMimeType::virtual_hook( id, data ); }
+
+#include "kmimetyperesolver.moc"
+
diff --git a/tdeio/tdeio/kmimetype.h b/tdeio/tdeio/kmimetype.h
new file mode 100644
index 000000000..19a846b46
--- /dev/null
+++ b/tdeio/tdeio/kmimetype.h
@@ -0,0 +1,641 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ * 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 __kmimetype_h__
+#define __kmimetype_h__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <tqstringlist.h>
+#include <tqvaluelist.h>
+#include <tqpixmap.h>
+
+#include <kicontheme.h>
+#include <kurl.h>
+#include <tdesycocatype.h>
+#include <kservicetype.h>
+
+class KSimpleConfig;
+/**
+ * Represent a mime type, like "text/plain", and the data that is associated
+ * with it.
+ *
+ * The starting point you need is often the static methods.
+ *
+ * KMimeType inherits KServiceType because "text/plain" can be used to find
+ * services (apps and components) "which can open text/plain".
+ *
+ * @see KServiceType
+ */
+class TDEIO_EXPORT KMimeType : public KServiceType
+{
+ K_SYCOCATYPE( KST_KMimeType, KServiceType )
+
+public:
+ typedef KSharedPtr<KMimeType> Ptr;
+ typedef TQValueList<Ptr> List;
+public:
+ /**
+ * Constructor.
+ *
+ * You may pass in arguments to create a mimetype with
+ * specific properties.
+ *
+ * @param _fullpath the path to the configuration file (.desktop)
+ * @param _type the mime type itself
+ * @param _icon the name of the icon that represens the mime type
+ * @param _comment a comment describing the mime type
+ * @param _patterns a list of file globs that describes the names (or
+ * extensions) of the files with this mime type
+ */
+ KMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
+ const TQString& _comment, const TQStringList& _patterns );
+
+ /**
+ * Construct a mimetype and take all information from a config file.
+ * @param _fullpath the path to the configuration file (.desktop)
+ */
+ KMimeType( const TQString & _fullpath );
+
+ /**
+ * Construct a mimetype and take all information from a desktop file.
+ * @param config the desktop configuration file that describes the mime type
+ */
+ KMimeType( KDesktopFile *config );
+
+ /**
+ * @internal Construct a service from a stream.
+ *
+ * The stream must already be positionned at the correct offset
+ */
+ KMimeType( TQDataStream& _str, int offset );
+
+ virtual ~KMimeType();
+
+ /**
+ * Return the filename of the icon associated with the mimetype.
+ *
+ * The arguments are unused, but provided so that KMimeType-derived classes
+ * can use them (e.g. KFolderType uses the URL to return one out of 2 icons)
+ *
+ * @return The path to the icon associated with this MIME type.
+ */
+ virtual TQString icon( const TQString& , bool ) const { return m_strIcon; }
+
+ /**
+ * Return the filename of the icon associated with the mimetype.
+ *
+ * The arguments are unused, but provided so that KMimeType-derived classes
+ * can use them (e.g. KFolderType uses the URL to return one out of 2 icons)
+ *
+ * @return The path to the icon associated with this MIME type.
+ */
+ virtual TQString icon( const KURL& , bool ) const { return m_strIcon; }
+
+ /**
+ * Use this function only if you don't have a special URL
+ * for which you search a pixmap.
+ *
+ * This function is useful to find
+ * out, which icon is usually chosen for a certain mime type. Since
+ * no URL is passed, it is impossible to obey icon hints in desktop
+ * entries for example.
+ * @param group The icon group where the icon is going to be used.
+ * @param force_size Override globallly configured icon size.
+ * Use 0 for the default size
+ * @param state The icon state, one of: @p KIcon::DefaultState,
+ * @p KIcon::ActiveState or @p KIcon::DisabledState.
+ * @param path Output parameter to get the full path. Seldom needed.
+ * Ignored if 0
+ * @return the pixmap of the mime type, can be a default icon if not found
+ */
+ virtual TQPixmap pixmap( KIcon::Group group, int force_size = 0, int state = 0,
+ TQString * path = 0L ) const;
+
+ /**
+ * Find the pixmap for a given file of this mimetype.
+ *
+ * Convenience method that uses icon(), but also locates and
+ * load the pixmap.
+ *
+ * @param _url URL for the file.
+ * @param _group The icon group where the icon is going to be used.
+ * @param _force_size Override globallly configured icon size.
+ * Use 0 for the default size
+ * @param _state The icon state, one of: KIcon::DefaultState,
+ * KIcon::ActiveState or KIcon::DisabledState.
+ * @param _path Output parameter to get the full path. Seldom needed.
+ * Ignored if 0
+ * @return the pixmap of the URL, can be a default icon if not found
+ */
+ virtual TQPixmap pixmap( const KURL& _url, KIcon::Group _group, int _force_size = 0,
+ int _state = 0, TQString * _path = 0L ) const;
+
+ /**
+ * Convenience method to find the pixmap for a URL.
+ *
+ * Call this one when you don't know the mimetype.
+ *
+ * @param _url URL for the file.
+ * @param _mode the mode of the file. The mode may modify the icon
+ * with overlays that show special properties of the
+ * icon. Use 0 for default
+ * @param _group The icon group where the icon is going to be used.
+ * @param _force_size Override globally configured icon size.
+ * Use 0 for the default size
+ * @param _state The icon state, one of: KIcon::DefaultState,
+ * KIcon::ActiveState or KIcon::DisabledState.
+ * @param _path Output parameter to get the full path. Seldom needed.
+ * Ignored if 0
+ * @return the pixmap of the URL, can be a default icon if not found
+ */
+ static TQPixmap pixmapForURL( const KURL & _url, mode_t _mode = 0, KIcon::Group _group = KIcon::Desktop,
+ int _force_size = 0, int _state = 0, TQString * _path = 0L );
+
+
+ /**
+ * The same functionality as pixmapForURL(), but this method returns the name
+ * of the icon to load. You'll have to use KIconLoader to load the pixmap for it.
+ * The advantage of this method is that you can store the result, and then use it
+ * later on for any kind of size.
+ * @param _url URL for the file
+ * @param _mode the mode of the file. The mode may modify the icon
+ * with overlays that show special properties of the
+ * icon. Use 0 for default
+ * @return the name of the icon. The name of a default icon if there is no icon
+ * for the mime type
+ */
+ static TQString iconForURL( const KURL & _url, mode_t _mode = 0 );
+
+ /**
+ * Return the "favicon" (see http://www.favicon.com) for the given @p url,
+ * if available. Does NOT attempt to download the favicon, it only returns
+ * one that is already available.
+ *
+ * If unavailable, returns TQString::null.
+ * @param url the URL of the favicon
+ * @return the name of the favicon, or TQString::null
+ */
+ static TQString favIconForURL( const KURL& url );
+
+ /**
+ * Returns the descriptive comment associated with the MIME type.
+ * @return the descriptive comment associated with the MIME type
+ */
+ TQString comment() const { return m_strComment; }
+
+ /**
+ * Returns the descriptive comment associated with the MIME type.
+ * The arguments are unused, but provided so that KMimeType derived classes
+ * can use them.
+ *
+ * @return The descriptive comment associated with the MIME type, if any.
+ */
+ virtual TQString comment( const TQString&, bool ) const { return m_strComment; }
+
+ /**
+ * Returns the descriptive comment associated with the MIME type.
+ * The arguments are unused, but provided so that KMimeType derived classes
+ * can use them.
+ *
+ * @return The descriptive comment associated with the MIME type, if any.
+ */
+ virtual TQString comment( const KURL&, bool ) const { return m_strComment; }
+
+ /**
+ * Retrieve the list of patterns associated with the MIME Type.
+ * @return a list of file globs that describe the file names
+ * (or, usually, the extensions) of files with this mime type
+ */
+ const TQStringList& patterns() const { return m_lstPatterns; }
+
+ /**
+ * Load the mimetype from a stream.
+ * @param qs the stream to load from
+ */
+ virtual void load( TQDataStream &qs );
+
+ /**
+ * Save the mimetype to a stream.
+ * @param qs the stream to save to
+ */
+ virtual void save( TQDataStream &qs );
+
+ /**
+ * Returns the property with the given @p _name.
+ * @param _name the name of the property
+ * @return the value of the property
+ * @see propertyNames()
+ */
+ virtual TQVariant property( const TQString& _name ) const;
+
+ /**
+ * Retrieves a list of all properties associated with this
+ * KMimeType.
+ * @return a list of all property names
+ * @see property()
+ */
+ virtual TQStringList propertyNames() const;
+
+ /**
+ * Retrieve a pointer to the mime type @p _name or a pointer to the default
+ * mime type "application/octet-stream".
+ *
+ * 0L is @em never returned.
+ *
+ * @em Very @em important: Don't store the result in a KMimeType* !
+ *
+ * @param _name the name of the mime type
+ * @return the pointer to the KMimeType with the given @p _name, or
+ * a pointer to the application/octet-stream KMimeType if
+ * not found
+ * @see KServiceType::serviceType
+ */
+ static Ptr mimeType( const TQString& _name );
+
+ /**
+ * Finds a KMimeType with the given @p _url.
+ * This function looks at mode_t first.
+ * If that does not help it
+ * looks at the extension. This is fine for FTP, FILE, TAR and
+ * friends, but is not for HTTP ( cgi scripts! ). You should use
+ * KRun instead, but this function returns immediately while
+ * KRun is async. If no extension matches, then
+ * the file will be examined if the URL a local file or
+ * "application/octet-stream" is returned otherwise.
+ *
+ * @param _url Is the right most URL with a filesystem protocol. It
+ * is up to you to find out about that if you have a nested
+ * URL. For example
+ * "http://localhost/mist.gz#gzip:/decompress" would have to
+ * pass the "http://..." URL part, while
+ * "file:/tmp/x.tar#tar:/src/test.gz#gzip:/decompress" would
+ * have to pass the "tar:/..." part of the URL, since gzip is
+ * a filter protocol and not a filesystem protocol.
+ * @param _mode the mode of the file (used, for example, to identify
+ * executables)
+ * @param _is_local_file true if the file is local
+ * @param _fast_mode If set to true no disk access is allowed to
+ * find out the mimetype. The result may be suboptimal, but
+ * it is @em fast.
+ * @return A pointer to the matching mimetype. 0L is never returned.
+ * @em Very @em Important: Don't store the result in a KMimeType* !
+ */
+ static Ptr findByURL( const KURL& _url, mode_t _mode = 0,
+ bool _is_local_file = false, bool _fast_mode = false );
+
+ static Ptr findByURL( const KURL& _url, mode_t _mode,
+ bool _is_local_file, bool _fast_mode,
+ bool *accurate);
+ /**
+ * Finds a KMimeType with the given @p _url.
+ * This function looks at mode_t first.
+ * If that does not help it
+ * looks at the extension. This is fine for FTP, FILE, TAR and
+ * friends, but is not for HTTP ( cgi scripts! ). You should use
+ * KRun instead, but this function returns immediately while
+ * KRun is async. If no extension matches, then
+ * the file will be examined if the URL a local file or
+ * "application/octet-stream" is returned otherwise.
+ *
+ * Equivalent to
+ * \code
+ * KURL u;
+ * u.setPath(path);
+ * return findByURL( u, mode, true, fast_mode );
+ * \endcode
+ *
+ * @param path the path to the file
+ * @param mode the mode of the file (used, for example, to identify
+ * executables)
+ * @param fast_mode If set to true no disk access is allowed to
+ * find out the mimetype. The result may be suboptimal, but
+ * it is @em fast.
+ * @return A pointer to the matching mimetype. 0L is never returned.
+ */
+ static Ptr findByPath( const TQString& path, mode_t mode = 0, bool fast_mode = false );
+
+ /**
+ * Tries to find out the MIME type of a data chunk by looking for
+ * certain magic numbers and characteristic strings in it.
+ *
+ * @param data the data to examine
+ * @param accuracy If not a null pointer, *accuracy is set to the
+ * accuracy of the match (which is in the range 0..100)
+ * @return a pointer to the KMimeType. application/octet-stream's KMimeType of the
+ * type can not be found this way.
+ */
+ static Ptr findByContent( const TQByteArray &data, int *accuracy=0 );
+
+ /**
+ * Tries to find out the MIME type of a file by looking for
+ * certain magic numbers and characteristic strings in it.
+ * This function is similar to the previous one. Note that the
+ * file name is not used for determining the file type, it is just
+ * used for loading the file's contents.
+ *
+ * @param fileName the path to the file
+ * @param accuracy If not a null pointer, *accuracy is set to the
+ * accuracy of the match (which is in the range 0..100)
+ * @return a pointer to the KMimeType. application/octet-stream's KMimeType of the
+ * type can not be found this way.
+ */
+ static Ptr findByFileContent( const TQString &fileName, int *accuracy=0 );
+
+ struct Format{
+ bool text : 1;
+ enum { NoCompression=0, GZipCompression } compression : 4;
+ unsigned dummy : 27;
+ };
+
+ /**
+ * Returns whether a file has an internal format that is human readable,
+ * or that would be human readable after decompression.
+ * @since 3.2
+ */
+ static Format findFormatByFileContent( const TQString &fileName );
+
+ /**
+ * Get all the mimetypes.
+ *
+ * Useful for showing the list of
+ * available mimetypes.
+ * More memory consuming than the ones above, don't use unless
+ * really necessary.
+ * @return the list of all existing KMimeTypes
+ */
+ static List allMimeTypes();
+
+ /**
+ * Returns the name of the default mimetype.
+ * Always application/octet-stream, but this method exists
+ * for performance purposes.
+ * @return the name of the default mime type, always
+ * "application/octet-stream"
+ */
+ static const TQString & defaultMimeType();
+
+ /**
+ * Returns the default mimetype.
+ * Always application/octet-stream.
+ * This can be used to check the result of mimeType(name).
+ * @return the "application/octet-stream" mimetype pointer.
+ * @since 3.2
+ */
+ static KMimeType::Ptr defaultMimeTypePtr();
+
+ /**
+ * If this mimetype inherits from ("is also") another mimetype,
+ * return the name of the parent.
+ *
+ * For instance a text/x-log is a special kind of text/plain,
+ * so the definition of text/x-log can say "X-TDE-IsAlso=text/plain".
+ * Or an smb-workgroup is a special kind of inode/directory, etc.
+ * This mechanism can also be used to rename mimetypes and preserve compat.
+ *
+ * Note that this notion doesn't map to the servicetype inheritance mechanism,
+ * since an application that handles the specific type doesn't necessarily handle
+ * the base type. The opposite is true though.
+ *
+ * @return the parent mime type, or TQString::null if not set
+ * @since 3.2
+ */
+ TQString parentMimeType() const;
+
+ /**
+ * Do not use name()=="somename" anymore, to check for a given mimetype.
+ * For mimetype inheritance to work, use is("somename") instead.
+ * Warning, do not use inherits(), that's the servicetype inheritance concept!
+ * @since 3.2
+ */
+ bool is( const TQString& mimeTypeName ) const;
+
+ /**
+ * @internal
+ * Determines the mimetype of file based on it's name and returns the
+ * matching pattern if any.
+ */
+ static KMimeType::Ptr diagnoseFileName(const TQString &file, TQString &pattern);
+
+protected:
+ void loadInternal( TQDataStream& );
+ void init( KDesktopFile * );
+
+ /**
+ * Signal a missing mime type.
+ * @param _type the missinf mime type
+ */
+ static void errorMissingMimeType( const TQString& _type );
+
+ /**
+ * This function makes sure that the default mime type exists.
+ */
+ static void buildDefaultType();
+
+ /**
+ * This function makes sure that vital mime types are installed.
+ */
+ static void checkEssentialMimeTypes();
+ /**
+ * true if check for vital mime types has been done.
+ */
+ static bool s_bChecked;
+
+ TQStringList m_lstPatterns;
+
+ static Ptr s_pDefaultType;
+
+protected:
+ friend class KServiceTypeFactory;
+ int patternsAccuracy() const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * Folder mime type. Handles locked folders, for instance.
+ * @short Mimetype for a folder (inode/directory)
+ */
+class TDEIO_EXPORT KFolderType : public KMimeType
+{
+ K_SYCOCATYPE( KST_KFolderType, KMimeType )
+
+public:
+// KFolderType( const TQString & _fullpath, const TQString& _type, const TQString& _icon, const TQString& _comment,
+// const TQStringList& _patterns );
+// KFolderType( const TQString & _fullpath ) : KMimeType( _fullpath ) { }
+ /**
+ * Construct a folder mimetype and take all information from a desktop file.
+ * @param config the desktop configuration file that describes the mime type
+ */
+ KFolderType( KDesktopFile *config) : KMimeType( config ) { }
+ /** \internal */
+ KFolderType( TQDataStream& _str, int offset ) : KMimeType( _str, offset ) { }
+
+ virtual TQString icon( const TQString& _url, bool _is_local ) const;
+ virtual TQString icon( const KURL& _url, bool _is_local ) const;
+ virtual TQString comment( const TQString& _url, bool _is_local ) const;
+ virtual TQString comment( const KURL& _url, bool _is_local ) const;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * Mime type for desktop files.
+ * Handles mount/umount icon, and user-defined properties.
+ * @short Mimetype for a .desktop file
+ */
+class TDEIO_EXPORT KDEDesktopMimeType : public KMimeType
+{
+ K_SYCOCATYPE( KST_KDEDesktopMimeType, KMimeType )
+
+public:
+ enum ServiceType { ST_MOUNT, ST_UNMOUNT, /* ST_PROPERTIES, */ ST_USER_DEFINED };
+
+ /**
+ * Structure representing a service, in the list of services
+ * returned by builtinServices and userDefinedServices
+ */
+ struct Service
+ {
+ Service() { m_display = true; }
+ bool isEmpty() const { return m_strName.isEmpty(); }
+ TQString m_strName;
+ TQString m_strIcon;
+ TQString m_strExec;
+ ServiceType m_type;
+ bool m_display;
+ };
+ // KDEDesktopMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
+ // const TQString& _comment, const TQStringList& _patterns );
+ // KDEDesktopMimeType( const TQString & _fullpath ) : KMimeType( _fullpath ) { }
+ /**
+ * Construct a desktop mimetype and take all information from a desktop file.
+ * @param config the desktop configuration file that describes the mime type
+ */
+ KDEDesktopMimeType( KDesktopFile *config) : KMimeType( config ) { }
+ /** \internal */
+ KDEDesktopMimeType( TQDataStream& _str, int offset ) : KMimeType( _str, offset ) { }
+
+ virtual TQString icon( const TQString& _url, bool _is_local ) const;
+ virtual TQString icon( const KURL& _url, bool _is_local ) const;
+ virtual TQPixmap pixmap( const KURL& _url, KIcon::Group _group, int _force_size = 0,
+ int _state = 0, TQString * _path = 0L ) const;
+ virtual TQString comment( const TQString& _url, bool _is_local ) const;
+ virtual TQString comment( const KURL& _url, bool _is_local ) const;
+
+ /**
+ * Returns a list of services for the given .desktop file that are handled
+ * by kio itself. Namely mount/unmount for FSDevice files.
+ * @return the list of services
+ */
+ static TQValueList<Service> builtinServices( const KURL& _url );
+ /**
+ * Returns a list of services defined by the user as possible actions
+ * on the given .desktop file. May include empty actions which represent where
+ * visual separators should appear in user-visible representations of those actions,
+ * such as separators in a menu.
+ * @param path the path to the desktop file describing the services
+ * @param bLocalFiles true if those services are to be applied to local files only
+ * (if false, services that don't have %u or %U in the Exec line won't be taken into account).
+ * @return the list of user deviced actions
+ */
+ static TQValueList<Service> userDefinedServices( const TQString& path, bool bLocalFiles );
+
+ /**
+ * Overload of userDefinedServices for speed purposes: it takes a TDEConfig* so that
+ * the caller can check things in the file without having it parsed twice.
+ * @since 3.4
+ */
+ static TQValueList<Service> userDefinedServices( const TQString& path, TDEConfig& config, bool bLocalFiles );
+
+ /**
+ * Overload of userDefinedServices but also allows you to pass a list of urls for this file.
+ * This allows for the menu to be changed depending on the exact files via
+ * the X-TDE-GetActionMenu extension.
+ * @since 3.5
+ */
+ static TQValueList<Service> userDefinedServices( const TQString& path, TDEConfig& config, bool bLocalFiles, const KURL::List & file_list);
+
+ /**
+ * @param path is the path of the desktop entry.
+ * @param service the service to execute
+ * @deprecated, see the other executeService
+ */
+ static void executeService( const TQString& path, KDEDesktopMimeType::Service& service ) KDE_DEPRECATED;
+
+ /**
+ * Execute @p service on the list of @p urls.
+ * @param urls the list of urls
+ * @param service the service to execute
+ */
+ static void executeService( const KURL::List& urls, KDEDesktopMimeType::Service& service );
+
+ /**
+ * Invokes the default action for the desktop entry. If the desktop
+ * entry is not local, then only false is returned. Otherwise we
+ * would create a security problem. Only types Link and Mimetype
+ * could be followed.
+ *
+ * @param _url the url to run
+ * @param _is_local true if the URL is local, false otherwise
+ * @return true on success and false on failure.
+ * @see KRun::runURL
+ */
+ static pid_t run( const KURL& _url, bool _is_local );
+
+protected:
+ virtual TQPixmap pixmap( KIcon::Group group, int force_size = 0, int state = 0,
+ TQString * path = 0L ) const
+ { return KMimeType::pixmap( group, force_size, state, path ); }
+
+ static pid_t runFSDevice( const KURL& _url, const KSimpleConfig &cfg );
+ static pid_t runApplication( const KURL& _url, const TQString & _serviceFile );
+ static pid_t runLink( const KURL& _url, const KSimpleConfig &cfg );
+ static pid_t runMimeType( const KURL& _url, const KSimpleConfig &cfg );
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * The mime type for executable files.
+ * @short MimeType for any executable, like /bin/ls
+ */
+class TDEIO_EXPORT KExecMimeType : public KMimeType
+{
+ K_SYCOCATYPE( KST_KExecMimeType, KMimeType )
+
+public:
+ // KExecMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
+ // const TQString& _comment, const TQStringList& _patterns );
+ // KExecMimeType( const TQString & _fullpath ) : KMimeType( _fullpath ) { }
+ /**
+ * Construct a executable mimetype and take all information from a desktop file.
+ * @param config the desktop configuration file that describes the mime type
+ */
+ KExecMimeType( KDesktopFile *config) : KMimeType( config ) { }
+ /** \internal */
+ KExecMimeType( TQDataStream& _str, int offset ) : KMimeType( _str, offset ) { }
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+#endif
diff --git a/tdeio/tdeio/kmimetypechooser.cpp b/tdeio/tdeio/kmimetypechooser.cpp
new file mode 100644
index 000000000..51db75fe1
--- /dev/null
+++ b/tdeio/tdeio/kmimetypechooser.cpp
@@ -0,0 +1,298 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 - 2004 Anders Lund <anders@alweb.dk>
+
+ 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 "kmimetypechooser.h"
+
+#include <tdeconfig.h>
+#include <kiconloader.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <kprocess.h>
+#include <krun.h>
+#include <tdesycoca.h>
+
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <tqpushbutton.h>
+#include <tqwhatsthis.h>
+
+//BEGIN KMimeTypeChooserPrivate
+class KMimeTypeChooserPrivate
+{
+ public:
+ KListView *lvMimeTypes;
+ TQPushButton *btnEditMimeType;
+
+ TQString defaultgroup;
+ TQStringList groups;
+ int visuals;
+};
+//END
+
+//BEGIN KMimeTypeChooser
+KMimeTypeChooser::KMimeTypeChooser( const TQString &text,
+ const TQStringList &selMimeTypes,
+ const TQString &defaultGroup,
+ const TQStringList &groupsToShow,
+ int visuals,
+ TQWidget *parent,
+ const char *name )
+ : TQVBox( parent, name )
+{
+ d = new KMimeTypeChooserPrivate();
+ d->lvMimeTypes = 0;
+ d->btnEditMimeType = 0;
+ d->defaultgroup = defaultGroup;
+ d->groups = groupsToShow;
+ d->visuals = visuals;
+
+ setSpacing( KDialogBase::spacingHint() );
+
+ if ( !text.isEmpty() )
+ {
+ new TQLabel( text, this );
+ }
+
+ d->lvMimeTypes = new KListView( this );
+
+ d->lvMimeTypes->addColumn( i18n("Mime Type") );
+// d->lvMimeTypes->setColumnWidthMode( 0, TQListView::Manual );
+
+ if ( visuals & Comments )
+ {
+ d->lvMimeTypes->addColumn( i18n("Comment") );
+ d->lvMimeTypes->setColumnWidthMode( 1, TQListView::Manual );
+ }
+ if ( visuals & Patterns )
+ d->lvMimeTypes->addColumn( i18n("Patterns") );
+
+ d->lvMimeTypes->setRootIsDecorated( true );
+
+ loadMimeTypes( selMimeTypes );
+
+ if (visuals & KMimeTypeChooser::EditButton)
+ {
+ TQHBox *btns = new TQHBox( this );
+ ((TQBoxLayout*)btns->layout())->addStretch(1);
+ d->btnEditMimeType = new TQPushButton( i18n("&Edit..."), btns );
+
+ connect( d->btnEditMimeType, TQT_SIGNAL(clicked()), this, TQT_SLOT(editMimeType()) );
+ d->btnEditMimeType->setEnabled( false );
+ connect( d->lvMimeTypes, TQT_SIGNAL( doubleClicked ( TQListViewItem * )),
+ this, TQT_SLOT( editMimeType()));
+ connect( d->lvMimeTypes, TQT_SIGNAL(currentChanged(TQListViewItem*)),
+ this, TQT_SLOT(slotCurrentChanged(TQListViewItem*)) );
+
+ TQWhatsThis::add( d->btnEditMimeType, i18n(
+ "Click this button to display the familiar TDE mime type editor.") );
+ }
+}
+
+KMimeTypeChooser::~KMimeTypeChooser()
+{
+ delete d;
+}
+
+void KMimeTypeChooser::loadMimeTypes( const TQStringList &_selectedMimeTypes )
+{
+ TQStringList selMimeTypes;
+
+ if ( !_selectedMimeTypes.isEmpty() )
+ selMimeTypes = _selectedMimeTypes;
+ else
+ selMimeTypes = mimeTypes();
+
+ d->lvMimeTypes->clear();
+
+ TQMap<TQString,TQListViewItem*> groups;
+ // thanks to tdebase/kcontrol/filetypes/filetypesview
+ KMimeType::List mimetypes = KMimeType::allMimeTypes();
+ TQValueListIterator<KMimeType::Ptr> it(mimetypes.begin());
+
+ TQListViewItem *groupItem;
+ bool agroupisopen = false;
+ TQListViewItem *idefault = 0; //open this, if all other fails
+ TQListViewItem *firstChecked = 0; // make this one visible after the loop
+
+ for (; it != mimetypes.end(); ++it)
+ {
+ TQString mimetype = (*it)->name();
+ int index = mimetype.find("/");
+ TQString maj = mimetype.left(index);
+
+ if ( d->groups.count() && !d->groups.contains( maj ) )
+ continue;
+
+ TQString min = mimetype.right(mimetype.length() - (index+1));
+
+ TQMapIterator<TQString,TQListViewItem*> mit = groups.find( maj );
+ if ( mit == groups.end() )
+ {
+ groupItem = new TQListViewItem( d->lvMimeTypes, maj );
+ groups.insert( maj, groupItem );
+ if ( maj == d->defaultgroup )
+ idefault = groupItem;
+ }
+ else
+ groupItem = mit.data();
+
+ TQCheckListItem *item = new TQCheckListItem( groupItem, min, TQCheckListItem::CheckBox );
+ item->setPixmap( 0, SmallIcon( (*it)->icon(TQString::null,false) ) );
+
+ int cl = 1;
+
+ if ( d->visuals & Comments )
+ {
+ item->setText( cl, (*it)->comment(TQString::null, false) );
+ cl++;
+ }
+
+ if ( d->visuals & Patterns )
+ item->setText( cl, (*it)->patterns().join("; ") );
+
+ if ( selMimeTypes.contains(mimetype) )
+ {
+ item->setOn( true );
+ groupItem->setOpen( true );
+ agroupisopen = true;
+ if ( !firstChecked )
+ firstChecked = item;
+ }
+ }
+
+ if ( firstChecked )
+ d->lvMimeTypes->ensureItemVisible( firstChecked );
+
+ if ( !agroupisopen && idefault )
+ {
+ idefault->setOpen( true );
+ d->lvMimeTypes->ensureItemVisible( idefault );
+ }
+}
+
+void KMimeTypeChooser::editMimeType()
+{
+ if ( !(d->lvMimeTypes->currentItem() && (d->lvMimeTypes->currentItem())->parent()) )
+ return;
+ TQString mt = (d->lvMimeTypes->currentItem()->parent())->text( 0 ) + "/" + (d->lvMimeTypes->currentItem())->text( 0 );
+ // thanks to libkonq/konq_operations.cc
+ connect( KSycoca::self(), TQT_SIGNAL(databaseChanged()),
+ this, TQT_SLOT(slotSycocaDatabaseChanged()) );
+ TQString keditfiletype = TQString::fromLatin1("keditfiletype");
+ KRun::runCommand( keditfiletype
+ + " --parent " + TQString::number( (ulong)topLevelWidget()->winId())
+ + " " + TDEProcess::quote(mt),
+ keditfiletype, keditfiletype /*unused*/);
+}
+
+void KMimeTypeChooser::slotCurrentChanged(TQListViewItem* i)
+{
+ if ( d->btnEditMimeType )
+ d->btnEditMimeType->setEnabled( i->parent() );
+}
+
+void KMimeTypeChooser::slotSycocaDatabaseChanged()
+{
+ if ( KSycoca::self()->isChanged("mime") )
+ loadMimeTypes();
+}
+
+TQStringList KMimeTypeChooser::mimeTypes() const
+{
+ TQStringList l;
+ TQListViewItemIterator it( d->lvMimeTypes );
+ for (; it.current(); ++it)
+ {
+ if ( it.current()->parent() && ((TQCheckListItem*)it.current())->isOn() )
+ l << it.current()->parent()->text(0) + "/" + it.current()->text(0); // FIXME uncecked, should be Ok unless someone changes mimetypes during this!
+ }
+ return l;
+}
+
+TQStringList KMimeTypeChooser::patterns() const
+{
+ TQStringList l;
+ KMimeType::Ptr p;
+ TQString defMT = KMimeType::defaultMimeType();
+ TQListViewItemIterator it( d->lvMimeTypes );
+ for (; it.current(); ++it)
+ {
+ if ( it.current()->parent() && ((TQCheckListItem*)it.current())->isOn() )
+ {
+ p = KMimeType::mimeType( it.current()->parent()->text(0) + "/" + it.current()->text(0) );
+ if ( p->name() != defMT )
+ l += p->patterns();
+ }
+ }
+ return l;
+}
+//END
+
+//BEGIN KMimeTypeChooserDialog
+KMimeTypeChooserDialog::KMimeTypeChooserDialog(
+ const TQString &caption,
+ const TQString& text,
+ const TQStringList &selMimeTypes,
+ const TQString &defaultGroup,
+ const TQStringList &groupsToShow,
+ int visuals,
+ TQWidget *parent, const char *name )
+ : KDialogBase(parent, name, true, caption, Cancel|Ok, Ok)
+{
+ m_chooser = new KMimeTypeChooser( text, selMimeTypes,
+ defaultGroup, groupsToShow, visuals,
+ this, "chooser" );
+ setMainWidget(m_chooser);
+
+ TDEConfigGroup group( TDEGlobal::config(), "KMimeTypeChooserDialog");
+ TQSize defaultSize( 400, 300 );
+ resize( group.readSizeEntry("size", &defaultSize) );
+}
+
+KMimeTypeChooserDialog::KMimeTypeChooserDialog(
+ const TQString &caption,
+ const TQString& text,
+ const TQStringList &selMimeTypes,
+ const TQString &defaultGroup,
+ TQWidget *parent, const char *name )
+ : KDialogBase(parent, name, true, caption, Cancel|Ok, Ok)
+{
+ m_chooser = new KMimeTypeChooser( text, selMimeTypes,
+ defaultGroup, TQStringList(),
+ KMimeTypeChooser::Comments|KMimeTypeChooser::Patterns|KMimeTypeChooser::EditButton,
+ this, "chooser" );
+ setMainWidget(m_chooser);
+
+ TDEConfigGroup group( TDEGlobal::config(), "KMimeTypeChooserDialog");
+ TQSize defaultSize( 400, 300 );
+ resize( group.readSizeEntry("size", &defaultSize) );
+}
+
+
+KMimeTypeChooserDialog::~KMimeTypeChooserDialog()
+{
+ TDEConfigGroup group( TDEGlobal::config(), "KMimeTypeChooserDialog");
+ group.writeEntry("size", size());
+}
+
+//END KMimeTypeChooserDialog
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+#include "kmimetypechooser.moc"
diff --git a/tdeio/tdeio/kmimetypechooser.h b/tdeio/tdeio/kmimetypechooser.h
new file mode 100644
index 000000000..16ec052f5
--- /dev/null
+++ b/tdeio/tdeio/kmimetypechooser.h
@@ -0,0 +1,180 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 - 2004 Anders Lund <anders@alweb.dk>
+
+ 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 _KMIMETYPE_CHOOSER_H_
+#define _KMIMETYPE_CHOOSER_H_
+
+#include <tqvbox.h>
+#include <kdialogbase.h>
+
+
+/**
+ * This widget provides a checkable list of all available mimetypes,
+ * and a list of selected ones, as well as a corresponding list of file
+ * extensions, an optional text and an optional edit button (not working yet).
+ * Mime types is presented in a list view, with name, comment and patterns columns.
+ *
+ * @author Anders Lund (anders at alweb dk), jan 23, 2002
+ */
+class TDEIO_EXPORT KMimeTypeChooser : public TQVBox
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Buttons and data for display.
+ */
+ enum Visuals {
+ Comments=1, ///< Show the Mimetypes Comment field in a column ("HTML Document").
+ Patterns=2, ///< Show the Mimetypes Patterns field in a column ("*.html;*.htm").
+ EditButton=4 ///< Show the "Edit" button, allowing to edit the selected type.
+ };
+ /**
+ * Create a new KMimeTypeChooser.
+ *
+ * @param text A Text to display above the list
+ * @param selectedMimeTypes A list of mimetype names, theese will be checked
+ * in the list if they exist.
+ * @param visuals A OR'd Visuals enum to decide which data and buttons to display.
+ * @param defaultGroup The group to open when no groups are selected (like
+ * "text"). If not provided, no group is opened. If @p groupsToShow
+ * is provided and defaultGroup is not a member of that, it is ignored.
+ * @param groupsToShow a list of mimetype groups to show. If empty, all
+ * groups are shown.
+ * @param parent The parent widget to use
+ * @param name The internal name of this object
+ */
+ KMimeTypeChooser( const TQString& text=TQString::null,
+ const TQStringList &selectedMimeTypes=0,
+ const TQString &defaultGroup=TQString::null,
+ const TQStringList &groupsToShow=TQStringList(),
+ int visuals=Comments|Patterns|EditButton,
+ TQWidget *parent=0, const char *name=0 );
+ ~KMimeTypeChooser();
+
+ /**
+ * @return a list of all selected selected mimetypes represented by their name.
+ */
+ TQStringList mimeTypes() const;
+ /**
+ * @return a list of the fileame patterns associated with all selected mimetypes.
+ */
+ TQStringList patterns() const;
+
+ public slots:
+ /**
+ * @short edit the current mimetype
+ * Uses KRun to start the KDE mimetype editor for editing the currently
+ * selected mimetype.
+ */
+ void editMimeType();
+
+ private slots:
+ /**
+ * @internal disables the "edit" button for groups
+ */
+ void slotCurrentChanged(TQListViewItem* i);
+
+ /**
+ * @internal called when the sycoca database has changed after
+ * the user edited a mimetype
+ */
+ void slotSycocaDatabaseChanged();
+
+ private:
+ /**
+ * @internal Load mime types into the list view
+ * If @p selected is empty, selectedMimeTypesStringList() is called
+ * to fill it in.
+ */
+ void loadMimeTypes( const TQStringList &selected=TQStringList() );
+
+ class KMimeTypeChooserPrivate *d;
+};
+
+/**
+ * @short A Dialog to choose some mimetypes.
+ * Provides a checkable tree list of mimetypes, with icons and optinally
+ * comments and patterns, and an (optional) button to display the KDE mimetype
+ * editor.
+ *
+ * Here is an example, using the dialog to set the text of two lineedits:
+ *
+ * @code
+ * TQString text = i18n("Select the MimeTypes you want for this file type.");
+ * TQStringList list = TQStringList::split( TQRegExp("\\s*;\\s*"), leMimetypes->text() );
+ * KMimeTypeChooserDialog *d = new KMimeTypeChooserDialog( this, 0,
+ * i18n("Select Mime Types"), text, list, "text" );
+ * if ( d->exec() == KDialogBase::Accepted ) {
+ * leWildcards->setText( d->chooser()->patterns().join(";") );
+ * leMimetypes->setText( d->chooser()->mimeTypes().join(";") );
+ * }
+ * @endcode
+ *
+ * @author Anders Lund (anders at alweb dk) dec 19, 2001
+ */
+class TDEIO_EXPORT KMimeTypeChooserDialog : public KDialogBase
+{
+ public:
+ /**
+ * Create a KMimeTypeChooser dialog.
+ *
+ * @param caption The title of the dialog
+ * @param text A Text to display above the list
+ * @param selectedMimeTypes A list of mimetype names, theese will be
+ * checked in the list if they exist.
+ * patterns will be added to the list view.
+ * @param visuals A OR'd KMimetypeChooser::Visuals enum to decide which data
+ * and buttons to display.
+ * @param defaultGroup The group to open when no groups are selected (like
+ * "text"). If not provided, no group is opened. If @p groupsToShow
+ * is provided and defaultGroup is not a member of that, it is ignored.
+ * @param groupsToShow a list of mimetype groups to show. If empty, all
+ * groups are shown.
+ * @param parent The parent widget to use
+ * @param name The internal name of this object
+ */
+ KMimeTypeChooserDialog( const TQString &caption=TQString::null,
+ const TQString& text=TQString::null,
+ const TQStringList &selectedMimeTypes=TQStringList(),
+ const TQString &defaultGroup=TQString::null,
+ const TQStringList &groupsToShow=TQStringList(),
+ int visuals=KMimeTypeChooser::Comments|KMimeTypeChooser::Patterns|KMimeTypeChooser::EditButton,
+ TQWidget *parent=0, const char *name=0 );
+
+ /**
+ * @overload
+ */
+ KMimeTypeChooserDialog( const TQString &caption,
+ const TQString& text,
+ const TQStringList &selectedMimeTypes,
+ const TQString &defaultGroup,
+ TQWidget *parent=0, const char *name=0 );
+
+ ~KMimeTypeChooserDialog();
+
+ /**
+ * @return a pointer to the KMimeTypeChooser widget
+ */
+ KMimeTypeChooser* chooser() { return m_chooser; }
+
+ private:
+ KMimeTypeChooser *m_chooser;
+};
+#endif // _KMIMETYPE_CHOOSER_H_
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/tdeio/tdeio/kmimetyperesolver.h b/tdeio/tdeio/kmimetyperesolver.h
new file mode 100644
index 000000000..c8828a0da
--- /dev/null
+++ b/tdeio/tdeio/kmimetyperesolver.h
@@ -0,0 +1,255 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2000 Rik Hemsley <rik@kde.org>
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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 __kmimetyperesolver_h
+#define __kmimetyperesolver_h
+
+#include <tqscrollview.h>
+#include <tqptrlist.h>
+#include <tqtimer.h>
+#include <kdebug.h>
+
+/**
+ * @internal
+ * A baseclass for KMimeTypeResolver, with the interface,
+ * KMimeTypeResolverHelper uses.
+ */
+class TDEIO_EXPORT KMimeTypeResolverBase
+{
+public:
+ virtual void slotViewportAdjusted() = 0;
+ virtual void slotProcessMimeIcons() = 0;
+protected:
+ virtual void virtual_hook( int, void* ) {}
+};
+
+/**
+ * @internal
+ * This class is used by KMimeTypeResolver, because it can't be a QObject
+ * itself. So an object of this class is used to handle signals, slots etc.
+ * and forwards them to the KMimeTypeResolver instance.
+ */
+class TDEIO_EXPORT KMimeTypeResolverHelper : public TQObject
+{
+ Q_OBJECT
+
+public:
+ KMimeTypeResolverHelper( KMimeTypeResolverBase *resolver,
+ TQScrollView *view )
+ : m_resolver( resolver ),
+ m_timer( new TQTimer( this ) )
+ {
+ connect( m_timer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotProcessMimeIcons() ));
+
+ connect( view->horizontalScrollBar(), TQT_SIGNAL( sliderMoved(int) ),
+ TQT_SLOT( slotAdjust() ) );
+ connect( view->verticalScrollBar(), TQT_SIGNAL( sliderMoved(int) ),
+ TQT_SLOT( slotAdjust() ) );
+
+ view->viewport()->installEventFilter( this );
+ }
+
+ void start( int delay, bool singleShot )
+ {
+ m_timer->start( delay, singleShot );
+ }
+
+protected:
+ virtual bool eventFilter( TQObject *o, TQEvent *e )
+ {
+ bool ret = TQObject::eventFilter( o, e );
+
+ if ( e->type() == TQEvent::Resize )
+ m_resolver->slotViewportAdjusted();
+
+ return ret;
+ }
+
+private slots:
+ void slotProcessMimeIcons()
+ {
+ m_resolver->slotProcessMimeIcons();
+ }
+
+ void slotAdjust()
+ {
+ m_resolver->slotViewportAdjusted();
+ }
+
+private:
+ KMimeTypeResolverBase *m_resolver;
+ TQTimer *m_timer;
+};
+
+/**
+ * This class implements the "delayed-mimetype-determination" feature,
+ * for konqueror's directory views (and KFileDialog's :).
+ *
+ * It determines the mimetypes of the icons in the background, but giving
+ * preferrence to the visible icons.
+ *
+ * It is implemented as a template, so that it can work with both QPtrListViewItem
+ * and TQIconViewItem, without requiring hacks such as void * or TQPtrDict lookups.
+ *
+ * Here's what the parent must implement :
+ * @li void mimeTypeDeterminationFinished();
+ * @li TQScrollView * scrollWidget();
+ * @li void determineIcon( IconItem * item ), which should call
+ * @li KFileItem::determineMimeType on the fileItem, and update the icon, etc.
+*/
+template<class IconItem, class Parent>
+class KMimeTypeResolver : public KMimeTypeResolverBase // if only this could be a TQObject....
+{
+public:
+ /**
+ * Creates a new KMimeTypeResolver with the given parent.
+ * @param parent the parent's resolver
+ */
+ KMimeTypeResolver( Parent * parent )
+ : m_parent(parent),
+ m_helper( new KMimeTypeResolverHelper(this, parent->scrollWidget())),
+ m_delayNonVisibleIcons(10)
+ {}
+
+ virtual ~KMimeTypeResolver() {
+ delete m_helper;
+ }
+
+ /**
+ * Start the mimetype-determination. Call this when the listing is completed.
+ * @param delayNonVisibleIcons the delay to use between icons not on screen.
+ * Usually 10, but should be set to 0 when the image preview feature is
+ * activated, because image preview can only start once we know the mimetypes
+ */
+ void start( uint delayNonVisibleIcons = 10 )
+ {
+ m_helper->start( 0, true /* single shot */ );
+ m_delayNonVisibleIcons = delayNonVisibleIcons;
+ }
+
+ /**
+ * The list of items to process. The view is free to
+ * clear it, insert new items into it, remove items, etc.
+ * @return the list of items to process
+ */
+ TQPtrList<IconItem> m_lstPendingMimeIconItems;
+
+ /**
+ * "Connected" to the viewportAdjusted signal of the scrollview
+ */
+ virtual void slotViewportAdjusted();
+
+ /**
+ * "Connected" to the timer
+ */
+ virtual void slotProcessMimeIcons();
+
+private:
+ /**
+ * Find a visible icon and determine its mimetype.
+ * KonqDirPart will call this method repeatedly until it returns 0L
+ * (no more visible icon to process).
+ * @return the file item that was just processed.
+ */
+ IconItem * findVisibleIcon();
+
+ Parent * m_parent;
+ KMimeTypeResolverHelper *m_helper;
+ uint m_delayNonVisibleIcons;
+};
+
+// The main slot
+template<class IconItem, class Parent>
+inline void KMimeTypeResolver<IconItem, Parent>::slotProcessMimeIcons()
+{
+ //kdDebug(1203) << "KMimeTypeResolver::slotProcessMimeIcons() "
+ // << m_lstPendingMimeIconItems.count() << endl;
+ IconItem * item = 0L;
+ int nextDelay = 0;
+
+ if ( m_lstPendingMimeIconItems.count() > 0 )
+ {
+ // We only find mimetypes for icons that are visible. When more
+ // of our viewport is exposed, we'll get a signal and then get
+ // the mimetypes for the newly visible icons. (Rikkus)
+ item = findVisibleIcon();
+ }
+
+ // No more visible items.
+ if (0 == item)
+ {
+ // Do the unvisible ones, then, but with a bigger delay, if so configured
+ if ( m_lstPendingMimeIconItems.count() > 0 )
+ {
+ item = m_lstPendingMimeIconItems.first();
+ nextDelay = m_delayNonVisibleIcons;
+ }
+ else
+ {
+ m_parent->mimeTypeDeterminationFinished();
+ return;
+ }
+ }
+
+ m_parent->determineIcon(item);
+ m_lstPendingMimeIconItems.remove(item);
+ m_helper->start( nextDelay, true /* single shot */ );
+}
+
+template<class IconItem, class Parent>
+inline void KMimeTypeResolver<IconItem, Parent>::slotViewportAdjusted()
+{
+ if (m_lstPendingMimeIconItems.isEmpty()) return;
+ IconItem * item = findVisibleIcon();
+ if (item)
+ {
+ m_parent->determineIcon( item );
+ m_lstPendingMimeIconItems.remove(item);
+ m_helper->start( 0, true /* single shot */ );
+ }
+}
+
+template<class IconItem, class Parent>
+inline IconItem * KMimeTypeResolver<IconItem, Parent>::findVisibleIcon()
+{
+ // Find an icon that's visible and whose mimetype we don't know.
+
+ TQPtrListIterator<IconItem> it(m_lstPendingMimeIconItems);
+ if ( m_lstPendingMimeIconItems.count()<20) // for few items, it's faster to not bother
+ return m_lstPendingMimeIconItems.first();
+
+ TQScrollView * view = m_parent->scrollWidget();
+ TQRect visibleContentsRect
+ (
+ view->viewportToContents(TQPoint(0, 0)),
+ view->viewportToContents
+ (
+ TQPoint(view->visibleWidth(), view->visibleHeight())
+ )
+ );
+
+ for (; it.current(); ++it)
+ if (visibleContentsRect.intersects(it.current()->rect()))
+ return it.current();
+
+ return 0L;
+}
+
+#endif
diff --git a/tdeio/tdeio/knfsshare.cpp b/tdeio/tdeio/knfsshare.cpp
new file mode 100644
index 000000000..b4a3d903a
--- /dev/null
+++ b/tdeio/tdeio/knfsshare.cpp
@@ -0,0 +1,219 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
+
+ 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 <tqdict.h>
+#include <tqfile.h>
+#include <tqtextstream.h>
+
+#include <kdirwatch.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <tdeconfig.h>
+
+#include "knfsshare.h"
+
+class KNFSSharePrivate
+{
+public:
+ KNFSSharePrivate();
+
+ bool readExportsFile();
+ bool findExportsFile();
+
+ TQDict<bool> sharedPaths;
+ TQString exportsFile;
+};
+
+KNFSSharePrivate::KNFSSharePrivate()
+{
+ if (findExportsFile())
+ readExportsFile();
+}
+
+/**
+ * Try to find the nfs config file path
+ * First tries the tdeconfig, then checks
+ * several well-known paths
+ * @return wether an 'exports' file was found.
+ **/
+bool KNFSSharePrivate::findExportsFile() {
+ TDEConfig config("knfsshare");
+ config.setGroup("General");
+ exportsFile = config.readPathEntry("exportsFile");
+
+ if ( TQFile::exists(exportsFile) )
+ return true;
+
+ if ( TQFile::exists("/etc/exports") )
+ exportsFile = "/etc/exports";
+ else {
+ kdDebug(7000) << "KNFSShare: Could not found exports file!" << endl;
+ return false;
+ }
+
+ config.writeEntry("exportsFile",exportsFile);
+ return true;
+}
+
+/**
+ * Reads all paths from the exports file
+ * and fills the sharedPaths dict with the values
+ */
+bool KNFSSharePrivate::readExportsFile() {
+ TQFile f(exportsFile);
+
+ kdDebug(7000) << "KNFSShare::readExportsFile " << exportsFile << endl;
+
+ if (!f.open(IO_ReadOnly)) {
+ kdError() << "KNFSShare: Could not open " << exportsFile << endl;
+ return false;
+ }
+
+
+ sharedPaths.clear();
+
+ TQTextStream s( &f );
+
+ bool continuedLine = false; // is true if the line before ended with a backslash
+ TQString completeLine;
+
+ while ( !s.eof() )
+ {
+ TQString currentLine = s.readLine().stripWhiteSpace();
+
+ if (continuedLine) {
+ completeLine += currentLine;
+ continuedLine = false;
+ }
+ else
+ completeLine = currentLine;
+
+ // is the line continued in the next line ?
+ if ( completeLine[completeLine.length()-1] == '\\' )
+ {
+ continuedLine = true;
+ // remove the ending backslash
+ completeLine.truncate( completeLine.length()-1 );
+ continue;
+ }
+
+ // comments or empty lines
+ if (completeLine.isEmpty() ||
+ '#' == completeLine[0])
+ {
+ continue;
+ }
+
+ TQString path;
+
+ // Handle quotation marks
+ if ( completeLine[0] == '"' ) {
+ int i = completeLine.find('"',1);
+ if (i == -1) {
+ kdError() << "KNFSShare: Parse error: Missing quotation mark: " << completeLine << endl;
+ continue;
+ }
+ path = completeLine.mid(1,i-1);
+
+ } else { // no quotation marks
+ int i = completeLine.find(' ');
+ if (i == -1)
+ i = completeLine.find('\t');
+
+ if (i == -1)
+ path = completeLine;
+ else
+ path = completeLine.left(i);
+
+ }
+
+ kdDebug(7000) << "KNFSShare: Found path: " << path << endl;
+
+ // normalize path
+ if ( path[path.length()-1] != '/' )
+ path += '/';
+
+ bool b = true;
+ sharedPaths.insert(path,&b);
+ }
+
+ f.close();
+
+ return true;
+
+}
+
+KNFSShare::KNFSShare() {
+ d = new KNFSSharePrivate();
+ if (TQFile::exists(d->exportsFile)) {
+ KDirWatch::self()->addFile(d->exportsFile);
+ connect(KDirWatch::self(), TQT_SIGNAL(dirty (const TQString&)),this,
+ TQT_SLOT(slotFileChange(const TQString&)));
+ }
+}
+
+KNFSShare::~KNFSShare() {
+ if (TQFile::exists(d->exportsFile)) {
+ KDirWatch::self()->removeFile(d->exportsFile);
+ }
+ delete d;
+}
+
+
+bool KNFSShare::isDirectoryShared( const TQString & path ) const {
+ TQString fixedPath = path;
+ if ( path[path.length()-1] != '/' )
+ fixedPath += '/';
+
+ return d->sharedPaths.find(fixedPath) != 0;
+}
+
+TQStringList KNFSShare::sharedDirectories() const {
+ TQStringList result;
+ TQDictIterator<bool> it(d->sharedPaths);
+ for( ; it.current(); ++it )
+ result << it.currentKey();
+
+ return result;
+}
+
+TQString KNFSShare::exportsPath() const {
+ return d->exportsFile;
+}
+
+
+
+void KNFSShare::slotFileChange( const TQString & path ) {
+ if (path == d->exportsFile)
+ d->readExportsFile();
+
+ emit changed();
+}
+
+KNFSShare* KNFSShare::_instance = 0L;
+static KStaticDeleter<KNFSShare> ksdNFSShare;
+
+KNFSShare* KNFSShare::instance() {
+ if (! _instance )
+ _instance = ksdNFSShare.setObject(_instance, new KNFSShare());
+
+ return _instance;
+}
+
+#include "knfsshare.moc"
+
diff --git a/tdeio/tdeio/knfsshare.h b/tdeio/tdeio/knfsshare.h
new file mode 100644
index 000000000..64cd28dcf
--- /dev/null
+++ b/tdeio/tdeio/knfsshare.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
+
+ 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 knfsshare_h
+#define knfsshare_h
+
+#include <tqobject.h>
+
+#include <tdelibs_export.h>
+
+class KNFSSharePrivate;
+
+/**
+ * Similar functionality like KFileShare,
+ * but works only for NFS and do not need
+ * any suid script.
+ * It parses the /etc/exports file to get its information.
+ * Singleton class, call instance() to get an instance.
+ */
+class TDEIO_EXPORT KNFSShare : public TQObject
+{
+Q_OBJECT
+public:
+ /**
+ * Returns the one and only instance of KNFSShare
+ */
+ static KNFSShare* instance();
+
+ /**
+ * Wether or not the given path is shared by NFS.
+ * @param path the path to check if it is shared by NFS.
+ * @return wether the given path is shared by NFS.
+ */
+ bool isDirectoryShared( const TQString & path ) const;
+
+ /**
+ * Returns a list of all directories shared by NFS.
+ * The resulting list is not sorted.
+ * @return a list of all directories shared by NFS.
+ */
+ TQStringList sharedDirectories() const;
+
+ /**
+ * KNFSShare destructor.
+ * Do not call!
+ * The instance is destroyed automatically!
+ */
+ virtual ~KNFSShare();
+
+ /**
+ * Returns the path to the used exports file,
+ * or null if no exports file was found
+ */
+ TQString exportsPath() const;
+
+signals:
+ /**
+ * Emitted when the /etc/exports file has changed
+ */
+ void changed();
+
+private:
+ KNFSShare();
+ static KNFSShare* _instance;
+ KNFSSharePrivate* d;
+
+private slots:
+ void slotFileChange(const TQString&);
+};
+
+#endif
diff --git a/tdeio/tdeio/kprotocolinfo.cpp b/tdeio/tdeio/kprotocolinfo.cpp
new file mode 100644
index 000000000..9523b70cb
--- /dev/null
+++ b/tdeio/tdeio/kprotocolinfo.cpp
@@ -0,0 +1,257 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2003 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 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.
+*/
+
+#ifdef MAKE_TDECORE_LIB //needed for proper linkage (win32)
+#undef TDEIO_EXPORT
+#define TDEIO_EXPORT KDE_EXPORT
+#endif
+
+#include "kprotocolinfo.h"
+#include "kprotocolinfofactory.h"
+#include "kprotocolmanager.h"
+
+// Most of this class is implemented in tdecore/kprotocolinfo_tdecore.cpp
+// This file only contains a few static class-functions that depend on
+// KProtocolManager
+
+KProtocolInfo* KProtocolInfo::findProtocol(const KURL &url)
+{
+#ifdef MAKE_TDECORE_LIB
+ return 0;
+#else
+ TQString protocol = url.protocol();
+
+ if ( !KProtocolInfo::proxiedBy( protocol ).isEmpty() )
+ {
+ TQString dummy;
+ protocol = KProtocolManager::slaveProtocol(url, dummy);
+ }
+
+ return KProtocolInfoFactory::self()->findProtocol(protocol);
+#endif
+}
+
+
+KProtocolInfo::Type KProtocolInfo::inputType( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return T_NONE;
+
+ return prot->m_inputType;
+}
+
+KProtocolInfo::Type KProtocolInfo::outputType( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return T_NONE;
+
+ return prot->m_outputType;
+}
+
+
+bool KProtocolInfo::isSourceProtocol( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_isSourceProtocol;
+}
+
+bool KProtocolInfo::isFilterProtocol( const KURL &url )
+{
+ return isFilterProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isFilterProtocol( const TQString &protocol )
+{
+ // We call the findProtocol (const TQString&) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ if ( !prot )
+ return false;
+
+ return !prot->m_isSourceProtocol;
+}
+
+bool KProtocolInfo::isHelperProtocol( const KURL &url )
+{
+ return isHelperProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isHelperProtocol( const TQString &protocol )
+{
+ // We call the findProtocol (const TQString&) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ if ( !prot )
+ return false;
+
+ return prot->m_isHelperProtocol;
+}
+
+bool KProtocolInfo::isKnownProtocol( const KURL &url )
+{
+ return isKnownProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isKnownProtocol( const TQString &protocol )
+{
+ // We call the findProtocol (const TQString&) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ return ( prot != 0);
+}
+
+bool KProtocolInfo::supportsListing( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsListing;
+}
+
+TQStringList KProtocolInfo::listing( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return TQStringList();
+
+ return prot->m_listing;
+}
+
+bool KProtocolInfo::supportsReading( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsReading;
+}
+
+bool KProtocolInfo::supportsWriting( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsWriting;
+}
+
+bool KProtocolInfo::supportsMakeDir( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsMakeDir;
+}
+
+bool KProtocolInfo::supportsDeleting( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsDeleting;
+}
+
+bool KProtocolInfo::supportsLinking( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsLinking;
+}
+
+bool KProtocolInfo::supportsMoving( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_supportsMoving;
+}
+
+bool KProtocolInfo::canCopyFromFile( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_canCopyFromFile;
+}
+
+
+bool KProtocolInfo::canCopyToFile( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->m_canCopyToFile;
+}
+
+bool KProtocolInfo::canRenameFromFile( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->canRenameFromFile();
+}
+
+
+bool KProtocolInfo::canRenameToFile( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->canRenameToFile();
+}
+
+bool KProtocolInfo::canDeleteRecursive( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return false;
+
+ return prot->canDeleteRecursive();
+}
+
+KProtocolInfo::FileNameUsedForCopying KProtocolInfo::fileNameUsedForCopying( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return FromURL;
+
+ return prot->fileNameUsedForCopying();
+}
+
+TQString KProtocolInfo::defaultMimetype( const KURL &url )
+{
+ KProtocolInfo::Ptr prot = findProtocol(url);
+ if ( !prot )
+ return TQString::null;
+
+ return prot->m_defaultMimetype;
+}
+
diff --git a/tdeio/tdeio/kprotocolinfo.h b/tdeio/tdeio/kprotocolinfo.h
new file mode 100644
index 000000000..65ed8c7cb
--- /dev/null
+++ b/tdeio/tdeio/kprotocolinfo.h
@@ -0,0 +1,688 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000-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 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 __kprotocolinfo_h__
+#define __kprotocolinfo_h__
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdatastream.h>
+
+#include <kurl.h>
+#include <tdesycocaentry.h>
+#include <tdesycocatype.h>
+
+/**
+ * Information about I/O (Internet, etc.) protocols supported by KDE.
+
+ * This class is useful if you want to know which protocols
+ * KDE supports. In addition you can find out lots of information
+ * about a certain protocol. A KProtocolInfo instance represents a
+ * single protocol. Most of the functionality is provided by the static
+ * methods that scan the *.protocol files of all installed tdeioslaves to get
+ * this information.
+ *
+ * *.protocol files are installed in the "services" resource.
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class TDEIO_EXPORT KProtocolInfo : public KSycocaEntry
+{
+ friend class KProtocolInfoFactory;
+ K_SYCOCATYPE( KST_KProtocolInfo, KSycocaEntry )
+
+public:
+ typedef KSharedPtr<KProtocolInfo> Ptr;
+
+public:
+ /**
+ * Read a protocol description file
+ * @param path the path of the description file
+ */
+ KProtocolInfo( const TQString & path); // KDE4: make private and add friend class KProtocolInfoBuildFactory
+ // Then we can get rid of the d pointer
+
+ /**
+ * Returns whether the protocol description file is valid.
+ * @return true if valid, false otherwise
+ */
+ virtual bool isValid() const { return !m_name.isEmpty(); }
+
+ /**
+ * Returns the name of the protocol.
+ *
+ * This corresponds to the "protocol=" field in the protocol description file.
+ *
+ * @return the name of the protocol
+ * @see KURL::protocol()
+ */
+ virtual TQString name() const { return m_name; }
+
+ //
+ // Static functions:
+ //
+
+ /**
+ * Returns list of all known protocols.
+ * @return a list of all known protocols
+ */
+ static TQStringList protocols();
+
+ /**
+ * Returns whether a protocol is installed that is able to handle @p url.
+ *
+ * @param url the url to check
+ * @return true if the protocol is known
+ * @see name()
+ */
+ static bool isKnownProtocol( const KURL &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isKnownProtocol( const TQString& protocol )
+#ifdef KPROTOCOLINFO_TDECORE
+ KDE_WEAK_SYMBOL
+#endif
+ ;
+
+ /**
+ * Returns the library / executable to open for the protocol @p protocol
+ * Example : "kio_ftp", meaning either the executable "kio_ftp" or
+ * the library "kio_ftp.la" (recommended), whichever is available.
+ *
+ * This corresponds to the "exec=" field in the protocol description file.
+ * @param protocol the protocol to check
+ * @return the executable of library to open, or TQString::null for
+ * unsupported protocols
+ * @see KURL::protocol()
+ */
+ static TQString exec( const TQString& protocol );
+
+ /**
+ * Describes the type of a protocol.
+ */
+ enum Type { T_STREAM, ///< protocol returns a stream
+ T_FILESYSTEM, ///<protocol describes location in a file system
+ T_NONE, ///< no information about the tyope available
+ T_ERROR ///< used to signal an error
+ };
+
+ /**
+ * Returns whether the protocol should be treated as a filesystem
+ * or as a stream when reading from it.
+ *
+ * This corresponds to the "input=" field in the protocol description file.
+ * Valid values for this field are "filesystem", "stream" or "none" (default).
+ *
+ * @param url the url to check
+ * @return the input type of the given @p url
+ */
+ static Type inputType( const KURL &url );
+
+ /**
+ * Returns whether the protocol should be treated as a filesystem
+ * or as a stream when writing to it.
+ *
+ * This corresponds to the "output=" field in the protocol description file.
+ * Valid values for this field are "filesystem", "stream" or "none" (default).
+ *
+ * @param url the url to check
+ * @return the output type of the given @p url
+ */
+ static Type outputType( const KURL &url );
+
+ /**
+ * Returns the list of fields this protocol returns when listing
+ * The current possibilities are
+ * Name, Type, Size, Date, AccessDate, Access, Owner, Group, Link, URL, MimeType
+ * as well as Extra1, Extra2 etc. for extra fields (see extraFields).
+ *
+ * This corresponds to the "listing=" field in the protocol description file.
+ * The supported fields should be separated with ',' in the protocol description file.
+ *
+ * @param url the url to check
+ * @return a list of field names
+ */
+ static TQStringList listing( const KURL &url );
+
+ /**
+ * Definition of an extra field in the UDS entries, returned by a listDir operation.
+ *
+ * The name is the name of the column, translated.
+ *
+ * The type name comes from TQVariant::typeName()
+ * Currently supported types: "TQString", "TQDateTime" (ISO-8601 format)
+ *
+ * @since 3.2
+ */
+ struct ExtraField {
+ ExtraField() {} // for QValueList
+ ExtraField(const TQString& _name, const TQString& _type )
+ : name(_name), type(_type) {
+ }
+ TQString name;
+ TQString type; // KDE4: make it TQVariant::Type
+ };
+ typedef TQValueList<ExtraField > ExtraFieldList;
+ /**
+ * Definition of extra fields in the UDS entries, returned by a listDir operation.
+ *
+ * This corresponds to the "ExtraNames=" and "ExtraTypes=" fields in the protocol description file.
+ * Those two lists should be separated with ',' in the protocol description file.
+ * See ExtraField for details about names and types
+ *
+ * @since 3.2
+ */
+ static ExtraFieldList extraFields( const KURL& url );
+
+ /**
+ * Returns whether the protocol can act as a source protocol.
+ *
+ * A source protocol retrieves data from or stores data to the
+ * location specified by a URL.
+ * A source protocol is the opposite of a filter protocol.
+ *
+ * The "source=" field in the protocol description file determines
+ * whether a protocol is a source protocol or a filter protocol.
+ * @param url the url to check
+ * @return true if the protocol is a source of data (e.g. http), false if the
+ * protocol is a filter (e.g. gzip)
+ */
+ static bool isSourceProtocol( const KURL &url );
+
+ /**
+ * Returns whether the protocol can act as a helper protocol.
+ * A helper protocol invokes an external application and does not return
+ * a file or stream.
+ *
+ * This corresponds to the "helper=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol is a helper protocol (e.g. vnc), false
+ * if not (e.g. http)
+ */
+ static bool isHelperProtocol( const KURL &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isHelperProtocol( const TQString& protocol )
+#ifdef KPROTOCOLINFO_TDECORE
+ KDE_WEAK_SYMBOL
+#endif
+ ;
+
+ /**
+ * Returns whether the protocol can act as a filter protocol.
+ *
+ * A filter protocol can operate on data that is passed to it
+ * but does not retrieve/store data itself, like gzip.
+ * A filter protocol is the opposite of a source protocol.
+ *
+ * The "source=" field in the protocol description file determines
+ * whether a protocol is a source protocol or a filter protocol.
+ * Valid values for this field are "true" (default) for source protocol or
+ * "false" for filter protocol.
+ *
+ * @param url the url to check
+ * @return true if the protocol is a filter (e.g. gzip), false if the
+ * protocol is a helper or source
+ */
+ static bool isFilterProtocol( const KURL &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isFilterProtocol( const TQString& protocol )
+#ifdef KPROTOCOLINFO_TDECORE
+ KDE_WEAK_SYMBOL
+#endif
+ ;
+
+ /**
+ * Returns whether the protocol can list files/objects.
+ * If a protocol supports listing it can be browsed in e.g. file-dialogs
+ * and konqueror.
+ *
+ * Whether a protocol supports listing is determined by the "listing="
+ * field in the protocol description file.
+ * If the protocol support listing it should list the fields it provides in
+ * this field. If the protocol does not support listing this field should
+ * remain empty (default.)
+ *
+ * @param url the url to check
+ * @return true if the protocol support listing
+ * @see listing()
+ */
+ static bool supportsListing( const KURL &url );
+
+ /**
+ * Returns whether the protocol can retrieve data from URLs.
+ *
+ * This corresponds to the "reading=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if it is possible to read from the URL
+ */
+ static bool supportsReading( const KURL &url );
+
+ /**
+ * Returns whether the protocol can store data to URLs.
+ *
+ * This corresponds to the "writing=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol supports writing
+ */
+ static bool supportsWriting( const KURL &url );
+
+ /**
+ * Returns whether the protocol can create directories/folders.
+ *
+ * This corresponds to the "makedir=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can create directories
+ */
+ static bool supportsMakeDir( const KURL &url );
+
+ /**
+ * Returns whether the protocol can delete files/objects.
+ *
+ * This corresponds to the "deleting=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol supports deleting
+ */
+ static bool supportsDeleting( const KURL &url );
+
+ /**
+ * Returns whether the protocol can create links between files/objects.
+ *
+ * This corresponds to the "linking=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol supports linking
+ */
+ static bool supportsLinking( const KURL &url );
+
+ /**
+ * Returns whether the protocol can move files/objects between different
+ * locations.
+ *
+ * This corresponds to the "moving=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol supports moving
+ */
+ static bool supportsMoving( const KURL &url );
+
+ /**
+ * Returns whether the protocol can copy files/objects directly from the
+ * filesystem itself. If not, the application will read files from the
+ * filesystem using the file-protocol and pass the data on to the destination
+ * protocol.
+ *
+ * This corresponds to the "copyFromFile=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can copy files from the local file system
+ */
+ static bool canCopyFromFile( const KURL &url );
+
+ /**
+ * Returns whether the protocol can copy files/objects directly to the
+ * filesystem itself. If not, the application will receive the data from
+ * the source protocol and store it in the filesystem using the
+ * file-protocol.
+ *
+ * This corresponds to the "copyToFile=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can copy files to the local file system
+ */
+ static bool canCopyToFile( const KURL &url );
+
+ /**
+ * Returns whether the protocol can rename (i.e. move fast) files/objects
+ * directly from the filesystem itself. If not, the application will read
+ * files from the filesystem using the file-protocol and pass the data on
+ * to the destination protocol.
+ *
+ * This corresponds to the "renameFromFile=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can rename/move files from the local file system
+ * @since 3.4
+ */
+ static bool canRenameFromFile( const KURL &url );
+
+ /**
+ * Returns whether the protocol can rename (i.e. move fast) files/objects
+ * directly to the filesystem itself. If not, the application will receive
+ * the data from the source protocol and store it in the filesystem using the
+ * file-protocol.
+ *
+ * This corresponds to the "renameToFile=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can rename files to the local file system
+ * @since 3.4
+ */
+ static bool canRenameToFile( const KURL &url );
+
+ /**
+ * Returns whether the protocol can recursively delete directories by itself.
+ * If not (the usual case) then KIO will list the directory and delete files
+ * and empty directories one by one.
+ *
+ * This corresponds to the "deleteRecursive=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol can delete non-empty directories by itself.
+ * @since 3.4
+ */
+ static bool canDeleteRecursive( const KURL &url );
+
+ typedef enum { Name, FromURL } FileNameUsedForCopying;
+
+ /**
+ * This setting defines the strategy to use for generating a filename, when
+ * copying a file or directory to another directory. By default the destination
+ * filename is made out of the filename in the source URL. However if the
+ * ioslave displays names that are different from the filename of the URL
+ * (e.g. kio_fonts shows Arial for arial.ttf, or kio_trash shows foo.txt and
+ * uses some internal URL), using Name means that the display name (UDS_NAME)
+ * will be used to as the filename in the destination directory.
+ *
+ * This corresponds to the "fileNameUsedForCopying=" field in the protocol description file.
+ * Valid values for this field are "Name" or "FromURL" (default).
+ *
+ * @param url the url to check
+ * @return how to generate the filename in the destination directory when copying/moving
+ * @since 3.4
+ */
+ static FileNameUsedForCopying fileNameUsedForCopying( const KURL &url );
+
+ /**
+ * Returns default mimetype for this URL based on the protocol.
+ *
+ * This corresponds to the "defaultMimetype=" field in the protocol description file.
+ *
+ * @param url the url to check
+ * @return the default mime type of the protocol, or null if unknown
+ */
+ static TQString defaultMimetype( const KURL& url );
+
+ /**
+ * Returns the name of the icon, associated with the specified protocol.
+ *
+ * This corresponds to the "Icon=" field in the protocol description file.
+ *
+ * @param protocol the protocol to check
+ * @return the icon of the protocol, or null if unknown
+ */
+ static TQString icon( const TQString& protocol );
+
+ /**
+ * Returns the name of the config file associated with the
+ * specified protocol. This is useful if two similar protocols
+ * need to share a single config file, e.g. http and https.
+ *
+ * This corresponds to the "config=" field in the protocol description file.
+ * The default is the protocol name, see name()
+ *
+ * @param protocol the protocol to check
+ * @return the config file, or null if unknown
+ */
+ static TQString config( const TQString& protocol );
+
+ /**
+ * Returns the soft limit on the number of slaves for this protocol.
+ * This limits the number of slaves used for a single operation, note
+ * that multiple operations may result in a number of instances that
+ * exceeds this soft limit.
+ *
+ * This corresponds to the "maxInstances=" field in the protocol description file.
+ * The default is 1.
+ *
+ * @param protocol the protocol to check
+ * @return the maximum number of slaves, or 1 if unknown
+ */
+ static int maxSlaves( const TQString& protocol );
+
+ /**
+ * Returns whether mimetypes can be determined based on extension for this
+ * protocol. For some protocols, e.g. http, the filename extension in the URL
+ * can not be trusted to truly reflect the file type.
+ *
+ * This corresponds to the "determineMimetypeFromExtension=" field in the protocol description file.
+ * Valid values for this field are "true" (default) or "false".
+ *
+ * @param protocol the protocol to check
+ * @return true if the mime types can be determined by extension
+ */
+ static bool determineMimetypeFromExtension( const TQString &protocol );
+
+ /**
+ * Returns the documentation path for the specified protocol.
+ *
+ * This corresponds to the "DocPath=" field in the protocol description file.
+ *
+ * @param protocol the protocol to check
+ * @return the docpath of the protocol, or null if unknown
+ * @since 3.2
+ */
+ static TQString docPath( const TQString& protocol );
+
+ /**
+ * Returns the protocol class for the specified protocol.
+ *
+ * This corresponds to the "Class=" field in the protocol description file.
+ *
+ * The following classes are defined:
+ * @li ":internet" for common internet protocols
+ * @li ":local" for protocols that access local resources
+ *
+ * Protocol classes always start with a ':' so that they can not be confused with
+ * the protocols themselves.
+ *
+ * @param protocol the protocol to check
+ * @return the class of the protocol, or null if unknown
+ * @since 3.2
+ */
+ static TQString protocolClass( const TQString& protocol );
+
+ /**
+ * Returns whether file previews should be shown for the specified protocol.
+ *
+ * This corresponds to the "ShowPreviews=" field in the protocol description file.
+ *
+ * By default previews are shown if protocolClass is :local.
+ *
+ * @param protocol the protocol to check
+ * @return true if previews should be shown by default, false otherwise
+ * @since 3.2
+ */
+ static bool showFilePreview( const TQString& protocol );
+
+ /**
+ * Returns the suggested URI parsing mode for the KURL parser.
+ *
+ * This corresponds to the "URIMode=" field in the protocol description file.
+ *
+ * The following parsing modes are defined:
+ * @li "url" for a standards compliant URL
+ * @li "rawuri" for a non-conformant URI for which URL parsing would be meaningless
+ * @li "mailto" for a mailto style URI (the path part contains only an email address)
+ *
+ * @param protocol the protocol to check
+ * @return the suggested parsing mode, or KURL::Auto if unspecified
+ *
+ * @since 3.2
+ */
+ static KURL::URIMode uriParseMode( const TQString& protocol );
+
+ /**
+ * Returns the list of capabilities provided by the tdeioslave implementing
+ * this protocol.
+ *
+ * This corresponds to the "Capabilities=" field in the protocol description file.
+ *
+ * The capability names are not defined globally, they are up to each
+ * slave implementation. For example when adding support for a new
+ * special command for mounting, one would add the string "Mount" to the
+ * capabilities list, and applications could check for that string
+ * before sending a special() command that would otherwise do nothing
+ * on older tdeioslave implementations.
+ *
+ * @param protocol the protocol to check
+ * @return the list of capabilities.
+ *
+ * @since 3.3
+ */
+ static TQStringList capabilities( const TQString& protocol );
+
+ /**
+ * Returns the name of the protocol through which the request
+ * will be routed if proxy support is enabled.
+ *
+ * A good example of this is the ftp protocol for which proxy
+ * support is commonly handled by the http protocol.
+ *
+ * This corresponds to the "ProxiedBy=" in the protocol description file.
+ *
+ * @since 3.3
+ */
+ static TQString proxiedBy( const TQString& protocol );
+
+public:
+ // Internal functions:
+ /**
+ * @internal construct a KProtocolInfo from a stream
+ */
+ KProtocolInfo( TQDataStream& _str, int offset);
+
+ virtual ~KProtocolInfo();
+
+ /**
+ * @internal
+ * Load the protocol info from a stream.
+ */
+ virtual void load(TQDataStream& );
+
+ /**
+ * @internal
+ * Save the protocol info to a stream.
+ */
+ virtual void save(TQDataStream& );
+
+ ////////////////////////// DEPRECATED /////////////////////////
+ // The following methods are deprecated:
+
+ /// @deprecated
+ static Type inputType( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static Type outputType( const TQString& protocol ) KDE_DEPRECATED;
+ /**
+ * @deprecated
+ * Returns the list of fields this protocol returns when listing
+ * The current possibilities are
+ * Name, Type, Size, Date, AccessDate, Access, Owner, Group, Link, URL, MimeType
+ */
+ static TQStringList listing( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool isSourceProtocol( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsListing( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsReading( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsWriting( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsMakeDir( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsDeleting( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsLinking( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool supportsMoving( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool canCopyFromFile( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static bool canCopyToFile( const TQString& protocol ) KDE_DEPRECATED;
+ /// @deprecated
+ static TQString defaultMimetype( const TQString& protocol) KDE_DEPRECATED;
+ //////////////////////// END DEPRECATED ///////////////////////
+
+protected:
+ TQString m_name;
+ TQString m_exec;
+ Type m_inputType;
+ Type m_outputType;
+ TQStringList m_listing;
+ bool m_isSourceProtocol;
+ bool m_isHelperProtocol;
+ bool m_supportsListing;
+ bool m_supportsReading;
+ bool m_supportsWriting;
+ bool m_supportsMakeDir;
+ bool m_supportsDeleting;
+ bool m_supportsLinking;
+ bool m_supportsMoving;
+ TQString m_defaultMimetype;
+ bool m_determineMimetypeFromExtension;
+ TQString m_icon;
+ bool m_canCopyFromFile;
+ bool m_canCopyToFile;
+ TQString m_config;
+ int m_maxSlaves;
+
+ bool canRenameFromFile() const; // for kprotocolinfo_tdecore
+ bool canRenameToFile() const; // for kprotocolinfo_tdecore
+ bool canDeleteRecursive() const; // for kprotocolinfo_tdecore
+ FileNameUsedForCopying fileNameUsedForCopying() const; // for kprotocolinfo_tdecore
+ static KProtocolInfo* findProtocol(const KURL &url); // for kprotocolinfo_tdecore
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KProtocolInfoPrivate;
+ KProtocolInfoPrivate* d;
+};
+
+TDEIO_EXPORT TQDataStream& operator>>( TQDataStream& s, KProtocolInfo::ExtraField& field );
+TDEIO_EXPORT TQDataStream& operator<<( TQDataStream& s, const KProtocolInfo::ExtraField& field );
+
+#endif
diff --git a/tdeio/tdeio/kprotocolmanager.cpp b/tdeio/tdeio/kprotocolmanager.cpp
new file mode 100644
index 000000000..450b9d107
--- /dev/null
+++ b/tdeio/tdeio/kprotocolmanager.cpp
@@ -0,0 +1,534 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000- Waldo Bastain <bastain@kde.org>
+ Copyright (C) 2000- Dawit Alemayehu <adawit@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 <string.h>
+#include <sys/utsname.h>
+
+#include <dcopref.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <tdeconfig.h>
+#include <kstandarddirs.h>
+#include <klibloader.h>
+#include <kstringhandler.h>
+#include <kstaticdeleter.h>
+#include <tdeio/slaveconfig.h>
+#include <tdeio/ioslave_defaults.h>
+#include <tdeio/http_slave_defaults.h>
+
+#include "kprotocolmanager.h"
+
+class
+KProtocolManagerPrivate
+{
+public:
+ KProtocolManagerPrivate();
+
+ ~KProtocolManagerPrivate();
+
+ TDEConfig *config;
+ TDEConfig *http_config;
+ bool init_busy;
+ KURL url;
+ TQString protocol;
+ TQString proxy;
+ TQString modifiers;
+ TQString useragent;
+};
+
+static KProtocolManagerPrivate* d = 0;
+static KStaticDeleter<KProtocolManagerPrivate> kpmpksd;
+
+KProtocolManagerPrivate::KProtocolManagerPrivate()
+ :config(0), http_config(0), init_busy(false)
+{
+ kpmpksd.setObject(d, this);
+}
+
+KProtocolManagerPrivate::~KProtocolManagerPrivate()
+{
+ delete config;
+ delete http_config;
+}
+
+
+// DEFAULT USERAGENT STRING
+#define CFG_DEFAULT_UAGENT(X) \
+TQString("Mozilla/5.0 (compatible; Konqueror/%1.%2%3) KHTML/%4.%5.%6 (like Gecko)") \
+ .arg(TDE_VERSION_MAJOR).arg(TDE_VERSION_MINOR).arg(X).arg(TDE_VERSION_MAJOR).arg(TDE_VERSION_MINOR).arg(TDE_VERSION_RELEASE)
+
+void KProtocolManager::reparseConfiguration()
+{
+ kpmpksd.destructObject();
+
+ // Force the slave config to re-read its config...
+ TDEIO::SlaveConfig::self()->reset ();
+}
+
+TDEConfig *KProtocolManager::config()
+{
+ if (!d)
+ d = new KProtocolManagerPrivate;
+
+ if (!d->config)
+ {
+ d->config = new TDEConfig("tdeioslaverc", true, false);
+ }
+ return d->config;
+}
+
+TDEConfig *KProtocolManager::http_config()
+{
+ if (!d)
+ d = new KProtocolManagerPrivate;
+
+ if (!d->http_config)
+ {
+ d->http_config = new TDEConfig("kio_httprc", false, false);
+ }
+ return d->http_config;
+}
+
+/*=============================== TIMEOUT SETTINGS ==========================*/
+
+int KProtocolManager::readTimeout()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ int val = cfg->readNumEntry( "ReadTimeout", DEFAULT_READ_TIMEOUT );
+ return QMAX(MIN_TIMEOUT_VALUE, val);
+}
+
+int KProtocolManager::connectTimeout()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ int val = cfg->readNumEntry( "ConnectTimeout", DEFAULT_CONNECT_TIMEOUT );
+ return QMAX(MIN_TIMEOUT_VALUE, val);
+}
+
+int KProtocolManager::proxyConnectTimeout()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ int val = cfg->readNumEntry( "ProxyConnectTimeout", DEFAULT_PROXY_CONNECT_TIMEOUT );
+ return QMAX(MIN_TIMEOUT_VALUE, val);
+}
+
+int KProtocolManager::responseTimeout()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ int val = cfg->readNumEntry( "ResponseTimeout", DEFAULT_RESPONSE_TIMEOUT );
+ return QMAX(MIN_TIMEOUT_VALUE, val);
+}
+
+/*========================== PROXY SETTINGS =================================*/
+
+bool KProtocolManager::useProxy()
+{
+ return proxyType() != NoProxy;
+}
+
+bool KProtocolManager::useReverseProxy()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+ return cfg->readBoolEntry("ReversedException", false);
+}
+
+KProtocolManager::ProxyType KProtocolManager::proxyType()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+ return static_cast<ProxyType>(cfg->readNumEntry( "ProxyType" ));
+}
+
+KProtocolManager::ProxyAuthMode KProtocolManager::proxyAuthMode()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+ return static_cast<ProxyAuthMode>(cfg->readNumEntry( "AuthMode" ));
+}
+
+/*========================== CACHING =====================================*/
+
+bool KProtocolManager::useCache()
+{
+ TDEConfig *cfg = http_config();
+ return cfg->readBoolEntry( "UseCache", true );
+}
+
+TDEIO::CacheControl KProtocolManager::cacheControl()
+{
+ TDEConfig *cfg = http_config();
+ TQString tmp = cfg->readEntry("cache");
+ if (tmp.isEmpty())
+ return DEFAULT_CACHE_CONTROL;
+ return TDEIO::parseCacheControl(tmp);
+}
+
+TQString KProtocolManager::cacheDir()
+{
+ TDEConfig *cfg = http_config();
+ return cfg->readPathEntry("CacheDir", TDEGlobal::dirs()->saveLocation("cache","http"));
+}
+
+int KProtocolManager::maxCacheAge()
+{
+ TDEConfig *cfg = http_config();
+ return cfg->readNumEntry( "MaxCacheAge", DEFAULT_MAX_CACHE_AGE ); // 14 days
+}
+
+int KProtocolManager::maxCacheSize()
+{
+ TDEConfig *cfg = http_config();
+ return cfg->readNumEntry( "MaxCacheSize", DEFAULT_MAX_CACHE_SIZE ); // 5 MB
+}
+
+TQString KProtocolManager::noProxyForRaw()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+
+ return cfg->readEntry( "NoProxyFor" );
+}
+
+TQString KProtocolManager::noProxyFor()
+{
+ TQString noProxy = noProxyForRaw();
+ if (proxyType() == EnvVarProxy)
+ noProxy = TQString::fromLocal8Bit(getenv(noProxy.local8Bit()));
+
+ return noProxy;
+}
+
+TQString KProtocolManager::proxyFor( const TQString& protocol )
+{
+ TQString scheme = protocol.lower();
+
+ if (scheme == "webdav")
+ scheme = "http";
+ else if (scheme == "webdavs")
+ scheme = "https";
+
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+ return cfg->readEntry( scheme + "Proxy" );
+}
+
+TQString KProtocolManager::proxyForURL( const KURL &url )
+{
+ TQString proxy;
+ ProxyType pt = proxyType();
+
+ switch (pt)
+ {
+ case PACProxy:
+ case WPADProxy:
+ if (!url.host().isEmpty())
+ {
+ KURL u (url);
+ TQString p = u.protocol().lower();
+
+ // webdav is a KDE specific protocol. Look up proxy
+ // information using HTTP instead...
+ if ( p == "webdav" )
+ {
+ p = "http";
+ u.setProtocol( p );
+ }
+ else if ( p == "webdavs" )
+ {
+ p = "https";
+ u.setProtocol( p );
+ }
+
+ if ( p.startsWith("http") || p == "ftp" || p == "gopher" )
+ DCOPRef( "kded", "proxyscout" ).call( "proxyForURL", u ).get( proxy );
+ }
+ break;
+ case EnvVarProxy:
+ proxy = TQString(TQString::fromLocal8Bit(getenv(proxyFor(url.protocol()).local8Bit()))).stripWhiteSpace();
+ break;
+ case ManualProxy:
+ proxy = proxyFor( url.protocol() );
+ break;
+ case NoProxy:
+ default:
+ break;
+ }
+
+ return (proxy.isEmpty() ? TQString::fromLatin1("DIRECT") : proxy);
+}
+
+void KProtocolManager::badProxy( const TQString &proxy )
+{
+ DCOPRef( "kded", "proxyscout" ).send( "blackListProxy", proxy );
+}
+
+/*
+ Domain suffix match. E.g. return true if host is "cuzco.inka.de" and
+ nplist is "inka.de,hadiko.de" or if host is "localhost" and nplist is
+ "localhost".
+*/
+static bool revmatch(const char *host, const char *nplist)
+{
+ if (host == 0)
+ return false;
+
+ const char *hptr = host + strlen( host ) - 1;
+ const char *nptr = nplist + strlen( nplist ) - 1;
+ const char *shptr = hptr;
+
+ while ( nptr >= nplist )
+ {
+ if ( *hptr != *nptr )
+ {
+ hptr = shptr;
+
+ // Try to find another domain or host in the list
+ while(--nptr>=nplist && *nptr!=',' && *nptr!=' ') ;
+
+ // Strip out multiple spaces and commas
+ while(--nptr>=nplist && (*nptr==',' || *nptr==' ')) ;
+ }
+ else
+ {
+ if ( nptr==nplist || nptr[-1]==',' || nptr[-1]==' ')
+ return true;
+ if ( hptr == host ) // e.g. revmatch("bugs.kde.org","mybugs.kde.org")
+ return false;
+
+ hptr--;
+ nptr--;
+ }
+ }
+
+ return false;
+}
+
+TQString KProtocolManager::slaveProtocol(const KURL &url, TQString &proxy)
+{
+ if (url.hasSubURL()) // We don't want the suburl's protocol
+ {
+ KURL::List list = KURL::split(url);
+ KURL::List::Iterator it = list.fromLast();
+ return slaveProtocol(*it, proxy);
+ }
+
+ if (!d)
+ d = new KProtocolManagerPrivate;
+
+ if (d->url == url)
+ {
+ proxy = d->proxy;
+ return d->protocol;
+ }
+
+ if (useProxy())
+ {
+ proxy = proxyForURL(url);
+ if ((proxy != "DIRECT") && (!proxy.isEmpty()))
+ {
+ bool isRevMatch = false;
+ KProtocolManager::ProxyType type = proxyType();
+ bool useRevProxy = ((type == ManualProxy) && useReverseProxy());
+
+ TQString noProxy;
+ // Check no proxy information iff the proxy type is either
+ // ManualProxy or EnvVarProxy
+ if ( (type == ManualProxy) || (type == EnvVarProxy) )
+ noProxy = noProxyFor();
+
+ if (!noProxy.isEmpty())
+ {
+ TQString qhost = url.host().lower();
+ const char *host = qhost.latin1();
+ TQString qno_proxy = noProxy.stripWhiteSpace().lower();
+ const char *no_proxy = qno_proxy.latin1();
+ isRevMatch = revmatch(host, no_proxy);
+
+ // If no match is found and the request url has a port
+ // number, try the combination of "host:port". This allows
+ // users to enter host:port in the No-proxy-For list.
+ if (!isRevMatch && url.port() > 0)
+ {
+ qhost += ':' + TQString::number (url.port());
+ host = qhost.latin1();
+ isRevMatch = revmatch (host, no_proxy);
+ }
+
+ // If the hostname does not contain a dot, check if
+ // <local> is part of noProxy.
+ if (!isRevMatch && host && (strchr(host, '.') == NULL))
+ isRevMatch = revmatch("<local>", no_proxy);
+ }
+
+ if ( (!useRevProxy && !isRevMatch) || (useRevProxy && isRevMatch) )
+ {
+ d->url = proxy;
+ if ( d->url.isValid() )
+ {
+ // The idea behind slave protocols is not applicable to http
+ // and webdav protocols.
+ TQString protocol = url.protocol().lower();
+ if (protocol.startsWith("http") || protocol.startsWith("webdav"))
+ d->protocol = protocol;
+ else
+ {
+ d->protocol = d->url.protocol();
+ kdDebug () << "slaveProtocol: " << d->protocol << endl;
+ }
+
+ d->url = url;
+ d->proxy = proxy;
+ return d->protocol;
+ }
+ }
+ }
+ }
+
+ d->url = url;
+ d->proxy = proxy = TQString::null;
+ d->protocol = url.protocol();
+ return d->protocol;
+}
+
+/*================================= USER-AGENT SETTINGS =====================*/
+
+TQString KProtocolManager::userAgentForHost( const TQString& hostname )
+{
+ TQString sendUserAgent = TDEIO::SlaveConfig::self()->configData("http", hostname.lower(), "SendUserAgent").lower();
+ if (sendUserAgent == "false")
+ return TQString::null;
+
+ TQString useragent = TDEIO::SlaveConfig::self()->configData("http", hostname.lower(), "UserAgent");
+
+ // Return the default user-agent if none is specified
+ // for the requested host.
+ if (useragent.isEmpty())
+ return defaultUserAgent();
+
+ return useragent;
+}
+
+TQString KProtocolManager::defaultUserAgent( )
+{
+ TQString modifiers = TDEIO::SlaveConfig::self()->configData("http", TQString::null, "UserAgentKeys");
+ return defaultUserAgent(modifiers);
+}
+
+TQString KProtocolManager::defaultUserAgent( const TQString &_modifiers )
+{
+ if (!d)
+ d = new KProtocolManagerPrivate;
+
+ TQString modifiers = _modifiers.lower();
+ if (modifiers.isEmpty())
+ modifiers = DEFAULT_USER_AGENT_KEYS;
+
+ if (d->modifiers == modifiers)
+ return d->useragent;
+
+ TQString supp;
+ struct utsname nam;
+ if( uname(&nam) >= 0 )
+ {
+ if( modifiers.contains('o') )
+ {
+ supp += TQString("; %1").arg(nam.sysname);
+ if ( modifiers.contains('v') )
+ supp += TQString(" %1").arg(nam.release);
+ }
+ if( modifiers.contains('p') )
+ {
+ // TODO: determine this value instead of hardcoding it...
+ supp += TQString::fromLatin1("; X11");
+ }
+ if( modifiers.contains('m') )
+ {
+ supp += TQString("; %1").arg(nam.machine);
+ }
+ if( modifiers.contains('l') )
+ {
+ TQStringList languageList = TDEGlobal::locale()->languageList();
+ TQStringList::Iterator it = languageList.find( TQString::fromLatin1("C") );
+ if( it != languageList.end() )
+ {
+ if( languageList.contains( TQString::fromLatin1("en") ) > 0 )
+ languageList.remove( it );
+ else
+ (*it) = TQString::fromLatin1("en");
+ }
+ if( languageList.count() )
+ supp += TQString("; %1").arg(languageList.join(", "));
+ }
+ }
+ d->modifiers = modifiers;
+ d->useragent = CFG_DEFAULT_UAGENT(supp);
+ return d->useragent;
+}
+
+/*==================================== OTHERS ===============================*/
+
+bool KProtocolManager::markPartial()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ return cfg->readBoolEntry( "MarkPartial", true );
+}
+
+int KProtocolManager::minimumKeepSize()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ return cfg->readNumEntry( "MinimumKeepSize",
+ DEFAULT_MINIMUM_KEEP_SIZE ); // 5000 byte
+}
+
+bool KProtocolManager::autoResume()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ return cfg->readBoolEntry( "AutoResume", false );
+}
+
+bool KProtocolManager::persistentConnections()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ return cfg->readBoolEntry( "PersistentConnections", true );
+}
+
+bool KProtocolManager::persistentProxyConnection()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( TQString::null );
+ return cfg->readBoolEntry( "PersistentProxyConnection", false );
+}
+
+TQString KProtocolManager::proxyConfigScript()
+{
+ TDEConfig *cfg = config();
+ cfg->setGroup( "Proxy Settings" );
+ return cfg->readEntry( "Proxy Config Script" );
+}
diff --git a/tdeio/tdeio/kprotocolmanager.h b/tdeio/tdeio/kprotocolmanager.h
new file mode 100644
index 000000000..ce504a83f
--- /dev/null
+++ b/tdeio/tdeio/kprotocolmanager.h
@@ -0,0 +1,389 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000- Waldo Bastain <bastain@kde.org>
+ Copyright (C) 2000- Dawit Alemayehu <adawit@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 __kprotocolmanager_h__
+#define __kprotocolmanager_h__
+
+#include <tqstringlist.h>
+
+#include <kapplication.h>
+#include <tdeio/global.h>
+
+/** @deprecated Use KProtocolManager::defaultUserAgent() instead. */
+#define DEFAULT_USERAGENT_STRING ""
+
+class TDEConfig;
+
+/**
+ * Provides information about I/O (Internet, etc.) settings chosen/set
+ * by the end user.
+ *
+ * KProtocolManager has a heap of static functions that allows only read
+ * access to KDE's IO related settings. These include proxy, cache, file
+ * transfer resumption, timeout and user-agent related settings.
+ *
+ * The information provided by this class is generic enough to be applicable
+ * to any application that makes use of KDE's IO sub-system. Note that this
+ * mean the proxy, timeout etc. settings are saved in a separate user-specific
+ * config file and not in the config file of the application.
+ *
+ * Original author:
+ * @author Torben Weis <weis@kde.org>
+ *
+ * Revised by:
+ * @author Waldo Bastain <bastain@kde.org>
+ * @author Dawit Alemayehu <adawit@kde.org>
+ * @see KPAC
+ */
+class TDEIO_EXPORT KProtocolManager
+{
+public:
+
+
+/*=========================== USER-AGENT SETTINGS ===========================*/
+
+
+ /**
+ * Returns the default user-agent string.
+ *
+ * @return the default user-agent string
+ */
+ static TQString defaultUserAgent();
+
+ /**
+ * Returns the default user-agent value.
+ *
+ * @param keys can be any of the following:
+ * @li 'o' Show OS
+ * @li 'v' Show OS Version
+ * @li 'p' Show platform
+ * @li 'm' Show machine architecture
+ * @li 'l' Show language
+ * @return the default user-agent value with the given @p keys
+ */
+ static TQString defaultUserAgent(const TQString &keys);
+
+ /**
+ * Returns the userAgent string configured for the
+ * specified host.
+ *
+ * If hostname is not found or is empty (i.e. "" or
+ * TQString::null) this function will return the default
+ * user agent.
+ *
+ * @param hostname name of the host
+ * @return specified userAgent string
+ */
+ static TQString userAgentForHost( const TQString &hostname );
+
+
+/*=========================== TIMEOUT CONFIG ================================*/
+
+
+ /**
+ * Returns the preferred timeout value for reading from
+ * remote connections in seconds.
+ *
+ * @return timeout value for remote connection in secs.
+ */
+ static int readTimeout();
+
+ /**
+ * Returns the preferred timeout value for remote connections
+ * in seconds.
+ *
+ * @return timeout value for remote connection in secs.
+ */
+ static int connectTimeout();
+
+ /**
+ * Returns the preferred timeout value for proxy connections
+ * in seconds.
+ *
+ * @return timeout value for proxy connection in secs.
+ */
+ static int proxyConnectTimeout();
+
+ /**
+ * Returns the preferred response timeout value for
+ * remote connecting in seconds.
+ *
+ * @return timeout value for remote connection in seconds.
+ */
+ static int responseTimeout();
+
+
+/*=============================== PROXY CONFIG ==============================*/
+
+
+ /**
+ * Returns true if the user specified a proxy server to make connections.
+ *
+ * @see slaveProtocol, proxyForURL, proxyFor
+ */
+ static bool useProxy();
+
+ /**
+ * Returns true if the proxy settings should apply to the list
+ * returned by @ref noProxyFor.
+ *
+ * Normally addresses listed in the noProxyFor list are not routed
+ * through a proxy server. However, if this function returns true,
+ * then all addresses listed in the noProxyFor list are to be routed
+ * through a proxy server where as those that are not should bypass it.
+ *
+ * This function as well as @ref noProxyFor only apply when @ref proxyType
+ * is @p ManualProxy.
+ *
+ * @see proxyForURL, proxyFor, slaveProtocol
+ */
+ static bool useReverseProxy();
+
+ /**
+ * Types of proxy configuration
+ * @li NoProxy - No proxy is used
+ * @li ManualProxy - Proxies are manually configured
+ * @li PACProxy - A Proxy configuration URL has been given
+ * @li WPADProxy - A proxy should be automatically discovered
+ * @li EnvVarProxy - Use the proxy values set through environment variables.
+ */
+ enum ProxyType
+ {
+ NoProxy,
+ ManualProxy,
+ PACProxy,
+ WPADProxy,
+ EnvVarProxy
+ };
+
+ /**
+ * Returns the type of proxy configuration that is used.
+ *
+ * @see ProxyType
+ */
+ static ProxyType proxyType();
+
+ /**
+ * Proxy authorization modes.
+ *
+ * @li Prompt - Ask for authorization as needed
+ * @li Automatic - Use auto login as defined in .kionetrc files.
+ *
+ * NOTE: .kionetrc files have the same format as ftp .netrc files.
+ * Please note the use of .kionetrc files is highly discouraged since
+ * password is stored in clear text. For future releases the ability
+ * to store preset password for proxy servers will probably be supported
+ * through KWallet integration.
+ */
+ enum ProxyAuthMode
+ {
+ Prompt,
+ Automatic
+ };
+
+ /**
+ * Returns the way proxy authorization should be handled.
+ *
+ * @see ProxyAuthMode
+ */
+ static ProxyAuthMode proxyAuthMode();
+
+ /**
+ * Returns a comma-separated list of hostnames or partial
+ * host-names that should bypass any proxy settings.
+ *
+ * This function as well as @ref useReverseProxy only apply
+ * when @ref proxyType is @p ManualProxy.
+ *
+ * @see useReverseProxy, proxyFor, proxyForURL, slaveProtocol
+ */
+ static TQString noProxyFor();
+
+ /**
+ * Same as above except the environment variable name
+ * is returned instead of the variable value when
+ * @ref proxyType is @p EnvVarProxy.
+ *
+ * @see noProxyFor
+ * @since 3.5.x
+ */
+ static TQString noProxyForRaw();
+
+ /**
+ * Returns the proxy server address for a given protocol.
+ *
+ * NOTE: This function does not take the @ref useReverseProxy()
+ * settings into account.
+ *
+ * @see useReverseProxy, slaveProtocol
+ * @param protocol the protocol whose proxy info is needed
+ * @returns the proxy server address if one is available,
+ * or TQString::null if not available
+ */
+ static TQString proxyFor( const TQString& protocol );
+
+ /**
+ * Returns the proxy server address for a given URL.
+ *
+ * If @ref proxyType returns Automatic, an external service
+ * called KPAC (a kded module) is used to determine the proxy
+ * server. Otherwise, @ref proxyFor is invoked to determine
+ * whether the URL needs to be routed through a proxy server.
+ *
+ * NOTE: This function does not take the @ref useReverseProxy()
+ * or the @ref noProxyFor() settings into account.
+ *
+ * @see useReverseProxy, slaveProtocol, noProxyFor
+ * @param url the URL whose proxy info is needed
+ * @returns the proxy server address or the text "DIRECT"
+ * if no proxying is needed for the given address.
+ */
+ static TQString proxyForURL( const KURL& url );
+
+ /**
+ * Marks this proxy as bad (down). It will not be used for the
+ * next 30 minutes. (The script may supply an alternate proxy)
+ * @param proxy the proxy to mark as bad (as URL)
+ */
+ static void badProxy( const TQString & proxy );
+
+ /**
+ * Returns the URL of the script for automatic proxy configuration.
+ * @return the proxy configuration script
+ */
+ static TQString proxyConfigScript();
+
+
+/*========================== CACHE CONFIG ===================================*/
+
+
+ /**
+ * Returns true/false to indicate whether a cache
+ * should be used
+ *
+ * @return true to use the cache, false otherwisea
+ */
+ static bool useCache();
+
+ /**
+ * Returns the maximum age in seconds cached files should be
+ * kept before they are deleted as necessary.
+ *
+ * @return the maximum cache age in seconds
+ */
+ static int maxCacheAge();
+
+ /**
+ * Returns the maximum size that can be used for caching.
+ *
+ * By default this function returns the DEFAULT_MAX_CACHE_SIZE
+ * value as defined in http_slave_defaults.h. Not that the
+ * value returned is in bytes, hence a value of 5120 would mean
+ * 5 Kb.
+ *
+ * @return the maximum cache size in bytes
+ */
+ static int maxCacheSize(); // Maximum cache size in Kb.
+
+ /**
+ * The directory which contains the cache files.
+ * @return the directory that contains the cache files
+ */
+ static TQString cacheDir();
+
+ /**
+ * Returns the Cache control directive to be used.
+ * @return the cache control value
+ */
+ static TDEIO::CacheControl cacheControl();
+
+
+/*============================ DOWNLOAD CONFIG ==============================*/
+
+ /**
+ * Returns true if partial downloads should be
+ * automatically resumed.
+ * @return true to resume partial downloads
+ */
+ static bool autoResume();
+
+ /**
+ * Returns true if partial downloads should be marked
+ * with a ".part" extension.
+ * @return true if partial downloads should get an ".part" extension
+ */
+ static bool markPartial();
+
+ /**
+ * Returns the minimum file size for keeping aborted
+ * downloads.
+ *
+ * Any data downloaded that does not meet this minimum
+ * requirement will simply be discarded. The default size
+ * is 5 KB.
+ *
+ * @return the minimum keep size for aborted downloads in bytes
+ */
+ static int minimumKeepSize();
+
+
+ /*============================ NETWORK CONNECTIONS ==========================*/
+ /**
+ * Returns true if proxy connections should be persistent.
+ * @return true if proxy connections should be persistent
+ * @since 3.1
+ */
+ static bool persistentProxyConnection();
+
+ /**
+ * Returns true if connections should be persistent
+ * @return true if the connections should be persistent
+ */
+ static bool persistentConnections();
+
+/*=============================== OTHERS ====================================*/
+
+
+ /**
+ * Force a reload of the general config file of
+ * io-slaves ( tdeioslaverc).
+ */
+ static void reparseConfiguration();
+
+ /**
+ * Return the protocol to use in order to handle the given @p url
+ * It's usually the same, except that FTP, when handled by a proxy,
+ * needs an HTTP ioslave.
+ *
+ * When a proxy is to be used, proxy contains the URL for the proxy.
+ * @param url the url to check
+ * @param proxy the URL of the proxy to use
+ * @return the slave protocol (e.g. 'http'), can be null if unknown
+ */
+ static TQString slaveProtocol(const KURL &url, TQString &proxy);
+
+ /**
+ * @internal
+ * (Shared with SlaveConfig)
+ */
+ static TDEConfig *config();
+private:
+ static TDEConfig *http_config();
+};
+#endif
diff --git a/tdeio/tdeio/kremoteencoding.cpp b/tdeio/tdeio/kremoteencoding.cpp
new file mode 100644
index 000000000..632eeb8b2
--- /dev/null
+++ b/tdeio/tdeio/kremoteencoding.cpp
@@ -0,0 +1,95 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+
+ 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 <config.h>
+
+#include <kdebug.h>
+#include <kstringhandler.h>
+#include "kremoteencoding.h"
+
+KRemoteEncoding::KRemoteEncoding(const char *name)
+ : codec(0L), d(0L)
+{
+ setEncoding(name);
+}
+
+KRemoteEncoding::~KRemoteEncoding()
+{
+ // delete d; // not necessary yet
+}
+
+TQString KRemoteEncoding::decode(const TQCString& name) const
+{
+#ifdef CHECK_UTF8
+ if (codec->mibEnum() == 106 && !KStringHandler::isUtf8(name))
+ return TQString::fromLatin1(name);
+#endif
+
+ TQString result = codec->toUnicode(name);
+ if (codec->fromUnicode(result) != name)
+ // fallback in case of decoding failure
+ return TQString::fromLatin1(name);
+
+ return result;
+}
+
+TQCString KRemoteEncoding::encode(const TQString& name) const
+{
+ TQCString result = codec->fromUnicode(name);
+ if (codec->toUnicode(result) != name)
+ return name.latin1();
+
+ return result;
+}
+
+TQCString KRemoteEncoding::encode(const KURL& url) const
+{
+ return encode(url.path());
+}
+
+TQCString KRemoteEncoding::directory(const KURL& url, bool ignore_trailing_slash) const
+{
+ TQString dir = url.directory(true, ignore_trailing_slash);
+
+ return encode(dir);
+}
+
+TQCString KRemoteEncoding::fileName(const KURL& url) const
+{
+ return encode(url.fileName());
+}
+
+void KRemoteEncoding::setEncoding(const char *name)
+{
+ // don't delete codecs
+
+ if (name)
+ codec = TQTextCodec::codecForName(name);
+ else
+ codec = TQTextCodec::codecForMib( 106 ); // fallback to UTF-8
+
+ if (codec == 0L)
+ codec = TQTextCodec::codecForMib(1);
+
+ kdDebug() << k_funcinfo << "setting encoding " << codec->name()
+ << " for name=" << name << endl;
+}
+
+void KRemoteEncoding::virtual_hook(int, void*)
+{
+}
diff --git a/tdeio/tdeio/kremoteencoding.h b/tdeio/tdeio/kremoteencoding.h
new file mode 100644
index 000000000..18dfe1fdb
--- /dev/null
+++ b/tdeio/tdeio/kremoteencoding.h
@@ -0,0 +1,127 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
+
+ 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 KREMOTEENCODING_H
+#define KREMOTEENCODING_H
+
+#include <kurl.h>
+#include <tqstring.h>
+#include <tqcstring.h>
+#include <tqtextcodec.h>
+
+class KRemoteEncodingPrivate;
+/**
+ * Allows encoding and decoding properly remote filenames into Unicode.
+ *
+ * Certain protocols do not specify an appropriate encoding for decoding
+ * their 8-bit data into proper Unicode forms. Therefore, ioslaves should
+ * use this class in order to convert those forms into QStrings before
+ * creating the respective TDEIO::UDSEntry. The same is true for decoding
+ * URLs to its components.
+ *
+ * Each TDEIO::SlaveBase has one object of this kind, even if it is not necessary.
+ * It can be accessed through TDEIO::SlaveBase::remoteEncoding.
+ *
+ * @short A class for handling remote filenames
+ * @author Thiago Macieira <thiago.macieira@kdemail.net>
+ * @since 3.3
+ */
+class TDEIO_EXPORT KRemoteEncoding
+{
+public:
+ /**
+ * Constructor.
+ *
+ * Constructs this object to use the given encoding name.
+ * If @p name is a null pointer, the standard encoding will be used.
+ */
+ explicit KRemoteEncoding(const char *name = 0L);
+
+ /**
+ * Destructor
+ */
+ virtual ~KRemoteEncoding();
+
+ /**
+ * Converts the given full pathname or filename to Unicode.
+ * This function is supposed to work for dirnames, filenames
+ * or a full pathname.
+ */
+ TQString decode(const TQCString& name) const;
+
+ /**
+ * Converts the given name from Unicode.
+ * This function is supposed to work for dirnames, filenames
+ * or a full pathname.
+ */
+ TQCString encode(const TQString& name) const;
+
+ /**
+ * Converts the given URL into its 8-bit components
+ */
+ TQCString encode(const KURL& url) const;
+
+ /**
+ * Converts the given URL into 8-bit form and separate the
+ * dirname from the filename. This is useful for slave functions
+ * like stat or get.
+ *
+ * The dirname is returned with the final slash always stripped
+ */
+ TQCString directory(const KURL& url, bool ignore_trailing_slash = true) const;
+
+ /**
+ * Converts the given URL into 8-bit form and retrieve the filename.
+ */
+ TQCString fileName(const KURL& url) const;
+
+ /**
+ * Returns the encoding being used.
+ */
+ inline const char *encoding() const
+ { return codec->name(); }
+
+ /**
+ * Returns the MIB for the codec being used.
+ */
+ inline int encodingMib() const
+ { return codec->mibEnum(); }
+
+ /**
+ * Sets the encoding being used.
+ * This function does not change the global configuration.
+ *
+ * Pass a null pointer in @p name to revert to the standard
+ * encoding.
+ */
+ void setEncoding(const char* name);
+
+protected:
+ TQTextCodec *codec;
+
+ virtual void virtual_hook(int id, void* data);
+
+private:
+ // copy constructor
+ KRemoteEncoding(const KRemoteEncoding&);
+
+
+ KRemoteEncodingPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdeio/krun.cpp b/tdeio/tdeio/krun.cpp
new file mode 100644
index 000000000..5810bdda4
--- /dev/null
+++ b/tdeio/tdeio/krun.cpp
@@ -0,0 +1,1574 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Torben Weis <weis@kde.org>
+ Copyright (C) 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 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 "krun.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <typeinfo>
+
+#include <tqwidget.h>
+#include <tqguardedptr.h>
+
+#include "kuserprofile.h"
+#include "kmimetype.h"
+#include "kmimemagic.h"
+#include "tdeio/job.h"
+#include "tdeio/global.h"
+#include "tdeio/scheduler.h"
+#include "tdeio/netaccess.h"
+#include "tdefile/kopenwith.h"
+#include "tdefile/krecentdocument.h"
+
+#include <kdatastream.h>
+#include <kmessageboxwrapper.h>
+#include <kurl.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <dcopclient.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqtextstream.h>
+#include <tqdatetime.h>
+#include <tqregexp.h>
+#include <kdesktopfile.h>
+#include <kstartupinfo.h>
+#include <kmacroexpander.h>
+#include <kshell.h>
+#include <kde_file.h>
+#include <kstringhandler.h>
+
+#ifdef Q_WS_X11
+#include <twin.h>
+#endif
+
+class KRun::KRunPrivate
+{
+public:
+ KRunPrivate() { m_showingError = false; }
+
+ bool m_showingError;
+ bool m_runExecutables;
+
+ TQString m_preferredService;
+ TQString m_externalBrowser;
+ TQString m_localPath;
+ TQString m_suggestedFileName;
+ TQGuardedPtr <TQWidget> m_window;
+ TQCString m_asn;
+};
+
+pid_t KRun::runURL( const KURL& u, const TQString& _mimetype )
+{
+ return runURL( u, _mimetype, false, true, TQString::null );
+}
+
+pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile )
+{
+ return runURL( u, _mimetype, tempFile, true, TQString::null );
+}
+
+pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile, bool runExecutables )
+{
+ return runURL( u, _mimetype, tempFile, runExecutables, TQString::null );
+}
+
+bool KRun::isExecutableFile( const KURL& url, const TQString &mimetype )
+{
+ if ( !url.isLocalFile() )
+ return false;
+ TQFileInfo file( url.path() );
+ if ( file.isExecutable() ) // Got a prospective file to run
+ {
+ KMimeType::Ptr mimeType = KMimeType::mimeType( mimetype );
+
+ if ( mimeType->is("application/x-executable") || mimeType->is("application/x-executable-script") )
+ return true;
+ }
+ return false;
+}
+
+pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile, bool runExecutables, const TQString& suggestedFileName )
+{
+ return runURL( u, _mimetype, NULL, "", tempFile, runExecutables, suggestedFileName );
+}
+
+// This is called by foundMimeType, since it knows the mimetype of the URL
+pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, TQWidget* window, const TQCString& asn,
+ bool tempFile, bool runExecutables, const TQString& suggestedFileName )
+{
+ bool noRun = false;
+ bool noAuth = false;
+ if ( _mimetype == "inode/directory-locked" )
+ {
+ KMessageBoxWrapper::error( window,
+ i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>").arg(u.htmlURL()) );
+ return 0;
+ }
+ else if ( (_mimetype == "application/x-desktop") ||
+ (_mimetype == "media/builtin-mydocuments") ||
+ (_mimetype == "media/builtin-mycomputer") ||
+ (_mimetype == "media/builtin-mynetworkplaces") ||
+ (_mimetype == "media/builtin-printers") ||
+ (_mimetype == "media/builtin-trash") ||
+ (_mimetype == "media/builtin-webbrowser") )
+ {
+ if ( u.isLocalFile() && runExecutables )
+ return KDEDesktopMimeType::run( u, true );
+ }
+ else if ( isExecutableFile(u, _mimetype) )
+ {
+ if ( u.isLocalFile() && runExecutables)
+ {
+ if (kapp->authorize("shell_access"))
+ {
+ TQString path = u.path();
+ shellQuote( path );
+ return (KRun::runCommand(path, TQString::null, TQString::null, window, asn)); // just execute the url as a command
+ // ## TODO implement deleting the file if tempFile==true
+ }
+ else
+ {
+ noAuth = true;
+ }
+ }
+ else if (_mimetype == "application/x-executable")
+ noRun = true;
+ }
+ else if ( isExecutable(_mimetype) )
+ {
+ if (!runExecutables)
+ noRun = true;
+
+ if (!kapp->authorize("shell_access"))
+ noAuth = true;
+ }
+
+ if ( noRun )
+ {
+ KMessageBox::sorry( window,
+ i18n("<qt>The file <b>%1</b> is an executable program. "
+ "For safety it will not be started.</qt>").arg(u.htmlURL()));
+ return 0;
+ }
+ if ( noAuth )
+ {
+ KMessageBoxWrapper::error( window,
+ i18n("<qt>You do not have permission to run <b>%1</b>.</qt>").arg(u.htmlURL()) );
+ return 0;
+ }
+
+ KURL::List lst;
+ lst.append( u );
+
+ static const TQString& app_str = TDEGlobal::staticQString("Application");
+
+ KService::Ptr offer = KServiceTypeProfile::preferredService( _mimetype, app_str );
+
+ if ( !offer )
+ {
+ // Open-with dialog
+ // TODO : pass the mimetype as a parameter, to show it (comment field) in the dialog !
+ // Hmm, in fact KOpenWithDlg::setServiceType already guesses the mimetype from the first URL of the list...
+ return displayOpenWithDialog( lst, tempFile, suggestedFileName );
+ }
+
+ return KRun::run( *offer, lst, window, asn, tempFile, suggestedFileName );
+}
+
+bool KRun::displayOpenWithDialog( const KURL::List& lst )
+{
+ return displayOpenWithDialog( lst, false, TQString::null );
+}
+
+bool KRun::displayOpenWithDialog( const KURL::List& lst, bool tempFiles )
+{
+ return displayOpenWithDialog( lst, tempFiles, TQString::null );
+}
+
+bool KRun::displayOpenWithDialog( const KURL::List& lst, bool tempFiles, const TQString& suggestedFileName )
+{
+ if (kapp && !kapp->authorizeKAction("openwith"))
+ {
+ // TODO: Better message, i18n freeze :-(
+ KMessageBox::sorry(0L, i18n("You are not authorized to open this file."));
+ return false;
+ }
+
+ KOpenWithDlg l( lst, i18n("Open with:"), TQString::null, 0L );
+ if ( l.exec() )
+ {
+ KService::Ptr service = l.service();
+ if ( !!service )
+ return KRun::run( *service, lst, 0 /*window*/, tempFiles, suggestedFileName );
+
+ kdDebug(7010) << "No service set, running " << l.text() << endl;
+ return KRun::run( l.text(), lst, suggestedFileName ); // TODO handle tempFiles
+ }
+ return false;
+}
+
+void KRun::shellQuote( TQString &_str )
+{
+ // Credits to Walter, says Bernd G. :)
+ if (_str.isEmpty()) // Don't create an explicit empty parameter
+ return;
+ TQChar q('\'');
+ _str.replace(q, "'\\''").prepend(q).append(q);
+}
+
+
+class KRunMX1 : public KMacroExpanderBase {
+public:
+ KRunMX1( const KService &_service ) :
+ KMacroExpanderBase( '%' ), hasUrls( false ), hasSpec( false ), service( _service ) {}
+ bool hasUrls:1, hasSpec:1;
+
+protected:
+ virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
+
+private:
+ const KService &service;
+};
+
+int
+KRunMX1::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
+{
+ uint option = str[pos + 1];
+ switch( option ) {
+ case 'c':
+ ret << service.name().replace( '%', "%%" );
+ break;
+ case 'k':
+ ret << service.desktopEntryPath().replace( '%', "%%" );
+ break;
+ case 'i':
+ ret << "-icon" << service.icon().replace( '%', "%%" );
+ break;
+ case 'm':
+ ret << "-miniicon" << service.icon().replace( '%', "%%" );
+ break;
+ case 'u':
+ case 'U':
+ hasUrls = true;
+ /* fallthrough */
+ case 'f':
+ case 'F':
+ case 'n':
+ case 'N':
+ case 'd':
+ case 'D':
+ case 'v':
+ hasSpec = true;
+ /* fallthrough */
+ default:
+ return -2; // subst with same and skip
+ }
+ return 2;
+}
+
+class KRunMX2 : public KMacroExpanderBase {
+public:
+ KRunMX2( const KURL::List &_urls ) :
+ KMacroExpanderBase( '%' ), ignFile( false ), urls( _urls ) {}
+ bool ignFile:1;
+
+protected:
+ virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
+
+private:
+ void subst( int option, const KURL &url, TQStringList &ret );
+
+ const KURL::List &urls;
+};
+
+void
+KRunMX2::subst( int option, const KURL &url, TQStringList &ret )
+{
+ switch( option ) {
+ case 'u':
+ ret << url.pathOrURL();
+ break;
+ case 'd':
+ ret << url.directory();
+ break;
+ case 'f':
+ ret << url.path();
+ break;
+ case 'n':
+ ret << url.fileName();
+ break;
+ case 'v':
+ if (url.isLocalFile() && TQFile::exists( url.path() ) )
+ ret << KDesktopFile( url.path(), true ).readEntry( "Dev" );
+ break;
+ }
+ return;
+}
+
+int
+KRunMX2::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
+{
+ uint option = str[pos + 1];
+ switch( option ) {
+ case 'f':
+ case 'u':
+ case 'n':
+ case 'd':
+ case 'v':
+ if( urls.isEmpty() ) {
+ if (!ignFile)
+ kdDebug() << "KRun::processDesktopExec: No URLs supplied to single-URL service " << str << endl;
+ } else if( urls.count() > 1 )
+ kdWarning() << "KRun::processDesktopExec: " << urls.count() << " URLs supplied to single-URL service " << str << endl;
+ else
+ subst( option, urls.first(), ret );
+ break;
+ case 'F':
+ case 'U':
+ case 'N':
+ case 'D':
+ option += 'a' - 'A';
+ for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it )
+ subst( option, *it, ret );
+ break;
+ case '%':
+ ret = "%";
+ break;
+ default:
+ return -2; // subst with same and skip
+ }
+ return 2;
+}
+
+// BIC: merge methods below
+TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell) {
+ return processDesktopExec( _service, _urls, has_shell, false, TQString::null );
+}
+
+TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell /* KDE4: remove */, bool tempFiles)
+{
+ return processDesktopExec( _service, _urls, has_shell, tempFiles, TQString::null );
+}
+
+TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell /* KDE4: remove */, bool tempFiles, const TQString& suggestedFileName)
+{
+ TQString exec = _service.exec();
+ TQStringList result;
+ bool appHasTempFileOption;
+
+ KRunMX1 mx1( _service );
+ KRunMX2 mx2( _urls );
+
+ /// compatibility hack -- KDE 4: remove
+ TQRegExp re("^\\s*(?:/bin/)?sh\\s+-c\\s+(.*)$");
+ if (!re.search( exec )) {
+ exec = TQString(re.cap( 1 )).stripWhiteSpace();
+ for (uint pos = 0; pos < exec.length(); ) {
+ TQChar c = exec.unicode()[pos];
+ if (c != '\'' && c != '"')
+ goto synerr; // what else can we do? after normal parsing the substs would be insecure
+ int pos2 = exec.find( c, pos + 1 ) - 1;
+ if (pos2 < 0)
+ goto synerr; // quoting error
+ memcpy( (void *)(exec.unicode() + pos), exec.unicode() + pos + 1, (pos2 - pos) * sizeof(TQChar));
+ pos = pos2;
+ exec.remove( pos, 2 );
+ }
+ }
+
+ if( !mx1.expandMacrosShellQuote( exec ) )
+ goto synerr; // error in shell syntax
+
+ // FIXME: the current way of invoking tdeioexec disables term and su use
+
+ // Check if we need "tempexec" (tdeioexec in fact)
+ appHasTempFileOption = tempFiles && _service.property("X-TDE-HasTempFileOption").toBool();
+ if( tempFiles && !appHasTempFileOption && _urls.size() ) {
+ result << "tdeioexec" << "--tempfiles" << exec;
+ result += _urls.toStringList();
+ if (has_shell)
+ result = KShell::joinArgs( result );
+ return result;
+ }
+
+ // Check if we need tdeioexec
+ if( !mx1.hasUrls ) {
+ for( KURL::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it )
+ if ( !(*it).isLocalFile() && !KProtocolInfo::isHelperProtocol(*it) ) {
+ // We need to run the app through tdeioexec
+ result << "tdeioexec";
+ if ( tempFiles )
+ result << "--tempfiles";
+ if ( !suggestedFileName.isEmpty() ) {
+ result << "--suggestedfilename";
+ result << suggestedFileName;
+ }
+ result << exec;
+ result += _urls.toStringList();
+ if (has_shell)
+ result = KShell::joinArgs( result );
+ return result;
+ }
+ }
+
+ if ( appHasTempFileOption )
+ exec += " --tempfile";
+
+ // Did the user forget to append something like '%f'?
+ // If so, then assume that '%f' is the right choice => the application
+ // accepts only local files.
+ if( !mx1.hasSpec ) {
+ exec += " %f";
+ mx2.ignFile = true;
+ }
+
+ mx2.expandMacrosShellQuote( exec ); // syntax was already checked, so don't check return value
+
+/*
+ 1 = need_shell, 2 = terminal, 4 = su, 8 = has_shell
+
+ 0 << split(cmd)
+ 1 << "sh" << "-c" << cmd
+ 2 << split(term) << "-e" << split(cmd)
+ 3 << split(term) << "-e" << "sh" << "-c" << cmd
+
+ 4 << "tdesu" << "-u" << user << "-c" << cmd
+ 5 << "tdesu" << "-u" << user << "-c" << ("sh -c " + quote(cmd))
+ 6 << split(term) << "-e" << "su" << user << "-c" << cmd
+ 7 << split(term) << "-e" << "su" << user << "-c" << ("sh -c " + quote(cmd))
+
+ 8 << cmd
+ 9 << cmd
+ a << term << "-e" << cmd
+ b << term << "-e" << ("sh -c " + quote(cmd))
+
+ c << "tdesu" << "-u" << user << "-c" << quote(cmd)
+ d << "tdesu" << "-u" << user << "-c" << quote("sh -c " + quote(cmd))
+ e << term << "-e" << "su" << user << "-c" << quote(cmd)
+ f << term << "-e" << "su" << user << "-c" << quote("sh -c " + quote(cmd))
+
+ "sh -c" is needed in the "su" case, too, as su uses the user's login shell, not sh.
+ this could be optimized with the -s switch of some su versions (e.g., debian linux).
+*/
+
+ if (_service.terminal()) {
+ TDEConfigGroupSaver gs(TDEGlobal::config(), "General");
+ TQString terminal = TDEGlobal::config()->readPathEntry("TerminalApplication", "konsole");
+ if (terminal == "konsole")
+ terminal += " -caption=%c %i %m";
+ terminal += " ";
+ terminal += _service.terminalOptions();
+ if( !mx1.expandMacrosShellQuote( terminal ) ) {
+ kdWarning() << "KRun: syntax error in command `" << terminal << "', service `" << _service.name() << "'" << endl;
+ return TQStringList();
+ }
+ mx2.expandMacrosShellQuote( terminal );
+ if (has_shell)
+ result << terminal;
+ else
+ result = KShell::splitArgs( terminal ); // assuming that the term spec never needs a shell!
+ result << "-e";
+ }
+
+ int err;
+ if (_service.substituteUid()) {
+ if (_service.terminal())
+ result << "su";
+ else
+ result << "tdesu" << "-u";
+ result << _service.username() << "-c";
+ KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
+ if (err == KShell::FoundMeta) {
+ shellQuote( exec );
+ exec.prepend( "/bin/sh -c " );
+ } else if (err != KShell::NoError)
+ goto synerr;
+ if (has_shell)
+ shellQuote( exec );
+ result << exec;
+ } else {
+ if (has_shell) {
+ if (_service.terminal()) {
+ KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
+ if (err == KShell::FoundMeta) {
+ shellQuote( exec );
+ exec.prepend( "/bin/sh -c " );
+ } else if (err != KShell::NoError)
+ goto synerr;
+ }
+ result << exec;
+ } else {
+ result += KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
+ if (err == KShell::FoundMeta)
+ result << "/bin/sh" << "-c" << exec;
+ else if (err != KShell::NoError)
+ goto synerr;
+ }
+ }
+
+ return result;
+
+ synerr:
+ kdWarning() << "KRun: syntax error in command `" << _service.exec() << "', service `" << _service.name() << "'" << endl;
+ return TQStringList();
+}
+
+//static
+TQString KRun::binaryName( const TQString & execLine, bool removePath )
+{
+ // Remove parameters and/or trailing spaces.
+ TQStringList args = KShell::splitArgs( execLine );
+ for (TQStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
+ if (!(*it).contains('='))
+ // Remove path if wanted
+ return removePath ? (*it).mid(TQString(*it).findRev('/') + 1) : *it;
+ return TQString();
+}
+
+static pid_t runCommandInternal( TDEProcess* proc, const KService* service, const TQString& binName,
+ const TQString &execName, const TQString & iconName, TQWidget* window, TQCString asn )
+{
+ if (service && !service->desktopEntryPath().isEmpty()
+ && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
+ {
+ kdWarning() << "No authorization to execute " << service->desktopEntryPath() << endl;
+ KMessageBox::sorry(window, i18n("You are not authorized to execute this file."));
+ return 0;
+ }
+ TQString bin = KRun::binaryName( binName, true );
+#ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
+ bool silent;
+ TQCString wmclass;
+ KStartupInfoId id;
+ bool startup_notify = ( asn != "0" && KRun::checkStartupNotify( binName, service, &silent, &wmclass ));
+ if( startup_notify )
+ {
+ id.initId( asn );
+ id.setupStartupEnv();
+ KStartupInfoData data;
+ data.setHostname();
+ data.setBin( bin );
+ if( !execName.isEmpty())
+ data.setName( execName );
+ else if( service && !service->name().isEmpty())
+ data.setName( service->name());
+ data.setDescription( i18n( "Launching %1" ).arg( data.name()));
+ if( !iconName.isEmpty())
+ data.setIcon( iconName );
+ else if( service && !service->icon().isEmpty())
+ data.setIcon( service->icon());
+ if( !wmclass.isEmpty())
+ data.setWMClass( wmclass );
+ if( silent )
+ data.setSilent( KStartupInfoData::Yes );
+ data.setDesktop( KWin::currentDesktop());
+ if( window )
+ data.setLaunchedBy( window->winId());
+ KStartupInfo::sendStartup( id, data );
+ }
+ pid_t pid = TDEProcessRunner::run( proc, binName, id );
+ if( startup_notify && pid )
+ {
+ KStartupInfoData data;
+ data.addPid( pid );
+ KStartupInfo::sendChange( id, data );
+ KStartupInfo::resetStartupEnv();
+ }
+ return pid;
+#else
+ Q_UNUSED( execName );
+ Q_UNUSED( iconName );
+ return TDEProcessRunner::run( proc, bin );
+#endif
+}
+
+// This code is also used in tdelauncher.
+bool KRun::checkStartupNotify( const TQString& /*binName*/, const KService* service, bool* silent_arg, TQCString* wmclass_arg )
+{
+ bool silent = false;
+ TQCString wmclass;
+ if( service && service->property( "StartupNotify" ).isValid())
+ {
+ silent = !service->property( "StartupNotify" ).toBool();
+ wmclass = service->property( "StartupWMClass" ).toString().latin1();
+ }
+ else if( service && service->property( "X-TDE-StartupNotify" ).isValid())
+ {
+ silent = !service->property( "X-TDE-StartupNotify" ).toBool();
+ wmclass = service->property( "X-TDE-WMClass" ).toString().latin1();
+ }
+ else // non-compliant app
+ {
+ if( service )
+ {
+ if( service->type() == "Application" )
+ wmclass = "0"; // doesn't have .desktop entries needed, start as non-compliant
+ else
+ return false; // no startup notification at all
+ }
+ else
+ {
+#if 0
+ // Create startup notification even for apps for which there shouldn't be any,
+ // just without any visual feedback. This will ensure they'll be positioned on the proper
+ // virtual desktop, and will get user timestamp from the ASN ID.
+ wmclass = "0";
+ silent = true;
+#else // That unfortunately doesn't work, when the launched non-compliant application
+ // launches another one that is compliant and there is any delay inbetween (bnc:#343359)
+ return false;
+#endif
+ }
+ }
+ if( silent_arg != NULL )
+ *silent_arg = silent;
+ if( wmclass_arg != NULL )
+ *wmclass_arg = wmclass;
+ return true;
+}
+
+static pid_t runTempService( const KService& _service, const KURL::List& _urls, TQWidget* window,
+ const TQCString& asn, bool tempFiles, const TQString& suggestedFileName )
+{
+ if (!_urls.isEmpty()) {
+ kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
+ }
+
+ TQStringList args;
+ if ((_urls.count() > 1) && !_service.allowMultipleFiles())
+ {
+ // We need to launch the application N times. That sucks.
+ // We ignore the result for application 2 to N.
+ // For the first file we launch the application in the
+ // usual way. The reported result is based on this
+ // application.
+ KURL::List::ConstIterator it = _urls.begin();
+ while(++it != _urls.end())
+ {
+ KURL::List singleUrl;
+ singleUrl.append(*it);
+ runTempService( _service, singleUrl, window, "", tempFiles, suggestedFileName );
+ }
+ KURL::List singleUrl;
+ singleUrl.append(_urls.first());
+ args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles, suggestedFileName);
+ }
+ else
+ {
+ args = KRun::processDesktopExec(_service, _urls, false, tempFiles, suggestedFileName);
+ }
+ kdDebug(7010) << "runTempService: TDEProcess args=" << args << endl;
+
+ TDEProcess * proc = new TDEProcess;
+ *proc << args;
+
+ if (!_service.path().isEmpty())
+ proc->setWorkingDirectory(_service.path());
+
+ return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
+ _service.name(), _service.icon(), window, asn );
+}
+
+// WARNING: don't call this from processDesktopExec, since tdelauncher uses that too...
+static KURL::List resolveURLs( const KURL::List& _urls, const KService& _service )
+{
+ // Check which protocols the application supports.
+ // This can be a list of actual protocol names, or just KIO for KDE apps.
+ TQStringList supportedProtocols = _service.property("X-TDE-Protocols").toStringList();
+ KRunMX1 mx1( _service );
+ TQString exec = _service.exec();
+ if ( mx1.expandMacrosShellQuote( exec ) && !mx1.hasUrls ) {
+ Q_ASSERT( supportedProtocols.isEmpty() ); // huh? If you support protocols you need %u or %U...
+ } else {
+ if ( supportedProtocols.isEmpty() )
+ {
+ // compat mode: assume KIO if not set and it's a KDE app
+ TQStringList categories = _service.property("Categories").toStringList();
+ if (( categories.find("TDE") != categories.end() ) && ( categories.find("KDE") != categories.end() ))
+ supportedProtocols.append( "KIO" );
+ else { // if no KDE app, be a bit over-generic
+ supportedProtocols.append( "http");
+ supportedProtocols.append( "ftp");
+ }
+ }
+ }
+ kdDebug(7010) << "supportedProtocols:" << supportedProtocols << endl;
+
+ KURL::List urls( _urls );
+ if ( supportedProtocols.find( "KIO" ) == supportedProtocols.end() ) {
+ for( KURL::List::Iterator it = urls.begin(); it != urls.end(); ++it ) {
+ const KURL url = *it;
+ bool supported = url.isLocalFile() || supportedProtocols.find( url.protocol().lower() ) != supportedProtocols.end();
+ kdDebug(7010) << "Looking at url=" << url << " supported=" << supported << endl;
+ if ( !supported && KProtocolInfo::protocolClass(url.protocol()) == ":local" )
+ {
+ // Maybe we can resolve to a local URL?
+ KURL localURL = TDEIO::NetAccess::mostLocalURL( url, 0 );
+ if ( localURL != url ) {
+ *it = localURL;
+ kdDebug(7010) << "Changed to " << localURL << endl;
+ }
+ }
+ }
+ }
+ return urls;
+}
+
+// BIC merge methods below
+pid_t KRun::run( const KService& _service, const KURL::List& _urls )
+{
+ return run( _service, _urls, 0, false, TQString::null );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
+{
+ return run( _service, _urls, 0, tempFiles, TQString::null );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles )
+{
+ return run( _service, _urls, window, "", tempFiles, TQString::null );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, const TQCString& asn, bool tempFiles )
+{
+ return run( _service, _urls, window, asn, tempFiles, TQString::null );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles, const TQString& suggestedFileName )
+{
+ return run( _service, _urls, window, "", tempFiles, suggestedFileName );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, const TQCString& asn,
+ bool tempFiles, const TQString& suggestedFileName )
+{
+ if (!_service.desktopEntryPath().isEmpty() &&
+ !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
+ {
+ kdWarning() << "No authorization to execute " << _service.desktopEntryPath() << endl;
+ KMessageBox::sorry(window, i18n("You are not authorized to execute this service."));
+ return 0;
+ }
+
+ if ( !tempFiles )
+ {
+ // Remember we opened those urls, for the "recent documents" menu in kicker
+ KURL::List::ConstIterator it = _urls.begin();
+ for(; it != _urls.end(); ++it) {
+ //kdDebug(7010) << "KRecentDocument::adding " << (*it).url() << endl;
+ KRecentDocument::add( *it, _service.desktopEntryName() );
+ }
+ }
+
+ if ( tempFiles || _service.desktopEntryPath().isEmpty() || !suggestedFileName.isEmpty() )
+ {
+ return runTempService(_service, _urls, window, asn, tempFiles, suggestedFileName);
+ }
+
+ kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
+
+ if (!_urls.isEmpty()) {
+ kdDebug(7010) << "First url " << _urls.first().url() << endl;
+ }
+
+ // Resolve urls if needed, depending on what the app supports
+ const KURL::List urls = resolveURLs( _urls, _service );
+
+ TQString error;
+ int pid = 0;
+
+ TQCString myasn = asn;
+ // startServiceByDesktopPath() doesn't take TQWidget*, add it to the startup info now
+ if( window != NULL )
+ {
+ if( myasn.isEmpty())
+ myasn = KStartupInfo::createNewStartupId();
+ if( myasn != "0" )
+ {
+ KStartupInfoId id;
+ id.initId( myasn );
+ KStartupInfoData data;
+ data.setLaunchedBy( window->winId());
+ KStartupInfo::sendChange( id, data );
+ }
+ }
+
+ int i = TDEApplication::startServiceByDesktopPath(
+ _service.desktopEntryPath(), urls.toStringList(), &error, 0L, &pid, myasn
+ );
+
+ if (i != 0)
+ {
+ kdDebug(7010) << error << endl;
+ KMessageBox::sorry( window, error );
+ return 0;
+ }
+
+ kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
+ return (pid_t) pid;
+}
+
+
+pid_t KRun::run( const TQString& _exec, const KURL::List& _urls, const TQString& _name,
+ const TQString& _icon, const TQString&, const TQString&)
+{
+ KService::Ptr service = new KService(_name, _exec, _icon);
+
+ return run(*service, _urls);
+}
+
+pid_t KRun::runCommand( TQString cmd )
+{
+ return KRun::runCommand( cmd, TQString::null, TQString::null, NULL, "" );
+}
+
+pid_t KRun::runCommand( const TQString& cmd, const TQString &execName, const TQString & iconName )
+{
+ return KRun::runCommand( cmd, execName, iconName, NULL, "" );
+}
+
+pid_t KRun::runCommand( const TQString& cmd, const TQString &execName, const TQString & iconName,
+ TQWidget* window, const TQCString& asn )
+{
+ kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
+ TDEProcess * proc = new TDEProcess;
+ proc->setUseShell(true);
+ *proc << cmd;
+ KService::Ptr service = KService::serviceByDesktopName( binaryName( execName, true ) );
+ TQString bin = binaryName( cmd, false );
+ int pos = bin.findRev( '/' );
+ if (pos != -1) {
+ proc->setWorkingDirectory( bin.mid(0, pos) );
+ }
+ return runCommandInternal( proc, service.data(), binaryName( execName, false ), execName, iconName, window, asn );
+}
+
+KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
+ :m_timer(0,"KRun::timer")
+{
+ init (url, 0, "", mode, isLocalFile, showProgressInfo);
+}
+
+KRun::KRun( const KURL& url, TQWidget* window, mode_t mode, bool isLocalFile,
+ bool showProgressInfo )
+ :m_timer(0,"KRun::timer")
+{
+ init (url, window, "", mode, isLocalFile, showProgressInfo);
+}
+
+KRun::KRun( const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode, bool isLocalFile,
+ bool showProgressInfo )
+ :m_timer(0,"KRun::timer")
+{
+ init (url, window, asn, mode, isLocalFile, showProgressInfo);
+}
+
+void KRun::init ( const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode, bool isLocalFile,
+ bool showProgressInfo )
+{
+ m_bFault = false;
+ m_bAutoDelete = true;
+ m_bProgressInfo = showProgressInfo;
+ m_bFinished = false;
+ m_job = 0L;
+ m_strURL = url;
+ m_bScanFile = false;
+ m_bIsDirectory = false;
+ m_bIsLocalFile = isLocalFile;
+ m_mode = mode;
+ d = new KRunPrivate;
+ d->m_runExecutables = true;
+ d->m_window = window;
+ d->m_asn = asn;
+ setEnableExternalBrowser(true);
+
+ // Start the timer. This means we will return to the event
+ // loop and do initialization afterwards.
+ // Reason: We must complete the constructor before we do anything else.
+ m_bInit = true;
+ connect( &m_timer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotTimeout() ) );
+ m_timer.start( 0, true );
+ kdDebug(7010) << " new KRun " << this << " " << url.prettyURL() << " timer=" << &m_timer << endl;
+
+ kapp->ref();
+}
+
+void KRun::init()
+{
+ kdDebug(7010) << "INIT called" << endl;
+
+ bool bypassErrorMessage = false;
+
+ if (m_strURL.url().startsWith("$(")) {
+ // check for environment variables and make necessary translations
+ TQString aValue = m_strURL.url();
+ int nDollarPos = aValue.find( '$' );
+
+ while( nDollarPos != -1 && nDollarPos+1 < static_cast<int>(aValue.length())) {
+ // there is at least one $
+ if( (aValue)[nDollarPos+1] == '(' ) {
+ uint nEndPos = nDollarPos+1;
+ // the next character is no $
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=')') )
+ nEndPos++;
+ nEndPos++;
+ TQString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+
+ TQString result;
+ FILE *fs = popen(TQFile::encodeName(cmd).data(), "r");
+ if (fs)
+ {
+ {
+ TQTextStream ts(fs, IO_ReadOnly);
+ result = ts.read().stripWhiteSpace();
+ }
+ pclose(fs);
+ }
+ aValue.replace( nDollarPos, nEndPos-nDollarPos, result );
+ } else if( (aValue)[nDollarPos+1] != '$' ) {
+ uint nEndPos = nDollarPos+1;
+ // the next character is no $
+ TQString aVarName;
+ if (aValue[nEndPos]=='{')
+ {
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!='}') )
+ nEndPos++;
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+ }
+ else
+ {
+ while ( nEndPos <= aValue.length() && (aValue[nEndPos].isNumber()
+ || aValue[nEndPos].isLetter() || aValue[nEndPos]=='_' ) )
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
+ }
+ const char* pEnv = 0;
+ if (!aVarName.isEmpty())
+ pEnv = getenv( aVarName.ascii() );
+ if( pEnv ) {
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // A environment variables may contain values in 8bit
+ // locale cpecified encoding or in UTF8 encoding.
+ aValue.replace( nDollarPos, nEndPos-nDollarPos, KStringHandler::from8Bit( pEnv ) );
+ } else
+ aValue.remove( nDollarPos, nEndPos-nDollarPos );
+ } else {
+ // remove one of the dollar signs
+ aValue.remove( nDollarPos, 1 );
+ nDollarPos++;
+ }
+ nDollarPos = aValue.find( '$', nDollarPos );
+ }
+ m_strURL = KURL(aValue);
+ bypassErrorMessage = true;
+ }
+
+ if ( !m_strURL.isValid() )
+ {
+ if (bypassErrorMessage == false) {
+ d->m_showingError = true;
+ KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
+ d->m_showingError = false;
+ }
+ m_bFault = true;
+ m_bFinished = true;
+ m_timer.start( 0, true );
+ return;
+ }
+ if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
+ {
+ TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
+ d->m_showingError = true;
+ KMessageBoxWrapper::error( d->m_window, msg );
+ d->m_showingError = false;
+ m_bFault = true;
+ m_bFinished = true;
+ m_timer.start( 0, true );
+ return;
+ }
+
+ if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
+ m_bIsLocalFile = true;
+
+ TQString exec;
+ if (m_strURL.protocol().startsWith("http"))
+ {
+ exec = d->m_externalBrowser;
+ }
+
+ if ( m_bIsLocalFile )
+ {
+ if ( m_mode == 0 )
+ {
+ KDE_struct_stat buff;
+ if ( KDE_stat( TQFile::encodeName(m_strURL.path()), &buff ) == -1 )
+ {
+ d->m_showingError = true;
+ KMessageBoxWrapper::error( d->m_window, i18n( "<qt>Unable to run the command specified. The file or folder <b>%1</b> does not exist.</qt>" ).arg( m_strURL.htmlURL() ) );
+ d->m_showingError = false;
+ m_bFault = true;
+ m_bFinished = true;
+ m_timer.start( 0, true );
+ return;
+ }
+ m_mode = buff.st_mode;
+ }
+
+ KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
+ assert( mime != 0L );
+ kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
+ foundMimeType( mime->name() );
+ return;
+ }
+ else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( m_strURL ) ) {
+ kdDebug(7010) << "Helper protocol" << endl;
+
+ bool ok = false;
+ KURL::List urls;
+ if (!((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")))
+ urls.append( m_strURL );
+ if (exec.isEmpty())
+ {
+ exec = KProtocolInfo::exec( m_strURL.protocol() );
+ if (exec.isEmpty())
+ {
+ foundMimeType(KProtocolInfo::defaultMimetype(m_strURL));
+ return;
+ }
+ run( exec, urls );
+ ok = true;
+ }
+ else if (exec.startsWith("!"))
+ {
+ exec = exec.mid(1); // Literal command
+ exec += " %u";
+ run( exec, urls );
+ ok = true;
+ }
+ else
+ {
+ KService::Ptr service = KService::serviceByStorageId( exec );
+ if (service)
+ {
+ run( *service, urls, d->m_window, d->m_asn );
+ ok = true;
+ }
+ }
+
+ if (ok)
+ {
+ m_bFinished = true;
+ // will emit the error and autodelete this
+ m_timer.start( 0, true );
+ return;
+ }
+ }
+
+ if ((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")) {
+ KURL::List urls;
+ run( "kfmclient openProfile webbrowsing", urls );
+ m_bFinished = true;
+ // will emit the error and autodelete this
+ m_timer.start( 0, true );
+ return;
+ }
+
+ // Did we already get the information that it is a directory ?
+ if ( S_ISDIR( m_mode ) )
+ {
+ foundMimeType( "inode/directory" );
+ return;
+ }
+
+ // Let's see whether it is a directory
+
+ if ( !KProtocolInfo::supportsListing( m_strURL ) )
+ {
+ //kdDebug(7010) << "Protocol has no support for listing" << endl;
+ // No support for listing => it can't be a directory (example: http)
+ scanFile();
+ return;
+ }
+
+ kdDebug(7010) << "Testing directory (stating)" << endl;
+
+ // It may be a directory or a file, let's stat
+ TDEIO::StatJob *job = TDEIO::stat( m_strURL, true, 0 /* no details */, m_bProgressInfo );
+ job->setWindow (d->m_window);
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ this, TQT_SLOT( slotStatResult( TDEIO::Job * ) ) );
+ m_job = job;
+ kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
+}
+
+KRun::~KRun()
+{
+ kdDebug(7010) << "KRun::~KRun() " << this << endl;
+ m_timer.stop();
+ killJob();
+ kapp->deref();
+ kdDebug(7010) << "KRun::~KRun() done " << this << endl;
+ delete d;
+}
+
+void KRun::scanFile()
+{
+ kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
+ // First, let's check for well-known extensions
+ // Not when there is a query in the URL, in any case.
+ if ( m_strURL.query().isEmpty() )
+ {
+ KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
+ assert( mime != 0L );
+ if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
+ {
+ kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
+ foundMimeType( mime->name() );
+ return;
+ }
+ }
+
+ // No mimetype found, and the URL is not local (or fast mode not allowed).
+ // We need to apply the 'KIO' method, i.e. either asking the server or
+ // getting some data out of the file, to know what mimetype it is.
+
+ if ( !KProtocolInfo::supportsReading( m_strURL ) )
+ {
+ kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
+ m_bFault = true;
+ m_bFinished = true;
+ m_timer.start( 0, true );
+ return;
+ }
+ kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
+
+ TDEIO::TransferJob *job = TDEIO::get( m_strURL, false /*reload*/, m_bProgressInfo );
+ job->setWindow (d->m_window);
+ connect(job, TQT_SIGNAL( result(TDEIO::Job *)),
+ this, TQT_SLOT( slotScanFinished(TDEIO::Job *)));
+ connect(job, TQT_SIGNAL( mimetype(TDEIO::Job *, const TQString &)),
+ this, TQT_SLOT( slotScanMimeType(TDEIO::Job *, const TQString &)));
+ m_job = job;
+ kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
+}
+
+void KRun::slotTimeout()
+{
+ kdDebug(7010) << this << " slotTimeout called" << endl;
+ if ( m_bInit )
+ {
+ m_bInit = false;
+ init();
+ return;
+ }
+
+ if ( m_bFault ) {
+ emit error();
+ }
+ if ( m_bFinished ) {
+ emit finished();
+ }
+ else
+ {
+ if ( m_bScanFile )
+ {
+ m_bScanFile = false;
+ scanFile();
+ return;
+ }
+ else if ( m_bIsDirectory )
+ {
+ m_bIsDirectory = false;
+ foundMimeType( "inode/directory" );
+ return;
+ }
+ }
+
+ if ( m_bAutoDelete )
+ {
+ delete this;
+ return;
+ }
+}
+
+void KRun::slotStatResult( TDEIO::Job * job )
+{
+ m_job = 0L;
+ if (job->error())
+ {
+ d->m_showingError = true;
+ kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
+ job->showErrorDialog();
+ //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
+ d->m_showingError = false;
+
+ m_bFault = true;
+ m_bFinished = true;
+
+ // will emit the error and autodelete this
+ m_timer.start( 0, true );
+
+ } else {
+
+ kdDebug(7010) << "Finished" << endl;
+ if(!dynamic_cast<TDEIO::StatJob*>(job))
+ kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
+
+ TQString knownMimeType;
+ TDEIO::UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
+ TDEIO::UDSEntry::ConstIterator it = entry.begin();
+ for( ; it != entry.end(); it++ ) {
+ switch( (*it).m_uds ) {
+ case TDEIO::UDS_FILE_TYPE:
+ if ( S_ISDIR( (mode_t)((*it).m_long) ) )
+ m_bIsDirectory = true; // it's a dir
+ else
+ m_bScanFile = true; // it's a file
+ break;
+ case TDEIO::UDS_MIME_TYPE: // mimetype already known? (e.g. print:/manager)
+ knownMimeType = (*it).m_str;
+ break;
+ case TDEIO::UDS_LOCAL_PATH:
+ d->m_localPath = (*it).m_str;
+ break;
+ default:
+ break;
+ }
+ }
+ if ( !knownMimeType.isEmpty() )
+ {
+ foundMimeType( knownMimeType );
+ m_bFinished = true;
+ }
+
+ // We should have found something
+ assert ( m_bScanFile || m_bIsDirectory );
+
+ // Start the timer. Once we get the timer event this
+ // protocol server is back in the pool and we can reuse it.
+ // This gives better performance than starting a new slave
+ m_timer.start( 0, true );
+ }
+}
+
+void KRun::slotScanMimeType( TDEIO::Job *, const TQString &mimetype )
+{
+ if ( mimetype.isEmpty() )
+ kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a tdeioslave bug." << endl;
+ foundMimeType( mimetype );
+ m_job = 0;
+}
+
+void KRun::slotScanFinished( TDEIO::Job *job )
+{
+ m_job = 0;
+ if (job->error())
+ {
+ d->m_showingError = true;
+ kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
+ job->showErrorDialog();
+ //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
+ d->m_showingError = false;
+
+ m_bFault = true;
+ m_bFinished = true;
+
+ // will emit the error and autodelete this
+ m_timer.start( 0, true );
+ }
+}
+
+void KRun::foundMimeType( const TQString& type )
+{
+ kdDebug(7010) << "Resulting mime type is " << type << endl;
+
+/*
+ // Automatically unzip stuff
+
+ // Disabled since the new KIO doesn't have filters yet.
+
+ if ( type == "application/x-gzip" ||
+ type == "application/x-bzip" ||
+ type == "application/x-bzip2" )
+ {
+ KURL::List lst = KURL::split( m_strURL );
+ if ( lst.isEmpty() )
+ {
+ TQString tmp = i18n( "Malformed URL" );
+ tmp += "\n";
+ tmp += m_strURL.url();
+ KMessageBoxWrapper::error( 0L, tmp );
+ return;
+ }
+
+ if ( type == "application/x-gzip" )
+ lst.prepend( KURL( "gzip:/decompress" ) );
+ else if ( type == "application/x-bzip" )
+ lst.prepend( KURL( "bzip:/decompress" ) );
+ else if ( type == "application/x-bzip2" )
+ lst.prepend( KURL( "bzip2:/decompress" ) );
+ else if ( type == "application/x-tar" )
+ lst.prepend( KURL( "tar:/" ) );
+
+ // Move the HTML style reference to the leftmost URL
+ KURL::List::Iterator it = lst.begin();
+ ++it;
+ (*lst.begin()).setRef( (*it).ref() );
+ (*it).setRef( TQString::null );
+
+ // Create the new URL
+ m_strURL = KURL::join( lst );
+
+ kdDebug(7010) << "Now trying with " << debugString(m_strURL.url()) << endl;
+
+ killJob();
+
+ // We don't know if this is a file or a directory. Let's test this first.
+ // (For instance a tar.gz is a directory contained inside a file)
+ // It may be a directory or a file, let's stat
+ TDEIO::StatJob *job = TDEIO::stat( m_strURL, m_bProgressInfo );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ this, TQT_SLOT( slotStatResult( TDEIO::Job * ) ) );
+ m_job = job;
+
+ return;
+ }
+*/
+ TDEIO::TransferJob *job = ::tqqt_cast<TDEIO::TransferJob *>( m_job );
+ if ( job )
+ {
+ job->putOnHold();
+ TDEIO::Scheduler::publishSlaveOnHold();
+ m_job = 0;
+ }
+
+ Q_ASSERT( !m_bFinished );
+
+ // Suport for preferred service setting, see setPreferredService
+ if ( !d->m_preferredService.isEmpty() ) {
+ kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
+ KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
+ if ( serv && serv->hasServiceType( type ) )
+ {
+ KURL::List lst;
+ lst.append( m_strURL );
+ m_bFinished = KRun::run( *serv, lst, d->m_window, d->m_asn );
+ /// Note: the line above means that if that service failed, we'll
+ /// go to runURL to maybe find another service, even though a dialog
+ /// box was displayed. That's good if runURL tries another service,
+ /// but it's not good if it tries the same one :}
+ }
+ }
+
+ // Resolve .desktop files from media:/, remote:/, applications:/ etc.
+ if ( ((type == "application/x-desktop") ||
+ (type == "media/builtin-mydocuments") ||
+ (type == "media/builtin-mycomputer") ||
+ (type == "media/builtin-mynetworkplaces") ||
+ (type == "media/builtin-printers") ||
+ (type == "media/builtin-trash") ||
+ (type == "media/builtin-webbrowser")) /* or inheriting? */ && (!d->m_localPath.isEmpty()) )
+ {
+ m_strURL = KURL();
+ m_strURL.setPath( d->m_localPath );
+ }
+
+ if (!m_bFinished && KRun::runURL( m_strURL, type, d->m_window, d->m_asn, false, d->m_runExecutables, d->m_suggestedFileName )){
+ m_bFinished = true;
+ }
+ else{
+ m_bFinished = true;
+ m_bFault = true;
+ }
+
+ m_timer.start( 0, true );
+}
+
+void KRun::killJob()
+{
+ if ( m_job )
+ {
+ kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
+ m_job->kill();
+ m_job = 0L;
+ }
+}
+
+void KRun::abort()
+{
+ kdDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
+ killJob();
+ // If we're showing an error message box, the rest will be done
+ // after closing the msgbox -> don't autodelete nor emit signals now.
+ if ( d->m_showingError )
+ return;
+ m_bFault = true;
+ m_bFinished = true;
+ m_bInit = false;
+ m_bScanFile = false;
+
+ // will emit the error and autodelete this
+ m_timer.start( 0, true );
+}
+
+void KRun::setEnableExternalBrowser(bool b)
+{
+ if (b)
+ d->m_externalBrowser = TDEConfigGroup(TDEGlobal::config(), "General").readEntry("BrowserApplication");
+ else
+ d->m_externalBrowser = TQString::null;
+}
+
+void KRun::setPreferredService( const TQString& desktopEntryName )
+{
+ d->m_preferredService = desktopEntryName;
+}
+
+void KRun::setRunExecutables(bool b)
+{
+ d->m_runExecutables = b;
+}
+
+void KRun::setSuggestedFileName( const TQString& fileName )
+{
+ d->m_suggestedFileName = fileName;
+}
+
+bool KRun::isExecutable( const TQString& serviceType )
+{
+ return ( serviceType == "application/x-desktop" ||
+ serviceType == "media/builtin-mydocuments" ||
+ serviceType == "media/builtin-mycomputer" ||
+ serviceType == "media/builtin-mynetworkplaces" ||
+ serviceType == "media/builtin-printers" ||
+ serviceType == "media/builtin-trash" ||
+ serviceType == "media/builtin-webbrowser" ||
+ serviceType == "application/x-executable" ||
+ serviceType == "application/x-msdos-program" ||
+ serviceType == "application/x-shellscript" );
+}
+
+/****************/
+
+pid_t
+TDEProcessRunner::run(TDEProcess * p, const TQString & binName)
+{
+ return (new TDEProcessRunner(p, binName))->pid();
+}
+
+#ifdef Q_WS_X11
+pid_t
+TDEProcessRunner::run(TDEProcess * p, const TQString & binName, const KStartupInfoId& id )
+{
+ return (new TDEProcessRunner(p, binName, id))->pid();
+}
+#endif
+
+TDEProcessRunner::TDEProcessRunner(TDEProcess * p, const TQString & _binName )
+ : TQObject(),
+ process_(p),
+ binName( _binName )
+{
+ TQObject::connect(
+ process_, TQT_SIGNAL(processExited(TDEProcess *)),
+ this, TQT_SLOT(slotProcessExited(TDEProcess *)));
+
+ process_->start();
+ if ( !process_->pid() )
+ slotProcessExited( process_ );
+}
+
+#ifdef Q_WS_X11
+TDEProcessRunner::TDEProcessRunner(TDEProcess * p, const TQString & _binName, const KStartupInfoId& id )
+ : TQObject(),
+ process_(p),
+ binName( _binName ),
+ id_( id )
+{
+ TQObject::connect(
+ process_, TQT_SIGNAL(processExited(TDEProcess *)),
+ this, TQT_SLOT(slotProcessExited(TDEProcess *)));
+
+ process_->start();
+ if ( !process_->pid() )
+ slotProcessExited( process_ );
+}
+#endif
+
+TDEProcessRunner::~TDEProcessRunner()
+{
+ delete process_;
+}
+
+ pid_t
+TDEProcessRunner::pid() const
+{
+ return process_->pid();
+}
+
+ void
+TDEProcessRunner::slotProcessExited(TDEProcess * p)
+{
+ if (p != process_)
+ return; // Eh ?
+
+ kdDebug(7010) << "slotProcessExited " << binName << endl;
+ kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
+ kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
+ bool showErr = process_->normalExit()
+ && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 );
+ if ( !binName.isEmpty() && ( showErr || process_->pid() == 0 ) )
+ {
+ // Often we get 1 (zsh, csh) or 127 (ksh, bash) because the binary doesn't exist.
+ // We can't just rely on that, but it's a good hint.
+ // Before assuming its really so, we'll try to find the binName
+ // relatively to current directory, and then in the PATH.
+ if ( !TQFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
+ {
+ kapp->ref();
+ KMessageBox::sorry( 0L, i18n("Could not find the program '%1'").arg( binName ) );
+ kapp->deref();
+ }
+ }
+#ifdef Q_WS_X11
+ if( !id_.none())
+ {
+ KStartupInfoData data;
+ data.addPid( pid()); // announce this pid for the startup notification has finished
+ data.setHostname();
+ KStartupInfo::sendFinish( id_, data );
+ }
+#endif
+ deleteLater();
+}
+
+void KRun::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "krun.moc"
diff --git a/tdeio/tdeio/krun.h b/tdeio/tdeio/krun.h
new file mode 100644
index 000000000..03186af85
--- /dev/null
+++ b/tdeio/tdeio/krun.h
@@ -0,0 +1,512 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 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 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 __k_run_h__
+#define __k_run_h__
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqobject.h>
+#include <tqtimer.h>
+#include <tqstring.h>
+#include <kurl.h>
+#include <kstartupinfo.h>
+
+class TDEProcess;
+class KService;
+namespace TDEIO {
+ class Job;
+ class StatJob;
+}
+
+/**
+ * To open files with their associated applications in KDE, use KRun.
+ *
+ * It can execute any desktop entry, as well as any file, using
+ * the default application or another application "bound" to the file type
+ * (or URL protocol).
+ *
+ * In that example, the mimetype of the file is not known by the application,
+ * so a KRun instance must be created. It will determine the mimetype by itself.
+ * If the mimetype is known, or if you even know the service (application) to
+ * use for this file, use one of the static methods.
+ *
+ * By default KRun uses auto deletion. It causes the KRun instance to delete
+ * itself when the it finished its task. If you allocate the KRun
+ * object on the stack you must disable auto deletion, otherwise it will crash.
+ *
+ * @short Opens files with their associated applications in KDE
+ */
+class TDEIO_EXPORT KRun : public TQObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a KRun object to run the preferred application for a file/URL.
+ * KRun will first determine the type of the file, and will then
+ * run the associated application.
+ *
+ * @param url the URL of the file or directory to 'run'
+ *
+ * @param mode The @p st_mode field of <tt>struct stat</tt>. If
+ * you don't know this set it to 0.
+ *
+ * @param isLocalFile
+ * If this parameter is set to @p false then @p url is
+ * examined to find out whether it is a local URL or
+ * not. This flag is just used to improve speed, since the
+ * function KURL::isLocalFile is a bit slow.
+ *
+ * @param showProgressInfo
+ * Whether to show progress information when determining the
+ * type of the file (i.e. when using TDEIO::stat and TDEIO::mimetype)
+ * Before you set this to false to avoid a dialog box, think about
+ * a very slow FTP server...
+ * It is always better to provide progress info in such cases.
+ */
+ KRun( const KURL& url, mode_t mode = 0,
+ bool isLocalFile = false, bool showProgressInfo = true );
+
+ /**
+ * BIC: Combine with the above ctor for KDE 4.0.
+ * @param window
+ * The top-level widget of the app that invoked this object.
+ * It is used to make sure private information like passwords
+ * are properly handled per application.
+ * @param url the URL of the file or directory to 'run'
+ *
+ * @param mode The @p st_mode field of <tt>struct stat</tt>. If
+ * you don't know this set it to 0.
+ *
+ * @param isLocalFile
+ * If this parameter is set to @p false then @p url is
+ * examined to find out whether it is a local URL or
+ * not. This flag is just used to improve speed, since the
+ * function KURL::isLocalFile is a bit slow.
+ *
+ * @param showProgressInfo
+ * Whether to show progress information when determining the
+ * type of the file (i.e. when using TDEIO::stat and TDEIO::mimetype)
+ * Before you set this to false to avoid a dialog box, think about
+ * a very slow FTP server...
+ * It is always better to provide progress info in such cases.
+ */
+ KRun( const KURL& url, TQWidget* window, mode_t mode = 0,
+ bool isLocalFile = false, bool showProgressInfo = true );
+ KRun( const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode = 0,
+ bool isLocalFile = false, bool showProgressInfo = true );
+
+ /**
+ * Destructor. Don't call it yourself, since a KRun object auto-deletes
+ * itself.
+ */
+ virtual ~KRun();
+
+ /**
+ * Abort this KRun. This kills any jobs launched by it,
+ * and leads to deletion if auto-deletion is on.
+ * This is much safer than deleting the KRun (in case it's
+ * currently showing an error dialog box, for instance)
+ */
+ void abort();
+
+ /**
+ * Returns true if the KRun instance has an error.
+ * @return true when an error occurred
+ * @see error()
+ */
+ bool hasError() const { return m_bFault; }
+
+ /**
+ * Returns true if the KRun instance has finished.
+ * @return true if the KRun instance has finished
+ * @see finished()
+ */
+ bool hasFinished() const { return m_bFinished; }
+
+ /**
+ * Checks whether auto delete is activated.
+ * Auto-deletion causes the KRun instance to delete itself
+ * when it finished its task.
+ * By default auto deletion is on.
+ * @return true if auto deletion is on, false otherwise
+ */
+ bool autoDelete() const { return m_bAutoDelete; }
+
+ /**
+ * Enables or disabled auto deletion.
+ * Auto deletion causes the KRun instance to delete itself
+ * when it finished its task. If you allocate the KRun
+ * object on the stack you must disable auto deletion.
+ * By default auto deletion is on.
+ * @param b true to enable auto deletion, false to disable
+ */
+ void setAutoDelete(bool b) { m_bAutoDelete = b; }
+
+ /**
+ * Set the preferred service for opening this URL, after
+ * its mimetype will have been found by KRun. IMPORTANT: the service is
+ * only used if its configuration says it can handle this mimetype.
+ * This is used for instance for the X-TDE-LastOpenedWith key, for
+ * the recent documents list.
+ * @param desktopEntryName the desktopEntryName of the service, e.g. "kate".
+ */
+ void setPreferredService( const TQString& desktopEntryName );
+
+ /**
+ * Sets whether executables, .desktop files or shell scripts should
+ * be run by KRun. This is enabled by default.
+ * @param b whether to run executable files or not.
+ * @see isExecutable()
+ * @since 3.2
+ */
+ void setRunExecutables(bool b);
+
+ /**
+ * Sets whether the external webbrowser setting should be honoured.
+ * This is enabled by default.
+ * This should only be disabled in webbrowser applications.
+ * @param b whether to enable the external browser or not.
+ * @since 3.4
+ */
+ void setEnableExternalBrowser(bool b);
+
+ /**
+ * Sets the file name to use in the case of downloading the file to a tempfile
+ * in order to give to a non-url-aware application. Some apps rely on the extension
+ * to determine the mimetype of the file. Usually the file name comes from the URL,
+ * but in the case of the HTTP Content-Disposition header, we need to override the
+ * file name.
+ * @since 3.5.3
+ */
+ void setSuggestedFileName( const TQString& fileName );
+
+ /**
+ * Open a list of URLs with a certain service (application).
+ *
+ * @param _service the service to run
+ * @param _urls the list of URLs, can be empty (app launched
+ * without argument)
+ * @param window The top-level widget of the app that invoked this object.
+ * @param tempFiles if true and _urls are local files, they will be deleted
+ * when the application exits.
+ * @return the process id, or 0 on error
+ * @since 3.5.2
+ */
+ static pid_t run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles = false );
+ static pid_t run( const KService& _service, const KURL::List& _urls, TQWidget* window,
+ const TQCString& asn, bool tempFiles = false );
+ /**
+ * Open a list of URLs with a certain service (application).
+ *
+ * @param _service the service to run
+ * @param _urls the list of URLs, can be empty (app launched
+ * without argument)
+ * @param tempFiles if true and _urls are local files, they will be deleted
+ * when the application exits.
+ * @return the process id, or 0 on error
+ */
+ // BIC merge second overload with first one, using tempFiles=false
+ static pid_t run( const KService& _service, const KURL::List& _urls, bool tempFiles );
+ static pid_t run( const KService& _service, const KURL::List& _urls );
+ /// @since 3.5.3
+ /// @internal
+ static pid_t run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles, const TQString& suggestedFileName );
+ static pid_t run( const KService& _service, const KURL::List& _urls, TQWidget* window,
+ const TQCString& asn, bool tempFiles, const TQString& suggestedFileName );
+
+ /**
+ * Open a list of URLs with.
+ *
+ * @param _exec the name of the executable, for example
+ * "/usr/bin/netscape".
+ * @param _urls the list of URLs to open, can be empty (app launched without argument)
+ * @param _name the logical name of the application, for example
+ * "Netscape 4.06".
+ * @param _icon the icon which should be used by the application.
+ * @param _obsolete1 Do not use!
+ * @param _obsolete2 Do not use!
+ * @return the process id, or 0 on error
+ */
+ static pid_t run( const TQString& _exec, const KURL::List& _urls,
+ const TQString& _name = TQString::null,
+ const TQString& _icon = TQString::null,
+ const TQString& _obsolete1 = TQString::null,
+ const TQString& _obsolete2 = TQString::null );
+
+ /**
+ * Open the given URL.
+ *
+ * This function is used after the mime type
+ * is found out. It will search for all services which can handle
+ * the mime type and call run() afterwards.
+ * @param _url the URL to open
+ * @param _mimetype the mime type of the resource
+ * @param tempFile if true and _url is a local file, it will be deleted
+ * when the launched application exits.
+ * @param runExecutables if false then local .desktop files,
+ * executables and shell scripts will not be run.
+ * See also isExecutable().
+ * @return the process id, or 0 on error
+ */
+ // BIC Merge second overload with first one using runExecutables=true, and
+ // merge third overload with first one as well using tempFiles=false and
+ // runExecutables=true
+ static pid_t runURL( const KURL& _url, const TQString& _mimetype, bool tempFile, bool runExecutables);
+ static pid_t runURL( const KURL& _url, const TQString& _mimetype, bool tempFile);
+ static pid_t runURL( const KURL& _url, const TQString& _mimetype );
+ /// @since 3.5.3
+ /// @internal
+ static pid_t runURL( const KURL& _url, const TQString& _mimetype, TQWidget* window, const TQCString& asn, bool tempFile, bool runExecutables, const TQString& suggestedFileName );
+ static pid_t runURL( const KURL& _url, const TQString& _mimetype, bool tempFile, bool runExecutables, const TQString& suggestedFileName );
+
+ /**
+ * Run the given shell command and notifies kicker of the starting
+ * of the application. If the program to be called doesn't exist,
+ * an error box will be displayed.
+ *
+ * Use only when you know the full command line. Otherwise use the other
+ * static methods, or KRun's constructor.
+ *
+ * @p _cmd must be a shell command. You must not append "&"
+ * to it, since the function will do that for you.
+ *
+ * @return PID of running command, 0 if it could not be started, 0 - (PID
+ * of running command) if command was unsafe for map notification.
+ */
+ static pid_t runCommand( TQString cmd );
+
+ /**
+ * Same as the other runCommand(), but it also takes the name of the
+ * binary, to display an error message in case it couldn't find it.
+ *
+ * @param cmd must be a shell command. You must not append "&"
+ * to it, since the function will do that for you.
+ * @param execName the name of the executable
+ * @param icon icon for app starting notification
+ * @return PID of running command, 0 if it could not be started, 0 - (PID
+ * of running command) if command was unsafe for map notification.
+ */
+ static pid_t runCommand( const TQString& cmd, const TQString & execName, const TQString & icon );
+ static pid_t runCommand( const TQString& cmd, const TQString & execName, const TQString & icon,
+ TQWidget* window, const TQCString& asn );
+
+ /**
+ * Display the Open-With dialog for those URLs, and run the chosen application.
+ * @param lst the list of applications to run
+ * @param tempFiles if true and lst are local files, they will be deleted
+ * when the application exits.
+ * @return false if the dialog was canceled
+ */
+ // BIC merge second overload with first one, using tempFiles=false
+ static bool displayOpenWithDialog( const KURL::List& lst, bool tempFiles );
+ static bool displayOpenWithDialog( const KURL::List& lst );
+ /// @since 3.5.3
+ /// @internal
+ static bool displayOpenWithDialog( const KURL::List& lst, bool tempFiles, const TQString& suggestedFileName );
+
+ /**
+ * Quotes a string for the shell.
+ * @param _str the string to quote. The quoted string will be written here
+ */
+ static void shellQuote( TQString &_str );
+
+ /**
+ * Processes a Exec= line as found in .desktop files.
+ * @param _service the service to extract information from.
+ * @param _urls The urls the service should open.
+ * @param has_shell If true, the arguments are going to be fed into a
+ * shell e.g by using system().
+ * If false, the arguments are going to be fed into a exec() kind
+ * call.
+ * If the arguments are intended for an exec() kind of call and
+ * the Exec line contains shell commands then "/bin/sh -c" is added.
+ * @param tempFiles if true and _urls are local files, they will be deleted
+ * when the application exits.
+ * @return a list of arguments suitable for either system() or exec().
+ */
+ static TQStringList processDesktopExec(const KService &_service, const KURL::List &_urls, bool has_shell, bool tempFiles);
+ static TQStringList processDesktopExec(const KService &_service, const KURL::List &_urls, bool has_shell);
+ /// @since 3.5.3
+ /// @internal
+ static TQStringList processDesktopExec(const KService &_service, const KURL::List &_urls, bool has_shell, bool tempFiles, const TQString& suggestedFileName);
+
+ /**
+ * Given a full command line (e.g. the Exec= line from a .desktop file),
+ * extract the name of the binary being run.
+ * @param execLine the full command line
+ * @param removePath if true, remove a (relative or absolute) path. E.g. /usr/bin/ls becomes ls.
+ * @return the name of the binary to run
+ * @since 3.1
+ */
+ static TQString binaryName( const TQString & execLine, bool removePath );
+
+ /**
+ * Returns whether @p serviceType refers to an executable program instead
+ * of a data file.
+ * @since 3.2
+ */
+ static bool isExecutable( const TQString& serviceType );
+
+ /**
+ * Returns wether the @p url of @p mimetype is executable.
+ * To be executable the file must pass the following rules:
+ * -# Must reside on the local filesystem.
+ * -# Must be marked as executable for the user by the filesystem.
+ * -# The mime type must inherit application/x-executable or application/x-executable-script.
+ * To allow a script to run when the above rules are satisfied add the entry
+ * @code
+ * X-TDE-IsAlso=application/x-executable-script
+ * @endcode
+ * to the mimetype's desktop file.
+ * @since 3.3
+ */
+ static bool isExecutableFile( const KURL& url, const TQString &mimetype );
+
+ /**
+ * @internal
+ * @since 3.4
+ */
+ static bool checkStartupNotify( const TQString& binName, const KService* service, bool* silent_arg, TQCString* wmclass_arg );
+
+signals:
+ /**
+ * Emitted when the operation finished.
+ * @see hasFinished()
+ */
+ void finished();
+ /**
+ * Emitted when the operation had an error.
+ * @see hasError()
+ */
+ void error();
+
+protected slots:
+ void slotTimeout();
+ void slotScanFinished( TDEIO::Job * );
+ void slotScanMimeType( TDEIO::Job *, const TQString &type );
+ virtual void slotStatResult( TDEIO::Job * );
+
+protected:
+ virtual void init();
+
+ virtual void scanFile();
+
+ /**
+ * Called if the mimetype has been detected. The function checks
+ * whether the document and appends the gzip protocol to the
+ * URL. Otherwise runURL is called to finish the job.
+ */
+ virtual void foundMimeType( const TQString& _type );
+
+ virtual void killJob();
+
+ KURL m_strURL;
+ bool m_bFault;
+ bool m_bAutoDelete;
+ bool m_bProgressInfo;
+ bool m_bFinished;
+ TDEIO::Job * m_job;
+ TQTimer m_timer;
+
+ /**
+ * Used to indicate that the next action is to scan the file.
+ * This action is invoked from slotTimeout.
+ */
+ bool m_bScanFile;
+ bool m_bIsDirectory;
+
+ /**
+ * USed to indicate that the next action is to initialize.
+ * This action is invoked from slotTimeout
+ */
+ bool m_bInit;
+
+ bool m_bIsLocalFile;
+ mode_t m_mode;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ void init (const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode,
+ bool isLocalFile, bool showProgressInfo);
+private:
+ class KRunPrivate;
+ KRunPrivate *d;
+};
+
+#ifndef KDE_NO_COMPAT
+/**
+ * @deprecated. Kept for source compatibility, does nothing nowadays.
+ * Do not use in new source.
+ * KRun can open the openwith dialog directly now.
+ * Use KRun::displayOpenWithDialog() if you were using KOpenWithHandler directly.
+ */
+class TDEIO_EXPORT_DEPRECATED KOpenWithHandler
+{
+public:
+ KOpenWithHandler() {}
+ static bool exists() { return true; }
+};
+#endif
+
+/**
+ * @internal
+ * This class watches a process launched by KRun.
+ * It sends a notification when the process exits (for the taskbar)
+ * and it will show an error message if necessary (e.g. "program not found").
+ */
+class TDEIO_EXPORT TDEProcessRunner : public TQObject
+{
+ Q_OBJECT
+
+ public:
+
+ static pid_t run(TDEProcess *, const TQString & binName);
+#ifdef Q_WS_X11 // We don't have KStartupInfo in Qt/Embedded
+ static pid_t run(TDEProcess *, const TQString & binName, const KStartupInfoId& id );
+#endif
+
+ virtual ~TDEProcessRunner();
+
+ pid_t pid() const;
+
+ protected slots:
+
+ void slotProcessExited(TDEProcess *);
+
+ private:
+
+ TDEProcessRunner(TDEProcess *, const TQString & binName);
+#ifdef Q_WS_X11 // We don't have KStartupInfo in Qt/Embedded
+ TDEProcessRunner(TDEProcess *, const TQString & binName, const KStartupInfoId& id );
+#endif
+ TDEProcessRunner();
+
+ TDEProcess * process_;
+ TQString binName;
+#ifdef Q_WS_X11 // We don't have KStartupInfo in Qt/Embedded
+ KStartupInfoId id_;
+#endif
+};
+
+#endif
diff --git a/tdeio/tdeio/ksambashare.cpp b/tdeio/tdeio/ksambashare.cpp
new file mode 100644
index 000000000..608594ee5
--- /dev/null
+++ b/tdeio/tdeio/ksambashare.cpp
@@ -0,0 +1,239 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
+
+ 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 <tqdict.h>
+#include <tqfile.h>
+#include <tqtextstream.h>
+
+#include <kdirwatch.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+
+#include "ksambashare.h"
+
+class KSambaSharePrivate
+{
+public:
+ KSambaSharePrivate();
+
+ bool readSmbConf();
+ bool findSmbConf();
+ bool load();
+
+ TQDict<bool> sharedPaths;
+ TQString smbConf;
+};
+
+KSambaSharePrivate::KSambaSharePrivate()
+{
+ load();
+}
+
+
+#define FILESHARECONF "/etc/security/fileshare.conf"
+
+bool KSambaSharePrivate::load() {
+ if (!findSmbConf())
+ return false;
+
+ return readSmbConf();
+}
+
+/**
+ * Try to find the samba config file path
+ * First tries the tdeconfig, then checks
+ * several well-known paths
+ * @return wether a smb.conf was found.
+ **/
+bool KSambaSharePrivate::findSmbConf() {
+ KSimpleConfig config(TQString::fromLatin1(FILESHARECONF),true);
+ smbConf = config.readEntry("SMBCONF");
+
+ if ( TQFile::exists(smbConf) )
+ return true;
+
+ if ( TQFile::exists("/etc/samba/smb.conf") )
+ smbConf = "/etc/samba/smb.conf";
+ else
+ if ( TQFile::exists("/etc/smb.conf") )
+ smbConf = "/etc/smb.conf";
+ else
+ if ( TQFile::exists("/usr/local/samba/lib/smb.conf") )
+ smbConf = "/usr/local/samba/lib/smb.conf";
+ else
+ if ( TQFile::exists("/usr/samba/lib/smb.conf") )
+ smbConf = "/usr/samba/lib/smb.conf";
+ else
+ if ( TQFile::exists("/usr/lib/smb.conf") )
+ smbConf = "/usr/lib/smb.conf";
+ else
+ if ( TQFile::exists("/usr/local/lib/smb.conf") )
+ smbConf = "/usr/local/lib/smb.conf";
+ else {
+ kdDebug(7000) << "KSambaShare: Could not found smb.conf!" << endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Reads all path= entries from the smb.conf file
+ * and fills the sharedPaths dict with the values
+ */
+bool KSambaSharePrivate::readSmbConf() {
+ TQFile f(smbConf);
+
+ kdDebug(7000) << "KSambaShare::readSmbConf " << smbConf << endl;
+
+ if (!f.open(IO_ReadOnly)) {
+ kdError() << "KSambaShare: Could not open " << smbConf << endl;
+ return false;
+ }
+
+ sharedPaths.clear();
+
+ TQTextStream s(&f);
+
+ bool continuedLine = false; // is true if the line before ended with a backslash
+ TQString completeLine;
+
+ while (!s.eof())
+ {
+ TQString currentLine = s.readLine().stripWhiteSpace();
+
+ if (continuedLine) {
+ completeLine += currentLine;
+ continuedLine = false;
+ }
+ else
+ completeLine = currentLine;
+
+ // is the line continued in the next line ?
+ if ( completeLine[completeLine.length()-1] == '\\' )
+ {
+ continuedLine = true;
+ // remove the ending backslash
+ completeLine.truncate( completeLine.length()-1 );
+ continue;
+ }
+
+ // comments or empty lines
+ if (completeLine.isEmpty() ||
+ '#' == completeLine[0] ||
+ ';' == completeLine[0])
+ {
+ continue;
+ }
+
+ // parameter
+ int i = completeLine.find('=');
+
+ if (i>-1)
+ {
+ TQString name = completeLine.left(i).stripWhiteSpace().lower();
+ TQString value = completeLine.mid(i+1).stripWhiteSpace();
+
+ if (name == TDEGlobal::staticQString("path")) {
+ // Handle quotation marks
+ if ( value[0] == '"' )
+ value.remove(0,1);
+
+ if ( value[value.length()-1] == '"' )
+ value.truncate(value.length()-1);
+
+ // Normalize path
+ if ( value[value.length()-1] != '/' )
+ value += '/';
+
+ bool b = true;
+ sharedPaths.insert(value,&b);
+ kdDebug(7000) << "KSambaShare: Found path: " << value << endl;
+ }
+ }
+ }
+
+ f.close();
+
+ return true;
+
+}
+
+KSambaShare::KSambaShare() {
+ d = new KSambaSharePrivate();
+ if (TQFile::exists(d->smbConf)) {
+ KDirWatch::self()->addFile(d->smbConf);
+ KDirWatch::self()->addFile(FILESHARECONF);
+ connect(KDirWatch::self(), TQT_SIGNAL(dirty (const TQString&)),this,
+ TQT_SLOT(slotFileChange(const TQString&)));
+ }
+}
+
+KSambaShare::~KSambaShare() {
+ if (TQFile::exists(d->smbConf)) {
+ KDirWatch::self()->removeFile(d->smbConf);
+ KDirWatch::self()->removeFile(FILESHARECONF);
+ }
+ delete d;
+}
+
+TQString KSambaShare::smbConfPath() const {
+ return d->smbConf;
+}
+
+bool KSambaShare::isDirectoryShared( const TQString & path ) const {
+ TQString fixedPath = path;
+ if ( path[path.length()-1] != '/' )
+ fixedPath += '/';
+
+ return d->sharedPaths.find(fixedPath) != 0;
+}
+
+TQStringList KSambaShare::sharedDirectories() const {
+ TQStringList result;
+ TQDictIterator<bool> it(d->sharedPaths);
+ for( ; it.current(); ++it )
+ result << it.currentKey();
+
+ return result;
+}
+
+void KSambaShare::slotFileChange( const TQString & path ) {
+ if (path == d->smbConf)
+ d->readSmbConf();
+ else
+ if (path == FILESHARECONF)
+ d->load();
+
+ emit changed();
+}
+
+KSambaShare* KSambaShare::_instance = 0L;
+static KStaticDeleter<KSambaShare> ksdSambaShare;
+
+KSambaShare* KSambaShare::instance() {
+ if (! _instance )
+ _instance = ksdSambaShare.setObject(_instance, new KSambaShare());
+
+ return _instance;
+}
+
+#include "ksambashare.moc"
+
diff --git a/tdeio/tdeio/ksambashare.h b/tdeio/tdeio/ksambashare.h
new file mode 100644
index 000000000..ffd298588
--- /dev/null
+++ b/tdeio/tdeio/ksambashare.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project
+ Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
+
+ 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 ksambashare_h
+#define ksambashare_h
+
+#include <tqobject.h>
+
+#include <tdelibs_export.h>
+
+class KSambaSharePrivate;
+
+/**
+ * Similar functionality like KFileShare,
+ * but works only for Samba and do not need
+ * any suid script.
+ * Singleton class, call instance() to get an instance.
+ */
+class TDEIO_EXPORT KSambaShare : public TQObject
+{
+Q_OBJECT
+public:
+ /**
+ * Returns the one and only instance of KSambaShare
+ */
+ static KSambaShare* instance();
+
+ /**
+ * Whether or not the given path is shared by Samba.
+ * @param path the path to check if it is shared by Samba.
+ * @return whether the given path is shared by Samba.
+ */
+ bool isDirectoryShared( const TQString & path ) const;
+
+ /**
+ * Returns a list of all directories shared by Samba.
+ * The resulting list is not sorted.
+ * @return a list of all directories shared by Samba.
+ */
+ TQStringList sharedDirectories() const;
+
+ /**
+ * KSambaShare destructor.
+ * Do not call!
+ * The instance is destroyed automatically!
+ */
+ virtual ~KSambaShare();
+
+ /**
+ * Returns the path to the used smb.conf file
+ * or null if no file was found
+ */
+ TQString smbConfPath() const;
+
+signals:
+ /**
+ * Emitted when the smb.conf file has changed
+ */
+ void changed();
+
+private:
+ KSambaShare();
+ static KSambaShare* _instance;
+ KSambaSharePrivate* d;
+
+private slots:
+ void slotFileChange(const TQString&);
+};
+
+#endif
diff --git a/tdeio/tdeio/kscan.cpp b/tdeio/tdeio/kscan.cpp
new file mode 100644
index 000000000..49ae7c5ab
--- /dev/null
+++ b/tdeio/tdeio/kscan.cpp
@@ -0,0 +1,185 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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 <tqfile.h>
+
+#include <klocale.h>
+#include <ktrader.h>
+
+#include "kscan.h"
+
+// static factory method
+KScanDialog * KScanDialog::getScanDialog( TQWidget *parent, const char *name,
+ bool modal )
+{
+ KTrader::OfferList offers = KTrader::self()->query("KScan/KScanDialog");
+ if ( offers.isEmpty() )
+ return 0L;
+
+ KService::Ptr ptr = *(offers.begin());
+ KLibFactory *factory = KLibLoader::self()->factory( TQFile::encodeName(ptr->library()) );
+
+ if ( !factory )
+ return 0;
+
+ TQStringList args;
+ args << TQString::number( (int)modal );
+
+ TQObject *res = factory->create( TQT_TQOBJECT(parent), name, "KScanDialog", args );
+
+ return dynamic_cast<KScanDialog *>( res );
+}
+
+
+KScanDialog::KScanDialog( int dialogFace, int buttonMask,
+ TQWidget *parent, const char *name, bool modal )
+ : KDialogBase( dialogFace, i18n("Acquire Image"), buttonMask, Close,
+ parent, name, modal, true ),
+ m_currentId( 1 )
+{
+}
+
+KScanDialog::~KScanDialog()
+{
+}
+
+bool KScanDialog::setup()
+{
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+
+
+// static factory method
+KOCRDialog * KOCRDialog::getOCRDialog( TQWidget *parent, const char *name,
+ bool modal )
+{
+ KTrader::OfferList offers = KTrader::self()->query("KScan/KOCRDialog");
+ if ( offers.isEmpty() )
+ return 0L;
+
+ KService::Ptr ptr = *(offers.begin());
+ KLibFactory *factory = KLibLoader::self()->factory( TQFile::encodeName(ptr->library()) );
+
+ if ( !factory )
+ return 0;
+
+ TQStringList args;
+ args << TQString::number( (int)modal );
+
+ TQObject *res = factory->create( TQT_TQOBJECT(parent), name, "KOCRDialog", args );
+
+ return dynamic_cast<KOCRDialog *>( res );
+}
+
+
+KOCRDialog::KOCRDialog( int dialogFace, int buttonMask,
+ TQWidget *parent, const char *name, bool modal )
+ : KDialogBase( dialogFace, i18n("OCR Image"), buttonMask, Close,
+ parent, name, modal, true ),
+ m_currentId( 1 )
+{
+
+}
+
+KOCRDialog::~KOCRDialog()
+{
+}
+
+
+///////////////////////////////////////////////////////////////////
+
+
+KScanDialogFactory::KScanDialogFactory( TQObject *parent, const char *name )
+ : KLibFactory( parent, name ),
+ m_instance( 0L )
+{
+}
+
+KScanDialogFactory::~KScanDialogFactory()
+{
+ delete m_instance;
+}
+
+TQObject *KScanDialogFactory::createObject( TQObject *parent, const char *name,
+ const char *classname,
+ const TQStringList &args )
+{
+ if ( strcmp( classname, "KScanDialog" ) != 0 )
+ return 0;
+
+ if ( parent && !parent->isWidgetType() )
+ return 0;
+
+ bool modal = false;
+
+ if ( args.count() == 1 )
+ modal = (bool)args[ 0 ].toInt();
+
+ return TQT_TQOBJECT(createDialog( TQT_TQWIDGET( parent ), name, modal ));
+}
+
+
+///////////////////////////////////////////////////////////////////
+
+
+KOCRDialogFactory::KOCRDialogFactory( TQObject *parent, const char *name )
+ : KLibFactory( parent, name ),
+ m_instance( 0L )
+{
+}
+
+KOCRDialogFactory::~KOCRDialogFactory()
+{
+ delete m_instance;
+}
+
+TQObject *KOCRDialogFactory::createObject( TQObject *parent, const char *name,
+ const char *classname,
+ const TQStringList &args )
+{
+ if ( strcmp( classname, "KOCRDialog" ) != 0 )
+ return 0;
+
+ if ( parent && !parent->isWidgetType() )
+ return 0;
+
+ bool modal = false;
+
+ if ( args.count() == 1 )
+ modal = (bool)args[ 0 ].toInt();
+
+ return TQT_TQOBJECT(createDialog( TQT_TQWIDGET( parent ), name, modal ));
+}
+
+void KScanDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+void KScanDialogFactory::virtual_hook( int id, void* data )
+{ KLibFactory::virtual_hook( id, data ); }
+
+void KOCRDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+void KOCRDialogFactory::virtual_hook( int id, void* data )
+{ KLibFactory::virtual_hook( id, data ); }
+
+
+#include "kscan.moc"
diff --git a/tdeio/tdeio/kscan.h b/tdeio/tdeio/kscan.h
new file mode 100644
index 000000000..940b8ceaa
--- /dev/null
+++ b/tdeio/tdeio/kscan.h
@@ -0,0 +1,370 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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 KSCAN_H
+#define KSCAN_H
+
+#include <kdialogbase.h>
+#include <kinstance.h>
+#include <klibloader.h>
+
+class TQImage;
+
+/**
+ * This is a base class for scanning dialogs. You can derive from this class
+ * and implement your own dialog. An implementation is available in
+ * tdegraphics/libkscan.
+ *
+ * Application developers that wish to add scanning support to their program
+ * can use the static method @p KScanDialog::getScanDialog() to get an instance
+ * of the user's preferred scanning dialog.
+ *
+ * Typical usage looks like this (e.g. in a slotShowScanDialog() method):
+ *
+ * \code
+ * if ( !m_scanDialog ) {
+ * m_scanDialog = KScanDialog::getScanDialog( this, "scandialog" );
+ * if ( !m_scanDialog ) // no scanning support installed?
+ * return;
+ *
+ * connect( m_scanDialog, TQT_SIGNAL( finalImage( const TQImage&, int )),
+ * TQT_SLOT( slotScanned( const TQImage&, int ) ));
+ * }
+ *
+ * if ( m_scanDialog->setup() ) // only if scanner configured/available
+ * m_scanDialog->show();
+ * \endcode
+ *
+ * This will create and show a non-modal scanning dialog. Connect to more
+ * signals if you like.
+ *
+ * If you implement an own scan-dialog, you also have to implement a
+ * KScanDialogFactory.
+ *
+ * @short A baseclass and accessor for Scanning Dialogs
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KScanDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Creates the user's preferred scanning dialog and returns it,
+ * or 0L if no scan-support
+ * is available. Pass a suitable @p parent widget, if you like. If you
+ * don't you have to 'delete' the returned pointer yourself.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ * @return the KScanDialog, or 0 if the function failed
+ */
+ static KScanDialog * getScanDialog( TQWidget *parent=0L,
+ const char *name=0, bool modal=false );
+ /**
+ * Destructs the scan dialog.
+ */
+ ~KScanDialog();
+
+ /**
+ * Reimplement this if you need to set up some things, before showing the
+ * dialog, e.g. to ask the user for the scanner device to use. If you
+ * return false (e.g. there is no device available or the user aborted
+ * device selection), the dialog will not be shown.
+ *
+ * @return true by default.
+ */
+ virtual bool setup();
+
+protected:
+ /**
+ * Constructs the scan dialog. If you implement an own dialog, you can
+ * customize it with the usual KDialogBase flags.
+ *
+ * @param dialogFace the KDialogBase::DialogType
+ * @param buttonMask a ORed mask of all buttons (see
+ * KDialogBase::ButtonCode)
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ * @see KDialogBase
+ */
+ KScanDialog( int dialogFace=Tabbed, int buttonMask = Close|Help,
+ TQWidget *parent=0L, const char *name=0, bool modal=false );
+
+ /**
+ * Returns the current id for an image. You can use that in your subclass
+ * for the signals. The id is used in the signals to let people know
+ * which preview and which text-recognition belongs to which scan.
+ *
+ * @return the current id for the image
+ * @see nextId
+ * @see finalImage
+ * @see preview
+ * @see textRecognized
+ */
+ int id() const { return m_currentId; }
+
+ /**
+ * Returns the id for the next image. You can use that in your subclass
+ * for the signals.
+ *
+ * @return the id for the next image
+ * @see id
+ * @see finalImage
+ * @see preview
+ * @see textRecognized
+ *
+ */
+ int nextId() { return ++m_currentId; }
+
+signals:
+ /**
+ * Informs you that an image has been previewed.
+ * @param img the image
+ * @param id the image's id
+ */
+ void preview( const TQImage &img, int id );
+
+ /**
+ * Informs you that an image has scanned. @p id is the same as in the
+ * @p preview() signal, if this image had been previewed before.
+ *
+ * Note, that those id's may not be properly implemented in the current
+ * libkscan.
+ * @param img the image
+ * @param id the image's id
+ */
+ void finalImage( const TQImage &img, int id );
+
+ /**
+ * Informs you that the image with the id @p id has been run through
+ * text-recognition. The text is in the TQString parameter. In the future,
+ * a compound document, using rich text will be used instead.
+ *
+ * @param text the text that has been recognized
+ * @param id the id of the image
+ */
+ void textRecognized( const TQString &text, int id );
+
+private:
+ int m_currentId;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KScanDialogPrivate;
+ KScanDialogPrivate *d;
+};
+
+
+/**
+ * A factory for creating a KScanDialog. You need to reimplement
+ * createDialog().
+ * @short Factory for creating KScanDialogs
+ */
+class TDEIO_EXPORT KScanDialogFactory : public KLibFactory
+{
+public:
+ virtual ~KScanDialogFactory();
+
+ /**
+ * Your library should reimplement this method to return your KScanDialog
+ * derived dialog.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ */
+ virtual KScanDialog * createDialog( TQWidget *parent=0, const char *name=0,
+ bool modal=false ) = 0;
+
+protected:
+ /**
+ * Creates a new KScanDialogFactory.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ */
+ KScanDialogFactory( TQObject *parent=0, const char *name=0 );
+
+ virtual TQObject* createObject( TQObject* parent = 0, const char* name = 0,
+ const char* classname = TQOBJECT_OBJECT_NAME_STRING,
+ const TQStringList &args = TQStringList() );
+
+
+ /**
+ * Creates a new instance with the given name.
+ * @param instanceName the name of the instance
+ */
+ void setName( const TQCString& instanceName ) {
+ delete m_instance;
+ m_instance = new TDEInstance( instanceName );
+ }
+
+ /**
+ * Returns the instance.
+ * @return the TDEInstance
+ */
+ TDEInstance *instance() const { return m_instance; }
+
+private:
+ TDEInstance *m_instance;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KScanDialogFactoryPrivate* d;
+};
+
+/**
+ * Base class for OCR Dialogs.
+ */
+class TDEIO_EXPORT KOCRDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Creates the user's preferred OCR dialog and returns it,
+ * or 0L if no OCR-support
+ * is available. Pass a suitable @p parent widget, if you like. If you
+ * don't you have to 'delete' the returned pointer yourself.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ * @return the KOCRDialog, or 0 if the function failed
+ */
+ static KOCRDialog * getOCRDialog( TQWidget *parent=0L,
+ const char *name=0, bool modal=false );
+ ~KOCRDialog();
+
+protected:
+ /**
+ * Constructs the OCR dialog. If you implement an own dialog, you can
+ * customize it with the usual KDialogBase flags.
+ *
+ * @param dialogFace the KDialogBase::DialogType
+ * @param buttonMask a ORed mask of all buttons (see
+ * KDialogBase::ButtonCode)
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ */
+ KOCRDialog( int dialogFace=Tabbed, int buttonMask = Close|Help,
+ TQWidget *parent=0L, const char *name=0, bool modal=false );
+
+ /**
+ * Returns the current id for an image. You can use that in your subclass
+ * for the signals. The id is used in the signals to let people know
+ * which text-recognition belongs to which scan.
+ *
+ * @return the current id for the image
+ * @see nextId
+ * @see textRecognized
+ */
+ int id() const { return m_currentId; }
+
+ /**
+ * Returns the id for the next image. You can use that in your subclass
+ * for the signals.
+ *
+ * @return the id for the next image
+ * @see id
+ * @see textRecognized
+ */
+ int nextId() { return ++m_currentId; }
+
+signals:
+ /**
+ * Informs you that the image with the id @p id has been run through
+ * text-recognition. The text is in the TQString parameter. In the future,
+ * a compound document, using rich text will be used instead.
+ *
+ * @param text the text that has been recognized
+ * @param id the id of the image
+ */
+ void textRecognized( const TQString &text, int id );
+
+private:
+ int m_currentId;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KOCRDialogPrivate;
+ KOCRDialogPrivate *d;
+};
+
+
+/**
+ * A factory for creating a KOCRDialog. You need to reimplement
+ * createDialog().
+ * @short Factory for creating KScanDialogs
+ */
+class TDEIO_EXPORT KOCRDialogFactory : public KLibFactory
+{
+public:
+ virtual ~KOCRDialogFactory();
+
+ /**
+ * Your library should reimplement this method to return your KOCRDialog
+ * derived dialog.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ * @param modal if true the dialog is model
+ */
+ virtual KOCRDialog * createDialog( TQWidget *parent=0, const char *name=0,
+ bool modal=false ) = 0;
+
+protected:
+ /**
+ * Creates a new KScanDialogFactory.
+ * @param parent the QWidget's parent, or 0
+ * @param name the name of the TQObject, can be 0
+ */
+ KOCRDialogFactory( TQObject *parent=0, const char *name=0 );
+
+ virtual TQObject* createObject( TQObject* parent = 0, const char* name = 0,
+ const char* className = TQOBJECT_OBJECT_NAME_STRING,
+ const TQStringList &args = TQStringList() );
+
+
+ /**
+ * Creates a new instance with the given name.
+ * @param instanceName the name of the instance
+ */
+ void setName( const TQCString& instanceName ) {
+ delete m_instance;
+ m_instance = new TDEInstance( instanceName );
+ }
+
+ /**
+ * Returns the instance.
+ * @return the TDEInstance
+ */
+ TDEInstance *instance() const { return m_instance; }
+
+private:
+ TDEInstance *m_instance;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KOCRDialogFactory* d;
+};
+
+
+#endif // KSCAN_H
diff --git a/tdeio/tdeio/kservice.cpp b/tdeio/tdeio/kservice.cpp
new file mode 100644
index 000000000..2a24743ab
--- /dev/null
+++ b/tdeio/tdeio/kservice.cpp
@@ -0,0 +1,934 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org>
+ * Copyright (C) 1999 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.
+ **/
+
+// $Id$
+
+#include <config.h>
+
+#include "kservice.h"
+#include "kservice_p.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stddef.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <tqstring.h>
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tqtl.h>
+
+#include <ksimpleconfig.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <tdeconfigbase.h>
+#include <kstandarddirs.h>
+#include <dcopclient.h>
+
+#include "kservicefactory.h"
+#include "kservicetypefactory.h"
+#include "kservicetype.h"
+#include "kuserprofile.h"
+#include "tdesycoca.h"
+
+class KService::KServicePrivate
+{
+public:
+ TQStringList categories;
+ TQString menuId;
+};
+
+KService::KService( const TQString & _name, const TQString &_exec, const TQString &_icon)
+ : KSycocaEntry( TQString::null)
+{
+ d = new KServicePrivate;
+ m_bValid = true;
+ m_bDeleted = false;
+ m_strType = "Application";
+ m_strName = _name;
+ m_strExec = _exec;
+ m_strIcon = _icon;
+ m_bTerminal = false;
+ m_bAllowAsDefault = true;
+ m_initialPreference = 10;
+}
+
+
+KService::KService( const TQString & _fullpath )
+ : KSycocaEntry( _fullpath)
+{
+ KDesktopFile config( _fullpath );
+
+ init(&config);
+}
+
+KService::KService( KDesktopFile *config )
+ : KSycocaEntry( config->fileName())
+{
+ init(config);
+}
+
+void
+KService::init( KDesktopFile *config )
+{
+ d = new KServicePrivate;
+ m_bValid = true;
+
+ bool absPath = !TQDir::isRelativePath(entryPath());
+ bool kde4application = config->fileName().startsWith("/usr/share/applications/kde4/");
+
+ config->setDesktopGroup();
+
+ TQMap<TQString, TQString> entryMap = config->entryMap(config->group());
+
+ entryMap.remove("Encoding"); // reserved as part of Desktop Entry Standard
+ entryMap.remove("Version"); // reserved as part of Desktop Entry Standard
+
+ m_bDeleted = config->readBoolEntry( "Hidden", false );
+ entryMap.remove("Hidden");
+ if (m_bDeleted)
+ {
+ //kdDebug() << "Hidden=true for " << entryPath() << endl;
+ m_bValid = false;
+ return;
+ }
+
+ m_strName = config->readName();
+ entryMap.remove("Name");
+ if ( m_strName.isEmpty() )
+ {
+ if (config->readEntry( "Exec" ).isEmpty())
+ {
+ //kdWarning(7012) << "The desktop entry file " << entryPath()
+ // << " has no Name and no Exec" << endl;
+ m_bValid = false;
+ return;
+ }
+ // Try to make up a name.
+ m_strName = entryPath();
+ int i = m_strName.findRev('/');
+ m_strName = m_strName.mid(i+1);
+ i = m_strName.findRev('.');
+ if (i != -1)
+ m_strName = m_strName.left(i);
+ }
+
+ m_strType = config->readType();
+ entryMap.remove("Type");
+ if ( m_strType.isEmpty() )
+ {
+ /*kdWarning(7012) << "The desktop entry file " << entryPath()
+ << " has no Type=... entry."
+ << " It should be \"Application\" or \"Service\"" << endl;
+ m_bValid = false;
+ return;*/
+ m_strType = "Application";
+ } else if ( m_strType != "Application" && m_strType != "Service" )
+ {
+ kdWarning(7012) << "The desktop entry file " << entryPath()
+ << " has Type=" << m_strType
+ << " instead of \"Application\" or \"Service\"" << endl;
+ m_bValid = false;
+ return;
+ }
+
+ // In case Try Exec is set, check if the application is available
+ if (!config->tryExec()) {
+ //kdDebug(7012) << "tryExec said false for " << entryPath() << endl;
+ m_bDeleted = true;
+ m_bValid = false;
+ return;
+ }
+
+ TQString resource = config->resource();
+
+ if ( (m_strType == "Application") &&
+ (!resource.isEmpty()) &&
+ (resource != "apps") &&
+ !absPath)
+ {
+ kdWarning(7012) << "The desktop entry file " << entryPath()
+ << " has Type=" << m_strType << " but is located under \"" << resource
+ << "\" instead of \"apps\"" << endl;
+ m_bValid = false;
+ return;
+ }
+
+ if ( (m_strType == "Service") &&
+ (!resource.isEmpty()) &&
+ (resource != "services") &&
+ !absPath)
+ {
+ kdWarning(7012) << "The desktop entry file " << entryPath()
+ << " has Type=" << m_strType << " but is located under \"" << resource
+ << "\" instead of \"services\"" << endl;
+ m_bValid = false;
+ return;
+ }
+
+ TQString name = entryPath();
+ int pos = name.findRev('/');
+ if (pos != -1)
+ name = name.mid(pos+1);
+ pos = name.find('.');
+ if (pos != -1)
+ name = name.left(pos);
+
+ m_strExec = config->readPathEntry( "Exec" );
+ if (kde4application && !m_strExec.startsWith("/")) {
+ m_strExec = "XDG_DATA_DIRS=/usr/share XDG_CONFIG_DIRS=/etc/xdg/ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:$PATH "+m_strExec;
+ } else if (config->readBoolEntry("X-TDE-SubstituteUID")) {
+ int space = m_strExec.find(" ");
+ if (space==-1)
+ m_strExec = KStandardDirs::findExe(m_strExec);
+ else {
+ const TQString command = m_strExec.left(space);
+ m_strExec.replace(command,KStandardDirs::findExe(command));
+ }
+ }
+
+ entryMap.remove("Exec");
+
+ m_strIcon = config->readEntry( "Icon", "unknown" );
+ if (kde4application) {
+ if (TQFile::exists("/usr/share/icons/oxygen/22x22/apps/" + m_strIcon + ".png")) {
+ m_strIcon = "/usr/share/icons/oxygen/22x22/apps/" + m_strIcon + ".png";
+ } else if (TQFile::exists("/usr/share/icons/hicolor/22x22/apps/" + m_strIcon + ".png")) {
+ m_strIcon = "/usr/share/icons/hicolor/22x22/apps/" + m_strIcon + ".png";
+ }
+ }
+ entryMap.remove("Icon");
+ m_bTerminal = (config->readBoolEntry( "Terminal" )); // should be a property IMHO
+ entryMap.remove("Terminal");
+ m_strTerminalOptions = config->readEntry( "TerminalOptions" ); // should be a property IMHO
+ entryMap.remove("TerminalOptions");
+ m_strPath = config->readPath();
+ entryMap.remove("Path");
+ m_strComment = config->readComment();
+ entryMap.remove("Comment");
+ m_strGenName = config->readGenericName();
+ if (kde4application) {
+ m_strGenName += " [KDE4]";
+ }
+ entryMap.remove("GenericName");
+ TQString untranslatedGenericName = config->readEntryUntranslated( "GenericName" );
+ if (!untranslatedGenericName.isEmpty())
+ entryMap.insert("UntranslatedGenericName", untranslatedGenericName);
+
+ m_lstKeywords = config->readListEntry("Keywords");
+ entryMap.remove("Keywords");
+ d->categories = config->readListEntry("Categories", ';');
+ entryMap.remove("Categories");
+ m_strLibrary = config->readEntry( "X-TDE-Library" );
+ entryMap.remove("X-TDE-Library");
+ m_strInit = config->readEntry("X-TDE-Init" );
+ entryMap.remove("X-TDE-Init");
+
+ m_lstServiceTypes = config->readListEntry( "ServiceTypes" );
+ entryMap.remove("ServiceTypes");
+ // For compatibility with KDE 1.x
+ if (!kde4application)
+ m_lstServiceTypes += config->readListEntry( "MimeType", ';' );
+ entryMap.remove("MimeType");
+
+ if ( m_strType == "Application" && !m_lstServiceTypes.contains("Application") )
+ // Applications implement the service type "Application" ;-)
+ m_lstServiceTypes += "Application";
+
+ TQString dcopServiceType = config->readEntry("X-DCOP-ServiceType").lower();
+ entryMap.remove("X-DCOP-ServiceType");
+ if (dcopServiceType == "unique")
+ m_DCOPServiceType = DCOP_Unique;
+ else if (dcopServiceType == "multi")
+ m_DCOPServiceType = DCOP_Multi;
+ else if (dcopServiceType == "wait")
+ m_DCOPServiceType = DCOP_Wait;
+ else
+ m_DCOPServiceType = DCOP_None;
+
+ m_strDesktopEntryName = name.lower();
+ if (kde4application)
+ m_strDesktopEntryName = "kde4-" + m_strDesktopEntryName;
+
+ m_bAllowAsDefault = config->readBoolEntry( "AllowDefault", true );
+ entryMap.remove("AllowDefault");
+
+ m_initialPreference = config->readNumEntry( "X-TDE-InitialPreference", 1 );
+ entryMap.remove("X-TDE-InitialPreference");
+ if ( m_initialPreference == 1 )
+ m_initialPreference = config->readNumEntry( "InitialPreference", 1 );
+ entryMap.remove("InitialPreference");
+
+ // Store all additional entries in the property map.
+ // A TQMap<TQString,TQString> would be easier for this but we can't
+ // brake BC, so we have to store it in m_mapProps.
+// tqWarning("Path = %s", entryPath().latin1());
+ TQMap<TQString,TQString>::ConstIterator it = entryMap.begin();
+ for( ; it != entryMap.end();++it)
+ {
+ //tqDebug(" Key = %s Data = %s", it.key().latin1(), it.data().latin1());
+ TQString key = it.key();
+ if (kde4application && key=="OnlyShowIn" && it.data()=="KDE;")
+ key = "NotShowIn";
+ m_mapProps.insert( key, TQVariant( it.data()));
+ }
+}
+
+KService::KService( TQDataStream& _str, int offset ) : KSycocaEntry( _str, offset )
+{
+ d = new KServicePrivate;
+ load( _str );
+}
+
+KService::~KService()
+{
+ //debug("KService::~KService()");
+ delete d;
+}
+
+TQPixmap KService::pixmap( KIcon::Group _group, int _force_size, int _state, TQString * _path ) const
+{
+ KIconLoader *iconLoader=TDEGlobal::iconLoader();
+ if (!iconLoader->extraDesktopThemesAdded())
+ {
+ TQPixmap pixmap=iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path, true );
+ if (!pixmap.isNull() ) return pixmap;
+
+ iconLoader->addExtraDesktopThemes();
+ }
+
+ return iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path );
+}
+
+void KService::load( TQDataStream& s )
+{
+ // dummies are here because of fields that were removed, to keep bin compat.
+ // Feel free to re-use, but fields for Applications only (not generic services)
+ // should rather be added to application.desktop
+ TQ_INT8 def, term, dummy1, dummy2;
+ TQ_INT8 dst, initpref;
+ TQString dummyStr1, dummyStr2;
+ int dummyI1, dummyI2;
+ TQ_UINT32 dummyUI32;
+
+ // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
+ // !! This data structure should remain binary compatible at all times !!
+ // You may add new fields at the end. Make sure to update the version
+ // number in tdesycoca.h
+ s >> m_strType >> m_strName >> m_strExec >> m_strIcon
+ >> term >> m_strTerminalOptions
+ >> m_strPath >> m_strComment >> m_lstServiceTypes >> def >> m_mapProps
+ >> m_strLibrary >> dummyI1 >> dummyI2
+ >> dst
+ >> m_strDesktopEntryName
+ >> dummy1 >> dummyStr1 >> initpref >> dummyStr2 >> dummy2
+ >> m_lstKeywords >> m_strInit >> dummyUI32 >> m_strGenName
+ >> d->categories >> d->menuId;
+
+ m_bAllowAsDefault = def;
+ m_bTerminal = term;
+ m_DCOPServiceType = (DCOPServiceType_t) dst;
+ m_initialPreference = initpref;
+
+ m_bValid = true;
+}
+
+void KService::save( TQDataStream& s )
+{
+ KSycocaEntry::save( s );
+ TQ_INT8 def = m_bAllowAsDefault, initpref = m_initialPreference;
+ TQ_INT8 term = m_bTerminal;
+ TQ_INT8 dst = (TQ_INT8) m_DCOPServiceType;
+ TQ_INT8 dummy1 = 0, dummy2 = 0; // see ::load
+ TQString dummyStr1, dummyStr2;
+ int dummyI1 = 0, dummyI2 = 0;
+ TQ_UINT32 dummyUI32 = 0;
+
+ // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
+ // !! This data structure should remain binary compatible at all times !!
+ // You may add new fields at the end. Make sure to update the version
+ // number in tdesycoca.h
+ s << m_strType << m_strName << m_strExec << m_strIcon
+ << term << m_strTerminalOptions
+ << m_strPath << m_strComment << m_lstServiceTypes << def << m_mapProps
+ << m_strLibrary << dummyI1 << dummyI2
+ << dst
+ << m_strDesktopEntryName
+ << dummy1 << dummyStr1 << initpref << dummyStr2 << dummy2
+ << m_lstKeywords << m_strInit << dummyUI32 << m_strGenName
+ << d->categories << d->menuId;
+}
+
+bool KService::hasServiceType( const TQString& _servicetype ) const
+{
+ if (!m_bValid) return false; // safety test
+
+ //kdDebug(7012) << "Testing " << m_strDesktopEntryName << " for " << _servicetype << endl;
+
+ KMimeType::Ptr mimePtr = KMimeType::mimeType( _servicetype );
+ if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() )
+ mimePtr = 0;
+
+ bool isNumber;
+ // For each service type we are associated with, if it doesn't
+ // match then we try its parent service types.
+ TQStringList::ConstIterator it = m_lstServiceTypes.begin();
+ for( ; it != m_lstServiceTypes.end(); ++it )
+ {
+ (*it).toInt(&isNumber);
+ if (isNumber)
+ continue;
+ //kdDebug(7012) << " has " << (*it) << endl;
+ KServiceType::Ptr ptr = KServiceType::serviceType( *it );
+ if ( ptr && ptr->inherits( _servicetype ) )
+ return true;
+
+ // The mimetype inheritance ("is also") works the other way.
+ // e.g. if we're looking for a handler for mimePtr==smb-workgroup
+ // then a handler for inode/directory is ok.
+ if ( mimePtr && mimePtr->is( *it ) )
+ return true;
+ }
+ return false;
+}
+
+int KService::initialPreferenceForMimeType( const TQString& mimeType ) const
+{
+ if (!m_bValid) return 0; // safety test
+
+ bool isNumber;
+
+ // For each service type we are associated with
+ TQStringList::ConstIterator it = m_lstServiceTypes.begin();
+ for( ; it != m_lstServiceTypes.end(); ++it )
+ {
+ (*it).toInt(&isNumber);
+ if (isNumber)
+ continue;
+ //kdDebug(7012) << " has " << (*it) << endl;
+ KServiceType::Ptr ptr = KServiceType::serviceType( *it );
+ if ( !ptr || !ptr->inherits( mimeType ) )
+ continue;
+
+ int initalPreference = m_initialPreference;
+ ++it;
+ if (it != m_lstServiceTypes.end())
+ {
+ int i = (*it).toInt(&isNumber);
+ if (isNumber)
+ initalPreference = i;
+ }
+ return initalPreference;
+ }
+
+ KMimeType::Ptr mimePtr = KMimeType::mimeType( mimeType );
+ if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() )
+ mimePtr = 0;
+
+ // Try its parent service types.
+ it = m_lstServiceTypes.begin();
+ for( ; it != m_lstServiceTypes.end(); ++it )
+ {
+ (*it).toInt(&isNumber);
+ if (isNumber)
+ continue;
+
+ // The mimetype inheritance ("is also") works the other way.
+ // e.g. if we're looking for a handler for mimePtr==smb-workgroup
+ // then a handler for inode/directory is ok.
+ if ( !mimePtr || !mimePtr->is( *it ) )
+ continue;
+
+ int initalPreference = m_initialPreference;
+ ++it;
+ if (it != m_lstServiceTypes.end())
+ {
+ int i = (*it).toInt(&isNumber);
+ if (isNumber)
+ initalPreference = i;
+ }
+ return initalPreference;
+ }
+ return 0;
+}
+
+class KServiceReadProperty : public TDEConfigBase
+{
+public:
+ KServiceReadProperty(const TQString &_key, const TQCString &_value)
+ : key(_key), value(_value) { }
+
+ bool internalHasGroup(const TQCString &) const { /*tqDebug("hasGroup(const TQCString &)");*/ return false; }
+
+ TQStringList groupList() const { return TQStringList(); }
+
+ TQMap<TQString,TQString> entryMap(const TQString &group) const
+ { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
+
+ void reparseConfiguration() { }
+
+ KEntryMap internalEntryMap( const TQString &pGroup) const
+ { Q_UNUSED(pGroup); return KEntryMap(); }
+
+ KEntryMap internalEntryMap() const { return KEntryMap(); }
+
+ void putData(const KEntryKey &_key, const KEntry& _data, bool _checkGroup)
+ { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
+
+ KEntry lookupData(const KEntryKey &_key) const
+ { Q_UNUSED(_key); KEntry entry; entry.mValue = value; return entry; }
+protected:
+ TQString key;
+ TQCString value;
+};
+
+TQVariant KService::property( const TQString& _name) const
+{
+ return property( _name, TQVariant::Invalid);
+}
+
+// Return a string TQVariant if string isn't null, and invalid variant otherwise
+// (the variant must be invalid if the field isn't in the .desktop file)
+// This allows trader queries like "exist Library" to work.
+static TQVariant makeStringVariant( const TQString& string )
+{
+ // Using isEmpty here would be wrong.
+ // Empty is "specified but empty", null is "not specified" (in the .desktop file)
+ return string.isNull() ? TQVariant() : TQVariant( string );
+}
+
+TQVariant KService::property( const TQString& _name, TQVariant::Type t ) const
+{
+ if ( _name == "Type" )
+ return TQVariant( m_strType ); // can't be null
+ else if ( _name == "Name" )
+ return TQVariant( m_strName ); // can't be null
+ else if ( _name == "Exec" )
+ return makeStringVariant( m_strExec );
+ else if ( _name == "Icon" )
+ return makeStringVariant( m_strIcon );
+ else if ( _name == "Terminal" )
+ return TQVariant( static_cast<int>(m_bTerminal) );
+ else if ( _name == "TerminalOptions" )
+ return makeStringVariant( m_strTerminalOptions );
+ else if ( _name == "Path" )
+ return makeStringVariant( m_strPath );
+ else if ( _name == "Comment" )
+ return makeStringVariant( m_strComment );
+ else if ( _name == "GenericName" )
+ return makeStringVariant( m_strGenName );
+ else if ( _name == "ServiceTypes" )
+ return TQVariant( m_lstServiceTypes );
+ else if ( _name == "AllowAsDefault" )
+ return TQVariant( static_cast<int>(m_bAllowAsDefault) );
+ else if ( _name == "InitialPreference" )
+ return TQVariant( m_initialPreference );
+ else if ( _name == "Library" )
+ return makeStringVariant( m_strLibrary );
+ else if ( _name == "DesktopEntryPath" ) // can't be null
+ return TQVariant( entryPath() );
+ else if ( _name == "DesktopEntryName")
+ return TQVariant( m_strDesktopEntryName ); // can't be null
+ else if ( _name == "Categories")
+ return TQVariant( d->categories );
+ else if ( _name == "Keywords")
+ return TQVariant( m_lstKeywords );
+
+ // Ok we need to convert the property from a TQString to its real type.
+ // Maybe the caller helped us.
+ if (t == TQVariant::Invalid)
+ {
+ // No luck, let's ask KServiceTypeFactory what the type of this property
+ // is supposed to be.
+ t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
+ if (t == TQVariant::Invalid)
+ {
+ kdDebug(7012) << "Request for unknown property '" << _name << "'\n";
+ return TQVariant(); // Unknown property: Invalid variant.
+ }
+ }
+
+ // Then we use a homebuild class based on TDEConfigBase to convert the TQString.
+ // For some often used property types we do the conversion ourselves.
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( _name );
+ if ( (it == m_mapProps.end()) || (!it.data().isValid()))
+ {
+ //kdDebug(7012) << "Property not found " << _name << endl;
+ return TQVariant(); // No property set.
+ }
+
+ switch(t)
+ {
+ case TQVariant::String:
+ return it.data();
+ case TQVariant::Bool:
+ case TQVariant::Int:
+ {
+ TQString aValue = it.data().toString();
+ int val = 0;
+ if (aValue == "true" || aValue == "on" || aValue == "yes")
+ val = 1;
+ else
+ {
+ bool bOK;
+ val = aValue.toInt( &bOK );
+ if( !bOK )
+ val = 0;
+ }
+ if (t == TQVariant::Bool)
+ {
+ return TQVariant((bool)val, 1);
+ }
+ return TQVariant(val);
+ }
+ default:
+ // All others
+ KServiceReadProperty ksrp(_name, it.data().toString().utf8());
+ return ksrp.readPropertyEntry(_name, t);
+ }
+}
+
+TQStringList KService::propertyNames() const
+{
+ TQStringList res;
+
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.begin();
+ for( ; it != m_mapProps.end(); ++it )
+ res.append( it.key() );
+
+ res.append( "Type" );
+ res.append( "Name" );
+ res.append( "Comment" );
+ res.append( "GenericName" );
+ res.append( "Icon" );
+ res.append( "Exec" );
+ res.append( "Terminal" );
+ res.append( "TerminalOptions" );
+ res.append( "Path" );
+ res.append( "ServiceTypes" );
+ res.append( "AllowAsDefault" );
+ res.append( "InitialPreference" );
+ res.append( "Library" );
+ res.append( "DesktopEntryPath" );
+ res.append( "DesktopEntryName" );
+ res.append( "Keywords" );
+ res.append( "Categories" );
+
+ return res;
+}
+
+KService::List KService::allServices()
+{
+ return KServiceFactory::self()->allServices();
+}
+
+KService::Ptr KService::serviceByName( const TQString& _name )
+{
+ KService * s = KServiceFactory::self()->findServiceByName( _name );
+ return KService::Ptr( s );
+}
+
+KService::Ptr KService::serviceByDesktopPath( const TQString& _name )
+{
+ KService * s = KServiceFactory::self()->findServiceByDesktopPath( _name );
+ return KService::Ptr( s );
+}
+
+KService::Ptr KService::serviceByDesktopName( const TQString& _name )
+{
+ KService * s = KServiceFactory::self()->findServiceByDesktopName( _name.lower() );
+ if (!s && !_name.startsWith("kde-"))
+ s = KServiceFactory::self()->findServiceByDesktopName( "kde-"+_name.lower() );
+ return KService::Ptr( s );
+}
+
+KService::Ptr KService::serviceByMenuId( const TQString& _name )
+{
+ KService * s = KServiceFactory::self()->findServiceByMenuId( _name );
+ return KService::Ptr( s );
+}
+
+KService::Ptr KService::serviceByStorageId( const TQString& _storageId )
+{
+ KService::Ptr service = KService::serviceByMenuId( _storageId );
+ if (service)
+ return service;
+
+ service = KService::serviceByDesktopPath(_storageId);
+ if (service)
+ return service;
+
+ if (!TQDir::isRelativePath(_storageId) && TQFile::exists(_storageId))
+ return new KService(_storageId);
+
+ TQString tmp = _storageId;
+ tmp = tmp.mid(tmp.findRev('/')+1); // Strip dir
+
+ if (tmp.endsWith(".desktop"))
+ tmp.truncate(tmp.length()-8);
+
+ if (tmp.endsWith(".kdelnk"))
+ tmp.truncate(tmp.length()-7);
+
+ service = KService::serviceByDesktopName(tmp);
+
+ return service;
+}
+
+KService::List KService::allInitServices()
+{
+ return KServiceFactory::self()->allInitServices();
+}
+
+bool KService::substituteUid() const {
+ TQVariant v = property("X-TDE-SubstituteUID", TQVariant::Bool);
+ return v.isValid() && v.toBool();
+}
+
+TQString KService::username() const {
+ // See also KDesktopFile::tryExec()
+ TQString user;
+ TQVariant v = property("X-TDE-Username", TQVariant::String);
+ user = v.isValid() ? v.toString() : TQString::null;
+ if (user.isEmpty())
+ user = ::getenv("ADMIN_ACCOUNT");
+ if (user.isEmpty())
+ user = "root";
+ return user;
+}
+
+bool KService::noDisplay() const {
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "NoDisplay" );
+ if ( (it != m_mapProps.end()) && (it.data().isValid()))
+ {
+ TQString aValue = it.data().toString().lower();
+ if (aValue == "true" || aValue == "on" || aValue == "yes")
+ return true;
+ }
+
+ it = m_mapProps.find( "OnlyShowIn" );
+ if ( (it != m_mapProps.end()) && (it.data().isValid()))
+ {
+ TQString aValue = it.data().toString();
+ TQStringList aList = TQStringList::split(';', aValue);
+ if ((!aList.contains("TDE")) && (!aList.contains("KDE")))
+ return true;
+ }
+
+ it = m_mapProps.find( "NotShowIn" );
+ if ( (it != m_mapProps.end()) && (it.data().isValid()))
+ {
+ TQString aValue = it.data().toString();
+ TQStringList aList = TQStringList::split(';', aValue);
+ if ((aList.contains("TDE")) || (aList.contains("KDE")))
+ return true;
+ }
+
+ if (!kapp->authorizeControlModule(d->menuId))
+ return true;
+
+ return false;
+}
+
+TQString KService::untranslatedGenericName() const {
+ TQVariant v = property("UntranslatedGenericName", TQVariant::String);
+ return v.isValid() ? v.toString() : TQString::null;
+}
+
+bool KService::SuSEunimportant() const {
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "X-SuSE-Unimportant" );
+ if ( (it == m_mapProps.end()) || (!it.data().isValid()))
+ {
+ return false;
+ }
+
+ TQString aValue = it.data().toString();
+ if (aValue == "true" || aValue == "on" || aValue == "yes")
+ return true;
+ else
+ return false;
+}
+
+TQString KService::parentApp() const {
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "X-TDE-ParentApp" );
+ if ( (it == m_mapProps.end()) || (!it.data().isValid()))
+ {
+ return TQString::null;
+ }
+
+ return it.data().toString();
+}
+
+bool KService::allowMultipleFiles() const {
+ // Can we pass multiple files on the command line or do we have to start the application for every single file ?
+ if ( m_strExec.find( "%F" ) != -1 || m_strExec.find( "%U" ) != -1 ||
+ m_strExec.find( "%N" ) != -1 || m_strExec.find( "%D" ) != -1 )
+ return true;
+ else
+ return false;
+}
+
+TQStringList KService::categories() const
+{
+ return d->categories;
+}
+
+TQString KService::menuId() const
+{
+ return d->menuId;
+}
+
+void KService::setMenuId(const TQString &menuId)
+{
+ d->menuId = menuId;
+}
+
+TQString KService::storageId() const
+{
+ if (!d->menuId.isEmpty())
+ return d->menuId;
+ return entryPath();
+}
+
+TQString KService::locateLocal()
+{
+ if (d->menuId.isEmpty() || desktopEntryPath().startsWith(".hidden") ||
+ (TQDir::isRelativePath(desktopEntryPath()) && d->categories.isEmpty()))
+ return KDesktopFile::locateLocal(desktopEntryPath());
+
+ return ::locateLocal("xdgdata-apps", d->menuId);
+}
+
+TQString KService::newServicePath(bool showInMenu, const TQString &suggestedName,
+ TQString *menuId, const TQStringList *reservedMenuIds)
+{
+ TQString base = suggestedName;
+ if (!showInMenu)
+ base.prepend("kde-");
+
+ TQString result;
+ for(int i = 1; true; i++)
+ {
+ if (i == 1)
+ result = base + ".desktop";
+ else
+ result = base + TQString("-%1.desktop").arg(i);
+
+ if (reservedMenuIds && reservedMenuIds->contains(result))
+ continue;
+
+ // Lookup service by menu-id
+ KService::Ptr s = serviceByMenuId(result);
+ if (s)
+ continue;
+
+ if (showInMenu)
+ {
+ if (!locate("xdgdata-apps", result).isEmpty())
+ continue;
+ }
+ else
+ {
+ TQString file = result.mid(4); // Strip "kde-"
+ if (!locate("apps", ".hidden/"+file).isEmpty())
+ continue;
+ }
+
+ break;
+ }
+ if (menuId)
+ *menuId = result;
+
+ if (showInMenu)
+ {
+ return ::locateLocal("xdgdata-apps", result);
+ }
+ else
+ {
+ TQString file = result.mid(4); // Strip "kde-"
+ return ::locateLocal("apps", ".hidden/"+file);
+ }
+}
+
+
+void KService::virtual_hook( int id, void* data )
+{ KSycocaEntry::virtual_hook( id, data ); }
+
+
+void KService::rebuildKSycoca(TQWidget *parent)
+{
+ KServiceProgressDialog dlg(parent, "tdesycoca_progress",
+ i18n("Updating System Configuration"),
+ i18n("Updating system configuration."));
+
+ TQByteArray data;
+ DCOPClient *client = kapp->dcopClient();
+
+ int result = client->callAsync("kded", "tdebuildsycoca", "recreate()",
+ data, TQT_TQOBJECT(&dlg), TQT_SLOT(slotFinished()));
+
+ if (result)
+ {
+ dlg.exec();
+ }
+}
+
+KServiceProgressDialog::KServiceProgressDialog(TQWidget *parent, const char *name,
+ const TQString &caption, const TQString &text)
+ : KProgressDialog(parent, name, caption, text, true)
+{
+ connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotProgress()));
+ progressBar()->setTotalSteps(20);
+ m_timeStep = 700;
+ m_timer.start(m_timeStep);
+ setAutoClose(false);
+}
+
+void
+KServiceProgressDialog::slotProgress()
+{
+ int p = progressBar()->progress();
+ if (p == 18)
+ {
+ progressBar()->reset();
+ progressBar()->setProgress(1);
+ m_timeStep = m_timeStep * 2;
+ m_timer.start(m_timeStep);
+ }
+ else
+ {
+ progressBar()->setProgress(p+1);
+ }
+}
+
+void
+KServiceProgressDialog::slotFinished()
+{
+ progressBar()->setProgress(20);
+ m_timer.stop();
+ TQTimer::singleShot(1000, this, TQT_SLOT(close()));
+}
+
+#include "kservice_p.moc"
diff --git a/tdeio/tdeio/kservice.h b/tdeio/tdeio/kservice.h
new file mode 100644
index 000000000..4db478ba6
--- /dev/null
+++ b/tdeio/tdeio/kservice.h
@@ -0,0 +1,562 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __kservices_h__
+#define __kservices_h__
+
+#include <tqstringlist.h>
+#include <tqmap.h>
+#include <tqvariant.h>
+#include <kicontheme.h>
+
+#include "tdesycocaentry.h"
+
+class TQDataStream;
+class KDesktopFile;
+class KService;
+class KBuildSycoca;
+class TQWidget;
+
+/**
+ * Represent a service, i.e. an application bound to one or several mimetypes
+ * (or servicetypes) as written in its desktop entry file.
+ *
+ * A service may be a library, too.
+ * The starting point you need is often the static methods.
+ * Service types are stored as desktop files in the "service" resource..
+ *
+ * @see KServiceType
+ * @see KServiceGroup
+ * @author Torben Weis <weis@kde.org>
+ */
+class TDEIO_EXPORT KService : public KSycocaEntry
+{
+ K_SYCOCATYPE( KST_KService, KSycocaEntry )
+
+ friend class KBuildSycoca;
+
+public:
+ typedef KSharedPtr<KService> Ptr;
+ typedef TQValueList<Ptr> List;
+public:
+ /**
+ * Construct a temporary service with a given name, exec-line and icon.
+ * @param _name the name of the service
+ * @param _exec the executable
+ * @param _icon the name of the icon
+ */
+ KService( const TQString & _name, const TQString &_exec, const TQString &_icon);
+
+ /**
+ * Construct a service and take all information from a config file.
+ *
+ * @param _fullpath Full path to the config file.
+ */
+ explicit KService( const TQString & _fullpath );
+
+ /**
+ * Construct a service and take all information from a desktop file.
+ * @param config the desktop file to read
+ */
+ KService( KDesktopFile *config ); // KDE-4.0: make explicit
+
+ /**
+ * @internal
+ * Construct a service from a stream.
+ * The stream must already be positionned at the correct offset.
+ */
+ KService( TQDataStream& _str, int offset );
+
+ virtual ~KService();
+
+ /**
+ * Returns the type of the service.
+ * @return the type of the service ("Application" or "Service")
+ */
+ virtual TQString type() const { return m_strType; }
+ /**
+ * Returns the name of the service.
+ * @return the name of the service,
+ * or TQString::null if not set
+ */
+ virtual TQString name() const { return m_strName; }
+ /**
+ * Returns the executable.
+ * @return the command that the service executes,
+ * or TQString::null if not set
+ */
+ TQString exec() const { return m_strExec; }
+ /**
+ * Returns the name of the service's library.
+ * @return the name of the library that contains the services
+ * implementation,
+ * or TQString::null if not set
+ */
+ TQString library() const { return m_strLibrary; }
+ /**
+ * Returns the name of the init function to call (KControl modules).
+ * @return the name of the init function to call in this service
+ * during startup of KDE. (KControl modules only),
+ * or TQString::null if not set
+ */
+ TQString init() const { return m_strInit; }
+
+ /**
+ * Returns the name of the icon.
+ * @return the icon associated with the service,
+ * or "unknown" if not set
+ */
+ TQString icon() const { return m_strIcon; }
+ /**
+ * Returns the pixmap that represents the icon.
+ * @return a pixmap for this service (finds and loads icon()),
+ * null if not set
+ * @see icon()
+ */
+ TQPixmap pixmap( KIcon::Group _group, int _force_size = 0, int _state = 0,
+ TQString * _path = 0L ) const;
+ /**
+ * Checks whethe the service should be run in a terminal.
+ * @return true if the service is to be run in a terminal.
+ */
+ bool terminal() const { return m_bTerminal; }
+ /**
+ * Returns any options associated with the terminal the service
+ * runs in, if it requires a terminal.
+ *
+ * The service must be a tty-oriented program.
+ * @return the terminal options,
+ * or TQString::null if not set
+ */
+ TQString terminalOptions() const { return m_strTerminalOptions; }
+ /**
+ * Checks whether the service runs with a different user id.
+ * @return true if the service has to be run under a different uid.
+ * @see username()
+ */
+ bool substituteUid() const;
+ /**
+ * Returns the user name, if the service runs with a
+ * different user id.
+ * @return the username under which the service has to be run,
+ * or TQString::null if not set
+ * @see substututeUid()a
+ */
+ TQString username() const;
+
+ /**
+ * Returns the path to the location where the service desktop entry
+ * is stored.
+ *
+ * This is a relative path if the desktop entry was found in any
+ * of the locations pointed to by $TDEDIRS (e.g. "Internet/kppp.desktop")
+ * It is a full path if the desktop entry originates from another
+ * location.
+ * @return the path of the service's desktop file,
+ * or TQString::null if not set
+ */
+ TQString desktopEntryPath() const { return entryPath(); }
+
+ /**
+ * Returns the filename of the service desktop entry without any
+ * extension. E.g. "kppp"
+ * @return the name of the desktop entry without path or extension,
+ * or TQString::null if not set
+ */
+ TQString desktopEntryName() const { return m_strDesktopEntryName; }
+
+ /**
+ * Returns the menu ID of the service desktop entry.
+ * The menu ID is used to add or remove the entry to a menu.
+ * @return the menu ID
+ * @since 3.2
+ */
+ TQString menuId() const;
+
+ /**
+ * Returns a normalized ID suitable for storing in configuration files.
+ * It will be based on the menu-id when available and otherwise falls
+ * back to desktopEntryPath()
+ * @return the storage ID
+ * @since 3.2
+ */
+ TQString storageId() const;
+
+ /**
+ * Describes the DCOP type of the service.
+ * @li None - This service has no DCOP support
+ * @li Unique - This service provides a unique DCOP service.
+ * The service name is equal to the desktopEntryName.
+ * @li Multi - This service provides a DCOP service which can be run
+ * with multiple instances in parallel. The service name of
+ * an instance is equal to the desktopEntryName + "-" +
+ * the PID of the process.
+ * @li Wait - This service has no DCOP support, the launcher will wait
+ * till it is finished.
+ */
+ enum DCOPServiceType_t { DCOP_None = 0, DCOP_Unique, DCOP_Multi, DCOP_Wait };
+
+ /**
+ * Returns the DCOPServiceType supported by this service.
+ * @return the DCOPServiceType supported by this service
+ */
+ DCOPServiceType_t DCOPServiceType() const { return m_DCOPServiceType; }
+
+ /**
+ * Returns the working directory to run the program in.
+ * @return the working directory to run the program in,
+ * or TQString::null if not set
+ */
+ TQString path() const { return m_strPath; }
+
+ /**
+ * Returns the descriptive comment for the service, if there is one.
+ * @return the descriptive comment for the service, or TQString::null
+ * if not set
+ */
+ TQString comment() const { return m_strComment; }
+
+ /**
+ * Returns the generic name for the service, if there is one
+ * (e.g. "Mail Client").
+ * @return the generic name,
+ * or TQString::null if not set
+ */
+ TQString genericName() const { return m_strGenName; }
+
+ /**
+ * Returns the untranslated (US English) generic name
+ * for the service, if there is one
+ * (e.g. "Mail Client").
+ * @return the generic name,
+ * or TQString::null if not set
+ * @since 3.2
+ */
+ TQString untranslatedGenericName() const;
+
+ /**
+ * Returns a list of descriptive keywords the service, if there are any.
+ * @return the list of keywords
+ */
+ TQStringList keywords() const { return m_lstKeywords; }
+
+ /**
+ * Returns a list of VFolder categories.
+ * @return the list of VFolder categories
+ * @since 3.1
+ */
+ TQStringList categories() const;
+
+ /**
+ * Returns the service types that this service supports.
+ * @return the list of service types that are supported
+ */
+ TQStringList serviceTypes() const { return m_lstServiceTypes; }
+
+ /**
+ * Checks whether the service supports this service type
+ * @param _service The name of the service type you are
+ * interested in determining whether this services supports.
+ *
+ * @return true if the service you specified is supported,
+ * otherwise false.
+ */
+ bool hasServiceType( const TQString& _service ) const;
+
+ /**
+ * Set to true if it is allowed to use this service as the default (main)
+ * action for the files it supports (e.g. Left Click in a file manager, or KRun in general).
+ *
+ * If not, then this service is only available in RMB popups, so it must
+ * be selected explicitely by the user in order to be used.
+ * Note that servicemenus supersede this functionality though, at least in konqueror.
+ *
+ * @return true if the service may be used as the default (main) handler
+ */
+ bool allowAsDefault() const { return m_bAllowAsDefault; }
+
+ /**
+ * Checks whether this service can handle several files as
+ * startup arguments.
+ * @return true if multiple files may be passed to this service at
+ * startup. False if only one file at a time may be passed.
+ */
+ bool allowMultipleFiles() const;
+
+ /**
+ * What preference to associate with this service initially (before
+ * the user has had any chance to define a profile for it).
+ * The bigger the value, the most preferred the service is.
+ * @return the service preference level of the service
+ */
+ int initialPreference() const { return m_initialPreference; }
+
+ /**
+ * What preference to associate with this service initially
+ * for handling the specified mimetype. (before the user has
+ * had any chance to define a profile for it).
+ * The bigger the value, the most preferred the service is.
+ * @return the service preference level of the service for
+ * this mimetype
+ */
+ int initialPreferenceForMimeType( const TQString& mimeType ) const;
+
+ /**
+ * @internal. Allows KServiceType::offers to tweak the initial preference.
+ */
+ void setInitialPreference( int i ) { m_initialPreference = i; }
+
+ /**
+ * Whether the entry should be suppressed in menus.
+ * @return true to suppress this service
+ */
+ bool noDisplay() const;
+ /**
+ * check if the application entry is important
+ */
+ bool SuSEunimportant() const;
+
+ /**
+ * Name of the application this service belongs to.
+ * (Useful for e.g. plugins)
+ * @return the parent application, or TQString::null if not set
+ * @since 3.1
+ */
+ TQString parentApp() const;
+
+ /**
+ * Returns the requested property. Some often used properties
+ * have convenience access functions like exec(),
+ * serviceTypes etc.
+ *
+ * It depends upon the serviceTypes() of this service which
+ * properties a service can have.
+ *
+ * @param _name the name of the property
+ * @return the property, or invalid if not found
+ * @see KServiceType
+ */
+ virtual TQVariant property( const TQString& _name ) const;
+
+ /**
+ * Returns the requested property.
+ *
+ * @param _name the name of the property
+ * @param t the assumed type of the property
+ * @return the property, or invalid if not found
+ * @see KServiceType
+ * @since 3.2
+ */
+ TQVariant property( const TQString& _name, TQVariant::Type t ) const;
+
+ /**
+ * Returns the list of all properties that this service can have.
+ * That means, that some of these properties may be empty.
+ * @return the list of supported properties
+ */
+ virtual TQStringList propertyNames() const;
+
+ /**
+ * Checks whether the service is valid.
+ * @return true if the service is valid (e.g. name is not empty)
+ */
+ bool isValid() const { return m_bValid; }
+
+ /**
+ * Returns a path that can be used for saving changes to this
+ * service
+ * @return path that can be used for saving changes to this service
+ * @since 3.2
+ */
+ TQString locateLocal();
+
+ /**
+ * @internal
+ * Load the service from a stream.
+ */
+ virtual void load( TQDataStream& );
+ /**
+ * @internal
+ * Save the service to a stream.
+ */
+ virtual void save( TQDataStream& );
+ /**
+ * @internal
+ * Set the menu id
+ */
+ void setMenuId(const TQString &menuId);
+ /**
+ * @internal
+ * Sets whether to use a terminal or not
+ */
+ void setTerminal(bool b) { m_bTerminal = b; }
+ /**
+ * @internal
+ * Sets the terminal options to use
+ */
+ void setTerminalOptions(const TQString &options) { m_strTerminalOptions = options; }
+
+ /**
+ * Find a service by name, i.e. the translated Name field. You should
+ * really not use this method, since the name is translated.
+ *
+ * @param _name the name to search
+ * @return a pointer to the requested service or 0 if the service is
+ * unknown.
+ * @em Very @em important: Don't store the result in a KService* !
+ */
+ static Ptr serviceByName( const TQString& _name );
+
+ /**
+ * Find a service based on its path as returned by desktopEntryPath().
+ * It's usually better to use serviceByStorageId() instead.
+ *
+ * @param _path the path of the configuration file
+ * @return a pointer to the requested service or 0 if the service is
+ * unknown.
+ * @em Very @em important: Don't store the result in a KService* !
+ */
+ static Ptr serviceByDesktopPath( const TQString& _path );
+
+ /**
+ * Find a service by the name of its desktop file, not depending on
+ * its actual location (as long as it's under the applnk or service
+ * directories). For instance "konqbrowser" or "kcookiejar". Note that
+ * the ".desktop" extension is implicit.
+ *
+ * This is the recommended method (safe even if the user moves stuff)
+ * but note that it assumes that no two entries have the same filename.
+ *
+ * @param _name the name of the configuration file
+ * @return a pointer to the requested service or 0 if the service is
+ * unknown.
+ * @em Very @em important: Don't store the result in a KService* !
+ */
+ static Ptr serviceByDesktopName( const TQString& _name );
+
+ /**
+ * Find a service by its menu-id
+ *
+ * @param _menuId the menu id of the service
+ * @return a pointer to the requested service or 0 if the service is
+ * unknown.
+ * @em Very @em important: Don't store the result in a KService* !
+ * @since 3.2
+ */
+ static Ptr serviceByMenuId( const TQString& _menuId );
+
+ /**
+ * Find a service by its storage-id or desktop-file path. This
+ * function will try very hard to find a matching service.
+ *
+ * @param _storageId the storage id or desktop-file path of the service
+ * @return a pointer to the requested service or 0 if the service is
+ * unknown.
+ * @em Very @em important: Don't store the result in a KService* !
+ * @since 3.2
+ */
+ static Ptr serviceByStorageId( const TQString& _storageId );
+
+ /**
+ * Returns the whole list of services.
+ *
+ * Useful for being able to
+ * to display them in a list box, for example.
+ * More memory consuming than the ones above, don't use unless
+ * really necessary.
+ * @return the list of all services
+ */
+ static List allServices();
+
+ /**
+ * Returns all services that require initialisation.
+ *
+ * Only needed by "kcminit"
+ * @return the list of all services that need to be initialized
+ */
+ static List allInitServices();
+
+ /**
+ * Returns a path that can be used to create a new KService based
+ * on @p suggestedName.
+ * @param showInMenu true, if the service should be shown in the TDE menu
+ * false, if the service should be hidden from the menu
+ * @param suggestedName name to base the file on, if a service with such
+ * name already exists, a prefix will be added to make it unique.
+ * @param menuId If provided, menuId will be set to the menu id to use for
+ * the KService
+ * @param reservedMenuIds If provided, the path and menu id will be chosen
+ * in such a way that the new menu id does not conflict with any
+ * of the reservedMenuIds
+ * @return The path to use for the new KService.
+ * @since 3.2
+ */
+ static TQString newServicePath(bool showInMenu, const TQString &suggestedName,
+ TQString *menuId = 0,
+ const TQStringList *reservedMenuIds = 0);
+
+
+ /**
+ * Rebuild KSycoca and show a progress dialog while doing so.
+ * @param parent Parent widget for the progress dialog
+ * @since 3.2
+ */
+ static void rebuildKSycoca(TQWidget *parent);
+
+protected:
+
+ void init(KDesktopFile *config);
+
+ TQStringList &accessServiceTypes() { return m_lstServiceTypes; }
+
+
+private:
+ KService( const KService& ); // forbidden
+ KService& operator=(const KService&);
+
+ TQString m_strType;
+ TQString m_strName;
+ TQString m_strExec;
+ TQString m_strIcon;
+ TQString m_strTerminalOptions;
+ TQString m_strPath;
+ TQString m_strComment;
+ TQString m_strLibrary;
+ TQStringList m_lstServiceTypes;
+ bool m_bAllowAsDefault;
+ int m_initialPreference;
+ bool m_bTerminal;
+ //bool m_bSuid;
+ //TQString m_strUsername;
+ TQString m_strDesktopEntryName;
+ //TQString m_docPath;
+ //bool m_bHideFromPanel;
+ DCOPServiceType_t m_DCOPServiceType;
+ TQMap<TQString,TQVariant> m_mapProps;
+ bool m_bValid;
+ TQStringList m_lstKeywords;
+ TQString m_strInit;
+ TQString m_strGenName;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KServicePrivate;
+ KServicePrivate* d;
+};
+#endif
diff --git a/tdeio/tdeio/kservice_p.h b/tdeio/tdeio/kservice_p.h
new file mode 100644
index 000000000..180ab8fc3
--- /dev/null
+++ b/tdeio/tdeio/kservice_p.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 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 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 __kservices_p_h__
+#define __kservices_p_h__
+
+#include <tqtimer.h>
+
+#include <kprogress.h>
+
+class KServiceProgressDialog : public KProgressDialog
+{
+ Q_OBJECT
+public:
+ KServiceProgressDialog(TQWidget *parent, const char *name,
+ const TQString &caption, const TQString &text);
+public slots:
+ void slotProgress();
+ void slotFinished();
+
+private:
+ TQTimer m_timer;
+ int m_timeStep;
+};
+
+#endif
diff --git a/tdeio/tdeio/kservicefactory.cpp b/tdeio/tdeio/kservicefactory.cpp
new file mode 100644
index 000000000..f4646fa75
--- /dev/null
+++ b/tdeio/tdeio/kservicefactory.cpp
@@ -0,0 +1,291 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 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 "kservicefactory.h"
+#include "tdesycoca.h"
+#include "tdesycocatype.h"
+#include "tdesycocadict.h"
+#include "kservice.h"
+
+#include <tqstring.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kstaticdeleter.h>
+
+KServiceFactory::KServiceFactory()
+ : KSycocaFactory( KST_KServiceFactory )
+{
+ m_offerListOffset = 0;
+ m_nameDictOffset = 0;
+ m_relNameDictOffset = 0;
+ m_menuIdDictOffset = 0;
+ if (m_str)
+ {
+ // Read Header
+ TQ_INT32 i;
+ (*m_str) >> i;
+ m_nameDictOffset = i;
+ (*m_str) >> i;
+ m_relNameDictOffset = i;
+ (*m_str) >> i;
+ m_offerListOffset = i;
+ (*m_str) >> i;
+ m_initListOffset = i;
+ (*m_str) >> i;
+ m_menuIdDictOffset = i;
+
+ int saveOffset = m_str->device()->at();
+ // Init index tables
+ m_nameDict = new KSycocaDict(m_str, m_nameDictOffset);
+ // Init index tables
+ m_relNameDict = new KSycocaDict(m_str, m_relNameDictOffset);
+ // Init index tables
+ m_menuIdDict = new KSycocaDict(m_str, m_menuIdDictOffset);
+ saveOffset = m_str->device()->at(saveOffset);
+ }
+ else
+ {
+ // Build new database
+ m_nameDict = new KSycocaDict();
+ m_relNameDict = new KSycocaDict();
+ m_menuIdDict = new KSycocaDict();
+ }
+ _self = this;
+}
+
+KServiceFactory::~KServiceFactory()
+{
+ _self = 0L;
+ delete m_nameDict;
+ delete m_relNameDict;
+ delete m_menuIdDict;
+}
+
+KServiceFactory * KServiceFactory::self()
+{
+ if (!_self) {
+ _self = new KServiceFactory();
+ }
+ return _self;
+}
+
+KService * KServiceFactory::findServiceByName(const TQString &_name)
+{
+ if (!m_sycocaDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByName isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_sycocaDict->find_string( _name );
+ if (!offset) return 0; // Not found
+
+ KService * newService = createEntry(offset);
+
+ // Check whether the dictionary was right.
+ if (newService && (newService->name() != _name))
+ {
+ // No it wasn't...
+ delete newService;
+ newService = 0; // Not found
+ }
+ return newService;
+}
+
+KService * KServiceFactory::findServiceByDesktopName(const TQString &_name)
+{
+ if (!m_nameDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByName isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_nameDict->find_string( _name );
+ if (!offset) return 0; // Not found
+
+ KService * newService = createEntry(offset);
+
+ // Check whether the dictionary was right.
+ if (newService && (newService->desktopEntryName() != _name))
+ {
+ // No it wasn't...
+ delete newService;
+ newService = 0; // Not found
+ }
+ return newService;
+}
+
+KService * KServiceFactory::findServiceByDesktopPath(const TQString &_name)
+{
+ if (!m_relNameDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByName isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_relNameDict->find_string( _name );
+ if (!offset) return 0; // Not found
+
+ KService * newService = createEntry(offset);
+
+ // Check whether the dictionary was right.
+ if (newService && (newService->desktopEntryPath() != _name))
+ {
+ // No it wasn't...
+ delete newService;
+ newService = 0; // Not found
+ }
+ return newService;
+}
+
+KService * KServiceFactory::findServiceByMenuId(const TQString &_menuId)
+{
+ if (!m_menuIdDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByMenuId isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_menuIdDict->find_string( _menuId );
+ if (!offset) return 0; // Not found
+
+ KService * newService = createEntry(offset);
+
+ // Check whether the dictionary was right.
+ if (newService && (newService->menuId() != _menuId))
+ {
+ // No it wasn't...
+ delete newService;
+ newService = 0; // Not found
+ }
+ return newService;
+}
+
+KService* KServiceFactory::createEntry(int offset)
+{
+ KService * newEntry = 0L;
+ KSycocaType type;
+ TQDataStream *str = KSycoca::self()->findEntry(offset, type);
+ switch(type)
+ {
+ case KST_KService:
+ newEntry = new KService(*str, offset);
+ break;
+
+ default:
+ kdError(7011) << TQString(TQString("KServiceFactory: unexpected object entry in KSycoca database (type = %1)").arg((int)type)) << endl;
+ return 0;
+ }
+ if (!newEntry->isValid())
+ {
+ kdError(7011) << "KServiceFactory: corrupt object in KSycoca database!\n" << endl;
+ delete newEntry;
+ newEntry = 0;
+ }
+ return newEntry;
+}
+
+KService::List KServiceFactory::allServices()
+{
+ KService::List result;
+ KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::Iterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ KService *newService = dynamic_cast<KService *>((*it).data());
+ if (newService)
+ result.append( KService::Ptr( newService ) );
+ }
+ return result;
+}
+
+KService::List KServiceFactory::allInitServices()
+{
+ KService::List list;
+ if (!m_str) return list;
+
+ // Assume we're NOT building a database
+
+ m_str->device()->at(m_initListOffset);
+ TQ_INT32 entryCount;
+ (*m_str) >> entryCount;
+
+ TQ_INT32 *offsetList = new TQ_INT32[entryCount];
+ for(int i = 0; i < entryCount; i++)
+ {
+ (*m_str) >> offsetList[i];
+ }
+
+ for(int i = 0; i < entryCount; i++)
+ {
+ KService *newEntry = createEntry(offsetList[i]);
+ if (newEntry)
+ {
+ list.append( KService::Ptr( newEntry ) );
+ }
+ }
+ delete [] offsetList;
+ return list;
+}
+
+KService::List KServiceFactory::offers( int serviceTypeOffset )
+{
+ KService::List list;
+
+ TQDataStream *str = m_str;
+ // Jump to the offer list
+ str->device()->at( m_offerListOffset );
+
+ TQ_INT32 aServiceTypeOffset;
+ TQ_INT32 aServiceOffset;
+ // We might want to do a binary search instead of a linear search
+ // since servicetype offsets are sorted. Bah.
+ while (true)
+ {
+ (*str) >> aServiceTypeOffset;
+ if ( aServiceTypeOffset )
+ {
+ (*str) >> aServiceOffset;
+ if ( aServiceTypeOffset == serviceTypeOffset )
+ {
+ // Save stream position !
+ int savedPos = str->device()->at();
+ // Create Service
+ KService * serv = createEntry( aServiceOffset );
+ if (serv)
+ list.append( KService::Ptr( serv ) );
+ // Restore position
+ str->device()->at( savedPos );
+ } else if ( aServiceTypeOffset > (TQ_INT32)serviceTypeOffset )
+ break; // too far
+ }
+ else
+ break; // 0 => end of list
+ }
+ return list;
+}
+
+KServiceFactory *KServiceFactory::_self = 0;
+
+void KServiceFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/kservicefactory.h b/tdeio/tdeio/kservicefactory.h
new file mode 100644
index 000000000..4e6df6534
--- /dev/null
+++ b/tdeio/tdeio/kservicefactory.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __kservicefactory_h__
+#define __kservicefactory_h__
+
+#include <tqstringlist.h>
+
+#include "kservice.h"
+#include "tdesycocafactory.h"
+#include <assert.h>
+
+class KSycoca;
+class KSycocaDict;
+
+/**
+ * @internal
+ * A sycoca factory for services (e.g. applications)
+ * It loads the services from parsing directories (e.g. applnk/)
+ * but can also create service from data streams or single config files
+ */
+class TDEIO_EXPORT KServiceFactory : public KSycocaFactory
+{
+ K_SYCOCAFACTORY( KST_KServiceFactory )
+public:
+ /**
+ * Create factory
+ */
+ KServiceFactory();
+ virtual ~KServiceFactory();
+
+ /**
+ * Construct a KService from a config file.
+ */
+ virtual KSycocaEntry *createEntry(const TQString &, const char *)
+ { assert(0); return 0; }
+
+ /**
+ * Find a service (by name, e.g. "Terminal")
+ */
+ KService * findServiceByName( const TQString &_name );
+
+ /**
+ * Find a service (by desktop file name, e.g. "konsole")
+ */
+ KService * findServiceByDesktopName( const TQString &_name );
+
+ /**
+ * Find a service ( by desktop path, e.g. "System/konsole.desktop")
+ */
+ KService * findServiceByDesktopPath( const TQString &_name );
+
+ /**
+ * Find a service ( by menu id, e.g. "tde-konsole.desktop")
+ */
+ KService * findServiceByMenuId( const TQString &_menuId );
+
+ /**
+ * @return the services supporting the given service type
+ */
+ KService::List offers( int serviceTypeOffset );
+
+ /**
+ * @return all services. Very memory consuming, avoid using.
+ */
+ KService::List allServices();
+
+ /**
+ * @return all services which have a "X-TDE-Init" line.
+ */
+ KService::List allInitServices();
+
+ /**
+ * @return the unique service factory, creating it if necessary
+ */
+ static KServiceFactory * self();
+
+protected:
+ virtual KService * createEntry(int offset);
+ int m_offerListOffset;
+ int m_initListOffset;
+ KSycocaDict *m_nameDict;
+ int m_nameDictOffset;
+ KSycocaDict *m_relNameDict;
+ int m_relNameDictOffset;
+ KSycocaDict *m_menuIdDict;
+ int m_menuIdDictOffset;
+
+private:
+ static KServiceFactory *_self;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KServiceFactoryPrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kservicegroup.cpp b/tdeio/tdeio/kservicegroup.cpp
new file mode 100644
index 000000000..2e27c99b0
--- /dev/null
+++ b/tdeio/tdeio/kservicegroup.cpp
@@ -0,0 +1,724 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 2000 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 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 <tqdir.h>
+
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <ksortablevaluelist.h>
+
+#include "kservicefactory.h"
+#include "kservicegroupfactory.h"
+#include "kservicegroup.h"
+#include "kservice.h"
+#include "tdesycoca.h"
+
+class KServiceGroup::Private
+{
+public:
+ Private() { m_bNoDisplay = false; m_bShowEmptyMenu = false;m_bShowInlineHeader=false;m_bInlineAlias=false; m_bAllowInline = false; m_inlineValue = 4; m_bShortMenu = false; m_bGeneralDescription = false;}
+ bool m_bNoDisplay;
+ bool m_bShortMenu;
+ bool m_bGeneralDescription;
+ bool m_bShowEmptyMenu;
+ bool m_bShowInlineHeader;
+ bool m_bInlineAlias;
+ bool m_bAllowInline;
+ int m_inlineValue;
+ TQStringList suppressGenericNames;
+ TQString directoryEntryPath;
+ TQStringList sortOrder;
+};
+
+KServiceGroup::KServiceGroup( const TQString & name )
+ : KSycocaEntry(name), m_childCount(-1)
+{
+ d = new KServiceGroup::Private;
+ m_bDeleted = false;
+ m_bDeep = false;
+}
+
+KServiceGroup::KServiceGroup( const TQString &configFile, const TQString & _relpath )
+ : KSycocaEntry(_relpath), m_childCount(-1)
+{
+ d = new KServiceGroup::Private;
+ m_bDeleted = false;
+ m_bDeep = false;
+
+ TQString cfg = configFile;
+ if (cfg.isEmpty())
+ cfg = _relpath+".directory";
+
+ d->directoryEntryPath = cfg;
+
+ KDesktopFile config( cfg, true, "apps" );
+
+ m_strCaption = config.readName();
+ m_strIcon = config.readIcon();
+ m_strComment = config.readComment();
+ m_bDeleted = config.readBoolEntry( "Hidden", false );
+ d->m_bNoDisplay = config.readBoolEntry( "NoDisplay", false );
+ if (d->directoryEntryPath.startsWith(TQDir::homeDirPath()))
+ d->m_bShortMenu = false;
+ else
+ d->m_bShortMenu = config.readBoolEntry( "X-SuSE-AutoShortMenu", false );
+ d->m_bGeneralDescription = config.readBoolEntry( "X-SuSE-GeneralDescription", false );
+ TQStringList tmpList;
+ if (config.hasKey("OnlyShowIn"))
+ {
+ if ((!config.readListEntry("OnlyShowIn", ';').contains("TDE")) && (!config.readListEntry("OnlyShowIn", ';').contains("KDE")))
+ d->m_bNoDisplay = true;
+ }
+ if (config.hasKey("NotShowIn"))
+ {
+ if ((config.readListEntry("NotShowIn", ';').contains("TDE")) || (config.readListEntry("NotShowIn", ';').contains("KDE")))
+ d->m_bNoDisplay = true;
+ }
+
+ m_strBaseGroupName = config.readEntry( "X-TDE-BaseGroup" );
+ d->suppressGenericNames = config.readListEntry( "X-TDE-SuppressGenericNames" );
+ d->sortOrder = config.readListEntry("SortOrder");
+
+ // Fill in defaults.
+ if (m_strCaption.isEmpty())
+ {
+ m_strCaption = _relpath;
+ if (m_strCaption.right(1) == "/")
+ m_strCaption = m_strCaption.left(m_strCaption.length()-1);
+ int i = m_strCaption.findRev('/');
+ if (i > 0)
+ m_strCaption = m_strCaption.mid(i+1);
+ }
+ if (m_strIcon.isEmpty())
+ m_strIcon = "folder";
+}
+
+KServiceGroup::KServiceGroup( TQDataStream& _str, int offset, bool deep ) :
+ KSycocaEntry( _str, offset )
+{
+ d = new KServiceGroup::Private;
+ m_bDeep = deep;
+ load( _str );
+}
+
+KServiceGroup::~KServiceGroup()
+{
+ delete d;
+}
+
+int KServiceGroup::childCount()
+{
+ if (m_childCount == -1)
+ {
+ TDEConfig global("kdeglobals");
+ global.setGroup("KDE");
+ bool showUnimportant = global.readBoolEntry("showUnimportant", true);
+
+ m_childCount = 0;
+
+ for( List::ConstIterator it = m_serviceList.begin();
+ it != m_serviceList.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+ if (!service->noDisplay())
+ if ( showUnimportant || !service->SuSEunimportant() )
+ m_childCount++;
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+ m_childCount += serviceGroup->childCount();
+ }
+ }
+ }
+ return m_childCount;
+}
+
+
+bool KServiceGroup::showInlineHeader() const
+{
+ return d->m_bShowInlineHeader;
+}
+
+bool KServiceGroup::showEmptyMenu() const
+{
+ return d->m_bShowEmptyMenu;
+}
+
+bool KServiceGroup::inlineAlias() const
+{
+ return d->m_bInlineAlias;
+}
+
+void KServiceGroup::setInlineAlias(bool _b)
+{
+ d->m_bInlineAlias = _b;
+}
+
+void KServiceGroup::setShowEmptyMenu(bool _b)
+{
+ d->m_bShowEmptyMenu=_b;
+}
+
+void KServiceGroup::setShowInlineHeader(bool _b)
+{
+ d->m_bShowInlineHeader=_b;
+}
+
+int KServiceGroup::inlineValue() const
+{
+ return d->m_inlineValue;
+}
+
+void KServiceGroup::setInlineValue(int _val)
+{
+ d->m_inlineValue = _val;
+}
+
+bool KServiceGroup::allowInline() const
+{
+ return d->m_bAllowInline;
+}
+
+void KServiceGroup::setAllowInline(bool _b)
+{
+ d->m_bAllowInline = _b;
+}
+
+bool KServiceGroup::noDisplay() const
+{
+ return d->m_bNoDisplay || m_strCaption.startsWith(".");
+}
+
+TQStringList KServiceGroup::suppressGenericNames() const
+{
+ return d->suppressGenericNames;
+}
+
+bool KServiceGroup::SuSEgeneralDescription() const
+{
+ return d->m_bGeneralDescription;
+}
+
+bool KServiceGroup::SuSEshortMenu() const
+{
+ return d->m_bShortMenu;
+}
+
+void KServiceGroup::load( TQDataStream& s )
+{
+ TQStringList groupList;
+ TQ_INT8 noDisplay;
+ TQ_INT8 _showEmptyMenu;
+ TQ_INT8 inlineHeader;
+ TQ_INT8 _inlineAlias;
+ TQ_INT8 _allowInline;
+ s >> m_strCaption >> m_strIcon >>
+ m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >>
+ noDisplay >> d->suppressGenericNames >> d->directoryEntryPath >>
+ d->sortOrder >> _showEmptyMenu >> inlineHeader >> _inlineAlias >>
+ _allowInline >> d->m_bShortMenu >> d->m_bGeneralDescription;
+
+ d->m_bNoDisplay = (noDisplay != 0);
+ d->m_bShowEmptyMenu = ( _showEmptyMenu != 0 );
+ d->m_bShowInlineHeader = ( inlineHeader != 0 );
+ d->m_bInlineAlias = ( _inlineAlias != 0 );
+ d->m_bAllowInline = ( _allowInline != 0 );
+
+ if (m_bDeep)
+ {
+ for(TQStringList::ConstIterator it = groupList.begin();
+ it != groupList.end(); it++)
+ {
+ TQString path = *it;
+ if (path[path.length()-1] == '/')
+ {
+ KServiceGroup *serviceGroup;
+ serviceGroup = KServiceGroupFactory::self()->findGroupByDesktopPath(path, false);
+ if (serviceGroup)
+ m_serviceList.append( SPtr(serviceGroup) );
+ }
+ else
+ {
+ KService *service;
+ service = KServiceFactory::self()->findServiceByDesktopPath(path);
+ if (service)
+ m_serviceList.append( SPtr(service) );
+ }
+ }
+ }
+}
+
+void KServiceGroup::addEntry( KSycocaEntry *entry)
+{
+ m_serviceList.append(entry);
+}
+
+void KServiceGroup::save( TQDataStream& s )
+{
+ KSycocaEntry::save( s );
+
+ TQStringList groupList;
+ for( List::ConstIterator it = m_serviceList.begin();
+ it != m_serviceList.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+ groupList.append( service->desktopEntryPath());
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+ groupList.append( serviceGroup->relPath());
+ }
+ else
+ {
+ //fprintf(stderr, "KServiceGroup: Unexpected object in list!\n");
+ }
+ }
+
+ (void) childCount();
+
+ TQ_INT8 noDisplay = d->m_bNoDisplay ? 1 : 0;
+ TQ_INT8 _showEmptyMenu = d->m_bShowEmptyMenu ? 1 : 0;
+ TQ_INT8 inlineHeader = d->m_bShowInlineHeader ? 1 : 0;
+ TQ_INT8 _inlineAlias = d->m_bInlineAlias ? 1 : 0;
+ TQ_INT8 _allowInline = d->m_bAllowInline ? 1 : 0;
+ s << m_strCaption << m_strIcon <<
+ m_strComment << groupList << m_strBaseGroupName << m_childCount <<
+ noDisplay << d->suppressGenericNames << d->directoryEntryPath <<
+ d->sortOrder <<_showEmptyMenu <<inlineHeader<<_inlineAlias<<_allowInline <<
+ d->m_bShortMenu << d->m_bGeneralDescription;
+}
+
+KServiceGroup::List
+KServiceGroup::entries(bool sort)
+{
+ return entries(sort, true);
+}
+
+KServiceGroup::List
+KServiceGroup::entries(bool sort, bool excludeNoDisplay)
+{
+ return entries(sort, excludeNoDisplay, false);
+}
+
+static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator)
+{
+ if (addSeparator && !sorted.isEmpty())
+ sorted.append(new KServiceSeparator());
+ sorted.append(p);
+ addSeparator = false;
+}
+
+KServiceGroup::List
+KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
+{
+ return SuSEentries(sort, excludeNoDisplay, allowSeparators, sortByGenericName);
+}
+
+KServiceGroup::List
+KServiceGroup::SuSEentries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName, bool excludeSuSEunimportant)
+{
+ KServiceGroup *group = this;
+
+ // If the entries haven't been loaded yet, we have to reload ourselves
+ // together with the entries. We can't only load the entries afterwards
+ // since the offsets could have been changed if the database has changed.
+
+ if (!m_bDeep) {
+
+ group =
+ KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true);
+
+ if (0 == group) // No guarantee that we still exist!
+ return List();
+ }
+
+ if (!sort)
+ return group->m_serviceList;
+
+ // Sort the list alphabetically, according to locale.
+ // Groups come first, then services.
+
+ KSortableValueList<SPtr,TQCString> slist;
+ KSortableValueList<SPtr,TQCString> glist;
+ for (List::ConstIterator it(group->m_serviceList.begin()); it != group->m_serviceList.end(); ++it)
+ {
+ KSycocaEntry *p = (*it);
+// if( !p->isType(KST_KServiceGroup) && !p->isType(KST_KService))
+// continue;
+ bool noDisplay = p->isType(KST_KServiceGroup) ?
+ static_cast<KServiceGroup *>(p)->noDisplay() :
+ static_cast<KService *>(p)->noDisplay();
+ if (excludeNoDisplay && noDisplay)
+ continue;
+ bool SuSEunimportant = p->isType(KST_KService) &&
+ static_cast<KService *>(p)->SuSEunimportant();
+ if (excludeSuSEunimportant && SuSEunimportant)
+ continue;
+
+ // Choose the right list
+ KSortableValueList<SPtr,TQCString> & list = p->isType(KST_KServiceGroup) ? glist : slist;
+ TQString name;
+ if (p->isType(KST_KServiceGroup))
+ name = static_cast<KServiceGroup *>(p)->caption();
+ else if (sortByGenericName)
+ name = static_cast<KService *>(p)->genericName() + " " + p->name();
+ else
+ name = p->name() + " " + static_cast<KService *>(p)->genericName();
+
+ TQCString key( name.length() * 4 + 1 );
+ // strxfrm() crashes on Solaris
+#ifndef USE_SOLARIS
+ // maybe it'd be better to use wcsxfrm() where available
+ size_t ln = strxfrm( key.data(), name.local8Bit().data(), key.size());
+ if( ln != size_t( -1 ))
+ {
+ if( ln >= key.size())
+ { // didn't fit?
+ key.resize( ln + 1 );
+ if( strxfrm( key.data(), name.local8Bit().data(), key.size()) == size_t( -1 ))
+ key = name.local8Bit();
+ }
+ }
+ else
+#endif
+ {
+ key = name.local8Bit();
+ }
+ list.insert(key,SPtr(*it));
+ }
+
+ return group->SuSEsortEntries( slist, glist, excludeNoDisplay, allowSeparators );
+}
+
+KServiceGroup::List
+KServiceGroup::SuSEsortEntries( KSortableValueList<SPtr,TQCString> slist, KSortableValueList<SPtr,TQCString> glist, bool excludeNoDisplay, bool allowSeparators )
+{
+ KServiceGroup *group = this;
+
+ // Now sort
+ slist.sort();
+ glist.sort();
+
+ if (d->sortOrder.isEmpty())
+ {
+ d->sortOrder << ":M";
+ d->sortOrder << ":F";
+ d->sortOrder << ":OIH IL[4]"; //just inline header
+ }
+
+ TQString rp = relPath();
+ if(rp == "/") rp = TQString::null;
+
+ // Iterate through the sort spec list.
+ // If an entry gets mentioned explicitly, we remove it from the sorted list
+ for (TQStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
+ {
+ const TQString &item = *it;
+ if (item.isEmpty()) continue;
+ if (item[0] == '/')
+ {
+ TQString groupPath = rp + item.mid(1) + "/";
+ // Remove entry from sorted list of services.
+ for(KSortableValueList<SPtr,TQCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
+ {
+ KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)((*it2).value()));
+ if (group->relPath() == groupPath)
+ {
+ glist.remove(it2);
+ break;
+ }
+ }
+ }
+ else if (item[0] != ':')
+ {
+ // Remove entry from sorted list of services.
+ // TODO: Remove item from sortOrder-list if not found
+ // TODO: This prevents duplicates
+ for(KSortableValueList<SPtr,TQCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
+ {
+ if (!(*it2).value()->isType(KST_KService))
+ continue;
+ KService *service = (KService *)((KSycocaEntry *)((*it2).value()));
+ if (service->menuId() == item)
+ {
+ slist.remove(it2);
+ break;
+ }
+ }
+ }
+ }
+
+ List sorted;
+
+ bool needSeparator = false;
+ // Iterate through the sort spec list.
+ // Add the entries to the list according to the sort spec.
+ for (TQStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
+ {
+ const TQString &item = *it;
+ if (item.isEmpty()) continue;
+ if (item[0] == ':')
+ {
+ // Special condition...
+ if (item == ":S")
+ {
+ if (allowSeparators)
+ needSeparator = true;
+ }
+ else if ( item.contains( ":O" ) )
+ {
+ //todo parse attribute:
+ TQString tmp( item );
+ tmp = tmp.remove(":O");
+ TQStringList optionAttribute = TQStringList::split(" ",tmp);
+ if( optionAttribute.count()==0)
+ optionAttribute.append(tmp);
+ bool showEmptyMenu = false;
+ bool showInline = false;
+ bool showInlineHeader = false;
+ bool showInlineAlias = false;
+ int inlineValue = -1;
+
+ for ( TQStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 )
+ {
+ parseAttribute( *it3, showEmptyMenu, showInline, showInlineHeader, showInlineAlias, inlineValue );
+ }
+ for(KSortableValueList<SPtr,TQCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
+ {
+ KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2).value());
+ group->setShowEmptyMenu( showEmptyMenu );
+ group->setAllowInline( showInline );
+ group->setShowInlineHeader( showInlineHeader );
+ group->setInlineAlias( showInlineAlias );
+ group->setInlineValue( inlineValue );
+ }
+
+ }
+ else if (item == ":M")
+ {
+ // Add sorted list of sub-menus
+ for(KSortableValueList<SPtr,TQCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
+ {
+ addItem(sorted, (*it2).value(), needSeparator);
+ }
+ }
+ else if (item == ":F")
+ {
+ // Add sorted list of services
+ for(KSortableValueList<SPtr,TQCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
+ {
+ addItem(sorted, (*it2).value(), needSeparator);
+ }
+ }
+ else if (item == ":A")
+ {
+ // Add sorted lists of services and submenus
+ KSortableValueList<SPtr,TQCString>::Iterator it_s = slist.begin();
+ KSortableValueList<SPtr,TQCString>::Iterator it_g = glist.begin();
+
+ while(true)
+ {
+ if (it_s == slist.end())
+ {
+ if (it_g == glist.end())
+ break; // Done
+
+ // Insert remaining sub-menu
+ addItem(sorted, (*it_g).value(), needSeparator);
+ it_g++;
+ }
+ else if (it_g == glist.end())
+ {
+ // Insert remaining service
+ addItem(sorted, (*it_s).value(), needSeparator);
+ it_s++;
+ }
+ else if ((*it_g).index() < (*it_s).index())
+ {
+ // Insert sub-menu first
+ addItem(sorted, (*it_g).value(), needSeparator);
+ it_g++;
+ }
+ else
+ {
+ // Insert service first
+ addItem(sorted, (*it_s).value(), needSeparator);
+ it_s++;
+ }
+ }
+ }
+ }
+ else if (item[0] == '/')
+ {
+ TQString groupPath = rp + item.mid(1) + "/";
+
+ for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
+ {
+ if (!(*it2)->isType(KST_KServiceGroup))
+ continue;
+ KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2));
+ if (group->relPath() == groupPath)
+ {
+ if (!excludeNoDisplay || !group->noDisplay())
+ {
+ const TQString &nextItem = *( ++it );
+ if ( nextItem.startsWith( ":O" ) )
+ {
+ TQString tmp( nextItem );
+ tmp = tmp.remove(":O");
+ TQStringList optionAttribute = TQStringList::split(" ",tmp);
+ if( optionAttribute.count()==0)
+ optionAttribute.append(tmp);
+ bool bShowEmptyMenu = false;
+ bool bShowInline = false;
+ bool bShowInlineHeader = false;
+ bool bShowInlineAlias = false;
+ int inlineValue = -1;
+ for ( TQStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 )
+ {
+ parseAttribute( *it3 , bShowEmptyMenu, bShowInline, bShowInlineHeader, bShowInlineAlias , inlineValue );
+ group->setShowEmptyMenu( bShowEmptyMenu );
+ group->setAllowInline( bShowInline );
+ group->setShowInlineHeader( bShowInlineHeader );
+ group->setInlineAlias( bShowInlineAlias );
+ group->setInlineValue( inlineValue );
+ }
+ }
+ else
+ it--;
+
+ addItem(sorted, (group), needSeparator);
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
+ {
+ if (!(*it2)->isType(KST_KService))
+ continue;
+ KService *service = (KService *)((KSycocaEntry *)(*it2));
+ if (service->menuId() == item)
+ {
+ if (!excludeNoDisplay || !service->noDisplay())
+ addItem(sorted, (*it2), needSeparator);
+ break;
+ }
+ }
+ }
+ }
+
+ return sorted;
+}
+
+void KServiceGroup::parseAttribute( const TQString &item , bool &showEmptyMenu, bool &showInline, bool &showInlineHeader, bool & showInlineAlias , int &inlineValue )
+{
+ if( item == "ME") //menu empty
+ showEmptyMenu=true;
+ else if ( item == "NME") //not menu empty
+ showEmptyMenu=false;
+ else if( item == "I") //inline menu !
+ showInline = true;
+ else if ( item == "NI") //not inline menu!
+ showInline = false;
+ else if( item == "IH") //inline header!
+ showInlineHeader= true;
+ else if ( item == "NIH") //not inline header!
+ showInlineHeader = false;
+ else if( item == "IA") //inline alias!
+ showInlineAlias = true;
+ else if ( item == "NIA") //not inline alias!
+ showInlineAlias = false;
+ else if( ( item ).contains( "IL" )) //inline limite!
+ {
+ TQString tmp( item );
+ tmp = tmp.remove( "IL[" );
+ tmp = tmp.remove( "]" );
+ bool ok;
+ int _inlineValue = tmp.toInt(&ok);
+ if ( !ok ) //error
+ _inlineValue = -1;
+ inlineValue = _inlineValue;
+ }
+ else
+ kdDebug()<<" This attribute is not supported :"<<item<<endl;
+}
+
+void KServiceGroup::setLayoutInfo(const TQStringList &layout)
+{
+ d->sortOrder = layout;
+}
+
+TQStringList KServiceGroup::layoutInfo() const
+{
+ return d->sortOrder;
+}
+
+KServiceGroup::Ptr
+KServiceGroup::baseGroup( const TQString & _baseGroupName )
+{
+ return KServiceGroupFactory::self()->findBaseGroup(_baseGroupName, true);
+}
+
+KServiceGroup::Ptr
+KServiceGroup::root()
+{
+ return KServiceGroupFactory::self()->findGroupByDesktopPath("/", true);
+}
+
+KServiceGroup::Ptr
+KServiceGroup::group(const TQString &relPath)
+{
+ if (relPath.isEmpty()) return root();
+ return KServiceGroupFactory::self()->findGroupByDesktopPath(relPath, true);
+}
+
+KServiceGroup::Ptr
+KServiceGroup::childGroup(const TQString &parent)
+{
+ return KServiceGroupFactory::self()->findGroupByDesktopPath("#parent#"+parent, true);
+}
+
+TQString
+KServiceGroup::directoryEntryPath() const
+{
+ return d->directoryEntryPath;
+}
+
+
+void KServiceGroup::virtual_hook( int id, void* data )
+{ KSycocaEntry::virtual_hook( id, data ); }
+
+
+KServiceSeparator::KServiceSeparator( )
+ : KSycocaEntry("separator")
+{
+}
diff --git a/tdeio/tdeio/kservicegroup.h b/tdeio/tdeio/kservicegroup.h
new file mode 100644
index 000000000..f2cd5a09f
--- /dev/null
+++ b/tdeio/tdeio/kservicegroup.h
@@ -0,0 +1,353 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 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 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 __kservicegroup_h__
+#define __kservicegroup_h__
+
+#include <tqptrlist.h>
+#include <tqstring.h>
+#include <tqshared.h>
+#include <tqdatastream.h>
+#include <tqvariant.h>
+
+#include <kdesktopfile.h>
+#include <ksortablevaluelist.h>
+
+#include "tdesycocaentry.h"
+#include "tdesycocatype.h"
+#include "kservice.h"
+
+class KBuildServiceGroupFactory;
+
+/**
+ * KServiceGroup represents a group of service, for example
+ * screensavers.
+ * This class is typically used like this:
+ *
+ * \code
+ * // Lookup screensaver group
+ * KServiceGroup::Ptr group = KServiceGroup::baseGroup("screensavers");
+ * if (!group || !group->isValid()) return;
+ *
+ * KServiceGroup::List list = group->entries();
+ *
+ * // Iterate over all entries in the group
+ * for( KServiceGroup::List::ConstIterator it = list.begin();
+ * it != list.end(); it++)
+ * {
+ * KSycocaEntry *p = (*it);
+ * if (p->isType(KST_KService))
+ * {
+ * KService *s = static_cast<KService *>(p);
+ * printf("Name = %s\n", s->name().latin1());
+ * }
+ * else if (p->isType(KST_KServiceGroup))
+ * {
+ * KServiceGroup *g = static_cast<KServiceGroup *>(p);
+ * // Sub group ...
+ * }
+ * }
+ * \endcode
+ * @short Represents a group of services
+ */
+class TDEIO_EXPORT KServiceGroup : public KSycocaEntry
+{
+ friend class KBuildServiceGroupFactory;
+ K_SYCOCATYPE( KST_KServiceGroup, KSycocaEntry )
+
+public:
+ typedef KSharedPtr<KServiceGroup> Ptr;
+ typedef KSharedPtr<KSycocaEntry> SPtr;
+ typedef TQValueList<SPtr> List;
+public:
+ /**
+ * Construct a dummy servicegroup indexed with @p name.
+ * @param name the name of the service group
+ * @since 3.1
+ */
+ KServiceGroup( const TQString & name );
+
+ /**
+ * Construct a service and take all informations from a config file
+ * @param _fullpath full path to the config file
+ * @param _relpath relative path to the config file
+ */
+ KServiceGroup( const TQString & _fullpath, const TQString & _relpath );
+
+ /**
+ * @internal construct a service from a stream.
+ * The stream must already be positionned at the correct offset
+ */
+ KServiceGroup( TQDataStream& _str, int offset, bool deep );
+
+ virtual ~KServiceGroup();
+
+ /**
+ * Checks whether the entry is valid, returns always true.
+ * @return true
+ */
+ bool isValid() const { return true; }
+
+ /**
+ * Name used for indexing.
+ * @return the service group's name
+ */
+ virtual TQString name() const { return entryPath(); }
+
+ /**
+ * Returns the relative path of the service group.
+ * @return the service group's relative path
+ */
+ virtual TQString relPath() const { return entryPath(); }
+
+ /**
+ * Returns the caption of this group.
+ * @return the caption of this group
+ */
+ TQString caption() const { return m_strCaption; }
+
+ /**
+ * Returns the name of the icon associated with the group.
+ * @return the name of the icon associated with the group,
+ * or TQString::null if not set
+ */
+ TQString icon() const { return m_strIcon; }
+
+ /**
+ * Returns the comment about this service group.
+ * @return the descriptive comment for the group, if there is one,
+ * or TQString::null if not set
+ */
+ TQString comment() const { return m_strComment; }
+
+ /**
+ * Returns the total number of displayable services in this group and
+ * any of its subgroups.
+ * @return the number of child services
+ */
+ int childCount();
+
+ /**
+ * Returns true if the NoDisplay flag was set, i.e. if this
+ * group should be hidden from menus, while still being in tdesycoca.
+ * @return true to hide this service group, false to display it
+ * @since 3.1
+ */
+ bool noDisplay() const;
+
+ /**
+ * Return true if we want to display empty menu entry
+ * @return true to show this service group as menu entry is empty, false to hide it
+ * @since 3.4
+ */
+ bool showEmptyMenu() const;
+ void setShowEmptyMenu( bool b);
+
+ /**
+ * @return true to show an inline header into menu
+ * @since 3.5
+ */
+ bool showInlineHeader() const;
+ void setShowInlineHeader(bool _b);
+
+ /**
+ * @return true to show an inline alias item into menu
+ * @since 3.5
+ */
+ bool inlineAlias() const;
+ void setInlineAlias(bool _b);
+ /**
+ * @return true if we allow to inline menu.
+ * @since 3.5
+ */
+ bool allowInline() const;
+ void setAllowInline(bool _b);
+
+ /**
+ * @return inline limite value
+ * @since 3.5
+ */
+ int inlineValue() const;
+ void setInlineValue(int _val);
+
+
+ /**
+ * Returns a list of untranslated generic names that should be
+ * be supressed when showing this group.
+ * E.g. The group "Games/Arcade" might want to suppress the generic name
+ * "Arcade Game" since it's redundant in this particular context.
+ * @since 3.2
+ */
+ TQStringList suppressGenericNames() const;
+
+ /**
+ * @internal
+ * Sets information related to the layout of services in this group.
+ */
+ void setLayoutInfo(const TQStringList &layout);
+
+ /**
+ * Original API and feature kindly provided by SuSE
+ */
+ bool SuSEshortMenu() const;
+ bool SuSEgeneralDescription() const;
+
+ /**
+ * @internal
+ * Returns information related to the layout of services in this group.
+ */
+ TQStringList layoutInfo() const;
+
+ /**
+ * @internal
+ * Load the service from a stream.
+ */
+ virtual void load( TQDataStream& );
+ /**
+ * @internal
+ * Save the service to a stream.
+ */
+ virtual void save( TQDataStream& );
+
+ /**
+ * List of all Services and ServiceGroups within this
+ * ServiceGroup.
+ * @param sorted true to sort items
+ * @param excludeNoDisplay true to exclude items marked "NoDisplay"
+ * @param allowSeparators true to allow separator items to be included
+ * @param sortByGenericName true to sort GenericName+Name instead of Name+GenericName
+ * @return the list of entries
+ * @since 3.2
+ */
+ List entries(bool sorted, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName=false);
+ virtual List entries(bool sorted, bool excludeNoDisplay);
+
+ /**
+ * List of all Services and ServiceGroups within this
+ * ServiceGroup.
+ * @param sorted true to sort items
+ * @return the list of entried
+ */
+ virtual List entries(bool sorted = false);
+
+ /*
+ * Original API and feature kindly provided by SuSE
+ */
+ virtual List SuSEentries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName, bool excludeSuSEunimportant = false);
+ virtual List SuSEsortEntries( KSortableValueList<SPtr,TQCString> slist, KSortableValueList<SPtr,TQCString> glist, bool excludeNoDisplay, bool allowSeparators );
+
+ /**
+ * Returns a non-empty string if the group is a special base group.
+ * By default, "Settings/" is the kcontrol base group ("settings")
+ * and "System/Screensavers/" is the screensavers base group ("screensavers").
+ * This allows moving the groups without breaking those apps.
+ *
+ * The base group is defined by the X-TDE-BaseGroup key
+ * in the .directory file.
+ * @return the base group name, or null if no base group
+ */
+ TQString baseGroupName() const { return m_strBaseGroupName; }
+
+ /**
+ * Returns a path to the .directory file describing this service group.
+ * The path is either absolute or relative to the "apps" resource.
+ * @since 3.2
+ */
+ TQString directoryEntryPath() const;
+
+ /**
+ * Returns the group for the given baseGroupName.
+ * Can return 0L if the directory (or the .directory file) was deleted.
+ * @return the base group with the given name, or 0 if not available.
+ */
+ static Ptr baseGroup( const TQString &baseGroupName );
+
+ /**
+ * Returns the root service group.
+ * @return the root service group
+ */
+ static Ptr root();
+
+ /**
+ * Returns the group with the given relative path.
+ * @param relPath the path of the service group
+ * @return the group with the given relative path name.
+ */
+ static Ptr group(const TQString &relPath);
+
+ /**
+ * Returns the group of services that have X-TDE-ParentApp equal
+ * to @p parent (siblings).
+ * @param parent the name of the service's parent
+ * @return the services group
+ * @since 3.1
+ */
+ static Ptr childGroup(const TQString &parent);
+
+ /**
+ * This function parse attributes into menu
+ * @since 3.5
+ */
+ void parseAttribute( const TQString &item , bool &showEmptyMenu, bool &showInline, bool &showInlineHeader, bool & showInlineAlias ,int &inlineValue );
+
+protected:
+ /**
+ * @internal
+ * Add a service to this group
+ */
+ void addEntry( KSycocaEntry *entry);
+
+ TQString m_strCaption;
+ TQString m_strIcon;
+ TQString m_strComment;
+
+ List m_serviceList;
+ bool m_bDeep;
+ TQString m_strBaseGroupName;
+ int m_childCount;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class Private;
+ Private* d;
+};
+
+class TDEIO_EXPORT KServiceSeparator : public KSycocaEntry
+{
+ K_SYCOCATYPE( KST_KServiceSeparator, KSycocaEntry )
+
+public:
+ typedef KSharedPtr<KServiceSeparator> Ptr;
+public:
+ /**
+ * Construct a service separator
+ * @since 3.2
+ */
+ KServiceSeparator();
+
+ bool isValid() const { return true; }
+
+ // Dummy
+ virtual TQString name() const { return "separator"; }
+ // Dummy
+ virtual void load( TQDataStream& ) { };
+ // Dummy
+ virtual void save( TQDataStream& ) { };
+};
+
+#endif
diff --git a/tdeio/tdeio/kservicegroupfactory.cpp b/tdeio/tdeio/kservicegroupfactory.cpp
new file mode 100644
index 000000000..56ec0c07f
--- /dev/null
+++ b/tdeio/tdeio/kservicegroupfactory.cpp
@@ -0,0 +1,148 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 2000 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 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 "kservicegroupfactory.h"
+#include "tdesycoca.h"
+#include "tdesycocatype.h"
+#include "tdesycocadict.h"
+#include "kservice.h"
+
+#include <tqstring.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+KServiceGroupFactory::KServiceGroupFactory()
+ : KSycocaFactory( KST_KServiceGroupFactory )
+{
+ m_baseGroupDictOffset = 0;
+ if (m_str)
+ {
+ // Read Header
+ TQ_INT32 i;
+ (*m_str) >> i;
+ m_baseGroupDictOffset = i;
+
+ int saveOffset = m_str->device()->at();
+ // Init index tables
+ m_baseGroupDict = new KSycocaDict(m_str, m_baseGroupDictOffset);
+ m_str->device()->at(saveOffset);
+ }
+ else
+ {
+ // Build new database
+ m_baseGroupDict = new KSycocaDict();
+ }
+ _self = this;
+}
+
+KServiceGroupFactory::~KServiceGroupFactory()
+{
+ _self = 0L;
+ delete m_baseGroupDict;
+}
+
+KServiceGroupFactory * KServiceGroupFactory::self()
+{
+ if (!_self)
+ _self = new KServiceGroupFactory();
+ return _self;
+}
+
+KServiceGroup * KServiceGroupFactory::findGroupByDesktopPath(const TQString &_name, bool deep)
+{
+ if (!m_sycocaDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByName isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_sycocaDict->find_string( _name );
+ if (!offset) return 0; // Not found
+
+ KServiceGroup * newGroup = createGroup(offset, deep);
+
+ // Check whether the dictionary was right.
+ if (newGroup && (newGroup->relPath() != _name))
+ {
+ // No it wasn't...
+ delete newGroup;
+ newGroup = 0; // Not found
+ }
+ return newGroup;
+}
+
+KServiceGroup * KServiceGroupFactory::findBaseGroup(const TQString &_baseGroupName, bool deep)
+{
+ if (!m_baseGroupDict) return 0; // Error!
+
+ // Warning : this assumes we're NOT building a database
+ // But since findServiceByName isn't called in that case...
+ // [ see KServiceTypeFactory for how to do it if needed ]
+
+ int offset = m_baseGroupDict->find_string( _baseGroupName );
+ if (!offset) return 0; // Not found
+
+ KServiceGroup * newGroup = createGroup(offset, deep);
+
+ // Check whether the dictionary was right.
+ if (newGroup && (newGroup->baseGroupName() != _baseGroupName))
+ {
+ // No it wasn't...
+ delete newGroup;
+ newGroup = 0; // Not found
+ }
+ return newGroup;
+}
+
+KServiceGroup* KServiceGroupFactory::createGroup(int offset, bool deep)
+{
+ KServiceGroup * newEntry = 0L;
+ KSycocaType type;
+ TQDataStream *str = KSycoca::self()->findEntry(offset, type);
+ switch(type)
+ {
+ case KST_KServiceGroup:
+ newEntry = new KServiceGroup(*str, offset, deep);
+ break;
+
+ default:
+ kdError(7011) << TQString(TQString("KServiceGroupFactory: unexpected object entry in KSycoca database (type = %1)").arg((int)type)) << endl;
+ return 0;
+ }
+ if (!newEntry->isValid())
+ {
+ kdError(7011) << "KServiceGroupFactory: corrupt object in KSycoca database!\n" << endl;
+ delete newEntry;
+ newEntry = 0;
+ }
+ return newEntry;
+}
+
+KServiceGroup* KServiceGroupFactory::createEntry(int offset)
+{
+ return createGroup(offset, true);
+}
+
+KServiceGroupFactory *KServiceGroupFactory::_self = 0;
+
+void KServiceGroupFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/kservicegroupfactory.h b/tdeio/tdeio/kservicegroupfactory.h
new file mode 100644
index 000000000..77bc7c042
--- /dev/null
+++ b/tdeio/tdeio/kservicegroupfactory.h
@@ -0,0 +1,80 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 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 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 __kservicegroupfactory_h__
+#define __kservicegroupfactory_h__
+
+#include <tqstringlist.h>
+
+#include "kservicegroup.h"
+#include "tdesycocafactory.h"
+#include <assert.h>
+
+class KSycoca;
+class KSycocaDict;
+
+/**
+ * @internal
+ * A sycoca factory for service groups (e.g. list of applications)
+ * It loads the services from parsing directories (e.g. applnk/)
+ */
+class TDEIO_EXPORT KServiceGroupFactory : public KSycocaFactory
+{
+ K_SYCOCAFACTORY( KST_KServiceGroupFactory )
+public:
+ /**
+ * Create factory
+ */
+ KServiceGroupFactory();
+ virtual ~KServiceGroupFactory();
+
+ /**
+ * Construct a KServiceGroup from a config file.
+ */
+ virtual KSycocaEntry *createEntry(const TQString &, const char *)
+ { assert(0); return 0; }
+
+ /**
+ * Find a group ( by desktop path, e.g. "Applications/Editors")
+ */
+ KServiceGroup * findGroupByDesktopPath( const TQString &_name, bool deep = true );
+
+ /**
+ * Find a base group by name, e.g. "settings"
+ */
+ KServiceGroup * findBaseGroup( const TQString &_baseGroupName, bool deep = true );
+
+ /**
+ * @return the unique service group factory, creating it if necessary
+ */
+ static KServiceGroupFactory * self();
+protected:
+ KServiceGroup* createGroup(int offset, bool deep);
+ KServiceGroup* createEntry(int offset);
+ KSycocaDict *m_baseGroupDict;
+ int m_baseGroupDictOffset;
+
+private:
+ static KServiceGroupFactory *_self;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KServiceGroupFactoryPrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kservicetype.cpp b/tdeio/tdeio/kservicetype.cpp
new file mode 100644
index 000000000..8565029ee
--- /dev/null
+++ b/tdeio/tdeio/kservicetype.cpp
@@ -0,0 +1,366 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ * 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 "kservice.h"
+#include "tdesycoca.h"
+#include "kservicetype.h"
+#include "kservicetypefactory.h"
+#include "kservicefactory.h"
+#include "kuserprofile.h"
+#include <assert.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+
+template TQDataStream& operator>> <TQString, TQVariant>(TQDataStream&, TQMap<TQString, TQVariant>&);
+template TQDataStream& operator<< <TQString, TQVariant>(TQDataStream&, const TQMap<TQString, TQVariant>&);
+
+class KServiceType::KServiceTypePrivate
+{
+public:
+ KServiceTypePrivate() : parentTypeLoaded(false) { }
+
+ KServiceType::Ptr parentType;
+ KService::List services;
+ bool parentTypeLoaded;
+};
+
+KServiceType::KServiceType( const TQString & _fullpath)
+ : KSycocaEntry(_fullpath), d(0)
+{
+ KDesktopFile config( _fullpath );
+
+ init(&config);
+}
+
+KServiceType::KServiceType( KDesktopFile *config )
+ : KSycocaEntry(config->fileName()), d(0)
+{
+ init(config);
+}
+
+void
+KServiceType::init( KDesktopFile *config)
+{
+ // Is it a mimetype ?
+ m_strName = config->readEntry( "MimeType" );
+
+ // Or is it a servicetype ?
+ if ( m_strName.isEmpty() )
+ {
+ m_strName = config->readEntry( "X-TDE-ServiceType" );
+ }
+
+ m_strComment = config->readComment();
+ m_bDeleted = config->readBoolEntry( "Hidden", false );
+ m_strIcon = config->readIcon();
+
+ // We store this as property to preserve BC, we can't change that
+ // because KSycoca needs to remain BC between KDE 2.x and KDE 3.x
+ TQString sDerived = config->readEntry( "X-TDE-Derived" );
+ m_bDerived = !sDerived.isEmpty();
+ if ( m_bDerived )
+ m_mapProps.insert( "X-TDE-Derived", sDerived );
+
+ TQStringList tmpList = config->groupList();
+ TQStringList::Iterator gIt = tmpList.begin();
+
+ for( ; gIt != tmpList.end(); ++gIt )
+ {
+ if ( (*gIt).find( "Property::" ) == 0 )
+ {
+ config->setGroup( *gIt );
+ TQVariant v = config->readPropertyEntry( "Value",
+ TQVariant::nameToType( config->readEntry( "Type" ).ascii() ) );
+ if ( v.isValid() )
+ m_mapProps.insert( (*gIt).mid( 10 ), v );
+ }
+ }
+
+ gIt = tmpList.begin();
+ for( ; gIt != tmpList.end(); ++gIt )
+ {
+ if( (*gIt).find( "PropertyDef::" ) == 0 )
+ {
+ config->setGroup( *gIt );
+ m_mapPropDefs.insert( (*gIt).mid( 13 ),
+ TQVariant::nameToType( config->readEntry( "Type" ).ascii() ) );
+ }
+ }
+
+ m_bValid = !m_strName.isEmpty();
+}
+
+KServiceType::KServiceType( const TQString & _fullpath, const TQString& _type,
+ const TQString& _icon, const TQString& _comment )
+ : KSycocaEntry(_fullpath), d(0)
+{
+ m_strName = _type;
+ m_strIcon = _icon;
+ m_strComment = _comment;
+ m_bValid = !m_strName.isEmpty();
+}
+
+KServiceType::KServiceType( TQDataStream& _str, int offset )
+ : KSycocaEntry( _str, offset ), d(0)
+{
+ load( _str);
+}
+
+void
+KServiceType::load( TQDataStream& _str )
+{
+ TQ_INT8 b;
+ _str >> m_strName >> m_strIcon >> m_strComment >> m_mapProps >> m_mapPropDefs
+ >> b;
+ m_bValid = b;
+ m_bDerived = m_mapProps.contains("X-TDE-Derived");
+}
+
+void
+KServiceType::save( TQDataStream& _str )
+{
+ KSycocaEntry::save( _str );
+ // !! This data structure should remain binary compatible at all times !!
+ // You may add new fields at the end. Make sure to update the version
+ // number in tdesycoca.h
+ _str << m_strName << m_strIcon << m_strComment << m_mapProps << m_mapPropDefs
+ << (TQ_INT8)m_bValid;
+}
+
+KServiceType::~KServiceType()
+{
+ delete d;
+}
+
+TQString KServiceType::parentServiceType() const
+{
+ TQVariant v = property("X-TDE-Derived");
+ return v.toString();
+}
+
+bool KServiceType::inherits( const TQString& servTypeName ) const
+{
+ if ( name() == servTypeName )
+ return true;
+ TQString st = parentServiceType();
+ while ( !st.isEmpty() )
+ {
+ KServiceType::Ptr ptr = KServiceType::serviceType( st );
+ if (!ptr) return false; //error
+ if ( ptr->name() == servTypeName )
+ return true;
+ st = ptr->parentServiceType();
+ }
+ return false;
+}
+
+TQVariant
+KServiceType::property( const TQString& _name ) const
+{
+ TQVariant v;
+
+ if ( _name == "Name" )
+ v = TQVariant( m_strName );
+ else if ( _name == "Icon" )
+ v = TQVariant( m_strIcon );
+ else if ( _name == "Comment" )
+ v = TQVariant( m_strComment );
+ else {
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( _name );
+ if ( it != m_mapProps.end() )
+ v = it.data();
+ }
+
+ return v;
+}
+
+TQStringList
+KServiceType::propertyNames() const
+{
+ TQStringList res;
+
+ TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.begin();
+ for( ; it != m_mapProps.end(); ++it )
+ res.append( it.key() );
+
+ res.append( "Name" );
+ res.append( "Comment" );
+ res.append( "Icon" );
+
+ return res;
+}
+
+TQVariant::Type
+KServiceType::propertyDef( const TQString& _name ) const
+{
+ TQMap<TQString,TQVariant::Type>::ConstIterator it = m_mapPropDefs.find( _name );
+ if ( it == m_mapPropDefs.end() )
+ return TQVariant::Invalid;
+ return it.data();
+}
+
+TQStringList
+KServiceType::propertyDefNames() const
+{
+ TQStringList l;
+
+ TQMap<TQString,TQVariant::Type>::ConstIterator it = m_mapPropDefs.begin();
+ for( ; it != m_mapPropDefs.end(); ++it )
+ l.append( it.key() );
+
+ return l;
+}
+
+KServiceType::Ptr KServiceType::serviceType( const TQString& _name )
+{
+ KServiceType * p = KServiceTypeFactory::self()->findServiceTypeByName( _name );
+ return KServiceType::Ptr( p );
+}
+
+static void addUnique(KService::List &lst, TQDict<KService> &dict, const KService::List &newLst, bool lowPrio)
+{
+ TQValueListConstIterator<KService::Ptr> it = newLst.begin();
+ for( ; it != newLst.end(); ++it )
+ {
+ KService *service = static_cast<KService*>(*it);
+ if (dict.find(service->desktopEntryPath()))
+ continue;
+ dict.insert(service->desktopEntryPath(), service);
+ lst.append(service);
+ if (lowPrio)
+ service->setInitialPreference( 0 );
+ }
+}
+
+KService::List KServiceType::offers( const TQString& _servicetype )
+{
+ TQDict<KService> dict(53);
+ KService::List lst;
+
+ // Services associated directly with this servicetype (the normal case)
+ KServiceType::Ptr serv = KServiceTypeFactory::self()->findServiceTypeByName( _servicetype );
+ if ( serv )
+ addUnique(lst, dict, KServiceFactory::self()->offers( serv->offset() ), false);
+ else
+ kdWarning(7009) << "KServiceType::offers : servicetype " << _servicetype << " not found" << endl;
+
+ // Find services associated with any mimetype parents. e.g. text/x-java -> text/plain
+ KMimeType::Ptr mime = dynamic_cast<KMimeType*>(static_cast<KServiceType *>(serv));
+ bool isAMimeType = (mime != 0);
+ if (mime)
+ {
+ while(true)
+ {
+ TQString parent = mime->parentMimeType();
+ if (parent.isEmpty())
+ break;
+ mime = dynamic_cast<KMimeType *>(KServiceTypeFactory::self()->findServiceTypeByName( parent ));
+ if (!mime)
+ break;
+
+ addUnique(lst, dict, KServiceFactory::self()->offers( mime->offset() ), false);
+ }
+ }
+ serv = mime = 0;
+
+ //TQValueListIterator<KService::Ptr> it = lst.begin();
+ //for( ; it != lst.end(); ++it )
+ // kdDebug() << (*it).data() << " " << (*it)->name() << endl;
+
+ // Support for all/* is deactivated by KServiceTypeProfile::configurationMode()
+ // (and makes no sense when querying for an "all" servicetype itself
+ // nor for non-mimetypes service types)
+ if ( !KServiceTypeProfile::configurationMode()
+ && isAMimeType
+ && _servicetype.left(4) != "all/" )
+ {
+ // Support for services associated with "all"
+ KServiceType * servAll = KServiceTypeFactory::self()->findServiceTypeByName( "all/all" );
+ if ( servAll )
+ {
+ addUnique(lst, dict, KServiceFactory::self()->offers( servAll->offset() ), true);
+ }
+ else
+ kdWarning(7009) << "KServiceType::offers : servicetype all/all not found" << endl;
+ delete servAll;
+
+ // Support for services associated with "allfiles"
+ if ( _servicetype != "inode/directory" && _servicetype != "inode/directory-locked" )
+ {
+ KServiceType * servAllFiles = KServiceTypeFactory::self()->findServiceTypeByName( "all/allfiles" );
+ if ( servAllFiles )
+ {
+ addUnique(lst, dict, KServiceFactory::self()->offers( servAllFiles->offset() ), true);
+ }
+ else
+ kdWarning(7009) << "KServiceType::offers : servicetype all/allfiles not found" << endl;
+ delete servAllFiles;
+ }
+ }
+
+ return lst;
+}
+
+KServiceType::List KServiceType::allServiceTypes()
+{
+ return KServiceTypeFactory::self()->allServiceTypes();
+}
+
+KServiceType::Ptr KServiceType::parentType()
+{
+ if (d && d->parentTypeLoaded)
+ return d->parentType;
+
+ if (!d)
+ d = new KServiceTypePrivate;
+
+ TQString parentSt = parentServiceType();
+ if (!parentSt.isEmpty())
+ {
+ d->parentType = KServiceTypeFactory::self()->findServiceTypeByName( parentSt );
+ if (!d->parentType)
+ kdWarning(7009) << "'" << desktopEntryPath() << "' specifies undefined mimetype/servicetype '"<< parentSt << "'" << endl;
+ }
+
+ d->parentTypeLoaded = true;
+
+ return d->parentType;
+}
+
+void KServiceType::addService(KService::Ptr service)
+{
+ if (!d)
+ d = new KServiceTypePrivate;
+
+ if (d->services.count() && d->services.last() == service)
+ return;
+
+ d->services.append(service);
+}
+
+KService::List KServiceType::services()
+{
+ if (d)
+ return d->services;
+
+ return KService::List();
+}
+
+void KServiceType::virtual_hook( int id, void* data )
+{ KSycocaEntry::virtual_hook( id, data ); }
diff --git a/tdeio/tdeio/kservicetype.h b/tdeio/tdeio/kservicetype.h
new file mode 100644
index 000000000..b1cad7284
--- /dev/null
+++ b/tdeio/tdeio/kservicetype.h
@@ -0,0 +1,251 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 1999 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 __kservicetype_h__
+#define __kservicetype_h__
+
+#include "tdesycocaentry.h"
+#include "kservice.h"
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqptrlist.h>
+#include <tqmap.h>
+#include <tqshared.h>
+#include <tqdatastream.h>
+#include <tqvariant.h>
+
+#include <ksimpleconfig.h>
+
+/**
+ * A service type is the generic notion for a mimetype, a type of service
+ * instead of a type of file.
+ * For instance, KOfficeFilter is a service type.
+ * It is associated to services according to the user profile (kuserprofile.h).
+ * Service types are stored as desktop files in $TDEHOME/share/servicetypes.
+ * @see KService
+ */
+class TDEIO_EXPORT KServiceType : public KSycocaEntry
+{
+ K_SYCOCATYPE( KST_KServiceType, KSycocaEntry )
+
+public:
+ typedef KSharedPtr<KServiceType> Ptr;
+ typedef TQValueList<Ptr> List;
+public:
+
+ /**
+ * Constructor. You may pass in arguments to create a servicetype with
+ * specific properties.
+ * @param _fullpath the path of the service type's desktop file
+ * @param _name the name of the service type
+ * @param _icon the icon name of the service type (can be null)
+ * @param _comment a comment (can be null)
+ */
+ KServiceType( const TQString & _fullpath, const TQString& _name,
+ const TQString& _icon, const TQString& _comment);
+
+ /**
+ * Construct a service type and take all informations from a config file.
+ * @param _fullpath path of the desktop file, set to "" if calling from
+ * a inherited constructor.
+ */
+ KServiceType( const TQString & _fullpath );
+
+ /**
+ * Construct a service type and take all informations from a deskop file.
+ * @param config the configuration file
+ */
+ KServiceType( KDesktopFile *config);
+
+ /**
+ * @internal construct a service from a stream.
+ * The stream must already be positionned at the correct offset
+ */
+ KServiceType( TQDataStream& _str, int offset );
+
+ virtual ~KServiceType();
+
+ /**
+ * Returns the icon associated with this service type. Some
+ * derived classes offer special functions which take for
+ * example an URL and returns a special icon for this
+ * URL. An example is KMimeType, KFolderType and
+ * others.
+ * @return the name of the icon, can be TQString::null.
+ */
+ TQString icon() const { return m_strIcon; }
+
+ /**
+ * Returns the descriptive comment associated, if any.
+ * @return the comment, or TQString::null
+ */
+ TQString comment() const { return m_strComment; }
+
+ /**
+ * Returns the name of this service type.
+ * @return the name of the service type
+ */
+ TQString name() const { return m_strName; }
+
+ /**
+ * Returns the relative path to the desktop entry file responsible for
+ * this servicetype.
+ * For instance inode/directory.desktop, or kpart.desktop
+ * @return the path of the desktop file
+ */
+ TQString desktopEntryPath() const { return entryPath(); }
+
+ /**
+ * Checks whether this service type inherits another one.
+ * @return true if this service type inherits another one
+ * @see parentServiceType()
+ */
+ bool isDerived() const { return m_bDerived; }
+
+ /**
+ * If this service type inherits from another service type,
+ * return the name of the parent.
+ * @return the parent service type, or TQString:: null if not set
+ * @see isDerived()
+ */
+ TQString parentServiceType() const;
+
+ /**
+ * Checks whether this service type is or inherits from @p servTypeName.
+ * @return true if this servicetype is or inherits from @p servTypeName
+ * @since 3.1
+ */
+ bool inherits( const TQString& servTypeName ) const;
+
+ /**
+ * Returns the requested property. Some often used properties
+ * have convenience access functions like name(),
+ * comment() etc.
+ *
+ * @param _name the name of the property
+ * @return the property, or invalid if not found
+ */
+ virtual TQVariant property( const TQString& _name ) const;
+
+ /**
+ * Returns the list of all properties of this service type.
+ * @return the list of properties
+ */
+ virtual TQStringList propertyNames() const;
+
+ /**
+ * Checks whether the service type is valid.
+ * @return true if the service is valid (e.g. name is not empty)
+ */
+ bool isValid() const { return m_bValid; }
+
+ /**
+ * Returns the type of the property with the given @p _name.
+ *
+ * @param _name the name of the property
+ * @return the property type, or null if not found
+ */
+ virtual TQVariant::Type propertyDef( const TQString& _name ) const;
+
+ virtual TQStringList propertyDefNames() const;
+ virtual const TQMap<TQString,TQVariant::Type>& propertyDefs() const { return m_mapPropDefs; }
+
+ /**
+ * @internal
+ * Save ourselves to the data stream.
+ */
+ virtual void save( TQDataStream& );
+
+ /**
+ * @internal
+ * Load ourselves from the data stream.
+ */
+ virtual void load( TQDataStream& );
+
+ /**
+ * @internal
+ * Pointer to parent serice type
+ */
+ // gcc 2.95.x doesn't understand KServiceType::Ptr here
+ /* KServiceType:: */ Ptr parentType();
+ /**
+ * @internal
+ * Register service that provides this service type
+ */
+ void addService(KService::Ptr service);
+ /**
+ * @internal
+ * List serices that provide this service type
+ */
+ KService::List services();
+
+ /**
+ * Returns a pointer to the servicetype '_name' or 0L if the
+ * service type is unknown.
+ * VERY IMPORTANT : don't store the result in a KServiceType * !
+ * @param _name the name of the service type to search
+ * @return the pointer to the service type, or 0
+ */
+ static Ptr serviceType( const TQString& _name );
+
+ /**
+ * Returns all services supporting the given servicetype name.
+ * This doesn't take care of the user profile.
+ * In fact it is used by KServiceTypeProfile,
+ * which is used by KTrader, and that's the one you should use.
+ * @param _servicetype the name of the service type to search
+ * @return the list of all services of the given type
+ */
+ static KService::List offers( const TQString& _servicetype );
+
+ /**
+ * Returns a list of all the supported servicetypes. Useful for
+ * showing the list of available servicetypes in a listbox,
+ * for example.
+ * More memory consuming than the ones above, don't use unless
+ * really necessary.
+ * @return the list of all services
+ */
+ static List allServiceTypes();
+
+protected:
+ void init( KDesktopFile *config );
+
+protected:
+ TQString m_strName;
+ TQString m_strIcon;
+ TQString m_strComment;
+ TQMap<TQString,TQVariant> m_mapProps;
+ TQMap<TQString,TQVariant::Type> m_mapPropDefs;
+
+ bool m_bValid:1;
+ bool m_bDerived:1;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KServiceTypePrivate;
+ KServiceTypePrivate* d;
+};
+
+//TQDataStream& operator>>( TQDataStream& _str, KServiceType& s );
+//TQDataStream& operator<<( TQDataStream& _str, KServiceType& s );
+
+#endif
diff --git a/tdeio/tdeio/kservicetypefactory.cpp b/tdeio/tdeio/kservicetypefactory.cpp
new file mode 100644
index 000000000..ecf527384
--- /dev/null
+++ b/tdeio/tdeio/kservicetypefactory.cpp
@@ -0,0 +1,300 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 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 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 "kservicetypefactory.h"
+#include "tdesycoca.h"
+#include "tdesycocatype.h"
+#include "tdesycocadict.h"
+#include "kservicetype.h"
+#include "kmimetype.h"
+#include "kuserprofile.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <assert.h>
+#include <kstringhandler.h>
+#include <tqfile.h>
+
+KServiceTypeFactory::KServiceTypeFactory()
+ : KSycocaFactory( KST_KServiceTypeFactory )
+{
+ _self = this;
+ m_fastPatternOffset = 0;
+ m_otherPatternOffset = 0;
+ if (m_str)
+ {
+ // Read Header
+ TQ_INT32 i,n;
+ (*m_str) >> i;
+ m_fastPatternOffset = i;
+ (*m_str) >> i;
+ m_otherPatternOffset = i;
+ (*m_str) >> n;
+
+ if (n > 1024)
+ {
+ KSycoca::flagError();
+ }
+ else
+ {
+ TQString str;
+ for(;n;n--)
+ {
+ KSycocaEntry::read(*m_str, str);
+ (*m_str) >> i;
+ m_propertyTypeDict.insert(str, i);
+ }
+ }
+ }
+}
+
+
+KServiceTypeFactory::~KServiceTypeFactory()
+{
+ _self = 0L;
+ KServiceTypeProfile::clear();
+}
+
+KServiceTypeFactory * KServiceTypeFactory::self()
+{
+ if (!_self)
+ _self = new KServiceTypeFactory();
+ return _self;
+}
+
+KServiceType * KServiceTypeFactory::findServiceTypeByName(const TQString &_name)
+{
+ if (!m_sycocaDict) return 0L; // Error!
+ assert (!KSycoca::self()->isBuilding());
+ int offset = m_sycocaDict->find_string( _name );
+ if (!offset) return 0; // Not found
+ KServiceType * newServiceType = createEntry(offset);
+
+ // Check whether the dictionary was right.
+ if (newServiceType && (newServiceType->name() != _name))
+ {
+ // No it wasn't...
+ delete newServiceType;
+ newServiceType = 0; // Not found
+ }
+ return newServiceType;
+}
+
+TQVariant::Type KServiceTypeFactory::findPropertyTypeByName(const TQString &_name)
+{
+ if (!m_sycocaDict)
+ return TQVariant::Invalid; // Error!
+
+ assert (!KSycoca::self()->isBuilding());
+
+ TQMapConstIterator<TQString,int> it = m_propertyTypeDict.find(_name);
+ if (it != m_propertyTypeDict.end()) {
+ return (TQVariant::Type)it.data();
+ }
+
+ return TQVariant::Invalid;
+}
+
+KMimeType * KServiceTypeFactory::findFromPattern(const TQString &_filename, TQString *match)
+{
+ // Assume we're NOT building a database
+ if (!m_str) return 0;
+
+ // Get stream to the header
+ TQDataStream *str = m_str;
+
+ str->device()->at( m_fastPatternOffset );
+
+ TQ_INT32 nrOfEntries;
+ (*str) >> nrOfEntries;
+ TQ_INT32 entrySize;
+ (*str) >> entrySize;
+
+ TQ_INT32 fastOffset = str->device()->at( );
+
+ TQ_INT32 matchingOffset = 0;
+
+ // Let's go for a binary search in the "fast" pattern index
+ TQ_INT32 left = 0;
+ TQ_INT32 right = nrOfEntries - 1;
+ TQ_INT32 middle;
+ // Extract extension
+ int lastDot = _filename.findRev('.');
+ int ext_len = _filename.length() - lastDot - 1;
+ if (lastDot != -1 && ext_len <= 4) // if no '.', skip the extension lookup
+ {
+ TQString extension = _filename.right( ext_len );
+ extension = extension.leftJustify(4);
+
+ TQString pattern;
+ while (left <= right) {
+ middle = (left + right) / 2;
+ // read pattern at position "middle"
+ str->device()->at( middle * entrySize + fastOffset );
+ KSycocaEntry::read(*str, pattern);
+ int cmp = pattern.compare( extension );
+ if (cmp < 0)
+ left = middle + 1;
+ else if (cmp == 0) // found
+ {
+ (*str) >> matchingOffset;
+ // don't return newServiceType - there may be an "other" pattern that
+ // matches best this file, like *.tar.bz
+ if (match)
+ *match = "*."+pattern.stripWhiteSpace();
+ break; // but get out of the fast patterns
+ }
+ else
+ right = middle - 1;
+ }
+ }
+
+ // Now try the "other" Pattern table
+ if ( m_patterns.isEmpty() ) {
+ str->device()->at( m_otherPatternOffset );
+
+ TQString pattern;
+ TQ_INT32 mimetypeOffset;
+
+ while (true)
+ {
+ KSycocaEntry::read(*str, pattern);
+ if (pattern.isEmpty()) // end of list
+ break;
+ (*str) >> mimetypeOffset;
+ m_patterns.push_back( pattern );
+ m_pattern_offsets.push_back( mimetypeOffset );
+ }
+ }
+
+ assert( m_patterns.size() == m_pattern_offsets.size() );
+
+ TQStringList::const_iterator it = m_patterns.begin();
+ TQStringList::const_iterator end = m_patterns.end();
+ TQValueVector<TQ_INT32>::const_iterator it_offset = m_pattern_offsets.begin();
+
+ for ( ; it != end; ++it, ++it_offset )
+ {
+ if ( KStringHandler::matchFileName( _filename, *it ) )
+ {
+ if ( !matchingOffset || !(*it).endsWith( "*" ) ) // *.html wins over Makefile.*
+ {
+ matchingOffset = *it_offset;
+ if (match)
+ *match = *it;
+ break;
+ }
+ }
+ }
+
+ if ( matchingOffset ) {
+ KServiceType *newServiceType = createEntry( matchingOffset );
+ assert (newServiceType && newServiceType->isType( KST_KMimeType ));
+ return (KMimeType *) newServiceType;
+ }
+ else
+ return 0;
+}
+
+KMimeType::List KServiceTypeFactory::allMimeTypes()
+{
+ KMimeType::List result;
+ KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::Iterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ KMimeType *newMimeType = dynamic_cast<KMimeType *>((*it).data());
+ if (newMimeType)
+ result.append( KMimeType::Ptr( newMimeType ) );
+ }
+ return result;
+}
+
+KServiceType::List KServiceTypeFactory::allServiceTypes()
+{
+ KServiceType::List result;
+ KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::Iterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+#ifndef Q_WS_QWS
+ KServiceType *newServiceType = dynamic_cast<KServiceType *>((*it).data());
+#else //FIXME
+ KServiceType *newServiceType = (KServiceType*)(*it).data();
+#endif
+ if (newServiceType)
+ result.append( KServiceType::Ptr( newServiceType ) );
+ }
+ return result;
+}
+
+bool KServiceTypeFactory::checkMimeTypes()
+{
+ TQDataStream *str = KSycoca::self()->findFactory( factoryId() );
+ if (!str) return false;
+
+ // check if there are mimetypes/servicetypes
+ return (m_beginEntryOffset != m_endEntryOffset);
+}
+
+KServiceType * KServiceTypeFactory::createEntry(int offset)
+{
+ KServiceType *newEntry = 0;
+ KSycocaType type;
+ TQDataStream *str = KSycoca::self()->findEntry(offset, type);
+ if (!str) return 0;
+
+ switch(type)
+ {
+ case KST_KServiceType:
+ newEntry = new KServiceType(*str, offset);
+ break;
+ case KST_KMimeType:
+ newEntry = new KMimeType(*str, offset);
+ break;
+ case KST_KFolderType:
+ newEntry = new KFolderType(*str, offset);
+ break;
+ case KST_KDEDesktopMimeType:
+ newEntry = new KDEDesktopMimeType(*str, offset);
+ break;
+ case KST_KExecMimeType:
+ newEntry = new KExecMimeType(*str, offset);
+ break;
+
+ default:
+ kdError(7011) << TQString(TQString("KServiceTypeFactory: unexpected object entry in KSycoca database (type = %1)").arg((int)type)) << endl;
+ break;
+ }
+ if (newEntry && !newEntry->isValid())
+ {
+ kdError(7011) << "KServiceTypeFactory: corrupt object in KSycoca database!\n" << endl;
+ delete newEntry;
+ newEntry = 0;
+ }
+ return newEntry;
+}
+
+KServiceTypeFactory *KServiceTypeFactory::_self = 0;
+
+void KServiceTypeFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
+// vim: ts=3 sw=3 et
diff --git a/tdeio/tdeio/kservicetypefactory.h b/tdeio/tdeio/kservicetypefactory.h
new file mode 100644
index 000000000..e18630b2c
--- /dev/null
+++ b/tdeio/tdeio/kservicetypefactory.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __k_service_type_factory_h__
+#define __k_service_type_factory_h__
+
+#include <assert.h>
+
+#include <tqstringlist.h>
+#include <tqvaluevector.h>
+
+#include "tdesycocafactory.h"
+#include "kmimetype.h"
+
+class KSycoca;
+class KSycocaDict;
+
+class KServiceType;
+class KFolderType;
+class KDEDesktopMimeType;
+class KExecMimeType;
+
+/**
+ * @internal
+ * A sycoca factory for service types (e.g. mimetypes)
+ * It loads the service types from parsing directories (e.g. mimelnk/)
+ * but can also create service types from data streams or single config files
+ */
+class TDEIO_EXPORT KServiceTypeFactory : public KSycocaFactory
+{
+ K_SYCOCAFACTORY( KST_KServiceTypeFactory )
+public:
+ /**
+ * Create factory
+ */
+ KServiceTypeFactory();
+
+ virtual ~KServiceTypeFactory();
+
+ /**
+ * Not meant to be called at this level
+ */
+ virtual KSycocaEntry *createEntry(const TQString &, const char *)
+ { assert(0); return 0; }
+
+ /**
+ * Find a service type in the database file (allocates it)
+ * Overloaded by KBuildServiceTypeFactory to return a memory one.
+ */
+ virtual KServiceType * findServiceTypeByName(const TQString &_name);
+
+ /**
+ * Find a the property type of a named property.
+ */
+ TQVariant::Type findPropertyTypeByName(const TQString &_name);
+
+ /**
+ * Find a mimetype from a filename (using the pattern list)
+ * @param _filename filename to check.
+ * @param match if provided, returns the pattern that matched.
+ */
+ KMimeType * findFromPattern(const TQString &_filename, TQString *match = 0);
+
+ /**
+ * @return all mimetypes
+ * Slow and memory consuming, avoid using
+ */
+ KMimeType::List allMimeTypes();
+
+ /**
+ * @return all servicetypes
+ * Slow and memory consuming, avoid using
+ */
+ KServiceType::List allServiceTypes();
+
+ /**
+ * @return true if at least one mimetype is present
+ * Safety test
+ */
+ bool checkMimeTypes();
+
+ /**
+ * @return the unique servicetype factory, creating it if necessary
+ */
+ static KServiceTypeFactory * self();
+
+protected:
+ virtual KServiceType *createEntry(int offset);
+
+private:
+ static KServiceTypeFactory *_self;
+
+protected:
+ int m_fastPatternOffset;
+ int m_otherPatternOffset;
+ TQMap<TQString,int> m_propertyTypeDict;
+
+private:
+ TQStringList m_patterns;
+ TQValueVector<TQ_INT32> m_pattern_offsets;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KServiceTypeFactoryPrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kshellcompletion.cpp b/tdeio/tdeio/kshellcompletion.cpp
new file mode 100644
index 000000000..2fb67a31f
--- /dev/null
+++ b/tdeio/tdeio/kshellcompletion.cpp
@@ -0,0 +1,311 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Smith <dsmith@algonet.se>
+
+ 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 <stdlib.h>
+#include <kdebug.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqregexp.h>
+#include <kcompletion.h>
+
+#include "kshellcompletion.h"
+
+class KShellCompletionPrivate
+{
+};
+
+KShellCompletion::KShellCompletion() : KURLCompletion()
+{
+ m_word_break_char = ' ';
+ m_quote_char1 = '\"';
+ m_quote_char2 = '\'';
+ m_escape_char = '\\';
+}
+
+/*
+ * makeCompletion()
+ *
+ * Entry point for file name completion
+ */
+TQString KShellCompletion::makeCompletion(const TQString &text)
+{
+ // Split text at the last unquoted space
+ //
+ splitText(text, m_text_start, m_text_compl);
+
+ // Remove quotes from the text to be completed
+ //
+ TQString tmp = unquote(m_text_compl);
+ m_text_compl = tmp;
+
+ // Do exe-completion if there was no unquoted space
+ //
+ bool is_exe_completion = true;
+
+ for ( uint i = 0; i < m_text_start.length(); i++ ) {
+ if ( m_text_start[i] != m_word_break_char ) {
+ is_exe_completion = false;
+ break;
+ }
+ }
+
+ Mode mode = (is_exe_completion ? ExeCompletion : FileCompletion );
+
+ setMode(mode);
+
+ // Make completion on the last part of text
+ //
+ return KURLCompletion::makeCompletion( m_text_compl );
+}
+
+/*
+ * postProcessMatch, postProcessMatches
+ *
+ * Called by KCompletion before emitting match() and matches()
+ *
+ * Add add the part of the text that was not completed
+ * Add quotes when needed
+ */
+void KShellCompletion::postProcessMatch( TQString *match ) const
+{
+ //kDebugInfo("KShellCompletion::postProcessMatch() in: '%s'",
+ // match->latin1());
+
+ KURLCompletion::postProcessMatch( match );
+
+ if ( match->isNull() )
+ return;
+
+ if ( match->right(1) == TQChar('/') )
+ quoteText( match, false, true ); // don't quote the trailing '/'
+ else
+ quoteText( match, false, false ); // quote the whole text
+
+ match->prepend( m_text_start );
+
+ //kDebugInfo("KShellCompletion::postProcessMatch() ut: '%s'",
+ // match->latin1());
+}
+
+void KShellCompletion::postProcessMatches( TQStringList *matches ) const
+{
+ KURLCompletion::postProcessMatches( matches );
+
+ for ( TQStringList::Iterator it = matches->begin();
+ it != matches->end(); it++ )
+ {
+ if ( !(*it).isNull() ) {
+ if ( (*it).right(1) == TQChar('/') )
+ quoteText( &(*it), false, true ); // don't quote trailing '/'
+ else
+ quoteText( &(*it), false, false ); // quote the whole text
+
+ (*it).prepend( m_text_start );
+ }
+ }
+}
+
+void KShellCompletion::postProcessMatches( KCompletionMatches *matches ) const
+{
+ KURLCompletion::postProcessMatches( matches );
+
+ for ( KCompletionMatches::Iterator it = matches->begin();
+ it != matches->end(); it++ )
+ {
+ if ( !(*it).value().isNull() ) {
+ if ( (*it).value().right(1) == TQChar('/') )
+ quoteText( &(*it).value(), false, true ); // don't quote trailing '/'
+ else
+ quoteText( &(*it).value(), false, false ); // quote the whole text
+
+ (*it).value().prepend( m_text_start );
+ }
+ }
+}
+
+/*
+ * splitText
+ *
+ * Split text at the last unquoted space
+ *
+ * text_start = [out] text at the left, including the space
+ * text_compl = [out] text at the right
+ */
+void KShellCompletion::splitText(const TQString &text, TQString &text_start,
+ TQString &text_compl) const
+{
+ bool in_quote = false;
+ bool escaped = false;
+ TQChar p_last_quote_char;
+ int last_unquoted_space = -1;
+ int end_space_len = 0;
+
+ for (uint pos = 0; pos < text.length(); pos++) {
+
+ end_space_len = 0;
+
+ if ( escaped ) {
+ escaped = false;
+ }
+ else if ( in_quote && text[pos] == p_last_quote_char ) {
+ in_quote = false;
+ }
+ else if ( !in_quote && text[pos] == m_quote_char1 ) {
+ p_last_quote_char = m_quote_char1;
+ in_quote = true;
+ }
+ else if ( !in_quote && text[pos] == m_quote_char2 ) {
+ p_last_quote_char = m_quote_char2;
+ in_quote = true;
+ }
+ else if ( text[pos] == m_escape_char ) {
+ escaped = true;
+ }
+ else if ( !in_quote && text[pos] == m_word_break_char ) {
+
+ end_space_len = 1;
+
+ while ( pos+1 < text.length() && text[pos+1] == m_word_break_char ) {
+ end_space_len++;
+ pos++;
+ }
+
+ if ( pos+1 == text.length() )
+ break;
+
+ last_unquoted_space = pos;
+ }
+ }
+
+ text_start = text.left( last_unquoted_space + 1 );
+
+ // the last part without trailing blanks
+ text_compl = text.mid( last_unquoted_space + 1 );
+
+// text_compl = text.mid( last_unquoted_space + 1,
+// text.length() - end_space_len - (last_unquoted_space + 1) );
+
+ //kDebugInfo("split right = '%s'", text_compl.latin1());
+}
+
+/*
+ * quoteText()
+ *
+ * Add quotations to 'text' if needed or if 'force' = true
+ * Returns true if quotes were added
+ *
+ * skip_last => ignore the last charachter (we add a space or '/' to all filenames)
+ */
+bool KShellCompletion::quoteText(TQString *text, bool force, bool skip_last) const
+{
+ int pos = 0;
+
+ if ( !force ) {
+ pos = text->find( m_word_break_char );
+ if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
+ }
+
+ if ( !force && pos == -1 ) {
+ pos = text->find( m_quote_char1 );
+ if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
+ }
+
+ if ( !force && pos == -1 ) {
+ pos = text->find( m_quote_char2 );
+ if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
+ }
+
+ if ( !force && pos == -1 ) {
+ pos = text->find( m_escape_char );
+ if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
+ }
+
+ if ( force || (pos >= 0) ) {
+
+ // Escape \ in the string
+ text->replace( m_escape_char,
+ TQString( m_escape_char ) + m_escape_char );
+
+ // Escape " in the string
+ text->replace( m_quote_char1,
+ TQString( m_escape_char ) + m_quote_char1 );
+
+ // " at the beginning
+ text->insert( 0, m_quote_char1 );
+
+ // " at the end
+ if ( skip_last )
+ text->insert( text->length()-1, m_quote_char1 );
+ else
+ text->insert( text->length(), m_quote_char1 );
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * unquote
+ *
+ * Remove quotes and return the result in a new string
+ *
+ */
+TQString KShellCompletion::unquote(const TQString &text) const
+{
+ bool in_quote = false;
+ bool escaped = false;
+ TQChar p_last_quote_char;
+ TQString result;
+
+ for (uint pos = 0; pos < text.length(); pos++) {
+
+ if ( escaped ) {
+ escaped = false;
+ result.insert( result.length(), text[pos] );
+ }
+ else if ( in_quote && text[pos] == p_last_quote_char ) {
+ in_quote = false;
+ }
+ else if ( !in_quote && text[pos] == m_quote_char1 ) {
+ p_last_quote_char = m_quote_char1;
+ in_quote = true;
+ }
+ else if ( !in_quote && text[pos] == m_quote_char2 ) {
+ p_last_quote_char = m_quote_char2;
+ in_quote = true;
+ }
+ else if ( text[pos] == m_escape_char ) {
+ escaped = true;
+ result.insert( result.length(), text[pos] );
+ }
+ else {
+ result.insert( result.length(), text[pos] );
+ }
+
+ }
+
+ return result;
+}
+
+void KShellCompletion::virtual_hook( int id, void* data )
+{ KURLCompletion::virtual_hook( id, data ); }
+
+#include "kshellcompletion.moc"
+
diff --git a/tdeio/tdeio/kshellcompletion.h b/tdeio/tdeio/kshellcompletion.h
new file mode 100644
index 000000000..fa90c509e
--- /dev/null
+++ b/tdeio/tdeio/kshellcompletion.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Smith <dsmith@algonet.se>
+
+ 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 KSHELLCOMPLETION_H
+#define KSHELLCOMPLETION_H
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+#include "kurlcompletion.h"
+
+class KShellCompletionPrivate;
+
+/**
+ * This class does shell-like completion of file names.
+ * A string passed to makeCompletion() will be interpreted as a shell
+ * command line. Completion will be done on the last argument on the line.
+ * Returned matches consist of the first arguments (uncompleted) plus the
+ * completed last argument.
+ *
+ * @short Shell-like completion of file names
+ * @author David Smith <dsmith@algonet.se>
+ */
+class TDEIO_EXPORT KShellCompletion : public KURLCompletion
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs a KShellCompletion object.
+ */
+ KShellCompletion();
+
+ /**
+ * Finds completions to the given text.
+ * The first match is returned and emitted in the signal match().
+ * @param text the text to complete
+ * @return the first match, or TQString::null if not found
+ */
+ TQString makeCompletion(const TQString &text);
+
+protected:
+ // Called by KCompletion
+ void postProcessMatch( TQString *match ) const;
+ void postProcessMatches( TQStringList *matches ) const;
+ void postProcessMatches( KCompletionMatches *matches ) const;
+
+private:
+ // Find the part of text that should be completed
+ void splitText(const TQString &text, TQString &text_start, TQString &text_compl) const;
+ // Insert quotes and neseccary escapes
+ bool quoteText(TQString *text, bool force, bool skip_last) const;
+ TQString unquote(const TQString &text) const;
+
+ TQString m_text_start; // part of the text that was not completed
+ TQString m_text_compl; // part of the text that was completed (unchanged)
+
+ TQChar m_word_break_char;
+ TQChar m_quote_char1;
+ TQChar m_quote_char2;
+ TQChar m_escape_char;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KShellCompletionPrivate *d;
+};
+
+#endif // KSHELLCOMPLETION_H
diff --git a/tdeio/tdeio/kshred.cpp b/tdeio/tdeio/kshred.cpp
new file mode 100644
index 000000000..f3997bf58
--- /dev/null
+++ b/tdeio/tdeio/kshred.cpp
@@ -0,0 +1,276 @@
+/*--------------------------------------------------------------------------*
+ KShred.h Copyright (c) 2000 MieTerra LLC.
+ Credits: Andreas F. Pour <bugs@mieterra.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "kshred.h"
+#include <time.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <stdlib.h>
+#include <kapplication.h>
+
+// antlarr: KDE 4: Make it const TQString &
+KShred::KShred(TQString fileName)
+{
+ if (fileName.isEmpty())
+ {
+ kdError() << "KShred: missing file name in constructor" << endl;
+ file = 0L;
+ }
+ else
+ {
+ file = new TQFile();
+ file->setName(fileName);
+ if (!file->open(IO_ReadWrite))
+ {
+ kdError() << "KShred: cannot open file '" << fileName.local8Bit().data() << "' for writing\n" << endl;
+ file = 0L;
+ fileSize = 0;
+ }
+ else
+ fileSize = file->size();
+
+ totalBytes = 0;
+ bytesWritten = 0;
+ lastSignalled = 0;
+ tbpc = 0;
+ fspc = 0;
+ }
+}
+
+
+KShred::~KShred()
+{
+ if (file != 0L)
+ delete file;
+}
+
+
+bool
+KShred::fill1s()
+{
+ return fillbyte(0xFF);
+}
+
+
+bool
+KShred::fill0s()
+{
+ return fillbyte(0x0);
+}
+
+
+bool
+KShred::fillbyte(unsigned int byte)
+{
+ if (file == 0L)
+ return false;
+ unsigned char buff[4096];
+ memset((void *) buff, byte, 4096);
+
+ unsigned int n;
+ for (unsigned int todo = fileSize; todo > 0; todo -= n)
+ {
+ n = (todo > 4096 ? 4096 : todo);
+ if (!writeData(buff, n))
+ return false;
+ }
+ if (!flush())
+ return false;
+ return file->at(0);
+}
+
+
+bool
+KShred::fillpattern(unsigned char *data, unsigned int size)
+{
+ if (file == 0L)
+ return false;
+
+ unsigned int n;
+ for (unsigned int todo = fileSize; todo > 0; todo -= n)
+ {
+ n = (todo > size ? size : todo);
+ if (!writeData(data, n))
+ return false;
+ }
+ if (!flush())
+ return false;
+ return file->at(0);
+}
+
+
+bool
+KShred::fillrandom()
+{
+ if (file == 0L)
+ return false;
+
+ long int buff[4096 / sizeof(long int)];
+ unsigned int n;
+
+ for (unsigned int todo = fileSize; todo > 0; todo -= n)
+ {
+ n = (todo > 4096 ? 4096 : todo);
+ // assumes that 4096 is a multipe of sizeof(long int)
+ int limit = (n + sizeof(long int) - 1) / sizeof(long int);
+ for (int i = 0; i < limit; i++)
+ buff[i] = kapp->random();
+
+ if (!writeData((unsigned char *) buff, n))
+ return false;
+ }
+ if (!flush())
+ return false;
+ return file->at(0);
+}
+
+
+// antlarr: KDE 4: Make it const TQString &
+bool
+KShred::shred(TQString fileName)
+{
+ if (fileName.isEmpty())
+ return false;
+
+ KShred shredder(fileName);
+ return shredder.shred();
+}
+
+
+bool
+KShred::writeData(unsigned char *data, unsigned int size)
+{
+ unsigned int ret = 0;
+
+ // write 'data' of size 'size' to the file
+ while ((ret < size) && (file->putch((int) data[ret]) >= 0))
+ ret++;
+
+ if ((totalBytes > 0) && (ret > 0))
+ {
+ if (tbpc == 0)
+ {
+ tbpc = ((unsigned int) (totalBytes / 100)) == 0 ? 1 : totalBytes / 100;
+ fspc = ((unsigned int) (fileSize / 100)) == 0 ? 1 : fileSize / 100;
+ }
+ bytesWritten += ret;
+ unsigned int pc = (unsigned int) (bytesWritten / tbpc);
+ if (pc > lastSignalled)
+ {
+ emit processedSize(fspc * pc);
+ lastSignalled = pc;
+ }
+ }
+ return ret == size;
+}
+
+
+bool
+KShred::flush()
+{
+ if (file == 0L)
+ return false;
+
+ file->flush();
+ return (fsync(file->handle()) == 0);
+}
+
+
+// shred the file, then close and remove it
+//
+// UPDATED: this function now uses 35 passes based on the the article
+// Peter Gutmann, "Secure Deletion of Data from Magnetic and Solid-State
+// Memory", first published in the Sixth USENIX Security Symposium
+// Proceedings, San Jose, CA, July 22-25, 1996 (available online at
+// http://rootprompt.org/article.php3?article=473)
+
+bool
+KShred::shred()
+{
+ unsigned char p[6][3] = {{'\222', '\111', '\044'}, {'\111', '\044', '\222'},
+ {'\044', '\222', '\111'}, {'\155', '\266', '\333'},
+ {'\266', '\333', '\155'}, {'\333', '\155', '\266'}};
+ TQString msg = i18n("Shredding: pass %1 of 35");
+
+ emit processedSize(0);
+
+ // thirty-five times writing the entire file size
+ totalBytes = fileSize * 35;
+ int iteration = 1;
+
+ for (int ctr = 0; ctr < 4; ctr++)
+ if (!fillrandom())
+ return false;
+ else
+ {
+ emit infoMessage(msg.arg(iteration));
+ }
+
+ if (!fillbyte((unsigned int) 0x55)) // '0x55' is 01010101
+ return false;
+ emit infoMessage(msg.arg(iteration));
+
+ if (!fillbyte((unsigned int) 0xAA)) // '0xAA' is 10101010
+ return false;
+ emit infoMessage(msg.arg(iteration));
+
+ for (unsigned int ctr = 0; ctr < 3; ctr++)
+ if (!fillpattern(p[ctr], 3)) // '0x92', '0x49', '0x24'
+ return false;
+ else
+ {
+ emit infoMessage(msg.arg(iteration));
+ }
+
+ for (unsigned int ctr = 0; ctr <= 255 ; ctr += 17)
+ if (!fillbyte(ctr)) // sequence of '0x00', '0x11', ..., '0xFF'
+ return false;
+ else
+ {
+ emit infoMessage(msg.arg(iteration));
+ }
+
+ for (unsigned int ctr = 0; ctr < 6; ctr++)
+ if (!fillpattern(p[ctr], 3)) // '0x92', '0x49', '0x24'
+ return false;
+ else
+ {
+ emit infoMessage(msg.arg(iteration));
+ }
+
+ for (int ctr = 0; ctr < 4; ctr++)
+ if (!fillrandom())
+ return false;
+ else
+ {
+ emit infoMessage(msg.arg(iteration));
+ }
+
+ if (!file->remove())
+ return false;
+ file = 0L;
+ emit processedSize(fileSize);
+ return true;
+}
+
+#include "kshred.moc"
+
diff --git a/tdeio/tdeio/kshred.h b/tdeio/tdeio/kshred.h
new file mode 100644
index 000000000..5fabcaa5b
--- /dev/null
+++ b/tdeio/tdeio/kshred.h
@@ -0,0 +1,156 @@
+/*--------------------------------------------------------------------------*
+ KShred.h Copyright (c) 2000 MieTerra LLC.
+ Credits: Andreas F. Pour <bugs@mieterra.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef kshred_h
+#define kshred_h
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <tqstring.h>
+#include <tqfile.h>
+#include <tqobject.h>
+
+#include <tdeio/global.h>
+
+/**
+ * @deprecated
+ * Erase a file in a way that makes recovery impossible -- well, no guarentee
+ * of that, but at least as difficult as reasonably possible.
+ * For this, KShred write several times over the
+ * existing file, using different patterns, before deleting it.
+ * @author Andreas F. Pour <bugs@mieterra.com>
+ * @author David Faure <faure@kde.org> (integration into KDE and progress signal)
+ */
+class TDEIO_EXPORT_DEPRECATED KShred : public TQObject { // KDE4: remove
+
+ Q_OBJECT
+
+ public:
+
+ /**
+ * Initialize the class using the name of the file to 'shred'.
+ * @param fileName fully qualified name of the file to shred.
+ */
+ KShred(TQString fileName);
+
+ /*
+ * Destructor for the class.
+ */
+ ~KShred();
+
+ /**
+ * Writes all 1's over the entire file and flushes the file buffers.
+ * @return true on success, false on error (invalid filename or write error)
+ */
+
+ bool fill1s();
+ /**
+ * Writes all 0's over the entire file and flushes the file buffers.
+ * @return true on success, false on error (invalid filename or write error)
+ */
+ bool fill0s();
+
+ /**
+ * Writes the specified byte over the entire file and flushes the file buffers.
+ * @param byte the value to write over every byte of the file
+ * @return true on success, false on error (invalid filename or write error)
+ */
+ bool fillbyte(unsigned int byte);
+
+ /**
+ * Writes random bites over the entire file and flushes the file buffers.
+ * @return true on success, false on error (invalid filename or write error)
+ */
+ bool fillrandom();
+
+ /**
+ * Writes the specified byte array over the entire file and flushes the file buffers.
+ * @param pattern the value to write over the entire file
+ * @param size the length of the 'pattern' byte array
+ * @return true on success, false on error (invalid filename or write error)
+ */
+ bool fillpattern(unsigned char *pattern, unsigned int size);
+
+ /**
+ * Shreds a file by writing a series of values over it (uses
+ * #fill0s, then fill1s, then fillrandom, then
+ * fillbyte with 0101..., then fillbyte with 1010....
+ * @return true on success, false on error (invalid filename or write error)
+ */
+ bool shred();
+
+ /**
+ * The simplest method to shred a file.
+ * No need to create an instance of the class.
+ * @param fileName fully qualified name of the file to shred.
+ */
+ static bool shred(TQString fileName);
+
+ signals:
+ /**
+ * Shows progress of the shredding.
+ * @param bytes the number of bytes written to the file
+ */
+ void processedSize(TDEIO::filesize_t bytes);
+
+ /**
+ * Shows a message in the progress dialog
+ * @param message the message to display
+ */
+ void infoMessage(const TQString & message);
+
+ private:
+ /**
+ * @internal write the data to the file
+ */
+ bool writeData(unsigned char *data, unsigned int size);
+
+ /**
+ * @internal flush the data to the file
+ */
+ bool flush();
+
+ /**
+ * @internal structure for the file information
+ */
+ TQFile *file;
+
+ /**
+ * @internal for the size of the file
+ */
+ TDEIO::filesize_t fileSize;
+
+ /**
+ * @internal for keeping track of progress
+ */
+ unsigned int totalBytes;
+ unsigned int bytesWritten;
+ unsigned int lastSignalled;
+ unsigned int tbpc;
+ unsigned int fspc;
+ private:
+ class KShredPrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/ktar.cpp b/tdeio/tdeio/ktar.cpp
new file mode 100644
index 000000000..9bde2873a
--- /dev/null
+++ b/tdeio/tdeio/ktar.cpp
@@ -0,0 +1,980 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
+
+ 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 <stdio.h>
+#include <stdlib.h> // strtol
+#include <time.h> // time()
+/*#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>*/
+#include <assert.h>
+
+#include <tqcstring.h>
+#include <tqdir.h>
+#include <tqfile.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <ktempfile.h>
+
+#include <kfilterdev.h>
+#include <kfilterbase.h>
+
+#include "ktar.h"
+#include <kstandarddirs.h>
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KTar ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KTar::KTarPrivate
+{
+public:
+ KTarPrivate() : tarEnd( 0 ), tmpFile( 0 ) {}
+ TQStringList dirList;
+ int tarEnd;
+ KTempFile* tmpFile;
+ TQString mimetype;
+ TQCString origFileName;
+
+ bool fillTempFile(const TQString & filename);
+ bool writeBackTempFile( const TQString & filename );
+};
+
+KTar::KTar( const TQString& filename, const TQString & _mimetype )
+ : KArchive( 0 )
+{
+ m_filename = filename;
+ d = new KTarPrivate;
+ TQString mimetype( _mimetype );
+ bool forced = true;
+ if ( mimetype.isEmpty() ) // Find out mimetype manually
+ {
+ if ( TQFile::exists( filename ) )
+ mimetype = KMimeType::findByFileContent( filename )->name();
+ else
+ mimetype = KMimeType::findByPath( filename, 0, true )->name();
+ kdDebug(7041) << "KTar::KTar mimetype = " << mimetype << endl;
+
+ // Don't move to prepareDevice - the other constructor theoretically allows ANY filter
+ if ( mimetype == "application/x-tgz" || mimetype == "application/x-targz" || // the latter is deprecated but might still be around
+ mimetype == "application/x-webarchive" )
+ {
+ // that's a gzipped tar file, so ask for gzip filter
+ mimetype = "application/x-gzip";
+ }
+ else if ( mimetype == "application/x-tbz" ) // that's a bzipped2 tar file, so ask for bz2 filter
+ {
+ mimetype = "application/x-bzip2";
+ }
+ else
+ {
+ // Something else. Check if it's not really gzip though (e.g. for KOffice docs)
+ TQFile file( filename );
+ if ( file.open( IO_ReadOnly ) )
+ {
+ unsigned char firstByte = file.getch();
+ unsigned char secondByte = file.getch();
+ unsigned char thirdByte = file.getch();
+ if ( firstByte == 0037 && secondByte == 0213 )
+ mimetype = "application/x-gzip";
+ else if ( firstByte == 'B' && secondByte == 'Z' && thirdByte == 'h' )
+ mimetype = "application/x-bzip2";
+ else if ( firstByte == 'P' && secondByte == 'K' && thirdByte == 3 )
+ {
+ unsigned char fourthByte = file.getch();
+ if ( fourthByte == 4 )
+ mimetype = "application/x-zip";
+ }
+ else if ( firstByte == 0xfd && secondByte == '7' && thirdByte == 'z' )
+ {
+ unsigned char fourthByte = file.getch();
+ unsigned char fifthByte = file.getch();
+ unsigned char sixthByte = file.getch();
+ if ( fourthByte == 'X' && fifthByte == 'Z' && sixthByte == 0x00 )
+ mimetype = "application/x-xz";
+ }
+ else if ( firstByte == 0x5d && secondByte == 0x00 && thirdByte == 0x00 )
+ {
+ unsigned char fourthByte = file.getch();
+ if ( fourthByte == 0x80 )
+ mimetype = "application/x-lzma";
+ }
+ }
+ file.close();
+ }
+ forced = false;
+ }
+ d->mimetype = mimetype;
+
+ prepareDevice( filename, mimetype, forced );
+}
+
+void KTar::prepareDevice( const TQString & filename,
+ const TQString & mimetype, bool /*forced*/ )
+{
+ if( "application/x-tar" == mimetype )
+ setDevice( TQT_TQIODEVICE(new TQFile( filename )) );
+ else
+ {
+ // The compression filters are very slow with random access.
+ // So instead of applying the filter to the device,
+ // the file is completly extracted instead,
+ // and we work on the extracted tar file.
+ // This improves the extraction speed by the tar ioslave dramatically,
+ // if the archive file contains many files.
+ // This is because the tar ioslave extracts one file after the other and normally
+ // has to walk through the decompression filter each time.
+ // Which is in fact nearly as slow as a complete decompression for each file.
+ d->tmpFile = new KTempFile(locateLocal("tmp", "ktar-"),".tar");
+ kdDebug( 7041 ) << "KTar::prepareDevice creating TempFile: " << d->tmpFile->name() << endl;
+ d->tmpFile->setAutoDelete(true);
+
+ // KTempFile opens the file automatically,
+ // the device must be closed, however, for KArchive.setDevice()
+ TQFile* file = d->tmpFile->file();
+ file->close();
+ setDevice(TQT_TQIODEVICE(file));
+ }
+}
+
+KTar::KTar( TQIODevice * dev )
+ : KArchive( dev )
+{
+ Q_ASSERT( dev );
+ d = new KTarPrivate;
+}
+
+KTar::~KTar()
+{
+ // mjarrett: Closes to prevent ~KArchive from aborting w/o device
+ if( isOpened() )
+ close();
+
+ if (d->tmpFile)
+ delete d->tmpFile; // will delete the device
+ else if ( !m_filename.isEmpty() )
+ delete device(); // we created it ourselves
+
+
+ delete d;
+}
+
+void KTar::setOrigFileName( const TQCString & fileName )
+{
+ if ( !isOpened() || !(mode() & IO_WriteOnly) )
+ {
+ kdWarning(7041) << "KTar::setOrigFileName: File must be opened for writing first.\n";
+ return;
+ }
+ d->origFileName = fileName;
+}
+
+TQ_LONG KTar::readRawHeader(char *buffer) {
+ // Read header
+ TQ_LONG n = device()->readBlock( buffer, 0x200 );
+ if ( n == 0x200 && buffer[0] != 0 ) {
+ // Make sure this is actually a tar header
+ if (strncmp(buffer + 257, "ustar", 5)) {
+ // The magic isn't there (broken/old tars), but maybe a correct checksum?
+ TQCString s;
+
+ int check = 0;
+ for( uint j = 0; j < 0x200; ++j )
+ check += buffer[j];
+
+ // adjust checksum to count the checksum fields as blanks
+ for( uint j = 0; j < 8 /*size of the checksum field including the \0 and the space*/; j++ )
+ check -= buffer[148 + j];
+ check += 8 * ' ';
+
+ s.sprintf("%o", check );
+
+ // only compare those of the 6 checksum digits that mean something,
+ // because the other digits are filled with all sorts of different chars by different tars ...
+ // Some tars right-justify the checksum so it could start in one of three places - we have to check each.
+ if( strncmp( buffer + 148 + 6 - s.length(), s.data(), s.length() )
+ && strncmp( buffer + 148 + 7 - s.length(), s.data(), s.length() )
+ && strncmp( buffer + 148 + 8 - s.length(), s.data(), s.length() ) ) {
+ kdWarning(7041) << "KTar: invalid TAR file. Header is: " << TQCString( buffer+257, 5 ) << endl;
+ return -1;
+ }
+ }/*end if*/
+ } else {
+ // reset to 0 if 0x200 because logical end of archive has been reached
+ if (n == 0x200) n = 0;
+ }/*end if*/
+ return n;
+}
+
+bool KTar::readLonglink(char *buffer,TQCString &longlink) {
+ TQ_LONG n = 0;
+ TQIODevice *dev = device();
+ // read size of longlink from size field in header
+ // size is in bytes including the trailing null (which we ignore)
+ buffer[ 0x88 ] = 0; // was 0x87, but 0x88 fixes BR #26437
+ char *dummy;
+ const char* p = buffer + 0x7c;
+ while( *p == ' ' ) ++p;
+ int size = (int)strtol( p, &dummy, 8 );
+
+ longlink.resize(size);
+ size--; // ignore trailing null
+ dummy = longlink.data();
+ int offset = 0;
+ while (size > 0) {
+ int chunksize = QMIN(size, 0x200);
+ n = dev->readBlock( dummy + offset, chunksize );
+ if (n == -1) return false;
+ size -= chunksize;
+ offset += 0x200;
+ }/*wend*/
+ // jump over the rest
+ int skip = 0x200 - (n % 0x200);
+ if (skip < 0x200) {
+ if (dev->readBlock(buffer,skip) != skip) return false;
+ }
+ return true;
+}
+
+TQ_LONG KTar::readHeader(char *buffer,TQString &name,TQString &symlink) {
+ name.truncate(0);
+ symlink.truncate(0);
+ while (true) {
+ TQ_LONG n = readRawHeader(buffer);
+ if (n != 0x200) return n;
+
+ // is it a longlink?
+ if (strcmp(buffer,"././@LongLink") == 0) {
+ char typeflag = buffer[0x9c];
+ TQCString longlink;
+ readLonglink(buffer,longlink);
+ switch (typeflag) {
+ case 'L': name = TQFile::decodeName(longlink); break;
+ case 'K': symlink = TQFile::decodeName(longlink); break;
+ }/*end switch*/
+ } else {
+ break;
+ }/*end if*/
+ }/*wend*/
+
+ // if not result of longlink, read names directly from the header
+ if (name.isEmpty())
+ // there are names that are exactly 100 bytes long
+ // and neither longlink nor \0 terminated (bug:101472)
+ name = TQFile::decodeName(TQCString(buffer, 101));
+ if (symlink.isEmpty())
+ symlink = TQFile::decodeName(TQCString(buffer + 0x9d, 101));
+
+ return 0x200;
+}
+
+/*
+ * If we have created a temporary file, we have
+ * to decompress the original file now and write
+ * the contents to the temporary file.
+ */
+bool KTar::KTarPrivate::fillTempFile( const TQString & filename) {
+ if ( ! tmpFile )
+ return true;
+
+ kdDebug( 7041 ) <<
+ "KTar::openArchive: filling tmpFile of mimetype '" << mimetype <<
+ "' ... " << endl;
+
+ bool forced = false;
+ if( "application/x-gzip" == mimetype
+ || "application/x-bzip2" == mimetype
+ || "application/x-lzma" == mimetype
+ || "application/x-xz" == mimetype)
+ forced = true;
+
+ TQIODevice *filterDev = KFilterDev::deviceForFile( filename, mimetype, forced );
+
+ if( filterDev ) {
+ TQFile* file = tmpFile->file();
+ file->close();
+ if ( ! file->open( IO_WriteOnly ) )
+ {
+ delete filterDev;
+ return false;
+ }
+ TQByteArray buffer(8*1024);
+ if ( ! filterDev->open( IO_ReadOnly ) )
+ {
+ delete filterDev;
+ return false;
+ }
+ TQ_LONG len = -1;
+ while ( !filterDev->atEnd() && len != 0) {
+ len = filterDev->readBlock(buffer.data(),buffer.size());
+ if ( len < 0 ) { // corrupted archive
+ delete filterDev;
+ return false;
+ }
+ file->writeBlock(buffer.data(),len);
+ }
+ filterDev->close();
+ delete filterDev;
+
+ file->close();
+ if ( ! file->open( IO_ReadOnly ) )
+ return false;
+ }
+ else
+ kdDebug( 7041 ) << "KTar::openArchive: no filterdevice found!" << endl;
+
+ kdDebug( 7041 ) << "KTar::openArchive: filling tmpFile finished." << endl;
+ return true;
+}
+
+bool KTar::openArchive( int mode )
+{
+ kdDebug( 7041 ) << "KTar::openArchive" << endl;
+ if ( !(mode & IO_ReadOnly) )
+ return true;
+
+ if ( !d->fillTempFile( m_filename ) )
+ return false;
+
+ // We'll use the permission and user/group of d->rootDir
+ // for any directory we emulate (see findOrCreate)
+ //struct stat buf;
+ //stat( m_filename, &buf );
+
+ d->dirList.clear();
+ TQIODevice* dev = device();
+
+ if ( !dev )
+ return false;
+
+ // read dir infos
+ char buffer[ 0x200 ];
+ bool ende = false;
+ do
+ {
+ TQString name;
+ TQString symlink;
+
+ // Read header
+ TQ_LONG n = readHeader(buffer,name,symlink);
+ if (n < 0) return false;
+ if (n == 0x200)
+ {
+ bool isdir = false;
+ TQString nm;
+
+ if ( name.right(1) == "/" )
+ {
+ isdir = true;
+ name = name.left( name.length() - 1 );
+ }
+
+ int pos = name.findRev( '/' );
+ if ( pos == -1 )
+ nm = name;
+ else
+ nm = name.mid( pos + 1 );
+
+ // read access
+ buffer[ 0x6b ] = 0;
+ char *dummy;
+ const char* p = buffer + 0x64;
+ while( *p == ' ' ) ++p;
+ int access = (int)strtol( p, &dummy, 8 );
+
+ // read user and group
+ TQString user( buffer + 0x109 );
+ TQString group( buffer + 0x129 );
+
+ // read time
+ buffer[ 0x93 ] = 0;
+ p = buffer + 0x88;
+ while( *p == ' ' ) ++p;
+ int time = (int)strtol( p, &dummy, 8 );
+
+ // read type flag
+ char typeflag = buffer[ 0x9c ];
+ // '0' for files, '1' hard link, '2' symlink, '5' for directory
+ // (and 'L' for longlink filenames, 'K' for longlink symlink targets)
+ // and 'D' for GNU tar extension DUMPDIR
+ if ( typeflag == '5' )
+ isdir = true;
+
+ bool isDumpDir = false;
+ if ( typeflag == 'D' )
+ {
+ isdir = false;
+ isDumpDir = true;
+ }
+ //bool islink = ( typeflag == '1' || typeflag == '2' );
+ //kdDebug(7041) << "typeflag=" << typeflag << " islink=" << islink << endl;
+
+ if (isdir)
+ access |= S_IFDIR; // f*cking broken tar files
+
+ KArchiveEntry* e;
+ if ( isdir )
+ {
+ //kdDebug(7041) << "KTar::openArchive directory " << nm << endl;
+ e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
+ }
+ else
+ {
+ // read size
+ buffer[ 0x88 ] = 0; // was 0x87, but 0x88 fixes BR #26437
+ char *dummy;
+ const char* p = buffer + 0x7c;
+ while( *p == ' ' ) ++p;
+ int size = (int)strtol( p, &dummy, 8 );
+
+ // for isDumpDir we will skip the additional info about that dirs contents
+ if ( isDumpDir )
+ {
+ //kdDebug(7041) << "KTar::openArchive " << nm << " isDumpDir" << endl;
+ e = new KArchiveDirectory( this, nm, access, time, user, group, symlink );
+ }
+ else
+ {
+
+ // Let's hack around hard links. Our classes don't support that, so make them symlinks
+ if ( typeflag == '1' )
+ {
+ kdDebug(7041) << "HARD LINK, setting size to 0 instead of " << size << endl;
+ size = 0; // no contents
+ }
+
+ //kdDebug(7041) << "KTar::openArchive file " << nm << " size=" << size << endl;
+ e = new KArchiveFile( this, nm, access, time, user, group, symlink,
+ dev->at(), size );
+ }
+
+ // Skip contents + align bytes
+ int rest = size % 0x200;
+ int skip = size + (rest ? 0x200 - rest : 0);
+ //kdDebug(7041) << "KTar::openArchive, at()=" << dev->at() << " rest=" << rest << " skipping " << skip << endl;
+ if (! dev->at( dev->at() + skip ) )
+ kdWarning(7041) << "KTar::openArchive skipping " << skip << " failed" << endl;
+ }
+
+ if ( pos == -1 )
+ {
+ if ( nm == "." ) // special case
+ {
+ Q_ASSERT( isdir );
+ if ( isdir )
+ setRootDir( static_cast<KArchiveDirectory *>( e ) );
+ }
+ else
+ rootDir()->addEntry( e );
+ }
+ else
+ {
+ // In some tar files we can find dir/./file => call cleanDirPath
+ TQString path = TQDir::cleanDirPath( name.left( pos ) );
+ // Ensure container directory exists, create otherwise
+ KArchiveDirectory * d = findOrCreate( path );
+ d->addEntry( e );
+ }
+ }
+ else
+ {
+ //tqDebug("Terminating. Read %d bytes, first one is %d", n, buffer[0]);
+ d->tarEnd = dev->at() - n; // Remember end of archive
+ ende = true;
+ }
+ } while( !ende );
+ return true;
+}
+
+/*
+ * Writes back the changes of the temporary file
+ * to the original file.
+ * Must only be called if in IO_WriteOnly mode
+ */
+bool KTar::KTarPrivate::writeBackTempFile( const TQString & filename ) {
+ if ( ! tmpFile )
+ return true;
+
+ kdDebug(7041) << "Write temporary file to compressed file" << endl;
+ kdDebug(7041) << filename << " " << mimetype << endl;
+
+ bool forced = false;
+ if( "application/x-gzip" == mimetype
+ || "application/x-bzip2" == mimetype
+ || "application/x-lzma" == mimetype
+ || "application/x-xz" == mimetype)
+ forced = true;
+
+ TQIODevice *dev = KFilterDev::deviceForFile( filename, mimetype, forced );
+ if( dev ) {
+ TQFile* file = tmpFile->file();
+ file->close();
+ if ( ! file->open(IO_ReadOnly) || ! dev->open(IO_WriteOnly) )
+ {
+ file->close();
+ delete dev;
+ return false;
+ }
+ if ( forced )
+ static_cast<KFilterDev *>(dev)->setOrigFileName( origFileName );
+ TQByteArray buffer(8*1024);
+ TQ_LONG len;
+ while ( ! file->atEnd()) {
+ len = file->readBlock(buffer.data(),buffer.size());
+ dev->writeBlock(buffer.data(),len);
+ }
+ file->close();
+ dev->close();
+ delete dev;
+ }
+
+ kdDebug(7041) << "Write temporary file to compressed file done." << endl;
+ return true;
+}
+
+bool KTar::closeArchive()
+{
+ d->dirList.clear();
+
+ // If we are in write mode and had created
+ // a temporary tar file, we have to write
+ // back the changes to the original file
+ if( mode() == IO_WriteOnly)
+ return d->writeBackTempFile( m_filename );
+
+ return true;
+}
+
+bool KTar::writeDir( const TQString& name, const TQString& user, const TQString& group )
+{
+ mode_t perm = 040755;
+ time_t the_time = time(0);
+ return writeDir(name,user,group,perm,the_time,the_time,the_time);
+#if 0
+ if ( !isOpened() )
+ {
+ kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
+ return false;
+ }
+
+ if ( !(mode() & IO_WriteOnly) )
+ {
+ kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
+ return false;
+ }
+
+ // In some tar files we can find dir/./ => call cleanDirPath
+ TQString dirName ( TQDir::cleanDirPath( name ) );
+
+ // Need trailing '/'
+ if ( dirName.right(1) != "/" )
+ dirName += "/";
+
+ if ( d->dirList.contains( dirName ) )
+ return true; // already there
+
+ char buffer[ 0x201 ];
+ memset( buffer, 0, 0x200 );
+ if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
+
+ // If more than 100 chars, we need to use the LongLink trick
+ if ( dirName.length() > 99 )
+ {
+ strcpy( buffer, "././@LongLink" );
+ fillBuffer( buffer, " 0", dirName.length()+1, 'L', user.local8Bit(), group.local8Bit() );
+ device()->writeBlock( buffer, 0x200 );
+ strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
+ buffer[0x200] = 0;
+ // write long name
+ device()->writeBlock( buffer, 0x200 );
+ // not even needed to reclear the buffer, tar doesn't do it
+ }
+ else
+ {
+ // Write name
+ strncpy( buffer, TQFile::encodeName(dirName), 0x200 );
+ buffer[0x200] = 0;
+ }
+
+ fillBuffer( buffer, " 40755", 0, 0x35, user.local8Bit(), group.local8Bit());
+
+ // Write header
+ device()->writeBlock( buffer, 0x200 );
+ if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
+
+ d->dirList.append( dirName ); // contains trailing slash
+ return true; // TODO if wanted, better error control
+#endif
+}
+
+bool KTar::prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size )
+{
+ mode_t dflt_perm = 0100644;
+ time_t the_time = time(0);
+ return prepareWriting(name,user,group,size,dflt_perm,
+ the_time,the_time,the_time);
+}
+
+bool KTar::doneWriting( uint size )
+{
+ // Write alignment
+ int rest = size % 0x200;
+ if ( mode() & IO_ReadWrite )
+ d->tarEnd = device()->at() + (rest ? 0x200 - rest : 0); // Record our new end of archive
+ if ( rest )
+ {
+ char buffer[ 0x201 ];
+ for( uint i = 0; i < 0x200; ++i )
+ buffer[i] = 0;
+ TQ_LONG nwritten = device()->writeBlock( buffer, 0x200 - rest );
+ return nwritten == 0x200 - rest;
+ }
+ return true;
+}
+
+/*** Some help from the tar sources
+struct posix_header
+{ byte offset
+ char name[100]; * 0 * 0x0
+ char mode[8]; * 100 * 0x64
+ char uid[8]; * 108 * 0x6c
+ char gid[8]; * 116 * 0x74
+ char size[12]; * 124 * 0x7c
+ char mtime[12]; * 136 * 0x88
+ char chksum[8]; * 148 * 0x94
+ char typeflag; * 156 * 0x9c
+ char linkname[100]; * 157 * 0x9d
+ char magic[6]; * 257 * 0x101
+ char version[2]; * 263 * 0x107
+ char uname[32]; * 265 * 0x109
+ char gname[32]; * 297 * 0x129
+ char devmajor[8]; * 329 * 0x149
+ char devminor[8]; * 337 * ...
+ char prefix[155]; * 345 *
+ * 500 *
+};
+*/
+
+void KTar::fillBuffer( char * buffer,
+ const char * mode, int size, time_t mtime, char typeflag,
+ const char * uname, const char * gname )
+{
+ // mode (as in stat())
+ assert( strlen(mode) == 6 );
+ strcpy( buffer+0x64, mode );
+ buffer[ 0x6a ] = ' ';
+ buffer[ 0x6b ] = '\0';
+
+ // dummy uid
+ strcpy( buffer + 0x6c, " 765 ");
+ // dummy gid
+ strcpy( buffer + 0x74, " 144 ");
+
+ // size
+ TQCString s;
+ s.sprintf("%o", size); // OCT
+ s = s.rightJustify( 11, ' ' );
+ strcpy( buffer + 0x7c, s.data() );
+ buffer[ 0x87 ] = ' '; // space-terminate (no null after)
+
+ // modification time
+ s.sprintf("%lo", static_cast<unsigned long>(mtime) ); // OCT
+ s = s.rightJustify( 11, ' ' );
+ strcpy( buffer + 0x88, s.data() );
+ buffer[ 0x93 ] = ' '; // space-terminate (no null after)
+
+ // spaces, replaced by the check sum later
+ buffer[ 0x94 ] = 0x20;
+ buffer[ 0x95 ] = 0x20;
+ buffer[ 0x96 ] = 0x20;
+ buffer[ 0x97 ] = 0x20;
+ buffer[ 0x98 ] = 0x20;
+ buffer[ 0x99 ] = 0x20;
+
+ /* From the tar sources :
+ Fill in the checksum field. It's formatted differently from the
+ other fields: it has [6] digits, a null, then a space -- rather than
+ digits, a space, then a null. */
+
+ buffer[ 0x9a ] = '\0';
+ buffer[ 0x9b ] = ' ';
+
+ // type flag (dir, file, link)
+ buffer[ 0x9c ] = typeflag;
+
+ // magic + version
+ strcpy( buffer + 0x101, "ustar");
+ strcpy( buffer + 0x107, "00" );
+
+ // user
+ strcpy( buffer + 0x109, uname );
+ // group
+ strcpy( buffer + 0x129, gname );
+
+ // Header check sum
+ int check = 32;
+ for( uint j = 0; j < 0x200; ++j )
+ check += buffer[j];
+ s.sprintf("%o", check ); // OCT
+ s = s.rightJustify( 7, ' ' );
+ strcpy( buffer + 0x94, s.data() );
+}
+
+void KTar::writeLonglink(char *buffer, const TQCString &name, char typeflag,
+ const char *uname, const char *gname) {
+ strcpy( buffer, "././@LongLink" );
+ int namelen = name.length() + 1;
+ fillBuffer( buffer, " 0", namelen, 0, typeflag, uname, gname );
+ device()->writeBlock( buffer, 0x200 );
+ int offset = 0;
+ while (namelen > 0) {
+ int chunksize = QMIN(namelen, 0x200);
+ memcpy(buffer, name.data()+offset, chunksize);
+ // write long name
+ device()->writeBlock( buffer, 0x200 );
+ // not even needed to reclear the buffer, tar doesn't do it
+ namelen -= chunksize;
+ offset += 0x200;
+ }/*wend*/
+}
+
+bool KTar::prepareWriting(const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime) {
+ return KArchive::prepareWriting(name,user,group,size,perm,atime,mtime,ctime);
+}
+
+bool KTar::prepareWriting_impl(const TQString &name, const TQString &user,
+ const TQString &group, uint size, mode_t perm,
+ time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
+ if ( !isOpened() )
+ {
+ kdWarning(7041) << "KTar::prepareWriting: You must open the tar file before writing to it\n";
+ return false;
+ }
+
+ if ( !(mode() & IO_WriteOnly) )
+ {
+ kdWarning(7041) << "KTar::prepareWriting: You must open the tar file for writing\n";
+ return false;
+ }
+
+ // In some tar files we can find dir/./file => call cleanDirPath
+ TQString fileName ( TQDir::cleanDirPath( name ) );
+
+ /*
+ // Create toplevel dirs
+ // Commented out by David since it's not necessary, and if anybody thinks it is,
+ // he needs to implement a findOrCreate equivalent in writeDir.
+ // But as KTar and the "tar" program both handle tar files without
+ // dir entries, there's really no need for that
+ TQString tmp ( fileName );
+ int i = tmp.findRev( '/' );
+ if ( i != -1 )
+ {
+ TQString d = tmp.left( i + 1 ); // contains trailing slash
+ if ( !m_dirList.contains( d ) )
+ {
+ tmp = tmp.mid( i + 1 );
+ writeDir( d, user, group ); // WARNING : this one doesn't create its toplevel dirs
+ }
+ }
+ */
+
+ char buffer[ 0x201 ];
+ memset( buffer, 0, 0x200 );
+ if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
+
+ // provide converted stuff we need lateron
+ TQCString encodedFilename = TQFile::encodeName(fileName);
+ TQCString uname = user.local8Bit();
+ TQCString gname = group.local8Bit();
+
+ // If more than 100 chars, we need to use the LongLink trick
+ if ( fileName.length() > 99 )
+ writeLonglink(buffer,encodedFilename,'L',uname,gname);
+
+ // Write (potentially truncated) name
+ strncpy( buffer, encodedFilename, 99 );
+ buffer[99] = 0;
+ // zero out the rest (except for what gets filled anyways)
+ memset(buffer+0x9d, 0, 0x200 - 0x9d);
+
+ TQCString permstr;
+ permstr.sprintf("%o",perm);
+ permstr = permstr.rightJustify(6, ' ');
+ fillBuffer(buffer, permstr, size, mtime, 0x30, uname, gname);
+
+ // Write header
+ return device()->writeBlock( buffer, 0x200 ) == 0x200;
+}
+
+bool KTar::writeDir(const TQString& name, const TQString& user,
+ const TQString& group, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime) {
+ return KArchive::writeDir(name,user,group,perm,atime,mtime,ctime);
+}
+
+bool KTar::writeDir_impl(const TQString &name, const TQString &user,
+ const TQString &group, mode_t perm,
+ time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
+ if ( !isOpened() )
+ {
+ kdWarning(7041) << "KTar::writeDir: You must open the tar file before writing to it\n";
+ return false;
+ }
+
+ if ( !(mode() & IO_WriteOnly) )
+ {
+ kdWarning(7041) << "KTar::writeDir: You must open the tar file for writing\n";
+ return false;
+ }
+
+ // In some tar files we can find dir/./ => call cleanDirPath
+ TQString dirName ( TQDir::cleanDirPath( name ) );
+
+ // Need trailing '/'
+ if ( dirName.right(1) != "/" )
+ dirName += "/";
+
+ if ( d->dirList.contains( dirName ) )
+ return true; // already there
+
+ char buffer[ 0x201 ];
+ memset( buffer, 0, 0x200 );
+ if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
+
+ // provide converted stuff we need lateron
+ TQCString encodedDirname = TQFile::encodeName(dirName);
+ TQCString uname = user.local8Bit();
+ TQCString gname = group.local8Bit();
+
+ // If more than 100 chars, we need to use the LongLink trick
+ if ( dirName.length() > 99 )
+ writeLonglink(buffer,encodedDirname,'L',uname,gname);
+
+ // Write (potentially truncated) name
+ strncpy( buffer, encodedDirname, 99 );
+ buffer[99] = 0;
+ // zero out the rest (except for what gets filled anyways)
+ memset(buffer+0x9d, 0, 0x200 - 0x9d);
+
+ TQCString permstr;
+ permstr.sprintf("%o",perm);
+ permstr = permstr.rightJustify(6, ' ');
+ fillBuffer( buffer, permstr, 0, mtime, 0x35, uname, gname);
+
+ // Write header
+ device()->writeBlock( buffer, 0x200 );
+ if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
+
+ d->dirList.append( dirName ); // contains trailing slash
+ return true; // TODO if wanted, better error control
+}
+
+bool KTar::writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime) {
+ return KArchive::writeSymLink(name,target,user,group,perm,atime,mtime,ctime);
+}
+
+bool KTar::writeSymLink_impl(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t /*atime*/, time_t mtime, time_t /*ctime*/) {
+ if ( !isOpened() )
+ {
+ kdWarning(7041) << "KTar::writeSymLink: You must open the tar file before writing to it\n";
+ return false;
+ }
+
+ if ( !(mode() & IO_WriteOnly) )
+ {
+ kdWarning(7041) << "KTar::writeSymLink: You must open the tar file for writing\n";
+ return false;
+ }
+
+ device()->flush();
+
+ // In some tar files we can find dir/./file => call cleanDirPath
+ TQString fileName ( TQDir::cleanDirPath( name ) );
+
+ char buffer[ 0x201 ];
+ memset( buffer, 0, 0x200 );
+ if ( mode() & IO_ReadWrite ) device()->at(d->tarEnd); // Go to end of archive as might have moved with a read
+
+ // provide converted stuff we need lateron
+ TQCString encodedFilename = TQFile::encodeName(fileName);
+ TQCString encodedTarget = TQFile::encodeName(target);
+ TQCString uname = user.local8Bit();
+ TQCString gname = group.local8Bit();
+
+ // If more than 100 chars, we need to use the LongLink trick
+ if (target.length() > 99)
+ writeLonglink(buffer,encodedTarget,'K',uname,gname);
+ if ( fileName.length() > 99 )
+ writeLonglink(buffer,encodedFilename,'L',uname,gname);
+
+ // Write (potentially truncated) name
+ strncpy( buffer, encodedFilename, 99 );
+ buffer[99] = 0;
+ // Write (potentially truncated) symlink target
+ strncpy(buffer+0x9d, encodedTarget, 99);
+ buffer[0x9d+99] = 0;
+ // zero out the rest
+ memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d);
+
+ TQCString permstr;
+ permstr.sprintf("%o",perm);
+ permstr = permstr.rightJustify(6, ' ');
+ fillBuffer(buffer, permstr, 0, mtime, 0x32, uname, gname);
+
+ // Write header
+ bool retval = device()->writeBlock( buffer, 0x200 ) == 0x200;
+ if ( mode() & IO_ReadWrite ) d->tarEnd = device()->at();
+ return retval;
+}
+
+void KTar::virtual_hook( int id, void* data ) {
+ switch (id) {
+ case VIRTUAL_WRITE_SYMLINK: {
+ WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
+ params->retval = writeSymLink_impl(*params->name,*params->target,
+ *params->user,*params->group,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ case VIRTUAL_WRITE_DIR: {
+ WriteDirParams *params = reinterpret_cast<WriteDirParams *>(data);
+ params->retval = writeDir_impl(*params->name,*params->user,
+ *params->group,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ case VIRTUAL_PREPARE_WRITING: {
+ PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
+ params->retval = prepareWriting_impl(*params->name,*params->user,
+ *params->group,params->size,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ default:
+ KArchive::virtual_hook( id, data );
+ }/*end switch*/
+}
+
diff --git a/tdeio/tdeio/ktar.h b/tdeio/tdeio/ktar.h
new file mode 100644
index 000000000..fc238073c
--- /dev/null
+++ b/tdeio/tdeio/ktar.h
@@ -0,0 +1,171 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2003 Leo Savernik <l.savernik@aon.at>
+
+ 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 __ktar_h
+#define __ktar_h
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdict.h>
+
+#include <karchive.h>
+
+/**
+ * A class for reading / writing (optionally compressed) tar archives.
+ *
+ * KTar allows you to read and write tar archives, including those
+ * that are compressed using gzip, bzip2, or xz.
+ *
+ * @author Torben Weis <weis@kde.org>, David Faure <faure@kde.org>
+ */
+class TDEIO_EXPORT KTar : public KArchive
+{
+public:
+ /**
+ * Creates an instance that operates on the given filename
+ * using the compression filter associated to given mimetype.
+ *
+ * @param filename is a local path (e.g. "/home/weis/myfile.tgz")
+ * @param mimetype "application/x-gzip", "application/x-bzip2",
+ * or "application/x-xz"
+ * Do not use application/x-tgz or similar - you only need to
+ * specify the compression layer ! If the mimetype is omitted, it
+ * will be determined from the filename.
+ */
+ KTar( const TQString& filename, const TQString & mimetype = TQString::null );
+
+ /**
+ * Creates an instance that operates on the given device.
+ * The device can be compressed (KFilterDev) or not (TQFile, etc.).
+ * @warning Do not assume that giving a TQFile here will decompress the file,
+ * in case it's compressed!
+ * @param dev the device to read from. If the source is compressed, the
+ * TQIODevice must take care of decompression
+ */
+ KTar( TQIODevice * dev );
+
+ /**
+ * If the tar ball is still opened, then it will be
+ * closed automatically by the destructor.
+ */
+ virtual ~KTar();
+
+ /**
+ * The name of the tar file, as passed to the constructor
+ * Null if you used the TQIODevice constructor.
+ * @return the name of the file, or TQString::null if unknown
+ */
+ TQString fileName() { return m_filename; } // TODO KDE4 const
+
+ /**
+ * Special function for setting the "original file name" in the gzip header,
+ * when writing a tar.gz file. It appears when using in the "file" command,
+ * for instance. Should only be called if the underlying device is a KFilterDev!
+ * @param fileName the original file name
+ */
+ void setOrigFileName( const TQCString & fileName );
+
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+ virtual bool writeDir( const TQString& name, const TQString& user, const TQString& group );
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool writeDir( const TQString& name, const TQString& user, const TQString& group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime );
+ virtual bool prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size );
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool prepareWriting( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime );
+ virtual bool doneWriting( uint size );
+
+protected:
+ /**
+ * Opens the archive for reading.
+ * Parses the directory listing of the archive
+ * and creates the KArchiveDirectory/KArchiveFile entries.
+ * @param mode the mode of the file
+ */
+ virtual bool openArchive( int mode );
+ virtual bool closeArchive();
+
+private:
+ /**
+ * @internal
+ */
+ void prepareDevice( const TQString & filename, const TQString & mimetype, bool forced = false );
+
+ /**
+ * @internal
+ * Fills @p buffer for writing a file as required by the tar format
+ * Has to be called LAST, since it does the checksum
+ * (normally, only the name has to be filled in before)
+ * @param mode is expected to be 6 chars long, [uname and gname 31].
+ */
+ void fillBuffer( char * buffer, const char * mode, int size, time_t mtime,
+ char typeflag, const char * uname, const char * gname );
+
+ /**
+ * @internal
+ * Writes an overlong name into a special longlink entry. Call this
+ * if the file name or symlink target (or both) are longer than 99 chars.
+ * @p buffer buffer at least 0x200 bytes big to be used as a write buffer
+ * @p name 8-bit encoded file name to be written
+ * @p typeflag specifying the type of the entry, 'L' for filenames or
+ * 'K' for symlink targets.
+ * @p uname user name
+ * @p gname group name
+ */
+ void writeLonglink(char *buffer, const TQCString &name, char typeflag,
+ const char *uname, const char *gname);
+
+ TQ_LONG readRawHeader(char *buffer);
+ bool readLonglink(char *buffer,TQCString &longlink);
+ TQ_LONG readHeader(char *buffer,TQString &name,TQString &symlink);
+
+ TQString m_filename;
+protected:
+ virtual void virtual_hook( int id, void* data );
+ bool prepareWriting_impl(const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime);
+ bool writeDir_impl(const TQString& name, const TQString& user,
+ const TQString& group, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime );
+ bool writeSymLink_impl(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+private:
+ class KTarPrivate;
+ KTarPrivate * d;
+};
+
+/**
+ * Old, deprecated naming
+ */
+#define KTarGz KTar
+#define KTarEntry KArchiveEntry
+#define KTarFile KArchiveFile
+#define KTarDirectory KArchiveDirectory
+
+#endif
diff --git a/tdeio/tdeio/ktrader.cpp b/tdeio/tdeio/ktrader.cpp
new file mode 100644
index 000000000..585c6a499
--- /dev/null
+++ b/tdeio/tdeio/ktrader.cpp
@@ -0,0 +1,186 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Torben Weis <weis@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 "ktrader.h"
+#include "ktraderparsetree.h"
+
+#include <tqtl.h>
+#include <tqbuffer.h>
+
+#include <kuserprofile.h>
+#include <kstandarddirs.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+
+template class KStaticDeleter<KTrader>;
+
+using namespace TDEIO;
+
+class KTraderSorter
+{
+public:
+ KTraderSorter() { m_pService = 0; };
+ KTraderSorter( const KTraderSorter& s ) : m_userPreference( s.m_userPreference ),
+ m_bAllowAsDefault( s.m_bAllowAsDefault ),
+ m_traderPreference( s.m_traderPreference ), m_pService( s.m_pService ) { }
+ KTraderSorter( const KService::Ptr &_service, double _pref1, int _pref2, bool _default )
+ { m_pService = _service;
+ m_userPreference = _pref2;
+ m_traderPreference = _pref1;
+ m_bAllowAsDefault = _default;
+ }
+
+ KService::Ptr service() const { return m_pService; }
+
+ bool operator< ( const KTraderSorter& ) const;
+
+private:
+ /**
+ * The bigger this number is, the better is this service in
+ * the users opinion.
+ */
+ int m_userPreference;
+ /**
+ * Is it allowed to use this service for default actions.
+ */
+ bool m_bAllowAsDefault;
+
+ /**
+ * The bigger this number is, the better is this service with
+ * respect to the queries preferences expression.
+ */
+ double m_traderPreference;
+
+ KService::Ptr m_pService;
+};
+
+bool KTraderSorter::operator< ( const KTraderSorter& _o ) const
+{
+ if ( _o.m_bAllowAsDefault && !m_bAllowAsDefault )
+ return true;
+ if ( _o.m_userPreference > m_userPreference )
+ return true;
+ if ( _o.m_userPreference < m_userPreference )
+ return false;
+ if ( _o.m_traderPreference > m_traderPreference )
+ return true;
+ return false;
+}
+
+// --------------------------------------------------
+
+KTrader* KTrader::s_self = 0;
+static KStaticDeleter<KTrader> ktradersd;
+
+KTrader* KTrader::self()
+{
+ if ( !s_self )
+ ktradersd.setObject( s_self, new KTrader );
+
+ return s_self;
+}
+
+KTrader::KTrader()
+{
+}
+
+KTrader::~KTrader()
+{
+}
+
+KTrader::OfferList KTrader::query( const TQString& _servicetype, const TQString& _constraint,
+ const TQString& _preferences ) const
+{
+ return query( _servicetype, TQString::null, _constraint, _preferences );
+}
+
+KTrader::OfferList KTrader::query( const TQString& _servicetype, const TQString& _genericServiceType,
+ const TQString& _constraint,
+ const TQString& _preferences ) const
+{
+ // TODO: catch errors here
+ ParseTreeBase::Ptr constr;
+ ParseTreeBase::Ptr prefs;
+
+ if ( !_constraint.isEmpty() )
+ constr = TDEIO::parseConstraints( _constraint );
+
+ if ( !_preferences.isEmpty() )
+ prefs = TDEIO::parsePreferences( _preferences );
+
+ KServiceTypeProfile::OfferList lst;
+ KTrader::OfferList ret;
+
+ // Get all services of this service type.
+ lst = KServiceTypeProfile::offers( _servicetype, _genericServiceType );
+ if ( lst.count() == 0 )
+ return ret;
+
+ if ( !!constr )
+ {
+ // Find all services matching the constraint
+ // and remove the other ones
+ KServiceTypeProfile::OfferList::Iterator it = lst.begin();
+ while( it != lst.end() )
+ {
+ if ( matchConstraint( constr, (*it).service(), lst ) != 1 )
+ it = lst.remove( it );
+ else
+ ++it;
+ }
+ }
+
+ if ( !!prefs )
+ {
+ TQValueList<KTraderSorter> sorter;
+ KServiceTypeProfile::OfferList::Iterator it = lst.begin();
+ for( ; it != lst.end(); ++it )
+ {
+ PreferencesReturn p = matchPreferences( prefs, (*it).service(), lst );
+ if ( p.type == PreferencesReturn::PRT_DOUBLE )
+ sorter.append( KTraderSorter( (*it).service(), p.f, (*it).preference(), (*it).allowAsDefault() ) );
+ }
+ qBubbleSort( sorter );
+
+ TQValueList<KTraderSorter>::Iterator it2 = sorter.begin();
+ for( ; it2 != sorter.end(); ++it2 )
+ ret.prepend( (*it2).service() );
+ }
+ else
+ {
+ KServiceTypeProfile::OfferList::Iterator it = lst.begin();
+ for( ; it != lst.end(); ++it )
+ ret.append( (*it).service() );
+ }
+
+#ifndef NDEBUG
+ TQString query = _servicetype;
+ if ( !_genericServiceType.isEmpty() ) {
+ query += ", ";
+ query += _genericServiceType;
+ }
+ kdDebug(7014) << "query for " << query
+ << " : returning " << ret.count() << " offers" << endl;
+#endif
+ return ret;
+}
+
+void KTrader::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "ktrader.moc"
diff --git a/tdeio/tdeio/ktrader.h b/tdeio/tdeio/ktrader.h
new file mode 100644
index 000000000..c96a64a21
--- /dev/null
+++ b/tdeio/tdeio/ktrader.h
@@ -0,0 +1,295 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Torben Weis <weis@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 __ktrader_h__
+#define __ktrader_h__
+
+#include <tqstring.h>
+#include <tqobject.h>
+#include <kservice.h>
+
+/**
+ * A Trader interface, similar to the CORBA Trader.
+ *
+ * Basically, it provides a way for an application to query
+ * all KDE services (that is, applications and components) that match
+ * a specific set of requirements. This allows you to find an
+ * application in real-time without you having to hard-code the name
+ * and/or path of the application.
+ *
+ * \par Examples
+ *
+ * A few examples will make this a lot more clear.
+ *
+ * Say you have an application that will display HTML. In this
+ * example, you don't want to link to tdehtml... and furthermore, you
+ * really don't care if the HTML browser is ours or not, as long as
+ * it works. The way that you formulate your query as well as the way
+ * that you execute the browser depends on whether or not you want the
+ * browser to run stand-alone or embedded.
+ *
+ * If you want the browser to run standalone, then you will limit the
+ * query to search for all services that handle 'text/html' @em and,
+ * furthermore, they must be applications (Type=Application). You
+ * then will use KRun::run() to invoke the application. In "trader-speak",
+ * this looks like this:
+ * \code
+ * KTrader::OfferList offers = KTrader::self()->query("text/html", "Type == 'Application'");
+ * KService::Ptr ptr = offers.first();
+ * KURL::List lst;
+ * lst.append("http://www.kde.org/index.html");
+ * KRun::run(*ptr, lst);
+ * \endcode
+ *
+ * Now, say that you want to list all KParts component that can handle HTML.
+ * \code
+ * KTrader::OfferList offers = KTrader::self()->query("text/html", "KParts/ReadOnlyPart");
+ * \endcode
+ *
+ * If you want to get the preferred KParts component for text/html you could use
+ * KServiceTypeProfile::preferredService("text/html", "KParts/ReadOnlyPart"), although if this is about
+ * loading that component you would rather use KParts::ComponentFactory directly.
+ *
+ *
+ * Please note that when including property names containing arithmetic operators like - or +, then you have
+ * to put brackets around the property name, in order to correctly separate arithmetic operations from
+ * the name. So for example a constraint expression like
+ * X-TDE-Blah < 4
+ * needs to be written as
+ * [X-TDE-Blah] < 4
+ * otherwise it could also be interpreted as
+ * Substract the numeric value of the property "KDE" and "Blah" from the property "X" and make sure it
+ * is less than 4.
+ * Instead of the other meaning, make sure that the numeric value of "X-TDE-Blah" is less than 4.
+ *
+ * See also the formal syntax defined in @ref tradersyntax .
+ *
+ * @short Provides a way to query the KDE infrastructure for specific
+ * applications or components.
+ * @author Torben Weis <weis@kde.org>
+ */
+class TDEIO_EXPORT KTrader : public TQObject
+{
+ Q_OBJECT
+public:
+ /**
+ * A list of services.
+ */
+ typedef TQValueList<KService::Ptr> OfferList;
+ typedef TQValueListIterator<KService::Ptr> OfferListIterator;
+
+ /**
+ * Standard destructor
+ */
+ virtual ~KTrader();
+
+ /**
+ * The main function in the KTrader class.
+ *
+ * It will return a list of services that match your
+ * specifications. The only required parameter is the service
+ * type. This is something like 'text/plain' or 'text/html'. The
+ * constraint parameter is used to limit the possible choices
+ * returned based on the constraints you give it.
+ *
+ * The @p constraint language is rather full. The most common
+ * keywords are AND, OR, NOT, IN, and EXIST, all used in an
+ * almost spoken-word form. An example is:
+ * \code
+ * (Type == 'Service') and (('KParts/ReadOnlyPart' in ServiceTypes) or (exist Exec))
+ * \endcode
+ *
+ * The keys used in the query (Type, ServiceType, Exec) are all
+ * fields found in the .desktop files.
+ *
+ * @param servicetype A service type like 'text/plain', 'text/html', or 'KOfficePlugin'.
+ * @param constraint A constraint to limit the choices returned, TQString::null to
+ * get all services of the given @p servicetype
+ * @param preferences Indicates a particular preference to return, TQString::null to ignore.
+ * Uses an expression in the constraint language that must return
+ * a number
+ *
+ * @return A list of services that satisfy the query
+ * @see http://developer.kde.org/documentation/library/3.5-api/tdelibs-apidocs/tdeio/tdeio/html/tradersyntax.html
+ */
+ virtual OfferList query( const TQString& servicetype,
+ const TQString& constraint = TQString::null,
+ const TQString& preferences = TQString::null) const;
+
+ /**
+ * A variant of query(), that takes two service types as an input.
+ * It is not exactly the same as adding the second service type
+ * in the constraints of the other query call, because this one
+ * takes into account user preferences for this combination of service types.
+ *
+ * Example usage:
+ * To get list of applications that can handle a given mimetype,
+ * set @p servicetype to the mimetype and @p genericServiceType is "Application".
+ * To get list of embeddable components that can handle a given mimetype,
+ * set @p servicetype to the mimetype and @p genericServiceType is "KParts/ReadOnlyPart".
+ *
+ * @param servicetype A service type like 'text/plain', 'text/html', or 'KOfficePlugin'.
+ * @param genericServiceType a basic service type, like 'KParts/ReadOnlyPart' or 'Application'
+ * @param constraint A constraint to limit the choices returned, TQString::null to
+ * get all services of the given @p servicetype
+ * @param preferences Indicates a particular preference to return, TQString::null to ignore.
+ * Uses an expression in the constraint language that must return
+ * a number
+ *
+ * @return A list of services that satisfy the query
+ * @see http://developer.kde.org/documentation/library/kdeqt/tradersyntax.html
+ */
+ OfferList query( const TQString& servicetype, const TQString& genericServiceType,
+ const TQString& constraint /*= TQString::null*/,
+ const TQString& preferences /*= TQString::null*/) const;
+
+ /**
+ * This is a static pointer to a KTrader instance.
+ *
+ * You will need
+ * to use this to access the KTrader functionality since the
+ * constuctors are protected.
+ *
+ * @return Static KTrader instance
+ */
+ static KTrader* self();
+
+protected:
+ /**
+ * @internal
+ */
+ KTrader();
+
+private:
+ static KTrader* s_self;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/** @page tradersyntax Trader Syntax
+ *
+ *
+ * @section Literals
+ *
+ * As elementary atoms of the constraint language, KTrader supports
+ * booleans, integers, floats and strings. Boolean literals are
+ * @a TRUE and @a FALSE . Integers can be positive or negative,
+ * i.e. @a 42 and @a -10 are legal values. Floating point
+ * numbers are @a 3.141592535 or @a -999.999 . Scientific notation
+ * like @a 1.5e-2 is not supported. Character literals are delimited
+ * by single quotation marks, e.g. @a 'Bernd' .
+ *
+ *
+ * @section Symbols
+ *
+ * Identifiers in query string are interpreted as property names, which
+ * are listed in the service's <tt>.desktop</tt> file. For example,
+ * <tt>Name</tt> is the name of the service, <tt>ServiceTypes</tt> is a
+ * list of the service types it supports. Note that only properties can
+ * be written as-is which start with an alphabetical character and contain
+ * only alphanumerical characters. Other properties have to be enclosed in
+ * brackets, e.g. <tt>[X-TDE-Init]</tt>. Properties must not contain any
+ * special characters other than <tt>-</tt>.
+ *
+ * Special property names:
+ * - <b>DesktopEntryName</b> stands for the filename of the service
+ * desktop entry without any extension. This can be useful to
+ * exclude some specific services.
+ * - <b>DesktopEntryPath</b> stands for the relative or full path
+ * to the .desktop file, see KService::desktopEntryPath. Mentionned
+ * here for completeness, better not use it (things can be moved
+ * around).
+ * - <b>Library</b> is the property whose value is set by
+ * <tt>X-TDE-Library</tt> in the .desktop file. This renaming
+ * happened to conform to the desktop file standard, but the
+ * property name didn't change.
+ *
+ *
+ * @section Comparison
+ *
+ * Supported comparison operators are:
+ *
+ * - <tt>==</tt>
+ * - <tt>!=</tt>
+ * - <tt>&lt;</tt>
+ * - <tt>&lt;=</tt>
+ * - <tt>&gt;</tt>
+ * - <tt>&gt;=</tt>
+ *
+ *
+ * @section Arithmetic Arithmetic and boolean expressions
+ *
+ * - <tt>+</tt>
+ * - <tt>-</tt>
+ * - <tt>*</tt>
+ * - <tt>/</tt>
+ * - <tt>and</tt>
+ * - <tt>or</tt>
+ * - <tt>not</tt>
+ *
+ * Note that the arithmetic operators are possible for integers and
+ * floating point numbers. <tt>-</tt> is both a unary and binary operator,
+ * <tt>not</tt> is a unary operator.
+ *
+ *
+ * @section Other Other operators
+ *
+ * - <tt>~</tt>
+ * - <tt>in</tt>
+ * - <tt>exist</tt>
+ * - <tt>()</tt>
+ *
+ * The tilde operator stands for a substring match. For example,
+ * <tt>KParts ~ 'KParts/ReadOnlyPart'</tt> is TRUE. The membership
+ * operator <tt>in</tt> tests whether a value is in a list. A list is a
+ * string with semi-colon- or comma-separated entries, depending on the
+ * type. An example for the membership operator is
+ * <tt>'text/plain' in ServiceTypes</tt>.
+ * The <tt>exist</tt> tests whether a certain property is defined in the
+ * <tt>.desktop</tt> file. Subexpressions are written in parentheses.
+ *
+ * Warning, testing the contents of a property only works if the property
+ * is specified. There is not support for default values. If the property
+ * might be missing, and you still want such services to be included, you
+ * have to check for existence before testing it. For instance, to say
+ * that MyProp is a boolean that defaults to true, and that you want the
+ * services that have it set to true, use:
+ * <tt>not exist MyProp or MyProp</tt>
+ * Simply testing for <tt>MyProp</tt> would
+ * exclude the services without the property at all.
+ *
+ *
+ * @section Examples
+ *
+ * The following examples show filters for .desktop files.
+ * <tt>Type</tt>, <tt>ServiceTypes</tt> and <tt>MimeType</tt> are
+ * properties in .desktop files. Be aware that within KTrader MimeType
+ * properties are understood as ServiceTypes ones.
+ *
+ *
+ * - <tt>Type == 'Application'</tt>@n
+ * All services that are applications.
+ * - <tt>'KParts/ReadOnlyPart' in ServiceTypes</tt>@n
+ * All read-only KParts.
+ * - <tt>('KParts/ReadOnlyPart' in ServiceTypes) and ('text/plain' in ServiceTypes)</tt>@n
+ * All read-only KParts that handle the mime type 'text/plain'.
+ *
+ * @author Bernd Gehrmann <a href="mailto:bernd@tdevelop.org">bernd@tdevelop.org</a>
+*/
+
+
+#endif
diff --git a/tdeio/tdeio/ktraderparse.cpp b/tdeio/tdeio/ktraderparse.cpp
new file mode 100644
index 000000000..627791c00
--- /dev/null
+++ b/tdeio/tdeio/ktraderparse.cpp
@@ -0,0 +1,159 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 <assert.h>
+#include <stdlib.h>
+
+// TODO: Torben: On error free memory!
+
+extern "C"
+{
+#include "ktraderparse.h"
+}
+
+#include "ktraderparsetree.h"
+#include <kdebug.h>
+
+using namespace TDEIO;
+
+static ParseTreeBase::Ptr *pTree = 0;
+static const char* sCode = 0;
+
+ParseTreeBase::Ptr TDEIO::parseConstraints( const TQString& _constr )
+{
+ TQCString str = _constr.utf8();
+ sCode = str.data();
+ KTraderParse_mainParse( sCode );
+ sCode = 0;
+ assert( pTree );
+ return *pTree;
+}
+
+ParseTreeBase::Ptr TDEIO::parsePreferences( const TQString& _prefs )
+{
+ TQCString str = _prefs.utf8();
+ sCode = str.data();
+ KTraderParse_mainParse( sCode );
+ sCode = 0;
+ assert( pTree );
+ return *pTree;
+}
+
+void KTraderParse_setParseTree( void *_ptr1 )
+{
+ if ( !pTree )
+ pTree = new ParseTreeBase::Ptr; // ### leak; should use KStaticDeleter
+ *pTree = static_cast<ParseTreeBase*>( _ptr1 );
+}
+
+
+void KTraderParse_error( const char* err )
+{
+ kdWarning(7014) << "Parsing '" << sCode << "' gave " << err << endl;
+}
+
+void* KTraderParse_newOR( void *_ptr1, void *_ptr2 )
+{
+ return new ParseTreeOR( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2 );
+}
+
+void* KTraderParse_newAND( void *_ptr1, void *_ptr2 )
+{
+ return new ParseTreeAND( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2 );
+}
+
+void* KTraderParse_newCMP( void *_ptr1, void *_ptr2, int _i )
+{
+ return new ParseTreeCMP( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2, _i );
+}
+
+void* KTraderParse_newIN( void *_ptr1, void *_ptr2 )
+{
+ return new ParseTreeIN( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2 );
+}
+
+void* KTraderParse_newMATCH( void *_ptr1, void *_ptr2 )
+{
+ return new ParseTreeMATCH( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2 );
+}
+
+void* KTraderParse_newCALC( void *_ptr1, void *_ptr2, int _i )
+{
+ return new ParseTreeCALC( (ParseTreeBase*)_ptr1, (ParseTreeBase*)_ptr2, _i );
+}
+
+void* KTraderParse_newBRACKETS( void *_ptr1 )
+{
+ return new ParseTreeBRACKETS( (ParseTreeBase*)_ptr1 );
+}
+
+void* KTraderParse_newNOT( void *_ptr1 )
+{
+ return new ParseTreeNOT( (ParseTreeBase*)_ptr1 );
+}
+
+void* KTraderParse_newEXIST( char *_ptr1 )
+{
+ ParseTreeEXIST *t = new ParseTreeEXIST( _ptr1 );
+ free(_ptr1);
+ return t;
+}
+
+void* KTraderParse_newID( char *_ptr1 )
+{
+ ParseTreeID *t = new ParseTreeID( _ptr1 );
+ free(_ptr1);
+ return t;
+}
+
+void* KTraderParse_newSTRING( char *_ptr1 )
+{
+ ParseTreeSTRING *t = new ParseTreeSTRING( _ptr1 );
+ free(_ptr1);
+ return t;
+}
+
+void* KTraderParse_newNUM( int _i )
+{
+ return new ParseTreeNUM( _i );
+}
+
+void* KTraderParse_newFLOAT( float _f )
+{
+ return new ParseTreeDOUBLE( _f );
+}
+
+void* KTraderParse_newBOOL( char _b )
+{
+ return new ParseTreeBOOL( (bool)_b );
+}
+
+void* KTraderParse_newMAX2( char *_id )
+{
+ ParseTreeMAX2 *t = new ParseTreeMAX2( _id );
+ free(_id);
+ return t;
+}
+
+void* KTraderParse_newMIN2( char *_id )
+{
+ ParseTreeMIN2 *t = new ParseTreeMIN2( _id );
+ free(_id);
+ return t;
+}
diff --git a/tdeio/tdeio/ktraderparse.h b/tdeio/tdeio/ktraderparse.h
new file mode 100644
index 000000000..bfeb15fe0
--- /dev/null
+++ b/tdeio/tdeio/ktraderparse.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __parse_h__
+#define __parse_h__
+
+/*
+ * Functions definition for yacc
+ */
+void KTraderParse_mainParse( const char *_code );
+void KTraderParse_setParseTree( void *_ptr1 );
+void KTraderParse_error( const char* err );
+void* KTraderParse_newOR( void *_ptr1, void *_ptr2 );
+void* KTraderParse_newAND( void *_ptr1, void *_ptr2 );
+void* KTraderParse_newCMP( void *_ptr1, void *_ptr2, int _i );
+void* KTraderParse_newIN( void *_ptr1, void *_ptr2 );
+void* KTraderParse_newMATCH( void *_ptr1, void *_ptr2 );
+void* KTraderParse_newCALC( void *_ptr1, void *_ptr2, int _i );
+void* KTraderParse_newBRACKETS( void *_ptr1 );
+void* KTraderParse_newNOT( void *_ptr1 );
+void* KTraderParse_newEXIST( char *_ptr1 );
+void* KTraderParse_newID( char *_ptr1 );
+void* KTraderParse_newSTRING( char *_ptr1 );
+void* KTraderParse_newNUM( int _i );
+void* KTraderParse_newFLOAT( float _f );
+void* KTraderParse_newBOOL( char _b );
+
+void* KTraderParse_newWITH( void *_ptr1 );
+void* KTraderParse_newMAX( void *_ptr1 );
+void* KTraderParse_newMIN( void *_ptr1 );
+void* KTraderParse_newMAX2( char *_id );
+void* KTraderParse_newMIN2( char *_id );
+void* KTraderParse_newFIRST();
+void* KTraderParse_newRANDOM();
+
+#endif
diff --git a/tdeio/tdeio/ktraderparsetree.cpp b/tdeio/tdeio/ktraderparsetree.cpp
new file mode 100644
index 000000000..0a04b7918
--- /dev/null
+++ b/tdeio/tdeio/ktraderparsetree.cpp
@@ -0,0 +1,714 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 "ktraderparsetree.h"
+
+namespace TDEIO {
+
+bool ParseTreeOR::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+
+// don't evaluate both expressions but return immediately
+// if the first one of them succeeds. Otherwise queries like
+// ((not exist Blah) or (Blah == 'Foo')) do not work, because
+// the evaluation of the second term ends up in a fatal error
+// (Simon)
+
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = c1.b;
+ _context->type = ParseContext::T_BOOL;
+ if ( c1.b )
+ return true;
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ if ( c2.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = ( c1.b || c2.b );
+ _context->type = ParseContext::T_BOOL;
+
+ return true;
+}
+
+bool ParseTreeAND::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+ if ( !c1.b )
+ {
+ _context->b = false;
+ return true;
+ }
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+ if ( c2.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = ( c1.b && c2.b );
+
+ return true;
+}
+
+bool ParseTreeCALC::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ // Bool extension
+ if ( c1.type != ParseContext::T_NUM && c1.type != ParseContext::T_DOUBLE && c1.type != ParseContext::T_BOOL )
+ return false;
+ // Bool extension
+ if ( c2.type != ParseContext::T_NUM && c2.type != ParseContext::T_DOUBLE && c2.type != ParseContext::T_BOOL )
+ return false;
+ // Bool extension
+ if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_BOOL )
+ return false;
+
+ /**
+ * Make types compatible
+ */
+ if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ c1.f = (double)c1.i;
+ }
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ c2.f = (double)c2.i;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_NUM )
+ {
+ c1.type = ParseContext::T_NUM;
+ if ( c1.b )
+ c1.i = 1;
+ else
+ c1.i = -1;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ if ( c1.b )
+ c1.f = 1.0;
+ else
+ c1.f = -1.0;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_BOOL )
+ {
+ c2.type = ParseContext::T_NUM;
+ if ( c2.b )
+ c2.i = 1;
+ else
+ c2.i = -1;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_BOOL )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ if ( c2.b )
+ c2.f = 1.0;
+ else
+ c2.f = -1.0;
+ }
+
+ _context->type = c1.type;
+
+ /**
+ * Calculate
+ */
+ switch( m_cmd )
+ {
+ case 1: /* Add */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f + c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i + c2.i );
+ return true;
+ }
+ break;
+ case 2: /* Sub */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f - c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i - c2.i );
+ return true;
+ }
+ break;
+ case 3: /* Mul */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ //cout << "Double Mult" << endl;
+ _context->f = ( c1.f * c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i * c2.i );
+ return true;
+ }
+ break;
+ case 4: /* Div */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f / c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i / c2.i );
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+bool ParseTreeCMP::eval( ParseContext *_context ) const
+{
+ //cout << "CMP 1 cmd=" << m_cmd << endl;
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ /**
+ * Make types compatible
+ */
+ if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ c1.f = (double)c1.i;
+ }
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ c2.f = (double)c2.i;
+ }
+
+ /**
+ * Compare
+ */
+ _context->type = ParseContext::T_BOOL;
+
+ switch( m_cmd )
+ {
+ case 1: /* EQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_STRING )
+ {
+ _context->b = ( c1.str == c2.str );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_BOOL )
+ {
+ _context->b = ( c1.b == c2.b );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f == c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i == c2.i );
+ return true;
+ }
+ break;
+ case 2: /* NEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = true;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_STRING )
+ {
+ _context->b = ( c1.str != c2.str );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_BOOL )
+ {
+ _context->b = ( c1.b != c2.b );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f != c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i != c2.i );
+ return true;
+ }
+ break;
+ case 3: /* GEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f >= c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i >= c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 4: /* LEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f <= c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i <= c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 5: /* < */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f < c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i < c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 6: /* > */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f > c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i > c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ }
+
+ return false;
+}
+
+bool ParseTreeNOT::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = !c1.b;
+ _context->type = ParseContext::T_BOOL;
+
+ return true;
+}
+
+bool ParseTreeEXIST::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ TQVariant prop = _context->service->property( m_id );
+ _context->b = prop.isValid();
+
+ return true;
+}
+
+bool ParseTreeMATCH::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+ if ( c1.type != ParseContext::T_STRING || c2.type != ParseContext::T_STRING )
+ return false;
+
+ _context->b = ( c2.str.find( c1.str ) != -1 );
+
+ return true;
+}
+
+bool ParseTreeIN::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ if ( (c1.type == ParseContext::T_NUM) &&
+ (c2.type == ParseContext::T_SEQ) &&
+ ((*(c2.seq.begin())).type() == TQVariant::Int)) {
+
+ TQValueList<TQVariant>::ConstIterator it = c2.seq.begin();
+ TQValueList<TQVariant>::ConstIterator end = c2.seq.end();
+ _context->b = false;
+ for (; it != end; it++)
+ if ((*it).type() == TQVariant::Int &&
+ (*it).toInt() == c1.i) {
+ _context->b = true;
+ break;
+ }
+ return true;
+ }
+
+ if ( c1.type == ParseContext::T_DOUBLE &&
+ c2.type == ParseContext::T_SEQ &&
+ (*(c2.seq.begin())).type() == TQVariant::Double) {
+
+ TQValueList<TQVariant>::ConstIterator it = c2.seq.begin();
+ TQValueList<TQVariant>::ConstIterator end = c2.seq.end();
+ _context->b = false;
+ for (; it != end; it++)
+ if ((*it).type() == TQVariant::Double &&
+ (*it).toDouble() == c1.i) {
+ _context->b = true;
+ break;
+ }
+ return true;
+ }
+
+ if ( c1.type == ParseContext::T_STRING && c2.type == ParseContext::T_STR_SEQ )
+ {
+ _context->b = ( c2.strSeq.find( c1.str ) != c2.strSeq.end() );
+ return true;
+ }
+
+ return false;
+}
+
+bool ParseTreeID::eval( ParseContext *_context ) const
+{
+ TQVariant prop = _context->service->property( m_str );
+ if ( !prop.isValid() )
+ return false;
+
+ if ( prop.type() == TQVariant::String )
+ {
+ _context->str = prop.toString();
+ _context->type = ParseContext::T_STRING;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Int )
+ {
+ _context->i = prop.toInt();
+ _context->type = ParseContext::T_NUM;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Bool )
+ {
+ _context->b = prop.toBool();
+ _context->type = ParseContext::T_BOOL;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Double )
+ {
+ _context->f = prop.toDouble();
+ _context->type = ParseContext::T_DOUBLE;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::List )
+ {
+ _context->seq = prop.toList();
+ _context->type = ParseContext::T_SEQ;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::StringList )
+ {
+ _context->strSeq = prop.toStringList();
+ _context->type = ParseContext::T_STR_SEQ;
+ return true;
+ }
+
+ // Value has unknown type
+ return false;
+}
+
+bool ParseTreeMIN2::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_DOUBLE;
+
+ TQVariant prop = _context->service->property( m_strId );
+ if ( !prop.isValid() )
+ return false;
+
+ if ( !_context->initMaxima( m_strId ) )
+ return false;
+
+ TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId );
+ if ( it == _context->maxima.end() )
+ return false;
+
+ if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT )
+ {
+ _context->f = (double)( prop.toInt() - it.data().iMin ) /
+ (double)(it.data().iMax - it.data().iMin ) * (-2.0) + 1.0;
+ return true;
+ }
+ else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE )
+ {
+ _context->f = ( prop.toDouble() - it.data().fMin ) / (it.data().fMax - it.data().fMin )
+ * (-2.0) + 1.0;
+ return true;
+ }
+
+ return false;
+}
+
+bool ParseTreeMAX2::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_DOUBLE;
+
+ TQVariant prop = _context->service->property( m_strId );
+ if ( !prop.isValid() )
+ return false;
+
+ // Create extrema
+ if ( !_context->initMaxima( m_strId ) )
+ return false;
+
+ // Find extrema
+ TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId );
+ if ( it == _context->maxima.end() )
+ return false;
+
+ if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT )
+ {
+ _context->f = (double)( prop.toInt() - it.data().iMin ) /
+ (double)(it.data().iMax - it.data().iMin ) * 2.0 - 1.0;
+ return true;
+ }
+ else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE )
+ {
+ _context->f = ( prop.toDouble() - it.data().fMin ) /
+ (it.data().fMax - it.data().fMin ) * 2.0 - 1.0;
+ return true;
+ }
+
+ return false;
+}
+
+int matchConstraint( const ParseTreeBase *_tree, const KService::Ptr &_service,
+ const KServiceTypeProfile::OfferList& _list )
+{
+ // Empty tree matches always
+ if ( !_tree )
+ return 1;
+
+ TQMap<TQString,PreferencesMaxima> maxima;
+ ParseContext c( _service, _list, maxima );
+
+ // Error during evaluation ?
+ if ( !_tree->eval( &c ) )
+ return -1;
+
+ // Did we get a bool ?
+ if ( c.type != ParseContext::T_BOOL )
+ return -1;
+
+ return ( c.b ? 1 : 0 );
+}
+
+PreferencesReturn matchPreferences( const ParseTreeBase *_tree, const KService::Ptr &_service,
+ const KServiceTypeProfile::OfferList& _list )
+{
+ // By default: error
+ PreferencesReturn ret;
+
+ if ( !_tree )
+ return ret;
+
+ TQMap<TQString,PreferencesMaxima> maxima;
+ ParseContext c( _service, _list, maxima );
+
+ if ( !_tree->eval( &c ) )
+ return ret;
+
+ // Did we get a numeric return value ?
+ if ( c.type == ParseContext::T_NUM )
+ {
+ ret.type = PreferencesReturn::PRT_DOUBLE;
+ ret.f = (double)c.i;
+ }
+ else if ( c.type == ParseContext::T_DOUBLE )
+ {
+ ret.type = PreferencesReturn::PRT_DOUBLE;
+ ret.f = c.f;
+ }
+
+ return ret;
+}
+
+bool ParseContext::initMaxima( const TQString& _prop )
+{
+ // Is the property known ?
+ TQVariant prop = service->property( _prop );
+ if ( !prop.isValid() )
+ return false;
+
+ // Numeric ?
+ if ( prop.type() != TQVariant::Int && prop.type() != TQVariant::Double )
+ return false;
+
+ // Did we cache the result ?
+ TQMap<TQString,PreferencesMaxima>::Iterator it = maxima.find( _prop );
+ if ( it != maxima.end() )
+ return ( it.data().type == PreferencesMaxima::PM_DOUBLE ||
+ it.data().type == PreferencesMaxima::PM_INT );
+
+ // Double or Int ?
+ PreferencesMaxima extrema;
+ if ( prop.type() == TQVariant::Int )
+ extrema.type = PreferencesMaxima::PM_INVALID_INT;
+ else
+ extrema.type = PreferencesMaxima::PM_INVALID_DOUBLE;
+
+ // Iterate over all offers
+ KServiceTypeProfile::OfferList::ConstIterator oit = offers.begin();
+ for( ; oit != offers.end(); ++oit )
+ {
+ TQVariant p = (*oit).service()->property( _prop );
+ if ( p.isValid() )
+ {
+ // Determine new maximum/minimum
+ if ( extrema.type == PreferencesMaxima::PM_INVALID_INT )
+ {
+ extrema.type = PreferencesMaxima::PM_INT;
+ extrema.iMin = p.toInt();
+ extrema.iMax = p.toInt();
+ }
+ // Correct existing extrema
+ else if ( extrema.type == PreferencesMaxima::PM_INT )
+ {
+ if ( p.toInt() < extrema.iMin )
+ extrema.iMin = p.toInt();
+ if ( p.toInt() > extrema.iMax )
+ extrema.iMax = p.toInt();
+ }
+ // Determine new maximum/minimum
+ else if ( extrema.type == PreferencesMaxima::PM_INVALID_DOUBLE )
+ {
+ extrema.type = PreferencesMaxima::PM_DOUBLE;
+ extrema.fMin = p.toDouble();
+ extrema.fMax = p.toDouble();
+ }
+ // Correct existing extrema
+ else if ( extrema.type == PreferencesMaxima::PM_DOUBLE )
+ {
+ if ( p.toDouble() < it.data().fMin )
+ extrema.fMin = p.toDouble();
+ if ( p.toDouble() > it.data().fMax )
+ extrema.fMax = p.toDouble();
+ }
+ }
+ }
+
+ // Cache the result
+ maxima.insert( _prop, extrema );
+
+ // Did we succeed ?
+ return ( extrema.type == PreferencesMaxima::PM_DOUBLE ||
+ extrema.type == PreferencesMaxima::PM_INT );
+}
+
+}
diff --git a/tdeio/tdeio/ktraderparsetree.h b/tdeio/tdeio/ktraderparsetree.h
new file mode 100644
index 000000000..a08b61a5a
--- /dev/null
+++ b/tdeio/tdeio/ktraderparsetree.h
@@ -0,0 +1,371 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __parse_tree_h__
+#define __parse_tree_h__
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqvaluelist.h>
+#include <tqmap.h>
+#include <tqshared.h>
+
+#include <kservice.h>
+#include <kuserprofile.h>
+
+#include "ktrader.h"
+
+namespace TDEIO {
+
+class ParseTreeBase;
+
+/** \internal */
+struct TDEIO_EXPORT PreferencesReturn
+{
+ enum Type { PRT_DOUBLE, PRT_ERROR };
+
+ PreferencesReturn() { type = PRT_ERROR; }
+
+ PreferencesReturn( const PreferencesReturn& _r )
+ {
+ type = _r.type;
+ f = _r.f;
+ }
+
+ Type type;
+ double f;
+};
+
+
+/**
+ * @internal
+ * @return 0 => Does not match
+ * 1 => Does match
+ * <0 => Error
+ */
+TDEIO_EXPORT int matchConstraint( const ParseTreeBase *_tree, const KService::Ptr &,
+ const KServiceTypeProfile::OfferList& );
+
+/**
+ * @internal
+ * @return 1 on success or <0 on Error
+ */
+TDEIO_EXPORT PreferencesReturn matchPreferences( const ParseTreeBase *_tree, const KService::Ptr &,
+ const KServiceTypeProfile::OfferList& );
+
+/**
+ * @internal
+ */
+struct TDEIO_EXPORT PreferencesMaxima
+{
+ enum Type { PM_ERROR, PM_INVALID_INT, PM_INVALID_DOUBLE, PM_DOUBLE, PM_INT };
+
+ Type type;
+ int iMax;
+ int iMin;
+ double fMax;
+ double fMin;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseContext
+{
+public:
+ /**
+ * This is NOT a copy constructor.
+ */
+ ParseContext( const ParseContext* _ctx ) : service( _ctx->service ), maxima( _ctx->maxima ),
+ offers( _ctx->offers ) {}
+ ParseContext( const KService::Ptr & _service, const KServiceTypeProfile::OfferList& _offers,
+ TQMap<TQString,PreferencesMaxima>& _m )
+ : service( _service ), maxima( _m ), offers( _offers ) {}
+
+ bool initMaxima( const TQString& _prop);
+
+ enum Type { T_STRING = 1, T_DOUBLE = 2, T_NUM = 3, T_BOOL = 4,
+ T_STR_SEQ = 5, T_SEQ = 6 };
+
+ TQString str;
+ int i;
+ double f;
+ bool b;
+ TQValueList<TQVariant> seq;
+ TQStringList strSeq;
+ Type type;
+
+ KService::Ptr service;
+
+ TQMap<TQString,PreferencesMaxima>& maxima;
+ const KServiceTypeProfile::OfferList& offers;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeBase : public KShared
+{
+public:
+ typedef KSharedPtr<ParseTreeBase> Ptr;
+ ParseTreeBase() { }
+
+ virtual bool eval( ParseContext *_context ) const = 0;
+protected:
+ virtual ~ParseTreeBase() { };
+};
+
+TDEIO_EXPORT ParseTreeBase::Ptr parseConstraints( const TQString& _constr );
+TDEIO_EXPORT ParseTreeBase::Ptr parsePreferences( const TQString& _prefs );
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeOR : public ParseTreeBase
+{
+public:
+ ParseTreeOR( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2 ) { m_pLeft = _ptr1; m_pRight = _ptr2; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeAND : public ParseTreeBase
+{
+public:
+ ParseTreeAND( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2 ) { m_pLeft = _ptr1; m_pRight = _ptr2; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeCMP : public ParseTreeBase
+{
+public:
+ ParseTreeCMP( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2, int _i ) { m_pLeft = _ptr1; m_pRight = _ptr2; m_cmd = _i; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+ int m_cmd;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeIN : public ParseTreeBase
+{
+public:
+ ParseTreeIN( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2 ) { m_pLeft = _ptr1; m_pRight = _ptr2; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeMATCH : public ParseTreeBase
+{
+public:
+ ParseTreeMATCH( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2 ) { m_pLeft = _ptr1; m_pRight = _ptr2; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeCALC : public ParseTreeBase
+{
+public:
+ ParseTreeCALC( ParseTreeBase *_ptr1, ParseTreeBase *_ptr2, int _i ) { m_pLeft = _ptr1; m_pRight = _ptr2; m_cmd = _i; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+ ParseTreeBase::Ptr m_pRight;
+ int m_cmd;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeBRACKETS : public ParseTreeBase
+{
+public:
+ ParseTreeBRACKETS( ParseTreeBase *_ptr ) { m_pLeft = _ptr; }
+
+ bool eval( ParseContext *_context ) const { return m_pLeft->eval( _context ); }
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeNOT : public ParseTreeBase
+{
+public:
+ ParseTreeNOT( ParseTreeBase *_ptr ) { m_pLeft = _ptr; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ ParseTreeBase::Ptr m_pLeft;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeEXIST : public ParseTreeBase
+{
+public:
+ ParseTreeEXIST( const char *_id ) { m_id = _id; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ TQString m_id;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeID : public ParseTreeBase
+{
+public:
+ ParseTreeID( const char *arg ) { m_str = arg; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ TQString m_str;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeSTRING : public ParseTreeBase
+{
+public:
+ ParseTreeSTRING( const char *arg ) { m_str = arg; }
+
+ bool eval( ParseContext *_context ) const { _context->type = ParseContext::T_STRING; _context->str = m_str; return true; }
+
+protected:
+ TQString m_str;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeNUM : public ParseTreeBase
+{
+public:
+ ParseTreeNUM( int arg ) { m_int = arg; }
+
+ bool eval( ParseContext *_context ) const { _context->type = ParseContext::T_NUM; _context->i = m_int; return true; }
+
+protected:
+ int m_int;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeDOUBLE : public ParseTreeBase
+{
+public:
+ ParseTreeDOUBLE( double arg ) { m_double = arg; }
+
+ bool eval( ParseContext *_context ) const { _context->type = ParseContext::T_DOUBLE; _context->f = m_double; return true; }
+
+protected:
+ double m_double;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeBOOL : public ParseTreeBase
+{
+public:
+ ParseTreeBOOL( bool arg ) { m_bool = arg; }
+
+ bool eval( ParseContext *_context ) const { _context->type = ParseContext::T_BOOL; _context->b = m_bool; return true; }
+
+protected:
+ bool m_bool;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeMAX2 : public ParseTreeBase
+{
+public:
+ ParseTreeMAX2( const char *_id ) { m_strId = _id; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ TQString m_strId;
+};
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT ParseTreeMIN2 : public ParseTreeBase
+{
+public:
+ ParseTreeMIN2( const char *_id ) { m_strId = _id; }
+
+ bool eval( ParseContext *_context ) const;
+
+protected:
+ TQString m_strId;
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/kurifilter.cpp b/tdeio/tdeio/kurifilter.cpp
new file mode 100644
index 000000000..5c50f4fa9
--- /dev/null
+++ b/tdeio/tdeio/kurifilter.cpp
@@ -0,0 +1,451 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 2000 Yves Arrouye <yves@realnames.com>
+ * Copyright (C) 2000 Dawit Alemayehu <adawit at 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 <config.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <ktrader.h>
+#include <kmimetype.h>
+#include <klibloader.h>
+#include <kstaticdeleter.h>
+#include <tdeparts/componentfactory.h>
+
+#ifdef HAVE_ELFICON
+#include <tqimage.h>
+#include "tdelficon.h"
+#endif // HAVE_ELFICON
+
+#include "kurifilter.h"
+
+template class TQPtrList<KURIFilterPlugin>;
+
+KURIFilterPlugin::KURIFilterPlugin( TQObject *parent, const char *name, double pri )
+ :TQObject( parent, name )
+{
+ m_strName = TQString::fromLatin1( name );
+ m_dblPriority = pri;
+}
+
+void KURIFilterPlugin::setFilteredURI( KURIFilterData& data, const KURL& uri ) const
+{
+ if ( data.uri() != uri )
+ {
+ data.m_pURI = uri;
+ data.m_bChanged = true;
+ }
+}
+
+class KURIFilterDataPrivate
+{
+public:
+ KURIFilterDataPrivate() {};
+ TQString abs_path;
+ TQString args;
+ TQString typedString;
+};
+
+KURIFilterData::KURIFilterData( const KURIFilterData& data )
+{
+ m_iType = data.m_iType;
+ m_pURI = data.m_pURI;
+ m_strErrMsg = data.m_strErrMsg;
+ m_strIconName = data.m_strIconName;
+ m_bChanged = data.m_bChanged;
+ m_bCheckForExecutables = data.m_bCheckForExecutables;
+ d = new KURIFilterDataPrivate;
+ d->abs_path = data.absolutePath();
+ d->typedString = data.typedString();
+ d->args = data.argsAndOptions();
+}
+
+KURIFilterData::~KURIFilterData()
+{
+ delete d;
+ d = 0;
+}
+
+void KURIFilterData::init( const KURL& url )
+{
+ m_iType = KURIFilterData::UNKNOWN;
+ m_pURI = url;
+ m_strErrMsg = TQString::null;
+ m_strIconName = TQString::null;
+ m_bCheckForExecutables = true;
+ m_bChanged = true;
+ d = new KURIFilterDataPrivate;
+ d->typedString = url.url();
+}
+
+void KURIFilterData::init( const TQString& url )
+{
+ m_iType = KURIFilterData::UNKNOWN;
+ m_pURI = url;
+ m_strErrMsg = TQString::null;
+ m_strIconName = TQString::null;
+ m_bCheckForExecutables = true;
+ m_bChanged = true;
+ d = new KURIFilterDataPrivate;
+ d->typedString = url;
+}
+
+void KURIFilterData::reinit(const KURL &url)
+{
+ delete d;
+ init(url);
+}
+
+void KURIFilterData::reinit(const TQString &url)
+{
+ delete d;
+ init(url);
+}
+
+TQString KURIFilterData::typedString() const
+{
+ return d->typedString;
+}
+
+void KURIFilterData::setCheckForExecutables( bool check )
+{
+ m_bCheckForExecutables = check;
+}
+
+bool KURIFilterData::hasArgsAndOptions() const
+{
+ return !d->args.isEmpty();
+}
+
+bool KURIFilterData::hasAbsolutePath() const
+{
+ return !d->abs_path.isEmpty();
+}
+
+bool KURIFilterData::setAbsolutePath( const TQString& absPath )
+{
+ // Since a malformed URL could possibly be a relative
+ // URL we tag it as a possible local resource...
+ if( (!m_pURI.isValid() || m_pURI.isLocalFile()) )
+ {
+ d->abs_path = absPath;
+ return true;
+ }
+ return false;
+}
+
+TQString KURIFilterData::absolutePath() const
+{
+ return d->abs_path;
+}
+
+TQString KURIFilterData::argsAndOptions() const
+{
+ return d->args;
+}
+
+TQString KURIFilterData::iconName()
+{
+ if( m_bChanged )
+ {
+ m_customIconPixmap = TQPixmap();
+ switch ( m_iType )
+ {
+ case KURIFilterData::LOCAL_FILE:
+ case KURIFilterData::LOCAL_DIR:
+ case KURIFilterData::NET_PROTOCOL:
+ {
+ m_strIconName = KMimeType::iconForURL( m_pURI );
+ break;
+ }
+ case KURIFilterData::EXECUTABLE:
+ {
+ TQString exeName = m_pURI.url();
+ exeName = exeName.mid( exeName.findRev( '/' ) + 1 ); // strip path if given
+ KService::Ptr service = KService::serviceByDesktopName( exeName );
+#ifndef HAVE_ELFICON
+ // Try to find an icon with the same name as the binary (useful for non-tde apps)
+ // FIXME: We should only do this if the binary is in the system path somewhere,
+ // otherwise TDE could end up showing system icons for user binaries
+ if (service && service->icon() != TQString::fromLatin1( "unknown" )) {
+ m_strIconName = service->icon();
+ }
+ else if ( !TDEGlobal::iconLoader()->loadIcon( exeName, KIcon::NoGroup, 16, KIcon::DefaultState, 0, true ).isNull() ) {
+ m_strIconName = exeName;
+ }
+ else {
+ // use default
+ m_strIconName = TQString::fromLatin1("exec");
+ }
+#else // HAVE_ELFICON
+ // Try to find an icon with the same name as the binary (useful for non-tde apps)
+ // FIXME: We should only do this if the binary is in the system path somewhere,
+ // otherwise TDE could end up showing system icons for user binaries
+ if (service && service->icon() != TQString::fromLatin1( "unknown" )) {
+ m_strIconName = service->icon();
+ }
+ else if ( !TDEGlobal::iconLoader()->loadIcon( exeName, KIcon::NoGroup, 16, KIcon::DefaultState, 0, true ).isNull() ) {
+ m_strIconName = exeName;
+ }
+ else {
+ // use default
+ m_strIconName = TQString::fromLatin1("exec");
+ }
+ // Try to load from elf file (if supported)
+ // Check for an embedded icon
+ unsigned int icon_size;
+ libr_icon *icon = NULL;
+ libr_file *handle = NULL;
+ libr_access_t access = LIBR_READ;
+ char libr_can_continue = 1;
+
+ if((handle = libr_open(const_cast<char*>(m_pURI.path().ascii()), access)) == NULL)
+ {
+ kdWarning() << "failed to open file" << m_pURI.path() << endl;
+ libr_can_continue = 0;
+ }
+
+ if (libr_can_continue == 1) {
+ icon_size = 32; // FIXME: Is this a reasonable size request for all possible usages of kurifilter?
+ icon = libr_icon_geticon_bysize(handle, icon_size);
+
+ if (libr_can_continue == 1) {
+ // See if the embedded icon name matches any icon file names already on the system
+ // If it does, use the system icon instead of the embedded one
+ int iconresnamefound = 0;
+ iconentry *entry = NULL;
+ iconlist icons;
+ if(!get_iconlist(handle, &icons))
+ {
+ // Failed to obtain a list of ELF icons
+ kdWarning() << "failed to obtain ELF icon: " << libr_errmsg() << endl;
+
+ // See if there is a system icon we can use
+ TQString sysIconName = elf_get_resource(handle, ".metadata_sysicon");
+ if (!sysIconName.isEmpty()) {
+ if (TDEGlobal::iconLoader()->iconPath(sysIconName.ascii(), 0, true) != "") {
+ m_strIconName = sysIconName;
+ }
+ }
+
+ libr_close(handle);
+ libr_can_continue = 0;
+ }
+ else {
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(icon == NULL)
+ {
+ // Try loading this icon as fallback
+ icon = libr_icon_geticon_byname(handle, entry->name);
+ }
+ if (TDEGlobal::iconLoader()->iconPath(entry->name, 0, true) != "") {
+ iconresnamefound = 1;
+ m_strIconName = entry->name;
+ break;
+ }
+ }
+ }
+
+ if (libr_can_continue == 1) {
+ if ((iconresnamefound == 0) && (icon)) {
+ // Extract the embedded icon
+ size_t icon_data_length;
+ char* icondata = libr_icon_malloc(icon, &icon_data_length);
+ m_customIconPixmap.loadFromData(static_cast<uchar*>(static_cast<void*>(icondata)), icon_data_length); // EVIL CAST
+ if (icon_size != 0) {
+ TQImage ip = m_customIconPixmap.convertToImage();
+ ip = ip.smoothScale(icon_size, icon_size);
+ m_customIconPixmap.convertFromImage(ip);
+ }
+ free(icondata);
+ libr_icon_close(icon);
+ }
+
+ libr_close(handle);
+ }
+ }
+ }
+#endif // HAVE_ELFICON
+ break;
+ }
+ case KURIFilterData::HELP:
+ {
+ m_strIconName = TQString::fromLatin1("khelpcenter");
+ break;
+ }
+ case KURIFilterData::SHELL:
+ {
+ m_strIconName = TQString::fromLatin1("konsole");
+ break;
+ }
+ case KURIFilterData::ERROR:
+ case KURIFilterData::BLOCKED:
+ {
+ m_strIconName = TQString::fromLatin1("error");
+ break;
+ }
+ default:
+ m_strIconName = TQString::null;
+ break;
+ }
+ m_bChanged = false;
+ }
+ return m_strIconName;
+}
+
+TQPixmap KURIFilterData::customIconPixmap()
+{
+ return m_customIconPixmap;
+}
+
+//******************************************** KURIFilterPlugin **********************************************
+void KURIFilterPlugin::setArguments( KURIFilterData& data, const TQString& args ) const
+{
+ data.d->args = args;
+}
+
+//******************************************** KURIFilter **********************************************
+KURIFilter *KURIFilter::s_self;
+static KStaticDeleter<KURIFilter> kurifiltersd;
+
+KURIFilter *KURIFilter::self()
+{
+ if (!s_self)
+ s_self = kurifiltersd.setObject(s_self, new KURIFilter);
+ return s_self;
+}
+
+KURIFilter::KURIFilter()
+{
+ m_lstPlugins.setAutoDelete(true);
+ loadPlugins();
+}
+
+KURIFilter::~KURIFilter()
+{
+}
+
+bool KURIFilter::filterURI( KURIFilterData& data, const TQStringList& filters )
+{
+ bool filtered = false;
+ KURIFilterPluginList use_plugins;
+
+ // If we have a filter list, only include the once
+ // explicitly specified by it. Otherwise, use all available filters...
+ if( filters.isEmpty() )
+ use_plugins = m_lstPlugins; // Use everything that is loaded...
+ else
+ {
+ //kdDebug() << "Named plugins requested..." << endl;
+ for( TQStringList::ConstIterator lst = filters.begin(); lst != filters.end(); ++lst )
+ {
+ TQPtrListIterator<KURIFilterPlugin> it( m_lstPlugins );
+ for( ; it.current() ; ++it )
+ {
+ if( (*lst) == it.current()->name() )
+ {
+ //kdDebug() << "Will use filter plugin named: " << it.current()->name() << endl;
+ use_plugins.append( it.current() );
+ break; // We already found it ; so lets test the next named filter...
+ }
+ }
+ }
+ }
+
+ TQPtrListIterator<KURIFilterPlugin> it( use_plugins );
+ //kdDebug() << "Using " << use_plugins.count() << " out of the "
+ // << m_lstPlugins.count() << " available plugins" << endl;
+ for (; it.current() && !filtered; ++it)
+ {
+ //kdDebug() << "Using a filter plugin named: " << it.current()->name() << endl;
+ filtered |= it.current()->filterURI( data );
+ }
+ return filtered;
+}
+
+bool KURIFilter::filterURI( KURL& uri, const TQStringList& filters )
+{
+ KURIFilterData data = uri;
+ bool filtered = filterURI( data, filters );
+ if( filtered ) uri = data.uri();
+ return filtered;
+}
+
+bool KURIFilter::filterURI( TQString& uri, const TQStringList& filters )
+{
+ KURIFilterData data = uri;
+ bool filtered = filterURI( data, filters );
+ if( filtered ) uri = data.uri().url();
+ return filtered;
+
+}
+
+KURL KURIFilter::filteredURI( const KURL &uri, const TQStringList& filters )
+{
+ KURIFilterData data = uri;
+ filterURI( data, filters );
+ return data.uri();
+}
+
+TQString KURIFilter::filteredURI( const TQString &uri, const TQStringList& filters )
+{
+ KURIFilterData data = uri;
+ filterURI( data, filters );
+ return data.uri().url();
+}
+
+TQPtrListIterator<KURIFilterPlugin> KURIFilter::pluginsIterator() const
+{
+ return TQPtrListIterator<KURIFilterPlugin>(m_lstPlugins);
+}
+
+TQStringList KURIFilter::pluginNames() const
+{
+ TQStringList list;
+ for(TQPtrListIterator<KURIFilterPlugin> i = pluginsIterator(); *i; ++i)
+ list.append((*i)->name());
+ return list;
+}
+
+void KURIFilter::loadPlugins()
+{
+ KTrader::OfferList offers = KTrader::self()->query( "KURIFilter/Plugin" );
+
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+
+ for (; it != end; ++it )
+ {
+ KURIFilterPlugin *plugin = KParts::ComponentFactory::createInstanceFromService<KURIFilterPlugin>( *it, 0, (*it)->desktopEntryName().latin1() );
+ if ( plugin )
+ m_lstPlugins.append( plugin );
+ }
+
+ // NOTE: Plugin priority is now determined by
+ // the entry in the .desktop files...
+ // TODO: Config dialog to differentiate "system"
+ // plugins from "user-defined" ones...
+ // m_lstPlugins.sort();
+}
+
+void KURIFilterPlugin::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kurifilter.moc"
diff --git a/tdeio/tdeio/kurifilter.h b/tdeio/tdeio/kurifilter.h
new file mode 100644
index 000000000..fd7cb9b3c
--- /dev/null
+++ b/tdeio/tdeio/kurifilter.h
@@ -0,0 +1,667 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2001,2003 Dawit Alemayehu <adawit at kde.org>
+ *
+ * Original author
+ * Copyright (C) 2000 Yves Arrouye <yves@realnames.com>
+ *
+ *
+ * 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 __kurifilter_h__
+#define __kurifilter_h__
+
+#include <tqptrlist.h>
+#include <tqobject.h>
+#include <tqstringlist.h>
+#include <tqpixmap.h>
+
+#include <kurl.h>
+
+#ifdef Q_OS_WIN
+#undef ERROR
+#endif
+
+class KURIFilterPrivate;
+class KURIFilterDataPrivate;
+
+class TDECModule;
+
+/**
+* A basic message object used for exchanging filtering
+* information between the filter plugins and the application
+* requesting the filtering service.
+*
+* Use this object if you require a more detailed information
+* about the URI you want to filter. Any application can create
+* an instance of this class and send it to KURIFilter to
+* have the plugins fill out all possible information about the
+* URI.
+*
+* \b Example
+*
+* \code
+* TQString text = "kde.org";
+* KURIFilterData d = text;
+* bool filtered = KURIFilter::self()->filter( d );
+* cout << "URL: " << text.latin1() << endl
+* << "Filtered URL: " << d.uri().url().latin1() << endl
+* << "URI Type: " << d.uriType() << endl
+* << "Was Filtered: " << filtered << endl;
+* \endcode
+*
+* The above code should yield the following output:
+* \code
+* URI: kde.org
+* Filtered URI: http://kde.org
+* URI Type: 0 <== means NET_PROTOCOL
+* Was Filtered: 1 <== means the URL was successfully filtered
+* \endcode
+*
+* @short A message object for exchanging filtering URI info.
+* @author Dawit Alemayehu <adawit at kde.org>
+*/
+
+class TDEIO_EXPORT KURIFilterData
+{
+friend class KURIFilterPlugin;
+
+public:
+ /**
+ * Describes the type of the URI that was filtered.
+ * Here is a brief description of the types:
+ *
+ * @li NET_PROTOCOL - Any network protocol: http, ftp, nttp, pop3, etc...
+ * @li LOCAL_FILE - A local file whose executable flag is not set
+ * @li LOCAL_DIR - A local directory
+ * @li EXECUTABLE - A local file whose executable flag is set
+ * @li HELP - A man or info page
+ * @li SHELL - A shell executable (ex: echo "Test..." >> ~/testfile)
+ * @li BLOCKED - A URI that should be blocked/filtered (ex: ad filtering)
+ * @li ERROR - An incorrect URI (ex: "~johndoe" when user johndoe
+ * does not exist in that system )
+ * @li UNKNOWN - A URI that is not identified. Default value when
+ * a KURIFilterData is first created.
+ */
+ enum URITypes { NET_PROTOCOL=0, LOCAL_FILE, LOCAL_DIR, EXECUTABLE, HELP, SHELL, BLOCKED, ERROR, UNKNOWN };
+
+ /**
+ * Default constructor.
+ *
+ * Creates a URIFilterData object.
+ */
+ KURIFilterData() { init(); }
+
+ /**
+ * Creates a URIFilterData object from the given URL.
+ *
+ * @param url is the URL to be filtered.
+ */
+ KURIFilterData( const KURL& url ) { init( url); }
+
+ /**
+ * Creates a URIFilterData object from the given string.
+ *
+ * @param url is the string to be filtered.
+ */
+ KURIFilterData( const TQString& url ) { init( url ); }
+
+ /**
+ * Copy constructor.
+ *
+ * Creates a URIFilterData object from another
+ * URI filter data object.
+ *
+ * @param data the uri filter data to be copied.
+ */
+ KURIFilterData( const KURIFilterData& data);
+
+ /**
+ * Destructor.
+ */
+ ~KURIFilterData();
+
+ /**
+ * This method has been deprecated and will always return
+ * true. You should instead use the result from the
+ * KURIFilter::filterURI() calls.
+ *
+ * @deprecated
+ */
+ KDE_DEPRECATED bool hasBeenFiltered() const { return true; }
+
+ /**
+ * Returns the filtered or the original URL.
+ *
+ * This function returns the filtered url if one
+ * of the plugins successfully filtered the original
+ * URL. Otherwise, it returns the original URL.
+ * See hasBeenFiltered() and
+ *
+ * @return the filtered or original url.
+ */
+ KURL uri() const { return m_pURI; }
+
+ /**
+ * Returns an error message.
+ *
+ * This functions returns the error message set
+ * by the plugin whenever the uri type is set to
+ * KURIFilterData::ERROR. Otherwise, it returns
+ * a TQString::null.
+ *
+ * @return the error message or a NULL when there is none.
+ */
+ TQString errorMsg() const { return m_strErrMsg; }
+
+ /**
+ * Returns the URI type.
+ *
+ * This method always returns KURIFilterData::UNKNOWN
+ * if the given URL was not filtered.
+ * @return the type of the URI
+ */
+ URITypes uriType() const { return m_iType; }
+
+ /**
+ * Sets the URL to be filtered.
+ *
+ * Use this function to set the string to be
+ * filtered when you construct an empty filter
+ * object.
+ *
+ * @param url the string to be filtered.
+ */
+ void setData( const TQString& url ) { reinit( url ); }
+
+ /**
+ * Same as above except the argument is a URL.
+ *
+ * Use this function to set the string to be
+ * filtered when you construct an empty filter
+ * object.
+ *
+ * @param url the URL to be filtered.
+ */
+ void setData( const KURL& url ) { reinit( url ); }
+
+ /**
+ * Sets the absolute path to be used whenever the supplied
+ * data is a relative local URL.
+ *
+ * NOTE: This function should only be used for local resources,
+ * i.e. the "file:/" protocol. It is useful for specifying the
+ * absolute path in cases where the actual URL might be relative.
+ * meta object. If deriving the path from a KURL, make sure you
+ * set the argument for this function to the result of calling
+ * path () instead of url ().
+ *
+ * @param abs_path the abolute path to the local resource.
+ * @return true if absolute path is successfully set. Otherwise, false.
+ */
+ bool setAbsolutePath( const TQString& abs_path );
+
+ /**
+ * Returns the absolute path if one has already been set.
+ * @return the absolute path, or TQString::null
+ * @see hasAbsolutePath()
+ */
+ TQString absolutePath() const;
+
+ /**
+ * Checks whether the supplied data had an absolute path.
+ * @return true if the supplied data has an absolute path
+ * @see absolutePath()
+ */
+ bool hasAbsolutePath() const;
+
+ /**
+ * Returns the command line options and arguments for a
+ * local resource when present.
+ *
+ * @return options and arguments when present, otherwise TQString::null
+ */
+ TQString argsAndOptions() const;
+
+ /**
+ * Checks whether the current data is a local resource with
+ * command line options and arguments.
+ * @return true if the current data has command line options and arguments
+ */
+ bool hasArgsAndOptions() const;
+
+ /**
+ * Returns the name of the icon that matches
+ * the current filtered URL.
+ *
+ * NOTE that this function will return a NULL
+ * string by default and when no associated icon
+ * is found.
+ *
+ * @return the name of the icon associated with the resource,
+ * or TQString::null if not found
+ */
+ TQString iconName();
+
+ /**
+ * Returns the current custom icon
+ * The results are valid iff iconName() has
+ * returned TQString::null
+ *
+ * @return a pixmap with the current custom icon,
+ * or a null pixmap if no icon is available
+ */
+ TQPixmap customIconPixmap();
+
+ /**
+ * Check whether the provided uri is executable or not.
+ *
+ * Setting this to false ensures that typing the name of
+ * an executable does not start that application. This is
+ * useful in the location bar of a browser. The default
+ * value is true.
+ *
+ * @since 3.2
+ */
+ void setCheckForExecutables (bool check);
+
+ /**
+ * @return true if the filters should attempt to check whether the
+ * supplied uri is an executable. False otherwise.
+ *
+ * @since 3.2
+ */
+ bool checkForExecutables() const { return m_bCheckForExecutables; }
+
+ /**
+ * @return the string as typed by the user, before any URL processing is done
+ * @since 3.2
+ */
+ TQString typedString() const;
+
+ /**
+ * Overloaded assigenment operator.
+ *
+ * This function allows you to easily assign a KURL
+ * to a KURIFilterData object.
+ *
+ * @return an instance of a KURIFilterData object.
+ */
+ KURIFilterData& operator=( const KURL& url ) { reinit( url ); return *this; }
+
+ /**
+ * Overloaded assigenment operator.
+ *
+ * This function allows you to easily assign a QString
+ * to a KURIFilterData object.
+ *
+ * @return an instance of a KURIFilterData object.
+ */
+ KURIFilterData& operator=( const TQString& url ) { reinit( url ); return *this; }
+
+protected:
+
+ /**
+ * Initializes the KURIFilterData on construction.
+ * @param url the URL to initialize the object with
+ */
+ void init( const KURL& url);
+
+ /**
+ * Initializes the KURIFilterData on construction.
+ * @param url the URL to initialize the object with
+ */
+ void init( const TQString& url = TQString::null );
+
+private:
+
+ // BC hack to avoid leaking KURIFilterDataPrivate objects.
+ // setData() and operator= used to call init() without deleting `d'
+ void reinit(const KURL& url);
+ void reinit(const TQString& url = TQString::null);
+
+ bool m_bCheckForExecutables;
+ bool m_bChanged;
+
+ TQString m_strErrMsg;
+ TQString m_strIconName;
+
+ KURL m_pURI;
+ URITypes m_iType;
+ KURIFilterDataPrivate *d;
+
+ TQPixmap m_customIconPixmap;
+};
+
+
+/**
+ * Base class for URI filter plugins.
+ *
+ * This class applies a single filter to a URI. All plugins designed
+ * to provide URI filtering service should inherit from this abstract
+ * class and provide a concrete implementation.
+ *
+ * All inheriting classes need to implement the pure virtual function
+ * filterURI.
+ *
+ * @short Abstract class for URI filter plugins.
+ */
+class TDEIO_EXPORT KURIFilterPlugin : public TQObject
+{
+ Q_OBJECT
+
+
+public:
+
+ /**
+ * Constructs a filter plugin with a given name and
+ * priority.
+ *
+ * @param parent the parent object, or 0 for no parent
+ * @param name the name of the plugin, or 0 for no name
+ * @param pri the priority of the plugin.
+ */
+ KURIFilterPlugin( TQObject *parent = 0, const char *name = 0, double pri = 1.0 );
+
+ /**
+ * Returns the filter's name.
+ *
+ * @return A string naming the filter.
+ */
+ virtual TQString name() const { return m_strName; }
+
+ /**
+ * Returns the filter's priority.
+ *
+ * Each filter has an assigned priority, a float from 0 to 1. Filters
+ * with the lowest priority are first given a chance to filter a URI.
+ *
+ * @return The priority of the filter.
+ */
+ virtual double priority() const { return m_dblPriority; }
+
+ /**
+ * Filters a URI.
+ *
+ * @param data the URI data to be filtered.
+ * @return A boolean indicating whether the URI has been changed.
+ */
+ virtual bool filterURI( KURIFilterData& data ) const = 0;
+
+ /**
+ * Creates a configuration module for the filter.
+ *
+ * It is the responsibility of the caller to delete the module
+ * once it is not needed anymore.
+ *
+ * @return A configuration module, 0 if the filter isn't configurable.
+ */
+ virtual TDECModule *configModule( TQWidget*, const char* ) const { return 0; }
+
+ /**
+ * Returns the name of the configuration module for the filter.
+ *
+ * @return the name of a configuration module or TQString::null if none.
+ */
+ virtual TQString configName() const { return name(); }
+
+protected:
+
+ /**
+ * Sets the the URL in @p data to @p uri.
+ */
+ void setFilteredURI ( KURIFilterData& data, const KURL& uri ) const;
+
+ /**
+ * Sets the error message in @p data to @p errormsg.
+ */
+ void setErrorMsg ( KURIFilterData& data, const TQString& errmsg ) const {
+ data.m_strErrMsg = errmsg;
+ }
+
+ /**
+ * Sets the URI type in @p data to @p type.
+ */
+ void setURIType ( KURIFilterData& data, KURIFilterData::URITypes type) const {
+ data.m_iType = type;
+ data.m_bChanged = true;
+ }
+
+ /**
+ * Sets the arguments and options string in @p data
+ * to @p args if any were found during filterting.
+ */
+ void setArguments( KURIFilterData& data, const TQString& args ) const;
+
+ TQString m_strName;
+ double m_dblPriority;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KURIFilterPluginPrivate *d;
+};
+
+
+/**
+ * A list of filter plugins.
+ */
+class TDEIO_EXPORT KURIFilterPluginList : public TQPtrList<KURIFilterPlugin>
+{
+public:
+ virtual int compareItems(Item a, Item b)
+ {
+ double diff = ((KURIFilterPlugin *) a)->priority() - ((KURIFilterPlugin *) b)->priority();
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
+ }
+
+private:
+ KURIFilterPrivate *d;
+
+};
+
+/**
+ * Manages the filtering of URIs.
+ *
+ * The intention of this plugin class is to allow people to extend the
+ * functionality of KURL without modifying it directly. This way KURL will
+ * remain a generic parser capable of parsing any generic URL that adheres
+ * to specifications.
+ *
+ * The KURIFilter class applies a number of filters to a URI and returns the
+ * filtered version whenever possible. The filters are implemented using
+ * plugins to provide easy extensibility of the filtering mechanism. New
+ * filters can be added in the future by simply inheriting from
+ * KURIFilterPlugin and implementing the KURIFilterPlugin::filterURI
+ * method.
+ *
+ * Use of this plugin-manager class is straight forward. Since it is a
+ * singleton object, all you have to do is obtain an instance by doing
+ * @p KURIFilter::self() and use any of the public member functions to
+ * preform the filtering.
+ *
+ * \b Example
+ *
+ * To simply filter a given string:
+ *
+ * \code
+ * bool filtered = KURIFilter::self()->filterURI( "kde.org" );
+ * \endcode
+ *
+ * You can alternatively use a KURL:
+ *
+ * \code
+ * KURL url = "kde.org";
+ * bool filtered = KURIFilter::self()->filterURI( url );
+ * \endcode
+ *
+ * If you have a constant string or a constant URL, simply invoke the
+ * corresponding function to obtain the filtered string or URL instead
+ * of a boolean flag:
+ *
+ * \code
+ * TQString u = KURIFilter::self()->filteredURI( "kde.org" );
+ * \endcode
+ *
+ * You can also restrict the filter(s) to be used by supplying
+ * the name of the filter(s) to use. By defualt all available
+ * filters will be used. To use specific filters, add the names
+ * of the filters you want to use to a TQStringList and invoke
+ * the appropriate filtering function. The examples below show
+ * the use of specific filters. The first one uses a single
+ * filter called kshorturifilter while the second example uses
+ * multiple filters:
+ *
+ * \code
+ * TQString text = "kde.org";
+ * bool filtered = KURIFilter::self()->filterURI( text, "kshorturifilter" );
+ * \endcode
+ *
+ * \code
+ * TQStringList list;
+ * list << "kshorturifilter" << "localdomainfilter";
+ * bool filtered = KURIFilter::self()->filterURI( text, list );
+ * \endcode
+ *
+ * KURIFilter also allows richer data exchange through a simple
+ * meta-object called @p KURIFilterData. Using this meta-object
+ * you can find out more information about the URL you want to
+ * filter. See KURIFilterData for examples and details.
+ *
+ * @short Filters a given URL into its proper format whenever possible.
+ */
+
+class TDEIO_EXPORT KURIFilter
+{
+public:
+ /**
+ * Destructor
+ */
+ ~KURIFilter ();
+
+ /**
+ * Returns an instance of KURIFilter.
+ */
+ static KURIFilter* self();
+
+ /**
+ * Filters the URI given by the object URIFilterData.
+ *
+ * The given URL is filtered based on the specified list of filters.
+ * If the list is empty all available filters would be used.
+ *
+ * @param data object that contains the URI to be filtered.
+ * @param filters specify the list of filters to be used.
+ *
+ * @return a boolean indicating whether the URI has been changed
+ */
+ bool filterURI( KURIFilterData& data, const TQStringList& filters = TQStringList() );
+
+ /**
+ * Filters the URI given by the URL.
+ *
+ * The given URL is filtered based on the specified list of filters.
+ * If the list is empty all available filters would be used.
+ *
+ * @param uri the URI to filter.
+ * @param filters specify the list of filters to be used.
+ *
+ * @return a boolean indicating whether the URI has been changed
+ */
+ bool filterURI( KURL &uri, const TQStringList& filters = TQStringList() );
+
+ /**
+ * Filters a string representing a URI.
+ *
+ * The given URL is filtered based on the specified list of filters.
+ * If the list is empty all available filters would be used.
+ *
+ * @param uri The URI to filter.
+ * @param filters specify the list of filters to be used.
+ *
+ * @return a boolean indicating whether the URI has been changed
+ */
+ bool filterURI( TQString &uri, const TQStringList& filters = TQStringList() );
+
+ /**
+ * Returns the filtered URI.
+ *
+ * The given URL is filtered based on the specified list of filters.
+ * If the list is empty all available filters would be used.
+ *
+ * @param uri The URI to filter.
+ * @param filters specify the list of filters to be used.
+ *
+ * @return the filtered URI or null if it cannot be filtered
+ */
+ KURL filteredURI( const KURL &uri, const TQStringList& filters = TQStringList() );
+
+ /**
+ * Return a filtered string representation of a URI.
+ *
+ * The given URL is filtered based on the specified list of filters.
+ * If the list is empty all available filters would be used.
+ *
+ * @param uri the URI to filter.
+ * @param filters specify the list of filters to be used.
+ *
+ * @return the filtered URI or null if it cannot be filtered
+ */
+ TQString filteredURI( const TQString &uri, const TQStringList& filters = TQStringList() );
+
+ /**
+ * Return an iterator to iterate over all loaded
+ * plugins.
+ *
+ * @return a plugin iterator.
+ */
+ TQPtrListIterator<KURIFilterPlugin> pluginsIterator() const;
+
+ /**
+ * Return a list of the names of all loaded plugins.
+ *
+ * @return a TQStringList of plugin names
+ * @since 3.1
+ */
+ TQStringList pluginNames() const;
+
+protected:
+
+ /**
+ * A protected constructor.
+ *
+ * This constructor creates a KURIFilter and
+ * initializes all plugins it can find by invoking
+ * loadPlugins.
+ */
+ KURIFilter();
+
+ /**
+ * Loads all allowed plugins.
+ *
+ * This function loads all filters that have not
+ * been disbled.
+ */
+ void loadPlugins();
+
+private:
+ static KURIFilter *s_self;
+ KURIFilterPluginList m_lstPlugins;
+ KURIFilterPrivate *d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kurlcompletion.cpp b/tdeio/tdeio/kurlcompletion.cpp
new file mode 100644
index 000000000..22bbe147a
--- /dev/null
+++ b/tdeio/tdeio/kurlcompletion.cpp
@@ -0,0 +1,1604 @@
+/* -*- indent-tabs-mode: t; tab-width: 4; c-basic-offset:4 -*-
+
+ This file is part of the KDE libraries
+ Copyright (C) 2000 David Smith <dsmith@algonet.se>
+ Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
+
+ This class was inspired by a previous KURLCompletion by
+ Henner Zeller <zeller@think.de>
+
+ 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 <config.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqvaluelist.h>
+#include <tqregexp.h>
+#include <tqtimer.h>
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <tqdeepcopy.h>
+#include <tqthread.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kcompletion.h>
+#include <kurl.h>
+#include <tdeio/jobclasses.h>
+#include <tdeio/job.h>
+#include <kprotocolinfo.h>
+#include <tdeconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kde_file.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <time.h>
+#include <sys/param.h>
+
+#include "kurlcompletion.h"
+
+static bool expandTilde(TQString &);
+static bool expandEnv(TQString &);
+
+static TQString unescape(const TQString &text);
+
+// Permission mask for files that are executable by
+// user, group or other
+#define MODE_EXE (S_IXUSR | S_IXGRP | S_IXOTH)
+
+// Constants for types of completion
+enum ComplType {CTNone=0, CTEnv, CTUser, CTMan, CTExe, CTFile, CTUrl, CTInfo};
+
+class CompletionThread;
+
+/**
+ * A custom event type that is used to return a list of completion
+ * matches from an asyncrynous lookup.
+ */
+
+class CompletionMatchEvent : public TQCustomEvent
+{
+public:
+ CompletionMatchEvent( CompletionThread *thread ) :
+ TQCustomEvent( uniqueType() ),
+ m_completionThread( thread )
+ {}
+
+ CompletionThread *completionThread() const { return m_completionThread; }
+ static int uniqueType() { return User + 61080; }
+
+private:
+ CompletionThread *m_completionThread;
+};
+
+class CompletionThread : public TQThread
+{
+protected:
+ CompletionThread( KURLCompletion *receiver ) :
+ TQThread(),
+ m_receiver( receiver ),
+ m_terminationRequested( false )
+ {}
+
+public:
+ void requestTermination() { m_terminationRequested = true; }
+ TQDeepCopy<TQStringList> matches() const { return m_matches; }
+
+protected:
+ void addMatch( const TQString &match ) { m_matches.append( match ); }
+ bool terminationRequested() const { return m_terminationRequested; }
+ void done()
+ {
+ if ( !m_terminationRequested )
+ kapp->postEvent( m_receiver, new CompletionMatchEvent( this ) );
+ else
+ delete this;
+ }
+
+private:
+ KURLCompletion *m_receiver;
+ TQStringList m_matches;
+ bool m_terminationRequested;
+};
+
+/**
+ * A simple thread that fetches a list of tilde-completions and returns this
+ * to the caller via a CompletionMatchEvent.
+ */
+
+class UserListThread : public CompletionThread
+{
+public:
+ UserListThread( KURLCompletion *receiver ) :
+ CompletionThread( receiver )
+ {}
+
+protected:
+ virtual void run()
+ {
+ static const TQChar tilde = '~';
+
+ struct passwd *pw;
+ while ( ( pw = ::getpwent() ) && !terminationRequested() )
+ addMatch( tilde + TQString::fromLocal8Bit( pw->pw_name ) );
+
+ ::endpwent();
+
+ addMatch( tilde );
+
+ done();
+ }
+};
+
+class DirectoryListThread : public CompletionThread
+{
+public:
+ DirectoryListThread( KURLCompletion *receiver,
+ const TQStringList &dirList,
+ const TQString &filter,
+ bool onlyExe,
+ bool onlyDir,
+ bool noHidden,
+ bool appendSlashToDir ) :
+ CompletionThread( receiver ),
+ m_dirList( TQDeepCopy<TQStringList>( dirList ) ),
+ m_filter( TQDeepCopy<TQString>( filter ) ),
+ m_onlyExe( onlyExe ),
+ m_onlyDir( onlyDir ),
+ m_noHidden( noHidden ),
+ m_appendSlashToDir( appendSlashToDir )
+ {}
+
+ virtual void run();
+
+private:
+ TQStringList m_dirList;
+ TQString m_filter;
+ bool m_onlyExe;
+ bool m_onlyDir;
+ bool m_noHidden;
+ bool m_appendSlashToDir;
+};
+
+void DirectoryListThread::run()
+{
+ // Thread safety notes:
+ //
+ // There very possibly may be thread safety issues here, but I've done a check
+ // of all of the things that would seem to be problematic. Here are a few
+ // things that I have checked to be safe here (some used indirectly):
+ //
+ // TQDir::currentDirPath(), TQDir::setCurrent(), TQFile::decodeName(), TQFile::encodeName()
+ // TQString::fromLocal8Bit(), TQString::local8Bit(), TQTextCodec::codecForLocale()
+ //
+ // Also see (for POSIX functions):
+ // http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html
+
+ DIR *dir = 0;
+
+ for ( TQStringList::ConstIterator it = m_dirList.begin();
+ it != m_dirList.end() && !terminationRequested();
+ ++it )
+ {
+ // Open the next directory
+
+ if ( !dir ) {
+ dir = ::opendir( TQFile::encodeName( *it ) );
+ if ( ! dir ) {
+ kdDebug() << "Failed to open dir: " << *it << endl;
+ done();
+ return;
+ }
+ }
+
+ // A trick from KIO that helps performance by a little bit:
+ // chdir to the directroy so we won't have to deal with full paths
+ // with stat()
+
+ TQString path = TQDir::currentDirPath();
+ TQDir::setCurrent( *it );
+
+ // Loop through all directory entries
+ // Solaris and IRIX dirent structures do not allocate space for d_name. On
+ // systems that do (HP-UX, Linux, Tru64 UNIX), we overallocate space but
+ // that's ok.
+#ifndef HAVE_READDIR_R
+ struct dirent *dirEntry = 0;
+ while ( !terminationRequested() &&
+ (dirEntry = ::readdir( dir)))
+#else
+#if !defined(MAXPATHLEN) && defined(__GNU__)
+#define MAXPATHLEN UCHAR_MAX
+#endif
+ struct dirent *dirPosition = (struct dirent *) malloc( sizeof( struct dirent ) + MAXPATHLEN + 1 );
+ struct dirent *dirEntry = 0;
+ while ( !terminationRequested() &&
+ ::readdir_r( dir, dirPosition, &dirEntry ) == 0 && dirEntry )
+#endif
+
+ {
+ // Skip hidden files if m_noHidden is true
+
+ if ( dirEntry->d_name[0] == '.' && m_noHidden )
+ continue;
+
+ // Skip "."
+
+ if ( dirEntry->d_name[0] == '.' && dirEntry->d_name[1] == '\0' )
+ continue;
+
+ // Skip ".."
+
+ if ( dirEntry->d_name[0] == '.' && dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0' )
+ continue;
+
+ TQString file = TQFile::decodeName( dirEntry->d_name );
+
+ if ( m_filter.isEmpty() || file.startsWith( m_filter ) ) {
+
+ if ( m_onlyExe || m_onlyDir || m_appendSlashToDir ) {
+ KDE_struct_stat sbuff;
+
+ if ( KDE_stat( dirEntry->d_name, &sbuff ) == 0 ) {
+
+ // Verify executable
+
+ if ( m_onlyExe && ( sbuff.st_mode & MODE_EXE ) == 0 )
+ continue;
+
+ // Verify directory
+
+ if ( m_onlyDir && !S_ISDIR( sbuff.st_mode ) )
+ continue;
+
+ // Add '/' to directories
+
+ if ( m_appendSlashToDir && S_ISDIR( sbuff.st_mode ) )
+ file.append( '/' );
+
+ }
+ else {
+ kdDebug() << "Could not stat file " << file << endl;
+ continue;
+ }
+ }
+
+ addMatch( file );
+ }
+ }
+
+ // chdir to the original directory
+
+ TQDir::setCurrent( path );
+
+ ::closedir( dir );
+ dir = 0;
+#ifdef HAVE_READDIR_R
+ free( dirPosition );
+#endif
+ }
+
+ done();
+}
+
+///////////////////////////////////////////////////////
+///////////////////////////////////////////////////////
+// MyURL - wrapper for KURL with some different functionality
+//
+
+class KURLCompletion::MyURL
+{
+public:
+ MyURL(const TQString &url, const TQString &cwd);
+ MyURL(const MyURL &url);
+ ~MyURL();
+
+ KURL *kurl() const { return m_kurl; }
+
+ TQString protocol() const { return m_kurl->protocol(); }
+ // The directory with a trailing '/'
+ TQString dir() const { return m_kurl->directory(false, false); }
+ TQString file() const { return m_kurl->fileName(false); }
+
+ // The initial, unparsed, url, as a string.
+ TQString url() const { return m_url; }
+
+ // Is the initial string a URL, or just a path (whether absolute or relative)
+ bool isURL() const { return m_isURL; }
+
+ void filter( bool replace_user_dir, bool replace_env );
+
+private:
+ void init(const TQString &url, const TQString &cwd);
+
+ KURL *m_kurl;
+ TQString m_url;
+ bool m_isURL;
+};
+
+KURLCompletion::MyURL::MyURL(const TQString &url, const TQString &cwd)
+{
+ init(url, cwd);
+}
+
+KURLCompletion::MyURL::MyURL(const MyURL &url)
+{
+ m_kurl = new KURL( *(url.m_kurl) );
+ m_url = url.m_url;
+ m_isURL = url.m_isURL;
+}
+
+void KURLCompletion::MyURL::init(const TQString &url, const TQString &cwd)
+{
+ // Save the original text
+ m_url = url;
+
+ // Non-const copy
+ TQString url_copy = url;
+
+ // Special shortcuts for "man:" and "info:"
+ if ( url_copy[0] == '#' ) {
+ if ( url_copy[1] == '#' )
+ url_copy.replace( 0, 2, TQString("info:") );
+ else
+ url_copy.replace( 0, 1, TQString("man:") );
+ }
+
+ // Look for a protocol in 'url'
+ TQRegExp protocol_regex = TQRegExp( "^[^/\\s\\\\]*:" );
+
+ // Assume "file:" or whatever is given by 'cwd' if there is
+ // no protocol. (KURL does this only for absoute paths)
+ if ( protocol_regex.search( url_copy ) == 0 )
+ {
+ m_kurl = new KURL( url_copy );
+ m_isURL = true;
+ }
+ else // relative path or ~ or $something
+ {
+ m_isURL = false;
+ if ( cwd.isEmpty() )
+ {
+ m_kurl = new KURL();
+ if ( !TQDir::isRelativePath(url_copy) || url_copy[0] == '$' || url_copy[0] == '~' )
+ m_kurl->setPath( url_copy );
+ else
+ *m_kurl = url_copy;
+ }
+ else
+ {
+ KURL base = KURL::fromPathOrURL( cwd );
+ base.adjustPath(+1);
+
+ if ( !TQDir::isRelativePath(url_copy) || url_copy[0] == '~' || url_copy[0] == '$' )
+ {
+ m_kurl = new KURL();
+ m_kurl->setPath( url_copy );
+ }
+ else // relative path
+ {
+ //m_kurl = new KURL( base, url_copy );
+ m_kurl = new KURL( base );
+ m_kurl->addPath( url_copy );
+ }
+ }
+ }
+}
+
+KURLCompletion::MyURL::~MyURL()
+{
+ delete m_kurl;
+}
+
+void KURLCompletion::MyURL::filter( bool replace_user_dir, bool replace_env )
+{
+ TQString d = dir() + file();
+ if ( replace_user_dir ) expandTilde( d );
+ if ( replace_env ) expandEnv( d );
+ m_kurl->setPath( d );
+}
+
+///////////////////////////////////////////////////////
+///////////////////////////////////////////////////////
+// KURLCompletionPrivate
+//
+class KURLCompletionPrivate
+{
+public:
+ KURLCompletionPrivate() : url_auto_completion(true),
+ userListThread(0),
+ dirListThread(0) {}
+ ~KURLCompletionPrivate();
+
+ TQValueList<KURL*> list_urls;
+
+ bool onlyLocalProto;
+
+ // urlCompletion() in Auto/Popup mode?
+ bool url_auto_completion;
+
+ // Append '/' to directories in Popup mode?
+ // Doing that stat's all files and is slower
+ bool popup_append_slash;
+
+ // Keep track of currently listed files to avoid reading them again
+ TQString last_path_listed;
+ TQString last_file_listed;
+ TQString last_prepend;
+ int last_compl_type;
+ int last_no_hidden;
+
+ TQString cwd; // "current directory" = base dir for completion
+
+ KURLCompletion::Mode mode; // ExeCompletion, FileCompletion, DirCompletion
+ bool replace_env;
+ bool replace_home;
+ bool complete_url; // if true completing a URL (i.e. 'prepend' is a URL), otherwise a path
+
+ TDEIO::ListJob *list_job; // kio job to list directories
+
+ TQString prepend; // text to prepend to listed items
+ TQString compl_text; // text to pass on to KCompletion
+
+ // Filters for files read with kio
+ bool list_urls_only_exe; // true = only list executables
+ bool list_urls_no_hidden;
+ TQString list_urls_filter; // filter for listed files
+
+ CompletionThread *userListThread;
+ CompletionThread *dirListThread;
+};
+
+KURLCompletionPrivate::~KURLCompletionPrivate()
+{
+ if ( userListThread )
+ userListThread->requestTermination();
+ if ( dirListThread )
+ dirListThread->requestTermination();
+}
+
+///////////////////////////////////////////////////////
+///////////////////////////////////////////////////////
+// KURLCompletion
+//
+
+KURLCompletion::KURLCompletion() : KCompletion()
+{
+ init();
+}
+
+
+KURLCompletion::KURLCompletion( Mode mode ) : KCompletion()
+{
+ init();
+ setMode ( mode );
+}
+
+KURLCompletion::~KURLCompletion()
+{
+ stop();
+ delete d;
+}
+
+
+void KURLCompletion::init()
+{
+ d = new KURLCompletionPrivate;
+
+ d->cwd = TQDir::homeDirPath();
+
+ d->replace_home = true;
+ d->replace_env = true;
+ d->last_no_hidden = false;
+ d->last_compl_type = 0;
+ d->list_job = 0L;
+ d->mode = KURLCompletion::FileCompletion;
+
+ // Read settings
+ TDEConfig *c = TDEGlobal::config();
+ TDEConfigGroupSaver cgs( c, "URLCompletion" );
+
+ d->url_auto_completion = c->readBoolEntry("alwaysAutoComplete", true);
+ d->popup_append_slash = c->readBoolEntry("popupAppendSlash", true);
+ d->onlyLocalProto = c->readBoolEntry("LocalProtocolsOnly", false);
+}
+
+void KURLCompletion::setDir(const TQString &dir)
+{
+ d->cwd = dir;
+}
+
+TQString KURLCompletion::dir() const
+{
+ return d->cwd;
+}
+
+KURLCompletion::Mode KURLCompletion::mode() const
+{
+ return d->mode;
+}
+
+void KURLCompletion::setMode( Mode mode )
+{
+ d->mode = mode;
+}
+
+bool KURLCompletion::replaceEnv() const
+{
+ return d->replace_env;
+}
+
+void KURLCompletion::setReplaceEnv( bool replace )
+{
+ d->replace_env = replace;
+}
+
+bool KURLCompletion::replaceHome() const
+{
+ return d->replace_home;
+}
+
+void KURLCompletion::setReplaceHome( bool replace )
+{
+ d->replace_home = replace;
+}
+
+/*
+ * makeCompletion()
+ *
+ * Entry point for file name completion
+ */
+TQString KURLCompletion::makeCompletion(const TQString &text)
+{
+ //kdDebug() << "KURLCompletion::makeCompletion: " << text << " d->cwd=" << d->cwd << endl;
+
+ MyURL url(text, d->cwd);
+
+ d->compl_text = text;
+
+ // Set d->prepend to the original URL, with the filename [and ref/query] stripped.
+ // This is what gets prepended to the directory-listing matches.
+ int toRemove = url.file().length() - url.kurl()->query().length();
+ if ( url.kurl()->hasRef() )
+ toRemove += url.kurl()->ref().length() + 1;
+ d->prepend = text.left( text.length() - toRemove );
+ d->complete_url = url.isURL();
+
+ TQString match;
+
+ // Environment variables
+ //
+ if ( d->replace_env && envCompletion( url, &match ) )
+ return match;
+
+ // User directories
+ //
+ if ( d->replace_home && userCompletion( url, &match ) )
+ return match;
+
+ // Replace user directories and variables
+ url.filter( d->replace_home, d->replace_env );
+
+ //kdDebug() << "Filtered: proto=" << url.protocol()
+ // << ", dir=" << url.dir()
+ // << ", file=" << url.file()
+ // << ", kurl url=" << *url.kurl() << endl;
+
+ if ( d->mode == ExeCompletion ) {
+ // Executables
+ //
+ if ( exeCompletion( url, &match ) )
+ return match;
+
+ // KRun can run "man:" and "info:" etc. so why not treat them
+ // as executables...
+
+ if ( urlCompletion( url, &match ) )
+ return match;
+ }
+ else if ( d->mode == SystemExeCompletion ) {
+ // Executables
+ //
+ if ( systemexeCompletion( url, &match ) )
+ return match;
+
+ // KRun can run "man:" and "info:" etc. so why not treat them
+ // as executables...
+
+ if ( urlCompletion( url, &match ) )
+ return match;
+ }
+ else {
+ // Local files, directories
+ //
+ if ( fileCompletion( url, &match ) )
+ return match;
+
+ // All other...
+ //
+ if ( urlCompletion( url, &match ) )
+ return match;
+ }
+
+ setListedURL( CTNone );
+ stop();
+
+ return TQString::null;
+}
+
+/*
+ * finished
+ *
+ * Go on and call KCompletion.
+ * Called when all matches have been added
+ */
+TQString KURLCompletion::finished()
+{
+ if ( d->last_compl_type == CTInfo )
+ return KCompletion::makeCompletion( d->compl_text.lower() );
+ else
+ return KCompletion::makeCompletion( d->compl_text );
+}
+
+/*
+ * isRunning
+ *
+ * Return true if either a KIO job or the DirLister
+ * is running
+ */
+bool KURLCompletion::isRunning() const
+{
+ return d->list_job || (d->dirListThread && !d->dirListThread->finished());
+}
+
+/*
+ * stop
+ *
+ * Stop and delete a running KIO job or the DirLister
+ */
+void KURLCompletion::stop()
+{
+ if ( d->list_job ) {
+ d->list_job->kill();
+ d->list_job = 0L;
+ }
+
+ if ( !d->list_urls.isEmpty() ) {
+ TQValueList<KURL*>::Iterator it = d->list_urls.begin();
+ for ( ; it != d->list_urls.end(); it++ )
+ delete (*it);
+ d->list_urls.clear();
+ }
+
+ if ( d->dirListThread ) {
+ d->dirListThread->requestTermination();
+ d->dirListThread = 0;
+ }
+}
+
+/*
+ * Keep track of the last listed directory
+ */
+void KURLCompletion::setListedURL( int complType,
+ const TQString& dir,
+ const TQString& filter,
+ bool no_hidden )
+{
+ d->last_compl_type = complType;
+ d->last_path_listed = dir;
+ d->last_file_listed = filter;
+ d->last_no_hidden = (int)no_hidden;
+ d->last_prepend = d->prepend;
+}
+
+bool KURLCompletion::isListedURL( int complType,
+ const TQString& dir,
+ const TQString& filter,
+ bool no_hidden )
+{
+ return d->last_compl_type == complType
+ && ( d->last_path_listed == dir
+ || (dir.isEmpty() && d->last_path_listed.isEmpty()) )
+ && ( filter.startsWith(d->last_file_listed)
+ || (filter.isEmpty() && d->last_file_listed.isEmpty()) )
+ && d->last_no_hidden == (int)no_hidden
+ && d->last_prepend == d->prepend; // e.g. relative path vs absolute
+}
+
+/*
+ * isAutoCompletion
+ *
+ * Returns true if completion mode is Auto or Popup
+ */
+bool KURLCompletion::isAutoCompletion()
+{
+ return completionMode() == TDEGlobalSettings::CompletionAuto
+ || completionMode() == TDEGlobalSettings::CompletionPopup
+ || completionMode() == TDEGlobalSettings::CompletionMan
+ || completionMode() == TDEGlobalSettings::CompletionPopupAuto;
+}
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// User directories
+//
+
+bool KURLCompletion::userCompletion(const MyURL &url, TQString *match)
+{
+ if ( url.protocol() != "file"
+ || !url.dir().isEmpty()
+ || url.file().at(0) != '~' )
+ return false;
+
+ if ( !isListedURL( CTUser ) ) {
+ stop();
+ clear();
+
+ if ( !d->userListThread ) {
+ d->userListThread = new UserListThread( this );
+ d->userListThread->start();
+
+ // If the thread finishes quickly make sure that the results
+ // are added to the first matching case.
+
+ d->userListThread->wait( 200 );
+ TQStringList l = d->userListThread->matches();
+ addMatches( l );
+ }
+ }
+ *match = finished();
+ return true;
+}
+
+/////////////////////////////////////////////////////
+/////////////////////////////////////////////////////
+// Environment variables
+//
+
+extern char **environ; // Array of environment variables
+
+bool KURLCompletion::envCompletion(const MyURL &url, TQString *match)
+{
+ if ( url.file().at(0) != '$' )
+ return false;
+
+ if ( !isListedURL( CTEnv ) ) {
+ stop();
+ clear();
+
+ char **env = environ;
+
+ TQString dollar = TQString("$");
+
+ TQStringList l;
+
+ while ( *env ) {
+ TQString s = TQString::fromLocal8Bit( *env );
+
+ int pos = s.find('=');
+
+ if ( pos == -1 )
+ pos = s.length();
+
+ if ( pos > 0 )
+ l.append( dollar + s.left(pos) );
+
+ env++;
+ }
+
+ addMatches( l );
+ }
+
+ setListedURL( CTEnv );
+
+ *match = finished();
+ return true;
+}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// Executables
+//
+
+bool KURLCompletion::exeCompletion(const MyURL &url, TQString *match)
+{
+ if ( url.protocol() != "file" )
+ return false;
+
+ TQString dir = url.dir();
+
+ dir = unescape( dir ); // remove escapes
+
+ // Find directories to search for completions, either
+ //
+ // 1. complete path given in url
+ // 2. current directory (d->cwd)
+ // 3. $PATH
+ // 4. no directory at all
+
+ TQStringList dirList;
+
+ if ( !TQDir::isRelativePath(dir) ) {
+ // complete path in url
+ dirList.append( dir );
+ }
+ else if ( !dir.isEmpty() && !d->cwd.isEmpty() ) {
+ // current directory
+ dirList.append( d->cwd + '/' + dir );
+ }
+ else if ( !url.file().isEmpty() ) {
+ // $PATH
+ dirList = TQStringList::split(KPATH_SEPARATOR,
+ TQString::fromLocal8Bit(::getenv("PATH")));
+
+ TQStringList::Iterator it = dirList.begin();
+
+ for ( ; it != dirList.end(); it++ )
+ (*it).append('/');
+ }
+
+ // No hidden files unless the user types "."
+ bool no_hidden_files = url.file().at(0) != '.';
+
+ // List files if needed
+ //
+ if ( !isListedURL( CTExe, dir, url.file(), no_hidden_files ) )
+ {
+ stop();
+ clear();
+
+ setListedURL( CTExe, dir, url.file(), no_hidden_files );
+
+ *match = listDirectories( dirList, url.file(), true, false, no_hidden_files );
+ }
+ else if ( !isRunning() ) {
+ *match = finished();
+ }
+ else {
+ if ( d->dirListThread )
+ setListedURL( CTExe, dir, url.file(), no_hidden_files );
+ *match = TQString::null;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// System Executables
+//
+
+bool KURLCompletion::systemexeCompletion(const MyURL &url, TQString *match)
+{
+ if ( url.protocol() != "file" )
+ return false;
+
+ TQString dir = url.dir();
+
+ dir = unescape( dir ); // remove escapes
+
+ // Find directories to search for completions, either
+ //
+ // 1. complete path given in url
+ // 2. current directory (d->cwd)
+ // 3. $PATH
+ // 4. no directory at all
+
+ TQStringList dirList;
+
+ if ( !url.file().isEmpty() ) {
+ // $PATH
+ dirList = TQStringList::split(KPATH_SEPARATOR,
+ TQString::fromLocal8Bit(::getenv("PATH")));
+
+ TQStringList::Iterator it = dirList.begin();
+
+ for ( ; it != dirList.end(); it++ )
+ (*it).append('/');
+ }
+
+ // No hidden files unless the user types "."
+ bool no_hidden_files = url.file().at(0) != '.';
+
+ // List files if needed
+ //
+ if ( !isListedURL( CTExe, dir, url.file(), no_hidden_files ) )
+ {
+ stop();
+ clear();
+
+ setListedURL( CTExe, dir, url.file(), no_hidden_files );
+
+ *match = listDirectories( dirList, url.file(), true, false, no_hidden_files );
+ }
+ else if ( !isRunning() ) {
+ *match = finished();
+ }
+ else {
+ if ( d->dirListThread )
+ setListedURL( CTExe, dir, url.file(), no_hidden_files );
+ *match = TQString::null;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// Local files
+//
+
+bool KURLCompletion::fileCompletion(const MyURL &url, TQString *match)
+{
+ if ( url.protocol() != "file" )
+ return false;
+
+ TQString dir = url.dir();
+
+ if (url.url()[0] == '.')
+ {
+ if (url.url().length() == 1)
+ {
+ *match =
+ ( completionMode() == TDEGlobalSettings::CompletionMan )? "." : "..";
+ return true;
+ }
+ if (url.url().length() == 2 && url.url()[1]=='.')
+ {
+ *match="..";
+ return true;
+ }
+ }
+
+ //kdDebug() << "fileCompletion " << url.url() << " dir=" << dir << endl;
+
+ dir = unescape( dir ); // remove escapes
+
+ // Find directories to search for completions, either
+ //
+ // 1. complete path given in url
+ // 2. current directory (d->cwd)
+ // 3. no directory at all
+
+ TQStringList dirList;
+
+ if ( !TQDir::isRelativePath(dir) ) {
+ // complete path in url
+ dirList.append( dir );
+ }
+ else if ( !d->cwd.isEmpty() ) {
+ // current directory
+ dirList.append( d->cwd + '/' + dir );
+ }
+
+ // No hidden files unless the user types "."
+ bool no_hidden_files = ( url.file().at(0) != '.' );
+
+ // List files if needed
+ //
+ if ( !isListedURL( CTFile, dir, "", no_hidden_files ) )
+ {
+ stop();
+ clear();
+
+ setListedURL( CTFile, dir, "", no_hidden_files );
+
+ // Append '/' to directories in Popup mode?
+ bool append_slash = ( d->popup_append_slash
+ && (completionMode() == TDEGlobalSettings::CompletionPopup ||
+ completionMode() == TDEGlobalSettings::CompletionPopupAuto ) );
+
+ bool only_dir = ( d->mode == DirCompletion );
+
+ *match = listDirectories( dirList, "", false, only_dir, no_hidden_files,
+ append_slash );
+ }
+ else if ( !isRunning() ) {
+ *match = finished();
+ }
+ else {
+ *match = TQString::null;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// URLs not handled elsewhere...
+//
+
+bool KURLCompletion::urlCompletion(const MyURL &url, TQString *match)
+{
+ //kdDebug() << "urlCompletion: url = " << *url.kurl() << endl;
+ if (d->onlyLocalProto && KProtocolInfo::protocolClass(url.protocol()) != ":local")
+ return false;
+
+ // Use d->cwd as base url in case url is not absolute
+ KURL url_cwd = KURL::fromPathOrURL( d->cwd );
+
+ // Create an URL with the directory to be listed
+ KURL url_dir( url_cwd, url.kurl()->url() );
+
+ // Don't try url completion if
+ // 1. malformed url
+ // 2. protocol that doesn't have listDir()
+ // 3. there is no directory (e.g. "ftp://ftp.kd" shouldn't do anything)
+ // 4. auto or popup completion mode depending on settings
+
+ bool man_or_info = ( url_dir.protocol() == TQString("man")
+ || url_dir.protocol() == TQString("info") );
+
+ if ( !url_dir.isValid()
+ || !KProtocolInfo::supportsListing( url_dir )
+ || ( !man_or_info
+ && ( url_dir.directory(false,false).isEmpty()
+ || ( isAutoCompletion()
+ && !d->url_auto_completion ) ) ) ) {
+ return false;
+ }
+
+ url_dir.setFileName(""); // not really nesseccary, but clear the filename anyway...
+
+ // Remove escapes
+ TQString dir = url_dir.directory( false, false );
+
+ dir = unescape( dir );
+
+ url_dir.setPath( dir );
+
+ // List files if needed
+ //
+ if ( !isListedURL( CTUrl, url_dir.prettyURL(), url.file() ) )
+ {
+ stop();
+ clear();
+
+ setListedURL( CTUrl, url_dir.prettyURL(), "" );
+
+ TQValueList<KURL*> url_list;
+ url_list.append( new KURL( url_dir ) );
+
+ listURLs( url_list, "", false );
+
+ *match = TQString::null;
+ }
+ else if ( !isRunning() ) {
+ *match = finished();
+ }
+ else {
+ *match = TQString::null;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+// Directory and URL listing
+//
+
+/*
+ * addMatches
+ *
+ * Called to add matches to KCompletion
+ */
+void KURLCompletion::addMatches( const TQStringList &matches )
+{
+ TQStringList::ConstIterator it = matches.begin();
+ TQStringList::ConstIterator end = matches.end();
+
+ if ( d->complete_url )
+ for ( ; it != end; it++ )
+ addItem( d->prepend + KURL::encode_string(*it));
+ else
+ for ( ; it != end; it++ )
+ addItem( d->prepend + (*it));
+}
+
+/*
+ * listDirectories
+ *
+ * List files starting with 'filter' in the given directories,
+ * either using DirLister or listURLs()
+ *
+ * In either case, addMatches() is called with the listed
+ * files, and eventually finished() when the listing is done
+ *
+ * Returns the match if available, or TQString::null if
+ * DirLister timed out or using kio
+ */
+TQString KURLCompletion::listDirectories(
+ const TQStringList &dirList,
+ const TQString &filter,
+ bool only_exe,
+ bool only_dir,
+ bool no_hidden,
+ bool append_slash_to_dir)
+{
+ assert( !isRunning() );
+
+ if ( !::getenv("KURLCOMPLETION_LOCAL_KIO") ) {
+
+ //kdDebug() << "Listing (listDirectories): " << dirList << " filter=" << filter << " without KIO" << endl;
+
+ // Don't use KIO
+
+ if ( d->dirListThread )
+ d->dirListThread->requestTermination();
+
+ TQStringList dirs;
+
+ for ( TQStringList::ConstIterator it = dirList.begin();
+ it != dirList.end();
+ ++it )
+ {
+ KURL url;
+ url.setPath(*it);
+ if ( kapp->authorizeURLAction( "list", KURL(), url ) )
+ dirs.append( *it );
+ }
+
+ d->dirListThread = new DirectoryListThread( this, dirs, filter, only_exe, only_dir,
+ no_hidden, append_slash_to_dir );
+ d->dirListThread->start();
+ d->dirListThread->wait( 200 );
+ addMatches( d->dirListThread->matches() );
+
+ return finished();
+ }
+ else {
+
+ // Use KIO
+ //kdDebug() << "Listing (listDirectories): " << dirList << " with KIO" << endl;
+
+ TQValueList<KURL*> url_list;
+
+ TQStringList::ConstIterator it = dirList.begin();
+
+ for ( ; it != dirList.end(); it++ )
+ url_list.append( new KURL(*it) );
+
+ listURLs( url_list, filter, only_exe, no_hidden );
+ // Will call addMatches() and finished()
+
+ return TQString::null;
+ }
+}
+
+/*
+ * listURLs
+ *
+ * Use KIO to list the given urls
+ *
+ * addMatches() is called with the listed files
+ * finished() is called when the listing is done
+ */
+void KURLCompletion::listURLs(
+ const TQValueList<KURL *> &urls,
+ const TQString &filter,
+ bool only_exe,
+ bool no_hidden )
+{
+ assert( d->list_urls.isEmpty() );
+ assert( d->list_job == 0L );
+
+ d->list_urls = urls;
+ d->list_urls_filter = filter;
+ d->list_urls_only_exe = only_exe;
+ d->list_urls_no_hidden = no_hidden;
+
+// kdDebug() << "Listing URLs: " << urls[0]->prettyURL() << ",..." << endl;
+
+ // Start it off by calling slotIOFinished
+ //
+ // This will start a new list job as long as there
+ // are urls in d->list_urls
+ //
+ slotIOFinished(0L);
+}
+
+/*
+ * slotEntries
+ *
+ * Receive files listed by KIO and call addMatches()
+ */
+void KURLCompletion::slotEntries(TDEIO::Job*, const TDEIO::UDSEntryList& entries)
+{
+ TQStringList matches;
+
+ TDEIO::UDSEntryListConstIterator it = entries.begin();
+ TDEIO::UDSEntryListConstIterator end = entries.end();
+
+ TQString filter = d->list_urls_filter;
+
+ int filter_len = filter.length();
+
+ // Iterate over all files
+ //
+ for (; it != end; ++it) {
+ TQString name;
+ TQString url;
+ bool is_exe = false;
+ bool is_dir = false;
+
+ TDEIO::UDSEntry e = *it;
+ TDEIO::UDSEntry::ConstIterator it_2 = e.begin();
+
+ for( ; it_2 != e.end(); it_2++ ) {
+ switch ( (*it_2).m_uds ) {
+ case TDEIO::UDS_NAME:
+ name = (*it_2).m_str;
+ break;
+ case TDEIO::UDS_ACCESS:
+ is_exe = ((*it_2).m_long & MODE_EXE) != 0;
+ break;
+ case TDEIO::UDS_FILE_TYPE:
+ is_dir = ((*it_2).m_long & S_IFDIR) != 0;
+ break;
+ case TDEIO::UDS_URL:
+ url = (*it_2).m_str;
+ break;
+ }
+ }
+
+ if (!url.isEmpty()) {
+ // kdDebug() << "KURLCompletion::slotEntries url: " << url << endl;
+ name = KURL(url).fileName();
+ }
+
+ // kdDebug() << "KURLCompletion::slotEntries name: " << name << endl;
+
+ if ( name[0] == '.' &&
+ ( d->list_urls_no_hidden ||
+ name.length() == 1 ||
+ ( name.length() == 2 && name[1] == '.' ) ) )
+ continue;
+
+ if ( d->mode == DirCompletion && !is_dir )
+ continue;
+
+ if ( filter_len == 0 || name.left(filter_len) == filter ) {
+ if ( is_dir )
+ name.append( '/' );
+
+ if ( is_exe || !d->list_urls_only_exe )
+ matches.append( name );
+ }
+ }
+
+ addMatches( matches );
+}
+
+/*
+ * slotIOFinished
+ *
+ * Called when a KIO job is finished.
+ *
+ * Start a new list job if there are still urls in
+ * d->list_urls, otherwise call finished()
+ */
+void KURLCompletion::slotIOFinished( TDEIO::Job * job )
+{
+// kdDebug() << "slotIOFinished() " << endl;
+
+ assert( job == d->list_job );
+
+ if ( d->list_urls.isEmpty() ) {
+
+ d->list_job = 0L;
+
+ finished(); // will call KCompletion::makeCompletion()
+
+ }
+ else {
+
+ KURL *kurl = d->list_urls.first();
+
+ d->list_urls.remove( kurl );
+
+// kdDebug() << "Start KIO: " << kurl->prettyURL() << endl;
+
+ d->list_job = TDEIO::listDir( *kurl, false );
+ d->list_job->addMetaData("no-auth-prompt", "true");
+
+ assert( d->list_job );
+
+ connect( d->list_job,
+ TQT_SIGNAL(result(TDEIO::Job*)),
+ TQT_SLOT(slotIOFinished(TDEIO::Job*)) );
+
+ connect( d->list_job,
+ TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)),
+ TQT_SLOT( slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList&)) );
+
+ delete kurl;
+ }
+}
+
+///////////////////////////////////////////////////
+///////////////////////////////////////////////////
+
+/*
+ * postProcessMatch, postProcessMatches
+ *
+ * Called by KCompletion before emitting match() and matches()
+ *
+ * Append '/' to directories for file completion. This is
+ * done here to avoid stat()'ing a lot of files
+ */
+void KURLCompletion::postProcessMatch( TQString *match ) const
+{
+// kdDebug() << "KURLCompletion::postProcess: " << *match << endl;
+
+ if ( !match->isEmpty() ) {
+
+ // Add '/' to directories in file completion mode
+ // unless it has already been done
+ if ( d->last_compl_type == CTFile )
+ adjustMatch( *match );
+ }
+}
+
+void KURLCompletion::adjustMatch( TQString& match ) const
+{
+ if ( match.at( match.length()-1 ) != '/' )
+ {
+ TQString copy;
+
+ if ( match.startsWith( TQString("file:") ) )
+ copy = KURL(match).path();
+ else
+ copy = match;
+
+ expandTilde( copy );
+ expandEnv( copy );
+ if ( TQDir::isRelativePath(copy) )
+ copy.prepend( d->cwd + '/' );
+
+// kdDebug() << "postProcess: stating " << copy << endl;
+
+ KDE_struct_stat sbuff;
+
+ TQCString file = TQFile::encodeName( copy );
+
+ if ( KDE_stat( (const char*)file, &sbuff ) == 0 ) {
+ if ( S_ISDIR ( sbuff.st_mode ) )
+ match.append( '/' );
+ }
+ else {
+ kdDebug() << "Could not stat file " << copy << endl;
+ }
+ }
+}
+
+void KURLCompletion::postProcessMatches( TQStringList * matches ) const
+{
+ if ( !matches->isEmpty() && d->last_compl_type == CTFile ) {
+ TQStringList::Iterator it = matches->begin();
+ for (; it != matches->end(); ++it ) {
+ adjustMatch( (*it) );
+ }
+ }
+}
+
+void KURLCompletion::postProcessMatches( KCompletionMatches * matches ) const
+{
+ if ( !matches->isEmpty() && d->last_compl_type == CTFile ) {
+ KCompletionMatches::Iterator it = matches->begin();
+ for (; it != matches->end(); ++it ) {
+ adjustMatch( (*it).value() );
+ }
+ }
+}
+
+void KURLCompletion::customEvent(TQCustomEvent *e)
+{
+ if ( e->type() == CompletionMatchEvent::uniqueType() ) {
+
+ CompletionMatchEvent *event = static_cast<CompletionMatchEvent *>( e );
+
+ event->completionThread()->wait();
+
+ if ( !isListedURL( CTUser ) ) {
+ stop();
+ clear();
+ addMatches( event->completionThread()->matches() );
+ }
+
+ setListedURL( CTUser );
+
+ if ( d->userListThread == event->completionThread() )
+ d->userListThread = 0;
+
+ if ( d->dirListThread == event->completionThread() )
+ d->dirListThread = 0;
+
+ delete event->completionThread();
+ }
+}
+
+// static
+TQString KURLCompletion::replacedPath( const TQString& text, bool replaceHome, bool replaceEnv )
+{
+ if ( text.isEmpty() )
+ return text;
+
+ MyURL url( text, TQString::null ); // no need to replace something of our current cwd
+ if ( !url.kurl()->isLocalFile() )
+ return text;
+
+ url.filter( replaceHome, replaceEnv );
+ return url.dir() + url.file();
+}
+
+
+TQString KURLCompletion::replacedPath( const TQString& text )
+{
+ return replacedPath( text, d->replace_home, d->replace_env );
+}
+
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+// Static functions
+
+/*
+ * expandEnv
+ *
+ * Expand environment variables in text. Escaped '$' are ignored.
+ * Return true if expansion was made.
+ */
+static bool expandEnv( TQString &text )
+{
+ // Find all environment variables beginning with '$'
+ //
+ int pos = 0;
+
+ bool expanded = false;
+
+ while ( (pos = text.find('$', pos)) != -1 ) {
+
+ // Skip escaped '$'
+ //
+ if ( text[pos-1] == '\\' ) {
+ pos++;
+ }
+ // Variable found => expand
+ //
+ else {
+ // Find the end of the variable = next '/' or ' '
+ //
+ int pos2 = text.find( ' ', pos+1 );
+ int pos_tmp = text.find( '/', pos+1 );
+
+ if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
+ pos2 = pos_tmp;
+
+ if ( pos2 == -1 )
+ pos2 = text.length();
+
+ // Replace if the variable is terminated by '/' or ' '
+ // and defined
+ //
+ if ( pos2 >= 0 ) {
+ int len = pos2 - pos;
+ TQString key = text.mid( pos+1, len-1);
+ TQString value =
+ TQString::fromLocal8Bit( ::getenv(key.local8Bit()) );
+
+ if ( !value.isEmpty() ) {
+ expanded = true;
+ text.replace( pos, len, value );
+ pos = pos + value.length();
+ }
+ else {
+ pos = pos2;
+ }
+ }
+ }
+ }
+
+ return expanded;
+}
+
+/*
+ * expandTilde
+ *
+ * Replace "~user" with the users home directory
+ * Return true if expansion was made.
+ */
+static bool expandTilde(TQString &text)
+{
+ if ( text[0] != '~' )
+ return false;
+
+ bool expanded = false;
+
+ // Find the end of the user name = next '/' or ' '
+ //
+ int pos2 = text.find( ' ', 1 );
+ int pos_tmp = text.find( '/', 1 );
+
+ if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
+ pos2 = pos_tmp;
+
+ if ( pos2 == -1 )
+ pos2 = text.length();
+
+ // Replace ~user if the user name is terminated by '/' or ' '
+ //
+ if ( pos2 >= 0 ) {
+
+ TQString user = text.mid( 1, pos2-1 );
+ TQString dir;
+
+ // A single ~ is replaced with $HOME
+ //
+ if ( user.isEmpty() ) {
+ dir = TQDir::homeDirPath();
+ }
+ // ~user is replaced with the dir from passwd
+ //
+ else {
+ struct passwd *pw = ::getpwnam( user.local8Bit() );
+
+ if ( pw )
+ dir = TQFile::decodeName( pw->pw_dir );
+
+ ::endpwent();
+ }
+
+ if ( !dir.isEmpty() ) {
+ expanded = true;
+ text.replace(0, pos2, dir);
+ }
+ }
+
+ return expanded;
+}
+
+/*
+ * unescape
+ *
+ * Remove escapes and return the result in a new string
+ *
+ */
+static TQString unescape(const TQString &text)
+{
+ TQString result;
+
+ for (uint pos = 0; pos < text.length(); pos++)
+ if ( text[pos] != '\\' )
+ result.insert( result.length(), text[pos] );
+
+ return result;
+}
+
+void KURLCompletion::virtual_hook( int id, void* data )
+{ KCompletion::virtual_hook( id, data ); }
+
+#include "kurlcompletion.moc"
+
diff --git a/tdeio/tdeio/kurlcompletion.h b/tdeio/tdeio/kurlcompletion.h
new file mode 100644
index 000000000..30a825d3d
--- /dev/null
+++ b/tdeio/tdeio/kurlcompletion.h
@@ -0,0 +1,236 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Smith <dsmith@algonet.se>
+
+ This class was inspired by a previous KURLCompletion by
+ Henner Zeller <zeller@think.de>
+
+ 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 KURLCOMPLETION_H
+#define KURLCOMPLETION_H
+
+#include <kcompletion.h>
+#include <tdeio/jobclasses.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+class KURL;
+class KURLCompletionPrivate;
+
+/**
+ * This class does completion of URLs including user directories (~user)
+ * and environment variables. Remote URLs are passed to KIO.
+ *
+ * @short Completion of a single URL
+ * @author David Smith <dsmith@algonet.se>
+ */
+class TDEIO_EXPORT KURLCompletion : public KCompletion
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Determines how completion is done.
+ * @li ExeCompletion - executables in $PATH or with full path.
+ * @li FileCompletion - all files with full path or in dir(), URLs
+ * are listed using KIO.
+ * @li DirCompletion - Same as FileCompletion but only returns directories.
+ */
+ enum Mode { ExeCompletion=1, FileCompletion, DirCompletion, SystemExeCompletion };
+
+ /**
+ * Constructs a KURLCompletion object in FileCompletion mode.
+ */
+ KURLCompletion();
+ /**
+ * This overloaded constructor allows you to set the Mode to ExeCompletion
+ * or FileCompletion without using setMode. Default is FileCompletion.
+ */
+ KURLCompletion(Mode);
+ /**
+ * Destructs the KURLCompletion object.
+ */
+ virtual ~KURLCompletion();
+
+ /**
+ * Finds completions to the given text.
+ *
+ * Remote URLs are listed with KIO. For performance reasons, local files
+ * are listed with KIO only if KURLCOMPLETION_LOCAL_KIO is set.
+ * The completion is done asyncronously if KIO is used.
+ *
+ * Returns the first match for user, environment, and local dir completion
+ * and TQString::null for asynchronous completion (KIO or threaded).
+ *
+ * @param text the text to complete
+ * @return the first match, or TQString::null if not found
+ */
+ virtual TQString makeCompletion(const TQString &text); // KDE4: remove return value, it's often null due to threading
+
+ /**
+ * Sets the current directory (used as base for completion).
+ * Default = $HOME.
+ * @param dir the current directory, either as a path or URL
+ */
+ virtual void setDir(const TQString &dir);
+
+ /**
+ * Returns the current directory, as it was given in setDir
+ * @return the current directory (path or URL)
+ */
+ virtual TQString dir() const;
+
+ /**
+ * Check whether asynchronous completion is in progress.
+ * @return true if asynchronous completion is in progress
+ */
+ virtual bool isRunning() const;
+
+ /**
+ * Stops asynchronous completion.
+ */
+ virtual void stop();
+
+ /**
+ * Returns the completion mode: exe or file completion (default FileCompletion).
+ * @return the completion mode
+ */
+ virtual Mode mode() const;
+
+ /**
+ * Changes the completion mode: exe or file completion
+ * @param mode the new completion mode
+ */
+ virtual void setMode( Mode mode );
+
+ /**
+ * Checks whether environment variables are completed and
+ * whether they are replaced internally while finding completions.
+ * Default is enabled.
+ * @return true if environment vvariables will be replaced
+ */
+ virtual bool replaceEnv() const;
+
+ /**
+ * Enables/disables completion and replacement (internally) of
+ * environment variables in URLs. Default is enabled.
+ * @param replace true to replace environment variables
+ */
+ virtual void setReplaceEnv( bool replace );
+
+ /**
+ * Returns whether ~username is completed and whether ~username
+ * is replaced internally with the user's home directory while
+ * finding completions. Default is enabled.
+ * @return true to replace tilde with the home directory
+ */
+ virtual bool replaceHome() const;
+
+ /**
+ * Enables/disables completion of ~username and replacement
+ * (internally) of ~username with the user's home directory.
+ * Default is enabled.
+ * @param replace true to replace tilde with the home directory
+ */
+ virtual void setReplaceHome( bool replace );
+
+ /**
+ * Replaces username and/or environment variables, depending on the
+ * current settings and returns the filtered url. Only works with
+ * local files, i.e. returns back the original string for non-local
+ * urls.
+ * @param text the text to process
+ * @return the path or URL resulting from this operation. If you
+ * want to convert it to a KURL, use KURL::fromPathOrURL.
+ */
+ TQString replacedPath( const TQString& text );
+
+ /**
+ * @internal I'll let ossi add a real one to KShell :)
+ * @since 3.2
+ */
+ static TQString replacedPath( const TQString& text,
+ bool replaceHome, bool replaceEnv = true );
+
+ class MyURL;
+protected:
+ // Called by KCompletion, adds '/' to directories
+ void postProcessMatch( TQString *match ) const;
+ void postProcessMatches( TQStringList *matches ) const;
+ void postProcessMatches( KCompletionMatches* matches ) const;
+
+ virtual void customEvent( TQCustomEvent *e );
+
+protected slots:
+ void slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList& );
+ void slotIOFinished( TDEIO::Job * );
+
+private:
+
+ bool isAutoCompletion();
+
+ bool userCompletion(const MyURL &url, TQString *match);
+ bool envCompletion(const MyURL &url, TQString *match);
+ bool exeCompletion(const MyURL &url, TQString *match);
+ bool systemexeCompletion(const MyURL &url, TQString *match);
+ bool fileCompletion(const MyURL &url, TQString *match);
+ bool urlCompletion(const MyURL &url, TQString *match);
+
+ // List a directory using readdir()
+ void listDir( const TQString& dir,
+ TQStringList *matches,
+ const TQString& filter,
+ bool only_exe,
+ bool no_hidden );
+
+ // List the next dir in m_dirs
+ TQString listDirectories(const TQStringList &,
+ const TQString &,
+ bool only_exe = false,
+ bool only_dir = false,
+ bool no_hidden = false,
+ bool stat_files = true);
+
+ void listURLs( const TQValueList<KURL *> &urls,
+ const TQString &filter = TQString::null,
+ bool only_exe = false,
+ bool no_hidden = false );
+
+ void addMatches( const TQStringList & );
+ TQString finished();
+
+ void init();
+
+ void setListedURL(int compl_type /* enum ComplType */,
+ const TQString& dir = TQString::null,
+ const TQString& filter = TQString::null,
+ bool no_hidden = false );
+
+ bool isListedURL( int compl_type /* enum ComplType */,
+ const TQString& dir = TQString::null,
+ const TQString& filter = TQString::null,
+ bool no_hidden = false );
+
+ void adjustMatch( TQString& match ) const;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ KURLCompletionPrivate *d;
+};
+
+#endif // KURLCOMPLETION_H
diff --git a/tdeio/tdeio/kurlpixmapprovider.cpp b/tdeio/tdeio/kurlpixmapprovider.cpp
new file mode 100644
index 000000000..caeedf066
--- /dev/null
+++ b/tdeio/tdeio/kurlpixmapprovider.cpp
@@ -0,0 +1,33 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@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 (LGPL) 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 "kurlpixmapprovider.h"
+
+TQPixmap KURLPixmapProvider::pixmapFor( const TQString& url, int size ) {
+ KURL u;
+ if ( url.at(0) == '/' )
+ u.setPath( url );
+ else
+ u = url;
+ return KMimeType::pixmapForURL( u, 0, KIcon::Desktop, size );
+ }
+
+void KURLPixmapProvider::virtual_hook( int id, void* data )
+{ KPixmapProvider::virtual_hook( id, data ); }
diff --git a/tdeio/tdeio/kurlpixmapprovider.h b/tdeio/tdeio/kurlpixmapprovider.h
new file mode 100644
index 000000000..82be4bd1b
--- /dev/null
+++ b/tdeio/tdeio/kurlpixmapprovider.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@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 (LGPL) 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 KURLPIXMAPPROVIDER_H
+#define KURLPIXMAPPROVIDER_H
+
+#include <kpixmapprovider.h>
+#include <kmimetype.h>
+
+/**
+ * Implementation of KPixmapProvider.
+ *
+ * Uses KMimeType::pixmapForURL() to resolve icons.
+ *
+ * Instatiate this class and supply it to the desired class, e.g.
+ * \code
+ * KHistoryCombo *combo = new KHistoryCombo( this );
+ * combo->setPixmapProvider( new KURLPixmapProvider );
+ * [...]
+ * \endcode
+ *
+ * @short Resolves pixmaps for URLs
+ * @author Carsten Pfeiffer <pfeiffer@kde.org>
+ */
+class TDEIO_EXPORT KURLPixmapProvider : public KPixmapProvider
+{
+public:
+ /**
+ * Returns a pixmap for @p url with size @p size.
+ * Uses KMimeType::pixmapForURL().
+ * @param url the URL to fetch a pixmap for
+ * @param size the size of the pixmap in pixels, or 0 for default.
+ * @return the resulting pixmap
+ * @see KIcon::StdSizes
+ */
+ virtual TQPixmap pixmapFor( const TQString& url, int size = 0 );
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+
+#endif // KURLPIXMAPPROVIDER_H
diff --git a/tdeio/tdeio/kuserprofile.cpp b/tdeio/tdeio/kuserprofile.cpp
new file mode 100644
index 000000000..ebd8b8deb
--- /dev/null
+++ b/tdeio/tdeio/kuserprofile.cpp
@@ -0,0 +1,355 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Torben Weis <weis@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 "kuserprofile.h"
+#include "kservice.h"
+#include "kservicetype.h"
+#include "kservicetypefactory.h"
+
+#include <tdeconfig.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+
+#include <tqtl.h>
+
+template class TQPtrList<KServiceTypeProfile>;
+typedef TQPtrList<KServiceTypeProfile> KServiceTypeProfileList;
+
+/*********************************************
+ *
+ * KServiceTypeProfile
+ *
+ *********************************************/
+
+KServiceTypeProfileList* KServiceTypeProfile::s_lstProfiles = 0L;
+static KStaticDeleter< KServiceTypeProfileList > profileDeleter;
+bool KServiceTypeProfile::s_configurationMode = false;
+
+void KServiceTypeProfile::initStatic()
+{
+ if ( s_lstProfiles )
+ return;
+
+ // Make sure that a KServiceTypeFactory gets created.
+ (void) KServiceTypeFactory::self();
+
+ profileDeleter.setObject(s_lstProfiles, new KServiceTypeProfileList);
+ s_lstProfiles->setAutoDelete( true );
+
+ TDEConfig config( "profilerc", true, false);
+
+ static const TQString & defaultGroup = TDEGlobal::staticQString("<default>");
+
+ TQStringList tmpList = config.groupList();
+ for (TQStringList::Iterator aIt = tmpList.begin();
+ aIt != tmpList.end(); ++aIt) {
+ if ( *aIt == defaultGroup )
+ continue;
+
+ config.setGroup( *aIt );
+
+ TQString appId = config.readEntry( "Application" );
+
+ KService::Ptr pService = KService::serviceByStorageId(appId);
+
+ if ( pService ) {
+ TQString application = pService->storageId();
+ TQString type = config.readEntry( "ServiceType" );
+ TQString type2 = config.readEntry( "GenericServiceType" );
+ if (type2.isEmpty()) // compat code
+ type2 = (pService->type() == "Application") ? "Application" : "KParts/ReadOnlyPart";
+ int pref = config.readNumEntry( "Preference" );
+
+ if ( !type.isEmpty() /* && pref >= 0*/ ) // Don't test for pref here. We want those in the list, to mark them as forbidden
+ {
+ KServiceTypeProfile* p =
+ KServiceTypeProfile::serviceTypeProfile( type, type2 );
+
+ if ( !p ) {
+ p = new KServiceTypeProfile( type, type2 );
+ s_lstProfiles->append( p );
+ }
+
+ bool allow = config.readBoolEntry( "AllowAsDefault" );
+ //kdDebug(7014) << "KServiceTypeProfile::initStatic adding service " << application << " to profile for " << type << "," << type2 << " with preference " << pref << endl;
+ p->addService( application, pref, allow );
+ }
+ }
+ }
+}
+
+//static
+void KServiceTypeProfile::clear()
+{
+ // HACK tdesycoca may open the dummy db, in such case the first call to tdesycoca
+ // in initStatic() leads to closing the dummy db and clear() being called
+ // in the middle of it, making s_lstProfiles be NULL
+ if( s_lstProfiles == NULL || s_lstProfiles->count() == 0 )
+ return;
+ profileDeleter.destructObject();
+}
+
+//static
+KServiceTypeProfile::OfferList KServiceTypeProfile::offers( const TQString& _servicetype, const TQString& _genericServiceType )
+{
+ OfferList offers;
+ TQStringList serviceList;
+ //kdDebug(7014) << "KServiceTypeProfile::offers( " << _servicetype << "," << _genericServiceType << " )" << endl;
+
+ // Note that KServiceTypeProfile::offers() calls KServiceType::offers(),
+ // so we _do_ get the new services, that are available but not in the profile.
+ if ( _genericServiceType.isEmpty() )
+ {
+ initStatic();
+ // We want all profiles for servicetype, if we have profiles.
+ // ## Slow loop, if profilerc is big. We should use a map instead?
+ TQPtrListIterator<KServiceTypeProfile> it( *s_lstProfiles );
+ for( ; it.current(); ++it )
+ if ( it.current()->m_strServiceType == _servicetype )
+ {
+ offers += it.current()->offers();
+ }
+ //kdDebug(7014) << "Found profile: " << offers.count() << " offers" << endl;
+ }
+ else
+ {
+ KServiceTypeProfile* profile = serviceTypeProfile( _servicetype, _genericServiceType );
+ if ( profile )
+ {
+ //kdDebug(7014) << "Found profile: " << profile->offers().count() << " offers" << endl;
+ offers += profile->offers();
+ }
+ else
+ {
+ // Try the other way round, order is not like size, it doesn't matter.
+ profile = serviceTypeProfile( _genericServiceType, _servicetype );
+ if ( profile )
+ {
+ //kdDebug(7014) << "Found profile after switching: " << profile->offers().count() << " offers" << endl;
+ offers += profile->offers();
+ }
+ }
+ }
+
+ // Collect services, to make the next loop faster
+ OfferList::Iterator itOffers = offers.begin();
+ for( ; itOffers != offers.end(); ++itOffers )
+ serviceList += (*itOffers).service()->desktopEntryPath(); // this should identify each service uniquely
+ //kdDebug(7014) << "serviceList: " << serviceList.join(",") << endl;
+
+ // Now complete with any other offers that aren't in the profile
+ // This can be because the services have been installed after the profile was written,
+ // but it's also the case for any service that's neither App nor ReadOnlyPart, e.g. RenameDlg/Plugin
+ KService::List list = KServiceType::offers( _servicetype );
+ //kdDebug(7014) << "Using KServiceType::offers, result: " << list.count() << " offers" << endl;
+ TQValueListIterator<KService::Ptr> it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ if (_genericServiceType.isEmpty() /*no constraint*/ || (*it)->hasServiceType( _genericServiceType ))
+ {
+ // Check that we don't already have it ;)
+ if ( serviceList.find( (*it)->desktopEntryPath() ) == serviceList.end() )
+ {
+ bool allow = (*it)->allowAsDefault();
+ KServiceOffer o( (*it), (*it)->initialPreferenceForMimeType(_servicetype), allow );
+ offers.append( o );
+ //kdDebug(7014) << "Appending offer " << (*it)->name() << " initial preference=" << (*it)->initialPreference() << " allow-as-default=" << allow << endl;
+ }
+ //else
+ // kdDebug(7014) << "Already having offer " << (*it)->name() << endl;
+ }
+ }
+
+ qBubbleSort( offers );
+
+#if 0
+ // debug code, comment if you wish but don't remove.
+ kdDebug(7014) << "Sorted list:" << endl;
+ OfferList::Iterator itOff = offers.begin();
+ for( ; itOff != offers.end(); ++itOff )
+ kdDebug(7014) << (*itOff).service()->name() << " allow-as-default=" << (*itOff).allowAsDefault() << endl;
+#endif
+
+ //kdDebug(7014) << "Returning " << offers.count() << " offers" << endl;
+ return offers;
+}
+
+KServiceTypeProfile::KServiceTypeProfile( const TQString& _servicetype, const TQString& _genericServiceType )
+{
+ initStatic();
+
+ m_strServiceType = _servicetype;
+ m_strGenericServiceType = _genericServiceType;
+}
+
+KServiceTypeProfile::~KServiceTypeProfile()
+{
+}
+
+void KServiceTypeProfile::addService( const TQString& _service,
+ int _preference, bool _allow_as_default )
+{
+ m_mapServices[ _service ].m_iPreference = _preference;
+ m_mapServices[ _service ].m_bAllowAsDefault = _allow_as_default;
+}
+
+int KServiceTypeProfile::preference( const TQString& _service ) const
+{
+ KService::Ptr service = KService::serviceByName( _service );
+ if (!service)
+ return 0;
+ TQMap<TQString,Service>::ConstIterator it = m_mapServices.find( service->storageId() );
+ if ( it == m_mapServices.end() )
+ return 0;
+
+ return it.data().m_iPreference;
+}
+
+bool KServiceTypeProfile::allowAsDefault( const TQString& _service ) const
+{
+ KService::Ptr service = KService::serviceByName( _service );
+ if (!service)
+ return false;
+
+ // Does the service itself not allow that ?
+ if ( !service->allowAsDefault() )
+ return false;
+
+ // Look what the user says ...
+ TQMap<TQString,Service>::ConstIterator it = m_mapServices.find( service->storageId() );
+ if ( it == m_mapServices.end() )
+ return 0;
+
+ return it.data().m_bAllowAsDefault;
+}
+
+KServiceTypeProfile* KServiceTypeProfile::serviceTypeProfile( const TQString& _servicetype, const TQString& _genericServiceType )
+{
+ initStatic();
+ static const TQString& app_str = TDEGlobal::staticQString("Application");
+
+ const TQString &_genservicetype = ((!_genericServiceType.isEmpty()) ? _genericServiceType : app_str);
+
+ TQPtrListIterator<KServiceTypeProfile> it( *s_lstProfiles );
+ for( ; it.current(); ++it )
+ if (( it.current()->m_strServiceType == _servicetype ) &&
+ ( it.current()->m_strGenericServiceType == _genservicetype))
+ return it.current();
+
+ return 0;
+}
+
+
+KServiceTypeProfile::OfferList KServiceTypeProfile::offers() const
+{
+ OfferList offers;
+
+ kdDebug(7014) << "KServiceTypeProfile::offers serviceType=" << m_strServiceType << " genericServiceType=" << m_strGenericServiceType << endl;
+ KService::List list = KServiceType::offers( m_strServiceType );
+ TQValueListIterator<KService::Ptr> it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ //kdDebug(7014) << "KServiceTypeProfile::offers considering " << (*it)->name() << endl;
+ if ( m_strGenericServiceType.isEmpty() || (*it)->hasServiceType( m_strGenericServiceType ) )
+ {
+ // Now look into the profile, to find this service's preference.
+ TQMap<TQString,Service>::ConstIterator it2 = m_mapServices.find( (*it)->storageId() );
+
+ if( it2 != m_mapServices.end() )
+ {
+ //kdDebug(7014) << "found in mapServices pref=" << it2.data().m_iPreference << endl;
+ if ( it2.data().m_iPreference > 0 ) {
+ bool allow = (*it)->allowAsDefault();
+ if ( allow )
+ allow = it2.data().m_bAllowAsDefault;
+ KServiceOffer o( (*it), it2.data().m_iPreference, allow );
+ offers.append( o );
+ }
+ }
+ else
+ {
+ //kdDebug(7014) << "not found in mapServices. Appending." << endl;
+ // We use 0 as the preference to ensure new apps don't take over existing apps (which default to 1)
+ KServiceOffer o( (*it), 0, (*it)->allowAsDefault() );
+ offers.append( o );
+ }
+ }/* else
+ kdDebug(7014) << "Doesn't have " << m_strGenericServiceType << endl;*/
+ }
+
+ qBubbleSort( offers );
+
+ //kdDebug(7014) << "KServiceTypeProfile::offers returning " << offers.count() << " offers" << endl;
+ return offers;
+}
+
+KService::Ptr KServiceTypeProfile::preferredService( const TQString & _serviceType, const TQString & _genericServiceType )
+{
+ OfferList lst = offers( _serviceType, _genericServiceType );
+
+ OfferList::Iterator itOff = lst.begin();
+ // Look for the first one that is allowed as default.
+ // Since the allowed-as-default are first anyway, we only have
+ // to look at the first one to know.
+ if( itOff != lst.end() && (*itOff).allowAsDefault() )
+ return (*itOff).service();
+
+ //kdDebug(7014) << "No offers, or none allowed as default" << endl;
+ return 0L;
+}
+
+/*********************************************
+ *
+ * KServiceOffer
+ *
+ *********************************************/
+
+KServiceOffer::KServiceOffer()
+{
+ m_iPreference = -1;
+}
+
+KServiceOffer::KServiceOffer( const KServiceOffer& _o )
+{
+ m_pService = _o.m_pService;
+ m_iPreference = _o.m_iPreference;
+ m_bAllowAsDefault = _o.m_bAllowAsDefault;
+}
+
+KServiceOffer::KServiceOffer( KService::Ptr _service, int _pref, bool _default )
+{
+ m_pService = _service;
+ m_iPreference = _pref;
+ m_bAllowAsDefault = _default;
+}
+
+
+bool KServiceOffer::operator< ( const KServiceOffer& _o ) const
+{
+ // Put offers allowed as default FIRST.
+ if ( _o.m_bAllowAsDefault && !m_bAllowAsDefault )
+ return false; // _o is default and not 'this'.
+ if ( !_o.m_bAllowAsDefault && m_bAllowAsDefault )
+ return true; // 'this' is default but not _o.
+ // Both offers are allowed or not allowed as default
+ // -> use preferences to sort them
+ // The bigger the better, but we want the better FIRST
+ return _o.m_iPreference < m_iPreference;
+}
diff --git a/tdeio/tdeio/kuserprofile.h b/tdeio/tdeio/kuserprofile.h
new file mode 100644
index 000000000..45b58fe6a
--- /dev/null
+++ b/tdeio/tdeio/kuserprofile.h
@@ -0,0 +1,282 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@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 __kuserprofile_h__
+#define __kuserprofile_h__
+
+#include <tqmap.h>
+#include <tqstring.h>
+#include <tqptrlist.h>
+#include <tqvaluelist.h>
+
+#include <kservice.h>
+
+/**
+ * This class holds the user-specific preferences of a service
+ * (whether it can be a default offer or not, how big is the preference
+ * for this offer, ...). Basically it is a reference to a
+ * KService, a number that represents the user's preference (bigger
+ * is better) and a flag whether the KService can be used as default.
+ *
+ * @see KService
+ * @short Holds the user's preference of a service.
+ */
+class TDEIO_EXPORT KServiceOffer
+{
+public:
+ /**
+ * Create an invalid service offer.
+ */
+ KServiceOffer();
+
+ /**
+ * Copy constructor.
+ * Shallow copy (the KService will not be copied).
+ */
+ KServiceOffer( const KServiceOffer& );
+
+ /**
+ * Creates a new KServiceOffer.
+ * @param _service a pointer to the KService
+ * @param _pref the user's preference value, must be positive,
+ * bigger is better
+ * @param _default true if the service should be used as
+ * default
+ */
+ KServiceOffer( KService::Ptr _service,
+ int _pref, bool _default );
+
+ /**
+ * A service is bigger that the other when it can be default
+ * (and the other is not) and its preference value it higher.
+ */
+ bool operator< ( const KServiceOffer& ) const;
+ /**
+ * Is it allowed to use this service for default actions
+ * (e.g. Left Click in a file manager, or KRun in general).
+ * @return true if the service is a allowed as default
+ */
+ bool allowAsDefault() const { return m_bAllowAsDefault; }
+ /**
+ * The bigger this number is, the better is this service.
+ * @return the preference number (negative numbers will be
+ * returned by invalid service offers)
+ */
+ int preference() const { return m_iPreference; }
+ /**
+ * The service which this offer is about.
+ * @return the service this offer is about, can be 0
+ * in valid offers or when not set
+ */
+ KService::Ptr service() const { return m_pService; }
+ /**
+ * Check whether the entry is valid. A service is valid if
+ * its preference value is positive.
+ * @return true if the service offer is valid
+ */
+ bool isValid() const { return m_iPreference >= 0; }
+
+private:
+ int m_iPreference;
+ bool m_bAllowAsDefault;
+ KService::Ptr m_pService;
+private:
+ class KServiceOfferPrivate;
+};
+
+/**
+ * KServiceTypeProfile represents the user's preferences for services
+ * of a service type.
+ * It consists of a list of services (service offers) for the service type
+ * that is sorted by the user's preference.
+ * KTrader uses KServiceTypeProfile to sort its results, so usually
+ * you can just use KTrader to find the user's preferred service.
+ *
+ * @see KService
+ * @see KServiceType
+ * @see KServiceOffer
+ * @see KTrader
+ * @short Represents the user's preferences for services of a service type
+ */
+class TDEIO_EXPORT KServiceTypeProfile
+{
+public:
+ typedef TQValueList<KServiceOffer> OfferList;
+
+ ~KServiceTypeProfile();
+
+ /**
+ * @deprecated Remove in KDE 4, unused.
+ * Returns the users preference of the given service.
+ * @param _service the name of the service to check
+ * @return the user's preference number of the given
+ * @p _service, or 0 the service is unknown.
+ */
+ int preference( const TQString& _service ) const;
+
+ /**
+ * @deprecated Remove in KDE 4, unused.
+ * Checks whether the given @p _service can be used as default.
+ * @param _service the name of the service to check
+ * @return true if allowed as default
+ */
+ bool allowAsDefault( const TQString& _service ) const;
+
+ /**
+ * Returns the list of all service offers for the service types
+ * that are represented by this profile.
+ * @return the list of KServiceOffer instances
+ */
+ OfferList offers() const;
+
+ /**
+ * Returns the preferred service for @p _serviceType and @p _genericServiceType
+ * ("Application", type of component, or null).
+ *
+ * @param serviceType the service type (e.g. a MIME type)
+ * @param genericServiceType the generic service type (e.g. "Application" or
+ * "KParts/ReadOnlyPart")
+ * @return the preferred service, or 0 if no service is available
+ */
+ static KService::Ptr preferredService( const TQString & serviceType, const TQString & genericServiceType );
+
+ /**
+ * Returns the profile for the requested service type.
+ * @param servicetype the service type (e.g. a MIME type)
+ * @param genericServiceType the generic service type (e.g. "Application"
+ * or "KParts/ReadOnlyPart"). Can be TQString::null,
+ * then the "Application" generic type will be used
+ * @return the KServiceTypeProfile with the given arguments, or 0 if not found
+ */
+ static KServiceTypeProfile* serviceTypeProfile( const TQString& servicetype, const TQString & genericServiceType = TQString::null );
+
+ /**
+ * Returns the offers associated with a given servicetype, sorted by preference.
+ * This is what KTrader uses to get the list of offers, before applying the
+ * constraints and preferences.
+ *
+ * If @p genericServiceType is specified, a list is returned with
+ * the offers associated with the combination of the two service types.
+ * This is almost like an "foo in ServiceTypes" constraint in the KTrader,
+ * but the difference is that to order the offers, we will look at entries
+ * specifically for those two service types. Typically, this is used for
+ * getting the list of embeddable components that can handle a given mimetype.
+ * In that case, @p servicetype is the mimetype and @p genericServiceType is "KParts/ReadOnlyPart".
+ *
+ * @param servicetype the service type (e.g. a MIME type)
+ * @param genericServiceType the generic service type (e.g. "Application"
+ * or "KParts/ReadOnlyPart"). Can be TQString::null,
+ * then all generic types will be included
+ * @return the list of offers witht he given parameters
+ */
+ static OfferList offers( const TQString& servicetype, const TQString& genericServiceType = TQString::null );
+
+ /**
+ * Returns a list of all KServiceTypeProfiles.
+ * @return a list of all KServiceTypeProfiles
+ */
+ static const TQPtrList<KServiceTypeProfile>& serviceTypeProfiles() { return *s_lstProfiles; }
+
+ /**
+ * Clear all cached information
+ */
+ static void clear();
+
+ /**
+ * This method activates a special mode of KServiceTypeProfile, in which all/all
+ * and all/allfiles are excluded from the results of the queries.
+ * It is meant for the configuration module _only_.
+ * @internal
+ */
+ static void setConfigurationMode() { s_configurationMode = true; }
+
+ /**
+ * This method deactivates the special mode above of KServiceTypeProfile
+ * It is meant for the configuration module _only_.
+ * @internal
+ * @since 3.5.7
+ */
+ static void unsetConfigurationMode() { s_configurationMode = false; }
+
+ /**
+ * @internal
+ */
+ static bool configurationMode() { return s_configurationMode; }
+
+protected:
+ /**
+ * Constructor is called when the user profile is read for the
+ * first time.
+ * @param serviceType the service type (e.g. a MIME type)
+ * @param genericServiceType the generic service type (e.g. "Application"
+ * or "KParts/ReadOnlyPart"). Can be TQString::null,
+ * then the "Application" generic type will be used
+ */
+ KServiceTypeProfile( const TQString& serviceType,
+ const TQString& genericServiceType = TQString::null );
+
+ /**
+ * Add a service to this profile.
+ * @param _service the name of the service
+ * @param _preference the user's preference value, must be positive,
+ * bigger is better
+ * @param _allow_as_default true if the service should be used as
+ * default
+ */
+ void addService( const TQString& _service, int _preference = 1, bool _allow_as_default = true );
+
+private:
+ /**
+ * Represents the users assessment of a special service
+ */
+ struct Service
+ {
+ /**
+ * The bigger this number is, the better is this service.
+ */
+ int m_iPreference;
+ /**
+ * Is it allowed to use this service for default actions.
+ */
+ bool m_bAllowAsDefault;
+ };
+
+ /**
+ * Map of all services for which we have assessments.
+ */
+ TQMap<TQString,Service> m_mapServices;
+
+ /**
+ * ServiceType of this profile.
+ */
+ TQString m_strServiceType;
+
+ /**
+ * Secondary ServiceType of this profile.
+ */
+ TQString m_strGenericServiceType;
+
+ static void initStatic();
+ static TQPtrList<KServiceTypeProfile>* s_lstProfiles;
+ static bool s_configurationMode;
+private:
+ class KServiceTypeProfilePrivate* d;
+};
+
+#endif
diff --git a/tdeio/tdeio/kzip.cpp b/tdeio/tdeio/kzip.cpp
new file mode 100644
index 000000000..85dcb76d1
--- /dev/null
+++ b/tdeio/tdeio/kzip.cpp
@@ -0,0 +1,1460 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2002 Holger Schroeder <holger-kde@holgis.net>
+
+ 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.
+*/
+
+/*
+ This class implements a tdeioslave to access ZIP files from KDE.
+ you can use it in IO_ReadOnly or in IO_WriteOnly mode, and it
+ behaves just as expected (i hope ;-) ).
+ It can also be used in IO_ReadWrite mode, in this case one can
+ append files to an existing zip archive. when you append new files, which
+ are not yet in the zip, it works as expected, they are appended at the end.
+ when you append a file, which is already in the file, the reference to the
+ old file is dropped and the new one is added to the zip. but the
+ old data from the file itself is not deleted, it is still in the
+ zipfile. so when you want to have a small and garbagefree zipfile,
+ just read the contents of the appended zipfile and write it to a new one
+ in IO_WriteOnly mode. especially take care of this, when you don't want
+ to leak information of how intermediate versions of files in the zip
+ were looking.
+ For more information on the zip fileformat go to
+ http://www.pkware.com/support/appnote.html .
+
+*/
+
+#include "kzip.h"
+#include "kfilterdev.h"
+#include "klimitediodevice.h"
+#include <kmimetype.h>
+#include <ksavefile.h>
+#include <kdebug.h>
+
+#include <tqasciidict.h>
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tqdatetime.h>
+#include <tqptrlist.h>
+
+#include <zlib.h>
+#include <time.h>
+#include <string.h>
+
+const int max_path_len = 4095; // maximum number of character a path may contain
+
+static void transformToMsDos(const TQDateTime& dt, char* buffer)
+{
+ if ( dt.isValid() )
+ {
+ const TQ_UINT16 time =
+ ( dt.time().hour() << 11 ) // 5 bit hour
+ | ( dt.time().minute() << 5 ) // 6 bit minute
+ | ( dt.time().second() >> 1 ); // 5 bit double seconds
+
+ buffer[0] = char(time);
+ buffer[1] = char(time >> 8);
+
+ const TQ_UINT16 date =
+ ( ( dt.date().year() - 1980 ) << 9 ) // 7 bit year 1980-based
+ | ( dt.date().month() << 5 ) // 4 bit month
+ | ( dt.date().day() ); // 5 bit day
+
+ buffer[2] = char(date);
+ buffer[3] = char(date >> 8);
+ }
+ else // !dt.isValid(), assume 1980-01-01 midnight
+ {
+ buffer[0] = 0;
+ buffer[1] = 0;
+ buffer[2] = 33;
+ buffer[3] = 0;
+ }
+}
+
+static time_t transformFromMsDos(const char* buffer)
+{
+ TQ_UINT16 time = (uchar)buffer[0] | ( (uchar)buffer[1] << 8 );
+ int h = time >> 11;
+ int m = ( time & 0x7ff ) >> 5;
+ int s = ( time & 0x1f ) * 2 ;
+ TQTime qt(h, m, s);
+
+ TQ_UINT16 date = (uchar)buffer[2] | ( (uchar)buffer[3] << 8 );
+ int y = ( date >> 9 ) + 1980;
+ int o = ( date & 0x1ff ) >> 5;
+ int d = ( date & 0x1f );
+ TQDate qd(y, o, d);
+
+ TQDateTime dt( qd, qt );
+ return dt.toTime_t();
+}
+
+// == parsing routines for zip headers
+
+/** all relevant information about parsing file information */
+struct ParseFileInfo {
+ // file related info
+// TQCString name; // filename
+ mode_t perm; // permissions of this file
+ time_t atime; // last access time (UNIX format)
+ time_t mtime; // modification time (UNIX format)
+ time_t ctime; // creation time (UNIX format)
+ int uid; // user id (-1 if not specified)
+ int gid; // group id (-1 if not specified)
+ TQCString guessed_symlink; // guessed symlink target
+ int extralen; // length of extra field
+
+ // parsing related info
+ bool exttimestamp_seen; // true if extended timestamp extra field
+ // has been parsed
+ bool newinfounix_seen; // true if Info-ZIP Unix New extra field has
+ // been parsed
+
+ ParseFileInfo() : perm(0100644), uid(-1), gid(-1), extralen(0),
+ exttimestamp_seen(false), newinfounix_seen(false) {
+ ctime = mtime = atime = time(0);
+ }
+};
+
+/** updates the parse information with the given extended timestamp extra field.
+ * @param buffer start content of buffer known to contain an extended
+ * timestamp extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseExtTimestamp(const char *buffer, int size, bool islocal,
+ ParseFileInfo &pfi) {
+ if (size < 1) {
+ kdDebug(7040) << "premature end of extended timestamp (#1)" << endl;
+ return false;
+ }/*end if*/
+ int flags = *buffer; // read flags
+ buffer += 1;
+ size -= 1;
+
+ if (flags & 1) { // contains modification time
+ if (size < 4) {
+ kdDebug(7040) << "premature end of extended timestamp (#2)" << endl;
+ return false;
+ }/*end if*/
+ pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
+ | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+ buffer += 4;
+ size -= 4;
+ }/*end if*/
+ // central extended field cannot contain more than the modification time
+ // even if other flags are set
+ if (!islocal) {
+ pfi.exttimestamp_seen = true;
+ return true;
+ }/*end if*/
+
+ if (flags & 2) { // contains last access time
+ if (size < 4) {
+ kdDebug(7040) << "premature end of extended timestamp (#3)" << endl;
+ return true;
+ }/*end if*/
+ pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
+ | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+ buffer += 4;
+ size -= 4;
+ }/*end if*/
+
+ if (flags & 4) { // contains creation time
+ if (size < 4) {
+ kdDebug(7040) << "premature end of extended timestamp (#4)" << endl;
+ return true;
+ }/*end if*/
+ pfi.ctime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
+ | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+ buffer += 4;
+ }/*end if*/
+
+ pfi.exttimestamp_seen = true;
+ return true;
+}
+
+/** updates the parse information with the given Info-ZIP Unix old extra field.
+ * @param buffer start of content of buffer known to contain an Info-ZIP
+ * Unix old extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseInfoZipUnixOld(const char *buffer, int size, bool islocal,
+ ParseFileInfo &pfi) {
+ // spec mandates to omit this field if one of the newer fields are available
+ if (pfi.exttimestamp_seen || pfi.newinfounix_seen) return true;
+
+ if (size < 8) {
+ kdDebug(7040) << "premature end of Info-ZIP unix extra field old" << endl;
+ return false;
+ }/*end if*/
+
+ pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
+ | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+ buffer += 4;
+ pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
+ | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+ buffer += 4;
+ if (islocal && size >= 12) {
+ pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+ pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+ }/*end if*/
+ return true;
+}
+
+#if 0 // not needed yet
+/** updates the parse information with the given Info-ZIP Unix new extra field.
+ * @param buffer start of content of buffer known to contain an Info-ZIP
+ * Unix new extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseInfoZipUnixNew(const char *buffer, int size, bool islocal,
+ ParseFileInfo &pfi) {
+ if (!islocal) { // contains nothing in central field
+ pfi.newinfounix = true;
+ return true;
+ }/*end if*/
+
+ if (size < 4) {
+ kdDebug(7040) << "premature end of Info-ZIP unix extra field new" << endl;
+ return false;
+ }/*end if*/
+
+ pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+ pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+
+ pfi.newinfounix = true;
+ return true;
+}
+#endif
+
+/**
+ * parses the extra field
+ * @param buffer start of buffer where the extra field is to be found
+ * @param size size of the extra field
+ * @param islocal true if this is part of a local header, false if of central
+ * @param pfi ParseFileInfo object which to write the results into
+ * @return true if parsing was successful
+ */
+static bool parseExtraField(const char *buffer, int size, bool islocal,
+ ParseFileInfo &pfi) {
+ // extra field in central directory doesn't contain useful data, so we
+ // don't bother parsing it
+ if (!islocal) return true;
+
+ while (size >= 4) { // as long as a potential extra field can be read
+ int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+ int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+ buffer += 2;
+ size -= 4;
+
+ if (fieldsize > size) {
+ //kdDebug(7040) << "fieldsize: " << fieldsize << " size: " << size << endl;
+ kdDebug(7040) << "premature end of extra fields reached" << endl;
+ break;
+ }/*end if*/
+
+ switch (magic) {
+ case 0x5455: // extended timestamp
+ if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) return false;
+ break;
+ case 0x5855: // old Info-ZIP unix extra field
+ if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) return false;
+ break;
+#if 0 // not needed yet
+ case 0x7855: // new Info-ZIP unix extra field
+ if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) return false;
+ break;
+#endif
+ default:
+ /* ignore everything else */;
+ }/*end switch*/
+
+ buffer += fieldsize;
+ size -= fieldsize;
+ }/*wend*/
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KZip ///////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KZip::KZipPrivate
+{
+public:
+ KZipPrivate()
+ : m_crc( 0 ),
+ m_currentFile( 0L ),
+ m_currentDev( 0L ),
+ m_compression( 8 ),
+ m_extraField( KZip::NoExtraField ),
+ m_offset( 0L ),
+ m_saveFile( 0 ) {}
+
+ unsigned long m_crc; // checksum
+ KZipFileEntry* m_currentFile; // file currently being written
+ TQIODevice* m_currentDev; // filterdev used to write to the above file
+ TQPtrList<KZipFileEntry> m_fileList; // flat list of all files, for the index (saves a recursive method ;)
+ int m_compression;
+ KZip::ExtraField m_extraField;
+ unsigned int m_offset; // holds the offset of the place in the zip,
+ // where new data can be appended. after openarchive it points to 0, when in
+ // writeonly mode, or it points to the beginning of the central directory.
+ // each call to writefile updates this value.
+ KSaveFile* m_saveFile;
+};
+
+KZip::KZip( const TQString& filename )
+ : KArchive( 0L )
+{
+ //kdDebug(7040) << "KZip(filename) reached." << endl;
+ Q_ASSERT( !filename.isEmpty() );
+ m_filename = filename;
+ d = new KZipPrivate;
+ // unusual: this ctor leaves the device set to 0.
+ // This is for the use of KSaveFile, see openArchive.
+ // KDE4: move KSaveFile support to base class, KArchive.
+}
+
+KZip::KZip( TQIODevice * dev )
+ : KArchive( dev )
+{
+ //kdDebug(7040) << "KZip::KZip( TQIODevice * dev) reached." << endl;
+ d = new KZipPrivate;
+}
+
+KZip::~KZip()
+{
+ // mjarrett: Closes to prevent ~KArchive from aborting w/o device
+ //kdDebug(7040) << "~KZip reached." << endl;
+ if( isOpened() )
+ close();
+ if ( !m_filename.isEmpty() ) { // we created the device ourselves
+ if ( d->m_saveFile ) // writing mode
+ delete d->m_saveFile;
+ else // reading mode
+ delete device(); // (the TQFile)
+ }
+ delete d;
+}
+
+bool KZip::openArchive( int mode )
+{
+ //kdDebug(7040) << "openarchive reached." << endl;
+ d->m_fileList.clear();
+
+ switch ( mode ) {
+ case IO_WriteOnly:
+ // The use of KSaveFile can't be done in the ctor (no mode known yet)
+ // Ideally we would reimplement open() and do it there (BIC)
+ if ( !m_filename.isEmpty() ) {
+ kdDebug(7040) << "Writing to a file using KSaveFile" << endl;
+ d->m_saveFile = new KSaveFile( m_filename );
+ if ( d->m_saveFile->status() != 0 ) {
+ kdWarning(7040) << "KSaveFile creation for " << m_filename << " failed, " << strerror( d->m_saveFile->status() ) << endl;
+ delete d->m_saveFile;
+ d->m_saveFile = 0;
+ return false;
+ }
+ Q_ASSERT( d->m_saveFile->file() );
+ setDevice( TQT_TQIODEVICE(d->m_saveFile->file()) );
+ }
+ return true;
+ case IO_ReadOnly:
+ case IO_ReadWrite:
+ {
+ // ReadWrite mode still uses TQFile for now; we'd need to copy to the tempfile, in fact.
+ if ( !m_filename.isEmpty() ) {
+ setDevice( TQT_TQIODEVICE(new TQFile( m_filename )) );
+ if ( !device()->open( mode ) )
+ return false;
+ }
+ break; // continued below
+ }
+ default:
+ kdWarning(7040) << "Unsupported mode " << mode << endl;
+ return false;
+ }
+
+ char buffer[47];
+
+ // Check that it's a valid ZIP file
+ // the above code opened the underlying device already.
+ TQIODevice* dev = device();
+
+ if (!dev) {
+ return false;
+ }
+
+ uint offset = 0; // holds offset, where we read
+ int n;
+
+ // contains information gathered from the local file headers
+ TQAsciiDict<ParseFileInfo> pfi_map(1009, true /*case sensitive */, true /*copy keys*/);
+ pfi_map.setAutoDelete(true);
+
+ // We set a bool for knowing if we are allowed to skip the start of the file
+ bool startOfFile = true;
+
+ for (;;) // repeat until 'end of entries' signature is reached
+ {
+kdDebug(7040) << "loop starts" << endl;
+kdDebug(7040) << "dev->at() now : " << dev->at() << endl;
+ n = dev->readBlock( buffer, 4 );
+
+ if (n < 4)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#1)" << endl;
+
+ return false;
+ }
+
+ if ( !memcmp( buffer, "PK\5\6", 4 ) ) // 'end of entries'
+ {
+ kdDebug(7040) << "PK56 found end of archive" << endl;
+ startOfFile = false;
+ break;
+ }
+
+ if ( !memcmp( buffer, "PK\3\4", 4 ) ) // local file header
+ {
+ kdDebug(7040) << "PK34 found local file header" << endl;
+ startOfFile = false;
+ // can this fail ???
+ dev->at( dev->at() + 2 ); // skip 'version needed to extract'
+
+ // read static header stuff
+ n = dev->readBlock( buffer, 24 );
+ if (n < 24) {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#4)" << endl;
+ return false;
+ }
+
+ int gpf = (uchar)buffer[0]; // "general purpose flag" not "general protection fault" ;-)
+ int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
+ time_t mtime = transformFromMsDos( buffer+4 );
+
+ TQ_LONG compr_size = (uchar)buffer[12] | (uchar)buffer[13] << 8
+ | (uchar)buffer[14] << 16 | (uchar)buffer[15] << 24;
+ TQ_LONG uncomp_size = (uchar)buffer[16] | (uchar)buffer[17] << 8
+ | (uchar)buffer[18] << 16 | (uchar)buffer[19] << 24;
+ int namelen = (uchar)buffer[20] | (uchar)buffer[21] << 8;
+ int extralen = (uchar)buffer[22] | (uchar)buffer[23] << 8;
+
+ kdDebug(7040) << "general purpose bit flag: " << gpf << endl;
+ kdDebug(7040) << "compressed size: " << compr_size << endl;
+ kdDebug(7040) << "uncompressed size: " << uncomp_size << endl;
+ kdDebug(7040) << "namelen: " << namelen << endl;
+ kdDebug(7040) << "extralen: " << extralen << endl;
+ kdDebug(7040) << "archive size: " << dev->size() << endl;
+
+ // read filename
+ TQCString filename(namelen + 1);
+ n = dev->readBlock(filename.data(), namelen);
+ if ( n < namelen ) {
+ kdWarning(7040) << "Invalid ZIP file. Name not completely read (#2)" << endl;
+ return false;
+ }
+
+ ParseFileInfo *pfi = new ParseFileInfo();
+ pfi->mtime = mtime;
+ pfi_map.insert(filename.data(), pfi);
+
+ // read and parse the beginning of the extra field,
+ // skip rest of extra field in case it is too long
+ unsigned int extraFieldEnd = dev->at() + extralen;
+ pfi->extralen = extralen;
+ int handledextralen = QMIN(extralen, (int)sizeof buffer);
+
+ kdDebug(7040) << "handledextralen: " << handledextralen << endl;
+
+ n = dev->readBlock(buffer, handledextralen);
+ // no error msg necessary as we deliberately truncate the extra field
+ if (!parseExtraField(buffer, handledextralen, true, *pfi))
+ {
+ kdWarning(7040) << "Invalid ZIP File. Broken ExtraField." << endl;
+ return false;
+ }
+
+ // jump to end of extra field
+ dev->at( extraFieldEnd );
+
+ // we have to take care of the 'general purpose bit flag'.
+ // if bit 3 is set, the header doesn't contain the length of
+ // the file and we look for the signature 'PK\7\8'.
+ if ( gpf & 8 )
+ {
+ // here we have to read through the compressed data to find
+ // the next PKxx
+ kdDebug(7040) << "trying to seek for next PK78" << endl;
+ bool foundSignature = false;
+
+ while (!foundSignature)
+ {
+ n = dev->readBlock( buffer, 1 );
+ if (n < 1)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#2)" << endl;
+ return false;
+ }
+
+ if ( buffer[0] != 'P' )
+ continue;
+
+ n = dev->readBlock( buffer, 3 );
+ if (n < 3)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#3)" << endl;
+ return false;
+ }
+
+ // we have to detect three magic tokens here:
+ // PK34 for the next local header in case there is no data descriptor
+ // PK12 for the central header in case there is no data descriptor
+ // PK78 for the data descriptor in case it is following the compressed data
+
+ if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
+ {
+ foundSignature = true;
+ dev->at( dev->at() + 12 ); // skip the 'data_descriptor'
+ }
+ else if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
+ || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
+ {
+ foundSignature = true;
+ dev->at( dev->at() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
+ }
+ else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
+ {
+ // We have another P character so we must go back a little to check if it is a magic
+ dev->at( dev->at() - 3 );
+ }
+
+ }
+ }
+ else
+ {
+ // here we skip the compressed data and jump to the next header
+ kdDebug(7040) << "general purpose bit flag indicates, that local file header contains valid size" << endl;
+ // check if this could be a symbolic link
+ if (compression_mode == NoCompression
+ && uncomp_size <= max_path_len
+ && uncomp_size > 0) {
+ // read content and store it
+ pfi->guessed_symlink.resize(uncomp_size + 1);
+ kdDebug(7040) << "guessed symlink size: " << uncomp_size << endl;
+ n = dev->readBlock(pfi->guessed_symlink.data(), uncomp_size);
+ if (n < uncomp_size) {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#5)" << endl;
+ return false;
+ }
+ } else {
+
+ if ( compr_size > (TQ_LONG)dev->size() )
+ {
+ // here we cannot trust the compressed size, so scan through the compressed
+ // data to find the next header
+ bool foundSignature = false;
+
+ while (!foundSignature)
+ {
+ n = dev->readBlock( buffer, 1 );
+ if (n < 1)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#2)" << endl;
+ return false;
+ }
+
+ if ( buffer[0] != 'P' )
+ continue;
+
+ n = dev->readBlock( buffer, 3 );
+ if (n < 3)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#3)" << endl;
+ return false;
+ }
+
+ // we have to detect three magic tokens here:
+ // PK34 for the next local header in case there is no data descriptor
+ // PK12 for the central header in case there is no data descriptor
+ // PK78 for the data descriptor in case it is following the compressed data
+
+ if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
+ {
+ foundSignature = true;
+ dev->at( dev->at() + 12 ); // skip the 'data_descriptor'
+ }
+
+ if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
+ || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
+ {
+ foundSignature = true;
+ dev->at( dev->at() - 4 );
+ // go back 4 bytes, so that the magic bytes can be found
+ // in the next cycle...
+ }
+ }
+ }
+ else
+ {
+// kdDebug(7040) << "before interesting dev->at(): " << dev->at() << endl;
+ bool success;
+ success = dev->at( dev->at() + compr_size ); // can this fail ???
+/* kdDebug(7040) << "after interesting dev->at(): " << dev->at() << endl;
+ if ( success )
+ kdDebug(7040) << "dev->at was successful... " << endl;
+ else
+ kdDebug(7040) << "dev->at failed... " << endl;*/
+ }
+
+ }
+
+// not needed any more
+/* // here we calculate the length of the file in the zip
+ // with headers and jump to the next header.
+ uint skip = compr_size + namelen + extralen;
+ offset += 30 + skip;*/
+ }
+ }
+ else if ( !memcmp( buffer, "PK\1\2", 4 ) ) // central block
+ {
+ kdDebug(7040) << "PK12 found central block" << endl;
+ startOfFile = false;
+
+ // so we reached the central header at the end of the zip file
+ // here we get all interesting data out of the central header
+ // of a file
+ offset = dev->at() - 4;
+
+ //set offset for appending new files
+ if ( d->m_offset == 0L ) d->m_offset = offset;
+
+ n = dev->readBlock( buffer + 4, 42 );
+ if (n < 42) {
+ kdWarning(7040) << "Invalid ZIP file, central entry too short" << endl; // not long enough for valid entry
+ return false;
+ }
+
+ //int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
+ //kdDebug() << "general purpose flag=" << gpf << endl;
+ // length of the filename (well, pathname indeed)
+ int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
+ TQCString bufferName( namelen + 1 );
+ n = dev->readBlock( bufferName.data(), namelen );
+ if ( n < namelen )
+ kdWarning(7040) << "Invalid ZIP file. Name not completely read" << endl;
+
+ ParseFileInfo *pfi = pfi_map[bufferName];
+ if (!pfi) { // can that happen?
+ pfi_map.insert(bufferName.data(), pfi = new ParseFileInfo());
+ }
+ TQString name( TQFile::decodeName(bufferName) );
+
+ //kdDebug(7040) << "name: " << name << endl;
+ // only in central header ! see below.
+ // length of extra attributes
+ int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
+ // length of comment for this file
+ int commlen = (uchar)buffer[33] << 8 | (uchar)buffer[32];
+ // compression method of this file
+ int cmethod = (uchar)buffer[11] << 8 | (uchar)buffer[10];
+
+ //kdDebug(7040) << "cmethod: " << cmethod << endl;
+ //kdDebug(7040) << "extralen: " << extralen << endl;
+
+ // uncompressed file size
+ uint ucsize = (uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 |
+ (uchar)buffer[25] << 8 | (uchar)buffer[24];
+ // compressed file size
+ uint csize = (uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 |
+ (uchar)buffer[21] << 8 | (uchar)buffer[20];
+
+ // offset of local header
+ uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 |
+ (uchar)buffer[43] << 8 | (uchar)buffer[42];
+
+ // some clever people use different extra field lengths
+ // in the central header and in the local header... funny.
+ // so we need to get the localextralen to calculate the offset
+ // from localheaderstart to dataoffset
+ int localextralen = pfi->extralen; // FIXME: this will not work if
+ // no local header exists
+
+ //kdDebug(7040) << "localextralen: " << localextralen << endl;
+
+ // offset, where the real data for uncompression starts
+ uint dataoffset = localheaderoffset + 30 + localextralen + namelen; //comment only in central header
+
+ //kdDebug(7040) << "esize: " << esize << endl;
+ //kdDebug(7040) << "eoffset: " << eoffset << endl;
+ //kdDebug(7040) << "csize: " << csize << endl;
+
+ int os_madeby = (uchar)buffer[5];
+ bool isdir = false;
+ int access = 0100644;
+
+ if (os_madeby == 3) { // good ole unix
+ access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
+ }
+
+ TQString entryName;
+
+ if ( name.endsWith( "/" ) ) // Entries with a trailing slash are directories
+ {
+ isdir = true;
+ name = name.left( name.length() - 1 );
+ if (os_madeby != 3) access = S_IFDIR | 0755;
+ else Q_ASSERT(access & S_IFDIR);
+ }
+
+ int pos = name.findRev( '/' );
+ if ( pos == -1 )
+ entryName = name;
+ else
+ entryName = name.mid( pos + 1 );
+ Q_ASSERT( !entryName.isEmpty() );
+
+ KArchiveEntry* entry;
+ if ( isdir )
+ {
+ TQString path = TQDir::cleanDirPath( name );
+ KArchiveEntry* ent = rootDir()->entry( path );
+ if ( ent && ent->isDirectory() )
+ {
+ //kdDebug(7040) << "Directory already exists, NOT going to add it again" << endl;
+ entry = 0L;
+ }
+ else
+ {
+ entry = new KArchiveDirectory( this, entryName, access, (int)pfi->mtime, rootDir()->user(), rootDir()->group(), TQString::null );
+ //kdDebug(7040) << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name << endl;
+ }
+ }
+ else
+ {
+ TQString symlink;
+ if (S_ISLNK(access)) {
+ symlink = TQFile::decodeName(pfi->guessed_symlink);
+ }
+ entry = new KZipFileEntry( this, entryName, access, pfi->mtime,
+ rootDir()->user(), rootDir()->group(),
+ symlink, name, dataoffset,
+ ucsize, cmethod, csize );
+ static_cast<KZipFileEntry *>(entry)->setHeaderStart( localheaderoffset );
+ //kdDebug(7040) << "KZipFileEntry created, entryName= " << entryName << ", name=" << name << endl;
+ d->m_fileList.append( static_cast<KZipFileEntry *>( entry ) );
+ }
+
+ if ( entry )
+ {
+ if ( pos == -1 )
+ {
+ rootDir()->addEntry(entry);
+ }
+ else
+ {
+ // In some tar files we can find dir/./file => call cleanDirPath
+ TQString path = TQDir::cleanDirPath( name.left( pos ) );
+ // Ensure container directory exists, create otherwise
+ KArchiveDirectory * tdir = findOrCreate( path );
+ tdir->addEntry(entry);
+ }
+ }
+
+ //calculate offset to next entry
+ offset += 46 + commlen + extralen + namelen;
+ bool b = dev->at(offset);
+ Q_ASSERT( b );
+ if ( !b )
+ return false;
+ }
+ else if ( startOfFile )
+ {
+ // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
+ // Therefore we need to find the first PK\003\004 (local header)
+ kdDebug(7040) << "Try to skip start of file" << endl;
+ startOfFile = false;
+ bool foundSignature = false;
+
+ while (!foundSignature)
+ {
+ n = dev->readBlock( buffer, 1 );
+ if (n < 1)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. " << k_funcinfo << endl;
+ return false;
+ }
+
+ if ( buffer[0] != 'P' )
+ continue;
+
+ n = dev->readBlock( buffer, 3 );
+ if (n < 3)
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. " << k_funcinfo << endl;
+ return false;
+ }
+
+ // We have to detect the magic token for a local header: PK\003\004
+ /*
+ * Note: we do not need to check the other magics, if the ZIP file has no
+ * local header, then it has not any files!
+ */
+ if ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 )
+ {
+ foundSignature = true;
+ dev->at( dev->at() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
+ }
+ else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
+ {
+ // We have another P character so we must go back a little to check if it is a magic
+ dev->at( dev->at() - 3 );
+ }
+ }
+ }
+ else
+ {
+ kdWarning(7040) << "Invalid ZIP file. Unrecognized header at offset " << offset << endl;
+
+ return false;
+ }
+ }
+ //kdDebug(7040) << "*** done *** " << endl;
+ return true;
+}
+
+bool KZip::closeArchive()
+{
+ if ( ! ( mode() & IO_WriteOnly ) )
+ {
+ //kdDebug(7040) << "closearchive readonly reached." << endl;
+ return true;
+ }
+
+ kdDebug() << k_funcinfo << "device=" << device() << endl;
+ //ReadWrite or WriteOnly
+ //write all central dir file entries
+
+ if ( !device() ) // saving aborted
+ return false;
+
+ // to be written at the end of the file...
+ char buffer[ 22 ]; // first used for 12, then for 22 at the end
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ TQ_LONG centraldiroffset = device()->at();
+ //kdDebug(7040) << "closearchive: centraldiroffset: " << centraldiroffset << endl;
+ TQ_LONG atbackup = centraldiroffset;
+ TQPtrListIterator<KZipFileEntry> it( d->m_fileList );
+
+ for ( ; it.current() ; ++it )
+ { //set crc and compressed size in each local file header
+ if ( !device()->at( it.current()->headerStart() + 14 ) )
+ return false;
+ //kdDebug(7040) << "closearchive setcrcandcsize: filename: "
+ // << it.current()->path()
+ // << " encoding: "<< it.current()->encoding() << endl;
+
+ uLong mycrc = it.current()->crc32();
+ buffer[0] = char(mycrc); // crc checksum, at headerStart+14
+ buffer[1] = char(mycrc >> 8);
+ buffer[2] = char(mycrc >> 16);
+ buffer[3] = char(mycrc >> 24);
+
+ int mysize1 = it.current()->compressedSize();
+ buffer[4] = char(mysize1); // compressed file size, at headerStart+18
+ buffer[5] = char(mysize1 >> 8);
+ buffer[6] = char(mysize1 >> 16);
+ buffer[7] = char(mysize1 >> 24);
+
+ int myusize = it.current()->size();
+ buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
+ buffer[9] = char(myusize >> 8);
+ buffer[10] = char(myusize >> 16);
+ buffer[11] = char(myusize >> 24);
+
+ if ( device()->writeBlock( buffer, 12 ) != 12 )
+ return false;
+ }
+ device()->at( atbackup );
+
+ for ( it.toFirst(); it.current() ; ++it )
+ {
+ //kdDebug(7040) << "closearchive: filename: " << it.current()->path()
+ // << " encoding: "<< it.current()->encoding() << endl;
+
+ TQCString path = TQFile::encodeName(it.current()->path());
+
+ const int extra_field_len = 9;
+ int bufferSize = extra_field_len + path.length() + 46;
+ char* buffer = new char[ bufferSize ];
+
+ memset(buffer, 0, 46); // zero is a nice default for most header fields
+
+ const char head[] =
+ {
+ 'P', 'K', 1, 2, // central file header signature
+ 0x14, 3, // version made by (3 == UNIX)
+ 0x14, 0 // version needed to extract
+ };
+
+ // I do not know why memcpy is not working here
+ //memcpy(buffer, head, sizeof(head));
+ tqmemmove(buffer, head, sizeof(head));
+
+ buffer[ 10 ] = char(it.current()->encoding()); // compression method
+ buffer[ 11 ] = char(it.current()->encoding() >> 8);
+
+ transformToMsDos( it.current()->datetime(), &buffer[ 12 ] );
+
+ uLong mycrc = it.current()->crc32();
+ buffer[ 16 ] = char(mycrc); // crc checksum
+ buffer[ 17 ] = char(mycrc >> 8);
+ buffer[ 18 ] = char(mycrc >> 16);
+ buffer[ 19 ] = char(mycrc >> 24);
+
+ int mysize1 = it.current()->compressedSize();
+ buffer[ 20 ] = char(mysize1); // compressed file size
+ buffer[ 21 ] = char(mysize1 >> 8);
+ buffer[ 22 ] = char(mysize1 >> 16);
+ buffer[ 23 ] = char(mysize1 >> 24);
+
+ int mysize = it.current()->size();
+ buffer[ 24 ] = char(mysize); // uncompressed file size
+ buffer[ 25 ] = char(mysize >> 8);
+ buffer[ 26 ] = char(mysize >> 16);
+ buffer[ 27 ] = char(mysize >> 24);
+
+ buffer[ 28 ] = char(it.current()->path().length()); // filename length
+ buffer[ 29 ] = char(it.current()->path().length() >> 8);
+
+ buffer[ 30 ] = char(extra_field_len);
+ buffer[ 31 ] = char(extra_field_len >> 8);
+
+ buffer[ 40 ] = char(it.current()->permissions());
+ buffer[ 41 ] = char(it.current()->permissions() >> 8);
+
+ int myhst = it.current()->headerStart();
+ buffer[ 42 ] = char(myhst); //relative offset of local header
+ buffer[ 43 ] = char(myhst >> 8);
+ buffer[ 44 ] = char(myhst >> 16);
+ buffer[ 45 ] = char(myhst >> 24);
+
+ // file name
+ strncpy( buffer + 46, path, path.length() );
+ //kdDebug(7040) << "closearchive length to write: " << bufferSize << endl;
+
+ // extra field
+ char *extfield = buffer + 46 + path.length();
+ extfield[0] = 'U';
+ extfield[1] = 'T';
+ extfield[2] = 5;
+ extfield[3] = 0;
+ extfield[4] = 1 | 2 | 4; // specify flags from local field
+ // (unless I misread the spec)
+ // provide only modification time
+ unsigned long time = (unsigned long)it.current()->date();
+ extfield[5] = char(time);
+ extfield[6] = char(time >> 8);
+ extfield[7] = char(time >> 16);
+ extfield[8] = char(time >> 24);
+
+ crc = crc32(crc, (Bytef *)buffer, bufferSize );
+ bool ok = ( device()->writeBlock( buffer, bufferSize ) == bufferSize );
+ delete[] buffer;
+ if ( !ok )
+ return false;
+ }
+ TQ_LONG centraldirendoffset = device()->at();
+ //kdDebug(7040) << "closearchive: centraldirendoffset: " << centraldirendoffset << endl;
+ //kdDebug(7040) << "closearchive: device()->at(): " << device()->at() << endl;
+
+ //write end of central dir record.
+ buffer[ 0 ] = 'P'; //end of central dir signature
+ buffer[ 1 ] = 'K';
+ buffer[ 2 ] = 5;
+ buffer[ 3 ] = 6;
+
+ buffer[ 4 ] = 0; // number of this disk
+ buffer[ 5 ] = 0;
+
+ buffer[ 6 ] = 0; // number of disk with start of central dir
+ buffer[ 7 ] = 0;
+
+ int count = d->m_fileList.count();
+ //kdDebug(7040) << "number of files (count): " << count << endl;
+
+
+ buffer[ 8 ] = char(count); // total number of entries in central dir of
+ buffer[ 9 ] = char(count >> 8); // this disk
+
+ buffer[ 10 ] = buffer[ 8 ]; // total number of entries in the central dir
+ buffer[ 11 ] = buffer[ 9 ];
+
+ int cdsize = centraldirendoffset - centraldiroffset;
+ buffer[ 12 ] = char(cdsize); // size of the central dir
+ buffer[ 13 ] = char(cdsize >> 8);
+ buffer[ 14 ] = char(cdsize >> 16);
+ buffer[ 15 ] = char(cdsize >> 24);
+
+ //kdDebug(7040) << "end : centraldiroffset: " << centraldiroffset << endl;
+ //kdDebug(7040) << "end : centraldirsize: " << cdsize << endl;
+
+ buffer[ 16 ] = char(centraldiroffset); // central dir offset
+ buffer[ 17 ] = char(centraldiroffset >> 8);
+ buffer[ 18 ] = char(centraldiroffset >> 16);
+ buffer[ 19 ] = char(centraldiroffset >> 24);
+
+ buffer[ 20 ] = 0; //zipfile comment length
+ buffer[ 21 ] = 0;
+
+ if ( device()->writeBlock( buffer, 22 ) != 22 )
+ return false;
+
+ if ( d->m_saveFile ) {
+ d->m_saveFile->close();
+ setDevice( 0 );
+ delete d->m_saveFile;
+ d->m_saveFile = 0;
+ }
+
+ //kdDebug(7040) << __FILE__" reached." << endl;
+ return true;
+}
+
+// Doesn't need to be reimplemented anymore. Remove for KDE-4.0
+bool KZip::writeFile( const TQString& name, const TQString& user, const TQString& group, uint size, const char* data )
+{
+ mode_t mode = 0100644;
+ time_t the_time = time(0);
+ return KArchive::writeFile( name, user, group, size, mode, the_time,
+ the_time, the_time, data );
+}
+
+// Doesn't need to be reimplemented anymore. Remove for KDE-4.0
+bool KZip::writeFile( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime,
+ const char* data ) {
+ return KArchive::writeFile(name, user, group, size, perm, atime, mtime,
+ ctime, data);
+}
+
+// Doesn't need to be reimplemented anymore. Remove for KDE-4.0
+bool KZip::prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size )
+{
+ mode_t dflt_perm = 0100644;
+ time_t the_time = time(0);
+ return prepareWriting(name,user,group,size,dflt_perm,
+ the_time,the_time,the_time);
+}
+
+// Doesn't need to be reimplemented anymore. Remove for KDE-4.0
+bool KZip::prepareWriting(const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime) {
+ return KArchive::prepareWriting(name,user,group,size,perm,atime,mtime,ctime);
+}
+
+bool KZip::prepareWriting_impl(const TQString &name, const TQString &user,
+ const TQString &group, uint /*size*/, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime) {
+ //kdDebug(7040) << "prepareWriting reached." << endl;
+ if ( !isOpened() )
+ {
+ tqWarning( "KZip::writeFile: You must open the zip file before writing to it\n");
+ return false;
+ }
+
+ if ( ! ( mode() & IO_WriteOnly ) ) // accept WriteOnly and ReadWrite
+ {
+ tqWarning( "KZip::writeFile: You must open the zip file for writing\n");
+ return false;
+ }
+
+ if ( !device() ) { // aborted
+ //kdWarning(7040) << "prepareWriting_impl: no device" << endl;
+ return false;
+ }
+
+ // set right offset in zip.
+ if ( !device()->at( d->m_offset ) ) {
+ kdWarning(7040) << "prepareWriting_impl: cannot seek in ZIP file. Disk full?" << endl;
+ abort();
+ return false;
+ }
+
+ // delete entries in the filelist with the same filename as the one we want
+ // to save, so that we don�t have duplicate file entries when viewing the zip
+ // with konqi...
+ // CAUTION: the old file itself is still in the zip and won't be removed !!!
+ TQPtrListIterator<KZipFileEntry> it( d->m_fileList );
+
+ //kdDebug(7040) << "filename to write: " << name <<endl;
+ for ( ; it.current() ; ++it )
+ {
+ //kdDebug(7040) << "prepfilename: " << it.current()->path() <<endl;
+ if (name == it.current()->path() )
+ {
+ //kdDebug(7040) << "removing following entry: " << it.current()->path() <<endl;
+ d->m_fileList.remove();
+ }
+
+ }
+ // Find or create parent dir
+ KArchiveDirectory* parentDir = rootDir();
+ TQString fileName( name );
+ int i = name.findRev( '/' );
+ if ( i != -1 )
+ {
+ TQString dir = name.left( i );
+ fileName = name.mid( i + 1 );
+ //kdDebug(7040) << "KZip::prepareWriting ensuring " << dir << " exists. fileName=" << fileName << endl;
+ parentDir = findOrCreate( dir );
+ }
+
+ // construct a KZipFileEntry and add it to list
+ KZipFileEntry * e = new KZipFileEntry( this, fileName, perm, mtime, user, group, TQString::null,
+ name, device()->at() + 30 + name.length(), // start
+ 0 /*size unknown yet*/, d->m_compression, 0 /*csize unknown yet*/ );
+ e->setHeaderStart( device()->at() );
+ //kdDebug(7040) << "wrote file start: " << e->position() << " name: " << name << endl;
+ parentDir->addEntry( e );
+
+ d->m_currentFile = e;
+ d->m_fileList.append( e );
+
+ int extra_field_len = 0;
+ if ( d->m_extraField == ModificationTime )
+ extra_field_len = 17; // value also used in doneWriting()
+
+ // write out zip header
+ TQCString encodedName = TQFile::encodeName(name);
+ int bufferSize = extra_field_len + encodedName.length() + 30;
+ //kdDebug(7040) << "KZip::prepareWriting bufferSize=" << bufferSize << endl;
+ char* buffer = new char[ bufferSize ];
+
+ buffer[ 0 ] = 'P'; //local file header signature
+ buffer[ 1 ] = 'K';
+ buffer[ 2 ] = 3;
+ buffer[ 3 ] = 4;
+
+ buffer[ 4 ] = 0x14; // version needed to extract
+ buffer[ 5 ] = 0;
+
+ buffer[ 6 ] = 0; // general purpose bit flag
+ buffer[ 7 ] = 0;
+
+ buffer[ 8 ] = char(e->encoding()); // compression method
+ buffer[ 9 ] = char(e->encoding() >> 8);
+
+ transformToMsDos( e->datetime(), &buffer[ 10 ] );
+
+ buffer[ 14 ] = 'C'; //dummy crc
+ buffer[ 15 ] = 'R';
+ buffer[ 16 ] = 'C';
+ buffer[ 17 ] = 'q';
+
+ buffer[ 18 ] = 'C'; //compressed file size
+ buffer[ 19 ] = 'S';
+ buffer[ 20 ] = 'I';
+ buffer[ 21 ] = 'Z';
+
+ buffer[ 22 ] = 'U'; //uncompressed file size
+ buffer[ 23 ] = 'S';
+ buffer[ 24 ] = 'I';
+ buffer[ 25 ] = 'Z';
+
+ buffer[ 26 ] = (uchar)(encodedName.length()); //filename length
+ buffer[ 27 ] = (uchar)(encodedName.length() >> 8);
+
+ buffer[ 28 ] = (uchar)(extra_field_len); // extra field length
+ buffer[ 29 ] = (uchar)(extra_field_len >> 8);
+
+ // file name
+ strncpy( buffer + 30, encodedName, encodedName.length() );
+
+ // extra field
+ if ( d->m_extraField == ModificationTime )
+ {
+ char *extfield = buffer + 30 + encodedName.length();
+ // "Extended timestamp" header (0x5455)
+ extfield[0] = 'U';
+ extfield[1] = 'T';
+ extfield[2] = 13; // data size
+ extfield[3] = 0;
+ extfield[4] = 1 | 2 | 4; // contains mtime, atime, ctime
+
+ extfield[5] = char(mtime);
+ extfield[6] = char(mtime >> 8);
+ extfield[7] = char(mtime >> 16);
+ extfield[8] = char(mtime >> 24);
+
+ extfield[9] = char(atime);
+ extfield[10] = char(atime >> 8);
+ extfield[11] = char(atime >> 16);
+ extfield[12] = char(atime >> 24);
+
+ extfield[13] = char(ctime);
+ extfield[14] = char(ctime >> 8);
+ extfield[15] = char(ctime >> 16);
+ extfield[16] = char(ctime >> 24);
+ }
+
+ // Write header
+ bool b = (device()->writeBlock( buffer, bufferSize ) == bufferSize );
+ d->m_crc = 0L;
+ delete[] buffer;
+
+ Q_ASSERT( b );
+ if (!b) {
+ abort();
+ return false;
+ }
+
+ // Prepare device for writing the data
+ // Either device() if no compression, or a KFilterDev to compress
+ if ( d->m_compression == 0 ) {
+ d->m_currentDev = device();
+ return true;
+ }
+
+ d->m_currentDev = KFilterDev::device( device(), "application/x-gzip", false );
+ Q_ASSERT( d->m_currentDev );
+ if ( !d->m_currentDev ) {
+ abort();
+ return false; // ouch
+ }
+ static_cast<KFilterDev *>(d->m_currentDev)->setSkipHeaders(); // Just zlib, not gzip
+
+ b = d->m_currentDev->open( IO_WriteOnly );
+ Q_ASSERT( b );
+ return b;
+}
+
+bool KZip::doneWriting( uint size )
+{
+ if ( d->m_currentFile->encoding() == 8 ) {
+ // Finish
+ (void)d->m_currentDev->writeBlock( 0, 0 );
+ delete d->m_currentDev;
+ }
+ // If 0, d->m_currentDev was device() - don't delete ;)
+ d->m_currentDev = 0L;
+
+ Q_ASSERT( d->m_currentFile );
+ //kdDebug(7040) << "donewriting reached." << endl;
+ //kdDebug(7040) << "filename: " << d->m_currentFile->path() << endl;
+ //kdDebug(7040) << "getpos (at): " << device()->at() << endl;
+ d->m_currentFile->setSize(size);
+ int extra_field_len = 0;
+ if ( d->m_extraField == ModificationTime )
+ extra_field_len = 17; // value also used in doneWriting()
+
+ int csize = device()->at() -
+ d->m_currentFile->headerStart() - 30 -
+ d->m_currentFile->path().length() - extra_field_len;
+ d->m_currentFile->setCompressedSize(csize);
+ //kdDebug(7040) << "usize: " << d->m_currentFile->size() << endl;
+ //kdDebug(7040) << "csize: " << d->m_currentFile->compressedSize() << endl;
+ //kdDebug(7040) << "headerstart: " << d->m_currentFile->headerStart() << endl;
+
+ //kdDebug(7040) << "crc: " << d->m_crc << endl;
+ d->m_currentFile->setCRC32( d->m_crc );
+
+ d->m_currentFile = 0L;
+
+ // update saved offset for appending new files
+ d->m_offset = device()->at();
+ return true;
+}
+
+bool KZip::writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime) {
+ return KArchive::writeSymLink(name,target,user,group,perm,atime,mtime,ctime);
+}
+
+bool KZip::writeSymLink_impl(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime) {
+
+ // reassure that symlink flag is set, otherwise strange things happen on
+ // extraction
+ perm |= S_IFLNK;
+ Compression c = compression();
+ setCompression(NoCompression); // link targets are never compressed
+
+ if (!prepareWriting(name, user, group, 0, perm, atime, mtime, ctime)) {
+ kdWarning() << "KZip::writeFile prepareWriting failed" << endl;
+ setCompression(c);
+ return false;
+ }
+
+ TQCString symlink_target = TQFile::encodeName(target);
+ if (!writeData(symlink_target, symlink_target.length())) {
+ kdWarning() << "KZip::writeFile writeData failed" << endl;
+ setCompression(c);
+ return false;
+ }
+
+ if (!doneWriting(symlink_target.length())) {
+ kdWarning() << "KZip::writeFile doneWriting failed" << endl;
+ setCompression(c);
+ return false;
+ }
+
+ setCompression(c);
+ return true;
+}
+
+void KZip::virtual_hook( int id, void* data )
+{
+ switch (id) {
+ case VIRTUAL_WRITE_DATA: {
+ WriteDataParams* params = reinterpret_cast<WriteDataParams *>(data);
+ params->retval = writeData_impl( params->data, params->size );
+ break;
+ }
+ case VIRTUAL_WRITE_SYMLINK: {
+ WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
+ params->retval = writeSymLink_impl(*params->name,*params->target,
+ *params->user,*params->group,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ case VIRTUAL_PREPARE_WRITING: {
+ PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
+ params->retval = prepareWriting_impl(*params->name,*params->user,
+ *params->group,params->size,params->perm,
+ params->atime,params->mtime,params->ctime);
+ break;
+ }
+ default:
+ KArchive::virtual_hook( id, data );
+ }/*end switch*/
+}
+
+// made virtual using virtual_hook
+bool KZip::writeData(const char * c, uint i)
+{
+ return KArchive::writeData( c, i );
+}
+
+bool KZip::writeData_impl(const char * c, uint i)
+{
+ Q_ASSERT( d->m_currentFile );
+ Q_ASSERT( d->m_currentDev );
+ if (!d->m_currentFile || !d->m_currentDev) {
+ abort();
+ return false;
+ }
+
+ // crc to be calculated over uncompressed stuff...
+ // and they didn't mention it in their docs...
+ d->m_crc = crc32(d->m_crc, (const Bytef *) c , i);
+
+ TQ_LONG written = d->m_currentDev->writeBlock( c, i );
+ //kdDebug(7040) << "KZip::writeData wrote " << i << " bytes." << endl;
+ bool ok = written == (TQ_LONG)i;
+ if ( !ok )
+ abort();
+ return ok;
+}
+
+void KZip::setCompression( Compression c )
+{
+ d->m_compression = ( c == NoCompression ) ? 0 : 8;
+}
+
+KZip::Compression KZip::compression() const
+{
+ return ( d->m_compression == 8 ) ? DeflateCompression : NoCompression;
+}
+
+void KZip::setExtraField( ExtraField ef )
+{
+ d->m_extraField = ef;
+}
+
+KZip::ExtraField KZip::extraField() const
+{
+ return d->m_extraField;
+}
+
+void KZip::abort()
+{
+ if ( d->m_saveFile ) {
+ d->m_saveFile->abort();
+ setDevice( 0 );
+ }
+}
+
+
+///////////////
+
+TQByteArray KZipFileEntry::data() const
+{
+ TQIODevice* dev = device();
+ TQByteArray arr;
+ if ( dev ) {
+ arr = dev->readAll();
+ delete dev;
+ }
+ return arr;
+}
+
+TQIODevice* KZipFileEntry::device() const
+{
+ //kdDebug(7040) << "KZipFileEntry::device creating iodevice limited to pos=" << position() << ", csize=" << compressedSize() << endl;
+ // Limit the reading to the appropriate part of the underlying device (e.g. file)
+ KLimitedIODevice* limitedDev = new KLimitedIODevice( archive()->device(), position(), compressedSize() );
+ if ( encoding() == 0 || compressedSize() == 0 ) // no compression (or even no data)
+ return limitedDev;
+
+ if ( encoding() == 8 )
+ {
+ // On top of that, create a device that uncompresses the zlib data
+ TQIODevice* filterDev = KFilterDev::device( limitedDev, "application/x-gzip" );
+ if ( !filterDev )
+ return 0L; // ouch
+ static_cast<KFilterDev *>(filterDev)->setSkipHeaders(); // Just zlib, not gzip
+ bool b = filterDev->open( IO_ReadOnly );
+ Q_ASSERT( b );
+ return filterDev;
+ }
+
+ kdError() << "This zip file contains files compressed with method "
+ << encoding() <<", this method is currently not supported by KZip,"
+ <<" please use a command-line tool to handle this file." << endl;
+ return 0L;
+}
diff --git a/tdeio/tdeio/kzip.h b/tdeio/tdeio/kzip.h
new file mode 100644
index 000000000..333736e21
--- /dev/null
+++ b/tdeio/tdeio/kzip.h
@@ -0,0 +1,284 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Holger Schroeder <holger-kde@holgis.net>
+
+ 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 __kzip_h
+#define __kzip_h
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqdict.h>
+#include <tqvaluelist.h>
+#include <karchive.h>
+
+class KZipFileEntry;
+/**
+ * This class implements a tdeioslave to access zip files from KDE.
+ * You can use it in IO_ReadOnly or in IO_WriteOnly mode, and it
+ * behaves just as expected.
+ * It can also be used in IO_ReadWrite mode, in this case one can
+ * append files to an existing zip archive. When you append new files, which
+ * are not yet in the zip, it works as expected, i.e. the files are appended at the end.
+ * When you append a file, which is already in the file, the reference to the
+ * old file is dropped and the new one is added to the zip - but the
+ * old data from the file itself is not deleted, it is still in the
+ * zipfile. so when you want to have a small and garbage-free zipfile,
+ * just read the contents of the appended zip file and write it to a new one
+ * in IO_WriteOnly mode. This is especially important when you don't want
+ * to leak information of how intermediate versions of files in the zip
+ * were looking.
+ * For more information on the zip fileformat go to
+ * http://www.pkware.com/products/enterprise/white_papers/appnote.html
+ * @short A class for reading/writing zip archives.
+ * @author Holger Schroeder <holger-kde@holgis.net>
+ * @since 3.1
+ */
+class TDEIO_EXPORT KZip : public KArchive
+{
+public:
+ /**
+ * Creates an instance that operates on the given filename.
+ * using the compression filter associated to given mimetype.
+ *
+ * @param filename is a local path (e.g. "/home/holger/myfile.zip")
+ */
+ KZip( const TQString& filename );
+
+ /**
+ * Creates an instance that operates on the given device.
+ * The device can be compressed (KFilterDev) or not (TQFile, etc.).
+ * @warning Do not assume that giving a TQFile here will decompress the file,
+ * in case it's compressed!
+ * @param dev the device to access
+ */
+ KZip( TQIODevice * dev );
+
+ /**
+ * If the zip file is still opened, then it will be
+ * closed automatically by the destructor.
+ */
+ virtual ~KZip();
+
+ /**
+ * The name of the zip file, as passed to the constructor.
+ * Null if you used the TQIODevice constructor.
+ * @return the zip's file name, or null if a TQIODevice is used
+ */
+ TQString fileName() { return m_filename; }
+
+ /**
+ * Describes the contents of the "extra field" for a given file in the Zip archive.
+ */
+ enum ExtraField { NoExtraField = 0, ///< No extra field
+ ModificationTime = 1, ///< Modification time ("extended timestamp" header)
+ DefaultExtraField = 1
+ };
+
+ /**
+ * Call this before writeFile or prepareWriting, to define what the next
+ * file to be written should have in its extra field.
+ * @param ef the type of "extra field"
+ * @see extraField()
+ */
+ void setExtraField( ExtraField ef );
+
+ /**
+ * The current type of "extra field" that will be used for new files.
+ * @return the current type of "extra field"
+ * @see setExtraField()
+ */
+ ExtraField extraField() const;
+
+ /**
+ * Describes the compression type for a given file in the Zip archive.
+ */
+ enum Compression { NoCompression = 0, ///< Uncompressed.
+ DeflateCompression = 1 ///< Deflate compression method.
+ };
+
+
+ /**
+ * Call this before writeFile or prepareWriting, to define whether the next
+ * files to be written should be compressed or not.
+ * @param c the new compression mode
+ * @see compression()
+ */
+ void setCompression( Compression c );
+
+ /**
+ * The current compression mode that will be used for new files.
+ * @return the current compression mode
+ * @see setCompression()
+ */
+ Compression compression() const;
+
+ /**
+ * If an archive is opened for writing then you can add a new file
+ * using this function.
+ * This method takes the whole data at once.
+ * @param name can include subdirs e.g. path/to/the/file
+ * @param user the user owning the file
+ * @param group the group owning the file
+ * @param size the size of the file
+ * @param data a pointer to the data
+ * @return true if successful, false otherwise
+ */
+ virtual bool writeFile( const TQString& name, const TQString& user, const TQString& group, uint size, const char* data ); // BC: remove reimplementation for KDE-4.0
+
+ /**
+ * Alternative method for writing: call prepareWriting(), then feed the data
+ * in small chunks using writeData(), and call doneWriting() when done.
+ * @param name can include subdirs e.g. path/to/the/file
+ * @param user the user owning the file
+ * @param group the group owning the file
+ * @param size unused argument
+ * @return true if successful, false otherwise
+ */
+ virtual bool prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size );
+
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool writeSymLink(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool prepareWriting( const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime );
+ // TODO(BIC) make virtual. For now it must be implemented by virtual_hook.
+ bool writeFile( const TQString& name, const TQString& user, const TQString& group,
+ uint size, mode_t perm, time_t atime, time_t mtime,
+ time_t ctime, const char* data );
+ /**
+ * Write data to a file that has been created using prepareWriting().
+ * @param data a pointer to the data
+ * @param size the size of the chunk
+ * @return true if successful, false otherwise
+ */
+ bool writeData( const char* data, uint size ); // TODO make virtual
+
+ /**
+ * Write data to a file that has been created using prepareWriting().
+ * @param size the size of the file
+ * @return true if successful, false otherwise
+ */
+ virtual bool doneWriting( uint size );
+
+protected:
+ /**
+ * Opens the archive for reading.
+ * Parses the directory listing of the archive
+ * and creates the KArchiveDirectory/KArchiveFile entries.
+ * @param mode the mode of the file
+ */
+ virtual bool openArchive( int mode );
+ /// Closes the archive
+ virtual bool closeArchive();
+
+ /**
+ * @internal Not needed for zip
+ */
+ virtual bool writeDir( const TQString& name, const TQString& user, const TQString& group) { Q_UNUSED(name); Q_UNUSED(user); Q_UNUSED(group); return true; }
+ // TODO(BIC) uncomment and make virtual for KDE 4.
+// bool writeDir( const TQString& name, const TQString& user, const TQString& group,
+// mode_t perm, time_t atime, time_t mtime, time_t ctime );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+ /** @internal for virtual_hook */
+ // from KArchive
+ bool writeData_impl( const char* data, uint size );
+ bool prepareWriting_impl(const TQString& name, const TQString& user,
+ const TQString& group, uint size, mode_t perm,
+ time_t atime, time_t mtime, time_t ctime);
+ bool writeSymLink_impl(const TQString &name, const TQString &target,
+ const TQString &user, const TQString &group,
+ mode_t perm, time_t atime, time_t mtime, time_t ctime);
+private:
+ void abort();
+
+private:
+ TQString m_filename;
+ class KZipPrivate;
+ KZipPrivate * d;
+};
+
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT KZipFileEntry : public KArchiveFile
+{
+public:
+ /*KZipFileEntry() : st(-1)
+ {}*/
+ KZipFileEntry( KZip* zip, const TQString& name, int access, int date,
+ const TQString& user, const TQString& group, const TQString& symlink,
+ const TQString& path, TQ_LONG start, TQ_LONG uncompressedSize,
+ int encoding, TQ_LONG compressedSize) :
+ KArchiveFile( zip, name, access, date, user, group, symlink,
+ start, uncompressedSize ),
+ m_crc(0),
+ m_compressedSize(compressedSize),
+ m_headerStart(0),
+ m_encoding(encoding),
+ m_path( path )
+ {}
+ int encoding() const { return m_encoding; }
+ TQ_LONG compressedSize() const { return m_compressedSize; }
+
+ /// Only used when writing
+ void setCompressedSize(TQ_LONG compressedSize) { m_compressedSize = compressedSize; }
+
+ /// Header start: only used when writing
+ void setHeaderStart(TQ_LONG headerstart) { m_headerStart = headerstart; }
+ TQ_LONG headerStart() const {return m_headerStart; }
+
+ /// CRC: only used when writing
+ unsigned long crc32() const { return m_crc; }
+ void setCRC32(unsigned long crc32) { m_crc=crc32; }
+
+ /// Name with complete path - KArchiveFile::name() is the filename only (no path)
+ TQString path() const { return m_path; }
+
+ /**
+ * @return the content of this file.
+ * Call data() with care (only once per file), this data isn't cached.
+ */
+ virtual TQByteArray data() const;
+
+ /**
+ * This method returns a TQIODevice to read the file contents.
+ * This is obviously for reading only.
+ * Note that the ownership of the device is being transferred to the caller,
+ * who will have to delete it.
+ * The returned device auto-opens (in readonly mode), no need to open it.
+ */
+ TQIODevice* device() const; // WARNING, not virtual!
+
+private:
+ unsigned long m_crc;
+ TQ_LONG m_compressedSize;
+ TQ_LONG m_headerStart;
+ int m_encoding;
+ TQString m_path;
+ // KDE4: d pointer or at least some int for future extensions
+};
+
+#endif
diff --git a/tdeio/tdeio/lex.c b/tdeio/tdeio/lex.c
new file mode 100644
index 000000000..99848a2f3
--- /dev/null
+++ b/tdeio/tdeio/lex.c
@@ -0,0 +1,1759 @@
+#define yy_create_buffer kiotrader_create_buffer
+#define yy_delete_buffer kiotrader_delete_buffer
+#define yy_scan_buffer kiotrader_scan_buffer
+#define yy_scan_string kiotrader_scan_string
+#define yy_scan_bytes kiotrader_scan_bytes
+#define yy_flex_debug kiotrader_flex_debug
+#define yy_init_buffer kiotrader_init_buffer
+#define yy_flush_buffer kiotrader_flush_buffer
+#define yy_load_buffer_state kiotrader_load_buffer_state
+#define yy_switch_to_buffer kiotrader_switch_to_buffer
+#define yyin kiotraderin
+#define yyleng kiotraderleng
+#define yylex kiotraderlex
+#define yyout kiotraderout
+#define yyrestart kiotraderrestart
+#define yytext kiotradertext
+#define yywrap kiotraderwrap
+
+#line 20 "lex.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+#include <unistd.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 25
+#define YY_END_OF_BUFFER 26
+static yyconst short int yy_accept[63] =
+ { 0,
+ 0, 0, 26, 24, 23, 23, 24, 24, 14, 14,
+ 24, 19, 3, 14, 4, 22, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 23, 2, 0, 17, 18,
+ 20, 0, 19, 5, 1, 6, 22, 22, 22, 0,
+ 22, 22, 10, 22, 22, 22, 9, 22, 22, 0,
+ 21, 8, 22, 12, 13, 7, 22, 15, 22, 16,
+ 11, 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 1, 1, 1, 1, 1, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 1, 1, 15,
+ 16, 17, 1, 1, 18, 19, 19, 19, 20, 21,
+ 19, 19, 19, 19, 19, 22, 19, 19, 19, 19,
+ 19, 23, 24, 25, 26, 19, 19, 19, 19, 19,
+ 27, 1, 28, 1, 1, 1, 29, 19, 19, 30,
+
+ 31, 19, 19, 19, 32, 19, 19, 19, 33, 34,
+ 35, 19, 19, 36, 37, 38, 19, 19, 19, 39,
+ 19, 19, 1, 1, 1, 40, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[41] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 1, 1, 3, 1, 1, 1, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 1, 2, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 1
+ } ;
+
+static yyconst short int yy_base[67] =
+ { 0,
+ 0, 0, 95, 96, 39, 41, 78, 88, 96, 78,
+ 77, 33, 74, 73, 72, 0, 69, 63, 0, 51,
+ 45, 49, 17, 47, 45, 48, 96, 75, 96, 65,
+ 64, 63, 40, 96, 96, 96, 0, 54, 49, 46,
+ 43, 40, 0, 32, 36, 31, 0, 44, 47, 38,
+ 96, 0, 28, 0, 0, 0, 44, 0, 15, 0,
+ 0, 96, 54, 56, 44, 59
+ } ;
+
+static yyconst short int yy_def[67] =
+ { 0,
+ 62, 1, 62, 62, 62, 62, 62, 63, 62, 62,
+ 62, 62, 62, 62, 62, 64, 64, 64, 65, 64,
+ 64, 64, 64, 64, 64, 62, 62, 63, 62, 62,
+ 62, 62, 62, 62, 62, 62, 64, 64, 64, 66,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 66,
+ 62, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 0, 62, 62, 62, 62
+ } ;
+
+static yyconst short int yy_nxt[137] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 9, 9, 9, 9,
+ 10, 11, 9, 12, 13, 14, 15, 16, 16, 16,
+ 17, 16, 16, 16, 18, 16, 19, 4, 20, 16,
+ 21, 22, 23, 24, 25, 16, 16, 16, 16, 9,
+ 26, 26, 26, 26, 32, 44, 33, 40, 45, 26,
+ 26, 32, 61, 33, 28, 28, 28, 28, 37, 37,
+ 50, 50, 50, 60, 59, 51, 58, 57, 56, 55,
+ 54, 53, 52, 51, 49, 48, 31, 31, 30, 29,
+ 47, 46, 43, 42, 41, 39, 38, 36, 35, 34,
+ 31, 30, 29, 27, 62, 3, 62, 62, 62, 62,
+
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62
+ } ;
+
+static yyconst short int yy_chk[137] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 5, 5, 6, 6, 12, 23, 12, 65, 23, 26,
+ 26, 33, 59, 33, 63, 63, 63, 63, 64, 64,
+ 66, 66, 66, 57, 53, 50, 49, 48, 46, 45,
+ 44, 42, 41, 40, 39, 38, 32, 31, 30, 28,
+ 25, 24, 22, 21, 20, 18, 17, 15, 14, 13,
+ 11, 10, 8, 7, 3, 62, 62, 62, 62, 62,
+
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lex.l"
+#define INITIAL 0
+#line 2 "lex.l"
+#define yylval kiotraderlval
+#define yywrap kiotraderwrap
+
+#include "yacc.h"
+#include <string.h>
+#include <stdlib.h>
+#define YY_NO_UNPUT
+
+char* KTraderParse_putSymbol( char *_name );
+char *KTraderParse_putSymbolInBrackets( char *_name );
+char* KTraderParse_putString( char *_name );
+int yywrap();
+int kiotraderlex(void);
+void KTraderParse_initFlex( const char *_code );
+
+#line 447 "lex.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 21 "lex.l"
+
+
+#line 601 "lex.c"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 63 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 96 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 23 "lex.l"
+{ return EQ; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 24 "lex.l"
+{ return NEQ; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 25 "lex.l"
+{ return LE; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 26 "lex.l"
+{ return GR; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 27 "lex.l"
+{ return LEQ; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 28 "lex.l"
+{ return GEQ; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 29 "lex.l"
+{ return NOT; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 30 "lex.l"
+{ return AND; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 31 "lex.l"
+{ return OR; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 32 "lex.l"
+{ return TOKEN_IN; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 33 "lex.l"
+{ return EXIST; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 34 "lex.l"
+{ return MAX; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 35 "lex.l"
+{ return MIN; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 37 "lex.l"
+{ yylval.name = 0L; return (int)(*yytext); }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 39 "lex.l"
+{ yylval.valb = 1; return VAL_BOOL; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 40 "lex.l"
+{ yylval.valb = 0; return VAL_BOOL; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 42 "lex.l"
+{ yylval.name = KTraderParse_putString( yytext ); return VAL_STRING; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 44 "lex.l"
+{ yylval.vali = atoi( yytext ); return VAL_NUM; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 45 "lex.l"
+{ yylval.vali = atoi( yytext ); return VAL_NUM; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 47 "lex.l"
+{ yylval.vald = atof( yytext ); return VAL_FLOAT; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 49 "lex.l"
+{ yylval.name = KTraderParse_putSymbolInBrackets( yytext ); return VAL_ID; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 51 "lex.l"
+{ yylval.name = KTraderParse_putSymbol( yytext ); return VAL_ID; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 53 "lex.l"
+/* eat up whitespace */
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 55 "lex.l"
+{ printf( "Unrecognized character: %s\n", yytext ); }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 57 "lex.l"
+ECHO;
+ YY_BREAK
+#line 809 "lex.c"
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 63 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 63 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 62);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "[lex] %s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 57 "lex.l"
+
+
+char* KTraderParse_putSymbolInBrackets( char *_name )
+{
+ int l = strlen( _name )-1;
+ char *p = (char *)malloc( l );
+ if (p != NULL)
+ {
+ strncpy( p, _name+1, l-1 );
+ p[l-1] = 0;
+ }
+
+ return p;
+}
+
+char *KTraderParse_putSymbol( char *_name )
+{
+ char *p = (char*)malloc( strlen( _name ) + 1 );
+ if (p != NULL)
+ {
+ strcpy( p, _name );
+ }
+ return p;
+}
+
+char* KTraderParse_putString( char *_str )
+{
+ int l = strlen( _str );
+ char *p = (char*)malloc( l );
+ char *s = _str + 1;
+ char *d = p;
+
+ if (p == NULL)
+ return NULL;
+
+ while ( s != _str + l - 1 )
+ {
+ if ( *s != '\\' )
+ *d++ = *s++;
+ else
+ {
+ s++;
+ if ( s != _str + l - 1 )
+ {
+ if ( *s == '\\' )
+ *d++ = '\\';
+ else if ( *s == 'n' )
+ *d++ = '\n';
+ else if ( *s == 'r' )
+ *d++ = '\r';
+ else if ( *s == 't' )
+ *d++ = '\t';
+ s++;
+ }
+ }
+ }
+ *d = 0;
+ return p;
+}
+
+void KTraderParse_initFlex( const char *_code )
+{
+ yy_switch_to_buffer( yy_scan_string( _code ) );
+}
+
+int yywrap()
+{
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ return 1;
+}
diff --git a/tdeio/tdeio/lex.l b/tdeio/tdeio/lex.l
new file mode 100644
index 000000000..073a34965
--- /dev/null
+++ b/tdeio/tdeio/lex.l
@@ -0,0 +1,126 @@
+%{
+#define yylval kiotraderlval
+#define yywrap kiotraderwrap
+
+#include "yacc.h"
+#include <string.h>
+#include <stdlib.h>
+#define YY_NO_UNPUT
+
+char* KTraderParse_putSymbol( char *_name );
+char *KTraderParse_putSymbolInBrackets( char *_name );
+char* KTraderParse_putString( char *_name );
+int yywrap();
+int kiotraderlex(void);
+void KTraderParse_initFlex( const char *_code );
+
+%}
+
+DIGIT [0-9]
+
+%%
+
+"==" { return EQ; }
+"!=" { return NEQ; }
+"<" { return LE; }
+">" { return GR; }
+"<=" { return LEQ; }
+">=" { return GEQ; }
+"not" { return NOT; }
+"and" { return AND; }
+"or" { return OR; }
+"in" { return TOKEN_IN; }
+"exist" { return EXIST; }
+"max" { return MAX; }
+"min" { return MIN; }
+
+"~"|"/"|"+"|"-"|"="|"*"|"("|")"|"," { yylval.name = 0L; return (int)(*yytext); }
+
+"TRUE" { yylval.valb = 1; return VAL_BOOL; }
+"FALSE" { yylval.valb = 0; return VAL_BOOL; }
+
+"'"[^']*"'" { yylval.name = KTraderParse_putString( yytext ); return VAL_STRING; }
+
+"-"{DIGIT}+ { yylval.vali = atoi( yytext ); return VAL_NUM; }
+{DIGIT}+ { yylval.vali = atoi( yytext ); return VAL_NUM; }
+
+{DIGIT}*"\."{DIGIT}+ { yylval.vald = atof( yytext ); return VAL_FLOAT; }
+
+\[[a-zA-Z][a-zA-Z0-9\-]*\] { yylval.name = KTraderParse_putSymbolInBrackets( yytext ); return VAL_ID; }
+
+[a-zA-Z][a-zA-Z0-9]* { yylval.name = KTraderParse_putSymbol( yytext ); return VAL_ID; }
+
+[ \t\n]+ /* eat up whitespace */
+
+. { printf( "Unrecognized character: %s\n", yytext ); }
+
+%%
+
+char* KTraderParse_putSymbolInBrackets( char *_name )
+{
+ int l = strlen( _name )-1;
+ char *p = (char *)malloc( l );
+ if (p != NULL)
+ {
+ strncpy( p, _name+1, l-1 );
+ p[l-1] = 0;
+ }
+
+ return p;
+}
+
+char *KTraderParse_putSymbol( char *_name )
+{
+ char *p = (char*)malloc( strlen( _name ) + 1 );
+ if (p != NULL)
+ {
+ strcpy( p, _name );
+ }
+ return p;
+}
+
+char* KTraderParse_putString( char *_str )
+{
+ int l = strlen( _str );
+ char *p = (char*)malloc( l );
+ char *s = _str + 1;
+ char *d = p;
+
+ if (p == NULL)
+ return NULL;
+
+ while ( s != _str + l - 1 )
+ {
+ if ( *s != '\\' )
+ *d++ = *s++;
+ else
+ {
+ s++;
+ if ( s != _str + l - 1 )
+ {
+ if ( *s == '\\' )
+ *d++ = '\\';
+ else if ( *s == 'n' )
+ *d++ = '\n';
+ else if ( *s == 'r' )
+ *d++ = '\r';
+ else if ( *s == 't' )
+ *d++ = '\t';
+ s++;
+ }
+ }
+ }
+ *d = 0;
+ return p;
+}
+
+void KTraderParse_initFlex( const char *_code )
+{
+ yy_switch_to_buffer( yy_scan_string( _code ) );
+}
+
+int yywrap()
+{
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ return 1;
+}
diff --git a/tdeio/tdeio/metainfojob.cpp b/tdeio/tdeio/metainfojob.cpp
new file mode 100644
index 000000000..d9a31ab0e
--- /dev/null
+++ b/tdeio/tdeio/metainfojob.cpp
@@ -0,0 +1,184 @@
+// -*- c++ -*-
+// vim: ts=4 sw=4 et
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Rolf Magnus <ramagnus@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 version 2.0.
+
+ 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.
+
+ $Id$
+*/
+
+#include <kdatastream.h> // Do not remove, needed for correct bool serialization
+#include <tdefileitem.h>
+#include <kdebug.h>
+#include <tdefilemetainfo.h>
+#include <tdeio/kservice.h>
+#include <tdeparts/componentfactory.h>
+
+#include <tqtimer.h>
+
+#include "metainfojob.moc"
+
+using namespace TDEIO;
+
+struct TDEIO::MetaInfoJobPrivate
+{
+ KFileItemList items; // all the items we got
+ KFileItemListIterator* currentItem; // argh! No default constructor
+ bool deleteItems; // Delete the KFileItems when done?
+ bool succeeded; // if the current item is ok
+};
+
+MetaInfoJob::MetaInfoJob(const KFileItemList &items, bool deleteItems)
+ : TDEIO::Job(false /* no GUI */)
+{
+ d = new MetaInfoJobPrivate;
+ d->deleteItems = deleteItems;
+ d->succeeded = false;
+ d->items = items;
+ d->currentItem = new KFileItemListIterator(d->items);
+
+ d->items.setAutoDelete(deleteItems);
+
+ if (d->currentItem->isEmpty())
+ {
+ kdDebug(7007) << "nothing to do for the MetaInfoJob\n";
+ emitResult();
+ return;
+ }
+
+ kdDebug(7007) << "starting MetaInfoJob\n";
+
+ // Return to event loop first, determineNextFile() might delete this;
+ // (no idea what that means, it comes from previewjob)
+ TQTimer::singleShot(0, this, TQT_SLOT(start()));
+}
+
+MetaInfoJob::~MetaInfoJob()
+{
+ delete d->currentItem;
+ delete d;
+}
+
+void MetaInfoJob::start()
+{
+ getMetaInfo();
+}
+
+void MetaInfoJob::removeItem(const KFileItem* item)
+{
+ if (d->currentItem->current() == item)
+ {
+ subjobs.first()->kill();
+ subjobs.removeFirst();
+ determineNextFile();
+ }
+
+ d->items.remove(d->items.find(item));
+}
+
+void MetaInfoJob::determineNextFile()
+{
+ if (d->currentItem->atLast())
+ {
+ kdDebug(7007) << "finished MetaInfoJob\n";
+ emitResult();
+ return;
+ }
+
+ ++(*d->currentItem);
+ d->succeeded = false;
+
+ // does the file item already have the needed info? Then shortcut
+ if (d->currentItem->current()->metaInfo(false).isValid())
+ {
+// kdDebug(7007) << "Is already valid *************************\n";
+ emit gotMetaInfo(d->currentItem->current());
+ determineNextFile();
+ return;
+ }
+
+ getMetaInfo();
+}
+
+void MetaInfoJob::slotResult( TDEIO::Job *job )
+{
+ subjobs.remove(job);
+ Q_ASSERT(subjobs.isEmpty()); // We should have only one job at a time ...
+
+ determineNextFile();
+}
+
+void MetaInfoJob::getMetaInfo()
+{
+ Q_ASSERT(!d->currentItem->isEmpty());
+
+ KURL URL;
+ URL.setProtocol("metainfo");
+ URL.setPath(d->currentItem->current()->url().path());
+
+ TDEIO::TransferJob* job = TDEIO::get(URL, false, false);
+ addSubjob(job);
+
+ connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
+ this, TQT_SLOT(slotMetaInfo(TDEIO::Job *, const TQByteArray &)));
+
+ job->addMetaData("mimeType", d->currentItem->current()->mimetype());
+}
+
+
+void MetaInfoJob::slotMetaInfo(TDEIO::Job*, const TQByteArray &data)
+{
+ KFileMetaInfo info;
+ TQDataStream s(data, IO_ReadOnly);
+
+ s >> info;
+
+ d->currentItem->current()->setMetaInfo(info);
+ emit gotMetaInfo(d->currentItem->current());
+ d->succeeded = true;
+}
+
+TQStringList MetaInfoJob::availablePlugins()
+{
+ TQStringList result;
+ KTrader::OfferList plugins = KTrader::self()->query("KFilePlugin");
+ for (KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
+ result.append((*it)->desktopEntryName());
+ return result;
+}
+
+TQStringList MetaInfoJob::supportedMimeTypes()
+{
+ TQStringList result;
+ KTrader::OfferList plugins = KTrader::self()->query("KFilePlugin");
+ for (KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
+ result += (*it)->property("MimeTypes").toStringList();
+ return result;
+}
+
+TDEIO_EXPORT MetaInfoJob *TDEIO::fileMetaInfo( const KFileItemList &items)
+{
+ return new MetaInfoJob(items, false);
+}
+
+TDEIO_EXPORT MetaInfoJob *TDEIO::fileMetaInfo( const KURL::List &items)
+{
+ KFileItemList fileItems;
+ for (KURL::List::ConstIterator it = items.begin(); it != items.end(); ++it)
+ fileItems.append(new KFileItem(KFileItem::Unknown, KFileItem::Unknown, *it, true));
+ return new MetaInfoJob(fileItems, true);
+}
+
diff --git a/tdeio/tdeio/metainfojob.h b/tdeio/tdeio/metainfojob.h
new file mode 100644
index 000000000..3a9fab67e
--- /dev/null
+++ b/tdeio/tdeio/metainfojob.h
@@ -0,0 +1,119 @@
+// -*- c++ -*-
+// vim: ts=4 sw=4 et
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Rolf Magnus <ramagnus@kde.org>
+ parts of this taken from previewjob.h
+
+ 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 version 2.0.
+
+ 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 __kio_metainfojob_h__
+#define __kio_metainfojob_h__
+
+#include <tdeio/job.h>
+#include <tdefileitem.h>
+
+namespace TDEIO {
+ /**
+ * MetaInfoJob is a KIO Job to retrieve meta information from files.
+ *
+ * @short KIO Job to retrieve meta information from files.
+ * @since 3.1
+ */
+ class TDEIO_EXPORT MetaInfoJob : public TDEIO::Job
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Creates a new MetaInfoJob.
+ * @param items A list of KFileItems to get the metainfo for
+ * @param deleteItems If true, the finished KFileItems are deleted
+ */
+ MetaInfoJob(const KFileItemList &items, bool deleteItems = false);
+ virtual ~MetaInfoJob();
+
+ /**
+ * Removes an item from metainfo extraction.
+ *
+ * @param item the item that should be removed from the queue
+ */
+ void removeItem( const KFileItem *item );
+
+ /**
+ * Returns a list of all available metainfo plugins. The list
+ * contains the basenames of the plugins' .desktop files (no path,
+ * no .desktop).
+ * @return the list of available meta info plugins
+ */
+ static TQStringList availablePlugins();
+
+ /**
+ * Returns a list of all supported MIME types. The list can
+ * contain entries like text/ * (without the space).
+ * @return the list of MIME types that are supported
+ */
+ static TQStringList supportedMimeTypes();
+
+ signals:
+ /**
+ * Emitted when the meta info for @p item has been successfully
+ * retrieved.
+ * @param item the KFileItem describing the fetched item
+ */
+ void gotMetaInfo( const KFileItem *item );
+ /**
+ * Emitted when metainfo for @p item could not be extracted,
+ * either because a plugin for its MIME type does not
+ * exist, or because something went wrong.
+ * @param item the KFileItem of the file that failed
+ */
+ void failed( const KFileItem *item );
+
+ protected:
+ void getMetaInfo();
+
+ protected slots:
+ virtual void slotResult( TDEIO::Job *job );
+
+ private slots:
+ void start();
+ void slotMetaInfo(TDEIO::Job *, const TQByteArray &);
+
+ private:
+ void determineNextFile();
+// void saveMetaInfo(const TQByteArray info);
+
+ private:
+ struct MetaInfoJobPrivate *d;
+ };
+
+ /**
+ * Retrieves meta information for the given items.
+ *
+ * @param items files to get metainfo for
+ * @return the MetaInfoJob to retrieve the items
+ */
+ TDEIO_EXPORT MetaInfoJob* fileMetaInfo(const KFileItemList& items);
+
+ /**
+ * Retrieves meta information for the given items.
+ *
+ * @param items files to get metainfo for
+ * @return the MetaInfoJob to retrieve the items
+ */
+ TDEIO_EXPORT MetaInfoJob* fileMetaInfo(const KURL::List& items);
+}
+
+#endif
diff --git a/tdeio/tdeio/netaccess.cpp b/tdeio/tdeio/netaccess.cpp
new file mode 100644
index 000000000..89830d88b
--- /dev/null
+++ b/tdeio/tdeio/netaccess.cpp
@@ -0,0 +1,536 @@
+/* $Id$
+
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Torben Weis (weis@kde.org)
+ Copyright (C) 1998 Matthias Ettrich (ettrich@kde.org)
+ Copyright (C) 1999 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 <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <cstring>
+
+#include <tqstring.h>
+#include <tqapplication.h>
+#include <tqfile.h>
+#include <tqmetaobject.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <tdeio/job.h>
+#include <tdeio/scheduler.h>
+
+#include "tdeio/netaccess.h"
+
+using namespace TDEIO;
+
+TQString * NetAccess::lastErrorMsg;
+int NetAccess::lastErrorCode = 0;
+TQStringList* NetAccess::tmpfiles;
+
+bool NetAccess::download(const KURL& u, TQString & target)
+{
+ return NetAccess::download (u, target, 0);
+}
+
+bool NetAccess::download(const KURL& u, TQString & target, TQWidget* window)
+{
+ if (u.isLocalFile()) {
+ // file protocol. We do not need the network
+ target = u.path();
+ bool accessible = checkAccess(target, R_OK);
+ if(!accessible)
+ {
+ if(!lastErrorMsg)
+ lastErrorMsg = new TQString;
+ *lastErrorMsg = i18n("File '%1' is not readable").arg(target);
+ lastErrorCode = ERR_COULD_NOT_READ;
+ }
+ return accessible;
+ }
+
+ if (target.isEmpty())
+ {
+ KTempFile tmpFile;
+ target = tmpFile.name();
+ if (!tmpfiles)
+ tmpfiles = new TQStringList;
+ tmpfiles->append(target);
+ }
+
+ NetAccess kioNet;
+ KURL dest;
+ dest.setPath( target );
+ return kioNet.filecopyInternal( u, dest, -1, true /*overwrite*/,
+ false, window, false /*copy*/);
+}
+
+bool NetAccess::upload(const TQString& src, const KURL& target)
+{
+ return NetAccess::upload(src, target, 0);
+}
+
+bool NetAccess::upload(const TQString& src, const KURL& target, TQWidget* window)
+{
+ if (target.isEmpty())
+ return false;
+
+ // If target is local... well, just copy. This can be useful
+ // when the client code uses a temp file no matter what.
+ // Let's make sure it's not the exact same file though
+ if (target.isLocalFile() && target.path() == src)
+ return true;
+
+ NetAccess kioNet;
+ KURL s;
+ s.setPath(src);
+ return kioNet.filecopyInternal( s, target, -1, true /*overwrite*/,
+ false, window, false /*copy*/ );
+}
+
+bool NetAccess::copy( const KURL & src, const KURL & target )
+{
+ return NetAccess::file_copy( src, target, -1, false /*not overwrite*/, false, 0L );
+}
+
+bool NetAccess::copy( const KURL & src, const KURL & target, TQWidget* window )
+{
+ return NetAccess::file_copy( src, target, -1, false /*not overwrite*/, false, window );
+}
+
+bool NetAccess::file_copy( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.filecopyInternal( src, target, permissions, overwrite, resume,
+ window, false /*copy*/ );
+}
+
+
+bool NetAccess::file_move( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.filecopyInternal( src, target, permissions, overwrite, resume,
+ window, true /*move*/ );
+}
+
+bool NetAccess::dircopy( const KURL & src, const KURL & target )
+{
+ return NetAccess::dircopy( src, target, 0 );
+}
+
+bool NetAccess::dircopy( const KURL & src, const KURL & target, TQWidget* window )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ return NetAccess::dircopy( srcList, target, window );
+}
+
+bool NetAccess::dircopy( const KURL::List & srcList, const KURL & target, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.dircopyInternal( srcList, target, window, false /*copy*/ );
+}
+
+bool NetAccess::move( const KURL& src, const KURL& target, TQWidget* window )
+{
+ KURL::List srcList;
+ srcList.append( src );
+ return NetAccess::move( srcList, target, window );
+}
+
+bool NetAccess::move( const KURL::List& srcList, const KURL& target, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.dircopyInternal( srcList, target, window, true /*move*/ );
+}
+
+bool NetAccess::exists( const KURL & url )
+{
+ return NetAccess::exists( url, false, 0 );
+}
+
+bool NetAccess::exists( const KURL & url, TQWidget* window )
+{
+ return NetAccess::exists( url, false, window );
+}
+
+bool NetAccess::exists( const KURL & url, bool source )
+{
+ return NetAccess::exists( url, source, 0 );
+}
+
+bool NetAccess::exists( const KURL & url, bool source, TQWidget* window )
+{
+ if ( url.isLocalFile() )
+ return TQFile::exists( url.path() );
+ NetAccess kioNet;
+ return kioNet.statInternal( url, 0 /*no details*/, source, window );
+}
+
+bool NetAccess::stat( const KURL & url, TDEIO::UDSEntry & entry )
+{
+ return NetAccess::stat( url, entry, 0 );
+}
+
+bool NetAccess::stat( const KURL & url, TDEIO::UDSEntry & entry, TQWidget* window )
+{
+ NetAccess kioNet;
+ bool ret = kioNet.statInternal( url, 2 /*all details*/, true /*source*/, window );
+ if (ret)
+ entry = kioNet.m_entry;
+ return ret;
+}
+
+KURL NetAccess::mostLocalURL(const KURL & url, TQWidget* window)
+{
+ if ( url.isLocalFile() )
+ {
+ return url;
+ }
+
+ TDEIO::UDSEntry entry;
+ if (!stat(url, entry, window))
+ {
+ return url;
+ }
+
+ TQString path;
+
+ // Extract the local path from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = entry.begin();
+ const TDEIO::UDSEntry::ConstIterator end = entry.end();
+ for ( ; it != end; ++it )
+ {
+ if ( (*it).m_uds == TDEIO::UDS_LOCAL_PATH )
+ {
+ path = (*it).m_str;
+ break;
+ }
+ }
+
+ if ( !path.isEmpty() )
+ {
+ KURL new_url;
+ new_url.setPath(path);
+ return new_url;
+ }
+
+ return url;
+}
+
+
+bool NetAccess::del( const KURL & url )
+{
+ return NetAccess::del( url, 0 );
+}
+
+bool NetAccess::del( const KURL & url, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.delInternal( url, window );
+}
+
+bool NetAccess::mkdir( const KURL & url, int permissions )
+{
+ return NetAccess::mkdir( url, 0, permissions );
+}
+
+bool NetAccess::mkdir( const KURL & url, TQWidget* window, int permissions )
+{
+ NetAccess kioNet;
+ return kioNet.mkdirInternal( url, permissions, window );
+}
+
+TQString NetAccess::fish_execute( const KURL & url, const TQString command, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.fish_executeInternal( url, command, window );
+}
+
+bool NetAccess::synchronousRun( Job* job, TQWidget* window, TQByteArray* data,
+ KURL* finalURL, TQMap<TQString, TQString>* metaData )
+{
+ NetAccess kioNet;
+ return kioNet.synchronousRunInternal( job, window, data, finalURL, metaData );
+}
+
+TQString NetAccess::mimetype( const KURL& url )
+{
+ NetAccess kioNet;
+ return kioNet.mimetypeInternal( url, 0 );
+}
+
+TQString NetAccess::mimetype( const KURL& url, TQWidget* window )
+{
+ NetAccess kioNet;
+ return kioNet.mimetypeInternal( url, window );
+}
+
+void NetAccess::removeTempFile(const TQString& name)
+{
+ if (!tmpfiles)
+ return;
+ if (tmpfiles->contains(name))
+ {
+ unlink(TQFile::encodeName(name));
+ tmpfiles->remove(name);
+ }
+}
+
+bool NetAccess::filecopyInternal(const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, TQWidget* window, bool move)
+{
+ bJobOK = true; // success unless further error occurs
+
+ TDEIO::Scheduler::checkSlaveOnHold(true);
+ TDEIO::Job * job = move
+ ? TDEIO::file_move( src, target, permissions, overwrite, resume )
+ : TDEIO::file_copy( src, target, permissions, overwrite, resume );
+ job->setWindow (window);
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+
+ enter_loop();
+ return bJobOK;
+}
+
+bool NetAccess::dircopyInternal(const KURL::List& src, const KURL& target,
+ TQWidget* window, bool move)
+{
+ bJobOK = true; // success unless further error occurs
+
+ TDEIO::Job * job = move
+ ? TDEIO::move( src, target )
+ : TDEIO::copy( src, target );
+ job->setWindow (window);
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+
+ enter_loop();
+ return bJobOK;
+}
+
+bool NetAccess::statInternal( const KURL & url, int details, bool source,
+ TQWidget* window )
+{
+ bJobOK = true; // success unless further error occurs
+ TDEIO::StatJob * job = TDEIO::stat( url, !url.isLocalFile() && !url.url().startsWith("beagle:?") );
+ job->setWindow (window);
+ job->setDetails( details );
+ job->setSide( source );
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+ enter_loop();
+ return bJobOK;
+}
+
+bool NetAccess::delInternal( const KURL & url, TQWidget* window )
+{
+ bJobOK = true; // success unless further error occurs
+ TDEIO::Job * job = TDEIO::del( url );
+ job->setWindow (window);
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+ enter_loop();
+ return bJobOK;
+}
+
+bool NetAccess::mkdirInternal( const KURL & url, int permissions,
+ TQWidget* window )
+{
+ bJobOK = true; // success unless further error occurs
+ TDEIO::Job * job = TDEIO::mkdir( url, permissions );
+ job->setWindow (window);
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+ enter_loop();
+ return bJobOK;
+}
+
+TQString NetAccess::mimetypeInternal( const KURL & url, TQWidget* window )
+{
+ bJobOK = true; // success unless further error occurs
+ m_mimetype = TQString::fromLatin1("unknown");
+ TDEIO::Job * job = TDEIO::mimetype( url );
+ job->setWindow (window);
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+ connect( job, TQT_SIGNAL( mimetype (TDEIO::Job *, const TQString &) ),
+ this, TQT_SLOT( slotMimetype (TDEIO::Job *, const TQString &) ) );
+ enter_loop();
+ return m_mimetype;
+}
+
+void NetAccess::slotMimetype( TDEIO::Job *, const TQString & type )
+{
+ m_mimetype = type;
+}
+
+TQString NetAccess::fish_executeInternal(const KURL & url, const TQString command, TQWidget* window)
+{
+ TQString target, remoteTempFileName, resultData;
+ KURL tempPathUrl;
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete( true );
+
+ if( url.protocol() == "fish" )
+ {
+ // construct remote temp filename
+ tempPathUrl = url;
+ remoteTempFileName = tmpFile.name();
+ // only need the filename KTempFile adds some KDE specific dirs
+ // that probably does not exist on the remote side
+ int pos = remoteTempFileName.findRev('/');
+ remoteTempFileName = "/tmp/fishexec_" + remoteTempFileName.mid(pos + 1);
+ tempPathUrl.setPath( remoteTempFileName );
+ bJobOK = true; // success unless further error occurs
+ TQByteArray packedArgs;
+ TQDataStream stream( packedArgs, IO_WriteOnly );
+
+ stream << int('X') << tempPathUrl << command;
+
+ TDEIO::Job * job = TDEIO::special( tempPathUrl, packedArgs, true );
+ job->setWindow( window );
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+ enter_loop();
+
+ // since the TDEIO::special does not provide feedback we need to download the result
+ if( NetAccess::download( tempPathUrl, target, window ) )
+ {
+ TQFile resultFile( target );
+
+ if (resultFile.open( IO_ReadOnly ))
+ {
+ TQTextStream ts( &resultFile );
+ ts.setEncoding( TQTextStream::Locale ); // Locale??
+ resultData = ts.read();
+ resultFile.close();
+ NetAccess::del( tempPathUrl, window );
+ }
+ }
+ }
+ else
+ {
+ resultData = i18n( "ERROR: Unknown protocol '%1'" ).arg( url.protocol() );
+ }
+ return resultData;
+}
+
+bool NetAccess::synchronousRunInternal( Job* job, TQWidget* window, TQByteArray* data,
+ KURL* finalURL, TQMap<TQString,TQString>* metaData )
+{
+ job->setWindow( window );
+
+ m_metaData = metaData;
+ if ( m_metaData ) {
+ for ( TQMap<TQString, TQString>::iterator it = m_metaData->begin(); it != m_metaData->end(); ++it ) {
+ job->addMetaData( it.key(), it.data() );
+ }
+ }
+
+ if ( finalURL ) {
+ SimpleJob *sj = dynamic_cast<SimpleJob*>( job );
+ if ( sj ) {
+ m_url = sj->url();
+ }
+ }
+
+ connect( job, TQT_SIGNAL( result (TDEIO::Job *) ),
+ this, TQT_SLOT( slotResult (TDEIO::Job *) ) );
+
+ TQMetaObject *meta = job->metaObject();
+
+ static const char dataSignal[] = "data(TDEIO::Job*,const " TQBYTEARRAY_OBJECT_NAME_STRING "&)";
+ if ( meta->findSignal( dataSignal ) != -1 ) {
+ connect( job, TQT_SIGNAL(data(TDEIO::Job*,const TQByteArray&)),
+ this, TQT_SLOT(slotData(TDEIO::Job*,const TQByteArray&)) );
+ }
+
+ static const char redirSignal[] = "redirection(TDEIO::Job*,const KURL&)";
+ if ( meta->findSignal( redirSignal ) != -1 ) {
+ connect( job, TQT_SIGNAL(redirection(TDEIO::Job*,const KURL&)),
+ this, TQT_SLOT(slotRedirection(TDEIO::Job*, const KURL&)) );
+ }
+
+ enter_loop();
+
+ if ( finalURL )
+ *finalURL = m_url;
+ if ( data )
+ *data = m_data;
+
+ return bJobOK;
+}
+
+// If a troll sees this, he kills me
+void tqt_enter_modal( TQWidget *widget );
+void tqt_leave_modal( TQWidget *widget );
+
+void NetAccess::enter_loop()
+{
+ TQWidget dummy(0,0,(WFlags)(WType_Dialog | WShowModal));
+ dummy.setFocusPolicy( TQ_NoFocus );
+ tqt_enter_modal(&dummy);
+ tqApp->enter_loop();
+ tqt_leave_modal(&dummy);
+}
+
+void NetAccess::slotResult( TDEIO::Job * job )
+{
+ lastErrorCode = job->error();
+ bJobOK = !job->error();
+ if ( !bJobOK )
+ {
+ if ( !lastErrorMsg )
+ lastErrorMsg = new TQString;
+ *lastErrorMsg = job->errorString();
+ }
+ if ( job->isA("TDEIO::StatJob") )
+ m_entry = static_cast<TDEIO::StatJob *>(job)->statResult();
+
+ if ( m_metaData )
+ *m_metaData = job->metaData();
+
+ tqApp->exit_loop();
+}
+
+void NetAccess::slotData( TDEIO::Job*, const TQByteArray& data )
+{
+ if ( data.isEmpty() )
+ return;
+
+ unsigned offset = m_data.size();
+ m_data.resize( offset + data.size() );
+ std::memcpy( m_data.data() + offset, data.data(), data.size() );
+}
+
+void NetAccess::slotRedirection( TDEIO::Job*, const KURL& url )
+{
+ m_url = url;
+}
+
+#include "netaccess.moc"
diff --git a/tdeio/tdeio/netaccess.h b/tdeio/tdeio/netaccess.h
new file mode 100644
index 000000000..356a91738
--- /dev/null
+++ b/tdeio/tdeio/netaccess.h
@@ -0,0 +1,540 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 1997 Torben Weis (weis@kde.org)
+ Copyright (C) 1998 Matthias Ettrich (ettrich@kde.org)
+ Copyright (C) 1999-2004 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 __kio_netaccess_h
+#define __kio_netaccess_h
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tdeio/global.h>
+
+class TQStringList;
+class TQWidget;
+class KURL;
+template<typename T, typename K> class TQMap;
+
+namespace TDEIO {
+
+ class Job;
+
+ /**
+ * Net Transparency.
+ *
+ * NetAccess allows you to do simple file operation (load, save,
+ * copy, delete...) without working with TDEIO::Job directly.
+ * Whereas a TDEIO::Job is asynchronous, meaning that the
+ * developer has to connect slots for it, TDEIO::NetAccess provides
+ * synchronous downloads and uploads, as well as temporary file
+ * creation and removal. The functions appear to be blocking,
+ * but the Qt event loop continues running while the operations
+ * are handled. This means that the GUI will not freeze.
+ *
+ * This class isn't meant to be used as a class but only as a simple
+ * namespace for static functions, though an instance of the class
+ * is built for internal purposes.
+ *
+ * Port to kio done by David Faure, faure@kde.org
+ *
+ * @short Provides an easy, synchronous interface to KIO file operations.
+ */
+class TDEIO_EXPORT NetAccess : public TQObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Downloads a file from an arbitrary URL (@p src) to a
+ * temporary file on the local filesystem (@p target).
+ *
+ * If the argument
+ * for @p target is an empty string, download will generate a
+ * unique temporary filename in /tmp. Since @p target is a reference
+ * to TQString you can access this filename easily. Download will
+ * return true if the download was successful, otherwise false.
+ *
+ * Special case:
+ * If the URL is of kind file:, then no downloading is
+ * processed but the full filename is returned in @p target.
+ * That means you @em have to take care about the @p target argument.
+ * (This is very easy to do, please see the example below.)
+ *
+ * Download is synchronous. That means you can use it like
+ * this, (assuming @p u is a string which represents a URL and your
+ * application has a loadFile() function):
+ *
+ * \code
+ * TQString tmpFile;
+ * if( TDEIO::NetAccess::download( u, tmpFile, window ) )
+ * {
+ * loadFile( tmpFile );
+ * TDEIO::NetAccess::removeTempFile( tmpFile );
+ * } else {
+ * KMessageBox::error(this, TDEIO::NetAccess::lastErrorString() );
+ * }
+ * \endcode
+ *
+ * Of course, your user interface will still process exposure/repaint
+ * events during the download.
+ *
+ * If the download fails, lastError() and lastErrorString() will be set.
+ *
+ * @param src URL Reference to the file to download.
+ * @param target String containing the final local location of the
+ * file. If you insert an empty string, it will
+ * return a location in a temporary spot. <B>Note:</B>
+ * you are responsible for the removal of this file when
+ * you are finished reading it using removeTempFile.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return true if successful, false for failure. Use lastErrorString() to
+ * get the reason it failed.
+ *
+ * @see lastErrorString()
+ * @since 3.2
+ */
+ static bool download(const KURL& src, TQString & target, TQWidget* window);
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool download(const KURL& src, TQString & target) KDE_DEPRECATED;
+
+ /**
+ * Removes the specified file if and only if it was created
+ * by TDEIO::NetAccess as a temporary file for a former download.
+ *
+ * Note: This means that if you created your temporary with KTempFile,
+ * use KTempFile::unlink() or KTempFile::setAutoDelete() to have
+ * it removed.
+ *
+ * @param name Path to temporary file to remove. May not be
+ * empty.
+ */
+ static void removeTempFile(const TQString& name);
+
+ /**
+ * Uploads file @p src to URL @p target.
+ *
+ * Both must be specified, unlike download.
+ * Note that this is assumed to be used for saving a file over
+ * the network, so overwriting is set to true. This is not the
+ * case with copy.
+ *
+ * @param src URL Referencing the file to upload.
+ * @param target URL containing the final location of the file.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be cached
+ * only for a short duration after which the user will again be
+ * prompted for passwords as needed.
+ *
+ * @return true if successful, false for failure
+ * @since 3.2
+ */
+ static bool upload(const TQString& src, const KURL& target, TQWidget* window);
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool upload(const TQString& src, const KURL& target) KDE_DEPRECATED;
+
+ /**
+ * Alternative to upload for copying over the network.
+ * Overwrite is false, so this will fail if @p target exists.
+ *
+ * This one takes two URLs and is a direct equivalent
+ * of TDEIO::file_copy (not TDEIO::copy!).
+ * It will be renamed file_copy in KDE4, so better use file_copy.
+ *
+ * @param src URL Referencing the file to upload.
+ * @param target URL containing the final location of the file.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be cached
+ * only for a short duration after which the user will again be
+ * prompted for passwords as needed.
+ *
+ * @return true if successful, false for failure
+ */
+ static bool copy( const KURL& src, const KURL& target, TQWidget* window );
+ // KDE4: rename to file_copy
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool copy( const KURL& src, const KURL& target ) KDE_DEPRECATED;
+ // KDE4: merge with above
+
+ /**
+ * Full-fledged equivalent of TDEIO::file_copy
+ */
+ static bool file_copy( const KURL& src, const KURL& dest, int permissions=-1,
+ bool overwrite=false, bool resume=false, TQWidget* window = 0L );
+
+ /**
+ * Full-fledged equivalent of TDEIO::file_move.
+ * Moves or renames *one file*.
+ * @since 3.2
+ */
+ static bool file_move( const KURL& src, const KURL& target, int permissions=-1,
+ bool overwrite=false, bool resume=false, TQWidget* window = 0L );
+
+
+ /**
+ * Alternative method for copying over the network.
+ * Overwrite is false, so this will fail if @p target exists.
+ *
+ * This one takes two URLs and is a direct equivalent
+ * of TDEIO::copy!.
+ * This means that it can copy files and directories alike
+ * (it should have been named copy()).
+ *
+ * @param src URL Referencing the file to upload.
+ * @param target URL containing the final location of the
+ * file.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be cached
+ * only for a short duration after which the user will again be
+ * prompted for passwords as needed.
+ * @return true if successful, false for failure
+ */
+ static bool dircopy( const KURL& src, const KURL& target, TQWidget* window );
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool dircopy( const KURL& src, const KURL& target ) KDE_DEPRECATED; // KDE4: merge
+
+ /**
+ * Overloaded method, which takes a list of source URLs
+ */
+ static bool dircopy( const KURL::List& src, const KURL& target, TQWidget* window = 0L );
+
+ /**
+ * Full-fledged equivalent of TDEIO::move.
+ * Moves or renames one file or directory.
+ * @since 3.2
+ */
+ static bool move( const KURL& src, const KURL& target, TQWidget* window = 0L );
+
+ /**
+ * Full-fledged equivalent of TDEIO::move.
+ * Moves or renames a list of files or directories.
+ * @since 3.2
+ */
+ static bool move( const KURL::List& src, const KURL& target, TQWidget* window = 0L );
+
+ /**
+ * Tests whether a URL exists.
+ *
+ * @param url the URL we are testing
+ * @param source if true, we want to read from that URL.
+ * If false, we want to write to it.
+ * IMPORTANT: see documentation for TDEIO::stat for more details about this.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return true if the URL exists and we can do the operation specified by
+ * @p source, false otherwise
+ * @since 3.2
+ */
+ static bool exists(const KURL& url, bool source, TQWidget* window);
+
+ /**
+ * @deprecated. Use the function above instead.
+ * @since 3.2
+ */
+ static bool exists(const KURL& url, TQWidget* window) KDE_DEPRECATED;
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool exists(const KURL& url) KDE_DEPRECATED;
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool exists(const KURL& url, bool source) KDE_DEPRECATED; // KDE4: merge
+
+ /**
+ * Tests whether a URL exists and return information on it.
+ *
+ * This is a convenience function for TDEIO::stat
+ * (it saves creating a slot and testing for the job result).
+ *
+ * @param url The URL we are testing.
+ * @param entry The result of the stat. Iterate over the list
+ * of atoms to get hold of name, type, size, etc., or use KFileItem.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return true if successful, false for failure
+ */
+ static bool stat(const KURL& url, TDEIO::UDSEntry & entry, TQWidget* window);
+
+ /**
+ * @deprecated. Use the function above instead.
+ */
+ static bool stat(const KURL& url, TDEIO::UDSEntry & entry) KDE_DEPRECATED;
+
+ /**
+ * Tries to map a local URL for the given URL.
+ *
+ * This is a convenience function for TDEIO::stat + parsing the
+ * resulting UDSEntry.
+ *
+ * @param url The URL we are testing.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return a local URL corresponding to the same ressource than the
+ * original URL, or the original URL if no local URL can be mapped
+ * @since 3.5
+ */
+ static KURL mostLocalURL(const KURL& url, TQWidget* window);
+
+ /**
+ * Deletes a file or a directory in a synchronous way.
+ *
+ * This is a convenience function for TDEIO::del
+ * (it saves creating a slot and testing for the job result).
+ *
+ * @param url The file or directory to delete.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return true on success, false on failure.
+ */
+ static bool del( const KURL & url, TQWidget* window );
+
+ /**
+ * @deprecated. Use the function above instead. Passing NULL as the
+ * additional argument will give the same behaviour, but
+ * you should try to identify a suitable parent widget
+ * if at all possible.
+ */
+ static bool del( const KURL & url ) KDE_DEPRECATED;
+
+ /**
+ * Creates a directory in a synchronous way.
+ *
+ * This is a convenience function for @p TDEIO::mkdir
+ * (it saves creating a slot and testing for the job result).
+ *
+ * @param url The directory to create.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @param permissions directory permissions.
+ * @return true on success, false on failure.
+ */
+ static bool mkdir( const KURL & url, TQWidget* window, int permissions = -1 );
+
+ /**
+ * @deprecated. Use the function above instead. Passing NULL as the
+ * additional argument will give the same behaviour, but
+ * you should try to identify a suitable parent widget
+ * if at all possible.
+ */
+ static bool mkdir( const KURL & url, int permissions = -1 ) KDE_DEPRECATED;
+
+ /**
+ * Executes a remote process via the fish ioslave in a synchronous way.
+ *
+ * @param url The remote machine where the command should be executed.
+ * e.g. fish://someuser\@somehost:sshport/
+ * some special cases exist.
+ * fish://someuser\@localhost/
+ * will use su instead of ssh to connect and execute the command.
+ * fish://someuser\@localhost:port/
+ * will use ssh to connect and execute the command.
+ * @param command The command to be executed.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return The resulting output of the @p command that is executed.
+ */
+ static TQString fish_execute( const KURL & url, const TQString command, TQWidget* window );
+
+ /**
+ * This function executes a job in a synchronous way.
+ * If a job fetches some data, pass a TQByteArray pointer as data parameter to this function
+ * and after the function returns it will contain all the data fetched by this job.
+ *
+ * <code>
+ * TDEIO::Job *job = TDEIO::get( url, false, false );
+ * TQMap<TQString, TQString> metaData;
+ * metaData.insert( "PropagateHttpHeader", "true" );
+ * if ( NetAccess::synchronousRun( job, 0, &data, &url, &metaData ) ) {
+ * TQString responseHeaders = metaData[ "HTTP-Headers" ];
+ * kdDebug()<<"Response header = "<< responseHeaders << endl;
+ * }
+ * </code>
+ *
+ * @param job job which the function will run. Note that after this function
+ * finishes running, job is deleted and you can't access it anymore!
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @param data if passed and relevant to this job then it will contain the data
+ * that was fetched by the job
+ * @param finalURL if passed will contain the final url of this job (it might differ
+ * from the one it was created with if there was a redirection)
+ * @param metaData you can pass a pointer to the map with meta data you wish to
+ * set on the job. After the job finishes this map will hold all the
+ * meta data from the job.
+ *
+ * @return true on success, false on failure.
+ *
+ * @since 3.4
+ */
+ static bool synchronousRun( Job* job, TQWidget* window, TQByteArray* data=0,
+ KURL* finalURL=0, TQMap<TQString,TQString>* metaData=0 );
+
+ /**
+ * @internal
+ * This function is not implemented!?
+ * (only mimetypeInternal)
+ *
+ * Determines the mimetype of a given URL.
+ *
+ * This is a convenience function for TDEIO::mimetype. You
+ * should call this only when really necessary.
+ * KMimeType::findByURL can determine extension a lot faster, but
+ * less reliably for remote files. Only when findByURL() returns
+ * unknown (application/octet-stream) then this one should be
+ * used.
+ *
+ * @param url The URL whose mimetype we are interested in.
+ * @param window main window associated with this job. This is used to
+ * automatically cache and discard authentication information
+ * as needed. If NULL, authentication information will be
+ * cached only for a short duration after which the user will
+ * again be prompted for passwords as needed.
+ * @return The mimetype name.
+ */
+ static TQString mimetype( const KURL & url, TQWidget* window );
+
+ /**
+ * @deprecated. Use the function above instead. Passing NULL as the
+ * additional argument will give the same behaviour, but
+ * you should try to identify a suitable parent widget
+ * if at all possible.
+ */
+ static TQString mimetype( const KURL & url ) KDE_DEPRECATED;
+
+ /**
+ * Returns the error string for the last job, in case it failed.
+ * Note that this is already translated.
+ * @return the last error string, or TQString::null
+ */
+ static TQString lastErrorString() { return lastErrorMsg ? *lastErrorMsg : TQString::null; }
+
+ /**
+ * Returns the error code for the last job, in case it failed.
+ * @return the last error code
+ * @since 3.3
+ */
+ static int lastError() { return lastErrorCode; }
+
+private:
+ /**
+ * Private constructor
+ */
+ NetAccess() : m_metaData(0), d(0) {}
+
+ /**
+ * Private destructor
+ */
+ ~NetAccess() {}
+
+ /**
+ * Internal methods
+ */
+ bool filecopyInternal(const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, TQWidget* window, bool move);
+ bool dircopyInternal(const KURL::List& src, const KURL& target,
+ TQWidget* window, bool move);
+ bool statInternal(const KURL & url, int details, bool source, TQWidget* window = 0);
+
+ bool delInternal(const KURL & url, TQWidget* window = 0);
+ bool mkdirInternal(const KURL & url, int permissions, TQWidget* window = 0);
+ TQString fish_executeInternal(const KURL & url, const TQString command, TQWidget* window = 0);
+ bool synchronousRunInternal( Job* job, TQWidget* window, TQByteArray* data,
+ KURL* finalURL, TQMap<TQString,TQString>* metaData );
+
+ TQString mimetypeInternal(const KURL & url, TQWidget* window = 0);
+ void enter_loop();
+
+ /**
+ * List of temporary files
+ */
+ static TQStringList* tmpfiles;
+
+ static TQString* lastErrorMsg;
+ static int lastErrorCode;
+
+ friend class I_like_this_class;
+
+private slots:
+ void slotResult( TDEIO::Job * job );
+ void slotMimetype( TDEIO::Job * job, const TQString & type );
+ void slotData( TDEIO::Job*, const TQByteArray& );
+ void slotRedirection( TDEIO::Job*, const KURL& );
+
+private:
+ UDSEntry m_entry;
+ TQString m_mimetype;
+ TQByteArray m_data;
+ KURL m_url;
+ TQMap<TQString, TQString> *m_metaData;
+
+ /**
+ * Whether the download succeeded or not
+ */
+ bool bJobOK;
+
+private:
+ class NetAccessPrivate* d; // not really needed, the ctor is private already.
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/observer.cpp b/tdeio/tdeio/observer.cpp
new file mode 100644
index 000000000..5e4e7aa87
--- /dev/null
+++ b/tdeio/tdeio/observer.cpp
@@ -0,0 +1,417 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+ David Faure <faure@kde.org>
+
+ $Id$
+
+ 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 <assert.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kurl.h>
+
+#include "jobclasses.h"
+#include "observer.h"
+
+#include "uiserver_stub.h"
+
+#include "passdlg.h"
+#include "slavebase.h"
+#include "observer_stub.h"
+#include <kmessagebox.h>
+#include <ksslinfodlg.h>
+#include <ksslcertdlg.h>
+#include <ksslcertificate.h>
+#include <ksslcertchain.h>
+#include <klocale.h>
+
+using namespace TDEIO;
+
+template class TQIntDict<TDEIO::Job>;
+
+Observer * Observer::s_pObserver = 0L;
+
+const int KDEBUG_OBSERVER = 7007; // Should be 7028
+
+Observer::Observer() : DCOPObject("TDEIO::Observer")
+{
+ // Register app as able to receive DCOP messages
+ if (kapp && !kapp->dcopClient()->isAttached())
+ {
+ kapp->dcopClient()->attach();
+ }
+
+ if ( !kapp->dcopClient()->isApplicationRegistered( "tdeio_uiserver" ) )
+ {
+ kdDebug(KDEBUG_OBSERVER) << "Starting tdeio_uiserver" << endl;
+ TQString error;
+ int ret = TDEApplication::startServiceByDesktopPath( "tdeio_uiserver.desktop",
+ TQStringList(), &error );
+ if ( ret > 0 )
+ {
+ kdError() << "Couldn't start tdeio_uiserver from tdeio_uiserver.desktop: " << error << endl;
+ } else
+ kdDebug(KDEBUG_OBSERVER) << "startServiceByDesktopPath returned " << ret << endl;
+
+ }
+ if ( !kapp->dcopClient()->isApplicationRegistered( "tdeio_uiserver" ) )
+ kdDebug(KDEBUG_OBSERVER) << "The application tdeio_uiserver is STILL NOT REGISTERED" << endl;
+ else
+ kdDebug(KDEBUG_OBSERVER) << "tdeio_uiserver registered" << endl;
+
+ m_uiserver = new UIServer_stub( "tdeio_uiserver", "UIServer" );
+}
+
+int Observer::newJob( TDEIO::Job * job, bool showProgress )
+{
+ // Tell the UI Server about this new job, and give it the application id
+ // at the same time
+ int progressId = m_uiserver->newJob( kapp->dcopClient()->appId(), showProgress );
+
+ // Keep the result in a dict
+ m_dctJobs.insert( progressId, job );
+
+ return progressId;
+}
+
+void Observer::jobFinished( int progressId )
+{
+ m_uiserver->jobFinished( progressId );
+ m_dctJobs.remove( progressId );
+}
+
+void Observer::killJob( int progressId )
+{
+ TDEIO::Job * job = m_dctJobs[ progressId ];
+ if (!job)
+ {
+ kdWarning() << "Can't find job to kill ! There is no job with progressId=" << progressId << " in this process" << endl;
+ return;
+ }
+ job->kill( false /* not quietly */ );
+}
+
+MetaData Observer::metadata( int progressId )
+{
+ TDEIO::Job * job = m_dctJobs[ progressId ];
+ assert(job);
+ return job->metaData();
+}
+
+void Observer::slotTotalSize( TDEIO::Job* job, TDEIO::filesize_t size )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotTotalSize " << job << " " << TDEIO::number(size) << endl;
+ m_uiserver->totalSize64( job->progressId(), size );
+}
+
+void Observer::slotTotalFiles( TDEIO::Job* job, unsigned long files )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotTotalFiles " << job << " " << files << endl;
+ m_uiserver->totalFiles( job->progressId(), files );
+}
+
+void Observer::slotTotalDirs( TDEIO::Job* job, unsigned long dirs )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotTotalDirs " << job << " " << dirs << endl;
+ m_uiserver->totalDirs( job->progressId(), dirs );
+}
+
+void Observer::slotProcessedSize( TDEIO::Job* job, TDEIO::filesize_t size )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotProcessedSize " << job << " " << job->progressId() << " " << TDEIO::number(size) << endl;
+ m_uiserver->processedSize64( job->progressId(), size );
+}
+
+void Observer::slotProcessedFiles( TDEIO::Job* job, unsigned long files )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotProcessedFiles " << job << " " << files << endl;
+ m_uiserver->processedFiles( job->progressId(), files );
+}
+
+void Observer::slotProcessedDirs( TDEIO::Job* job, unsigned long dirs )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotProcessedDirs " << job << " " << dirs << endl;
+ m_uiserver->processedDirs( job->progressId(), dirs );
+}
+
+void Observer::slotSpeed( TDEIO::Job* job, unsigned long speed )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotSpeed " << job << " " << speed << endl;
+ m_uiserver->speed( job->progressId(), speed );
+}
+
+void Observer::slotPercent( TDEIO::Job* job, unsigned long percent )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotPercent " << job << " " << percent << endl;
+ m_uiserver->percent( job->progressId(), percent );
+}
+
+void Observer::slotInfoMessage( TDEIO::Job* job, const TQString & msg )
+{
+ m_uiserver->infoMessage( job->progressId(), msg );
+}
+
+void Observer::slotCopying( TDEIO::Job* job, const KURL& from, const KURL& to )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotCopying " << job << " " << from.url() << " " << to.url() << endl;
+ m_uiserver->copying( job->progressId(), from, to );
+}
+
+void Observer::slotMoving( TDEIO::Job* job, const KURL& from, const KURL& to )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotMoving " << job << " " << from.url() << " " << to.url() << endl;
+ m_uiserver->moving( job->progressId(), from, to );
+}
+
+void Observer::slotDeleting( TDEIO::Job* job, const KURL& url )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotDeleting " << job << " " << url.url() << endl;
+ m_uiserver->deleting( job->progressId(), url );
+}
+
+void Observer::slotTransferring( TDEIO::Job* job, const KURL& url )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotTransferring " << job << " " << url.url() << endl;
+ m_uiserver->transferring( job->progressId(), url );
+}
+
+void Observer::slotCreatingDir( TDEIO::Job* job, const KURL& dir )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotCreatingDir " << job << " " << dir.url() << endl;
+ m_uiserver->creatingDir( job->progressId(), dir );
+}
+
+void Observer::slotCanResume( TDEIO::Job* job, TDEIO::filesize_t offset )
+{
+ //kdDebug(KDEBUG_OBSERVER) << "** Observer::slotCanResume " << job << " " << TDEIO::number(offset) << endl;
+ m_uiserver->canResume64( job->progressId(), offset );
+}
+
+void Observer::stating( TDEIO::Job* job, const KURL& url )
+{
+ m_uiserver->stating( job->progressId(), url );
+}
+
+void Observer::mounting( TDEIO::Job* job, const TQString & dev, const TQString & point )
+{
+ m_uiserver->mounting( job->progressId(), dev, point );
+}
+
+void Observer::unmounting( TDEIO::Job* job, const TQString & point )
+{
+ m_uiserver->unmounting( job->progressId(), point );
+}
+
+bool Observer::openPassDlg( const TQString& prompt, TQString& user,
+ TQString& pass, bool readOnly )
+{
+ AuthInfo info;
+ info.prompt = prompt;
+ info.username = user;
+ info.password = pass;
+ info.readOnly = readOnly;
+ bool result = openPassDlg ( info );
+ if ( result )
+ {
+ user = info.username;
+ pass = info.password;
+ }
+ return result;
+}
+
+bool Observer::openPassDlg( TDEIO::AuthInfo& info )
+{
+ kdDebug(KDEBUG_OBSERVER) << "Observer::openPassDlg: User= " << info.username
+ << ", Message= " << info.prompt << endl;
+ int result = TDEIO::PasswordDialog::getNameAndPassword( info.username, info.password,
+ &info.keepPassword, info.prompt,
+ info.readOnly, info.caption,
+ info.comment, info.commentLabel );
+ if ( result == TQDialog::Accepted )
+ {
+ info.setModified( true );
+ return true;
+ }
+ return false;
+}
+
+int Observer::messageBox( int progressId, int type, const TQString &text,
+ const TQString &caption, const TQString &buttonYes,
+ const TQString &buttonNo )
+{
+ return messageBox( progressId, type, text, caption, buttonYes, buttonNo, TQString::null );
+}
+
+int Observer::messageBox( int progressId, int type, const TQString &text,
+ const TQString &caption, const TQString &buttonYes,
+ const TQString &buttonNo, const TQString &dontAskAgainName )
+{
+ kdDebug() << "Observer::messageBox " << type << " " << text << " - " << caption << endl;
+ int result = -1;
+ TDEConfig *config = new TDEConfig("tdeioslaverc");
+ KMessageBox::setDontShowAskAgainConfig(config);
+
+ switch (type) {
+ case TDEIO::SlaveBase::QuestionYesNo:
+ result = KMessageBox::questionYesNo( 0L, // parent ?
+ text, caption, buttonYes, buttonNo, dontAskAgainName );
+ break;
+ case TDEIO::SlaveBase::WarningYesNo:
+ result = KMessageBox::warningYesNo( 0L, // parent ?
+ text, caption, buttonYes, buttonNo, dontAskAgainName );
+ break;
+ case TDEIO::SlaveBase::WarningContinueCancel:
+ result = KMessageBox::warningContinueCancel( 0L, // parent ?
+ text, caption, buttonYes, dontAskAgainName );
+ break;
+ case TDEIO::SlaveBase::WarningYesNoCancel:
+ result = KMessageBox::warningYesNoCancel( 0L, // parent ?
+ text, caption, buttonYes, buttonNo, dontAskAgainName );
+ break;
+ case TDEIO::SlaveBase::Information:
+ KMessageBox::information( 0L, // parent ?
+ text, caption, dontAskAgainName );
+ result = 1; // whatever
+ break;
+ case TDEIO::SlaveBase::SSLMessageBox:
+ {
+ TQCString observerAppId = caption.utf8(); // hack, see slaveinterface.cpp
+ // Contact the object "TDEIO::Observer" in the application <appId>
+ // Yes, this could be the same application we are, but not necessarily.
+ Observer_stub observer( observerAppId, "TDEIO::Observer" );
+
+ TDEIO::MetaData meta = observer.metadata( progressId );
+ KSSLInfoDlg *kid = new KSSLInfoDlg(meta["ssl_in_use"].upper()=="TRUE", 0L /*parent?*/, 0L, true);
+ KSSLCertificate *x = KSSLCertificate::fromString(meta["ssl_peer_certificate"].local8Bit());
+ if (x) {
+ // Set the chain back onto the certificate
+ TQStringList cl =
+ TQStringList::split(TQString("\n"), meta["ssl_peer_chain"]);
+ TQPtrList<KSSLCertificate> ncl;
+
+ ncl.setAutoDelete(true);
+ for (TQStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
+ KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
+ if (y) ncl.append(y);
+ }
+
+ if (ncl.count() > 0)
+ x->chain().setChain(ncl);
+
+ kid->setup( x,
+ meta["ssl_peer_ip"],
+ text, // the URL
+ meta["ssl_cipher"],
+ meta["ssl_cipher_desc"],
+ meta["ssl_cipher_version"],
+ meta["ssl_cipher_used_bits"].toInt(),
+ meta["ssl_cipher_bits"].toInt(),
+ KSSLCertificate::KSSLValidation(meta["ssl_cert_state"].toInt()));
+ kdDebug(7024) << "Showing SSL Info dialog" << endl;
+ kid->exec();
+ delete x;
+ kdDebug(7024) << "SSL Info dialog closed" << endl;
+ } else {
+ KMessageBox::information( 0L, // parent ?
+ i18n("The peer SSL certificate appears to be corrupt."), i18n("SSL") );
+ }
+ // This doesn't have to get deleted. It deletes on it's own.
+ result = 1; // whatever
+ break;
+ }
+ default:
+ kdWarning() << "Observer::messageBox: unknown type " << type << endl;
+ result = 0;
+ break;
+ }
+ KMessageBox::setDontShowAskAgainConfig(0);
+ delete config;
+ return result;
+#if 0
+ TQByteArray data, replyData;
+ TQCString replyType;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << progressId;
+ arg << type;
+ arg << text;
+ arg << caption;
+ arg << buttonYes;
+ arg << buttonNo;
+ if ( kapp->dcopClient()->call( "tdeio_uiserver", "UIServer", "messageBox(int,int,TQString,TQString,TQString,TQString)", data, replyType, replyData, true )
+ && replyType == "int" )
+ {
+ int result;
+ TQDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ kdDebug(KDEBUG_OBSERVER) << "Observer::messageBox got result " << result << endl;
+ return result;
+ }
+ kdDebug(KDEBUG_OBSERVER) << "Observer::messageBox call failed" << endl;
+ return 0;
+#endif
+}
+
+RenameDlg_Result Observer::open_RenameDlg( TDEIO::Job* job,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ RenameDlg_Mode mode, TQString& newDest,
+ TDEIO::filesize_t sizeSrc,
+ TDEIO::filesize_t sizeDest,
+ time_t ctimeSrc,
+ time_t ctimeDest,
+ time_t mtimeSrc,
+ time_t mtimeDest
+ )
+{
+ kdDebug(KDEBUG_OBSERVER) << "Observer::open_RenameDlg job=" << job << endl;
+ if (job)
+ kdDebug(KDEBUG_OBSERVER) << " progressId=" << job->progressId() << endl;
+ // Hide existing dialog box if any
+ if (job && job->progressId())
+ m_uiserver->setJobVisible( job->progressId(), false );
+ // We now do it in process => KDE4: move this code out of Observer (back to job.cpp), so that
+ // opening the rename dialog doesn't start uiserver for nothing if progressId=0 (e.g. F2 in konq)
+ RenameDlg_Result res = TDEIO::open_RenameDlg( caption, src, dest, mode,
+ newDest, sizeSrc, sizeDest,
+ ctimeSrc, ctimeDest, mtimeSrc,
+ mtimeDest );
+ if (job && job->progressId())
+ m_uiserver->setJobVisible( job->progressId(), true );
+ return res;
+}
+
+SkipDlg_Result Observer::open_SkipDlg( TDEIO::Job* job,
+ bool _multi,
+ const TQString& _error_text )
+{
+ kdDebug(KDEBUG_OBSERVER) << "Observer::open_SkipDlg job=" << job << " progressId=" << job->progressId() << endl;
+ // Hide existing dialog box if any
+ if (job && job->progressId())
+ m_uiserver->setJobVisible( job->progressId(), false );
+ // We now do it in process. So this method is a useless wrapper around TDEIO::open_RenameDlg.
+ SkipDlg_Result res = TDEIO::open_SkipDlg( _multi, _error_text );
+ if (job && job->progressId())
+ m_uiserver->setJobVisible( job->progressId(), true );
+ return res;
+}
+
+void Observer::virtual_hook( int id, void* data )
+{ DCOPObject::virtual_hook( id, data ); }
+
+#include "observer.moc"
diff --git a/tdeio/tdeio/observer.h b/tdeio/tdeio/observer.h
new file mode 100644
index 000000000..f018bb399
--- /dev/null
+++ b/tdeio/tdeio/observer.h
@@ -0,0 +1,213 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+ 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 __kio_observer_h__
+#define __kio_observer_h__
+
+#include <tqobject.h>
+#include <dcopobject.h>
+#include <tqintdict.h>
+
+#include <tdeio/global.h>
+#include <tdeio/authinfo.h>
+#include "tdeio/job.h"
+#include "tdeio/skipdlg.h"
+#include "tdeio/renamedlg.h"
+
+class UIServer_stub;
+class KURL;
+
+namespace TDEIO {
+ class Job;
+}
+
+/**
+ * Observer for TDEIO::Job progress information.
+ *
+ * This class, of which there is always only one instance,
+ * "observes" what jobs do and forwards this information
+ * to the progress-info server.
+ *
+ * It is a DCOP object so that the UI server can call the
+ * kill method when the user presses Cancel.
+ *
+ * Usually jobs are automatically registered by the
+ * TDEIO::Scheduler, so you do not have to care about that.
+ *
+ * @short Observer for TDEIO::Job progress information
+ * @author David Faure <faure@kde.org>
+ */
+class TDEIO_EXPORT Observer : public TQObject, public DCOPObject {
+
+ K_DCOP
+ Q_OBJECT
+
+public:
+
+ /**
+ * Returns the unique observer object.
+ * @return the observer object
+ */
+ static Observer * self() {
+ if (!s_pObserver) s_pObserver = new Observer;
+ return s_pObserver;
+ }
+
+ /**
+ * Called by the job constructor, to signal its presence to the
+ * UI Server.
+ * @param job the new job
+ * @param showProgress true to show progress, false otherwise
+ * @return the progress ID assigned by the UI Server to the Job.
+ */
+ int newJob( TDEIO::Job * job, bool showProgress );
+
+ /**
+ * Called by the job destructor, to tell the UI Server that
+ * the job ended.
+ * @param progressId the progress ID of the job, as returned by newJob()
+ */
+ void jobFinished( int progressId );
+
+ /**
+ * @deprecated use TDEIO::AutoInfo
+ */
+ bool openPassDlg( const TQString& prompt, TQString& user, TQString& pass,
+ bool readOnly );
+
+ /**
+ * Opens a password dialog.
+ * @param info the authentication information
+ * @return true if successful ("ok" clicked), false otherwise
+ */
+ bool openPassDlg( TDEIO::AuthInfo& info );
+
+ /**
+ * Popup a message box. See TDEIO::SlaveBase.
+ * This doesn't use DCOP anymore, it shows the dialog in the application's process.
+ * Otherwise, other apps would block when trying to communicate with UIServer.
+ * @param progressId the progress ID of the job, as returned by newJob()
+ * @param type the type of the message box
+ * @param text the text to show
+ * @param caption the window caption
+ * @param buttonYes the text of the "Yes" button
+ * @param buttonNo the text of the "No button
+ */
+ static int messageBox( int progressId, int type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo );
+
+ /**
+ * Popup a message box. See TDEIO::SlaveBase.
+ * This doesn't use DCOP anymore, it shows the dialog in the application's process.
+ * Otherwise, other apps would block when trying to communicate with UIServer.
+ * @param progressId the progress ID of the job, as returned by newJob()
+ * @param type the type of the message box
+ * @param text the text to show
+ * @param caption the window caption
+ * @param buttonYes the text of the "Yes" button
+ * @param buttonNo the text of the "No button
+ * @param dontAskAgainName A checkbox is added with which further confirmation can be turned off.
+ * The string is used to lookup and store the setting in tdeioslaverc.
+ * @since 3.3
+ */
+ static int messageBox( int progressId, int type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName );
+
+ /**
+ * @internal
+ * See renamedlg.h
+ */
+ TDEIO::RenameDlg_Result open_RenameDlg( TDEIO::Job * job,
+ const TQString & caption,
+ const TQString& src, const TQString & dest,
+ TDEIO::RenameDlg_Mode mode,
+ TQString& newDest,
+ TDEIO::filesize_t sizeSrc = (TDEIO::filesize_t) -1,
+ TDEIO::filesize_t sizeDest = (TDEIO::filesize_t) -1,
+ time_t ctimeSrc = (time_t) -1,
+ time_t ctimeDest = (time_t) -1,
+ time_t mtimeSrc = (time_t) -1,
+ time_t mtimeDest = (time_t) -1
+ );
+
+ /**
+ * @internal
+ * See skipdlg.h
+ */
+ TDEIO::SkipDlg_Result open_SkipDlg( TDEIO::Job * job,
+ bool multi,
+ const TQString & error_text );
+
+k_dcop:
+ /**
+ * Called by the UI Server (using DCOP) if the user presses cancel.
+ * @param progressId the progress ID of the job, as returned by newJob()
+ */
+ void killJob( int progressId );
+
+ /**
+ * Called by the UI Server (using DCOP) to get all the metadata of the job
+ * @param progressId the progress IDof the job, as returned by newJob()
+ */
+ TDEIO::MetaData metadata( int progressId );
+
+protected:
+
+ static Observer * s_pObserver;
+ Observer();
+ ~Observer() {}
+
+ UIServer_stub * m_uiserver;
+
+ TQIntDict< TDEIO::Job > m_dctJobs;
+
+public slots:
+
+ void slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size );
+ void slotTotalFiles( TDEIO::Job*, unsigned long files );
+ void slotTotalDirs( TDEIO::Job*, unsigned long dirs );
+
+ void slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t size );
+ void slotProcessedFiles( TDEIO::Job*, unsigned long files );
+ void slotProcessedDirs( TDEIO::Job*, unsigned long dirs );
+
+ void slotSpeed( TDEIO::Job*, unsigned long speed );
+ void slotPercent( TDEIO::Job*, unsigned long percent );
+ void slotInfoMessage( TDEIO::Job*, const TQString & msg );
+
+ void slotCopying( TDEIO::Job*, const KURL& from, const KURL& to );
+ void slotMoving( TDEIO::Job*, const KURL& from, const KURL& to );
+ void slotDeleting( TDEIO::Job*, const KURL& url );
+ /// @since 3.1
+ void slotTransferring( TDEIO::Job*, const KURL& url );
+ void slotCreatingDir( TDEIO::Job*, const KURL& dir );
+ // currently unused
+ void slotCanResume( TDEIO::Job*, TDEIO::filesize_t offset );
+
+public:
+ void stating( TDEIO::Job*, const KURL& url );
+ void mounting( TDEIO::Job*, const TQString & dev, const TQString & point );
+ void unmounting( TDEIO::Job*, const TQString & point );
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class ObserverPrivate* d;
+};
+
+// -*- mode: c++; c-basic-offset: 2 -*-
+#endif
diff --git a/tdeio/tdeio/passdlg.cpp b/tdeio/tdeio/passdlg.cpp
new file mode 100644
index 000000000..54bcec3b2
--- /dev/null
+++ b/tdeio/tdeio/passdlg.cpp
@@ -0,0 +1,367 @@
+/* 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.
+*/
+
+#include "passdlg.h"
+
+#include <tqapplication.h>
+#include <tqcheckbox.h>
+#include <tqhbox.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqsimplerichtext.h>
+#include <tqstylesheet.h>
+
+#include <kcombobox.h>
+#include <tdeconfig.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+using namespace TDEIO;
+
+struct PasswordDialog::PasswordDialogPrivate
+{
+ TQGridLayout *layout;
+ TQLineEdit* userEdit;
+ KLineEdit* passEdit;
+ TQLabel* userNameLabel;
+ TQLabel* prompt;
+ TQCheckBox* keepCheckBox;
+ TQMap<TQString,TQString> knownLogins;
+ KComboBox* userEditCombo;
+ TQHBox* userNameHBox;
+
+ bool keep;
+ short unsigned int nRow;
+};
+
+PasswordDialog::PasswordDialog( const TQString& prompt, const TQString& user,
+ bool enableKeep, bool modal, TQWidget* parent,
+ const char* name )
+ :KDialogBase( parent, name, modal, i18n("Password"), Ok|Cancel, Ok, true)
+{
+ init ( prompt, user, enableKeep );
+}
+
+PasswordDialog::~PasswordDialog()
+{
+ delete d;
+}
+
+void PasswordDialog::init( const TQString& prompt, const TQString& user,
+ bool enableKeep )
+{
+ TQWidget *main = makeMainWidget();
+
+ d = new PasswordDialogPrivate;
+ d->keep = false;
+ d->nRow = 0;
+ d->keepCheckBox = 0;
+
+ TDEConfig* cfg = TDEGlobal::config();
+ TDEConfigGroupSaver saver( cfg, "Passwords" );
+
+ d->layout = new TQGridLayout( main, 9, 3, spacingHint(), marginHint());
+ d->layout->addColSpacing(1, 5);
+
+ // Row 0: pixmap prompt
+ TQLabel* lbl;
+ TQPixmap pix( TDEGlobal::iconLoader()->loadIcon( "password", KIcon::NoGroup, KIcon::SizeHuge, 0, 0, true));
+ if ( !pix.isNull() )
+ {
+ lbl = new TQLabel( main );
+ lbl->setPixmap( pix );
+ lbl->setAlignment( Qt::AlignLeft|Qt::AlignVCenter );
+ lbl->setFixedSize( lbl->sizeHint() );
+ d->layout->addWidget( lbl, 0, 0, Qt::AlignLeft );
+ }
+ d->prompt = new TQLabel( main );
+ d->prompt->setAlignment( Qt::AlignLeft|Qt::AlignVCenter|TQt::WordBreak );
+ d->layout->addWidget( d->prompt, 0, 2, Qt::AlignLeft );
+ if ( prompt.isEmpty() )
+ setPrompt( i18n( "You need to supply a username and a password" ) );
+ else
+ setPrompt( prompt );
+
+ // Row 1: Row Spacer
+ d->layout->addRowSpacing( 1, 7 );
+
+ // Row 2-3: Reserved for an additional comment
+
+ // Row 4: Username field
+ d->userNameLabel = new TQLabel( i18n("&Username:"), main );
+ d->userNameLabel->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
+ d->userNameLabel->setFixedSize( d->userNameLabel->sizeHint() );
+ d->userNameHBox = new TQHBox( main );
+
+ d->userEdit = new KLineEdit( d->userNameHBox );
+ TQSize s = d->userEdit->sizeHint();
+ d->userEdit->setFixedHeight( s.height() );
+ d->userEdit->setMinimumWidth( s.width() );
+ d->userNameLabel->setBuddy( d->userEdit );
+ d->layout->addWidget( d->userNameLabel, 4, 0 );
+ d->layout->addWidget( d->userNameHBox, 4, 2 );
+
+ // Row 5: Row spacer
+ d->layout->addRowSpacing( 5, 4 );
+
+ // Row 6: Password field
+ lbl = new TQLabel( i18n("&Password:"), main );
+ lbl->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
+ lbl->setFixedSize( lbl->sizeHint() );
+ TQHBox* hbox = new TQHBox( main );
+ d->passEdit = new KLineEdit( hbox );
+ if ( cfg->readEntry("EchoMode", "OneStar") == "NoEcho" )
+ d->passEdit->setEchoMode( TQLineEdit::NoEcho );
+ else
+ d->passEdit->setEchoMode( TQLineEdit::Password );
+ s = d->passEdit->sizeHint();
+ d->passEdit->setFixedHeight( s.height() );
+ d->passEdit->setMinimumWidth( s.width() );
+ lbl->setBuddy( d->passEdit );
+ d->layout->addWidget( lbl, 6, 0 );
+ d->layout->addWidget( hbox, 6, 2 );
+
+ if ( enableKeep )
+ {
+ // Row 7: Add spacer
+ d->layout->addRowSpacing( 7, 4 );
+ // Row 8: Keep Password
+ hbox = new TQHBox( main );
+ d->keepCheckBox = new TQCheckBox( i18n("&Keep password"), hbox );
+ d->keepCheckBox->setFixedSize( d->keepCheckBox->sizeHint() );
+ d->keep = cfg->readBoolEntry("Keep", false );
+ d->keepCheckBox->setChecked( d->keep );
+ connect(d->keepCheckBox, TQT_SIGNAL(toggled( bool )), TQT_SLOT(slotKeep( bool )));
+ d->layout->addWidget( hbox, 8, 2 );
+ }
+
+ // Configure necessary key-bindings and connect necessar slots and signals
+ connect( d->userEdit, TQT_SIGNAL(returnPressed()), d->passEdit, TQT_SLOT(setFocus()) );
+ connect( d->passEdit, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotOk()) );
+
+ if ( !user.isEmpty() )
+ {
+ d->userEdit->setText( user );
+ d->passEdit->setFocus();
+ }
+ else
+ d->userEdit->setFocus();
+
+ d->userEditCombo = 0;
+// setFixedSize( sizeHint() );
+}
+
+TQString PasswordDialog::username() const
+{
+ return d->userEdit->text();
+}
+
+TQString PasswordDialog::password() const
+{
+ return d->passEdit->text();
+}
+
+void PasswordDialog::setKeepPassword( bool b )
+{
+ if ( d->keepCheckBox )
+ d->keepCheckBox->setChecked( b );
+}
+
+bool PasswordDialog::keepPassword() const
+{
+ return d->keep;
+}
+
+static void calculateLabelSize(TQLabel *label)
+{
+ TQString qt_text = label->text();
+
+ int pref_width = 0;
+ int pref_height = 0;
+ // Calculate a proper size for the text.
+ {
+ TQSimpleRichText rt(qt_text, label->font());
+ TQRect d = TDEGlobalSettings::desktopGeometry(label->topLevelWidget());
+
+ pref_width = d.width() / 4;
+ rt.setWidth(pref_width-10);
+ int used_width = rt.widthUsed();
+ pref_height = rt.height();
+ if (used_width <= pref_width)
+ {
+ while(true)
+ {
+ int new_width = (used_width * 9) / 10;
+ rt.setWidth(new_width-10);
+ int new_height = rt.height();
+ if (new_height > pref_height)
+ break;
+ used_width = rt.widthUsed();
+ if (used_width > new_width)
+ break;
+ }
+ pref_width = used_width;
+ }
+ else
+ {
+ if (used_width > (pref_width *2))
+ pref_width = pref_width *2;
+ else
+ pref_width = used_width;
+ }
+ }
+ label->setFixedSize(TQSize(pref_width+10, pref_height));
+}
+
+void PasswordDialog::addCommentLine( const TQString& label,
+ const TQString comment )
+{
+ if (d->nRow > 0)
+ return;
+
+ TQWidget *main = mainWidget();
+
+ TQLabel* lbl = new TQLabel( label, main);
+ lbl->setAlignment( Qt::AlignVCenter|Qt::AlignRight );
+ lbl->setFixedSize( lbl->sizeHint() );
+ d->layout->addWidget( lbl, d->nRow+2, 0, Qt::AlignLeft );
+ lbl = new TQLabel( comment, main);
+ lbl->setAlignment( Qt::AlignVCenter|Qt::AlignLeft|TQt::WordBreak );
+ calculateLabelSize(lbl);
+ d->layout->addWidget( lbl, d->nRow+2, 2, Qt::AlignLeft );
+ d->layout->addRowSpacing( 3, 10 ); // Add a spacer
+ d->nRow++;
+}
+
+void PasswordDialog::slotKeep( bool keep )
+{
+ d->keep = keep;
+}
+
+static TQString qrichtextify( const TQString& text )
+{
+ if ( text.isEmpty() || text[0] == '<' )
+ return text;
+
+ TQStringList lines = TQStringList::split('\n', text);
+ for(TQStringList::Iterator it = lines.begin(); it != lines.end(); ++it)
+ {
+ *it = TQStyleSheet::convertFromPlainText( *it, TQStyleSheetItem::WhiteSpaceNormal );
+ }
+
+ return lines.join(TQString::null);
+}
+
+void PasswordDialog::setPrompt(const TQString& prompt)
+{
+ TQString text = qrichtextify(prompt);
+ d->prompt->setText(text);
+ calculateLabelSize(d->prompt);
+}
+
+void PasswordDialog::setPassword(const TQString &p)
+{
+ d->passEdit->setText(p);
+}
+
+void PasswordDialog::setUserReadOnly( bool readOnly )
+{
+ d->userEdit->setReadOnly( readOnly );
+ if ( readOnly && d->userEdit->hasFocus() )
+ d->passEdit->setFocus();
+}
+
+void PasswordDialog::setKnownLogins( const TQMap<TQString, TQString>& knownLogins )
+{
+ const int nr = knownLogins.count();
+ if ( nr == 0 )
+ return;
+ if ( nr == 1 ) {
+ d->userEdit->setText( knownLogins.begin().key() );
+ setPassword( knownLogins.begin().data() );
+ return;
+ }
+
+ Q_ASSERT( !d->userEdit->isReadOnly() );
+ if ( !d->userEditCombo ) {
+ delete d->userEdit;
+ d->userEditCombo = new KComboBox( true, d->userNameHBox );
+ d->userEdit = d->userEditCombo->lineEdit();
+ TQSize s = d->userEditCombo->sizeHint();
+ d->userEditCombo->setFixedHeight( s.height() );
+ d->userEditCombo->setMinimumWidth( s.width() );
+ d->userNameLabel->setBuddy( d->userEditCombo );
+ d->layout->addWidget( d->userNameHBox, 4, 2 );
+ }
+
+ d->knownLogins = knownLogins;
+ d->userEditCombo->insertStringList( knownLogins.keys() );
+ d->userEditCombo->setFocus();
+
+ connect( d->userEditCombo, TQT_SIGNAL( activated( const TQString& ) ),
+ this, TQT_SLOT( slotActivated( const TQString& ) ) );
+}
+
+void PasswordDialog::slotActivated( const TQString& userName )
+{
+ TQMap<TQString, TQString>::ConstIterator it = d->knownLogins.find( userName );
+ if ( it != d->knownLogins.end() )
+ setPassword( it.data() );
+}
+
+
+int PasswordDialog::getNameAndPassword( TQString& user, TQString& pass, bool* keep,
+ const TQString& prompt, bool readOnly,
+ const TQString& caption,
+ const TQString& comment,
+ const TQString& label )
+{
+ PasswordDialog* dlg;
+ if( keep )
+ dlg = new PasswordDialog( prompt, user, (*keep) );
+ else
+ dlg = new PasswordDialog( prompt, user );
+
+ if ( !caption.isEmpty() )
+ dlg->setPlainCaption( caption );
+ else
+ dlg->setPlainCaption( i18n("Authorization Dialog") );
+
+ if ( !comment.isEmpty() )
+ dlg->addCommentLine( label, comment );
+
+ if ( readOnly )
+ dlg->setUserReadOnly( readOnly );
+
+ int ret = dlg->exec();
+ if ( ret == Accepted )
+ {
+ user = dlg->username();
+ pass = dlg->password();
+ if ( keep ) { (*keep) = dlg->keepPassword(); }
+ }
+ delete dlg;
+ return ret;
+ }
+
+void PasswordDialog::virtual_hook( int id, void* data )
+{ KDialogBase::virtual_hook( id, data ); }
+
+#include "passdlg.moc"
diff --git a/tdeio/tdeio/passdlg.h b/tdeio/tdeio/passdlg.h
new file mode 100644
index 000000000..864023398
--- /dev/null
+++ b/tdeio/tdeio/passdlg.h
@@ -0,0 +1,175 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2000 Dawit Alemayehu <adawit@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 __kio_pass_dlg_h__
+#define __kio_pass_dlg_h__
+
+#include <kdialogbase.h>
+
+class TQGridLayout;
+
+namespace TDEIO {
+
+/**
+ * A dialog for requesting a login and a password from the end user.
+ *
+ * KIO-Slave authors are encouraged to use SlaveBase::openPassDlg
+ * instead of directly instantiating this dialog.
+ * @short dialog for requesting login and password from the end user
+ */
+class TDEIO_EXPORT PasswordDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Create a password dialog.
+ *
+ * @param prompt instructional text to be shown.
+ * @param user username, if known initially.
+ * @param enableKeep if true, shows checkbox that makes password persistent until KDE is shutdown.
+ * @param modal if true, the dialog will be modal (default:true).
+ * @param parent the parent widget (default:NULL).
+ * @param name the dialog name (default:NULL).
+ */
+ PasswordDialog( const TQString& prompt, const TQString& user,
+ bool enableKeep = false, bool modal=true,
+ TQWidget* parent=0, const char* name=0 );
+
+ /**
+ * Destructor
+ */
+ ~PasswordDialog();
+
+ /**
+ * Sets the prompt to show to the user.
+ * @param prompt instructional text to be shown.
+ */
+ void setPrompt( const TQString& prompt );
+
+ /**
+ * Adds a comment line to the dialog.
+ *
+ * This function allows you to add one additional comment
+ * line to this widget. Calling this function after a
+ * comment has already been added will not have any effect.
+ *
+ * @param label label for comment (ex:"Command:")
+ * @param comment the actual comment text.
+ */
+ void addCommentLine( const TQString& label, const TQString comment );
+
+ /**
+ * Returns the password entered by the user.
+ * @return the password
+ */
+ TQString password() const;
+
+ /**
+ * Returns the username entered by the user.
+ * @return the user name
+ */
+ TQString username() const;
+
+ /**
+ * Determines whether supplied authorization should
+ * persist even after the application has been closed.
+ * @return true to keep the password
+ */
+ bool keepPassword() const;
+
+ /**
+ * Check or uncheck the "keep password" checkbox.
+ * This can be used to check it before showing the dialog, to tell
+ * the user that the password is stored already (e.g. in the wallet).
+ * enableKeep must have been set to true in the constructor.
+ */
+ void setKeepPassword( bool b );
+
+ /**
+ * Sets the username field read-only and sets the
+ * focus to the password field.
+ *
+ * @param readOnly true to set the user field to read-only
+ */
+ void setUserReadOnly( bool readOnly );
+
+ /**
+ * @deprecated. Use setUserReadOnly(bool).
+ */
+ KDE_DEPRECATED void setEnableUserField( bool enable, bool=false ) {
+ setUserReadOnly( !enable );
+ };
+
+ /**
+ * Presets the password.
+ * @param password the password to set
+ * @since 3.1
+ */
+ void setPassword( const TQString& password );
+
+ /**
+ * Presets a number of login+password pairs that the user can choose from.
+ * The passwords can be empty if you simply want to offer usernames to choose from.
+ * This is incompatible with setUserReadOnly(true).
+ * @param knownLogins map of known logins: the keys are usernames, the values are passwords.
+ * @since 3.4
+ */
+ void setKnownLogins( const TQMap<TQString, TQString>& knownLogins );
+
+ /**
+ * A convienence static method for obtaining authorization
+ * information from the end user.
+ *
+ *
+ * @param user username
+ * @param pass password
+ * @param keep pointer to flag that indicates whether to keep password (can be null)
+ * @param prompt text to display to user.
+ * @param readOnly make the username field read-only.
+ * @param caption set the title bar to given text.
+ * @param comment extra comment to display to user.
+ * @param label optinal label for extra comment.
+ *
+ * @return Accepted/Rejected based on the user choice.
+ */
+ static int getNameAndPassword( TQString& user, TQString& pass, bool* keep,
+ const TQString& prompt = TQString::null,
+ bool readOnly = false,
+ const TQString& caption = TQString::null,
+ const TQString& comment = TQString::null,
+ const TQString& label = TQString::null );
+
+private slots:
+ void slotKeep( bool );
+ void slotActivated( const TQString& userName );
+
+private:
+ void init( const TQString&, const TQString&, bool );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ struct PasswordDialogPrivate;
+ PasswordDialogPrivate* d;
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/paste.cpp b/tdeio/tdeio/paste.cpp
new file mode 100644
index 000000000..fd24f9a0d
--- /dev/null
+++ b/tdeio/tdeio/paste.cpp
@@ -0,0 +1,308 @@
+/* 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.
+*/
+
+#include "paste.h"
+#include "pastedialog.h"
+
+#include "tdeio/job.h"
+#include "tdeio/global.h"
+#include "tdeio/netaccess.h"
+#include "tdeio/observer.h"
+#include "tdeio/renamedlg.h"
+#include "tdeio/kprotocolmanager.h"
+
+#include <kurl.h>
+#include <kurldrag.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <ktempfile.h>
+
+#include <tqapplication.h>
+#include <tqclipboard.h>
+#include <tqdragobject.h>
+#include <tqtextstream.h>
+#include <tqvaluevector.h>
+
+static KURL getNewFileName( const KURL &u, const TQString& text )
+{
+ bool ok;
+ TQString dialogText( text );
+ if ( dialogText.isEmpty() )
+ dialogText = i18n( "Filename for clipboard content:" );
+ TQString file = KInputDialog::getText( TQString::null, dialogText, TQString::null, &ok );
+ if ( !ok )
+ return KURL();
+
+ KURL myurl(u);
+ myurl.addPath( file );
+
+ if (TDEIO::NetAccess::exists(myurl, false, 0))
+ {
+ kdDebug(7007) << "Paste will overwrite file. Prompting..." << endl;
+ TDEIO::RenameDlg_Result res = TDEIO::R_OVERWRITE;
+
+ TQString newPath;
+ // Ask confirmation about resuming previous transfer
+ res = Observer::self()->open_RenameDlg(
+ 0L, i18n("File Already Exists"),
+ u.pathOrURL(),
+ myurl.pathOrURL(),
+ (TDEIO::RenameDlg_Mode) (TDEIO::M_OVERWRITE | TDEIO::M_SINGLE), newPath);
+
+ if ( res == TDEIO::R_RENAME )
+ {
+ myurl = newPath;
+ }
+ else if ( res == TDEIO::R_CANCEL )
+ {
+ return KURL();
+ }
+ }
+
+ return myurl;
+}
+
+// The finaly step: write _data to tempfile and move it to neW_url
+static TDEIO::CopyJob* pasteDataAsyncTo( const KURL& new_url, const TQByteArray& _data )
+{
+ KTempFile tempFile;
+ tempFile.dataStream()->writeRawBytes( _data.data(), _data.size() );
+ tempFile.close();
+
+ KURL orig_url;
+ orig_url.setPath(tempFile.name());
+
+ return TDEIO::move( orig_url, new_url );
+}
+
+#ifndef QT_NO_MIMECLIPBOARD
+static TDEIO::CopyJob* chooseAndPaste( const KURL& u, TQMimeSource* data,
+ const TQValueVector<TQCString>& formats,
+ const TQString& text,
+ TQWidget* widget,
+ bool clipboard )
+{
+ TQStringList formatLabels;
+ for ( uint i = 0; i < formats.size(); ++i ) {
+ const TQCString& fmt = formats[i];
+ KMimeType::Ptr mime = KMimeType::mimeType( fmt );
+ if ( mime != KMimeType::defaultMimeTypePtr() )
+ formatLabels.append( i18n( "%1 (%2)" ).arg( mime->comment() ).arg( fmt.data() ) );
+ else
+ formatLabels.append( fmt );
+ }
+
+ TQString dialogText( text );
+ if ( dialogText.isEmpty() )
+ dialogText = i18n( "Filename for clipboard content:" );
+ TDEIO::PasteDialog dlg( TQString::null, dialogText, TQString::null, formatLabels, widget, clipboard );
+
+ if ( dlg.exec() != KDialogBase::Accepted )
+ return 0;
+
+ if ( clipboard && dlg.clipboardChanged() ) {
+ KMessageBox::sorry( widget,
+ i18n( "The clipboard has changed since you used 'paste': "
+ "the chosen data format is no longer applicable. "
+ "Please copy again what you wanted to paste." ) );
+ return 0;
+ }
+
+ const TQString result = dlg.lineEditText();
+ const TQCString chosenFormat = formats[ dlg.comboItem() ];
+
+ kdDebug() << " result=" << result << " chosenFormat=" << chosenFormat << endl;
+ KURL new_url( u );
+ new_url.addPath( result );
+ // if "data" came from TQClipboard, then it was deleted already - by a nice 0-seconds timer
+ // In that case, get it again. Let's hope the user didn't copy something else meanwhile :/
+ if ( clipboard ) {
+ data = TQApplication::clipboard()->data();
+ }
+ const TQByteArray ba = data->encodedData( chosenFormat );
+ return pasteDataAsyncTo( new_url, ba );
+}
+#endif
+
+// KDE4: remove
+TDEIO_EXPORT bool TDEIO::isClipboardEmpty()
+{
+#ifndef QT_NO_MIMECLIPBOARD
+ TQMimeSource *data = TQApplication::clipboard()->data();
+ if ( data->provides( "text/uri-list" ) && data->encodedData( "text/uri-list" ).size() > 0 )
+ return false;
+#else
+ // Happens with some versions of Qt Embedded... :/
+ // Guess.
+ TQString data = TQApplication::clipboard()->text();
+ if(data.contains("://"))
+ return false;
+#endif
+ return true;
+}
+
+#ifndef QT_NO_MIMECLIPBOARD
+// The main method for dropping
+TDEIO::CopyJob* TDEIO::pasteMimeSource( TQMimeSource* data, const KURL& dest_url,
+ const TQString& dialogText, TQWidget* widget, bool clipboard )
+{
+ TQByteArray ba;
+
+ // Now check for plain text
+ // We don't want to display a mimetype choice for a TQTextDrag, those mimetypes look ugly.
+ TQString text;
+ if ( TQTextDrag::canDecode( data ) && TQTextDrag::decode( data, text ) )
+ {
+ TQTextStream txtStream( ba, IO_WriteOnly );
+ txtStream << text;
+ }
+ else
+ {
+ TQValueVector<TQCString> formats;
+ const char* fmt;
+ for ( int i = 0; ( fmt = data->format( i ) ); ++i ) {
+ if ( qstrcmp( fmt, "application/x-qiconlist" ) == 0 ) // see QIconDrag
+ continue;
+ if ( qstrcmp( fmt, "application/x-kde-cutselection" ) == 0 ) // see KonqDrag
+ continue;
+ if ( strchr( fmt, '/' ) == 0 ) // e.g. TARGETS, MULTIPLE, TIMESTAMP
+ continue;
+ formats.append( fmt );
+ }
+
+ if ( formats.size() == 0 )
+ return 0;
+
+ if ( formats.size() > 1 ) {
+ return chooseAndPaste( dest_url, data, formats, dialogText, widget, clipboard );
+ }
+ ba = data->encodedData( formats.first() );
+ }
+ if ( ba.size() == 0 )
+ {
+ KMessageBox::sorry(0, i18n("The clipboard is empty"));
+ return 0;
+ }
+
+ return pasteDataAsync( dest_url, ba, dialogText );
+}
+#endif
+
+// The main method for pasting
+TDEIO_EXPORT TDEIO::Job *TDEIO::pasteClipboard( const KURL& dest_url, bool move )
+{
+ if ( !dest_url.isValid() ) {
+ KMessageBox::error( 0L, i18n( "Malformed URL\n%1" ).arg( dest_url.url() ) );
+ return 0;
+ }
+
+#ifndef QT_NO_MIMECLIPBOARD
+ TQMimeSource *data = TQApplication::clipboard()->data();
+
+ // First check for URLs.
+ KURL::List urls;
+ if ( KURLDrag::canDecode( data ) && KURLDrag::decode( data, urls ) ) {
+ if ( urls.count() == 0 ) {
+ KMessageBox::error( 0L, i18n("The clipboard is empty"));
+ return 0;
+ }
+
+ TDEIO::Job *res = 0;
+ if ( move )
+ res = TDEIO::move( urls, dest_url );
+ else
+ res = TDEIO::copy( urls, dest_url );
+
+ // If moving, erase the clipboard contents, the original files don't exist anymore
+ if ( move )
+ TQApplication::clipboard()->clear();
+ return res;
+ }
+ return pasteMimeSource( data, dest_url, TQString::null, 0 /*TODO parent widget*/, true /*clipboard*/ );
+#else
+ TQByteArray ba;
+ TQTextStream txtStream( ba, IO_WriteOnly );
+ TQStringList data = TQStringList::split("\n", TQApplication::clipboard()->text());
+ KURL::List urls;
+ KURLDrag::decode(data, urls);
+ TQStringList::Iterator end(data.end());
+ for(TQStringList::Iterator it=data.begin(); it!=end; ++it)
+ txtStream << *it;
+ if ( ba.size() == 0 )
+ {
+ KMessageBox::sorry(0, i18n("The clipboard is empty"));
+ return 0;
+ }
+ return pasteDataAsync( dest_url, ba );
+#endif
+}
+
+
+TDEIO_EXPORT void TDEIO::pasteData( const KURL& u, const TQByteArray& _data )
+{
+ KURL new_url = getNewFileName( u, TQString::null );
+ // We could use TDEIO::put here, but that would require a class
+ // for the slotData call. With NetAccess, we can do a synchronous call.
+
+ if (new_url.isEmpty())
+ return;
+
+ KTempFile tempFile;
+ tempFile.setAutoDelete( true );
+ tempFile.dataStream()->writeRawBytes( _data.data(), _data.size() );
+ tempFile.close();
+
+ (void) TDEIO::NetAccess::upload( tempFile.name(), new_url, 0 );
+}
+
+TDEIO_EXPORT TDEIO::CopyJob* TDEIO::pasteDataAsync( const KURL& u, const TQByteArray& _data )
+{
+ return pasteDataAsync( u, _data, TQString::null );
+}
+
+TDEIO_EXPORT TDEIO::CopyJob* TDEIO::pasteDataAsync( const KURL& u, const TQByteArray& _data, const TQString& text )
+{
+ KURL new_url = getNewFileName( u, text );
+
+ if (new_url.isEmpty())
+ return 0;
+
+ return pasteDataAsyncTo( new_url, _data );
+}
+
+TDEIO_EXPORT TQString TDEIO::pasteActionText()
+{
+ TQMimeSource *data = TQApplication::clipboard()->data();
+ KURL::List urls;
+ if ( KURLDrag::canDecode( data ) && KURLDrag::decode( data, urls ) ) {
+ if ( urls.isEmpty() )
+ return TQString::null; // nothing to paste
+ else if ( urls.first().isLocalFile() )
+ return i18n( "&Paste File", "&Paste %n Files", urls.count() );
+ else
+ return i18n( "&Paste URL", "&Paste %n URLs", urls.count() );
+ } else if ( data->format(0) != 0 ) {
+ return i18n( "&Paste Clipboard Contents" );
+ } else {
+ return TQString::null;
+ }
+}
+
diff --git a/tdeio/tdeio/paste.h b/tdeio/tdeio/paste.h
new file mode 100644
index 000000000..66579831a
--- /dev/null
+++ b/tdeio/tdeio/paste.h
@@ -0,0 +1,125 @@
+/* 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 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 __kio_paste_h__
+#define __kio_paste_h__
+
+#include <tqstring.h>
+#include <tqmemarray.h>
+#include <kurl.h>
+class TQWidget;
+class TQMimeSource;
+
+// KDE4 TODO pass a parent widget to all methods that will display a message box
+
+namespace TDEIO {
+ class Job;
+ class CopyJob;
+
+ /**
+ * Pastes the content of the clipboard to the given destination URL.
+ * URLs are treated separately (performing a file copy)
+ * from other data (which is saved into a file after asking the user
+ * to choose a filename and the preferred data format)
+ *
+ * @param destURL the URL to receive the data
+ * @param move true to move the data, false to copy
+ * @return the job that handles the operation
+ * @see pasteData()
+ */
+ TDEIO_EXPORT Job *pasteClipboard( const KURL& destURL, bool move = false );
+
+ /**
+ * Pastes the given @p data to the given destination URL.
+ * NOTE: This method is blocking (uses NetAccess for saving the data).
+ * Please consider using pasteDataAsync instead.
+ *
+ * @param destURL the URL of the directory where the data will be pasted.
+ * The filename to use in that directory is prompted by this method.
+ * @param data the data to copy
+ * @see pasteClipboard()
+ */
+ TDEIO_EXPORT void pasteData( const KURL& destURL, const TQByteArray& data );
+
+ /**
+ * Pastes the given @p data to the given destination URL.
+ * Note that this method requires the caller to have chosen the QByteArray
+ * to paste before hand, unlike pasteClipboard and pasteMimeSource.
+ *
+ * @param destURL the URL of the directory where the data will be pasted.
+ * The filename to use in that directory is prompted by this method.
+ * @param data the data to copy
+ * @see pasteClipboard()
+ */
+ TDEIO_EXPORT CopyJob *pasteDataAsync( const KURL& destURL, const TQByteArray& data );
+
+ /**
+ * Pastes the given @p data to the given destination URL.
+ * Note that this method requires the caller to have chosen the QByteArray
+ * to paste before hand, unlike pasteClipboard and pasteMimeSource.
+ *
+ * @param destURL the URL of the directory where the data will be pasted.
+ * The filename to use in that directory is prompted by this method.
+ * @param data the data to copy
+ * @param dialogText the text to show in the dialog
+ * @see pasteClipboard()
+ */
+ TDEIO_EXPORT CopyJob *pasteDataAsync( const KURL& destURL, const TQByteArray& data, const TQString& dialogText ); // KDE4: merge with above
+
+
+ /**
+ * Save the given mimesource @p data to the given destination URL
+ * after offering the user to choose a data format.
+ * This is the method used when handling drops (of anything else than URLs)
+ * onto kdesktop and konqueror.
+ *
+ * @param data the TQMimeSource (e.g. a TQDropEvent)
+ * @param destURL the URL of the directory where the data will be pasted.
+ * The filename to use in that directory is prompted by this method.
+ * @param dialogText the text to show in the dialog
+ * @param widget parent widget to use for dialogs
+ * @param clipboard whether the TQMimeSource comes from TQClipboard. If you
+ * use pasteClipboard for that case, you never have to worry about this parameter.
+ *
+ * @see pasteClipboard()
+ *
+ * @since 3.5
+ */
+ TDEIO_EXPORT CopyJob* pasteMimeSource( TQMimeSource* data, const KURL& destURL,
+ const TQString& dialogText, TQWidget* widget,
+ bool clipboard = false );
+
+ /**
+ * Checks whether the clipboard contains any URLs.
+ * @return true if not
+ * Not used anymore, wrong method name, so it will disappear in KDE4.
+ */
+ TDEIO_EXPORT_DEPRECATED bool isClipboardEmpty();
+
+ /**
+ * Returns the text to use for the Paste action, when the application supports
+ * pasting files, urls, and clipboard data, using pasteClipboard().
+ * @return a string suitable for KAction::setText, or an empty string if pasting
+ * isn't possible right now.
+ *
+ * @since 3.5
+ */
+ TDEIO_EXPORT TQString pasteActionText();
+}
+
+#endif
diff --git a/tdeio/tdeio/pastedialog.cpp b/tdeio/tdeio/pastedialog.cpp
new file mode 100644
index 000000000..0252baff1
--- /dev/null
+++ b/tdeio/tdeio/pastedialog.cpp
@@ -0,0 +1,84 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 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 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 "pastedialog.h"
+
+#include <klineedit.h>
+#include <kmimetype.h>
+#include <klocale.h>
+
+#include <tqlayout.h>
+#include <tqlabel.h>
+#include <tqcombobox.h>
+#include <tqapplication.h>
+#include <tqclipboard.h>
+
+TDEIO::PasteDialog::PasteDialog( const TQString &caption, const TQString &label,
+ const TQString &value, const TQStringList& items,
+ TQWidget *parent,
+ bool clipboard )
+ : KDialogBase( parent, 0 /*name*/, true, caption, Ok|Cancel, Ok, true )
+{
+ TQFrame *frame = makeMainWidget();
+ TQVBoxLayout *layout = new TQVBoxLayout( frame, 0, spacingHint() );
+
+ m_label = new TQLabel( label, frame );
+ layout->addWidget( m_label );
+
+ m_lineEdit = new KLineEdit( value, frame );
+ layout->addWidget( m_lineEdit );
+
+ m_lineEdit->setFocus();
+ m_label->setBuddy( m_lineEdit );
+
+ layout->addWidget( new TQLabel( i18n( "Data format:" ), frame ) );
+ m_comboBox = new TQComboBox( frame );
+ m_comboBox->insertStringList( items );
+ layout->addWidget( m_comboBox );
+
+ layout->addStretch();
+
+ //connect( m_lineEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
+ // TQT_SLOT( slotEditTextChanged( const TQString & ) ) );
+ //connect( this, TQT_SIGNAL( user1Clicked() ), m_lineEdit, TQT_SLOT( clear() ) );
+
+ //slotEditTextChanged( value );
+ setMinimumWidth( 350 );
+
+ m_clipboardChanged = false;
+ if ( clipboard )
+ connect( TQApplication::clipboard(), TQT_SIGNAL( dataChanged() ),
+ this, TQT_SLOT( slotClipboardDataChanged() ) );
+}
+
+void TDEIO::PasteDialog::slotClipboardDataChanged()
+{
+ m_clipboardChanged = true;
+}
+
+TQString TDEIO::PasteDialog::lineEditText() const
+{
+ return m_lineEdit->text();
+}
+
+int TDEIO::PasteDialog::comboItem() const
+{
+ return m_comboBox->currentItem();
+}
+
+#include "pastedialog.moc"
diff --git a/tdeio/tdeio/pastedialog.h b/tdeio/tdeio/pastedialog.h
new file mode 100644
index 000000000..2e7bdfda1
--- /dev/null
+++ b/tdeio/tdeio/pastedialog.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 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 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 PASTEDIALOG_H
+#define PASTEDIALOG_H
+
+#include <kdialogbase.h>
+
+class TQComboBox;
+class KLineEdit;
+class TQLabel;
+
+namespace TDEIO {
+
+/**
+ * @internal
+ * Internal class used by paste.h. DO NOT USE.
+ * @since 3.5
+ */
+class PasteDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ PasteDialog( const TQString &caption, const TQString &label,
+ const TQString &value, const TQStringList& items,
+ TQWidget *parent, bool clipboard );
+
+ TQString lineEditText() const;
+ int comboItem() const;
+ bool clipboardChanged() const { return m_clipboardChanged; }
+
+private slots:
+ void slotClipboardDataChanged();
+
+private:
+ TQLabel* m_label;
+ KLineEdit* m_lineEdit;
+ TQComboBox* m_comboBox;
+ bool m_clipboardChanged;
+
+ class Private;
+ Private* d;
+};
+
+} // namespace
+
+
+#endif /* PASTEDIALOG_H */
+
diff --git a/tdeio/tdeio/posixacladdons.cpp b/tdeio/tdeio/posixacladdons.cpp
new file mode 100644
index 000000000..bae51592b
--- /dev/null
+++ b/tdeio/tdeio/posixacladdons.cpp
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Markus Brueffer <markus@brueffer.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "posixacladdons.h"
+
+#if defined(USE_POSIX_ACL) && !defined(HAVE_NON_POSIX_ACL_EXTENSIONS)
+
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <tqptrlist.h>
+
+class SortedEntryList : public TQPtrList<acl_entry_t>
+{
+protected:
+ int compareItems( TQPtrCollection::Item i1,
+ TQPtrCollection::Item i2 )
+ {
+ acl_entry_t *e1 = static_cast<acl_entry_t*>( i1 );
+ acl_entry_t *e2 = static_cast<acl_entry_t*>( i2 );
+
+ acl_tag_t tag1, tag2;
+ uid_t uid1 = 0, uid2 = 0;
+
+ acl_get_tag_type( *e1, &tag1 );
+ acl_get_tag_type( *e2, &tag2 );
+
+ if ( tag1 == ACL_USER || tag1 == ACL_GROUP )
+ uid1 = *( (uid_t*) acl_get_qualifier( *e1 ) );
+
+ if ( tag2 == ACL_USER || tag2 == ACL_GROUP )
+ uid2 = *( (uid_t*) acl_get_qualifier( *e2 ) );
+
+ if ( tag1 < tag2 )
+ return -1;
+ else if ( tag1 > tag2 )
+ return 1;
+
+ if ( uid1 < uid2 )
+ return -1;
+ else if ( uid1 > uid2 )
+ return 1;
+
+ return 0;
+ }
+};
+
+int acl_cmp(acl_t acl1, acl_t acl2)
+{
+ if ( !acl1 || !acl2 )
+ return -1;
+
+ SortedEntryList entries1, entries2;
+ entries1.setAutoDelete( true );
+ entries2.setAutoDelete( true );
+
+ /* Add ACL entries to vectors */
+ acl_entry_t *entry = new acl_entry_t;
+ int ret = acl_get_entry( acl1, ACL_FIRST_ENTRY, entry );
+ while( ret == 1 ) {
+ entries1.append( entry );
+ entry = new acl_entry_t;
+ ret = acl_get_entry( acl1, ACL_NEXT_ENTRY, entry );
+ }
+ delete entry;
+
+ entry = new acl_entry_t;
+ ret = acl_get_entry( acl2, ACL_FIRST_ENTRY, entry );
+ while ( ret == 1 ) {
+ entries2.append( entry );
+ entry = new acl_entry_t;
+ ret = acl_get_entry( acl2, ACL_NEXT_ENTRY, entry );
+ }
+ delete entry;
+
+ /* If the entry count differs, we are done */
+ if ( entries1.count() != entries2.count() )
+ return 1;
+
+ /* Sort vectors */
+ entries1.sort();
+ entries2.sort();
+
+ /* Compare all entries */
+ acl_permset_t permset1, permset2;
+ acl_tag_t tag1, tag2;
+ uid_t uid1, uid2;
+ acl_entry_t *e1, *e2;
+
+ for ( e1 = entries1.first(), e2 = entries2.first(); e1; e1 = entries1.next(), e2 = entries2.next() ) {
+ /* Compare tag */
+ if ( acl_get_tag_type( *e1, &tag1 ) != 0 ) return 1;
+ if ( acl_get_tag_type( *e2, &tag2 ) != 0 ) return 1;
+ if ( tag1 != tag2 ) return 1;
+
+ /* Compare permissions */
+ if ( acl_get_permset( *e1, &permset1 ) != 0 ) return 1;
+ if ( acl_get_permset( *e2, &permset2 ) != 0 ) return 1;
+ if ( *permset1 != *permset2) return 1;
+
+ /* Compare uid */
+ switch( tag1 ) {
+ case ACL_USER:
+ case ACL_GROUP:
+ uid1 = *( (uid_t*) acl_get_qualifier( *e1 ) );
+ uid2 = *( (uid_t*) acl_get_qualifier( *e2 ) );
+ if ( uid1 != uid2 ) return 1;
+ }
+ }
+
+ return 0;
+}
+
+acl_t acl_from_mode(mode_t mode)
+{
+ acl_t newACL = acl_init( 3 );
+ acl_entry_t entry;
+ acl_permset_t permset;
+ int error = 0;
+
+ /* Add owner entry */
+ if ( ( error = acl_create_entry( &newACL, &entry ) ) == 0 ) {
+ /* Set owner permissions */
+ acl_set_tag_type( entry, ACL_USER_OBJ );
+ acl_get_permset( entry, &permset );
+ acl_clear_perms( permset );
+ if ( mode & S_IRUSR ) acl_add_perm( permset, ACL_READ );
+ if ( mode & S_IWUSR ) acl_add_perm( permset, ACL_WRITE );
+ if ( mode & S_IXUSR ) acl_add_perm( permset, ACL_EXECUTE );
+ acl_set_permset( entry, permset );
+
+ /* Add group entry */
+ if ( ( error = acl_create_entry( &newACL, &entry ) ) == 0 ) {
+ /* Set group permissions */
+ acl_set_tag_type( entry, ACL_GROUP_OBJ );
+ acl_get_permset( entry, &permset );
+ acl_clear_perms( permset );
+ if ( mode & S_IRGRP ) acl_add_perm( permset, ACL_READ );
+ if ( mode & S_IWGRP ) acl_add_perm( permset, ACL_WRITE );
+ if ( mode & S_IXGRP ) acl_add_perm( permset, ACL_EXECUTE );
+ acl_set_permset( entry, permset );
+
+ /* Add other entry */
+ if ( ( error = acl_create_entry( &newACL, &entry ) ) == 0) {
+ /* Set other permissions */
+ acl_set_tag_type( entry, ACL_OTHER );
+ acl_get_permset( entry, &permset );
+ acl_clear_perms( permset );
+ if ( mode & S_IROTH ) acl_add_perm( permset, ACL_READ );
+ if ( mode & S_IWOTH ) acl_add_perm( permset, ACL_WRITE );
+ if ( mode & S_IXOTH ) acl_add_perm( permset, ACL_EXECUTE );
+ acl_set_permset( entry, permset );
+ }
+ }
+ }
+
+ if ( error ) {
+ acl_free ( &newACL );
+ return NULL;
+ }
+
+ return newACL;
+}
+
+int acl_equiv_mode(acl_t acl, mode_t *mode_p)
+{
+ acl_entry_t entry;
+ acl_tag_t tag;
+ acl_permset_t permset;
+ mode_t mode = 0;
+ int notEquiv = 0;
+
+ if ( !acl )
+ return -1;
+
+ int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry );
+ while ( ret == 1 ) {
+ acl_get_tag_type( entry, &tag );
+ acl_get_permset( entry, &permset );
+
+ switch( tag ) {
+ case ACL_USER_OBJ:
+ if ( acl_get_perm( permset, ACL_READ ) ) mode |= S_IRUSR;
+ if ( acl_get_perm( permset, ACL_WRITE ) ) mode |= S_IWUSR;
+ if ( acl_get_perm( permset, ACL_EXECUTE ) ) mode |= S_IXUSR;
+ break;
+
+ case ACL_GROUP_OBJ:
+ if ( acl_get_perm( permset, ACL_READ ) ) mode |= S_IRGRP;
+ if ( acl_get_perm( permset, ACL_WRITE ) ) mode |= S_IWGRP;
+ if ( acl_get_perm( permset, ACL_EXECUTE ) ) mode |= S_IXGRP;
+ break;
+
+ case ACL_OTHER:
+ if ( acl_get_perm( permset, ACL_READ ) ) mode |= S_IROTH;
+ if ( acl_get_perm( permset, ACL_WRITE ) ) mode |= S_IWOTH;
+ if ( acl_get_perm( permset, ACL_EXECUTE ) ) mode |= S_IXOTH;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ case ACL_MASK:
+ notEquiv = 1;
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry );
+ }
+
+ if (mode_p)
+ *mode_p = mode;
+
+ return notEquiv;
+}
+
+#endif // USE_POSIX_ACL
diff --git a/tdeio/tdeio/posixacladdons.h b/tdeio/tdeio/posixacladdons.h
new file mode 100644
index 000000000..45c4af245
--- /dev/null
+++ b/tdeio/tdeio/posixacladdons.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Markus Brueffer <markus@brueffer.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public 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 __posixacladdons_h__
+#define __posixacladdons_h__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqglobal.h>
+
+#if defined(USE_POSIX_ACL) && !defined(HAVE_NON_POSIX_ACL_EXTENSIIONS)
+
+#ifdef Q_OS_FREEBSD
+#include <sys/types.h>
+#endif
+
+#include <sys/acl.h>
+
+#ifdef Q_OS_FREEBSD
+#define acl_get_perm acl_get_perm_np
+#endif
+
+int acl_cmp(acl_t acl1, acl_t acl2);
+acl_t acl_from_mode(mode_t mode);
+int acl_equiv_mode(acl_t acl, mode_t *mode_p);
+
+#endif // USE_POSIX_ACL
+
+#endif // __posixacladdons_h__
diff --git a/tdeio/tdeio/previewjob.cpp b/tdeio/tdeio/previewjob.cpp
new file mode 100644
index 000000000..539d88bea
--- /dev/null
+++ b/tdeio/tdeio/previewjob.cpp
@@ -0,0 +1,597 @@
+// -*- c++ -*-
+// vim: ts=4 sw=4 et
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Malte Starostik <malte.starostik@t-online.de>
+
+ 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 "previewjob.h"
+
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+ #include <machine/param.h>
+#endif
+#include <sys/types.h>
+
+#ifdef Q_OS_UNIX
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqimage.h>
+#include <tqtimer.h>
+#include <tqregexp.h>
+
+#include <kdatastream.h> // Do not remove, needed for correct bool serialization
+#include <tdefileitem.h>
+#include <kapplication.h>
+#include <ktempfile.h>
+#include <ktrader.h>
+#include <kmdcodec.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include <tdeio/kservice.h>
+
+#include "previewjob.moc"
+
+namespace TDEIO { struct PreviewItem; }
+using namespace TDEIO;
+
+struct TDEIO::PreviewItem
+{
+ KFileItem *item;
+ KService::Ptr plugin;
+};
+
+struct TDEIO::PreviewJobPrivate
+{
+ enum { STATE_STATORIG, // if the thumbnail exists
+ STATE_GETORIG, // if we create it
+ STATE_CREATETHUMB // thumbnail:/ slave
+ } state;
+ KFileItemList initialItems;
+ const TQStringList *enabledPlugins;
+ // Our todo list :)
+ TQValueList<PreviewItem> items;
+ // The current item
+ PreviewItem currentItem;
+ // The modification time of that URL
+ time_t tOrig;
+ // Path to thumbnail cache for the current size
+ TQString thumbPath;
+ // Original URL of current item in TMS format
+ // (file:///path/to/file instead of file:/path/to/file)
+ TQString origName;
+ // Thumbnail file name for current item
+ TQString thumbName;
+ // Size of thumbnail
+ int width;
+ int height;
+ // Unscaled size of thumbnail (128 or 256 if cache is enabled)
+ int cacheWidth;
+ int cacheHeight;
+ // Whether the thumbnail should be scaled
+ bool bScale;
+ // Whether we should save the thumbnail
+ bool bSave;
+ // If the file to create a thumb for was a temp file, this is its name
+ TQString tempName;
+ // Over that, it's too much
+ unsigned long maximumSize;
+ // the size for the icon overlay
+ int iconSize;
+ // the transparency of the blended mimetype icon
+ int iconAlpha;
+ // Shared memory segment Id. The segment is allocated to a size
+ // of extent x extent x 4 (32 bit image) on first need.
+ int shmid;
+ // And the data area
+ uchar *shmaddr;
+ // Delete the KFileItems when done?
+ bool deleteItems;
+ bool succeeded;
+ // Root of thumbnail cache
+ TQString thumbRoot;
+ bool ignoreMaximumSize;
+ TQTimer startPreviewTimer;
+};
+
+PreviewJob::PreviewJob( const KFileItemList &items, int width, int height,
+ int iconSize, int iconAlpha, bool scale, bool save,
+ const TQStringList *enabledPlugins, bool deleteItems )
+ : TDEIO::Job( false /* no GUI */ )
+{
+ d = new PreviewJobPrivate;
+ d->tOrig = 0;
+ d->shmid = -1;
+ d->shmaddr = 0;
+ d->initialItems = items;
+ d->enabledPlugins = enabledPlugins;
+ d->width = width;
+ d->height = height ? height : width;
+ d->cacheWidth = d->width;
+ d->cacheHeight = d->height;
+ d->iconSize = iconSize;
+ d->iconAlpha = iconAlpha;
+ d->deleteItems = deleteItems;
+ d->bScale = scale;
+ d->bSave = save && scale;
+ d->succeeded = false;
+ d->currentItem.item = 0;
+ d->thumbRoot = TQDir::homeDirPath() + "/.thumbnails/";
+ d->ignoreMaximumSize = false;
+
+ // Return to event loop first, determineNextFile() might delete this;
+ connect(&d->startPreviewTimer, TQT_SIGNAL(timeout()), TQT_SLOT(startPreview()) );
+ d->startPreviewTimer.start(0, true);
+}
+
+PreviewJob::~PreviewJob()
+{
+#ifdef Q_OS_UNIX
+ if (d->shmaddr) {
+ shmdt((char*)d->shmaddr);
+ shmctl(d->shmid, IPC_RMID, 0);
+ }
+#endif
+ delete d;
+}
+
+void PreviewJob::startPreview()
+{
+ // Load the list of plugins to determine which mimetypes are supported
+ KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
+ TQMap<TQString, KService::Ptr> mimeMap;
+
+ for (KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
+ if (!d->enabledPlugins || d->enabledPlugins->contains((*it)->desktopEntryName()))
+ {
+ TQStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
+ for (TQStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
+ mimeMap.insert(*mt, *it);
+ }
+
+ // Look for images and store the items in our todo list :)
+ bool bNeedCache = false;
+ for (KFileItemListIterator it(d->initialItems); it.current(); ++it )
+ {
+ PreviewItem item;
+ item.item = it.current();
+ TQMap<TQString, KService::Ptr>::ConstIterator plugin = mimeMap.find(it.current()->mimetype());
+ if (plugin == mimeMap.end()
+ && (it.current()->mimetype() != "application/x-desktop")
+ && (it.current()->mimetype() != "media/builtin-mydocuments")
+ && (it.current()->mimetype() != "media/builtin-mycomputer")
+ && (it.current()->mimetype() != "media/builtin-mynetworkplaces")
+ && (it.current()->mimetype() != "media/builtin-printers")
+ && (it.current()->mimetype() != "media/builtin-trash")
+ && (it.current()->mimetype() != "media/builtin-webbrowser"))
+ {
+ TQString mimeType = it.current()->mimetype();
+ plugin = mimeMap.find(mimeType.replace(TQRegExp("/.*"), "/*"));
+
+ if (plugin == mimeMap.end())
+ {
+ // check mime type inheritance
+ KMimeType::Ptr mimeInfo = KMimeType::mimeType(it.current()->mimetype());
+ TQString parentMimeType = mimeInfo->parentMimeType();
+ while (!parentMimeType.isEmpty())
+ {
+ plugin = mimeMap.find(parentMimeType);
+ if (plugin != mimeMap.end()) break;
+
+ KMimeType::Ptr parentMimeInfo = KMimeType::mimeType(parentMimeType);
+ if (!parentMimeInfo) break;
+
+ parentMimeType = parentMimeInfo->parentMimeType();
+ }
+ }
+
+ if (plugin == mimeMap.end())
+ {
+ // check X-TDE-Text property
+ KMimeType::Ptr mimeInfo = KMimeType::mimeType(it.current()->mimetype());
+ TQVariant textProperty = mimeInfo->property("X-TDE-text");
+ if (textProperty.isValid() && textProperty.type() == TQVariant::Bool)
+ {
+ if (textProperty.toBool())
+ {
+ plugin = mimeMap.find("text/plain");
+ if (plugin == mimeMap.end())
+ {
+ plugin = mimeMap.find( "text/*" );
+ }
+ }
+ }
+ }
+ }
+
+ if (plugin != mimeMap.end())
+ {
+ item.plugin = *plugin;
+ d->items.append(item);
+ if (!bNeedCache && d->bSave &&
+ (it.current()->url().protocol() != "file" ||
+ !it.current()->url().directory( false ).startsWith(d->thumbRoot)) &&
+ (*plugin)->property("CacheThumbnail").toBool())
+ bNeedCache = true;
+ }
+ else
+ {
+ emitFailed(it.current());
+ if (d->deleteItems)
+ delete it.current();
+ }
+ }
+
+ // Read configuration value for the maximum allowed size
+ TDEConfig * config = TDEGlobal::config();
+ TDEConfigGroupSaver cgs( config, "PreviewSettings" );
+ d->maximumSize = config->readNumEntry( "MaximumSize", 1024*1024 /* 1MB */ );
+
+ if (bNeedCache)
+ {
+ if (d->width <= 128 && d->height <= 128) d->cacheWidth = d->cacheHeight = 128;
+ else d->cacheWidth = d->cacheHeight = 256;
+ d->thumbPath = d->thumbRoot + (d->cacheWidth == 128 ? "normal/" : "large/");
+ KStandardDirs::makeDir(d->thumbPath, 0700);
+ }
+ else
+ d->bSave = false;
+ determineNextFile();
+}
+
+void PreviewJob::removeItem( const KFileItem *item )
+{
+ for (TQValueList<PreviewItem>::Iterator it = d->items.begin(); it != d->items.end(); ++it)
+ if ((*it).item == item)
+ {
+ d->items.remove(it);
+ break;
+ }
+
+ if (d->currentItem.item == item)
+ {
+ subjobs.first()->kill();
+ subjobs.removeFirst();
+ determineNextFile();
+ }
+}
+
+void PreviewJob::setIgnoreMaximumSize(bool ignoreSize)
+{
+ d->ignoreMaximumSize = ignoreSize;
+}
+
+void PreviewJob::determineNextFile()
+{
+ if (d->currentItem.item)
+ {
+ if (!d->succeeded)
+ emitFailed();
+ if (d->deleteItems) {
+ delete d->currentItem.item;
+ d->currentItem.item = 0L;
+ }
+ }
+ // No more items ?
+ if ( d->items.isEmpty() )
+ {
+ emitResult();
+ return;
+ }
+ else
+ {
+ // First, stat the orig file
+ d->state = PreviewJobPrivate::STATE_STATORIG;
+ d->currentItem = d->items.first();
+ d->succeeded = false;
+ d->items.remove(d->items.begin());
+ TDEIO::Job *job = TDEIO::stat( d->currentItem.item->url(), false );
+ job->addMetaData( "no-auth-prompt", "true" );
+ addSubjob(job);
+ }
+}
+
+void PreviewJob::slotResult( TDEIO::Job *job )
+{
+ subjobs.remove( job );
+ Q_ASSERT ( subjobs.isEmpty() ); // We should have only one job at a time ...
+ switch ( d->state )
+ {
+ case PreviewJobPrivate::STATE_STATORIG:
+ {
+ if (job->error()) // that's no good news...
+ {
+ // Drop this one and move on to the next one
+ determineNextFile();
+ return;
+ }
+ TDEIO::UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
+ TDEIO::UDSEntry::ConstIterator it = entry.begin();
+ d->tOrig = 0;
+ int found = 0;
+ for( ; it != entry.end() && found < 2; it++ )
+ {
+ if ( (*it).m_uds == TDEIO::UDS_MODIFICATION_TIME )
+ {
+ d->tOrig = (time_t)((*it).m_long);
+ found++;
+ }
+ else if ( (*it).m_uds == TDEIO::UDS_SIZE )
+ {
+ if ( filesize_t((*it).m_long) > d->maximumSize &&
+ !d->ignoreMaximumSize &&
+ !d->currentItem.plugin->property("IgnoreMaximumSize").toBool() )
+ {
+ determineNextFile();
+ return;
+ }
+ found++;
+ }
+ }
+
+ if ( !d->currentItem.plugin->property( "CacheThumbnail" ).toBool() )
+ {
+ // This preview will not be cached, no need to look for a saved thumbnail
+ // Just create it, and be done
+ getOrCreateThumbnail();
+ return;
+ }
+
+ if ( statResultThumbnail() )
+ return;
+
+ getOrCreateThumbnail();
+ return;
+ }
+ case PreviewJobPrivate::STATE_GETORIG:
+ {
+ if (job->error())
+ {
+ determineNextFile();
+ return;
+ }
+
+ createThumbnail( static_cast<TDEIO::FileCopyJob*>(job)->destURL().path() );
+ return;
+ }
+ case PreviewJobPrivate::STATE_CREATETHUMB:
+ {
+ if (!d->tempName.isEmpty())
+ {
+ TQFile::remove(d->tempName);
+ d->tempName = TQString::null;
+ }
+ determineNextFile();
+ return;
+ }
+ }
+}
+
+bool PreviewJob::statResultThumbnail()
+{
+ if ( d->thumbPath.isEmpty() )
+ return false;
+
+ KURL url = d->currentItem.item->url();
+ // Don't include the password if any
+ url.setPass(TQString::null);
+ // The TMS defines local files as file:///path/to/file instead of KDE's
+ // way (file:/path/to/file)
+#ifdef KURL_TRIPLE_SLASH_FILE_PROT
+ d->origName = url.url();
+#else
+ if (url.protocol() == "file") d->origName = "file://" + url.path();
+ else d->origName = url.url();
+#endif
+
+ KMD5 md5( TQFile::encodeName( d->origName ).data() );
+ d->thumbName = TQFile::encodeName( md5.hexDigest() ) + ".png";
+
+ TQImage thumb;
+ if ( !thumb.load( d->thumbPath + d->thumbName ) ) return false;
+
+ if ( thumb.text( "Thumb::URI", 0 ) != d->origName ||
+ thumb.text( "Thumb::MTime", 0 ).toInt() != d->tOrig ) return false;
+
+ // Found it, use it
+ emitPreview( thumb );
+ d->succeeded = true;
+ determineNextFile();
+ return true;
+}
+
+
+void PreviewJob::getOrCreateThumbnail()
+{
+ // We still need to load the orig file ! (This is getting tedious) :)
+ const KFileItem* item = d->currentItem.item;
+ const TQString localPath = item->localPath();
+ if ( !localPath.isEmpty() )
+ createThumbnail( localPath );
+ else
+ {
+ d->state = PreviewJobPrivate::STATE_GETORIG;
+ KTempFile localFile;
+ KURL localURL;
+ localURL.setPath( d->tempName = localFile.name() );
+ const KURL currentURL = item->url();
+ TDEIO::Job * job = TDEIO::file_copy( currentURL, localURL, -1, true,
+ false, false /* No GUI */ );
+ job->addMetaData("thumbnail","1");
+ addSubjob(job);
+ }
+}
+
+// KDE 4: Make it const TQString &
+void PreviewJob::createThumbnail( TQString pixPath )
+{
+ d->state = PreviewJobPrivate::STATE_CREATETHUMB;
+ KURL thumbURL;
+ thumbURL.setProtocol("thumbnail");
+ thumbURL.setPath(pixPath);
+ TDEIO::TransferJob *job = TDEIO::get(thumbURL, false, false);
+ addSubjob(job);
+ connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), TQT_SLOT(slotThumbData(TDEIO::Job *, const TQByteArray &)));
+ bool save = d->bSave && d->currentItem.plugin->property("CacheThumbnail").toBool();
+ job->addMetaData("mimeType", d->currentItem.item->mimetype());
+ job->addMetaData("width", TQString().setNum(save ? d->cacheWidth : d->width));
+ job->addMetaData("height", TQString().setNum(save ? d->cacheHeight : d->height));
+ job->addMetaData("iconSize", TQString().setNum(save ? 64 : d->iconSize));
+ job->addMetaData("iconAlpha", TQString().setNum(d->iconAlpha));
+ job->addMetaData("plugin", d->currentItem.plugin->library());
+#ifdef Q_OS_UNIX
+ if (d->shmid == -1)
+ {
+ if (d->shmaddr) {
+ shmdt((char*)d->shmaddr);
+ shmctl(d->shmid, IPC_RMID, 0);
+ }
+ d->shmid = shmget(IPC_PRIVATE, d->cacheWidth * d->cacheHeight * 4, IPC_CREAT|0600);
+ if (d->shmid != -1)
+ {
+ d->shmaddr = (uchar *)(shmat(d->shmid, 0, SHM_RDONLY));
+ if (d->shmaddr == (uchar *)-1)
+ {
+ shmctl(d->shmid, IPC_RMID, 0);
+ d->shmaddr = 0;
+ d->shmid = -1;
+ }
+ }
+ else
+ d->shmaddr = 0;
+ }
+ if (d->shmid != -1)
+ job->addMetaData("shmid", TQString().setNum(d->shmid));
+#endif
+}
+
+void PreviewJob::slotThumbData(TDEIO::Job *, const TQByteArray &data)
+{
+ bool save = d->bSave &&
+ d->currentItem.plugin->property("CacheThumbnail").toBool() &&
+ (d->currentItem.item->url().protocol() != "file" ||
+ !d->currentItem.item->url().directory( false ).startsWith(d->thumbRoot));
+ TQImage thumb;
+#ifdef Q_OS_UNIX
+ if (d->shmaddr)
+ {
+ TQDataStream str(data, IO_ReadOnly);
+ int width, height, depth;
+ bool alpha;
+ str >> width >> height >> depth >> alpha;
+ thumb = TQImage(d->shmaddr, width, height, depth, 0, 0, TQImage::IgnoreEndian);
+ thumb.setAlphaBuffer(alpha);
+ }
+ else
+#endif
+ thumb.loadFromData(data);
+
+ if (save)
+ {
+ thumb.setText("Thumb::URI", 0, d->origName);
+ thumb.setText("Thumb::MTime", 0, TQString::number(d->tOrig));
+ thumb.setText("Thumb::Size", 0, number(d->currentItem.item->size()));
+ thumb.setText("Thumb::Mimetype", 0, d->currentItem.item->mimetype());
+ thumb.setText("Software", 0, "KDE Thumbnail Generator");
+ KTempFile temp(d->thumbPath + "kde-tmp-", ".png");
+ if (temp.status() == 0) //Only try to write out the thumbnail if we
+ { //actually created the temp file.
+ thumb.save(temp.name(), "PNG");
+ rename(TQFile::encodeName(temp.name()), TQFile::encodeName(d->thumbPath + d->thumbName));
+ }
+ }
+ emitPreview( thumb );
+ d->succeeded = true;
+}
+
+void PreviewJob::emitPreview(const TQImage &thumb)
+{
+ TQPixmap pix;
+ if (thumb.width() > d->width || thumb.height() > d->height)
+ {
+ double imgRatio = (double)thumb.height() / (double)thumb.width();
+ if (imgRatio > (double)d->height / (double)d->width)
+ pix.convertFromImage(
+ thumb.smoothScale((int)TQMAX((double)d->height / imgRatio, 1), d->height));
+ else pix.convertFromImage(
+ thumb.smoothScale(d->width, (int)TQMAX((double)d->width * imgRatio, 1)));
+ }
+ else pix.convertFromImage(thumb);
+ emit gotPreview(d->currentItem.item, pix);
+}
+
+void PreviewJob::emitFailed(const KFileItem *item)
+{
+ if (!item)
+ item = d->currentItem.item;
+ emit failed(item);
+}
+
+TQStringList PreviewJob::availablePlugins()
+{
+ TQStringList result;
+ KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
+ for (KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
+ if (!result.contains((*it)->desktopEntryName()))
+ result.append((*it)->desktopEntryName());
+ return result;
+}
+
+TQStringList PreviewJob::supportedMimeTypes()
+{
+ TQStringList result;
+ KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
+ for (KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
+ result += (*it)->property("MimeTypes").toStringList();
+ return result;
+}
+
+void PreviewJob::kill( bool quietly )
+{
+ d->startPreviewTimer.stop();
+ Job::kill( quietly );
+}
+
+PreviewJob *TDEIO::filePreview( const KFileItemList &items, int width, int height,
+ int iconSize, int iconAlpha, bool scale, bool save,
+ const TQStringList *enabledPlugins )
+{
+ return new PreviewJob(items, width, height, iconSize, iconAlpha,
+ scale, save, enabledPlugins);
+}
+
+PreviewJob *TDEIO::filePreview( const KURL::List &items, int width, int height,
+ int iconSize, int iconAlpha, bool scale, bool save,
+ const TQStringList *enabledPlugins )
+{
+ KFileItemList fileItems;
+ for (KURL::List::ConstIterator it = items.begin(); it != items.end(); ++it)
+ fileItems.append(new KFileItem(KFileItem::Unknown, KFileItem::Unknown, *it, true));
+ return new PreviewJob(fileItems, width, height, iconSize, iconAlpha,
+ scale, save, enabledPlugins, true);
+}
+
+void PreviewJob::virtual_hook( int id, void* data )
+{ TDEIO::Job::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/previewjob.h b/tdeio/tdeio/previewjob.h
new file mode 100644
index 000000000..9c62859c9
--- /dev/null
+++ b/tdeio/tdeio/previewjob.h
@@ -0,0 +1,182 @@
+// -*- c++ -*-
+// vim: ts=4 sw=4 et
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Malte Starostik <malte.starostik@t-online.de>
+
+ 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 __kio_previewjob_h__
+#define __kio_previewjob_h__
+
+#include <tdefileitem.h>
+#include <tdeio/job.h>
+
+class TQPixmap;
+
+namespace TDEIO {
+ /*!
+ * This class catches a preview (thumbnail) for files.
+ * @short KIO Job to get a thumbnail picture
+ */
+ class TDEIO_EXPORT PreviewJob : public TDEIO::Job
+ {
+ Q_OBJECT
+ public:
+ /**
+ * Creates a new PreviewJob.
+ * @param items a list of files to create previews for
+ * @param width the desired width
+ * @param height the desired height, 0 to use the @p width
+ * @param iconSize the size of the mimetype icon to overlay over the
+ * preview or zero to not overlay an icon. This has no effect if the
+ * preview plugin that will be used doesn't use icon overlays.
+ * @param iconAlpha transparency to use for the icon overlay
+ * @param scale if the image is to be scaled to the requested size or
+ * returned in its original size
+ * @param save if the image should be cached for later use
+ * @param enabledPlugins if non-zero, this points to a list containing
+ * the names of the plugins that may be used.
+ * @param deleteItems true to delete the items when done
+ */
+ PreviewJob( const KFileItemList &items, int width, int height,
+ int iconSize, int iconAlpha, bool scale, bool save,
+ const TQStringList *enabledPlugins, bool deleteItems = false );
+ virtual ~PreviewJob();
+
+ /**
+ * Removes an item from preview processing. Use this if you passed
+ * an item to filePreview and want to delete it now.
+ *
+ * @param item the item that should be removed from the preview queue
+ */
+ void removeItem( const KFileItem *item );
+
+ /**
+ * If @p ignoreSize is true, then the preview is always
+ * generated regardless of the settings
+ *
+ * @since KDE 3.4
+ **/
+ void setIgnoreMaximumSize(bool ignoreSize = true);
+
+ /**
+ * Returns a list of all available preview plugins. The list
+ * contains the basenames of the plugins' .desktop files (no path,
+ * no .desktop).
+ * @return the list of plugins
+ */
+ static TQStringList availablePlugins();
+
+ /**
+ * Returns a list of all supported MIME types. The list can
+ * contain entries like text/ * (without the space).
+ * @return the list of mime types
+ */
+ static TQStringList supportedMimeTypes();
+
+ /**
+ * Reimplemented for internal reasons
+ */
+ virtual void kill( bool quietly = true );
+
+ signals:
+ /**
+ * Emitted when a thumbnail picture for @p item has been successfully
+ * retrieved.
+ * @param item the file of the preview
+ * @param preview the preview image
+ */
+ void gotPreview( const KFileItem *item, const TQPixmap &preview );
+ /**
+ * Emitted when a thumbnail for @p item could not be created,
+ * either because a ThumbCreator for its MIME type does not
+ * exist, or because something went wrong.
+ * @param item the file that failed
+ */
+ void failed( const KFileItem *item );
+
+ protected:
+ void getOrCreateThumbnail();
+ bool statResultThumbnail();
+ void createThumbnail( TQString );
+
+ protected slots:
+ virtual void slotResult( TDEIO::Job *job );
+
+ private slots:
+ void startPreview();
+ void slotThumbData(TDEIO::Job *, const TQByteArray &);
+
+ private:
+ void determineNextFile();
+ void emitPreview(const TQImage &thumb);
+ void emitFailed(const KFileItem *item = 0);
+
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ struct PreviewJobPrivate *d;
+ };
+
+ /**
+ * Creates a PreviewJob to generate or retrieve a preview image
+ * for the given URL.
+ *
+ * @param items files to get previews for
+ * @param width the maximum width to use
+ * @param height the maximum height to use, if this is 0, the same
+ * value as width is used.
+ * @param iconSize the size of the mimetype icon to overlay over the
+ * preview or zero to not overlay an icon. This has no effect if the
+ * preview plugin that will be used doesn't use icon overlays.
+ * @param iconAlpha transparency to use for the icon overlay
+ * @param scale if the image is to be scaled to the requested size or
+ * returned in its original size
+ * @param save if the image should be cached for later use
+ * @param enabledPlugins if non-zero, this points to a list containing
+ * the names of the plugins that may be used.
+ * @return the new PreviewJob
+ * @see PreviewJob::availablePlugins()
+ */
+ TDEIO_EXPORT PreviewJob *filePreview( const KFileItemList &items, int width, int height = 0, int iconSize = 0, int iconAlpha = 70, bool scale = true, bool save = true, const TQStringList *enabledPlugins = 0 );
+
+ /**
+ * Creates a PreviewJob to generate or retrieve a preview image
+ * for the given URL.
+ *
+ * @param items files to get previews for
+ * @param width the maximum width to use
+ * @param height the maximum height to use, if this is 0, the same
+ * value as width is used.
+ * @param iconSize the size of the mimetype icon to overlay over the
+ * preview or zero to not overlay an icon. This has no effect if the
+ * preview plugin that will be used doesn't use icon overlays.
+ * @param iconAlpha transparency to use for the icon overlay
+ * @param scale if the image is to be scaled to the requested size or
+ * returned in its original size
+ * @param save if the image should be cached for later use
+ * @param enabledPlugins if non-zero, this points to a list containing
+ * the names of the plugins that may be used.
+ * @return the new PreviewJob
+ * @see PreviewJob::availablePlugins()
+ */
+ TDEIO_EXPORT PreviewJob *filePreview( const KURL::List &items, int width, int height = 0, int iconSize = 0, int iconAlpha = 70, bool scale = true, bool save = true, const TQStringList *enabledPlugins = 0 );
+}
+
+#endif
diff --git a/tdeio/tdeio/progressbase.cpp b/tdeio/tdeio/progressbase.cpp
new file mode 100644
index 000000000..146f4182e
--- /dev/null
+++ b/tdeio/tdeio/progressbase.cpp
@@ -0,0 +1,180 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 "jobclasses.h"
+#include "progressbase.h"
+
+namespace TDEIO {
+
+ProgressBase::ProgressBase( TQWidget *parent )
+ : TQWidget( parent )
+{
+ m_pJob = 0;
+
+ // delete dialog after the job is finished / canceled
+ m_bOnlyClean = false;
+
+ // stop job on close
+ m_bStopOnClose = true;
+}
+
+
+void ProgressBase::setJob( TDEIO::Job *job )
+{
+ // first connect all slots
+ connect( job, TQT_SIGNAL( percent( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ connect( job, TQT_SIGNAL( canceled( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ // then assign job
+ m_pJob = job;
+}
+
+
+void ProgressBase::setJob( TDEIO::CopyJob *job )
+{
+ // first connect all slots
+ connect( job, TQT_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ TQT_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( job, TQT_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ TQT_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( job, TQT_SIGNAL( processedFiles( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotProcessedFiles( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( processedDirs( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotProcessedDirs( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( speed( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotSpeed( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( percent( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( copying( TDEIO::Job*, const KURL& , const KURL& ) ),
+ TQT_SLOT( slotCopying( TDEIO::Job*, const KURL&, const KURL& ) ) );
+ connect( job, TQT_SIGNAL( moving( TDEIO::Job*, const KURL& , const KURL& ) ),
+ TQT_SLOT( slotMoving( TDEIO::Job*, const KURL&, const KURL& ) ) );
+ connect( job, TQT_SIGNAL( creatingDir( TDEIO::Job*, const KURL& ) ),
+ TQT_SLOT( slotCreatingDir( TDEIO::Job*, const KURL& ) ) );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ connect( job, TQT_SIGNAL( canceled( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ // then assign job
+ m_pJob = job;
+}
+
+
+void ProgressBase::setJob( TDEIO::DeleteJob *job )
+{
+ // first connect all slots
+ connect( job, TQT_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ TQT_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( job, TQT_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
+ TQT_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
+ connect( job, TQT_SIGNAL( processedFiles( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotProcessedFiles( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( processedDirs( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotProcessedDirs( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( speed( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotSpeed( TDEIO::Job*, unsigned long ) ) );
+ connect( job, TQT_SIGNAL( percent( TDEIO::Job*, unsigned long ) ),
+ TQT_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) );
+
+ connect( job, TQT_SIGNAL( deleting( TDEIO::Job*, const KURL& ) ),
+ TQT_SLOT( slotDeleting( TDEIO::Job*, const KURL& ) ) );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ connect( job, TQT_SIGNAL( canceled( TDEIO::Job* ) ),
+ TQT_SLOT( slotFinished( TDEIO::Job* ) ) );
+
+ // then assign job
+ m_pJob = job;
+}
+
+
+void ProgressBase::closeEvent( TQCloseEvent* ) {
+ // kill job when desired
+ if ( m_bStopOnClose ) {
+ slotStop();
+ } else {
+ // clean or delete dialog
+ if ( m_bOnlyClean ) {
+ slotClean();
+ } else {
+ delete this;
+ }
+ }
+}
+
+void ProgressBase::finished() {
+ // clean or delete dialog
+ if ( m_bOnlyClean ) {
+ slotClean();
+ } else {
+ deleteLater();
+ }
+}
+
+void ProgressBase::slotFinished( TDEIO::Job* ) {
+ finished();
+}
+
+
+void ProgressBase::slotStop() {
+ if ( m_pJob ) {
+ m_pJob->kill(); // this will call slotFinished
+ m_pJob = 0L;
+ } else {
+ slotFinished( 0 ); // here we call it ourselves
+ }
+
+ emit stopped();
+}
+
+
+void ProgressBase::slotClean() {
+ hide();
+}
+
+void ProgressBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+} /* namespace */
+
+#include "progressbase.moc"
+
diff --git a/tdeio/tdeio/progressbase.h b/tdeio/tdeio/progressbase.h
new file mode 100644
index 000000000..655edeee5
--- /dev/null
+++ b/tdeio/tdeio/progressbase.h
@@ -0,0 +1,271 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 __progressbase_h__
+#define __progressbase_h__
+
+
+#include <tqwidget.h>
+
+#include <tdeio/global.h>
+
+class KURL;
+namespace TDEIO {
+ class Job;
+ class CopyJob;
+ class DeleteJob;
+}
+
+namespace TDEIO
+{
+ enum Progress {
+ DEFAULT = 1,
+ STATUSBAR = 2,
+ LIST = 3
+ };
+
+/**
+* This class does all initialization stuff for progress,
+* like connecting signals to slots.
+* All slots are implemented as pure virtual methods.
+*
+* All custom IO progress dialog should inherit this class.
+* Add your GUI code to the constructor and implemement those virtual
+* methods which you need in order to display progress.
+*
+* E.g. StatusbarProgress only implements slotTotalSize(),
+* slotPercent() and slotSpeed().
+*
+* Custom progress dialog will be used like this :
+* \code
+* // create job
+* CopyJob* job = TDEIO::copy(...);
+* // create a dialog
+* MyCustomProgress *customProgress;
+* customProgress = new MyCustomProgress();
+* // connect progress with job
+* customProgress->setJob( job );
+* ...
+* \endcode
+*
+* There is a special method setStopOnClose() that controls the behavior of
+* the dialog.
+* @short Base class for IO progress dialogs.
+* @author Matej Koss <koss@miesto.sk>
+*/
+class TDEIO_EXPORT ProgressBase : public TQWidget {
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * Creates a new progress dialog.
+ * @param parent the parent of this dialog window, or 0
+ */
+ ProgressBase( TQWidget *parent );
+ ~ProgressBase() {}
+
+ /**
+ * Assign a TDEIO::Job to this progress dialog.
+ * @param job the job to assign
+ */
+ void setJob( TDEIO::Job *job );
+ /**
+ * Assign a TDEIO::Job to this progress dialog.
+ * @param job the job to assign
+ */
+ void setJob( TDEIO::CopyJob *job );
+ /**
+ * Assign a TDEIO::Job to this progress dialog.
+ * @param job the job to assign
+ */
+ void setJob( TDEIO::DeleteJob *job );
+
+ // should we stop the job when the dialog is closed ?
+ void setStopOnClose( bool stopOnClose ) { m_bStopOnClose = stopOnClose; }
+ bool stopOnClose() const { return m_bStopOnClose; }
+
+ // should we delete the dialog or just clean it when the job is finished ?
+ /**
+ * This controls whether the dialog should be deleted or only cleaned when
+ * the TDEIO::Job is finished (or canceled).
+ *
+ * If your dialog is an embedded widget and not a separate window, you should
+ * setOnlyClean(true) in the constructor of your custom dialog.
+ *
+ * @param onlyClean If true the dialog will only call method slotClean.
+ * If false the dialog will be deleted.
+ * @see onlyClean()
+ */
+ void setOnlyClean( bool onlyClean ) { m_bOnlyClean = onlyClean; }
+
+ /**
+ * Checks whether the dialog should be deleted or cleaned.
+ * @return true if the dialog only calls slotClean, false if it will be
+ * deleted
+ * @see setOnlyClean()
+ */
+ bool onlyClean() const { return m_bOnlyClean; }
+
+ /**
+ * Call when the operation finished.
+ * @since 3.1
+ */
+ void finished();
+
+public slots:
+ /**
+ * This method should be called for correct cancellation of IO operation
+ * Connect this to the progress widgets buttons etc.
+ */
+ void slotStop();
+ /**
+ * This method is called when the widget should be cleaned (after job is finished).
+ * redefine this for custom behavior.
+ */
+ virtual void slotClean();
+
+ // progress slots
+ /**
+ * Called to set the total size.
+ * @param job the TDEIO::Job
+ * @param size the total size in bytes
+ */
+ virtual void slotTotalSize( TDEIO::Job* job, TDEIO::filesize_t size ) {
+ Q_UNUSED(job);Q_UNUSED(size);}
+ /**
+ * Called to set the total number of files.
+ * @param job the TDEIO::Job
+ * @param files the number of files
+ */
+ virtual void slotTotalFiles( TDEIO::Job* job, unsigned long files ) {
+ Q_UNUSED(job);Q_UNUSED(files);}
+ /**
+ * Called to set the total number of directories.
+ * @param job the TDEIO::Job
+ * @param dirs the number of directories
+ */
+ virtual void slotTotalDirs( TDEIO::Job* job, unsigned long dirs ) {
+ Q_UNUSED(job);Q_UNUSED(dirs);}
+
+ /**
+ * Called to set the processed size.
+ * @param job the TDEIO::Job
+ * @param bytes the processed size in bytes
+ */
+ virtual void slotProcessedSize( TDEIO::Job* job, TDEIO::filesize_t bytes ) {
+ Q_UNUSED(job);Q_UNUSED(bytes);}
+ /**
+ * Called to set the number of processed files.
+ * @param job the TDEIO::Job
+ * @param files the number of files
+ */
+ virtual void slotProcessedFiles( TDEIO::Job* job, unsigned long files ) {
+ Q_UNUSED(job);Q_UNUSED(files);}
+ /**
+ * Called to set the number of processed directories.
+ * @param job the TDEIO::Job
+ * @param dirs the number of directories
+ */
+ virtual void slotProcessedDirs( TDEIO::Job* job, unsigned long dirs ) {
+ Q_UNUSED(job);Q_UNUSED(dirs);}
+
+ /**
+ * Called to set the speed.
+ * @param job the TDEIO::Job
+ * @param speed the speed in bytes/second
+ */
+ virtual void slotSpeed( TDEIO::Job* job, unsigned long speed ) {
+ Q_UNUSED(job);Q_UNUSED(speed);}
+
+ /**
+ * Called to set the percentage.
+ * @param job the TDEIO::Job
+ * @param percent the percentage
+ */
+ virtual void slotPercent( TDEIO::Job* job, unsigned long percent ) {
+ Q_UNUSED(job);Q_UNUSED(percent);}
+
+ /**
+ * Called when the job is copying.
+ * @param job the TDEIO::Job
+ * @param src the source of the operation
+ * @param dest the destination of the operation
+ */
+ virtual void slotCopying( TDEIO::Job* job, const KURL& src, const KURL& dest ) {
+ Q_UNUSED(job);Q_UNUSED(src);Q_UNUSED(dest);}
+ /**
+ * Called when the job is moving.
+ * @param job the TDEIO::Job
+ * @param src the source of the operation
+ * @param dest the destination of the operation
+ */
+ virtual void slotMoving( TDEIO::Job* job, const KURL& src, const KURL& dest ) {
+ Q_UNUSED(job);Q_UNUSED(src);Q_UNUSED(dest);}
+ /**
+ * Called when the job is deleting.
+ * @param job the TDEIO::Job
+ * @param url the URL to delete
+ */
+ virtual void slotDeleting( TDEIO::Job* job, const KURL& url) {
+ Q_UNUSED(job);Q_UNUSED(url);}
+ /**
+ * Called when the job is creating a directory.
+ * @param job the TDEIO::Job
+ * @param dir the URL of the directory to create
+ */
+ virtual void slotCreatingDir( TDEIO::Job* job, const KURL& dir ) {
+ Q_UNUSED(job);Q_UNUSED(dir);}
+
+ /**
+ * Called when the job is resuming..
+ * @param job the TDEIO::Job
+ * @param from the position to resume from in bytes
+ */
+ virtual void slotCanResume( TDEIO::Job* job, TDEIO::filesize_t from) {
+ Q_UNUSED(job);Q_UNUSED(from);}
+
+signals:
+ /**
+ * Called when the operation stopped.
+ */
+ void stopped();
+
+protected slots:
+ void slotFinished( TDEIO::Job* );
+
+protected:
+
+ virtual void closeEvent( TQCloseEvent * );
+
+ TDEIO::Job* m_pJob;
+
+private:
+ bool m_bOnlyClean;
+ bool m_bStopOnClose;
+
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class ProgressBasePrivate* d;
+};
+
+} /* namespace */
+
+#endif // __progressbase_h__
diff --git a/tdeio/tdeio/renamedlg.cpp b/tdeio/tdeio/renamedlg.cpp
new file mode 100644
index 000000000..d66130993
--- /dev/null
+++ b/tdeio/tdeio/renamedlg.cpp
@@ -0,0 +1,574 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ David Faure <faure@kde.org>
+ 2001 Holger Freyther <freyther@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 "tdeio/renamedlg.h"
+#include "tdeio/renamedlgplugin.h"
+#include <stdio.h>
+#include <assert.h>
+
+#include <tqfileinfo.h>
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqlineedit.h>
+#include <tqdir.h>
+
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <tdeio/global.h>
+#include <ktrader.h>
+#include <klibloader.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kmimetype.h>
+#include <kseparator.h>
+#include <kstringhandler.h>
+#include <kstdguiitem.h>
+#include <kguiitem.h>
+#include <ksqueezedtextlabel.h>
+
+#ifdef Q_WS_X11
+#include <twin.h>
+#endif
+
+using namespace TDEIO;
+
+class RenameDlg::RenameDlgPrivate
+{
+ public:
+ RenameDlgPrivate(){
+ bCancel = 0;
+ bRename = bSkip = bAutoSkip = bOverwrite = bOverwriteAll = 0;
+ bResume = bResumeAll = bSuggestNewName = 0;
+ m_pLineEdit = 0;
+ }
+ KPushButton *bCancel;
+ TQPushButton *bRename;
+ TQPushButton *bSkip;
+ TQPushButton *bAutoSkip;
+ TQPushButton *bOverwrite;
+ TQPushButton *bOverwriteAll;
+ TQPushButton *bResume;
+ TQPushButton *bResumeAll;
+ TQPushButton *bSuggestNewName;
+ TQLineEdit* m_pLineEdit;
+ KURL src;
+ KURL dest;
+ TQString mimeSrc;
+ TQString mimeDest;
+ bool modal;
+ bool plugin;
+};
+
+RenameDlg::RenameDlg(TQWidget *parent, const TQString & _caption,
+ const TQString &_src, const TQString &_dest,
+ RenameDlg_Mode _mode,
+ TDEIO::filesize_t sizeSrc,
+ TDEIO::filesize_t sizeDest,
+ time_t ctimeSrc,
+ time_t ctimeDest,
+ time_t mtimeSrc,
+ time_t mtimeDest,
+ bool _modal)
+ : TQDialog ( parent, "TDEIO::RenameDialog" , _modal )
+{
+ d = new RenameDlgPrivate( );
+ d->modal = _modal;
+#if 0
+ // Set "StaysOnTop", because this dialog is typically used in tdeio_uiserver,
+ // i.e. in a separate process.
+ // ####### This isn't the case anymore - remove?
+#if !defined(Q_WS_QWS) && !defined(Q_WS_WIN) //FIXME(E): Implement for QT Embedded & win32
+ if (d->modal)
+ KWin::setState( winId(), NET::StaysOnTop );
+#endif
+#endif
+
+ d->src = _src;
+ d->dest = _dest;
+ d->plugin = false;
+
+
+ setCaption( _caption );
+
+ d->bCancel = new KPushButton( KStdGuiItem::cancel(), this );
+ connect(d->bCancel, TQT_SIGNAL(clicked()), this, TQT_SLOT(b0Pressed()));
+
+ if ( ! (_mode & M_NORENAME ) ) {
+ d->bRename = new TQPushButton( i18n( "&Rename" ), this );
+ d->bRename->setEnabled(false);
+ d->bSuggestNewName = new TQPushButton( i18n( "Suggest New &Name" ), this );
+ connect(d->bSuggestNewName, TQT_SIGNAL(clicked()), this, TQT_SLOT(b8Pressed()));
+ connect(d->bRename, TQT_SIGNAL(clicked()), this, TQT_SLOT(b1Pressed()));
+ }
+
+ if ( ( _mode & M_MULTI ) && ( _mode & M_SKIP ) ) {
+ d->bSkip = new TQPushButton( i18n( "&Skip" ), this );
+ connect(d->bSkip, TQT_SIGNAL(clicked()), this, TQT_SLOT(b2Pressed()));
+
+ d->bAutoSkip = new TQPushButton( i18n( "&Auto Skip" ), this );
+ connect(d->bAutoSkip, TQT_SIGNAL(clicked()), this, TQT_SLOT(b3Pressed()));
+ }
+
+ if ( _mode & M_OVERWRITE ) {
+ d->bOverwrite = new TQPushButton( i18n( "&Overwrite" ), this );
+ connect(d->bOverwrite, TQT_SIGNAL(clicked()), this, TQT_SLOT(b4Pressed()));
+
+ if ( _mode & M_MULTI ) {
+ d->bOverwriteAll = new TQPushButton( i18n( "O&verwrite All" ), this );
+ connect(d->bOverwriteAll, TQT_SIGNAL(clicked()), this, TQT_SLOT(b5Pressed()));
+ }
+ }
+
+ if ( _mode & M_RESUME ) {
+ d->bResume = new TQPushButton( i18n( "&Resume" ), this );
+ connect(d->bResume, TQT_SIGNAL(clicked()), this, TQT_SLOT(b6Pressed()));
+
+ if ( _mode & M_MULTI )
+ {
+ d->bResumeAll = new TQPushButton( i18n( "R&esume All" ), this );
+ connect(d->bResumeAll, TQT_SIGNAL(clicked()), this, TQT_SLOT(b7Pressed()));
+ }
+ }
+
+ TQVBoxLayout* pLayout = new TQVBoxLayout( this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+ pLayout->addStrut( 360 ); // makes dlg at least that wide
+
+ // User tries to overwrite a file with itself ?
+ if ( _mode & M_OVERWRITE_ITSELF ) {
+ TQLabel *lb = new TQLabel( i18n( "This action would overwrite '%1' with itself.\n"
+ "Please enter a new file name:" ).arg( KStringHandler::csqueeze( d->src.pathOrURL(),100 ) ), this );
+ d->bRename->setText(i18n("C&ontinue"));
+ pLayout->addWidget( lb );
+ }
+ else if ( _mode & M_OVERWRITE ) {
+
+ // Figure out the mimetype and load one plugin
+ // (This is the only mode that is handled by plugins)
+ pluginHandling();
+ KTrader::OfferList plugin_offers;
+ if( d->mimeSrc != KMimeType::defaultMimeType() ){
+ plugin_offers = KTrader::self()->query(d->mimeSrc, "'RenameDlg/Plugin' in ServiceTypes");
+
+ }else if(d->mimeDest != KMimeType::defaultMimeType() ) {
+ plugin_offers = KTrader::self()->query(d->mimeDest, "'RenameDlg/Plugin' in ServiceTypes");
+ }
+ if(!plugin_offers.isEmpty() ){
+ kdDebug(7024) << "Offers" << endl;
+ KTrader::OfferList::ConstIterator it = plugin_offers.begin();
+ KTrader::OfferList::ConstIterator end = plugin_offers.end();
+ for( ; it != end; ++it ){
+ TQString libName = (*it)->library();
+ if( libName.isEmpty() ){
+ kdDebug(7024) << "lib is empty" << endl;
+ continue;
+ }
+ KLibrary *lib = KLibLoader::self()->library(libName.local8Bit() );
+ if(!lib) {
+ continue;
+ }
+ KLibFactory *factory = lib->factory();
+ if(!factory){
+ lib->unload();
+ continue;
+ }
+ TQObject *obj = factory->create( TQT_TQOBJECT(this), (*it)->name().latin1() );
+ if(!obj) {
+ lib->unload();
+ continue;
+ }
+ RenameDlgPlugin *plugin = static_cast<RenameDlgPlugin *>(TQT_TQWIDGET(obj));
+ if(!plugin ){
+ delete obj;
+ continue;
+ }
+ if( plugin->initialize( _mode, _src, _dest, d->mimeSrc,
+ d->mimeDest, sizeSrc, sizeDest,
+ ctimeSrc, ctimeDest,
+ mtimeSrc, mtimeDest ) ) {
+ d->plugin = true;
+ pLayout->addWidget(plugin );
+ kdDebug(7024) << "RenameDlgPlugin" << endl;
+ break;
+ } else {
+ delete obj;
+ }
+ }
+
+ }
+
+ if( !d->plugin ){
+ // No plugin found, build default dialog
+ TQGridLayout * gridLayout = new TQGridLayout( 0L, 9, 2, KDialog::marginHint(),
+ KDialog::spacingHint() );
+ pLayout->addLayout(TQT_TQLAYOUT(gridLayout));
+ gridLayout->setColStretch(0,0);
+ gridLayout->setColStretch(1,10);
+
+ TQString sentence1;
+ if (mtimeDest < mtimeSrc)
+ sentence1 = i18n("An older item named '%1' already exists.");
+ else if (mtimeDest == mtimeSrc)
+ sentence1 = i18n("A similar file named '%1' already exists.");
+ else
+ sentence1 = i18n("A newer item named '%1' already exists.");
+
+ TQLabel * lb1 = new KSqueezedTextLabel( sentence1.arg(d->dest.pathOrURL() ), this );
+ gridLayout->addMultiCellWidget( lb1, 0, 0, 0, 1 ); // takes the complete first line
+
+ lb1 = new TQLabel( this );
+ lb1->setPixmap( KMimeType::pixmapForURL( d->dest ) );
+ gridLayout->addMultiCellWidget( lb1, 1, 3, 0, 0 ); // takes the first column on rows 1-3
+
+ int row = 1;
+ if ( sizeDest != (TDEIO::filesize_t)-1 )
+ {
+ TQLabel * lb = new TQLabel( i18n("size %1").arg( TDEIO::convertSize(sizeDest) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+
+ }
+ if ( ctimeDest != (time_t)-1 )
+ {
+ TQDateTime dctime; dctime.setTime_t( ctimeDest );
+ TQLabel * lb = new TQLabel( i18n("created on %1").arg( TDEGlobal::locale()->formatDateTime(dctime) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+ }
+ if ( mtimeDest != (time_t)-1 )
+ {
+ TQDateTime dmtime; dmtime.setTime_t( mtimeDest );
+ TQLabel * lb = new TQLabel( i18n("modified on %1").arg( TDEGlobal::locale()->formatDateTime(dmtime) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+ }
+
+ if ( !d->src.isEmpty() )
+ {
+ // rows 1 to 3 are the details (size/ctime/mtime), row 4 is empty
+ gridLayout->addRowSpacing( 4, 20 );
+
+ TQLabel * lb2 = new KSqueezedTextLabel( i18n("The source file is '%1'").arg(d->src.pathOrURL()), this );
+ gridLayout->addMultiCellWidget( lb2, 5, 5, 0, 1 ); // takes the complete first line
+
+ lb2 = new TQLabel( this );
+ lb2->setPixmap( KMimeType::pixmapForURL( d->src ) );
+ gridLayout->addMultiCellWidget( lb2, 6, 8, 0, 0 ); // takes the first column on rows 6-8
+
+ row = 6;
+
+ if ( sizeSrc != (TDEIO::filesize_t)-1 )
+ {
+ TQLabel * lb = new TQLabel( i18n("size %1").arg( TDEIO::convertSize(sizeSrc) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+ }
+ if ( ctimeSrc != (time_t)-1 )
+ {
+ TQDateTime dctime; dctime.setTime_t( ctimeSrc );
+ TQLabel * lb = new TQLabel( i18n("created on %1").arg( TDEGlobal::locale()->formatDateTime(dctime) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+ }
+ if ( mtimeSrc != (time_t)-1 )
+ {
+ TQDateTime dmtime; dmtime.setTime_t( mtimeSrc );
+ TQLabel * lb = new TQLabel( i18n("modified on %1").arg( TDEGlobal::locale()->formatDateTime(dmtime) ), this );
+ gridLayout->addWidget( lb, row, 1 );
+ row++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // This is the case where we don't want to allow overwriting, the existing
+ // file must be preserved (e.g. when renaming).
+ TQString sentence1;
+ if (mtimeDest < mtimeSrc)
+ sentence1 = i18n("An older item named '%1' already exists.");
+ else if (mtimeDest == mtimeSrc)
+ sentence1 = i18n("A similar file named '%1' already exists.");
+ else
+ sentence1 = i18n("A newer item named '%1' already exists.");
+
+ TQLabel *lb = new KSqueezedTextLabel( sentence1.arg(d->dest.pathOrURL()), this );
+ pLayout->addWidget(lb);
+ }
+ TQHBoxLayout* layout2 = new TQHBoxLayout();
+ pLayout->addLayout( layout2 );
+
+ d->m_pLineEdit = new TQLineEdit( this );
+ layout2->addWidget( d->m_pLineEdit );
+ TQString fileName = d->dest.fileName();
+ d->m_pLineEdit->setText( TDEIO::decodeFileName( fileName ) );
+ if ( d->bRename || d->bOverwrite )
+ connect(d->m_pLineEdit, TQT_SIGNAL(textChanged(const TQString &)),
+ TQT_SLOT(enableRenameButton(const TQString &)));
+ if ( d->bSuggestNewName )
+ {
+ layout2->addWidget( d->bSuggestNewName );
+ setTabOrder( d->m_pLineEdit, d->bSuggestNewName );
+ }
+
+ KSeparator* separator = new KSeparator( this );
+ pLayout->addWidget( separator );
+
+ TQHBoxLayout* layout = new TQHBoxLayout();
+ pLayout->addLayout( layout );
+
+ layout->addStretch(1);
+
+ if ( d->bRename )
+ {
+ layout->addWidget( d->bRename );
+ setTabOrder( d->bRename, d->bCancel );
+ }
+ if ( d->bSkip )
+ {
+ layout->addWidget( d->bSkip );
+ setTabOrder( d->bSkip, d->bCancel );
+ }
+ if ( d->bAutoSkip )
+ {
+ layout->addWidget( d->bAutoSkip );
+ setTabOrder( d->bAutoSkip, d->bCancel );
+ }
+ if ( d->bOverwrite )
+ {
+ layout->addWidget( d->bOverwrite );
+ setTabOrder( d->bOverwrite, d->bCancel );
+ }
+ if ( d->bOverwriteAll )
+ {
+ layout->addWidget( d->bOverwriteAll );
+ setTabOrder( d->bOverwriteAll, d->bCancel );
+ }
+ if ( d->bResume )
+ {
+ layout->addWidget( d->bResume );
+ setTabOrder( d->bResume, d->bCancel );
+ }
+ if ( d->bResumeAll )
+ {
+ layout->addWidget( d->bResumeAll );
+ setTabOrder( d->bResumeAll, d->bCancel );
+ }
+
+ d->bCancel->setDefault( true );
+ layout->addWidget( d->bCancel );
+
+ resize( sizeHint() );
+}
+
+RenameDlg::~RenameDlg()
+{
+ delete d;
+ // no need to delete Pushbuttons,... qt will do this
+}
+
+void RenameDlg::enableRenameButton(const TQString &newDest)
+{
+ if ( newDest != TDEIO::decodeFileName( d->dest.fileName() ) && !newDest.isEmpty() )
+ {
+ d->bRename->setEnabled( true );
+ d->bRename->setDefault( true );
+ if ( d->bOverwrite )
+ d->bOverwrite->setEnabled( false ); // prevent confusion (#83114)
+ }
+ else
+ {
+ d->bRename->setEnabled( false );
+ if ( d->bOverwrite )
+ d->bOverwrite->setEnabled( true );
+ }
+}
+
+KURL RenameDlg::newDestURL()
+{
+ KURL newDest( d->dest );
+ TQString fileName = d->m_pLineEdit->text();
+ newDest.setFileName( TDEIO::encodeFileName( fileName ) );
+ return newDest;
+}
+
+void RenameDlg::b0Pressed()
+{
+ done( 0 );
+}
+
+// Rename
+void RenameDlg::b1Pressed()
+{
+ if ( d->m_pLineEdit->text().isEmpty() )
+ return;
+
+ KURL u = newDestURL();
+ if ( !u.isValid() )
+ {
+ KMessageBox::error( this, i18n( "Malformed URL\n%1" ).arg( u.url() ) );
+ return;
+ }
+
+ done( 1 );
+}
+
+TQString RenameDlg::suggestName(const KURL& baseURL, const TQString& oldName)
+{
+ TQString dotSuffix, suggestedName;
+ TQString basename = oldName;
+
+ int index = basename.find( '.' );
+ if ( index != -1 ) {
+ dotSuffix = basename.mid( index );
+ basename.truncate( index );
+ }
+
+ int pos = basename.findRev( '_' );
+ if(pos != -1 ){
+ TQString tmp = basename.mid( pos+1 );
+ bool ok;
+ int number = tmp.toInt( &ok );
+ if ( !ok ) {// ok there is no number
+ suggestedName = basename + "1" + dotSuffix;
+ }
+ else {
+ // yes there's already a number behind the _ so increment it by one
+ basename.replace( pos+1, tmp.length(), TQString::number(number+1) );
+ suggestedName = basename + dotSuffix;
+ }
+ }
+ else // no underscore yet
+ suggestedName = basename + "_1" + dotSuffix ;
+
+ // Check if suggested name already exists
+ bool exists = false;
+ // TODO: network transparency. However, using NetAccess from a modal dialog
+ // could be a problem, no? (given that it uses a modal widget itself....)
+ if ( baseURL.isLocalFile() )
+ exists = TQFileInfo( baseURL.path(+1) + suggestedName ).exists();
+
+ if ( !exists )
+ return suggestedName;
+ else // already exists -> recurse
+ return suggestName( baseURL, suggestedName );
+}
+
+// Propose button clicked
+void RenameDlg::b8Pressed()
+{
+ /* no name to play with */
+ if ( d->m_pLineEdit->text().isEmpty() )
+ return;
+
+ KURL destDirectory( d->dest );
+ destDirectory.setPath( destDirectory.directory() );
+ d->m_pLineEdit->setText( suggestName( destDirectory, d->m_pLineEdit->text() ) );
+ return;
+}
+
+void RenameDlg::b2Pressed()
+{
+ done( 2 );
+}
+
+void RenameDlg::b3Pressed()
+{
+ done( 3 );
+}
+
+void RenameDlg::b4Pressed()
+{
+ done( 4 );
+}
+
+void RenameDlg::b5Pressed()
+{
+ done( 5 );
+}
+
+void RenameDlg::b6Pressed()
+{
+ done( 6 );
+}
+
+void RenameDlg::b7Pressed()
+{
+ done( 7 );
+}
+
+static TQString mime( const KURL& src )
+{
+ KMimeType::Ptr type = KMimeType::findByURL( src );
+ //if( type->name() == KMimeType::defaultMimeType() ){ // ok no mimetype
+ // TQString ty = TDEIO::NetAccess::mimetype(d->src );
+ // return ty;
+ return type->name();
+}
+
+/** This will figure out the mimetypes and query for a plugin
+ * Loads it then and asks the plugin if it wants to do the job
+ * We'll take the first available mimetype
+ * The scanning for a mimetype will be done in 2 ways
+ *
+ */
+void RenameDlg::pluginHandling()
+{
+ d->mimeSrc = mime( d->src );
+ d->mimeDest = mime(d->dest );
+
+ kdDebug(7024) << "Source Mimetype: "<< d->mimeSrc << endl;
+ kdDebug(7024) << "Dest Mimetype: "<< d->mimeDest << endl;
+}
+
+
+RenameDlg_Result TDEIO::open_RenameDlg( const TQString & _caption,
+ const TQString & _src, const TQString & _dest,
+ RenameDlg_Mode _mode,
+ TQString& _new,
+ TDEIO::filesize_t sizeSrc,
+ TDEIO::filesize_t sizeDest,
+ time_t ctimeSrc,
+ time_t ctimeDest,
+ time_t mtimeSrc,
+ time_t mtimeDest)
+{
+ Q_ASSERT(kapp);
+
+ RenameDlg dlg( 0L, _caption, _src, _dest, _mode,
+ sizeSrc, sizeDest, ctimeSrc, ctimeDest, mtimeSrc, mtimeDest,
+ true /*modal*/ );
+ int i = dlg.exec();
+ _new = dlg.newDestURL().path();
+
+ return (RenameDlg_Result)i;
+}
+
+#include "renamedlg.moc"
+
+
+
+
+
diff --git a/tdeio/tdeio/renamedlg.h b/tdeio/tdeio/renamedlg.h
new file mode 100644
index 000000000..81f16df94
--- /dev/null
+++ b/tdeio/tdeio/renamedlg.h
@@ -0,0 +1,153 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ David Faure <faure@kde.org>
+ 2001 Holger Freyther <freyther@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 __kio_rename_dlg__
+#define __kio_rename_dlg__
+
+#include <kurl.h>
+#include <tqdialog.h>
+#include <tqstring.h>
+#include <sys/types.h>
+
+#include <tdeio/global.h>
+
+namespace TDEIO {
+
+// KDE4: get rid of M_OVERWRITE_ITSELF, trigger it internally if src==dest
+enum RenameDlg_Mode { M_OVERWRITE = 1, M_OVERWRITE_ITSELF = 2, M_SKIP = 4, M_SINGLE = 8, M_MULTI = 16, M_RESUME = 32, M_NORENAME = 64 };
+
+/**
+ * The result of open_RenameDlg().
+ */
+enum RenameDlg_Result { R_RESUME = 6, R_RESUME_ALL = 7, R_OVERWRITE = 4, R_OVERWRITE_ALL = 5, R_SKIP = 2, R_AUTO_SKIP = 3, R_RENAME = 1, R_CANCEL = 0 };
+
+
+/**
+ * A dialog for the options to rename two files.
+ * @short A dialog for renaming files.
+ * @since 3.1
+ */
+class TDEIO_EXPORT RenameDlg : public TQDialog
+{
+ Q_OBJECT
+public:
+ /**
+ * Construct a "rename" dialog.
+ * @param parent parent widget (often 0)
+ * @param caption the caption for the dialog box
+ * @param src the url to the file/dir we're trying to copy, as it's part of the text message
+ * @param dest the path to destination file/dir, i.e. the one that already exists
+ * @param mode parameters for the dialog (which buttons to show...),
+ * @param sizeSrc size of source file
+ * @param sizeDest size of destination file
+ * @param ctimeSrc creation time of source file
+ * @param ctimeDest creation time of destination file
+ * @param mtimeSrc modification time of source file
+ * @param mtimeDest modification time of destination file
+ * @param modal set to true for a modal dialog
+ * @see RenameDlg_Mode
+ */
+ RenameDlg( TQWidget *parent, const TQString & caption,
+ // KDE4: make those KURLs, and use pathOrURL() internally.
+ const TQString & src, const TQString & dest,
+ RenameDlg_Mode mode,
+ TDEIO::filesize_t sizeSrc = (TDEIO::filesize_t) -1,
+ TDEIO::filesize_t sizeDest = (TDEIO::filesize_t) -1,
+ time_t ctimeSrc = (time_t) -1,
+ time_t ctimeDest = (time_t) -1,
+ time_t mtimeSrc = (time_t) -1,
+ time_t mtimeDest = (time_t) -1,
+ bool modal = false );
+ ~RenameDlg();
+
+ /**
+ * @return the new destination
+ * valid only if RENAME was chosen
+ */
+ KURL newDestURL();
+
+ /**
+ * Given a directory path and a filename (which usually exists already),
+ * this function returns a suggested name for a file that doesn't exist
+ * in that directory. The existence is only checked for local urls though.
+ * The suggested file name is of the form foo_1 foo_2 etc.
+ * @since 3.4
+ */
+ static TQString suggestName(const KURL& baseURL, const TQString& oldName);
+
+public slots:
+ /// KDE4: rename to cancelPressed(), renamePressed() etc.
+ void b0Pressed();
+ void b1Pressed();
+ void b2Pressed();
+ void b3Pressed();
+ void b4Pressed();
+ void b5Pressed();
+ void b6Pressed();
+ void b7Pressed();
+ void b8Pressed();
+
+protected slots:
+ void enableRenameButton(const TQString &);
+private:
+ class RenameDlgPrivate;
+ RenameDlgPrivate *d;
+ void pluginHandling( );
+};
+
+ /**
+ * \addtogroup renamedlg "RenameDlg related Functions"
+ * @{
+ * \relates TDEIO::RenameDlg
+ * Construct a modal, parent-less "rename" dialog, and return
+ * a result code, as well as the new dest. Much easier to use than the
+ * class RenameDlg directly.
+
+ * @param caption the caption for the dialog box
+ * @param src the URL of the file/dir we're trying to copy, as it's part of the text message
+ * @param dest the URL of the destination file/dir, i.e. the one that already exists
+ * @param mode parameters for the dialog (which buttons to show...),
+ * see RenameDlg_Mode
+ * @param newDest the new destination path, valid if R_RENAME was returned.
+ * @param sizeSrc size of source file
+ * @param sizeDest size of destination file
+ * @param ctimeSrc creation time of source file
+ * @param ctimeDest creation time of destination file
+ * @param mtimeSrc modification time of source file
+ * @param mtimeDest modification time of destination file
+ * @return the result
+ */
+TDEIO_EXPORT RenameDlg_Result open_RenameDlg( const TQString & caption,
+ // KDE4: make those KURLs
+ const TQString& src, const TQString & dest,
+ RenameDlg_Mode mode, TQString& newDestPath,
+ TDEIO::filesize_t sizeSrc = (TDEIO::filesize_t) -1,
+ TDEIO::filesize_t sizeDest = (TDEIO::filesize_t) -1,
+ time_t ctimeSrc = (time_t) -1,
+ time_t ctimeDest = (time_t) -1,
+ time_t mtimeSrc = (time_t) -1,
+ time_t mtimeDest = (time_t) -1
+ );
+
+/*! @} */
+
+}
+#endif
diff --git a/tdeio/tdeio/renamedlgplugin.h b/tdeio/tdeio/renamedlgplugin.h
new file mode 100644
index 000000000..18daab017
--- /dev/null
+++ b/tdeio/tdeio/renamedlgplugin.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Holger Freyther <freyther@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 renamedlgplugin_h
+#define renamedlgplugin_h
+
+#include <tdeio/renamedlg.h>
+#include <tqdialog.h>
+#include <sys/types.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+/**
+ * This is the base class for all RenameDlg plugins.
+ * @short Base class for RenameDlg plugins.
+ * @since 3.1
+ */
+class TDEIO_EXPORT RenameDlgPlugin : public TQWidget
+{
+public:
+ /**
+ * This is the c'tor.
+ */
+ RenameDlgPlugin(TQDialog *dialog, const char *name, const TQStringList &/*list*/ = TQStringList() ): TQWidget(dialog, name ) {};
+
+ /**
+ * This function will be called by RenameDlg. The params are infos about the files.
+ * @return If the plugin want's to display it return true, if not return false
+ */
+ virtual bool initialize(TDEIO::RenameDlg_Mode /*mod*/ , const TQString &/*_src*/, const TQString &/*_dest*/,
+ const TQString &/*mimeSrc*/,
+ const TQString &/*mimeDest*/,
+ TDEIO::filesize_t /*sizeSrc*/,
+ TDEIO::filesize_t /*sizeDest*/,
+ time_t /*ctimeSrc*/,
+ time_t /*ctimeDest*/,
+ time_t /*mtimeSrc*/,
+ time_t /*mtimeDest*/ ) {return false;};
+
+};
+
+#endif
+
diff --git a/tdeio/tdeio/scheduler.cpp b/tdeio/tdeio/scheduler.cpp
new file mode 100644
index 000000000..c0aad7d38
--- /dev/null
+++ b/tdeio/tdeio/scheduler.cpp
@@ -0,0 +1,922 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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 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 "tdeio/sessiondata.h"
+#include "tdeio/slaveconfig.h"
+#include "tdeio/scheduler.h"
+#include "tdeio/authinfo.h"
+#include "tdeio/slave.h"
+#include <tqptrlist.h>
+#include <tqdict.h>
+
+#include <dcopclient.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kprotocolmanager.h>
+#include <kprotocolinfo.h>
+#include <assert.h>
+#include <kstaticdeleter.h>
+#include <tdesu/client.h>
+
+
+// Slaves may be idle for MAX_SLAVE_IDLE time before they are being returned
+// to the system wide slave pool. (3 minutes)
+#define MAX_SLAVE_IDLE (3*60)
+
+using namespace TDEIO;
+
+template class TQDict<TDEIO::Scheduler::ProtocolInfo>;
+
+Scheduler *Scheduler::instance = 0;
+
+class TDEIO::SlaveList: public TQPtrList<Slave>
+{
+ public:
+ SlaveList() { }
+};
+
+//
+// There are two kinds of protocol:
+// (1) The protocol of the url
+// (2) The actual protocol that the io-slave uses.
+//
+// These two often match, but not necasserily. Most notably, they don't
+// match when doing ftp via a proxy.
+// In that case (1) is ftp, but (2) is http.
+//
+// JobData::protocol stores (2) while Job::url().protocol() returns (1).
+// The ProtocolInfoDict is indexed with (2).
+//
+// We schedule slaves based on (2) but tell the slave about (1) via
+// Slave::setProtocol().
+
+class TDEIO::Scheduler::JobData
+{
+public:
+ JobData() : checkOnHold(false) { }
+
+public:
+ TQString protocol;
+ TQString proxy;
+ bool checkOnHold;
+};
+
+class TDEIO::Scheduler::ExtraJobData: public TQPtrDict<TDEIO::Scheduler::JobData>
+{
+public:
+ ExtraJobData() { setAutoDelete(true); }
+};
+
+class TDEIO::Scheduler::ProtocolInfo
+{
+public:
+ ProtocolInfo() : maxSlaves(1), skipCount(0)
+ {
+ joblist.setAutoDelete(false);
+ }
+
+ TQPtrList<SimpleJob> joblist;
+ SlaveList activeSlaves;
+ int maxSlaves;
+ int skipCount;
+ TQString protocol;
+};
+
+class TDEIO::Scheduler::ProtocolInfoDict : public TQDict<TDEIO::Scheduler::ProtocolInfo>
+{
+ public:
+ ProtocolInfoDict() { }
+
+ TDEIO::Scheduler::ProtocolInfo *get( const TQString &protocol);
+};
+
+TDEIO::Scheduler::ProtocolInfo *
+TDEIO::Scheduler::ProtocolInfoDict::get(const TQString &protocol)
+{
+ ProtocolInfo *info = find(protocol);
+ if (!info)
+ {
+ info = new ProtocolInfo;
+ info->protocol = protocol;
+ info->maxSlaves = KProtocolInfo::maxSlaves( protocol );
+
+ insert(protocol, info);
+ }
+ return info;
+}
+
+
+Scheduler::Scheduler()
+ : DCOPObject( "TDEIO::Scheduler" ),
+ TQObject(kapp, "scheduler"),
+ slaveTimer(0, "Scheduler::slaveTimer"),
+ coSlaveTimer(0, "Scheduler::coSlaveTimer"),
+ cleanupTimer(0, "Scheduler::cleanupTimer")
+{
+ checkOnHold = true; // !! Always check with KLauncher for the first request.
+ slaveOnHold = 0;
+ protInfoDict = new ProtocolInfoDict;
+ slaveList = new SlaveList;
+ idleSlaves = new SlaveList;
+ coIdleSlaves = new SlaveList;
+ extraJobData = new ExtraJobData;
+ sessionData = new SessionData;
+ slaveConfig = SlaveConfig::self();
+ connect(&slaveTimer, TQT_SIGNAL(timeout()), TQT_SLOT(startStep()));
+ connect(&coSlaveTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotScheduleCoSlave()));
+ connect(&cleanupTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotCleanIdleSlaves()));
+ busy = false;
+}
+
+Scheduler::~Scheduler()
+{
+ protInfoDict->setAutoDelete(true);
+ delete protInfoDict; protInfoDict = 0;
+ delete idleSlaves; idleSlaves = 0;
+ delete coIdleSlaves; coIdleSlaves = 0;
+ slaveList->setAutoDelete(true);
+ delete slaveList; slaveList = 0;
+ delete extraJobData; extraJobData = 0;
+ delete sessionData; sessionData = 0;
+ instance = 0;
+}
+
+void
+Scheduler::debug_info()
+{
+}
+
+bool Scheduler::process(const TQCString &fun, const TQByteArray &data, TQCString &replyType, TQByteArray &replyData )
+{
+ if ( fun != "reparseSlaveConfiguration(TQString)" )
+ return DCOPObject::process( fun, data, replyType, replyData );
+
+ slaveConfig = SlaveConfig::self();
+ replyType = "void";
+ TQDataStream stream( data, IO_ReadOnly );
+ TQString proto;
+ stream >> proto;
+
+ kdDebug( 7006 ) << "reparseConfiguration( " << proto << " )" << endl;
+ KProtocolManager::reparseConfiguration();
+ slaveConfig->reset();
+ sessionData->reset();
+ NetRC::self()->reload();
+
+ Slave *slave = slaveList->first();
+ for (; slave; slave = slaveList->next() )
+ if ( slave->slaveProtocol() == proto || proto.isEmpty() )
+ {
+ slave->send( CMD_REPARSECONFIGURATION );
+ slave->resetHost();
+ }
+ return true;
+}
+
+QCStringList Scheduler::functions()
+{
+ QCStringList funcs = DCOPObject::functions();
+ funcs << "void reparseSlaveConfiguration(TQString)";
+ return funcs;
+}
+
+void Scheduler::_doJob(SimpleJob *job) {
+ JobData *jobData = new JobData;
+ jobData->protocol = KProtocolManager::slaveProtocol(job->url(), jobData->proxy);
+// kdDebug(7006) << "Scheduler::_doJob protocol=" << jobData->protocol << endl;
+ if (job->command() == CMD_GET)
+ {
+ jobData->checkOnHold = checkOnHold;
+ checkOnHold = false;
+ }
+ extraJobData->replace(job, jobData);
+ newJobs.append(job);
+ slaveTimer.start(0, true);
+#ifndef NDEBUG
+ if (newJobs.count() > 150)
+ kdDebug() << "WARNING - TDEIO::Scheduler got more than 150 jobs! This shows a misuse in your app (yes, a job is a TQObject)." << endl;
+#endif
+}
+
+void Scheduler::_scheduleJob(SimpleJob *job) {
+ newJobs.removeRef(job);
+ JobData *jobData = extraJobData->find(job);
+ if (!jobData)
+{
+ kdFatal(7006) << "BUG! _ScheduleJob(): No extraJobData for job!" << endl;
+ return;
+}
+ TQString protocol = jobData->protocol;
+// kdDebug(7006) << "Scheduler::_scheduleJob protocol=" << protocol << endl;
+ ProtocolInfo *protInfo = protInfoDict->get(protocol);
+ protInfo->joblist.append(job);
+
+ slaveTimer.start(0, true);
+}
+
+void Scheduler::_cancelJob(SimpleJob *job) {
+// kdDebug(7006) << "Scheduler: canceling job " << job << endl;
+ Slave *slave = job->slave();
+ if ( !slave )
+ {
+ // was not yet running (don't call this on a finished job!)
+ JobData *jobData = extraJobData->find(job);
+ if (!jobData)
+ return; // I said: "Don't call this on a finished job!"
+
+ newJobs.removeRef(job);
+ ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
+ protInfo->joblist.removeRef(job);
+
+ // Search all slaves to see if job is in the queue of a coSlave
+ slave = slaveList->first();
+ for(; slave; slave = slaveList->next())
+ {
+ JobList *list = coSlaves.find(slave);
+ if (list && list->removeRef(job))
+ break; // Job was found and removed.
+ // Fall through to kill the slave as well!
+ }
+ if (!slave)
+ {
+ extraJobData->remove(job);
+ return; // Job was not yet running and not in a coSlave queue.
+ }
+ }
+ kdDebug(7006) << "Scheduler: killing slave " << slave->slave_pid() << endl;
+ slave->kill();
+ _jobFinished( job, slave );
+ slotSlaveDied( slave);
+}
+
+void Scheduler::startStep()
+{
+ while(newJobs.count())
+ {
+ (void) startJobDirect();
+ }
+ TQDictIterator<TDEIO::Scheduler::ProtocolInfo> it(*protInfoDict);
+ while(it.current())
+ {
+ if (startJobScheduled(it.current())) return;
+ ++it;
+ }
+}
+
+void Scheduler::setupSlave(TDEIO::Slave *slave, const KURL &url, const TQString &protocol, const TQString &proxy , bool newSlave, const TDEIO::MetaData *config)
+{
+ TQString host = url.host();
+ int port = url.port();
+ TQString user = url.user();
+ TQString passwd = url.pass();
+
+ if ((newSlave) ||
+ (slave->host() != host) ||
+ (slave->port() != port) ||
+ (slave->user() != user) ||
+ (slave->passwd() != passwd))
+ {
+ slaveConfig = SlaveConfig::self();
+
+ MetaData configData = slaveConfig->configData(protocol, host);
+ sessionData->configDataFor( configData, protocol, host );
+
+ configData["UseProxy"] = proxy;
+
+ TQString autoLogin = configData["EnableAutoLogin"].lower();
+ if ( autoLogin == "true" )
+ {
+ NetRC::AutoLogin l;
+ l.login = user;
+ bool usern = (protocol == "ftp");
+ if ( NetRC::self()->lookup( url, l, usern) )
+ {
+ configData["autoLoginUser"] = l.login;
+ configData["autoLoginPass"] = l.password;
+ if ( usern )
+ {
+ TQString macdef;
+ TQMap<TQString, TQStringList>::ConstIterator it = l.macdef.begin();
+ for ( ; it != l.macdef.end(); ++it )
+ macdef += it.key() + '\\' + it.data().join( "\\" ) + '\n';
+ configData["autoLoginMacro"] = macdef;
+ }
+ }
+ }
+ if (config)
+ configData += *config;
+ slave->setConfig(configData);
+ slave->setProtocol(url.protocol());
+ slave->setHost(host, port, user, passwd);
+ }
+}
+
+bool Scheduler::startJobScheduled(ProtocolInfo *protInfo)
+{
+ if (protInfo->joblist.isEmpty())
+ return false;
+
+// kdDebug(7006) << "Scheduling job" << endl;
+ debug_info();
+ bool newSlave = false;
+
+ SimpleJob *job = 0;
+ Slave *slave = 0;
+
+ if (protInfo->skipCount > 2)
+ {
+ bool dummy;
+ // Prevent starvation. We skip the first entry in the queue at most
+ // 2 times in a row. The
+ protInfo->skipCount = 0;
+ job = protInfo->joblist.at(0);
+ slave = findIdleSlave(protInfo, job, dummy );
+ }
+ else
+ {
+ bool exact=false;
+ SimpleJob *firstJob = 0;
+ Slave *firstSlave = 0;
+ for(uint i = 0; (i < protInfo->joblist.count()) && (i < 10); i++)
+ {
+ job = protInfo->joblist.at(i);
+ slave = findIdleSlave(protInfo, job, exact);
+ if (!firstSlave)
+ {
+ firstJob = job;
+ firstSlave = slave;
+ }
+ if (!slave) break;
+ if (exact) break;
+ }
+
+ if (!exact)
+ {
+ slave = firstSlave;
+ job = firstJob;
+ }
+ if (job == firstJob)
+ protInfo->skipCount = 0;
+ else
+ protInfo->skipCount++;
+ }
+
+ if (!slave)
+ {
+ if ( protInfo->maxSlaves > static_cast<int>(protInfo->activeSlaves.count()) )
+ {
+ newSlave = true;
+ slave = createSlave(protInfo, job, job->url());
+ if (!slave)
+ slaveTimer.start(0, true);
+ }
+ }
+
+ if (!slave)
+ {
+// kdDebug(7006) << "No slaves available" << endl;
+// kdDebug(7006) << " -- active: " << protInfo->activeSlaves.count() << endl;
+ return false;
+ }
+
+ protInfo->activeSlaves.append(slave);
+ idleSlaves->removeRef(slave);
+ protInfo->joblist.removeRef(job);
+// kdDebug(7006) << "scheduler: job started " << job << endl;
+
+
+ JobData *jobData = extraJobData->find(job);
+ setupSlave(slave, job->url(), jobData->protocol, jobData->proxy, newSlave);
+ job->start(slave);
+
+ slaveTimer.start(0, true);
+ return true;
+}
+
+bool Scheduler::startJobDirect()
+{
+ debug_info();
+ SimpleJob *job = newJobs.take(0);
+ JobData *jobData = extraJobData->find(job);
+ if (!jobData)
+ {
+ kdFatal(7006) << "BUG! startjobDirect(): No extraJobData for job!"
+ << endl;
+ return false;
+ }
+ TQString protocol = jobData->protocol;
+ ProtocolInfo *protInfo = protInfoDict->get(protocol);
+
+ bool newSlave = false;
+ bool dummy;
+
+ // Look for matching slave
+ Slave *slave = findIdleSlave(protInfo, job, dummy);
+
+ if (!slave)
+ {
+ newSlave = true;
+ slave = createSlave(protInfo, job, job->url());
+ }
+
+ if (!slave)
+ return false;
+
+ idleSlaves->removeRef(slave);
+// kdDebug(7006) << "scheduler: job started " << job << endl;
+
+ setupSlave(slave, job->url(), protocol, jobData->proxy, newSlave);
+ job->start(slave);
+ return true;
+}
+
+static Slave *searchIdleList(SlaveList *idleSlaves, const KURL &url, const TQString &protocol, bool &exact)
+{
+ TQString host = url.host();
+ int port = url.port();
+ TQString user = url.user();
+ exact = true;
+
+ for( Slave *slave = idleSlaves->first();
+ slave;
+ slave = idleSlaves->next())
+ {
+ if ((protocol == slave->slaveProtocol()) &&
+ (host == slave->host()) &&
+ (port == slave->port()) &&
+ (user == slave->user()))
+ return slave;
+ }
+
+ exact = false;
+
+ // Look for slightly matching slave
+ for( Slave *slave = idleSlaves->first();
+ slave;
+ slave = idleSlaves->next())
+ {
+ if (protocol == slave->slaveProtocol())
+ return slave;
+ }
+ return 0;
+}
+
+Slave *Scheduler::findIdleSlave(ProtocolInfo *, SimpleJob *job, bool &exact)
+{
+ Slave *slave = 0;
+ JobData *jobData = extraJobData->find(job);
+ if (!jobData)
+ {
+ kdFatal(7006) << "BUG! findIdleSlave(): No extraJobData for job!" << endl;
+ return 0;
+ }
+ if (jobData->checkOnHold)
+ {
+ slave = Slave::holdSlave(jobData->protocol, job->url());
+ if (slave)
+ return slave;
+ }
+ if (slaveOnHold)
+ {
+ // Make sure that the job wants to do a GET or a POST, and with no offset
+ bool bCanReuse = (job->command() == CMD_GET);
+ TDEIO::TransferJob * tJob = dynamic_cast<TDEIO::TransferJob *>(job);
+ if ( tJob )
+ {
+ bCanReuse = (job->command() == CMD_GET || job->command() == CMD_SPECIAL);
+ if ( bCanReuse )
+ {
+ TDEIO::MetaData outgoing = tJob->outgoingMetaData();
+ TQString resume = (!outgoing.contains("resume")) ? TQString() : outgoing["resume"];
+ kdDebug(7006) << "Resume metadata is '" << resume << "'" << endl;
+ bCanReuse = (resume.isEmpty() || resume == "0");
+ }
+ }
+// kdDebug(7006) << "bCanReuse = " << bCanReuse << endl;
+ if (bCanReuse)
+ {
+ if (job->url() == urlOnHold)
+ {
+ kdDebug(7006) << "HOLD: Reusing held slave for " << urlOnHold.prettyURL() << endl;
+ slave = slaveOnHold;
+ }
+ else
+ {
+ kdDebug(7006) << "HOLD: Discarding held slave (" << urlOnHold.prettyURL() << ")" << endl;
+ slaveOnHold->kill();
+ }
+ slaveOnHold = 0;
+ urlOnHold = KURL();
+ }
+ if (slave)
+ return slave;
+ }
+
+ return searchIdleList(idleSlaves, job->url(), jobData->protocol, exact);
+}
+
+Slave *Scheduler::createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KURL &url)
+{
+ int error;
+ TQString errortext;
+ Slave *slave = Slave::createSlave(protInfo->protocol, url, error, errortext);
+ if (slave)
+ {
+ slaveList->append(slave);
+ idleSlaves->append(slave);
+ connect(slave, TQT_SIGNAL(slaveDied(TDEIO::Slave *)),
+ TQT_SLOT(slotSlaveDied(TDEIO::Slave *)));
+ connect(slave, TQT_SIGNAL(slaveStatus(pid_t,const TQCString &,const TQString &, bool)),
+ TQT_SLOT(slotSlaveStatus(pid_t,const TQCString &, const TQString &, bool)));
+
+ connect(slave,TQT_SIGNAL(authorizationKey(const TQCString&, const TQCString&, bool)),
+ sessionData,TQT_SLOT(slotAuthData(const TQCString&, const TQCString&, bool)));
+ connect(slave,TQT_SIGNAL(delAuthorization(const TQCString&)), sessionData,
+ TQT_SLOT(slotDelAuthData(const TQCString&)));
+ }
+ else
+ {
+ kdError() <<": couldn't create slave : " << errortext << endl;
+ if (job)
+ {
+ protInfo->joblist.removeRef(job);
+ extraJobData->remove(job);
+ job->slotError( error, errortext );
+ }
+ }
+ return slave;
+}
+
+void Scheduler::slotSlaveStatus(pid_t, const TQCString &, const TQString &, bool)
+{
+}
+
+void Scheduler::_jobFinished(SimpleJob *job, Slave *slave)
+{
+ JobData *jobData = extraJobData->take(job);
+ if (!jobData)
+ {
+ kdFatal(7006) << "BUG! _jobFinished(): No extraJobData for job!" << endl;
+ return;
+ }
+ ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
+ delete jobData;
+ slave->disconnect(job);
+ protInfo->activeSlaves.removeRef(slave);
+ if (slave->isAlive())
+ {
+ JobList *list = coSlaves.find(slave);
+ if (list)
+ {
+ assert(slave->isConnected());
+ assert(!coIdleSlaves->contains(slave));
+ coIdleSlaves->append(slave);
+ if (!list->isEmpty())
+ coSlaveTimer.start(0, true);
+ return;
+ }
+ else
+ {
+ assert(!slave->isConnected());
+ idleSlaves->append(slave);
+ slave->setIdle();
+ _scheduleCleanup();
+// slave->send( CMD_SLAVE_STATUS );
+ }
+ }
+ if (protInfo->joblist.count())
+ {
+ slaveTimer.start(0, true);
+ }
+}
+
+void Scheduler::slotSlaveDied(TDEIO::Slave *slave)
+{
+ assert(!slave->isAlive());
+ ProtocolInfo *protInfo = protInfoDict->get(slave->slaveProtocol());
+ protInfo->activeSlaves.removeRef(slave);
+ if (slave == slaveOnHold)
+ {
+ slaveOnHold = 0;
+ urlOnHold = KURL();
+ }
+ idleSlaves->removeRef(slave);
+ JobList *list = coSlaves.find(slave);
+ if (list)
+ {
+ // coSlave dies, kill jobs waiting in queue
+ disconnectSlave(slave);
+ }
+
+ if (!slaveList->removeRef(slave))
+ kdDebug(7006) << "Scheduler: BUG!! Slave " << slave << "/" << slave->slave_pid() << " died, but is NOT in slaveList!!!\n" << endl;
+ else
+ slave->deref(); // Delete slave
+}
+
+void Scheduler::slotCleanIdleSlaves()
+{
+ for(Slave *slave = idleSlaves->first();slave;)
+ {
+ if (slave->idleTime() >= MAX_SLAVE_IDLE)
+ {
+ // kdDebug(7006) << "Removing idle slave: " << slave->slaveProtocol() << " " << slave->host() << endl;
+ Slave *removeSlave = slave;
+ slave = idleSlaves->next();
+ idleSlaves->removeRef(removeSlave);
+ slaveList->removeRef(removeSlave);
+ removeSlave->connection()->close();
+ removeSlave->deref();
+ }
+ else
+ {
+ slave = idleSlaves->next();
+ }
+ }
+ _scheduleCleanup();
+}
+
+void Scheduler::_scheduleCleanup()
+{
+ if (idleSlaves->count())
+ {
+ if (!cleanupTimer.isActive())
+ cleanupTimer.start( MAX_SLAVE_IDLE*1000, true );
+ }
+}
+
+void Scheduler::_putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url)
+{
+ Slave *slave = job->slave();
+ slave->disconnect(job);
+
+ if (slaveOnHold)
+ {
+ slaveOnHold->kill();
+ }
+ slaveOnHold = slave;
+ urlOnHold = url;
+ slaveOnHold->suspend();
+}
+
+void Scheduler::_publishSlaveOnHold()
+{
+ if (!slaveOnHold)
+ return;
+
+ slaveOnHold->hold(urlOnHold);
+}
+
+void Scheduler::_removeSlaveOnHold()
+{
+ if (slaveOnHold)
+ {
+ slaveOnHold->kill();
+ }
+ slaveOnHold = 0;
+ urlOnHold = KURL();
+}
+
+Slave *
+Scheduler::_getConnectedSlave(const KURL &url, const TDEIO::MetaData &config )
+{
+ TQString proxy;
+ TQString protocol = KProtocolManager::slaveProtocol(url, proxy);
+ bool dummy;
+ Slave *slave = searchIdleList(idleSlaves, url, protocol, dummy);
+ if (!slave)
+ {
+ ProtocolInfo *protInfo = protInfoDict->get(protocol);
+ slave = createSlave(protInfo, 0, url);
+ }
+ if (!slave)
+ return 0; // Error
+ idleSlaves->removeRef(slave);
+
+ setupSlave(slave, url, protocol, proxy, true, &config);
+
+ slave->send( CMD_CONNECT );
+ connect(slave, TQT_SIGNAL(connected()),
+ TQT_SLOT(slotSlaveConnected()));
+ connect(slave, TQT_SIGNAL(error(int, const TQString &)),
+ TQT_SLOT(slotSlaveError(int, const TQString &)));
+
+ coSlaves.insert(slave, new TQPtrList<SimpleJob>());
+// kdDebug(7006) << "_getConnectedSlave( " << slave << ")" << endl;
+ return slave;
+}
+
+void
+Scheduler::slotScheduleCoSlave()
+{
+ Slave *nextSlave;
+ slaveConfig = SlaveConfig::self();
+ for(Slave *slave = coIdleSlaves->first();
+ slave;
+ slave = nextSlave)
+ {
+ nextSlave = coIdleSlaves->next();
+ JobList *list = coSlaves.find(slave);
+ assert(list);
+ if (list && !list->isEmpty())
+ {
+ SimpleJob *job = list->take(0);
+ coIdleSlaves->removeRef(slave);
+// kdDebug(7006) << "scheduler: job started " << job << endl;
+
+ assert(!coIdleSlaves->contains(slave));
+
+ KURL url =job->url();
+ TQString host = url.host();
+ int port = url.port();
+
+ if (slave->host() == "<reset>")
+ {
+ TQString user = url.user();
+ TQString passwd = url.pass();
+
+ MetaData configData = slaveConfig->configData(url.protocol(), url.host());
+ slave->setConfig(configData);
+ slave->setProtocol(url.protocol());
+ slave->setHost(host, port, user, passwd);
+ }
+
+ assert(slave->protocol() == url.protocol());
+ assert(slave->host() == host);
+ assert(slave->port() == port);
+ job->start(slave);
+ }
+ }
+}
+
+void
+Scheduler::slotSlaveConnected()
+{
+ Slave *slave = (Slave *)sender();
+// kdDebug(7006) << "slotSlaveConnected( " << slave << ")" << endl;
+ slave->setConnected(true);
+ disconnect(slave, TQT_SIGNAL(connected()),
+ this, TQT_SLOT(slotSlaveConnected()));
+ emit slaveConnected(slave);
+ assert(!coIdleSlaves->contains(slave));
+ coIdleSlaves->append(slave);
+ coSlaveTimer.start(0, true);
+}
+
+void
+Scheduler::slotSlaveError(int errorNr, const TQString &errorMsg)
+{
+ Slave *slave = (Slave *)sender();
+ if (!slave->isConnected() || (coIdleSlaves->find(slave) != -1))
+ {
+ // Only forward to application if slave is idle or still connecting.
+ emit slaveError(slave, errorNr, errorMsg);
+ }
+}
+
+bool
+Scheduler::_assignJobToSlave(TDEIO::Slave *slave, SimpleJob *job)
+{
+// kdDebug(7006) << "_assignJobToSlave( " << job << ", " << slave << ")" << endl;
+ TQString dummy;
+ if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
+ ||
+ (!newJobs.removeRef(job)))
+ {
+ kdDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job." << endl;
+ job->kill();
+ return false;
+ }
+
+ JobList *list = coSlaves.find(slave);
+ assert(list);
+ if (!list)
+ {
+ kdDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave." << endl;
+ job->kill();
+ return false;
+ }
+
+ assert(list->contains(job) == 0);
+ list->append(job);
+ coSlaveTimer.start(0, true); // Start job on timer event
+
+ return true;
+}
+
+bool
+Scheduler::_disconnectSlave(TDEIO::Slave *slave)
+{
+// kdDebug(7006) << "_disconnectSlave( " << slave << ")" << endl;
+ JobList *list = coSlaves.take(slave);
+ assert(list);
+ if (!list)
+ return false;
+ // Kill jobs still in queue.
+ while(!list->isEmpty())
+ {
+ Job *job = list->take(0);
+ job->kill();
+ }
+ delete list;
+ coIdleSlaves->removeRef(slave);
+ assert(!coIdleSlaves->contains(slave));
+ disconnect(slave, TQT_SIGNAL(connected()),
+ this, TQT_SLOT(slotSlaveConnected()));
+ disconnect(slave, TQT_SIGNAL(error(int, const TQString &)),
+ this, TQT_SLOT(slotSlaveError(int, const TQString &)));
+ if (slave->isAlive())
+ {
+ idleSlaves->append(slave);
+ slave->send( CMD_DISCONNECT );
+ slave->setIdle();
+ slave->setConnected(false);
+ _scheduleCleanup();
+ }
+ return true;
+}
+
+void
+Scheduler::_checkSlaveOnHold(bool b)
+{
+ checkOnHold = b;
+}
+
+void
+Scheduler::_registerWindow(TQWidget *wid)
+{
+ if (!wid)
+ return;
+
+ TQObject *obj = TQT_TQOBJECT(wid);
+ if (!m_windowList.contains(obj))
+ {
+ // We must store the window Id because by the time
+ // the destroyed signal is emitted we can no longer
+ // access TQWidget::winId() (already destructed)
+ WId windowId = wid->winId();
+ m_windowList.insert(obj, windowId);
+ connect(TQT_TQOBJECT(wid), TQT_SIGNAL(destroyed(TQObject *)),
+ this, TQT_SLOT(slotUnregisterWindow(TQObject*)));
+ TQByteArray params;
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << windowId;
+ if( !kapp->dcopClient()->send( "kded", "kded",
+ "registerWindowId(long int)", params ) )
+ kdDebug(7006) << "Could not register window with kded!" << endl;
+ }
+}
+
+void
+Scheduler::slotUnregisterWindow(TQObject *obj)
+{
+ if (!obj)
+ return;
+
+ TQMap<TQObject *, WId>::Iterator it = m_windowList.find(obj);
+ if (it == m_windowList.end())
+ return;
+ WId windowId = it.data();
+ disconnect( it.key(), TQT_SIGNAL(destroyed(TQObject *)),
+ this, TQT_SLOT(slotUnregisterWindow(TQObject*)));
+ m_windowList.remove( it );
+ if (kapp)
+ {
+ TQByteArray params;
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << windowId;
+ kapp->dcopClient()->send( "kded", "kded",
+ "unregisterWindowId(long int)", params );
+ }
+}
+
+Scheduler* Scheduler::self() {
+ if ( !instance ) {
+ instance = new Scheduler;
+ }
+ return instance;
+}
+
+void Scheduler::virtual_hook( int id, void* data )
+{ DCOPObject::virtual_hook( id, data ); }
+
+
+
+#include "scheduler.moc"
diff --git a/tdeio/tdeio/scheduler.h b/tdeio/tdeio/scheduler.h
new file mode 100644
index 000000000..e55b2293c
--- /dev/null
+++ b/tdeio/tdeio/scheduler.h
@@ -0,0 +1,364 @@
+// -*- c++ -*-
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ 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 _kio_scheduler_h
+#define _kio_scheduler_h
+
+#include "tdeio/job.h"
+#include "tdeio/jobclasses.h"
+#include <tqtimer.h>
+#include <tqptrdict.h>
+#include <tqmap.h>
+
+#include <dcopobject.h>
+
+namespace TDEIO {
+
+ class Slave;
+ class SlaveList;
+ class SlaveConfig;
+ class SessionData;
+
+ /**
+ * The TDEIO::Scheduler manages io-slaves for the application.
+ * It also queues jobs and assigns the job to a slave when one
+ * becomes available.
+ *
+ * There are 3 possible ways for a job to get a slave:
+ *
+ * <h3>1. Direct</h3>
+ * This is the default. When you create a job the
+ * TDEIO::Scheduler will be notified and will find either an existing
+ * slave that is idle or it will create a new slave for the job.
+ *
+ * Example:
+ * \code
+ * TransferJob *job = TDEIO::get(KURL("http://www.kde.org"));
+ * \endcode
+ *
+ *
+ * <h3>2. Scheduled</h3>
+ * If you create a lot of jobs, you might want not want to have a
+ * slave for each job. If you schedule a job, a maximum number
+ * of slaves will be created. When more jobs arrive, they will be
+ * queued. When a slave is finished with a job, it will be assigned
+ * a job from the queue.
+ *
+ * Example:
+ * \code
+ * TransferJob *job = TDEIO::get(KURL("http://www.kde.org"));
+ * TDEIO::Scheduler::scheduleJob(job);
+ * \endcode
+ *
+ * <h3>3. Connection Oriented</h3>
+ * For some operations it is important that multiple jobs use
+ * the same connection. This can only be ensured if all these jobs
+ * use the same slave.
+ *
+ * You can ask the scheduler to open a slave for connection oriented
+ * operations. You can then use the scheduler to assign jobs to this
+ * slave. The jobs will be queued and the slave will handle these jobs
+ * one after the other.
+ *
+ * Example:
+ * \code
+ * Slave *slave = TDEIO::Scheduler::getConnectedSlave(
+ * KURL("pop3://bastian:password@mail.kde.org"));
+ * TransferJob *job1 = TDEIO::get(
+ * KURL("pop3://bastian:password@mail.kde.org/msg1"));
+ * TDEIO::Scheduler::assignJobToSlave(slave, job1);
+ * TransferJob *job2 = TDEIO::get(
+ * KURL("pop3://bastian:password@mail.kde.org/msg2"));
+ * TDEIO::Scheduler::assignJobToSlave(slave, job2);
+ * TransferJob *job3 = TDEIO::get(
+ * KURL("pop3://bastian:password@mail.kde.org/msg3"));
+ * TDEIO::Scheduler::assignJobToSlave(slave, job3);
+ *
+ * // ... Wait for jobs to finish...
+ *
+ * TDEIO::Scheduler::disconnectSlave(slave);
+ * \endcode
+ *
+ * Note that you need to explicitly disconnect the slave when the
+ * connection goes down, so your error handler should contain:
+ * \code
+ * if (error == TDEIO::ERR_CONNECTION_BROKEN)
+ * TDEIO::Scheduler::disconnectSlave(slave);
+ * \endcode
+ *
+ * @see TDEIO::Slave
+ * @see TDEIO::Job
+ **/
+
+ class TDEIO_EXPORT Scheduler : public TQObject, virtual public DCOPObject {
+ Q_OBJECT
+
+ public:
+ typedef TQPtrList<SimpleJob> JobList;
+
+ // InfoDict needs Info, so we can't declare it private
+ class ProtocolInfo;
+ class JobData;
+
+ ~Scheduler();
+
+ /**
+ * Register @p job with the scheduler.
+ * The default is to create a new slave for the job if no slave
+ * is available. This can be changed by calling scheduleJob.
+ * @param job the job to register
+ */
+ static void doJob(SimpleJob *job)
+ { self()->_doJob(job); }
+
+ /**
+ * Calling ths function makes that @p job gets scheduled for later
+ * execution, if multiple jobs are registered it might wait for
+ * other jobs to finish.
+ * @param job the job to schedule
+ */
+ static void scheduleJob(SimpleJob *job)
+ { self()->_scheduleJob(job); }
+
+ /**
+ * Stop the execution of a job.
+ * @param job the job to cancel
+ */
+ static void cancelJob(SimpleJob *job)
+ { self()->_cancelJob(job); }
+
+ /**
+ * Called when a job is done.
+ * @param job the finished job
+ * @param slave the slave that executed the @p job
+ */
+ static void jobFinished(TDEIO::SimpleJob *job, TDEIO::Slave *slave)
+ { self()->_jobFinished(job, slave); }
+
+ /**
+ * Puts a slave on notice. A next job may reuse this slave if it
+ * requests the same URL.
+ *
+ * A job can be put on hold after it has emit'ed its mimetype.
+ * Based on the mimetype, the program can give control to another
+ * component in the same process which can then resume the job
+ * by simply asking for the same URL again.
+ * @param job the job that should be stopped
+ * @param url the URL that is handled by the @p url
+ */
+ static void putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url)
+ { self()->_putSlaveOnHold(job, url); }
+
+ /**
+ * Removes any slave that might have been put on hold. If a slave
+ * was put on hold it will be killed.
+ */
+ static void removeSlaveOnHold()
+ { self()->_removeSlaveOnHold(); }
+
+ /**
+ * Send the slave that was put on hold back to KLauncher. This
+ * allows another process to take over the slave and resume the job
+ * that was started.
+ */
+ static void publishSlaveOnHold()
+ { self()->_publishSlaveOnHold(); }
+
+ /**
+ * Requests a slave for use in connection-oriented mode.
+ *
+ * @param url This defines the username,password,host & port to
+ * connect with.
+ * @param config Configuration data for the slave.
+ *
+ * @return A pointer to a connected slave or 0 if an error occurred.
+ * @see assignJobToSlave()
+ * @see disconnectSlave()
+ */
+ static TDEIO::Slave *getConnectedSlave(const KURL &url, const TDEIO::MetaData &config = MetaData() )
+ { return self()->_getConnectedSlave(url, config); }
+
+ /*
+ * Uses @p slave to do @p job.
+ * This function should be called immediately after creating a Job.
+ *
+ * @param slave The slave to use. The slave must have been obtained
+ * with a call to getConnectedSlave and must not
+ * be currently assigned to any other job.
+ * @param job The job to do.
+ *
+ * @return true is successful, false otherwise.
+ *
+ * @see getConnectedSlave()
+ * @see disconnectSlave()
+ * @see slaveConnected()
+ * @see slaveError()
+ */
+ static bool assignJobToSlave(TDEIO::Slave *slave, TDEIO::SimpleJob *job)
+ { return self()->_assignJobToSlave(slave, job); }
+
+ /*
+ * Disconnects @p slave.
+ *
+ * @param slave The slave to disconnect. The slave must have been
+ * obtained with a call to getConnectedSlave
+ * and must not be assigned to any job.
+ *
+ * @return true is successful, false otherwise.
+ *
+ * @see getConnectedSlave
+ * @see assignJobToSlave
+ */
+ static bool disconnectSlave(TDEIO::Slave *slave)
+ { return self()->_disconnectSlave(slave); }
+
+ /**
+ * Send the slave that was put on hold back to KLauncher. This
+ * allows another process to take over the slave and resume the job
+ * the that was started.
+ * Register the mainwindow @p wid with the KIO subsystem
+ * Do not call this, it is called automatically from
+ * void TDEIO::Job::setWindow(TQWidget*).
+ * @param wid the window to register
+ * @since 3.1
+ */
+ static void registerWindow(TQWidget *wid)
+ { self()->_registerWindow(wid); }
+
+ /**
+ * @internal
+ * Unregisters the window registered by registerWindow().
+ */
+ static void unregisterWindow(TQObject *wid)
+ { self()->slotUnregisterWindow(wid); }
+
+ /**
+ * Function to connect signals emitted by the scheduler.
+ *
+ * @see slaveConnected()
+ * @see slaveError()
+ */
+ static bool connect( const char *signal, const TQObject *receiver,
+ const char *member)
+ { return TQObject::connect(self(), signal, receiver, member); }
+
+ static bool connect( const TQObject* sender, const char* signal,
+ const TQObject* receiver, const char* member )
+ { return TQObject::connect(sender, signal, receiver, member); }
+
+ static bool disconnect( const TQObject* sender, const char* signal,
+ const TQObject* receiver, const char* member )
+ { return TQObject::disconnect(sender, signal, receiver, member); }
+
+ bool connect( const TQObject *sender, const char *signal,
+ const char *member )
+ { return TQObject::connect(sender, signal, member); }
+
+ /**
+ * When true, the next job will check whether KLauncher has a slave
+ * on hold that is suitable for the job.
+ * @param b true when KLauncher has a job on hold
+ */
+ static void checkSlaveOnHold(bool b) { self()->_checkSlaveOnHold(b); }
+
+ void debug_info();
+
+ virtual bool process(const TQCString &fun, const TQByteArray &data,
+ TQCString& replyType, TQByteArray &replyData);
+
+ virtual QCStringList functions();
+
+ public slots:
+ void slotSlaveDied(TDEIO::Slave *slave);
+ void slotSlaveStatus(pid_t pid, const TQCString &protocol,
+ const TQString &host, bool connected);
+ signals:
+ void slaveConnected(TDEIO::Slave *slave);
+ void slaveError(TDEIO::Slave *slave, int error, const TQString &errorMsg);
+
+ protected:
+ void setupSlave(TDEIO::Slave *slave, const KURL &url, const TQString &protocol, const TQString &proxy , bool newSlave, const TDEIO::MetaData *config=0);
+ bool startJobScheduled(ProtocolInfo *protInfo);
+ bool startJobDirect();
+ Scheduler();
+
+ protected slots:
+ void startStep();
+ void slotCleanIdleSlaves();
+ void slotSlaveConnected();
+ void slotSlaveError(int error, const TQString &errorMsg);
+ void slotScheduleCoSlave();
+ /// @since 3.1
+ void slotUnregisterWindow(TQObject *);
+
+ private:
+ class ProtocolInfoDict;
+ class ExtraJobData;
+
+ Scheduler(const Scheduler&);
+ static Scheduler *self();
+ static Scheduler *instance;
+ void _doJob(SimpleJob *job);
+ void _scheduleJob(SimpleJob *job);
+ void _cancelJob(SimpleJob *job);
+ void _jobFinished(TDEIO::SimpleJob *job, TDEIO::Slave *slave);
+ void _scheduleCleanup();
+ void _putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url);
+ void _removeSlaveOnHold();
+ Slave *_getConnectedSlave(const KURL &url, const TDEIO::MetaData &metaData );
+ bool _assignJobToSlave(TDEIO::Slave *slave, TDEIO::SimpleJob *job);
+ bool _disconnectSlave(TDEIO::Slave *slave);
+ void _checkSlaveOnHold(bool b);
+ void _publishSlaveOnHold();
+ void _registerWindow(TQWidget *wid);
+
+ Slave *findIdleSlave(ProtocolInfo *protInfo, SimpleJob *job, bool &exact);
+ Slave *createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KURL &url);
+
+
+ TQTimer slaveTimer;
+ TQTimer coSlaveTimer;
+ TQTimer cleanupTimer;
+ bool busy;
+
+ SlaveList *slaveList;
+ SlaveList *idleSlaves;
+ SlaveList *coIdleSlaves;
+
+ ProtocolInfoDict *protInfoDict;
+ Slave *slaveOnHold;
+ KURL urlOnHold;
+ JobList newJobs;
+
+ TQPtrDict<JobList> coSlaves;
+ ExtraJobData *extraJobData;
+ SlaveConfig *slaveConfig;
+ SessionData *sessionData;
+ bool checkOnHold;
+ TQMap<TQObject *,WId> m_windowList;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ private:
+ class SchedulerPrivate* d;
+};
+
+}
+#endif
diff --git a/tdeio/tdeio/sessiondata.cpp b/tdeio/tdeio/sessiondata.cpp
new file mode 100644
index 000000000..99c6a26f3
--- /dev/null
+++ b/tdeio/tdeio/sessiondata.cpp
@@ -0,0 +1,311 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License (LGPL) 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 Lesser 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 <tqptrlist.h>
+#include <tqtextcodec.h>
+
+#include <kdebug.h>
+#include <tdeconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <dcopclient.h>
+#include <kprotocolmanager.h>
+#include <kstandarddirs.h>
+
+#include <tdesu/client.h>
+#include <tdeio/slaveconfig.h>
+#include <tdeio/http_slave_defaults.h>
+
+#include "sessiondata.h"
+#include "sessiondata.moc"
+
+namespace TDEIO {
+
+/***************************** SessionData::AuthData ************************/
+struct SessionData::AuthData
+{
+
+public:
+ AuthData() {}
+
+ AuthData(const TQCString& k, const TQCString& g, bool p) {
+ key = k;
+ group = g;
+ persist = p;
+ }
+
+ bool isKeyMatch( const TQCString& val ) const {
+ return (val==key);
+ }
+
+ bool isGroupMatch( const TQCString& val ) const {
+ return (val==group);
+ }
+
+ TQCString key;
+ TQCString group;
+ bool persist;
+};
+
+/************************* SessionData::AuthDataList ****************************/
+class SessionData::AuthDataList : public TQPtrList<SessionData::AuthData>
+{
+public:
+ AuthDataList();
+ ~AuthDataList();
+
+ void addData( SessionData::AuthData* );
+ void removeData( const TQCString& );
+
+ bool pingCacheDaemon();
+ void registerAuthData( SessionData::AuthData* );
+ void unregisterAuthData( SessionData::AuthData* );
+ void purgeCachedData();
+
+private:
+#ifdef Q_OS_UNIX
+ KDEsuClient * m_tdesuClient;
+#endif
+};
+
+SessionData::AuthDataList::AuthDataList()
+{
+#ifdef Q_OS_UNIX
+ m_tdesuClient = new KDEsuClient;
+#endif
+ setAutoDelete(true);
+}
+
+SessionData::AuthDataList::~AuthDataList()
+{
+ purgeCachedData();
+#ifdef Q_OS_UNIX
+ delete m_tdesuClient;
+ m_tdesuClient = 0;
+#endif
+}
+
+void SessionData::AuthDataList::addData( SessionData::AuthData* d )
+{
+ TQPtrListIterator<SessionData::AuthData> it ( *this );
+ for ( ; it.current(); ++it )
+ {
+ if ( it.current()->isKeyMatch( d->key ) )
+ return;
+ }
+ registerAuthData( d );
+ append( d );
+}
+
+void SessionData::AuthDataList::removeData( const TQCString& gkey )
+{
+ TQPtrListIterator<SessionData::AuthData> it( *this );
+ for( ; it.current(); ++it )
+ {
+ if ( it.current()->isGroupMatch(gkey) && pingCacheDaemon() )
+ {
+ unregisterAuthData( it.current() );
+ remove( it.current() );
+ }
+ }
+}
+
+bool SessionData::AuthDataList::pingCacheDaemon()
+{
+#ifdef Q_OS_UNIX
+ Q_ASSERT(m_tdesuClient);
+
+ int success = m_tdesuClient->ping();
+ if( success == -1 )
+ {
+ success = m_tdesuClient->startServer();
+ if( success == -1 )
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+void SessionData::AuthDataList::registerAuthData( SessionData::AuthData* d )
+{
+ if( !pingCacheDaemon() )
+ return;
+
+#ifdef Q_OS_UNIX
+ bool ok;
+ TQCString ref_key = d->key + "-refcount";
+ int count = m_tdesuClient->getVar(ref_key).toInt( &ok );
+ if( ok )
+ {
+ TQCString val;
+ val.setNum( count+1 );
+ m_tdesuClient->setVar( ref_key, val, 0, d->group );
+ }
+ else
+ m_tdesuClient->setVar( ref_key, "1", 0, d->group );
+#endif
+}
+
+void SessionData::AuthDataList::unregisterAuthData( SessionData::AuthData* d )
+{
+ if ( !d || d->persist )
+ return;
+
+ bool ok;
+ int count;
+ TQCString ref_key = d->key + "-refcount";
+
+#ifdef Q_OS_UNIX
+ count = m_tdesuClient->getVar( ref_key ).toInt( &ok );
+ if ( ok )
+ {
+ if ( count > 1 )
+ {
+ TQCString val;
+ val.setNum(count-1);
+ m_tdesuClient->setVar( ref_key, val, 0, d->group );
+ }
+ else
+ {
+ m_tdesuClient->delVars(d->key);
+ }
+ }
+#endif
+}
+
+void SessionData::AuthDataList::purgeCachedData()
+{
+ if ( !isEmpty() && pingCacheDaemon() )
+ {
+ TQPtrListIterator<SessionData::AuthData> it( *this );
+ for ( ; it.current(); ++it )
+ unregisterAuthData( it.current() );
+ }
+}
+
+/********************************* SessionData ****************************/
+
+class SessionData::SessionDataPrivate
+{
+public:
+ SessionDataPrivate() {
+ useCookie = true;
+ initDone = false;
+ }
+
+ bool initDone;
+ bool useCookie;
+ TQString charsets;
+ TQString language;
+};
+
+SessionData::SessionData()
+{
+ authData = 0;
+ d = new SessionDataPrivate;
+}
+
+SessionData::~SessionData()
+{
+ delete d;
+ delete authData;
+ d = 0L;
+ authData = 0L;
+}
+
+void SessionData::configDataFor( MetaData &configData, const TQString &proto,
+ const TQString & )
+{
+ if ( (proto.find("http", 0, false) == 0 ) ||
+ (proto.find("webdav", 0, false) == 0) )
+ {
+ if (!d->initDone)
+ reset();
+
+ // These might have already been set so check first
+ // to make sure that we do not trumpt settings sent
+ // by apps or end-user.
+ if ( configData["Cookies"].isEmpty() )
+ configData["Cookies"] = d->useCookie ? "true" : "false";
+ if ( configData["Languages"].isEmpty() )
+ configData["Languages"] = d->language;
+ if ( configData["Charsets"].isEmpty() )
+ configData["Charsets"] = d->charsets;
+ if ( configData["CacheDir"].isEmpty() )
+ configData["CacheDir"] = TDEGlobal::dirs()->saveLocation("cache", "http");
+ if ( configData["UserAgent"].isEmpty() )
+ {
+ configData["UserAgent"] = KProtocolManager::defaultUserAgent();
+ }
+ }
+}
+
+void SessionData::reset()
+{
+ d->initDone = true;
+ // Get Cookie settings...
+ TDEConfig* cfg = new TDEConfig("kcookiejarrc", true, false);
+ cfg->setGroup( "Cookie Policy" );
+ d->useCookie = cfg->readBoolEntry( "Cookies", true );
+ delete cfg;
+
+ static const TQString & english = TDEGlobal::staticQString( "en" );
+
+ // Get language settings...
+ TQStringList languageList = TDEGlobal::locale()->languagesTwoAlpha();
+ TQStringList::Iterator it = languageList.find( TQString::fromLatin1("C") );
+ if ( it != languageList.end() )
+ {
+ if ( languageList.contains( english ) > 0 )
+ languageList.remove( it );
+ else
+ (*it) = english;
+ }
+ if ( !languageList.contains( english ) )
+ languageList.append( english );
+
+ d->language = languageList.join( ", " );
+
+ d->charsets = TQString::fromLatin1(TQTextCodec::codecForLocale()->mimeName()).lower();
+ KProtocolManager::reparseConfiguration();
+}
+
+void SessionData::slotAuthData( const TQCString& key, const TQCString& gkey,
+ bool keep )
+{
+ if (!authData)
+ authData = new AuthDataList;
+ authData->addData( new SessionData::AuthData(key, gkey, keep) );
+}
+
+void SessionData::slotDelAuthData( const TQCString& gkey )
+{
+ if (!authData)
+ return;
+ authData->removeData( gkey );
+}
+
+void SessionData::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+}
diff --git a/tdeio/tdeio/sessiondata.h b/tdeio/tdeio/sessiondata.h
new file mode 100644
index 000000000..a87e63dba
--- /dev/null
+++ b/tdeio/tdeio/sessiondata.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Dawit Alemayehu <adawit@kde.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License (LGPL) 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 Lesser 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 __KIO_SESSIONDATA_H
+#define __KIO_SESSIONDATA_H
+
+#include <tqobject.h>
+#include <tdeio/global.h>
+
+namespace TDEIO {
+
+class SlaveConfig;
+
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT SessionData : public TQObject
+{
+ Q_OBJECT
+
+public:
+ SessionData();
+ ~SessionData();
+
+ virtual void configDataFor( TDEIO::MetaData &configData, const TQString &proto,
+ const TQString &host );
+ virtual void reset();
+
+ /// @since 3.1
+ struct AuthData;
+public slots:
+ void slotAuthData( const TQCString&, const TQCString&, bool );
+ void slotDelAuthData( const TQCString& );
+
+private:
+ class AuthDataList;
+ friend class AuthDataList;
+ AuthDataList* authData;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class SessionDataPrivate;
+ SessionDataPrivate* d;
+};
+
+} // namespace
+
+#endif
diff --git a/tdeio/tdeio/skipdlg.cpp b/tdeio/tdeio/skipdlg.cpp
new file mode 100644
index 000000000..eab245dfc
--- /dev/null
+++ b/tdeio/tdeio/skipdlg.cpp
@@ -0,0 +1,143 @@
+/* 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.
+*/
+
+#include "tdeio/skipdlg.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <tqmessagebox.h>
+#include <tqwidget.h>
+#include <tqlayout.h>
+#include <tqlabel.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#ifdef Q_WS_X11
+#include <twin.h>
+#endif
+
+using namespace TDEIO;
+
+SkipDlg::SkipDlg(TQWidget *parent, bool _multi, const TQString& _error_text, bool _modal ) :
+ KDialog ( parent, "" , _modal )
+{
+ // TODO : port to KDialogBase
+ modal = _modal;
+
+ // Set "StaysOnTop", because this dialog is typically used in tdeio_uiserver,
+ // i.e. in a separate process.
+#ifdef Q_WS_X11 //FIXME(E): Implement for QT Embedded, mac & win32
+ if (modal)
+ KWin::setState( winId(), NET::StaysOnTop );
+#endif
+
+ b0 = b1 = b2 = 0L;
+
+ setCaption( i18n( "Information" ) );
+
+ b0 = new KPushButton( KStdGuiItem::cancel(), this );
+ connect(b0, TQT_SIGNAL(clicked()), this, TQT_SLOT(b0Pressed()));
+
+ if ( _multi )
+ {
+ b1 = new TQPushButton( i18n( "Skip" ), this );
+ connect(b1, TQT_SIGNAL(clicked()), this, TQT_SLOT(b1Pressed()));
+
+ b2 = new TQPushButton( i18n( "Auto Skip" ), this );
+ connect(b2, TQT_SIGNAL(clicked()), this, TQT_SLOT(b2Pressed()));
+ }
+
+ TQVBoxLayout *vlayout = new TQVBoxLayout( this, 10, 0 );
+ // vlayout->addStrut( 360 ); makes dlg at least that wide
+
+ TQLabel * lb = new TQLabel( _error_text, this );
+ lb->setFixedHeight( lb->sizeHint().height() );
+ lb->setMinimumWidth( lb->sizeHint().width() );
+ vlayout->addWidget( lb );
+
+ vlayout->addSpacing( 10 );
+
+ TQHBoxLayout* layout = new TQHBoxLayout();
+ vlayout->addLayout( layout );
+ if ( b0 )
+ {
+ b0->setDefault( true );
+ b0->setFixedSize( b0->sizeHint() );
+ layout->addWidget( b0 );
+ layout->addSpacing( 5 );
+ }
+ if ( b1 )
+ {
+ b1->setFixedSize( b1->sizeHint() );
+ layout->addWidget( b1 );
+ layout->addSpacing( 5 );
+ }
+ if ( b2 )
+ {
+ b2->setFixedSize( b2->sizeHint() );
+ layout->addWidget( b2 );
+ layout->addSpacing( 5 );
+ }
+
+ vlayout->addStretch( 10 );
+ vlayout->activate();
+ resize( sizeHint() );
+}
+
+SkipDlg::~SkipDlg()
+{
+}
+
+void SkipDlg::b0Pressed()
+{
+ if ( modal )
+ done( 0 );
+ else
+ emit result( this, 0 );
+}
+
+void SkipDlg::b1Pressed()
+{
+ if ( modal )
+ done( 1 );
+ else
+ emit result( this, 1 );
+}
+
+void SkipDlg::b2Pressed()
+{
+ if ( modal )
+ done( 2 );
+ else
+ emit result( this, 2 );
+}
+
+SkipDlg_Result TDEIO::open_SkipDlg( bool _multi, const TQString& _error_text )
+{
+ Q_ASSERT(kapp);
+
+ SkipDlg dlg( 0L, _multi, _error_text, true );
+ return (SkipDlg_Result) dlg.exec();
+}
+
+#include "skipdlg.moc"
diff --git a/tdeio/tdeio/skipdlg.h b/tdeio/tdeio/skipdlg.h
new file mode 100644
index 000000000..56252dace
--- /dev/null
+++ b/tdeio/tdeio/skipdlg.h
@@ -0,0 +1,61 @@
+/* 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 __kio_skip_dlg__
+#define __kio_skip_dlg__
+
+#include <tdelibs_export.h>
+#include <kdialog.h>
+
+class TQPushButton;
+class TQWidget;
+
+namespace TDEIO {
+
+ enum SkipDlg_Result { S_SKIP = 1, S_AUTO_SKIP = 2, S_CANCEL = 0 };
+
+ TDEIO_EXPORT SkipDlg_Result open_SkipDlg( bool _multi, const TQString& _error_text = TQString::null );
+
+/**
+ * @internal
+ */
+class TDEIO_EXPORT SkipDlg : public KDialog
+{
+ Q_OBJECT
+public:
+ SkipDlg( TQWidget *parent, bool _multi, const TQString& _error_text, bool _modal = false );
+ ~SkipDlg();
+
+protected:
+ TQPushButton *b0;
+ TQPushButton *b1;
+ TQPushButton *b2;
+
+ bool modal;
+
+public slots:
+ void b0Pressed();
+ void b1Pressed();
+ void b2Pressed();
+
+signals:
+ void result( SkipDlg *_this, int _button );
+};
+
+}
+#endif
diff --git a/tdeio/tdeio/slave.cpp b/tdeio/tdeio/slave.cpp
new file mode 100644
index 000000000..dfd6d6bb3
--- /dev/null
+++ b/tdeio/tdeio/slave.cpp
@@ -0,0 +1,519 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+ * 2000 Stephan Kulow <coolo@kde.org>
+ *
+ * $Id$
+ *
+ * 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 <config.h>
+
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#include <tqfile.h>
+#include <tqtimer.h>
+
+#include <dcopclient.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <ktempfile.h>
+#include <ksock.h>
+#include <kprocess.h>
+#include <klibloader.h>
+
+#include "tdeio/dataprotocol.h"
+#include "tdeio/slave.h"
+#include "tdeio/kservice.h"
+#include <tdeio/global.h>
+#include <kprotocolmanager.h>
+#include <kprotocolinfo.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp"
+#endif
+
+using namespace TDEIO;
+
+#define SLAVE_CONNECTION_TIMEOUT_MIN 2
+
+// Without debug info we consider it an error if the slave doesn't connect
+// within 10 seconds.
+// With debug info we give the slave an hour so that developers have a chance
+// to debug their slave.
+#ifdef NDEBUG
+#define SLAVE_CONNECTION_TIMEOUT_MAX 10
+#else
+#define SLAVE_CONNECTION_TIMEOUT_MAX 3600
+#endif
+
+namespace TDEIO {
+
+ /**
+ * @internal
+ */
+ class SlavePrivate {
+ public:
+ bool derived; // true if this instance of Slave is actually an
+ // instance of a derived class.
+
+ SlavePrivate(bool derived) : derived(derived) {}
+ };
+}
+
+void Slave::accept(TDESocket *socket)
+{
+#ifndef Q_WS_WIN
+ slaveconn.init(socket);
+#endif
+ delete serv;
+ serv = 0;
+ slaveconn.connect(this, TQT_SLOT(gotInput()));
+ unlinkSocket();
+}
+
+void Slave::unlinkSocket()
+{
+ if (m_socket.isEmpty()) return;
+ TQCString filename = TQFile::encodeName(m_socket);
+ unlink(filename.data());
+ m_socket = TQString::null;
+}
+
+void Slave::timeout()
+{
+ if (!serv) return;
+ kdDebug(7002) << "slave failed to connect to application pid=" << m_pid << " protocol=" << m_protocol << endl;
+ if (m_pid && (::kill(m_pid, 0) == 0))
+ {
+ int delta_t = (int) difftime(time(0), contact_started);
+ kdDebug(7002) << "slave is slow... pid=" << m_pid << " t=" << delta_t << endl;
+ if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
+ {
+ TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, TQT_SLOT(timeout()));
+ return;
+ }
+ }
+ kdDebug(7002) << "Houston, we lost our slave, pid=" << m_pid << endl;
+ delete serv;
+ serv = 0;
+ unlinkSocket();
+ dead = true;
+ TQString arg = m_protocol;
+ if (!m_host.isEmpty())
+ arg += "://"+m_host;
+ kdDebug(7002) << "slave died pid = " << m_pid << endl;
+ ref();
+ // Tell the job about the problem.
+ emit error(ERR_SLAVE_DIED, arg);
+ // Tell the scheduler about the problem.
+ emit slaveDied(this);
+ // After the above signal we're dead!!
+ deref();
+}
+
+Slave::Slave(TDEServerSocket *socket, const TQString &protocol, const TQString &socketname)
+ : SlaveInterface(&slaveconn), serv(socket), contacted(false),
+ d(new SlavePrivate(false))
+{
+ m_refCount = 1;
+ m_protocol = protocol;
+ m_slaveProtocol = protocol;
+ m_socket = socketname;
+ dead = false;
+ contact_started = time(0);
+ idle_since = contact_started;
+ m_pid = 0;
+ m_port = 0;
+#ifndef Q_WS_WIN
+ connect(serv, TQT_SIGNAL(accepted( TDESocket* )),
+ TQT_SLOT(accept(TDESocket*) ) );
+#endif
+}
+
+Slave::Slave(bool /*derived*/, TDEServerSocket *socket, const TQString &protocol,
+ const TQString &socketname)
+ : SlaveInterface(&slaveconn), serv(socket), contacted(false),
+ d(new SlavePrivate(true))
+{
+ // FIXME: hmm, duplicating code here from public ctor, no good (LS)
+ m_refCount = 1;
+ m_protocol = protocol;
+ m_slaveProtocol = protocol;
+ m_socket = socketname;
+ dead = false;
+ contact_started = time(0);
+ idle_since = contact_started;
+ m_pid = 0;
+ m_port = 0;
+ if (serv != 0) {
+#ifndef Q_WS_WIN
+ connect(serv, TQT_SIGNAL(accepted( TDESocket* )),
+ TQT_SLOT(accept(TDESocket*) ) );
+#endif
+ }
+}
+
+Slave::~Slave()
+{
+ // kdDebug(7002) << "destructing slave object pid = " << m_pid << endl;
+ if (serv != 0) {
+ delete serv;
+ serv = 0;
+ }
+ unlinkSocket();
+ m_pid = 99999;
+ delete d;
+ d = 0;
+}
+
+void Slave::setProtocol(const TQString & protocol)
+{
+ m_protocol = protocol;
+}
+
+void Slave::setIdle()
+{
+ idle_since = time(0);
+}
+
+time_t Slave::idleTime()
+{
+ return (time_t) difftime(time(0), idle_since);
+}
+
+void Slave::setPID(pid_t pid)
+{
+ m_pid = pid;
+}
+
+void Slave::hold(const KURL &url)
+{
+ if (d->derived) { // TODO: clean up before KDE 4
+ HoldParams params;
+ params.url = &url;
+ virtual_hook(VIRTUAL_HOLD, &params);
+ return;
+ }/*end if*/
+
+ ref();
+ {
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ stream << url;
+ slaveconn.send( CMD_SLAVE_HOLD, data );
+ slaveconn.close();
+ dead = true;
+ emit slaveDied(this);
+ }
+ deref();
+ // Call KLauncher::waitForSlave(pid);
+ {
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isAttached())
+ client->attach();
+
+ TQByteArray params, reply;
+ TQCString replyType;
+ TQDataStream stream(params, IO_WriteOnly);
+ pid_t pid = m_pid;
+ stream << pid;
+
+ TQCString launcher = TDEApplication::launcher();
+ client->call(launcher, launcher, "waitForSlave(pid_t)",
+ params, replyType, reply);
+ }
+}
+
+void Slave::suspend()
+{
+ if (d->derived) { // TODO: clean up before KDE 4
+ virtual_hook(VIRTUAL_SUSPEND, 0);
+ return;
+ }/*end if*/
+
+ slaveconn.suspend();
+}
+
+void Slave::resume()
+{
+ if (d->derived) { // TODO: clean up before KDE 4
+ virtual_hook(VIRTUAL_RESUME, 0);
+ return;
+ }/*end if*/
+
+ slaveconn.resume();
+}
+
+bool Slave::suspended()
+{
+ if (d->derived) { // TODO: clean up before KDE 4
+ SuspendedParams params;
+ virtual_hook(VIRTUAL_SUSPENDED, &params);
+ return params.retval;
+ }/*end if*/
+
+ return slaveconn.suspended();
+}
+
+void Slave::send(int cmd, const TQByteArray &arr) {
+ if (d->derived) { // TODO: clean up before KDE 4
+ SendParams params;
+ params.cmd = cmd;
+ params.arr = &arr;
+ virtual_hook(VIRTUAL_SEND, &params);
+ return;
+ }/*end if*/
+
+ slaveconn.send(cmd, arr);
+}
+
+void Slave::gotInput()
+{
+ ref();
+ if (!dispatch())
+ {
+ slaveconn.close();
+ dead = true;
+ TQString arg = m_protocol;
+ if (!m_host.isEmpty())
+ arg += "://"+m_host;
+ kdDebug(7002) << "slave died pid = " << m_pid << endl;
+ // Tell the job about the problem.
+ emit error(ERR_SLAVE_DIED, arg);
+ // Tell the scheduler about the problem.
+ emit slaveDied(this);
+ }
+ deref();
+ // Here we might be dead!!
+}
+
+void Slave::kill()
+{
+ dead = true; // OO can be such simple.
+ kdDebug(7002) << "killing slave pid=" << m_pid << " (" << m_protocol << "://"
+ << m_host << ")" << endl;
+ if (m_pid)
+ {
+ ::kill(m_pid, SIGTERM);
+ }
+}
+
+void Slave::setHost( const TQString &host, int port,
+ const TQString &user, const TQString &passwd)
+{
+ m_host = host;
+ m_port = port;
+ m_user = user;
+ m_passwd = passwd;
+
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ stream << m_host << m_port << m_user << m_passwd;
+ slaveconn.send( CMD_HOST, data );
+}
+
+void Slave::resetHost()
+{
+ m_host = "<reset>";
+}
+
+void Slave::setConfig(const MetaData &config)
+{
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ stream << config;
+ slaveconn.send( CMD_CONFIG, data );
+}
+
+Slave* Slave::createSlave( const TQString &protocol, const KURL& url, int& error, TQString& error_text )
+{
+ //kdDebug(7002) << "createSlave '" << protocol << "' for " << url.prettyURL() << endl;
+ // Firstly take into account all special slaves
+ if (protocol == "data")
+ return new DataProtocol();
+
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isAttached())
+ client->attach();
+
+ TQString prefix = locateLocal("socket", TDEGlobal::instance()->instanceName());
+ KTempFile socketfile(prefix, TQString::fromLatin1(".slave-socket"));
+ if ( socketfile.status() != 0 )
+ {
+ error_text = i18n("Unable to create io-slave: %1").arg(strerror(errno));
+ error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
+ return 0;
+ }
+
+#ifdef __CYGWIN__
+ socketfile.close();
+#endif
+
+#ifndef Q_WS_WIN
+ TDEServerSocket *kss = new TDEServerSocket(TQFile::encodeName(socketfile.name()).data());
+
+ Slave *slave = new Slave(kss, protocol, socketfile.name());
+#else
+ Slave *slave = 0;
+#endif
+
+ // WABA: if the dcopserver is running under another uid we don't ask
+ // tdelauncher for a slave, because the slave might have that other uid
+ // as well, which might either be a) undesired or b) make it impossible
+ // for the slave to connect to the application.
+ // In such case we start the slave via TDEProcess.
+ // It's possible to force this by setting the env. variable
+ // TDE_FORK_SLAVES, Clearcase seems to require this.
+ static bool bForkSlaves = !TQCString(getenv("TDE_FORK_SLAVES")).isEmpty();
+
+ if (bForkSlaves || !client->isAttached() || client->isAttachedToForeignServer())
+ {
+ TQString _name = KProtocolInfo::exec(protocol);
+ if (_name.isEmpty())
+ {
+ error_text = i18n("Unknown protocol '%1'.").arg(protocol);
+ error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
+ delete slave;
+ return 0;
+ }
+ TQString lib_path = KLibLoader::findLibrary(_name.latin1());
+ if (lib_path.isEmpty())
+ {
+ error_text = i18n("Can not find io-slave for protocol '%1'.").arg(protocol);
+ error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
+ return 0;
+ }
+
+ TDEProcess proc;
+
+ proc << locate("exe", "tdeioslave") << lib_path << protocol << "" << socketfile.name();
+ kdDebug(7002) << "tdeioslave" << ", " << lib_path << ", " << protocol << ", " << TQString::null << ", " << socketfile.name() << endl;
+
+ proc.start(TDEProcess::DontCare);
+
+#ifndef Q_WS_WIN
+ slave->setPID(proc.pid());
+ TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
+#endif
+ return slave;
+ }
+
+
+ TQByteArray params, reply;
+ TQCString replyType;
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << protocol << url.host() << socketfile.name();
+
+ TQCString launcher = TDEApplication::launcher();
+ if (!client->call(launcher, launcher, "requestSlave(TQString,TQString,TQString)",
+ params, replyType, reply)) {
+ error_text = i18n("Cannot talk to tdelauncher");
+ error = TDEIO::ERR_SLAVE_DEFINED;
+ delete slave;
+ return 0;
+ }
+ TQDataStream stream2(reply, IO_ReadOnly);
+ TQString errorStr;
+ pid_t pid;
+ stream2 >> pid >> errorStr;
+ if (!pid)
+ {
+ error_text = i18n("Unable to create io-slave:\ntdelauncher said: %1").arg(errorStr);
+ error = TDEIO::ERR_CANNOT_LAUNCH_PROCESS;
+ delete slave;
+ return 0;
+ }
+#ifndef Q_WS_WIN
+ slave->setPID(pid);
+ TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
+#endif
+ return slave;
+}
+
+Slave* Slave::holdSlave( const TQString &protocol, const KURL& url )
+{
+ //kdDebug(7002) << "holdSlave '" << protocol << "' for " << url.prettyURL() << endl;
+ // Firstly take into account all special slaves
+ if (protocol == "data")
+ return 0;
+
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isAttached())
+ client->attach();
+
+ TQString prefix = locateLocal("socket", TDEGlobal::instance()->instanceName());
+ KTempFile socketfile(prefix, TQString::fromLatin1(".slave-socket"));
+ if ( socketfile.status() != 0 )
+ return 0;
+
+#ifdef __CYGWIN__
+ socketfile.close();
+ socketfile.unlink();
+#endif
+
+#ifndef Q_WS_WIN
+ TDEServerSocket *kss = new TDEServerSocket(TQFile::encodeName(socketfile.name()).data());
+
+ Slave *slave = new Slave(kss, protocol, socketfile.name());
+#else
+ Slave *slave = 0;
+#endif
+
+ TQByteArray params, reply;
+ TQCString replyType;
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << url << socketfile.name();
+
+ TQCString launcher = TDEApplication::launcher();
+ if (!client->call(launcher, launcher, "requestHoldSlave(KURL,TQString)",
+ params, replyType, reply)) {
+ delete slave;
+ return 0;
+ }
+ TQDataStream stream2(reply, IO_ReadOnly);
+ pid_t pid;
+ stream2 >> pid;
+ if (!pid)
+ {
+ delete slave;
+ return 0;
+ }
+#ifndef Q_WS_WIN
+ slave->setPID(pid);
+ TQTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, TQT_SLOT(timeout()));
+#endif
+ return slave;
+}
+
+void Slave::virtual_hook( int id, void* data ) {
+ TDEIO::SlaveInterface::virtual_hook( id, data );
+}
+
+#include "slave.moc"
diff --git a/tdeio/tdeio/slave.h b/tdeio/tdeio/slave.h
new file mode 100644
index 000000000..80ae30d3a
--- /dev/null
+++ b/tdeio/tdeio/slave.h
@@ -0,0 +1,270 @@
+// -*- c++ -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+ * 2000 Stephan Kulow <coolo@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 KIO_SLAVE_H
+#define KIO_SLAVE_H
+
+#include <time.h>
+#include <unistd.h>
+
+#include <tqobject.h>
+
+#include <kurl.h>
+
+#include "tdeio/slaveinterface.h"
+#include "tdeio/connection.h"
+
+class TDEServerSocket;
+class TDESocket;
+
+namespace TDEIO {
+
+ /** Attention developers: If you change the implementation of TDEIO::Slave,
+ * do *not* use connection() or slaveconn but the respective TDEIO::Slave
+ * accessor methods. Otherwise classes derived from Slave might break. (LS)
+ */
+ class TDEIO_EXPORT Slave : public TDEIO::SlaveInterface
+ {
+ Q_OBJECT
+
+
+ protected:
+ /**
+ * Use this constructor if you derive your own class from Slave
+ * @p derived must be true in any case
+ * @internal
+ * @since 3.2
+ */
+ Slave(bool derived, TDEServerSocket *unixdomain, const TQString &protocol,
+ const TQString &socketname); // TODO(BIC): Remove in KDE 4
+
+ public:
+ Slave(TDEServerSocket *unixdomain,
+ const TQString &protocol, const TQString &socketname);
+
+ virtual ~Slave();
+
+ void setPID(pid_t);
+
+ int slave_pid() { return m_pid; }
+
+ /**
+ * Force termination
+ */
+ void kill();
+
+ /**
+ * @return true if the slave survived the last mission.
+ */
+ bool isAlive() { return !dead; }
+
+ /**
+ * Set host for url
+ * @param host to connect to.
+ * @param port to connect to.
+ * @param user to login as
+ * @param passwd to login with
+ */
+ void setHost( const TQString &host, int port,
+ const TQString &user, const TQString &passwd); // TODO(BIC): make virtual
+
+ /**
+ * Clear host info.
+ */
+ void resetHost();
+
+ /**
+ * Configure slave
+ */
+ void setConfig(const MetaData &config); // TODO(BIC): make virtual
+
+ /**
+ * The protocol this slave handles.
+ *
+ * @return name of protocol handled by this slave, as seen by the user
+ */
+ TQString protocol() { return m_protocol; }
+
+ void setProtocol(const TQString & protocol);
+ /**
+ * The actual protocol used to handle the request.
+ *
+ * This method will return a different protocol than
+ * the one obtained by using protocol() if a
+ * proxy-server is used for the given protocol. This
+ * usually means that this method will return "http"
+ * when the actuall request was to retrieve a resource
+ * from an "ftp" server by going through a proxy server.
+ *
+ * @return the actual protocol (io-slave) that handled the request
+ */
+ TQString slaveProtocol() { return m_slaveProtocol; }
+
+ /**
+ * @return Host this slave is (was?) connected to
+ */
+ TQString host() { return m_host; }
+
+ /**
+ * @return port this slave is (was?) connected to
+ */
+ int port() { return m_port; }
+
+ /**
+ * @return User this slave is (was?) logged in as
+ */
+ TQString user() { return m_user; }
+
+ /**
+ * @return Passwd used to log in
+ */
+ TQString passwd() { return m_passwd; }
+
+ /**
+ * Creates a new slave.
+ *
+ * @param protocol protocol the slave is for.
+ * @param url URL the slave should operate on.
+ * @param error is the error code on failure and undefined else.
+ * @param error_text is the error text on failure and undefined else.
+ *
+ * @return 0 on failure, or a pointer to a slave otherwise.
+ * @todo What are legal @p protocol values?
+ */
+ static Slave* createSlave( const TQString &protocol, const KURL& url, int& error, TQString& error_text );
+
+ static Slave* holdSlave( const TQString &protocol, const KURL& url );
+
+ // == communication with connected tdeioslave ==
+ // whenever possible prefer these methods over the respective
+ // methods in connection()
+ /**
+ * Suspends the operation of the attached tdeioslave.
+ */
+ void suspend(); // TODO(BIC): make virtual
+ /**
+ * Resumes the operation of the attached tdeioslave.
+ */
+ void resume(); // TODO(BIC): make virtual
+ /**
+ * Tells wether the tdeioslave is suspended.
+ * @return true if the tdeioslave is suspended.
+ * @since 3.2
+ */
+ bool suspended(); // TODO(BIC): make virtual
+ /**
+ * Sends the given command to the tdeioslave.
+ * @param cmd command id
+ * @param data byte array containing data
+ * @since 3.2
+ */
+ void send(int cmd, const TQByteArray &data = TQByteArray());// TODO(BIC): make virtual
+ // == end communication with connected tdeioslave ==
+
+ /**
+ * Puts the tdeioslave associated with @p url at halt.
+ */
+ void hold(const KURL &url); // TODO(BIC): make virtual
+
+ /**
+ * @return The time this slave has been idle.
+ */
+ time_t idleTime();
+
+ /**
+ * Marks this slave as idle.
+ */
+ void setIdle();
+
+ /*
+ * @returns Whether the slave is connected
+ * (Connection oriented slaves only)
+ */
+ bool isConnected() { return contacted; }
+ void setConnected(bool c) { contacted = c; }
+
+ /** @deprecated This method is obsolete, use the accessor methods
+ * within TDEIO::Slave instead. Old code directly accessing connection()
+ * will not be able to access special protocols.
+ */
+ KDE_DEPRECATED Connection *connection() { return &slaveconn; } // TODO(BIC): remove before KDE 4
+
+ void ref() { m_refCount++; }
+ void deref() { m_refCount--; if (!m_refCount) delete this; }
+
+ public slots:
+ void accept(TDESocket *socket);
+ void gotInput();
+ void timeout();
+ signals:
+ void slaveDied(TDEIO::Slave *slave);
+
+ protected:
+ void unlinkSocket();
+
+ private:
+ TQString m_protocol;
+ TQString m_slaveProtocol;
+ TQString m_host;
+ int m_port;
+ TQString m_user;
+ TQString m_passwd;
+ TDEServerSocket *serv;
+ TQString m_socket;
+ pid_t m_pid;
+ bool contacted;
+ bool dead;
+ time_t contact_started;
+ time_t idle_since;
+ TDEIO::Connection slaveconn;
+ int m_refCount;
+ protected:
+ virtual void virtual_hook( int id, void* data );
+ // grant SlaveInterface all IDs < 0x200
+ enum { VIRTUAL_SUSPEND = 0x200, VIRTUAL_RESUME, VIRTUAL_SEND,
+ VIRTUAL_HOLD, VIRTUAL_SUSPENDED,
+ VIRTUAL_SET_HOST, VIRTUAL_SET_CONFIG };
+ struct SendParams {
+ int cmd;
+ const TQByteArray *arr;
+ };
+ struct HoldParams {
+ const KURL *url;
+ };
+ struct SuspendedParams {
+ bool retval;
+ };
+ struct SetHostParams {
+ const TQString *host;
+ int port;
+ const TQString *user;
+ const TQString *passwd;
+ };
+ struct SetConfigParams {
+ const MetaData *config;
+ };
+ private:
+ class SlavePrivate* d;
+ };
+
+}
+
+#endif
diff --git a/tdeio/tdeio/slavebase.cpp b/tdeio/tdeio/slavebase.cpp
new file mode 100644
index 000000000..e979f530b
--- /dev/null
+++ b/tdeio/tdeio/slavebase.cpp
@@ -0,0 +1,1315 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+ * Copyright (c) 2000 David Faure <faure@kde.org>
+ * Copyright (c) 2000 Stephan Kulow <coolo@kde.org>
+ *
+ * $Id$
+ *
+ * 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 "slavebase.h"
+
+#include <config.h>
+
+#include <sys/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h> // Needed on some systems.
+#endif
+
+#include <assert.h>
+#include <kdebug.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+
+#include <tqfile.h>
+
+#include <dcopclient.h>
+
+#include <kapplication.h>
+#include <ksock.h>
+#include <kcrash.h>
+#include <tdesu/client.h>
+#include <klocale.h>
+#include <ksocks.h>
+
+#include "kremoteencoding.h"
+
+#include "tdeio/slavebase.h"
+#include "tdeio/connection.h"
+#include "tdeio/ioslave_defaults.h"
+#include "tdeio/slaveinterface.h"
+
+#include "uiserver_stub.h"
+
+#ifndef NDEBUG
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+#endif
+
+using namespace TDEIO;
+
+template class TQPtrList<TQValueList<UDSAtom> >;
+typedef TQValueList<TQCString> AuthKeysList;
+typedef TQMap<TQString,TQCString> AuthKeysMap;
+#define KIO_DATA TQByteArray data; TQDataStream stream( data, IO_WriteOnly ); stream
+#define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
+
+namespace TDEIO {
+
+class SlaveBaseConfig : public TDEConfigBase
+{
+public:
+ SlaveBaseConfig(SlaveBase *_slave)
+ : slave(_slave) { }
+
+ bool internalHasGroup(const TQCString &) const { tqWarning("hasGroup(const TQCString &)");
+return false; }
+
+ TQStringList groupList() const { return TQStringList(); }
+
+ TQMap<TQString,TQString> entryMap(const TQString &group) const
+ { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
+
+ void reparseConfiguration() { }
+
+ KEntryMap internalEntryMap( const TQString &pGroup) const { Q_UNUSED(pGroup); return KEntryMap(); }
+
+ KEntryMap internalEntryMap() const { return KEntryMap(); }
+
+ void putData(const KEntryKey &_key, const KEntry&_data, bool _checkGroup)
+ { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
+
+ KEntry lookupData(const KEntryKey &_key) const
+ {
+ KEntry entry;
+ TQString value = slave->metaData(_key.c_key);
+ if (!value.isNull())
+ entry.mValue = value.utf8();
+ return entry;
+ }
+protected:
+ SlaveBase *slave;
+};
+
+
+class SlaveBasePrivate {
+public:
+ TQString slaveid;
+ bool resume:1;
+ bool needSendCanResume:1;
+ bool onHold:1;
+ bool wasKilled:1;
+ MetaData configData;
+ SlaveBaseConfig *config;
+ KURL onHoldUrl;
+
+ struct timeval last_tv;
+ TDEIO::filesize_t totalSize;
+ TDEIO::filesize_t sentListEntries;
+ DCOPClient *dcopClient;
+ KRemoteEncoding *remotefile;
+ time_t timeout;
+ TQByteArray timeoutData;
+};
+
+}
+
+static SlaveBase *globalSlave;
+long SlaveBase::s_seqNr;
+
+static volatile bool slaveWriteError = false;
+
+static const char *s_protocol;
+
+#ifdef Q_OS_UNIX
+static void genericsig_handler(int sigNumber)
+{
+ signal(sigNumber,SIG_IGN);
+ //WABA: Don't do anything that requires malloc, we can deadlock on it since
+ //a SIGTERM signal can come in while we are in malloc/free.
+ //kdDebug()<<"tdeioslave : exiting due to signal "<<sigNumber<<endl;
+ //set the flag which will be checked in dispatchLoop() and which *should* be checked
+ //in lengthy operations in the various slaves
+ if (globalSlave!=0)
+ globalSlave->setKillFlag();
+ signal(SIGALRM,SIG_DFL);
+ alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
+}
+#endif
+
+//////////////
+
+SlaveBase::SlaveBase( const TQCString &protocol,
+ const TQCString &pool_socket,
+ const TQCString &app_socket )
+ : mProtocol(protocol), m_pConnection(0),
+ mPoolSocket( TQFile::decodeName(pool_socket)),
+ mAppSocket( TQFile::decodeName(app_socket))
+{
+ s_protocol = protocol.data();
+#ifdef Q_OS_UNIX
+ if (!getenv("TDE_DEBUG"))
+ {
+ KCrash::setCrashHandler( sigsegv_handler );
+ signal(SIGILL,&sigsegv_handler);
+ signal(SIGTRAP,&sigsegv_handler);
+ signal(SIGABRT,&sigsegv_handler);
+ signal(SIGBUS,&sigsegv_handler);
+ signal(SIGALRM,&sigsegv_handler);
+ signal(SIGFPE,&sigsegv_handler);
+#ifdef SIGPOLL
+ signal(SIGPOLL, &sigsegv_handler);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, &sigsegv_handler);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, &sigsegv_handler);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, &sigsegv_handler);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, &sigsegv_handler);
+#endif
+ }
+
+ struct sigaction act;
+ act.sa_handler = sigpipe_handler;
+ sigemptyset( &act.sa_mask );
+ act.sa_flags = 0;
+ sigaction( SIGPIPE, &act, 0 );
+
+ signal(SIGINT,&genericsig_handler);
+ signal(SIGQUIT,&genericsig_handler);
+ signal(SIGTERM,&genericsig_handler);
+#endif
+
+ globalSlave=this;
+
+ appconn = new Connection();
+ listEntryCurrentSize = 100;
+ struct timeval tp;
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ mConnectedToApp = true;
+
+ d = new SlaveBasePrivate;
+ // by kahl for netmgr (need a way to identify slaves)
+ d->slaveid = protocol;
+ d->slaveid += TQString::number(getpid());
+ d->resume = false;
+ d->needSendCanResume = false;
+ d->config = new SlaveBaseConfig(this);
+ d->onHold = false;
+ d->wasKilled=false;
+ d->last_tv.tv_sec = 0;
+ d->last_tv.tv_usec = 0;
+// d->processed_size = 0;
+ d->totalSize=0;
+ d->sentListEntries=0;
+ d->timeout = 0;
+ connectSlave(mAppSocket);
+
+ d->dcopClient = 0;
+ d->remotefile = 0;
+}
+
+SlaveBase::~SlaveBase()
+{
+ delete d;
+ s_protocol = "";
+}
+
+DCOPClient *SlaveBase::dcopClient()
+{
+ if (!d->dcopClient)
+ {
+ d->dcopClient = TDEApplication::dcopClient();
+ if (!d->dcopClient->isAttached())
+ d->dcopClient->attach();
+ d->dcopClient->setDaemonMode( true );
+ }
+ return d->dcopClient;
+}
+
+void SlaveBase::dispatchLoop()
+{
+#ifdef Q_OS_UNIX //TODO: WIN32
+ fd_set rfds;
+ int retval;
+
+ while (true)
+ {
+ if (d->timeout && (d->timeout < time(0)))
+ {
+ TQByteArray data = d->timeoutData;
+ d->timeout = 0;
+ d->timeoutData = TQByteArray();
+ special(data);
+ }
+ FD_ZERO(&rfds);
+
+ assert(appconn->inited());
+ int maxfd = appconn->fd_from();
+ FD_SET(appconn->fd_from(), &rfds);
+ if( d->dcopClient )
+ {
+ FD_SET( d->dcopClient->socket(), &rfds );
+ if( d->dcopClient->socket() > maxfd )
+ maxfd = d->dcopClient->socket();
+ }
+
+ if (!d->timeout) // we can wait forever
+ {
+ retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
+ }
+ else
+ {
+ struct timeval tv;
+ tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
+ tv.tv_usec = 0;
+ retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
+ }
+ if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
+ { // dispatch application messages
+ int cmd;
+ TQByteArray data;
+ if ( appconn->read(&cmd, data) != -1 )
+ {
+ dispatch(cmd, data);
+ }
+ else // some error occurred, perhaps no more application
+ {
+ // When the app exits, should the slave be put back in the pool ?
+ if (mConnectedToApp && !mPoolSocket.isEmpty())
+ {
+ disconnectSlave();
+ mConnectedToApp = false;
+ closeConnection();
+ connectSlave(mPoolSocket);
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+ if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
+ {
+ d->dcopClient->processSocketData( d->dcopClient->socket());
+ }
+ if ((retval<0) && (errno != EINTR))
+ {
+ kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
+ << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
+ << " (" << errno << ")" << endl;
+ return;
+ }
+ //I think we get here when we were killed in dispatch() and not in select()
+ if (wasKilled())
+ {
+ kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
+ return;
+ }
+ }
+#else
+#error The KIO slave system only works under UNIX
+#endif
+}
+
+void SlaveBase::connectSlave(const TQString& path)
+{
+#ifdef Q_OS_UNIX //TODO: TDESocket not yet available on WIN32
+ appconn->init(new TDESocket(TQFile::encodeName(path).data()));
+ if (!appconn->inited())
+ {
+ kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
+ exit();
+ }
+
+ setConnection(appconn);
+#endif
+}
+
+void SlaveBase::disconnectSlave()
+{
+ appconn->close();
+}
+
+void SlaveBase::setMetaData(const TQString &key, const TQString &value)
+{
+ mOutgoingMetaData.replace(key, value);
+}
+
+TQString SlaveBase::metaData(const TQString &key) const
+{
+ if (mIncomingMetaData.contains(key))
+ return mIncomingMetaData[key];
+ if (d->configData.contains(key))
+ return d->configData[key];
+ return TQString::null;
+}
+
+bool SlaveBase::hasMetaData(const TQString &key) const
+{
+ if (mIncomingMetaData.contains(key))
+ return true;
+ if (d->configData.contains(key))
+ return true;
+ return false;
+}
+
+// ### remove the next two methods for KDE4 (they miss the const)
+TQString SlaveBase::metaData(const TQString &key) {
+ return const_cast<const SlaveBase*>(this)->metaData( key );
+}
+bool SlaveBase::hasMetaData(const TQString &key) {
+ return const_cast<const SlaveBase*>(this)->hasMetaData( key );
+}
+
+TDEConfigBase *SlaveBase::config()
+{
+ return d->config;
+}
+
+void SlaveBase::sendMetaData()
+{
+ KIO_DATA << mOutgoingMetaData;
+
+ slaveWriteError = false;
+ m_pConnection->send( INF_META_DATA, data );
+ if (slaveWriteError) exit();
+ mOutgoingMetaData.clear(); // Clear
+}
+
+KRemoteEncoding *SlaveBase::remoteEncoding()
+{
+ if (d->remotefile != 0)
+ return d->remotefile;
+
+ return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1());
+}
+
+void SlaveBase::data( const TQByteArray &data )
+{
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+ slaveWriteError = false;
+ m_pConnection->send( MSG_DATA, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::dataReq( )
+{
+/*
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+*/
+ if (d->needSendCanResume)
+ canResume(0);
+ m_pConnection->send( MSG_DATA_REQ );
+}
+
+void SlaveBase::error( int _errid, const TQString &_text )
+{
+ mIncomingMetaData.clear(); // Clear meta data
+ mOutgoingMetaData.clear();
+ KIO_DATA << (TQ_INT32) _errid << _text;
+
+ m_pConnection->send( MSG_ERROR, data );
+ //reset
+ listEntryCurrentSize = 100;
+ d->sentListEntries=0;
+ d->totalSize=0;
+}
+
+void SlaveBase::connected()
+{
+ slaveWriteError = false;
+ m_pConnection->send( MSG_CONNECTED );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::finished()
+{
+ mIncomingMetaData.clear(); // Clear meta data
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+ m_pConnection->send( MSG_FINISHED );
+
+ // reset
+ listEntryCurrentSize = 100;
+ d->sentListEntries=0;
+ d->totalSize=0;
+}
+
+void SlaveBase::needSubURLData()
+{
+ m_pConnection->send( MSG_NEED_SUBURL_DATA );
+}
+
+void SlaveBase::slaveStatus( const TQString &host, bool connected )
+{
+ pid_t pid = getpid();
+ TQ_INT8 b = connected ? 1 : 0;
+ KIO_DATA << pid << mProtocol << host << b;
+ if (d->onHold)
+ stream << d->onHoldUrl;
+ m_pConnection->send( MSG_SLAVE_STATUS, data );
+}
+
+void SlaveBase::canResume()
+{
+ m_pConnection->send( MSG_CANRESUME );
+}
+
+void SlaveBase::totalSize( TDEIO::filesize_t _bytes )
+{
+ KIO_DATA << KIO_FILESIZE_T(_bytes);
+ slaveWriteError = false;
+ m_pConnection->send( INF_TOTAL_SIZE, data );
+ if (slaveWriteError) exit();
+
+ //this one is usually called before the first item is listed in listDir()
+ struct timeval tp;
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ d->totalSize=_bytes;
+ d->sentListEntries=0;
+}
+
+void SlaveBase::processedSize( TDEIO::filesize_t _bytes )
+{
+ bool emitSignal=false;
+ struct timeval tv;
+ int gettimeofday_res=gettimeofday( &tv, 0L );
+
+ if( _bytes == d->totalSize )
+ emitSignal=true;
+ else if ( gettimeofday_res == 0 ) {
+ time_t msecdiff = 2000;
+ if (d->last_tv.tv_sec) {
+ // Compute difference, in ms
+ msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
+ time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
+ if ( usecdiff < 0 ) {
+ msecdiff--;
+ msecdiff += 1000;
+ }
+ msecdiff += usecdiff / 1000;
+ }
+ emitSignal=msecdiff >= 100; // emit size 10 times a second
+ }
+
+ if( emitSignal ) {
+ KIO_DATA << KIO_FILESIZE_T(_bytes);
+ slaveWriteError = false;
+ m_pConnection->send( INF_PROCESSED_SIZE, data );
+ if (slaveWriteError) exit();
+ if ( gettimeofday_res == 0 ) {
+ d->last_tv.tv_sec = tv.tv_sec;
+ d->last_tv.tv_usec = tv.tv_usec;
+ }
+ }
+// d->processed_size = _bytes;
+}
+
+void SlaveBase::processedPercent( float /* percent */ )
+{
+ kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
+}
+
+
+void SlaveBase::speed( unsigned long _bytes_per_second )
+{
+ KIO_DATA << (TQ_UINT32) _bytes_per_second;
+ slaveWriteError = false;
+ m_pConnection->send( INF_SPEED, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::redirection( const KURL& _url )
+{
+ KIO_DATA << _url;
+ m_pConnection->send( INF_REDIRECTION, data );
+}
+
+void SlaveBase::errorPage()
+{
+ m_pConnection->send( INF_ERROR_PAGE );
+}
+
+static bool isSubCommand(int cmd)
+{
+ return ( (cmd == CMD_REPARSECONFIGURATION) ||
+ (cmd == CMD_META_DATA) ||
+ (cmd == CMD_CONFIG) ||
+ (cmd == CMD_SUBURL) ||
+ (cmd == CMD_SLAVE_STATUS) ||
+ (cmd == CMD_SLAVE_CONNECT) ||
+ (cmd == CMD_SLAVE_HOLD) ||
+ (cmd == CMD_MULTI_GET));
+}
+
+void SlaveBase::mimeType( const TQString &_type)
+{
+ // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
+ int cmd;
+ do
+ {
+ // Send the meta-data each time we send the mime-type.
+ if (!mOutgoingMetaData.isEmpty())
+ {
+ // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
+ KIO_DATA << mOutgoingMetaData;
+ m_pConnection->send( INF_META_DATA, data );
+ }
+ KIO_DATA << _type;
+ m_pConnection->send( INF_MIME_TYPE, data );
+ while(true)
+ {
+ cmd = 0;
+ if ( m_pConnection->read( &cmd, data ) == -1 ) {
+ kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
+ exit();
+ }
+ // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
+ if ( cmd == CMD_HOST) // Ignore.
+ continue;
+ if ( isSubCommand(cmd) )
+ {
+ dispatch( cmd, data );
+ continue; // Disguised goto
+ }
+ break;
+ }
+ }
+ while (cmd != CMD_NONE);
+ mOutgoingMetaData.clear();
+}
+
+void SlaveBase::exit()
+{
+ this->~SlaveBase();
+ ::exit(255);
+}
+
+void SlaveBase::warning( const TQString &_msg)
+{
+ KIO_DATA << _msg;
+ m_pConnection->send( INF_WARNING, data );
+}
+
+void SlaveBase::infoMessage( const TQString &_msg)
+{
+ KIO_DATA << _msg;
+ m_pConnection->send( INF_INFOMESSAGE, data );
+}
+
+bool SlaveBase::requestNetwork(const TQString& host)
+{
+ KIO_DATA << host << d->slaveid;
+ m_pConnection->send( MSG_NET_REQUEST, data );
+
+ if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
+ {
+ bool status;
+ TQDataStream stream( data, IO_ReadOnly );
+ stream >> status;
+ return status;
+ } else
+ return false;
+}
+
+void SlaveBase::dropNetwork(const TQString& host)
+{
+ KIO_DATA << host << d->slaveid;
+ m_pConnection->send( MSG_NET_DROP, data );
+}
+
+void SlaveBase::statEntry( const UDSEntry& entry )
+{
+ KIO_DATA << entry;
+ slaveWriteError = false;
+ m_pConnection->send( MSG_STAT_ENTRY, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
+{
+ static struct timeval tp;
+ static const int maximum_updatetime = 300;
+ static const int minimum_updatetime = 100;
+
+ if (!_ready) {
+ pendingListEntries.append(entry);
+
+ if (pendingListEntries.count() > listEntryCurrentSize) {
+ gettimeofday(&tp, 0);
+
+ long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
+ tp.tv_usec - listEntry_usec) / 1000;
+ if (diff==0) diff=1;
+
+ if (diff > maximum_updatetime) {
+ listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
+ _ready = true;
+ }
+//if we can send all list entries of this dir which have not yet been sent
+//within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
+ else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
+ listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
+//if we are below minimum_updatetime, estimate how much we will get within
+//maximum_updatetime
+ else if (diff < minimum_updatetime)
+ listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
+ else
+ _ready=true;
+ }
+ }
+ if (_ready) { // may happen when we started with !ready
+ listEntries( pendingListEntries );
+ pendingListEntries.clear();
+
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ }
+}
+
+void SlaveBase::listEntries( const UDSEntryList& list )
+{
+ KIO_DATA << (TQ_UINT32)list.count();
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it)
+ stream << *it;
+ slaveWriteError = false;
+ m_pConnection->send( MSG_LIST_ENTRIES, data);
+ if (slaveWriteError) exit();
+ d->sentListEntries+=(uint)list.count();
+}
+
+void SlaveBase::sendAuthenticationKey( const TQCString& key,
+ const TQCString& group,
+ bool keepPass )
+{
+ KIO_DATA << key << group << keepPass;
+ m_pConnection->send( MSG_AUTH_KEY, data );
+}
+
+void SlaveBase::delCachedAuthentication( const TQString& key )
+{
+ KIO_DATA << key.utf8() ;
+ m_pConnection->send( MSG_DEL_AUTH_KEY, data );
+}
+
+void SlaveBase::sigsegv_handler(int sig)
+{
+#ifdef Q_OS_UNIX
+ signal(sig,SIG_DFL); // Next one kills
+
+ //Kill us if we deadlock
+ signal(SIGALRM,SIG_DFL);
+ alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
+
+ // Debug and printf should be avoided because they might
+ // call malloc.. and get in a nice recursive malloc loop
+ char buffer[120];
+ snprintf(buffer, sizeof(buffer), "tdeioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
+ write(2, buffer, strlen(buffer));
+#ifndef NDEBUG
+#ifdef HAVE_BACKTRACE
+ void* trace[256];
+ int n = backtrace(trace, 256);
+ if (n)
+ backtrace_symbols_fd(trace, n, 2);
+#endif
+#endif
+ ::exit(1);
+#endif
+}
+
+void SlaveBase::sigpipe_handler (int)
+{
+ // We ignore a SIGPIPE in slaves.
+ // A SIGPIPE can happen in two cases:
+ // 1) Communication error with application.
+ // 2) Communication error with network.
+ slaveWriteError = true;
+
+ // Don't add anything else here, especially no debug output
+}
+
+void SlaveBase::setHost(TQString const &, int, TQString const &, TQString const &)
+{
+}
+
+void SlaveBase::openConnection(void)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
+void SlaveBase::closeConnection(void)
+{ } // No response!
+void SlaveBase::stat(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
+void SlaveBase::put(KURL const &, int, bool, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
+void SlaveBase::special(const TQByteArray &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
+void SlaveBase::listDir(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
+void SlaveBase::get(KURL const & )
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
+void SlaveBase::mimetype(KURL const &url)
+{ get(url); }
+void SlaveBase::rename(KURL const &, KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
+void SlaveBase::symlink(TQString const &, KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
+void SlaveBase::copy(KURL const &, KURL const &, int, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
+void SlaveBase::del(KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
+void SlaveBase::mkdir(KURL const &, int)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
+void SlaveBase::chmod(KURL const &, int)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
+void SlaveBase::setSubURL(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
+void SlaveBase::multiGet(const TQByteArray &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
+
+
+void SlaveBase::slave_status()
+{ slaveStatus( TQString::null, false ); }
+
+void SlaveBase::reparseConfiguration()
+{
+}
+
+void SlaveBase::localURL(const KURL& remoteURL)
+{
+ bool local = remoteURL.isLocalFile();
+ TQ_INT8 islocal;
+ KURL retURL;
+ if (local) {
+ islocal = true;
+ retURL = remoteURL;
+ }
+ else {
+ islocal = false;
+ retURL = remoteURL;
+ }
+ KIO_DATA << islocal << retURL;
+ m_pConnection->send( INF_LOCALURL, data );
+}
+
+bool SlaveBase::dispatch()
+{
+ assert( m_pConnection );
+
+ int cmd;
+ TQByteArray data;
+ if ( m_pConnection->read( &cmd, data ) == -1 )
+ {
+ kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
+ return false;
+ }
+
+ dispatch( cmd, data );
+ return true;
+}
+
+bool SlaveBase::openPassDlg( AuthInfo& info )
+{
+ return openPassDlg(info, TQString::null);
+}
+
+bool SlaveBase::openPassDlg( AuthInfo& info, const TQString &errorMsg )
+{
+ TQCString replyType;
+ TQByteArray params;
+ TQByteArray reply;
+ AuthInfo authResult;
+ long windowId = metaData("window-id").toLong();
+ long progressId = metaData("progress-id").toLong();
+ unsigned long userTimestamp = metaData("user-timestamp").toULong();
+
+ kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << " progress-id=" << progressId << endl;
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ UIServer_stub uiserver( "tdeio_uiserver", "UIServer" );
+ if (progressId)
+ uiserver.setJobVisible( progressId, false );
+
+ TQDataStream stream(params, IO_WriteOnly);
+
+ if (metaData("no-auth-prompt").lower() == "true")
+ stream << info << TQString("<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
+ else
+ stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
+
+ bool callOK = d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(TDEIO::AuthInfo, TQString, long int, long int, unsigned long int)",
+ params, replyType, reply );
+
+ if (progressId)
+ uiserver.setJobVisible( progressId, true );
+
+ if (!callOK)
+ {
+ kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
+ return false;
+ }
+
+ if ( replyType == "TDEIO::AuthInfo" )
+ {
+ TQDataStream stream2( reply, IO_ReadOnly );
+ stream2 >> authResult >> s_seqNr;
+ }
+ else
+ {
+ kdError(7019) << "DCOP function queryAuthInfo(...) returns "
+ << replyType << ", expected TDEIO::AuthInfo" << endl;
+ return false;
+ }
+
+ if (!authResult.isModified())
+ return false;
+
+ info = authResult;
+
+ kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
+ kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
+
+ return true;
+}
+
+int SlaveBase::messageBox( MessageBoxType type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo )
+{
+ return messageBox( text, type, caption, buttonYes, buttonNo, TQString::null );
+}
+
+int SlaveBase::messageBox( const TQString &text, MessageBoxType type, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName )
+{
+ kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
+ KIO_DATA << (TQ_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
+ m_pConnection->send( INF_MESSAGEBOX, data );
+ if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
+ {
+ TQDataStream stream( data, IO_ReadOnly );
+ int answer;
+ stream >> answer;
+ kdDebug(7019) << "got messagebox answer" << answer << endl;
+ return answer;
+ } else
+ return 0; // communication failure
+}
+
+bool SlaveBase::canResume( TDEIO::filesize_t offset )
+{
+ kdDebug(7019) << "SlaveBase::canResume offset=" << TDEIO::number(offset) << endl;
+ d->needSendCanResume = false;
+ KIO_DATA << KIO_FILESIZE_T(offset);
+ m_pConnection->send( MSG_RESUME, data );
+ if ( offset )
+ {
+ int cmd;
+ if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
+ {
+ kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
+ return cmd == CMD_RESUMEANSWER;
+ } else
+ return false;
+ }
+ else // No resuming possible -> no answer to wait for
+ return true;
+}
+
+
+
+int SlaveBase::waitForAnswer( int expected1, int expected2, TQByteArray & data, int *pCmd )
+{
+ int cmd, result;
+ for (;;)
+ {
+ result = m_pConnection->read( &cmd, data );
+ if ( result == -1 )
+ {
+ kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
+ return -1;
+ }
+ if ( cmd == expected1 || cmd == expected2 )
+ {
+ if ( pCmd ) *pCmd = cmd;
+ return result;
+ }
+ if ( isSubCommand(cmd) )
+ {
+ dispatch( cmd, data );
+ }
+ else
+ {
+ kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
+ }
+ }
+}
+
+
+int SlaveBase::readData( TQByteArray &buffer)
+{
+ int result = waitForAnswer( MSG_DATA, 0, buffer );
+ //kdDebug(7019) << "readData: length = " << result << " " << endl;
+ return result;
+}
+
+void SlaveBase::setTimeoutSpecialCommand(int timeout, const TQByteArray &data)
+{
+ if (timeout > 0)
+ d->timeout = time(0)+(time_t)timeout;
+ else if (timeout == 0)
+ d->timeout = 1; // Immediate timeout
+ else
+ d->timeout = 0; // Canceled
+
+ d->timeoutData = data;
+}
+
+void SlaveBase::dispatch( int command, const TQByteArray &data )
+{
+ TQDataStream stream( data, IO_ReadOnly );
+
+ KURL url;
+ int i;
+
+ switch( command ) {
+ case CMD_HOST: {
+ // Reset s_seqNr, see kpasswdserver/DESIGN
+ s_seqNr = 0;
+ TQString passwd;
+ TQString host, user;
+ stream >> host >> i >> user >> passwd;
+ setHost( host, i, user, passwd );
+ }
+ break;
+ case CMD_CONNECT:
+ openConnection( );
+ break;
+ case CMD_DISCONNECT:
+ closeConnection( );
+ break;
+ case CMD_SLAVE_STATUS:
+ slave_status();
+ break;
+ case CMD_SLAVE_CONNECT:
+ {
+ d->onHold = false;
+ TQString app_socket;
+ TQDataStream stream( data, IO_ReadOnly);
+ stream >> app_socket;
+ appconn->send( MSG_SLAVE_ACK );
+ disconnectSlave();
+ mConnectedToApp = true;
+ connectSlave(app_socket);
+ } break;
+ case CMD_SLAVE_HOLD:
+ {
+ KURL url;
+ TQDataStream stream( data, IO_ReadOnly);
+ stream >> url;
+ d->onHoldUrl = url;
+ d->onHold = true;
+ disconnectSlave();
+ mConnectedToApp = false;
+ // Do not close connection!
+ connectSlave(mPoolSocket);
+ } break;
+ case CMD_REPARSECONFIGURATION:
+ reparseConfiguration();
+ break;
+ case CMD_CONFIG:
+ stream >> d->configData;
+#ifdef Q_OS_UNIX //TODO: not yet available on WIN32
+ KSocks::setConfig(d->config);
+#endif
+ delete d->remotefile;
+ d->remotefile = 0;
+ break;
+ case CMD_GET:
+ {
+ stream >> url;
+ get( url );
+ } break;
+ case CMD_PUT:
+ {
+ int permissions;
+ TQ_INT8 iOverwrite, iResume;
+ stream >> url >> iOverwrite >> iResume >> permissions;
+ bool overwrite = ( iOverwrite != 0 );
+ bool resume = ( iResume != 0 );
+
+ // Remember that we need to send canResume(), TransferJob is expecting
+ // it. Well, in theory this shouldn't be done if resume is true.
+ // (the resume bool is currently unused)
+ d->needSendCanResume = true /* !resume */;
+
+ put( url, permissions, overwrite, resume);
+ } break;
+ case CMD_STAT:
+ stream >> url;
+ stat( url );
+ break;
+ case CMD_MIMETYPE:
+ stream >> url;
+ mimetype( url );
+ break;
+ case CMD_LISTDIR:
+ stream >> url;
+ listDir( url );
+ break;
+ case CMD_MKDIR:
+ stream >> url >> i;
+ mkdir( url, i );
+ break;
+ case CMD_RENAME:
+ {
+ TQ_INT8 iOverwrite;
+ KURL url2;
+ stream >> url >> url2 >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ rename( url, url2, overwrite );
+ } break;
+ case CMD_SYMLINK:
+ {
+ TQ_INT8 iOverwrite;
+ TQString target;
+ stream >> target >> url >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ symlink( target, url, overwrite );
+ } break;
+ case CMD_COPY:
+ {
+ int permissions;
+ TQ_INT8 iOverwrite;
+ KURL url2;
+ stream >> url >> url2 >> permissions >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ copy( url, url2, permissions, overwrite );
+ } break;
+ case CMD_DEL:
+ {
+ TQ_INT8 isFile;
+ stream >> url >> isFile;
+ del( url, isFile != 0);
+ } break;
+ case CMD_CHMOD:
+ stream >> url >> i;
+ chmod( url, i);
+ break;
+ case CMD_SPECIAL:
+ special( data );
+ break;
+ case CMD_META_DATA:
+ //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
+ stream >> mIncomingMetaData;
+ break;
+ case CMD_SUBURL:
+ stream >> url;
+ setSubURL(url);
+ break;
+ case CMD_NONE:
+ fprintf(stderr, "Got unexpected CMD_NONE!\n");
+ break;
+ case CMD_MULTI_GET:
+ multiGet( data );
+ break;
+ case CMD_LOCALURL:
+ {
+ stream >> url;
+ localURL( url );
+ } break;
+ default:
+ // Some command we don't understand.
+ // Just ignore it, it may come from some future version of KDE.
+ break;
+ }
+}
+
+TQString SlaveBase::createAuthCacheKey( const KURL& url )
+{
+ if( !url.isValid() )
+ return TQString::null;
+
+ // Generate the basic key sequence.
+ TQString key = url.protocol();
+ key += '-';
+ key += url.host();
+ int port = url.port();
+ if( port )
+ {
+ key += ':';
+ key += TQString::number(port);
+ }
+
+ return key;
+}
+
+bool SlaveBase::pingCacheDaemon() const
+{
+#ifdef Q_OS_UNIX
+ // TODO: Ping kded / kpasswdserver
+ KDEsuClient client;
+ int success = client.ping();
+ if( success == -1 )
+ {
+ success = client.startServer();
+ if( success == -1 )
+ {
+ kdDebug(7019) << "Cannot start a new deamon!!" << endl;
+ return false;
+ }
+ kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
+{
+ TQCString replyType;
+ TQByteArray params;
+ TQByteArray reply;
+ AuthInfo authResult;
+ long windowId = metaData("window-id").toLong();
+ unsigned long userTimestamp = metaData("user-timestamp").toULong();
+
+ kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << info << windowId << userTimestamp;
+
+ if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(TDEIO::AuthInfo, long int, unsigned long int)",
+ params, replyType, reply ) )
+ {
+ kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
+ return false;
+ }
+
+ if ( replyType == "TDEIO::AuthInfo" )
+ {
+ TQDataStream stream2( reply, IO_ReadOnly );
+ stream2 >> authResult;
+ }
+ else
+ {
+ kdError(7019) << "DCOP function checkAuthInfo(...) returns "
+ << replyType << ", expected TDEIO::AuthInfo" << endl;
+ return false;
+ }
+ if (!authResult.isModified())
+ {
+ return false;
+ }
+
+ info = authResult;
+ return true;
+}
+
+bool SlaveBase::cacheAuthentication( const AuthInfo& info )
+{
+ TQByteArray params;
+ long windowId = metaData("window-id").toLong();
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << info << windowId;
+
+ d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(TDEIO::AuthInfo, long int)", params );
+
+ return true;
+}
+
+int SlaveBase::connectTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ConnectTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_CONNECT_TIMEOUT;
+}
+
+int SlaveBase::proxyConnectTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ProxyConnectTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_PROXY_CONNECT_TIMEOUT;
+}
+
+
+int SlaveBase::responseTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ResponseTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_RESPONSE_TIMEOUT;
+}
+
+
+int SlaveBase::readTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ReadTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_READ_TIMEOUT;
+}
+
+bool SlaveBase::wasKilled() const
+{
+ return d->wasKilled;
+}
+
+void SlaveBase::setKillFlag()
+{
+ d->wasKilled=true;
+}
+
+void SlaveBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/tdeio/tdeio/slavebase.h b/tdeio/tdeio/slavebase.h
new file mode 100644
index 000000000..1030d94c4
--- /dev/null
+++ b/tdeio/tdeio/slavebase.h
@@ -0,0 +1,847 @@
+/*
+ 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 __slavebase_h
+#define __slavebase_h
+
+#include <kurl.h>
+#include <tdeconfigbase.h>
+#include <tdeio/global.h>
+#include <tdeio/authinfo.h>
+
+class DCOPClient;
+class KRemoteEncoding;
+
+namespace TDEIO {
+
+class Connection;
+class SlaveBasePrivate;
+
+/**
+ * There are two classes that specifies the protocol between application (job)
+ * and tdeioslave. SlaveInterface is the class to use on the application end,
+ * SlaveBase is the one to use on the slave end.
+ *
+ * Slave implementations should simply inherit SlaveBase
+ *
+ * A call to foo() results in a call to slotFoo() on the other end.
+ */
+class TDEIO_EXPORT SlaveBase
+{
+public:
+ SlaveBase( const TQCString &protocol, const TQCString &pool_socket, const TQCString &app_socket);
+ virtual ~SlaveBase();
+
+ /**
+ * @internal
+ * Terminate the slave by calling the destructor and then ::exit()
+ */
+ void exit();
+
+ /**
+ * @internal
+ */
+ void dispatchLoop();
+
+ /**
+ * @internal
+ */
+ void setConnection( Connection* connection ) { m_pConnection = connection; }
+ /**
+ * @internal
+ */
+ Connection *connection() const { return m_pConnection; }
+
+
+ ///////////
+ // Message Signals to send to the job
+ ///////////
+
+ /**
+ * Sends data in the slave to the job (i.e. in get).
+ *
+ * To signal end of data, simply send an empty
+ * TQByteArray().
+ *
+ * @param data the data read by the slave
+ */
+ void data( const TQByteArray &data );
+
+ /**
+ * Asks for data from the job.
+ * @see readData
+ */
+ void dataReq( );
+
+ /**
+ * Call to signal an error.
+ * This also finishes the job, no need to call finished.
+ *
+ * If the Error code is TDEIO::ERR_SLAVE_DEFINED then the
+ * _text should contain the complete translated text of
+ * of the error message. This message will be displayed
+ * in an KTextBrowser which allows rich text complete
+ * with hyper links. Email links will call the default
+ * mailer, "exec:/command arg1 arg2" will be forked and
+ * all other links will call the default browser.
+ *
+ * @see TDEIO::Error
+ * @see KTextBrowser
+ * @param _errid the error code from TDEIO::Error
+ * @param _text the rich text error message
+ */
+ void error( int _errid, const TQString &_text );
+
+ /**
+ * Call in openConnection, if you reimplement it, when you're done.
+ */
+ void connected();
+
+ /**
+ * Call to signal successful completion of any command
+ * (besides openConnection and closeConnection)
+ */
+ void finished();
+
+ /**
+ * Call to signal that data from the sub-URL is needed
+ */
+ void needSubURLData();
+
+ /**
+ * Used to report the status of the slave.
+ * @param host the slave is currently connected to. (Should be
+ * empty if not connected)
+ * @param connected Whether an actual network connection exists.
+ **/
+ void slaveStatus(const TQString &host, bool connected);
+
+ /**
+ * Call this from stat() to express details about an object, the
+ * UDSEntry customarily contains the atoms describing file name, size,
+ * mimetype, etc.
+ * @param _entry The UDSEntry containing all of the object attributes.
+ */
+ void statEntry( const UDSEntry& _entry );
+
+ /**
+ * Call this in listDir, each time you have a bunch of entries
+ * to report.
+ * @param _entry The UDSEntry containing all of the object attributes.
+ */
+ void listEntries( const UDSEntryList& _entry );
+
+ /**
+ * Call this at the beginning of put(), to give the size of the existing
+ * partial file, if there is one. The @p offset argument notifies the
+ * other job (the one that gets the data) about the offset to use.
+ * In this case, the boolean returns whether we can indeed resume or not
+ * (we can't if the protocol doing the get() doesn't support setting an offset)
+ */
+ bool canResume( TDEIO::filesize_t offset );
+
+ /*
+ * Call this at the beginning of get(), if the "resume" metadata was set
+ * and resuming is implemented by this protocol.
+ */
+ void canResume();
+
+ ///////////
+ // Info Signals to send to the job
+ ///////////
+
+ /**
+ * Call this in get and copy, to give the total size
+ * of the file
+ * Call in listDir too, when you know the total number of items.
+ */
+ void totalSize( TDEIO::filesize_t _bytes );
+ /**
+ * Call this during get and copy, once in a while,
+ * to give some info about the current state.
+ * Don't emit it in listDir, listEntries speaks for itself.
+ */
+ void processedSize( TDEIO::filesize_t _bytes );
+
+ /**
+ * Only use this if you can't know in advance the size of the
+ * copied data. For example, if you're doing variable bitrate
+ * compression of the source.
+ *
+ * STUB ! Currently unimplemented. Here now for binary compatibility.
+ *
+ * Call this during get and copy, once in a while,
+ * to give some info about the current state.
+ * Don't emit it in listDir, listEntries speaks for itself.
+ */
+ void processedPercent( float percent );
+
+ /**
+ * Call this in get and copy, to give the current transfer
+ * speed, but only if it can't be calculated out of the size you
+ * passed to processedSize (in most cases you don't want to call it)
+ */
+ void speed( unsigned long _bytes_per_second );
+
+ /**
+ * Call this to signal a redirection
+ * The job will take care of going to that url.
+ */
+ void redirection( const KURL &_url );
+
+ /**
+ * Tell that we will only get an error page here.
+ * This means: the data you'll get isn't the data you requested,
+ * but an error page (usually HTML) that describes an error.
+ */
+ void errorPage();
+
+ /**
+ * Call this in mimetype() and in get(), when you know the mimetype.
+ * See mimetype about other ways to implement it.
+ */
+ void mimeType( const TQString &_type );
+
+ /**
+ * Call to signal a warning, to be displayed in a dialog box.
+ */
+ void warning( const TQString &msg );
+
+ /**
+ * Call to signal a message, to be displayed if the application wants to,
+ * for instance in a status bar. Usual examples are "connecting to host xyz", etc.
+ */
+ void infoMessage( const TQString &msg );
+
+ enum MessageBoxType { QuestionYesNo = 1, WarningYesNo = 2, WarningContinueCancel = 3, WarningYesNoCancel = 4, Information = 5, SSLMessageBox = 6 };
+
+ /**
+ * Call this to show a message box from the slave
+ * @param type type of message box: QuestionYesNo, WarningYesNo, WarningContinueCancel...
+ * @param text Message string. May contain newlines.
+ * @param caption Message box title.
+ * @param buttonYes The text for the first button.
+ * The default is i18n("&Yes").
+ * @param buttonNo The text for the second button.
+ * The default is i18n("&No").
+ * Note: for ContinueCancel, buttonYes is the continue button and buttonNo is unused.
+ * and for Information, none is used.
+ * @return a button code, as defined in KMessageBox, or 0 on communication error.
+ */
+ int messageBox( MessageBoxType type, const TQString &text,
+ const TQString &caption = TQString::null,
+ const TQString &buttonYes = TQString::null,
+ const TQString &buttonNo = TQString::null );
+
+ /**
+ * Call this to show a message box from the slave
+ * @param text Message string. May contain newlines.
+ * @param type type of message box: QuestionYesNo, WarningYesNo, WarningContinueCancel...
+ * @param caption Message box title.
+ * @param buttonYes The text for the first button.
+ * The default is i18n("&Yes").
+ * @param buttonNo The text for the second button.
+ * The default is i18n("&No").
+ * Note: for ContinueCancel, buttonYes is the continue button and buttonNo is unused.
+ * and for Information, none is used.
+ * @param dontAskAgainName A checkbox is added with which further confirmation can be turned off.
+ * The string is used to lookup and store the setting in tdeioslaverc.
+ * @return a button code, as defined in KMessageBox, or 0 on communication error.
+ * @since 3.3
+ */
+ int messageBox( const TQString &text, MessageBoxType type,
+ const TQString &caption = TQString::null,
+ const TQString &buttonYes = TQString::null,
+ const TQString &buttonNo = TQString::null,
+ const TQString &dontAskAgainName = TQString::null );
+
+ /**
+ * Sets meta-data to be send to the application before the first
+ * data() or finished() signal.
+ */
+ void setMetaData(const TQString &key, const TQString &value);
+
+ /**
+ * Queries for the existence of a certain config/meta-data entry
+ * send by the application to the slave.
+ * @since 3.2
+ */
+ bool hasMetaData(const TQString &key) const;
+
+ /**
+ * Queries for config/meta-data send by the application to the slave.
+ * @since 3.2
+ */
+ TQString metaData(const TQString &key) const;
+
+ /**
+ * @obsolete kept for binary compatibility
+ * Queries for the existence of a certain config/meta-data entry
+ * send by the application to the slave.
+ */
+ bool hasMetaData(const TQString &key);
+
+ /**
+ * @obsolete kept for binary compatibility
+ * Queries for config/meta-data sent by the application to the slave.
+ */
+ TQString metaData(const TQString &key);
+
+ /**
+ * @internal for ForwardingSlaveBase
+ * Contains all metadata (but no config) sent by the application to the slave.
+ * @since 3.5.2
+ */
+ MetaData allMetaData() const { return mIncomingMetaData; }
+
+ /**
+ * Returns a configuration object to query config/meta-data information
+ * from.
+ *
+ * The application provides the slave with all configuration information
+ * relevant for the current protocol and host.
+ */
+ TDEConfigBase* config();
+
+ /**
+ * Returns an object that can translate remote filenames into proper
+ * Unicode forms. This encoding can be set by the user.
+ *
+ * @since 3.3
+ */
+ KRemoteEncoding* remoteEncoding();
+
+
+ ///////////
+ // Commands sent by the job, the slave has to
+ // override what it wants to implement
+ ///////////
+
+ /**
+ * Set the host
+ * @param host
+ * @param port
+ * @param user
+ * @param pass
+ * Called directly by createSlave, this is why there is no equivalent in
+ * SlaveInterface, unlike the other methods.
+ *
+ * This method is called whenever a change in host, port or user occurs.
+ */
+ virtual void setHost(const TQString& host, int port, const TQString& user, const TQString& pass);
+
+ /**
+ * Prepare slave for streaming operation
+ */
+ virtual void setSubURL(const KURL&url);
+
+ /**
+ * Opens the connection (forced)
+ * When this function gets called the slave is operating in
+ * connection-oriented mode.
+ * When a connection gets lost while the slave operates in
+ * connection oriented mode, the slave should report
+ * ERR_CONNECTION_BROKEN instead of reconnecting. The user is
+ * expected to disconnect the slave in the error handler.
+ */
+ virtual void openConnection();
+
+ /**
+ * Closes the connection (forced)
+ * Called when the application disconnects the slave to close
+ * any open network connections.
+ *
+ * When the slave was operating in connection-oriented mode,
+ * it should reset itself to connectionless (default) mode.
+ */
+ virtual void closeConnection();
+
+ /**
+ * get, aka read.
+ * @param url the full url for this request. Host, port and user of the URL
+ * can be assumed to be the same as in the last setHost() call.
+ * The slave emits the data through data
+ */
+ virtual void get( const KURL& url );
+
+ /**
+ * put, i.e. write data into a file.
+ *
+ * @param url where to write the file
+ * @param permissions may be -1. In this case no special permission mode is set.
+ * @param overwrite if true, any existing file will be overwritten.
+ * If the file indeed already exists, the slave should NOT apply the
+ * permissions change to it.
+ * @param resume currently unused, please ignore.
+ * The support for resuming using .part files is done by calling canResume().
+ *
+ * IMPORTANT: Use the "modified" metadata in order to set the modification time of the file.
+ *
+ * @see canResume()
+ */
+ virtual void put( const KURL& url, int permissions, bool overwrite, bool resume );
+
+ /**
+ * Finds all details for one file or directory.
+ * The information returned is the same as what listDir returns,
+ * but only for one file or directory.
+ */
+ virtual void stat( const KURL& url );
+
+ /**
+ * Finds mimetype for one file or directory.
+ *
+ * This method should either emit 'mimeType' or it
+ * should send a block of data big enough to be able
+ * to determine the mimetype.
+ *
+ * If the slave doesn't reimplement it, a get will
+ * be issued, i.e. the whole file will be downloaded before
+ * determining the mimetype on it - this is obviously not a
+ * good thing in most cases.
+ */
+ virtual void mimetype( const KURL& url );
+
+ /**
+ * Lists the contents of @p url.
+ * The slave should emit ERR_CANNOT_ENTER_DIRECTORY if it doesn't exist,
+ * if we don't have enough permissions, or if it is a file
+ * It should also emit totalFiles as soon as it knows how many
+ * files it will list.
+ */
+ virtual void listDir( const KURL& url );
+
+ /**
+ * Create a directory
+ * @param url path to the directory to create
+ * @param permissions the permissions to set after creating the directory
+ * (-1 if no permissions to be set)
+ * The slave emits ERR_COULD_NOT_MKDIR if failure.
+ */
+ virtual void mkdir( const KURL&url, int permissions );
+
+ /**
+ * Rename @p oldname into @p newname.
+ * If the slave returns an error ERR_UNSUPPORTED_ACTION, the job will
+ * ask for copy + del instead.
+ * @param src where to move the file from
+ * @param dest where to move the file to
+ * @param overwrite if true, any existing file will be overwritten
+ */
+ virtual void rename( const KURL& src, const KURL& dest, bool overwrite );
+
+ /**
+ * Creates a symbolic link named @p dest, pointing to @p target, which
+ * may be a relative or an absolute path.
+ * @param target The string that will become the "target" of the link (can be relative)
+ * @param dest The symlink to create.
+ * @param overwrite whether to automatically overwrite if the dest exists
+ */
+ virtual void symlink( const TQString& target, const KURL& dest, bool overwrite );
+
+ /**
+ * Change permissions on @p path
+ * The slave emits ERR_DOES_NOT_EXIST or ERR_CANNOT_CHMOD
+ */
+ virtual void chmod( const KURL& url, int permissions );
+
+ /**
+ * Copy @p src into @p dest.
+ * If the slave returns an error ERR_UNSUPPORTED_ACTION, the job will
+ * ask for get + put instead.
+ * @param src where to copy the file from (decoded)
+ * @param dest where to copy the file to (decoded)
+ * @param permissions may be -1. In this case no special permission mode is set.
+ * @param overwrite if true, any existing file will be overwritten
+ *
+ */
+ virtual void copy( const KURL &src, const KURL &dest, int permissions, bool overwrite );
+
+ /**
+ * Delete a file or directory.
+ * @param url file/directory to delete
+ * @param isfile if true, a file should be deleted.
+ * if false, a directory should be deleted.
+ */
+ virtual void del( const KURL &url, bool isfile);
+
+ // TODO KDE4: add setLinkDest() or something, to modify symlink targets.
+ // Will be used for kio_file but also kio_remote (#97129)
+
+ /**
+ * Used for any command that is specific to this slave (protocol)
+ * Examples are : HTTP POST, mount and unmount (kio_file)
+ *
+ * @param data packed data; the meaning is completely dependent on the
+ * slave, but usually starts with an int for the command number.
+ * Document your slave's commands, at least in its header file.
+ */
+ virtual void special( const TQByteArray & data );
+
+ /**
+ * Used for multiple get. Currently only used foir HTTP pielining
+ * support.
+ *
+ * @param data packed data; Contains number of URLs to fetch, and for
+ * each URL the URL itself and its associated MetaData.
+ */
+ virtual void multiGet( const TQByteArray & data );
+
+ /**
+ * Called to get the status of the slave. Slave should respond
+ * by calling slaveStatus(...)
+ */
+ virtual void slave_status();
+
+ /**
+ * Called by the scheduler to tell the slave that the configuration
+ * changed (i.e. proxy settings) .
+ */
+ virtual void reparseConfiguration();
+
+ /**
+ * For use with for ForwardingSlaveBase
+ * Returns the local URL of the given remote URL if possible
+ * @since R14.0.0
+ */
+ virtual void localURL( const KURL& remoteURL );
+
+ /**
+ * @return timeout value for connecting to remote host.
+ */
+ int connectTimeout();
+
+ /**
+ * @return timeout value for connecting to proxy in secs.
+ */
+ int proxyConnectTimeout();
+
+ /**
+ * @return timeout value for read from first data from
+ * remote host in seconds.
+ */
+ int responseTimeout();
+
+ /**
+ * @return timeout value for read from subsequent data from
+ * remote host in secs.
+ */
+ int readTimeout();
+
+ /**
+ * This function sets a timeout of @p timeout seconds and calls
+ * special(data) when the timeout occurs as if it was called by the
+ * application.
+ *
+ * A timeout can only occur when the slave is waiting for a command
+ * from the application.
+ *
+ * Specifying a negative timeout cancels a pending timeout.
+ *
+ * Only one timeout at a time is supported, setting a timeout
+ * cancels any pending timeout.
+ * @since 3.1
+ */
+ void setTimeoutSpecialCommand(int timeout, const TQByteArray &data=TQByteArray());
+
+ /**
+ * @internal
+ */
+ static void sigsegv_handler(int);
+ /**
+ * @internal
+ */
+ static void sigpipe_handler(int);
+
+ /////////////////
+ // Dispatching (internal)
+ ////////////////
+
+ /**
+ * @internal
+ */
+ virtual bool dispatch();
+ /**
+ * @internal
+ */
+ virtual void dispatch( int command, const TQByteArray &data );
+
+ /**
+ * Read data send by the job, after a dataReq
+ *
+ * @param buffer buffer where data is stored
+ * @return 0 on end of data,
+ * > 0 bytes read
+ * < 0 error
+ **/
+ int readData( TQByteArray &buffer );
+
+ /**
+ * internal function to be called by the slave.
+ * It collects entries and emits them via listEntries
+ * when enough of them are there or a certain time
+ * frame exceeded (to make sure the app gets some
+ * items in time but not too many items one by one
+ * as this will cause a drastic performance penalty)
+ * @param _entry The UDSEntry containing all of the object attributes.
+ * @param ready set to true after emitting all items. @p _entry is not
+ * used in this case
+ */
+ void listEntry( const UDSEntry& _entry, bool ready);
+
+ /**
+ * internal function to connect a slave to/ disconnect from
+ * either the slave pool or the application
+ */
+ void connectSlave(const TQString& path);
+ void disconnectSlave();
+
+ /**
+ * Prompt the user for Authorization info (login & password).
+ *
+ * Use this function to request authorization information from
+ * the end user. You can also pass an error message which explains
+ * why a previous authorization attempt failed. Here is a very
+ * simple example:
+ *
+ * \code
+ * TDEIO::AuthInfo authInfo;
+ * if ( openPassDlg( authInfo ) )
+ * {
+ * kdDebug() << TQString::fromLatin1("User: ")
+ * << authInfo.username << endl;
+ * kdDebug() << TQString::fromLatin1("Password: ")
+ * << TQString::fromLatin1("Not displayed here!") << endl;
+ * }
+ * \endcode
+ *
+ * You can also preset some values like the username, caption or
+ * comment as follows:
+ *
+ * \code
+ * TDEIO::AuthInfo authInfo;
+ * authInfo.caption= "Acme Password Dialog";
+ * authInfo.username= "Wile E. Coyote";
+ * TQString errorMsg = "You entered an incorrect password.";
+ * if ( openPassDlg( authInfo, errorMsg ) )
+ * {
+ * kdDebug() << TQString::fromLatin1("User: ")
+ * << authInfo.username << endl;
+ * kdDebug() << TQString::fromLatin1("Password: ")
+ * << TQString::fromLatin1("Not displayed here!") << endl;
+ * }
+ * \endcode
+ *
+ * \note You should consider using checkCachedAuthentication() to
+ * see if the password is available in kpasswdserver before calling
+ * this function.
+ *
+ * \note A call to this function can fail and return @p false,
+ * if the UIServer could not be started for whatever reason.
+ *
+ * @see checkCachedAuthentication
+ * @param info See AuthInfo.
+ * @param errorMsg Error message to show
+ * @return @p true if user clicks on "OK", @p false otherwsie.
+ * @since 3.1
+ */
+ bool openPassDlg( TDEIO::AuthInfo& info, const TQString &errorMsg );
+
+ /**
+ * Same as above function except it does not need error message.
+ * BIC: Combine this function with the above for KDE4.
+ */
+ bool openPassDlg( TDEIO::AuthInfo& info );
+
+ /**
+ * Checks for cached authentication based on parameters
+ * given by @p info.
+ *
+ * Use this function to check if any cached password exists
+ * for the URL given by @p info. If @p AuthInfo::realmValue
+ * and/or @p AuthInfo::verifyPath flag is specified, then
+ * they will also be factored in determining the presence
+ * of a cached password. Note that @p Auth::url is a required
+ * parameter when attempting to check for cached authorization
+ * info. Here is a simple example:
+ *
+ * \code
+ * AuthInfo info;
+ * info.url = KURL("http://www.foobar.org/foo/bar");
+ * info.username = "somename";
+ * info.verifyPath = true;
+ * if ( !checkCachedAuthentication( info ) )
+ * {
+ * if ( !openPassDlg(info) )
+ * ....
+ * }
+ * \endcode
+ *
+ * @param info See AuthInfo.
+ * @return @p true if cached Authorization is found, false otherwise.
+ */
+ bool checkCachedAuthentication( AuthInfo& info );
+
+ /**
+ * Explicitly store authentication information. openPassDlg already
+ * stores password information automatically, you only need to call
+ * this function if you want to store authentication information that
+ * is different from the information returned by openPassDlg.
+ */
+ bool cacheAuthentication( const AuthInfo& info );
+
+ /**
+ * @obsolete as of 3.1.
+ * TODO: Remove before KDE 4.0
+ */
+ bool pingCacheDaemon() const;
+
+ /**
+ * @obsolete as of 3.1. Use openPassDlg instead.
+ * TODO: Remove before KDE 4.0
+ * Creates a basic key to be used to cache the password.
+ * @param url the url from which the key is supposed to be generated
+ */
+ TQString createAuthCacheKey( const KURL& url );
+
+ /**
+ * @obsolete as of 3.1. Use openPassDlg instead.
+ * TODO: Remove before KDE 4.0
+ *
+ * Cache authentication information is now stored automatically
+ * by openPassDlg.
+ */
+ void sendAuthenticationKey( const TQCString& gKey, const TQCString& key, bool keep );
+
+ /**
+ * @obsolete as of 3.1. Use openPassDlg instead.
+ * TODO: Remove before KDE 4.0
+ *
+ * Cached authentication information is now session based and
+ * removed automatically when a given session ends, i.e. the
+ * application is closed.
+ */
+ void delCachedAuthentication( const TQString& key );
+
+ /**
+ * @obsolete as of 3.1. Use openPassDlg instead.
+ * TODO: Remove before KDE 4.0
+ */
+ void setMultipleAuthCaching( bool ) {};
+
+ /**
+ * @obsolete as of 3.1. Use openPassDlg instead.
+ * TODO: Remove before KDE 4.0
+ */
+ bool multipleAuthCaching() const { return false; }
+
+ /**
+ * Used by the slave to check if it can connect
+ * to a given host. This should be called where the slave is ready
+ * to do a ::connect() on a socket. For each call to
+ * requestNetwork must exist a matching call to
+ * dropNetwork, or the system will stay online until
+ * KNetMgr gets closed (or the SlaveBase gets destructed)!
+ *
+ * If KNetMgr is not running, then this is a no-op and returns true
+ *
+ * @param host tells the netmgr the host the slave wants to connect
+ * to. As this could also be a proxy, we can't just take
+ * the host currenctly connected to (but that's the default
+ * value)
+ *
+ * @return true in theorie, the host is reachable
+ * false the system is offline and the host is in a remote network.
+ */
+ bool requestNetwork(const TQString& host = TQString::null);
+
+ /**
+ * Used by the slave to withdraw a connection requested by
+ * requestNetwork. This function cancels the last call to
+ * requestNetwork. If a client uses more than one internet
+ * connection, it must use dropNetwork(host) to
+ * stop each request.
+ *
+ * If KNetMgr is not running, then this is a no-op.
+ *
+ * @param host the host passed to requestNetwork
+ *
+ * A slave should call this function every time it disconnect from a host.
+ * */
+ void dropNetwork(const TQString& host = TQString::null);
+
+ /**
+ * Return the dcop client used by this slave.
+ * @since 3.1
+ */
+ DCOPClient *dcopClient();
+
+ /**
+ * Wait for an answer to our request, until we get @p expected1 or @p expected2
+ * @return the result from readData, as well as the cmd in *pCmd if set, and the data in @p data
+ */
+ int waitForAnswer( int expected1, int expected2, TQByteArray & data, int * pCmd = 0 );
+
+ /**
+ * Internal function to transmit meta data to the application.
+ */
+ void sendMetaData();
+
+ /**
+ * Name of the protocol supported by this slave
+ */
+ TQCString mProtocol;
+
+ Connection * m_pConnection;
+
+ MetaData mOutgoingMetaData;
+ MetaData mIncomingMetaData;
+
+ /** If your ioslave was killed by a signal, wasKilled() returns true.
+ Check it regularly in lengthy functions (e.g. in get();) and return
+ as fast as possible from this function if wasKilled() returns true.
+ This will ensure that your slave destructor will be called correctly.
+ @since 3.1
+ */
+ bool wasKilled() const;
+
+ /** Internally used.
+ * @internal
+ * @since 3.1
+ */
+ void setKillFlag();
+
+protected:
+ UDSEntryList pendingListEntries;
+ uint listEntryCurrentSize;
+ long listEntry_sec, listEntry_usec;
+ Connection *appconn;
+ TQString mPoolSocket;
+ TQString mAppSocket;
+ bool mConnectedToApp;
+ static long s_seqNr;
+ virtual void virtual_hook( int id, void* data );
+
+private:
+ SlaveBasePrivate *d;
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/slaveconfig.cpp b/tdeio/tdeio/slaveconfig.cpp
new file mode 100644
index 000000000..e81146e76
--- /dev/null
+++ b/tdeio/tdeio/slaveconfig.cpp
@@ -0,0 +1,225 @@
+// -*- c++ -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+ *
+ * $Id$
+ *
+ * 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 <assert.h>
+
+#include <tqdict.h>
+
+#include <tdeconfig.h>
+#include <kstaticdeleter.h>
+#include <kprotocolinfo.h>
+#include <kprotocolmanager.h>
+
+#include "slaveconfig.h"
+
+using namespace TDEIO;
+
+namespace TDEIO {
+
+class SlaveConfigProtocol
+{
+public:
+ SlaveConfigProtocol() { host.setAutoDelete(true); }
+ ~SlaveConfigProtocol()
+ {
+ delete configFile;
+ }
+
+public:
+ MetaData global;
+ TQDict<MetaData> host;
+ TDEConfig *configFile;
+};
+
+static void readConfig(TDEConfig *config, const TQString & group, MetaData *metaData)
+{
+ *metaData += config->entryMap(group);
+}
+
+class SlaveConfigPrivate
+{
+ public:
+ void readGlobalConfig();
+ SlaveConfigProtocol *readProtocolConfig(const TQString &_protocol);
+ SlaveConfigProtocol *findProtocolConfig(const TQString &_protocol);
+ void readConfigProtocolHost(const TQString &_protocol, SlaveConfigProtocol *scp, const TQString &host);
+ public:
+ MetaData global;
+ TQDict<SlaveConfigProtocol> protocol;
+};
+
+void SlaveConfigPrivate::readGlobalConfig()
+{
+ global.clear();
+ // Read stuff...
+ TDEConfig *config = KProtocolManager::config();
+ readConfig(TDEGlobal::config(), "Socks", &global); // Socks settings.
+ if ( config )
+ readConfig(config, "<default>", &global);
+}
+
+SlaveConfigProtocol* SlaveConfigPrivate::readProtocolConfig(const TQString &_protocol)
+{
+ SlaveConfigProtocol *scp = protocol.find(_protocol);
+ if (!scp)
+ {
+ TQString filename = KProtocolInfo::config(_protocol);
+ scp = new SlaveConfigProtocol;
+ scp->configFile = new TDEConfig(filename, true, false);
+ protocol.insert(_protocol, scp);
+ }
+ // Read global stuff...
+ readConfig(scp->configFile, "<default>", &(scp->global));
+ return scp;
+}
+
+SlaveConfigProtocol* SlaveConfigPrivate::findProtocolConfig(const TQString &_protocol)
+{
+ SlaveConfigProtocol *scp = protocol.find(_protocol);
+ if (!scp)
+ scp = readProtocolConfig(_protocol);
+ return scp;
+}
+
+void SlaveConfigPrivate::readConfigProtocolHost(const TQString &, SlaveConfigProtocol *scp, const TQString &host)
+{
+ MetaData *metaData = new MetaData;
+ scp->host.replace(host, metaData);
+
+ // Read stuff
+ // Break host into domains
+ TQString domain = host;
+
+ if (!domain.contains('.'))
+ {
+ // Host without domain.
+ if (scp->configFile->hasGroup("<local>"))
+ readConfig(scp->configFile, "<local>", metaData);
+ }
+
+ int pos = 0;
+ do
+ {
+ pos = host.findRev('.', pos-1);
+
+ if (pos < 0)
+ domain = host;
+ else
+ domain = host.mid(pos+1);
+
+ if (scp->configFile->hasGroup(domain))
+ readConfig(scp->configFile, domain.lower(), metaData);
+ }
+ while (pos > 0);
+}
+
+
+SlaveConfig *SlaveConfig::_self = 0;
+static KStaticDeleter<SlaveConfig> slaveconfigsd;
+
+SlaveConfig *SlaveConfig::self()
+{
+ if (!_self)
+ _self = slaveconfigsd.setObject(_self, new SlaveConfig);
+ return _self;
+}
+
+SlaveConfig::SlaveConfig()
+{
+ d = new SlaveConfigPrivate;
+ d->protocol.setAutoDelete(true);
+ d->readGlobalConfig();
+}
+
+SlaveConfig::~SlaveConfig()
+{
+ delete d; d = 0;
+ _self = 0;
+}
+
+void SlaveConfig::setConfigData(const TQString &protocol,
+ const TQString &host,
+ const TQString &key,
+ const TQString &value )
+{
+ MetaData config;
+ config.insert(key, value);
+ setConfigData(protocol, host, config);
+}
+
+void SlaveConfig::setConfigData(const TQString &protocol, const TQString &host, const MetaData &config )
+{
+ if (protocol.isEmpty())
+ d->global += config;
+ else {
+ SlaveConfigProtocol *scp = d->findProtocolConfig(protocol);
+ if (host.isEmpty())
+ {
+ scp->global += config;
+ }
+ else
+ {
+ MetaData *hostConfig = scp->host.find(host);
+ if (!hostConfig)
+ {
+ d->readConfigProtocolHost(protocol, scp, host);
+ hostConfig = scp->host.find(host);
+ assert(hostConfig);
+ }
+ *hostConfig += config;
+ }
+ }
+}
+
+MetaData SlaveConfig::configData(const TQString &protocol, const TQString &host)
+{
+ MetaData config = d->global;
+ SlaveConfigProtocol *scp = d->findProtocolConfig(protocol);
+ config += scp->global;
+ if (host.isEmpty())
+ return config;
+ MetaData *hostConfig = scp->host.find(host);
+ if (!hostConfig)
+ {
+ d->readConfigProtocolHost(protocol, scp, host);
+ emit configNeeded(protocol, host);
+ hostConfig = scp->host.find(host);
+ assert(hostConfig);
+ }
+ config += *hostConfig;
+ return config;
+}
+
+TQString SlaveConfig::configData(const TQString &protocol, const TQString &host, const TQString &key)
+{
+ return configData(protocol, host)[key];
+}
+
+void SlaveConfig::reset()
+{
+ d->protocol.clear();
+ d->readGlobalConfig();
+}
+
+}
+
+#include "slaveconfig.moc"
diff --git a/tdeio/tdeio/slaveconfig.h b/tdeio/tdeio/slaveconfig.h
new file mode 100644
index 000000000..500910062
--- /dev/null
+++ b/tdeio/tdeio/slaveconfig.h
@@ -0,0 +1,106 @@
+// -*- c++ -*-
+/*
+ * This file is part of the KDE libraries
+ * 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 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 KIO_SLAVE_CONFIG_H
+#define KIO_SLAVE_CONFIG_H
+
+#include <tqobject.h>
+#include <tdeio/global.h>
+
+namespace TDEIO {
+
+ class SlaveConfigPrivate;
+ /**
+ * SlaveConfig
+ *
+ * This class manages the configuration for io-slaves based on protocol
+ * and host. The Scheduler makes use of this class to configure the slave
+ * whenever it has to connect to a new host.
+ *
+ * You only need to use this class if you want to override specific
+ * configuration items of an io-slave when the io-slave is used by
+ * your application.
+ *
+ * Normally io-slaves are being configured by "kio_<protocol>rc"
+ * configuration files. Groups defined in such files are treated as host
+ * or domain specification. Configuration items defined in a group are
+ * only applied when the slave is connecting with a host that matches with
+ * the host and/or domain specified by the group.
+ */
+ class TDEIO_EXPORT SlaveConfig : public TQObject
+ {
+ Q_OBJECT
+ public:
+ static SlaveConfig *self();
+ ~SlaveConfig();
+ /**
+ * Configure slaves of type @p protocol by setting @p key to @p value.
+ * If @p host is specified the configuration only applies when dealing
+ * with @p host.
+ *
+ * Changes made to the slave configuration only apply to slaves
+ * used by the current process.
+ */
+ void setConfigData(const TQString &protocol, const TQString &host, const TQString &key, const TQString &value );
+
+ /**
+ * Configure slaves of type @p protocol with @p config.
+ * If @p host is specified the configuration only applies when dealing
+ * with @p host.
+ *
+ * Changes made to the slave configuration only apply to slaves
+ * used by the current process.
+ */
+ void setConfigData(const TQString &protocol, const TQString &host, const MetaData &config );
+
+ /**
+ * Query slave configuration for slaves of type @p protocol when
+ * dealing with @p host.
+ */
+ MetaData configData(const TQString &protocol, const TQString &host);
+
+ /**
+ * Query a specific configuration key for slaves of type @p protocol when
+ * dealing with @p host.
+ */
+ TQString configData(const TQString &protocol, const TQString &host, const TQString &key);
+
+ /**
+ * Undo any changes made by calls to setConfigData.
+ */
+ void reset();
+ signals:
+ /**
+ * This signal is raised when a slave of type @p protocol deals
+ * with @p host for the first time.
+ *
+ * Your application can use this signal to make some last minute
+ * configuration changes with setConfigData based on the
+ * host.
+ */
+ void configNeeded(const TQString &protocol, const TQString &host);
+ protected:
+ SlaveConfig();
+ static SlaveConfig *_self;
+ SlaveConfigPrivate *d;
+ };
+}
+
+#endif
diff --git a/tdeio/tdeio/slaveinterface.cpp b/tdeio/tdeio/slaveinterface.cpp
new file mode 100644
index 000000000..40b66c47a
--- /dev/null
+++ b/tdeio/tdeio/slaveinterface.cpp
@@ -0,0 +1,550 @@
+/* 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.
+*/
+
+#include "tdeio/slaveinterface.h"
+#include "tdeio/slavebase.h"
+#include "tdeio/connection.h"
+#include <errno.h>
+#include <assert.h>
+#include <kdebug.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <signal.h>
+#include <tdeio/observer.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <time.h>
+#include <tqtimer.h>
+
+using namespace TDEIO;
+
+
+TQDataStream &operator <<(TQDataStream &s, const TDEIO::UDSEntry &e )
+{
+ // On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front
+ // of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because
+ // that would break the compatibility of the wire-protocol with KDE 2.
+ // We do the same on 64-bit platforms in case we run in a mixed 32/64bit
+ // environment.
+
+ TQ_UINT32 size = 0;
+ TDEIO::UDSEntry::ConstIterator it = e.begin();
+ for( ; it != e.end(); ++it )
+ {
+ size++;
+ if ((*it).m_uds == TDEIO::UDS_SIZE)
+ size++;
+ }
+ s << size;
+ it = e.begin();
+ for( ; it != e.end(); ++it )
+ {
+ if ((*it).m_uds == TDEIO::UDS_SIZE)
+ {
+ TDEIO::UDSAtom a;
+ a.m_uds = TDEIO::UDS_SIZE_LARGE;
+ a.m_long = (*it).m_long >> 32;
+ s << a;
+ }
+ s << *it;
+ }
+ return s;
+}
+
+TQDataStream &operator >>(TQDataStream &s, TDEIO::UDSEntry &e )
+{
+ e.clear();
+ TQ_UINT32 size;
+ s >> size;
+
+ // On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front
+ // of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because
+ // that would break the compatibility of the wire-protocol with KDE 2.
+ // We do the same on 64-bit platforms in case we run in a mixed 32/64bit
+ // environment.
+ TQ_LLONG msb = 0;
+ for(TQ_UINT32 i = 0; i < size; i++)
+ {
+ TDEIO::UDSAtom a;
+ s >> a;
+ if (a.m_uds == TDEIO::UDS_SIZE_LARGE)
+ {
+ msb = a.m_long;
+ }
+ else
+ {
+ if (a.m_uds == TDEIO::UDS_SIZE)
+ {
+ if (a.m_long < 0)
+ a.m_long += (TQ_LLONG) 1 << 32;
+ a.m_long += msb << 32;
+ }
+ e.append(a);
+ msb = 0;
+ }
+ }
+ return s;
+}
+
+static const unsigned int max_nums = 8;
+
+class TDEIO::SlaveInterfacePrivate
+{
+public:
+ SlaveInterfacePrivate() {
+ slave_calcs_speed = false;
+ start_time.tv_sec = 0;
+ start_time.tv_usec = 0;
+ last_time = 0;
+ nums = 0;
+ filesize = 0;
+ offset = 0;
+ }
+ bool slave_calcs_speed;
+ struct timeval start_time;
+ uint nums;
+ long times[max_nums];
+ TDEIO::filesize_t sizes[max_nums];
+ size_t last_time;
+ TDEIO::filesize_t filesize, offset;
+
+ TQTimer speed_timer;
+};
+
+//////////////
+
+SlaveInterface::SlaveInterface( Connection * connection )
+{
+ m_pConnection = connection;
+ m_progressId = 0;
+
+ d = new SlaveInterfacePrivate;
+ connect(&d->speed_timer, TQT_SIGNAL(timeout()), TQT_SLOT(calcSpeed()));
+}
+
+SlaveInterface::~SlaveInterface()
+{
+ // Note: no kdDebug() here (scheduler is deleted very late)
+ m_pConnection = 0; // a bit like the "wasDeleted" of TQObject...
+
+ delete d;
+}
+
+static TDEIO::filesize_t readFilesize_t(TQDataStream &stream)
+{
+ TDEIO::filesize_t result;
+ unsigned long ul;
+ stream >> ul;
+ result = ul;
+ if (stream.atEnd())
+ return result;
+ stream >> ul;
+ result += ((TDEIO::filesize_t)ul) << 32;
+ return result;
+}
+
+
+bool SlaveInterface::dispatch()
+{
+ assert( m_pConnection );
+
+ int cmd;
+ TQByteArray data;
+
+ if (m_pConnection->read( &cmd, data ) == -1)
+ return false;
+
+ return dispatch( cmd, data );
+}
+
+void SlaveInterface::calcSpeed()
+{
+ if (d->slave_calcs_speed) {
+ d->speed_timer.stop();
+ return;
+ }
+
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
+ tv.tv_usec - d->start_time.tv_usec) / 1000;
+ if (diff - d->last_time >= 900) {
+ d->last_time = diff;
+ if (d->nums == max_nums) {
+ // let's hope gcc can optimize that well enough
+ // otherwise I'd try memcpy :)
+ for (unsigned int i = 1; i < max_nums; ++i) {
+ d->times[i-1] = d->times[i];
+ d->sizes[i-1] = d->sizes[i];
+ }
+ d->nums--;
+ }
+ d->times[d->nums] = diff;
+ d->sizes[d->nums++] = d->filesize - d->offset;
+
+ TDEIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
+
+// kdDebug() << "proceeed " << (long)d->filesize << " " << diff << " "
+// << long(d->sizes[d->nums-1] - d->sizes[0]) << " "
+// << d->times[d->nums-1] - d->times[0] << " "
+// << long(lspeed) << " " << double(d->filesize) / diff
+// << " " << convertSize(lspeed) << " "
+// << convertSize(long(double(d->filesize) / diff) * 1000) << " "
+// << endl ;
+
+ if (!lspeed) {
+ d->nums = 1;
+ d->times[0] = diff;
+ d->sizes[0] = d->filesize - d->offset;
+ }
+ emit speed(lspeed);
+ }
+}
+
+bool SlaveInterface::dispatch( int _cmd, const TQByteArray &rawdata )
+{
+ //kdDebug(7007) << "dispatch " << _cmd << endl;
+
+ TQDataStream stream( rawdata, IO_ReadOnly );
+
+ TQString str1;
+ TQ_INT32 i;
+ TQ_INT8 b;
+ TQ_UINT32 ul;
+
+ switch( _cmd ) {
+ case MSG_DATA:
+ emit data( rawdata );
+ break;
+ case MSG_DATA_REQ:
+ emit dataReq();
+ break;
+ case MSG_FINISHED:
+ //kdDebug(7007) << "Finished [this = " << this << "]" << endl;
+ d->offset = 0;
+ d->speed_timer.stop();
+ emit finished();
+ break;
+ case MSG_STAT_ENTRY:
+ {
+ UDSEntry entry;
+ stream >> entry;
+ emit statEntry(entry);
+ }
+ break;
+ case MSG_LIST_ENTRIES:
+ {
+ TQ_UINT32 count;
+ stream >> count;
+
+ UDSEntryList list;
+ UDSEntry entry;
+ for (uint i = 0; i < count; i++) {
+ stream >> entry;
+ list.append(entry);
+ }
+ emit listEntries(list);
+
+ }
+ break;
+ case MSG_RESUME: // From the put job
+ {
+ d->offset = readFilesize_t(stream);
+ emit canResume( d->offset );
+ }
+ break;
+ case MSG_CANRESUME: // From the get job
+ d->filesize = d->offset;
+ emit canResume(0); // the arg doesn't matter
+ break;
+ case MSG_ERROR:
+ stream >> i >> str1;
+ kdDebug(7007) << "error " << i << " " << str1 << endl;
+ emit error( i, str1 );
+ break;
+ case MSG_SLAVE_STATUS:
+ {
+ pid_t pid;
+ TQCString protocol;
+ stream >> pid >> protocol >> str1 >> b;
+ emit slaveStatus(pid, protocol, str1, (b != 0));
+ }
+ break;
+ case MSG_CONNECTED:
+ emit connected();
+ break;
+
+ case INF_TOTAL_SIZE:
+ {
+ TDEIO::filesize_t size = readFilesize_t(stream);
+ gettimeofday(&d->start_time, 0);
+ d->last_time = 0;
+ d->filesize = d->offset;
+ d->sizes[0] = d->filesize - d->offset;
+ d->times[0] = 0;
+ d->nums = 1;
+ d->speed_timer.start(1000);
+ d->slave_calcs_speed = false;
+ emit totalSize( size );
+ }
+ break;
+ case INF_PROCESSED_SIZE:
+ {
+ TDEIO::filesize_t size = readFilesize_t(stream);
+ emit processedSize( size );
+ d->filesize = size;
+ }
+ break;
+ case INF_SPEED:
+ stream >> ul;
+ d->slave_calcs_speed = true;
+ d->speed_timer.stop();
+
+ emit speed( ul );
+ break;
+ case INF_GETTING_FILE:
+ break;
+ case INF_ERROR_PAGE:
+ emit errorPage();
+ break;
+ case INF_REDIRECTION:
+ {
+ KURL url;
+ stream >> url;
+
+ emit redirection( url );
+ }
+ break;
+ case INF_MIME_TYPE:
+ stream >> str1;
+
+ emit mimeType( str1 );
+ if (!m_pConnection->suspended())
+ m_pConnection->sendnow( CMD_NONE, TQByteArray() );
+ break;
+ case INF_WARNING:
+ stream >> str1;
+
+ emit warning( str1 );
+ break;
+ case INF_NEED_PASSWD: {
+ AuthInfo info;
+ stream >> info;
+ openPassDlg( info );
+ break;
+ }
+ case INF_MESSAGEBOX: {
+ kdDebug(7007) << "needs a msg box" << endl;
+ TQString text, caption, buttonYes, buttonNo, dontAskAgainName;
+ int type;
+ stream >> type >> text >> caption >> buttonYes >> buttonNo;
+ if (stream.atEnd())
+ messageBox(type, text, caption, buttonYes, buttonNo);
+ else {
+ stream >> dontAskAgainName;
+ messageBox(type, text, caption, buttonYes, buttonNo, dontAskAgainName);
+ }
+ break;
+ }
+ case INF_INFOMESSAGE: {
+ TQString msg;
+ stream >> msg;
+ infoMessage(msg);
+ break;
+ }
+ case INF_META_DATA: {
+ MetaData meta_data;
+ stream >> meta_data;
+ metaData(meta_data);
+ break;
+ }
+ case INF_LOCALURL: {
+ TQ_INT8 islocal;
+ KURL url;
+ stream >> islocal >> url;
+ emit localURL( url, islocal );
+ break;
+ }
+ case MSG_NET_REQUEST: {
+ TQString host;
+ TQString slaveid;
+ stream >> host >> slaveid;
+ requestNetwork(host, slaveid);
+ break;
+ }
+ case MSG_NET_DROP: {
+ TQString host;
+ TQString slaveid;
+ stream >> host >> slaveid;
+ dropNetwork(host, slaveid);
+ break;
+ }
+ case MSG_NEED_SUBURL_DATA: {
+ emit needSubURLData();
+ break;
+ }
+ case MSG_AUTH_KEY: {
+ bool keep;
+ TQCString key, group;
+ stream >> key >> group >> keep;
+ kdDebug(7007) << "Got auth-key: " << key << endl
+ << " group-key: " << group << endl
+ << " keep password: " << keep << endl;
+ emit authorizationKey( key, group, keep );
+ break;
+ }
+ case MSG_DEL_AUTH_KEY: {
+ TQCString key;
+ stream >> key;
+ kdDebug(7007) << "Delete auth-key: " << key << endl;
+ emit delAuthorization( key );
+ }
+ default:
+ kdWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave" << endl;
+ return false;
+ }
+ return true;
+}
+
+void SlaveInterface::setOffset( TDEIO::filesize_t o)
+{
+ d->offset = o;
+}
+
+TDEIO::filesize_t SlaveInterface::offset() const { return d->offset; }
+
+void SlaveInterface::requestNetwork(const TQString &host, const TQString &slaveid)
+{
+ kdDebug(7007) << "requestNetwork " << host << slaveid << endl;
+ TQByteArray packedArgs;
+ TQDataStream stream( packedArgs, IO_WriteOnly );
+ stream << true;
+ m_pConnection->sendnow( INF_NETWORK_STATUS, packedArgs );
+}
+
+void SlaveInterface::dropNetwork(const TQString &host, const TQString &slaveid)
+{
+ kdDebug(7007) << "dropNetwork " << host << slaveid << endl;
+}
+
+void SlaveInterface::sendResumeAnswer( bool resume )
+{
+ kdDebug(7007) << "SlaveInterface::sendResumeAnswer ok for resuming :" << resume << endl;
+ m_pConnection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, TQByteArray() );
+}
+
+void SlaveInterface::openPassDlg( const TQString& prompt, const TQString& user, bool readOnly )
+{
+ AuthInfo info;
+ info.prompt = prompt;
+ info.username = user;
+ info.readOnly = readOnly;
+ openPassDlg( info );
+}
+
+void SlaveInterface::openPassDlg( const TQString& prompt, const TQString& user,
+ const TQString& caption, const TQString& comment,
+ const TQString& label, bool readOnly )
+{
+ AuthInfo info;
+ info.prompt = prompt;
+ info.username = user;
+ info.caption = caption;
+ info.comment = comment;
+ info.commentLabel = label;
+ info.readOnly = readOnly;
+ openPassDlg( info );
+}
+
+void SlaveInterface::openPassDlg( AuthInfo& info )
+{
+ kdDebug(7007) << "SlaveInterface::openPassDlg: "
+ << "User= " << info.username
+ << ", Message= " << info.prompt << endl;
+ bool result = Observer::self()->openPassDlg( info );
+ if ( m_pConnection )
+ {
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly );
+ if ( result )
+ {
+ stream << info;
+ kdDebug(7007) << "SlaveInterface:::openPassDlg got: "
+ << "User= " << info.username
+ << ", Password= [hidden]" << endl;
+ m_pConnection->sendnow( CMD_USERPASS, data );
+ }
+ else
+ m_pConnection->sendnow( CMD_NONE, data );
+ }
+}
+
+void SlaveInterface::messageBox( int type, const TQString &text, const TQString &_caption,
+ const TQString &buttonYes, const TQString &buttonNo )
+{
+ messageBox( type, text, _caption, buttonYes, buttonNo, TQString::null );
+}
+
+void SlaveInterface::messageBox( int type, const TQString &text, const TQString &_caption,
+ const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName )
+{
+ kdDebug(7007) << "messageBox " << type << " " << text << " - " << _caption << " " << dontAskAgainName << endl;
+ TQByteArray packedArgs;
+ TQDataStream stream( packedArgs, IO_WriteOnly );
+
+ TQString caption( _caption );
+ if ( type == TDEIO::SlaveBase::SSLMessageBox )
+ caption = TQString::fromUtf8(kapp->dcopClient()->appId()); // hack, see observer.cpp
+
+ emit needProgressId();
+ kdDebug(7007) << "SlaveInterface::messageBox m_progressId=" << m_progressId << endl;
+ TQGuardedPtr<SlaveInterface> me = this;
+ m_pConnection->suspend();
+ int result = Observer::/*self()->*/messageBox( m_progressId, type, text, caption, buttonYes, buttonNo, dontAskAgainName );
+ if ( me && m_pConnection ) // Don't do anything if deleted meanwhile
+ {
+ m_pConnection->resume();
+ kdDebug(7007) << this << " SlaveInterface result=" << result << endl;
+ stream << result;
+ m_pConnection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs );
+ }
+}
+
+// No longer used.
+// Remove in KDE 4.0
+void SlaveInterface::sigpipe_handler(int)
+{
+ int saved_errno = errno;
+ // Using kdDebug from a signal handler is not a good idea.
+#ifndef NDEBUG
+ char msg[1000];
+ sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
+ write(2, msg, strlen(msg));
+#endif
+
+ // Do nothing.
+ // dispatch will return false and that will trigger ERR_SLAVE_DIED in slave.cpp
+ errno = saved_errno;
+}
+
+void SlaveInterface::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "slaveinterface.moc"
diff --git a/tdeio/tdeio/slaveinterface.h b/tdeio/tdeio/slaveinterface.h
new file mode 100644
index 000000000..a8992ee65
--- /dev/null
+++ b/tdeio/tdeio/slaveinterface.h
@@ -0,0 +1,290 @@
+/* This file is part of the KDE project
+ 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 __kio_slaveinterface_h
+#define __kio_slaveinterface_h
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <tqobject.h>
+
+#include <kurl.h>
+#include <tdeio/global.h>
+#include <tdeio/authinfo.h>
+#include <kdatastream.h>
+
+namespace TDEIO {
+
+class Connection;
+// better there is one ...
+class SlaveInterfacePrivate;
+
+ // Definition of enum Command has been moved to global.h
+
+ /**
+ * Identifiers for KIO informational messages.
+ */
+ enum Info {
+ INF_TOTAL_SIZE = 10,
+ INF_PROCESSED_SIZE = 11,
+ INF_SPEED,
+ INF_REDIRECTION = 20,
+ INF_MIME_TYPE = 21,
+ INF_ERROR_PAGE = 22,
+ INF_WARNING = 23,
+ INF_GETTING_FILE, // Deprecated
+ INF_NEED_PASSWD = 25,
+ INF_INFOMESSAGE,
+ INF_META_DATA,
+ INF_NETWORK_STATUS,
+ INF_MESSAGEBOX,
+ INF_LOCALURL
+ // add new ones here once a release is done, to avoid breaking binary compatibility
+ };
+
+ /**
+ * Identifiers for KIO data messages.
+ */
+ enum Message {
+ MSG_DATA = 100,
+ MSG_DATA_REQ,
+ MSG_ERROR,
+ MSG_CONNECTED,
+ MSG_FINISHED,
+ MSG_STAT_ENTRY,
+ MSG_LIST_ENTRIES,
+ MSG_RENAMED, // unused
+ MSG_RESUME,
+ MSG_SLAVE_STATUS,
+ MSG_SLAVE_ACK,
+ MSG_NET_REQUEST,
+ MSG_NET_DROP,
+ MSG_NEED_SUBURL_DATA,
+ MSG_CANRESUME,
+ MSG_AUTH_KEY, // deprecated.
+ MSG_DEL_AUTH_KEY // deprecated.
+ // add new ones here once a release is done, to avoid breaking binary compatibility
+ };
+
+/**
+ * There are two classes that specifies the protocol between application
+ * (TDEIO::Job) and tdeioslave. SlaveInterface is the class to use on the application
+ * end, SlaveBase is the one to use on the slave end.
+ *
+ * A call to foo() results in a call to slotFoo() on the other end.
+ */
+class TDEIO_EXPORT SlaveInterface : public TQObject
+{
+ Q_OBJECT
+
+public:
+ SlaveInterface( Connection *connection );
+ virtual ~SlaveInterface();
+
+ void setConnection( Connection* connection ) { m_pConnection = connection; }
+ Connection *connection() const { return m_pConnection; }
+
+ void setProgressId( int id ) { m_progressId = id; }
+ int progressId() const { return m_progressId; }
+
+ /** Send our answer to the MSG_RESUME (canResume) request
+ * (to tell the "put" job whether to resume or not)
+ */
+ void sendResumeAnswer( bool resume );
+
+ void setOffset( TDEIO::filesize_t offset );
+ TDEIO::filesize_t offset() const;
+
+signals:
+ ///////////
+ // Messages sent by the slave
+ ///////////
+
+ void data( const TQByteArray & );
+ void dataReq( );
+ void error( int , const TQString & );
+ void connected();
+ void finished();
+ void slaveStatus(pid_t, const TQCString &, const TQString &, bool);
+ void listEntries( const TDEIO::UDSEntryList& );
+ void statEntry( const TDEIO::UDSEntry& );
+ void needSubURLData();
+ void needProgressId();
+
+ void canResume( TDEIO::filesize_t ) ;
+
+ ///////////
+ // Info sent by the slave
+ //////////
+ void metaData( const TDEIO::MetaData & );
+ void totalSize( TDEIO::filesize_t ) ;
+ void processedSize( TDEIO::filesize_t ) ;
+ void redirection( const KURL& ) ;
+ void localURL( const KURL&, bool ) ;
+
+ void speed( unsigned long ) ;
+ void errorPage() ;
+ void mimeType( const TQString & ) ;
+ void warning( const TQString & ) ;
+ void infoMessage( const TQString & ) ;
+ void connectFinished();
+
+ /**
+ * @deprecated. Obsolete as of 3.1. Replaced by kpassword, a kded module.
+ */
+ void authorizationKey( const TQCString&, const TQCString&, bool );
+
+ /**
+ * @deprecated. Obsolete as of 3.1. Replaced by kpassword, a kded module.
+ */
+ void delAuthorization( const TQCString& grpkey );
+
+protected:
+ /////////////////
+ // Dispatching
+ ////////////////
+
+ virtual bool dispatch();
+ virtual bool dispatch( int _cmd, const TQByteArray &data );
+
+ /**
+ * Prompt the user for authrization info (login & password).
+ *
+ * Use this function to request authorization info from the
+ * the end user. For example to open an empty password dialog
+ * using default values:
+ *
+ * \code
+ * TDEIO::AuthInfo authInfo;
+ * bool result = openPassDlg( authInfo );
+ * if ( result )
+ * {
+ * printf( "Username: %s", result.username.latin1() );
+ * printf( "Username: %s", result.username.latin1() );
+ * }
+ * \endcode
+ *
+ * You can also pre-set some values like the username before hand
+ * if it is known as well as the comment and caption to be displayed:
+ *
+ * \code
+ * authInfo.comment= "Enter username and password to access acmeone";
+ * authInfo.caption= "Acme Password Dialog";
+ * authInfo.username= "Wily E. kaiody";
+ * bool result = openPassDlg( authInfo );
+ * if ( result )
+ * {
+ * printf( "Username: %s", result.username.latin1() );
+ * printf( "Username: %s", result.username.latin1() );
+ * }
+ * \endcode
+ *
+ * NOTE: A call to this function can also fail and result
+ * in a return value of @p false, if the UIServer could not
+ * be started for whatever reason.
+ *
+ * @param info See AuthInfo.
+ * @return true if user clicks on "OK", false otherwsie.
+ */
+ void openPassDlg( TDEIO::AuthInfo& info );
+
+ /**
+ * @deprecated. Use openPassDlg( AuthInfo& ) instead.
+ */
+ void openPassDlg( const TQString& prompt, const TQString& user,
+ const TQString& caption, const TQString& comment,
+ const TQString& label, bool readOnly ) KDE_DEPRECATED;
+
+ /**
+ * @deprecated. Use openPassDlg( AuthInfo& ) instead.
+ */
+ void openPassDlg( const TQString& prompt, const TQString& user, bool readOnly ) KDE_DEPRECATED;
+
+ void messageBox( int type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo );
+
+ /**
+ * @since 3.3
+ */
+ void messageBox( int type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName );
+
+ // I need to identify the slaves
+ void requestNetwork( const TQString &, const TQString &);
+ void dropNetwork( const TQString &, const TQString &);
+
+ /**
+ * @internal
+ * KDE 4.0: Remove
+ */
+ static void sigpipe_handler(int);
+
+protected slots:
+ void calcSpeed();
+
+protected:
+ Connection * m_pConnection;
+
+private:
+ int m_progressId;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ SlaveInterfacePrivate *d;
+};
+
+}
+
+inline TQDataStream &operator >>(TQDataStream &s, TDEIO::UDSAtom &a )
+{
+ TQ_INT32 l;
+ s >> a.m_uds;
+
+ if ( a.m_uds & TDEIO::UDS_LONG ) {
+ s >> l;
+ a.m_long = l;
+ a.m_str = TQString::null;
+ } else if ( a.m_uds & TDEIO::UDS_STRING ) {
+ s >> a.m_str;
+ a.m_long = 0;
+ } else {} // DIE!
+ // assert( 0 );
+
+ return s;
+}
+
+inline TQDataStream &operator <<(TQDataStream &s, const TDEIO::UDSAtom &a )
+{
+ s << a.m_uds;
+
+ if ( a.m_uds & TDEIO::UDS_LONG )
+ s << (TQ_INT32) a.m_long;
+ else if ( a.m_uds & TDEIO::UDS_STRING )
+ s << a.m_str;
+ else {} // DIE!
+ // assert( 0 );
+
+ return s;
+}
+
+TDEIO_EXPORT TQDataStream &operator <<(TQDataStream &s, const TDEIO::UDSEntry &e );
+TDEIO_EXPORT TQDataStream &operator >>(TQDataStream &s, TDEIO::UDSEntry &e );
+
+#endif
diff --git a/tdeio/tdeio/statusbarprogress.cpp b/tdeio/tdeio/statusbarprogress.cpp
new file mode 100644
index 000000000..66517ca03
--- /dev/null
+++ b/tdeio/tdeio/statusbarprogress.cpp
@@ -0,0 +1,166 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 <tqtooltip.h>
+#include <tqlayout.h>
+#include <tqwidgetstack.h>
+#include <tqpushbutton.h>
+#include <tqlabel.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kprogress.h>
+
+#include "jobclasses.h"
+#include "statusbarprogress.h"
+
+namespace TDEIO {
+
+StatusbarProgress::StatusbarProgress( TQWidget* parent, bool button )
+ : ProgressBase( parent ) {
+
+ m_bShowButton = button;
+
+ // only clean this dialog
+ setOnlyClean(true);
+ // TODO : is this really needed ?
+ setStopOnClose(false);
+
+ int w = fontMetrics().width( " 999.9 kB/s 00:00:01 " ) + 8;
+ box = new TQHBoxLayout( this, 0, 0 );
+
+ m_pButton = new TQPushButton( "X", this );
+ box->addWidget( m_pButton );
+ stack = new TQWidgetStack( this );
+ box->addWidget( stack );
+ connect( m_pButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotStop() ) );
+
+ m_pProgressBar = new KProgress( this );
+ m_pProgressBar->setFrameStyle( TQFrame::Box | TQFrame::Raised );
+ m_pProgressBar->setLineWidth( 1 );
+ m_pProgressBar->setBackgroundMode( TQWidget::PaletteBackground );
+ m_pProgressBar->installEventFilter( this );
+ m_pProgressBar->setMinimumWidth( w );
+ stack->addWidget( m_pProgressBar, 1 );
+
+ m_pLabel = new TQLabel( "", this );
+ m_pLabel->setAlignment( AlignHCenter | AlignVCenter );
+ m_pLabel->installEventFilter( this );
+ m_pLabel->setMinimumWidth( w );
+ stack->addWidget( m_pLabel, 2 );
+ setMinimumSize( sizeHint() );
+
+ mode = None;
+ setMode();
+}
+
+
+void StatusbarProgress::setJob( TDEIO::Job *job )
+{
+ ProgressBase::setJob( job );
+
+ mode = Progress;
+ setMode();
+}
+
+
+void StatusbarProgress::setMode() {
+ switch ( mode ) {
+ case None:
+ if ( m_bShowButton ) {
+ m_pButton->hide();
+ }
+ stack->hide();
+ break;
+
+ case Label:
+ if ( m_bShowButton ) {
+ m_pButton->show();
+ }
+ stack->show();
+ stack->raiseWidget( m_pLabel );
+ break;
+
+ case Progress:
+ if ( m_bShowButton ) {
+ m_pButton->show();
+ }
+ stack->show();
+ stack->raiseWidget( m_pProgressBar );
+ break;
+ }
+}
+
+
+void StatusbarProgress::slotClean() {
+ // we don't want to delete this widget, only clean
+ m_pProgressBar->setValue( 0 );
+ m_pLabel->clear();
+
+ mode = None;
+ setMode();
+}
+
+
+void StatusbarProgress::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size ) {
+ m_iTotalSize = size; // size is measured in bytes
+}
+
+void StatusbarProgress::slotPercent( TDEIO::Job*, unsigned long percent ) {
+ m_pProgressBar->setValue( percent );
+}
+
+
+void StatusbarProgress::slotSpeed( TDEIO::Job*, unsigned long speed ) {
+ if ( speed == 0 ) { // spped is measured in bytes-per-second
+ m_pLabel->setText( i18n( " Stalled ") );
+ } else {
+ m_pLabel->setText( i18n( " %1/s ").arg( TDEIO::convertSize( speed )) );
+ }
+}
+
+
+bool StatusbarProgress::eventFilter( TQObject *, TQEvent *ev ) {
+ if ( ! m_pJob ) { // don't react when there isn't any job doing IO
+ return true;
+ }
+
+ if ( ev->type() == TQEvent::MouseButtonPress ) {
+ TQMouseEvent *e = (TQMouseEvent*)ev;
+
+ if ( e->button() == Qt::LeftButton ) { // toggle view on left mouse button
+ if ( mode == Label ) {
+ mode = Progress;
+ } else if ( mode == Progress ) {
+ mode = Label;
+ }
+ setMode();
+ return true;
+
+ }
+ }
+
+ return false;
+}
+
+void StatusbarProgress::virtual_hook( int id, void* data )
+{ ProgressBase::virtual_hook( id, data ); }
+
+} /* namespace */
+#include "statusbarprogress.moc"
diff --git a/tdeio/tdeio/statusbarprogress.h b/tdeio/tdeio/statusbarprogress.h
new file mode 100644
index 000000000..d1d591fbe
--- /dev/null
+++ b/tdeio/tdeio/statusbarprogress.h
@@ -0,0 +1,112 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Matej Koss <koss@miesto.sk>
+
+ 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 __statusbarprogress_h__
+#define __statusbarprogress_h__
+
+#include "progressbase.h"
+
+class TQWidgetStack;
+class TQBoxLayout;
+class TQPushButton;
+class TQLabel;
+class KProgress;
+
+namespace TDEIO {
+
+class Job;
+
+/**
+* This is a special IO progress widget.
+*
+* Similarly to DefaultProgress,
+* it's purpose is to show a progress of the IO operation.
+*
+* Instead of creating a separate window, this is only a widget that can be
+* easily embedded in a statusbar.
+*
+* Usage of StatusbarProgress is little different.
+* This dialog will be a part of some application.
+* \code
+* // create a dialog
+* StatusbarProgress *statusProgress;
+* statusProgress = new StatusbarProgress( statusBar() );
+* statusBar()->insertWidget( statusProgress, statusProgress->width() , 0 );
+* ...
+* // create job and connect it to the progress
+* CopyJob* job = TDEIO::copy(...);
+* statusProgress->setJob( job );
+* ...
+* \endcode
+*
+* @short IO progress widget for embedding in a statusbar.
+* @author Matej Koss <koss@miesto.sk>
+*/
+class TDEIO_EXPORT StatusbarProgress : public ProgressBase {
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * Creates a new StatusbarProgress.
+ * @param parent the parent of this widget
+ * @param button true to add an abort button. The button will be
+ * connected to ProgressBase::slotStop()
+ */
+ StatusbarProgress( TQWidget* parent, bool button = true );
+ ~StatusbarProgress() {}
+
+ /**
+ * Sets the job to monitor.
+ * @param job the job to monitor
+ */
+ void setJob( TDEIO::Job *job );
+
+public slots:
+ virtual void slotClean();
+ virtual void slotTotalSize( TDEIO::Job* job, TDEIO::filesize_t size );
+ virtual void slotPercent( TDEIO::Job* job, unsigned long percent );
+ virtual void slotSpeed( TDEIO::Job* job, unsigned long speed );
+
+protected:
+ KProgress* m_pProgressBar;
+ TQLabel* m_pLabel;
+ TQPushButton* m_pButton;
+
+ TDEIO::filesize_t m_iTotalSize;
+
+ enum Mode { None, Label, Progress };
+
+ uint mode;
+ bool m_bShowButton;
+
+ void setMode();
+
+ virtual bool eventFilter( TQObject *, TQEvent * );
+ TQBoxLayout *box;
+ TQWidgetStack *stack;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class StatusbarProgressPrivate* d;
+};
+
+} /* namespace */
+
+#endif // __statusbarprogress_h__
diff --git a/tdeio/tdeio/tcpslavebase.cpp b/tdeio/tdeio/tcpslavebase.cpp
new file mode 100644
index 000000000..2b7df9d7b
--- /dev/null
+++ b/tdeio/tdeio/tcpslavebase.cpp
@@ -0,0 +1,1343 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net
+ * Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
+ * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
+ *
+ * This file is part of the KDE project
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <ksocks.h>
+#include <kdebug.h>
+#include <ksslall.h>
+#include <ksslcertdlg.h>
+#include <kmessagebox.h>
+#ifndef Q_WS_WIN //temporary
+#include <kresolver.h>
+#endif
+
+#include <klocale.h>
+#include <dcopclient.h>
+#include <tqcstring.h>
+#include <tqdatastream.h>
+
+#include <kapplication.h>
+
+#include <kprotocolmanager.h>
+#include <kde_file.h>
+
+#include "tdeio/tcpslavebase.h"
+
+using namespace TDEIO;
+
+class TCPSlaveBase::TcpSlaveBasePrivate
+{
+public:
+
+ TcpSlaveBasePrivate() : rblockSz(256), militantSSL(false), userAborted(false) {}
+ ~TcpSlaveBasePrivate() {}
+
+ KSSL *kssl;
+ bool usingTLS;
+ KSSLCertificateCache *cc;
+ TQString host;
+ TQString realHost;
+ TQString ip;
+ DCOPClient *dcc;
+ KSSLPKCS12 *pkcs;
+
+ int status;
+ int timeout;
+ int rblockSz; // Size for reading blocks in readLine()
+ bool block;
+ bool useSSLTunneling;
+ bool needSSLHandShake;
+ bool militantSSL; // If true, we just drop a connection silently
+ // if SSL certificate check fails in any way.
+ bool userAborted;
+ MetaData savedMetaData;
+};
+
+
+TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,
+ const TQCString &protocol,
+ const TQCString &poolSocket,
+ const TQCString &appSocket)
+ :SlaveBase (protocol, poolSocket, appSocket),
+ m_iSock(-1),
+ m_iDefaultPort(defaultPort),
+ m_sServiceName(protocol),
+ fp(0)
+{
+ // We have to have two constructors, so don't add anything
+ // else in here. Put it in doConstructorStuff() instead.
+ doConstructorStuff();
+ m_bIsSSL = false;
+}
+
+TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,
+ const TQCString &protocol,
+ const TQCString &poolSocket,
+ const TQCString &appSocket,
+ bool useSSL)
+ :SlaveBase (protocol, poolSocket, appSocket),
+ m_iSock(-1),
+ m_bIsSSL(useSSL),
+ m_iDefaultPort(defaultPort),
+ m_sServiceName(protocol),
+ fp(0)
+{
+ doConstructorStuff();
+ if (useSSL)
+ m_bIsSSL = initializeSSL();
+}
+
+// The constructor procedures go here now.
+void TCPSlaveBase::doConstructorStuff()
+{
+ d = new TcpSlaveBasePrivate;
+ d->kssl = 0L;
+ d->ip = "";
+ d->cc = 0L;
+ d->usingTLS = false;
+ d->dcc = 0L;
+ d->pkcs = 0L;
+ d->status = -1;
+ d->timeout = KProtocolManager::connectTimeout();
+ d->block = false;
+ d->useSSLTunneling = false;
+}
+
+TCPSlaveBase::~TCPSlaveBase()
+{
+ cleanSSL();
+ if (d->usingTLS) delete d->kssl;
+ if (d->dcc) delete d->dcc;
+ if (d->pkcs) delete d->pkcs;
+ delete d;
+}
+
+ssize_t TCPSlaveBase::write(const void *data, ssize_t len)
+{
+#ifdef Q_OS_UNIX
+ if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
+ {
+ if ( d->needSSLHandShake )
+ (void) doSSLHandShake( true );
+ return d->kssl->write(data, len);
+ }
+ return KSocks::self()->write(m_iSock, data, len);
+#else
+ return 0;
+#endif
+}
+
+ssize_t TCPSlaveBase::read(void *data, ssize_t len)
+{
+#ifdef Q_OS_UNIX
+ if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
+ {
+ if ( d->needSSLHandShake )
+ (void) doSSLHandShake( true );
+ return d->kssl->read(data, len);
+ }
+ return KSocks::self()->read(m_iSock, data, len);
+#else
+ return 0;
+#endif
+}
+
+
+void TCPSlaveBase::setBlockSize(int sz)
+{
+ if (sz <= 0)
+ sz = 1;
+
+ d->rblockSz = sz;
+}
+
+
+ssize_t TCPSlaveBase::readLine(char *data, ssize_t len)
+{
+// Optimization:
+// It's small, but it probably results in a gain on very high
+// speed connections. I moved 3 if statements out of the while loop
+// so that the while loop is as small as possible. (GS)
+
+ // let's not segfault!
+ if (!data)
+ return -1;
+
+ char tmpbuf[1024]; // 1kb temporary buffer for peeking
+ *data = 0;
+ ssize_t clen = 0;
+ char *buf = data;
+ int rc = 0;
+
+if ((m_bIsSSL || d->usingTLS) && !d->useSSLTunneling) { // SSL CASE
+ if ( d->needSSLHandShake )
+ (void) doSSLHandShake( true );
+
+ while (clen < len-1) {
+ rc = d->kssl->pending();
+ if (rc > 0) { // Read a chunk
+ int bytes = rc;
+ if (bytes > d->rblockSz)
+ bytes = d->rblockSz;
+
+ rc = d->kssl->peek(tmpbuf, bytes);
+ if (rc <= 0) {
+ // FIXME: this doesn't cover rc == 0 case
+ return -1;
+ }
+
+ bytes = rc; // in case it contains no \n
+ for (int i = 0; i < rc; i++) {
+ if (tmpbuf[i] == '\n') {
+ bytes = i+1;
+ break;
+ }
+ }
+
+ if (bytes+clen >= len) // don't read too much!
+ bytes = len - clen - 1;
+
+ rc = d->kssl->read(buf, bytes);
+ if (rc > 0) {
+ clen += rc;
+ buf += (rc-1);
+ if (*buf++ == '\n')
+ break;
+ } else {
+ // FIXME: different case if rc == 0;
+ return -1;
+ }
+ } else { // Read a byte
+ rc = d->kssl->read(buf, 1);
+ if (rc <= 0) {
+ return -1;
+ // hm rc = 0 then
+ // SSL_read says to call SSL_get_error to see if
+ // this was an error. FIXME
+ } else {
+ clen++;
+ if (*buf++ == '\n')
+ break;
+ }
+ }
+ }
+} else { // NON SSL CASE
+ while (clen < len-1) {
+#ifdef Q_OS_UNIX
+ rc = KSocks::self()->read(m_iSock, buf, 1);
+#else
+ rc = 0;
+#endif
+ if (rc <= 0) {
+ // FIXME: this doesn't cover rc == 0 case
+ return -1;
+ } else {
+ clen++;
+ if (*buf++ == '\n')
+ break;
+ }
+ }
+}
+
+ // Both cases fall through to here
+ *buf = 0;
+return clen;
+}
+
+unsigned short int TCPSlaveBase::port(unsigned short int _p)
+{
+ unsigned short int p = _p;
+
+ if (_p <= 0)
+ {
+ p = m_iDefaultPort;
+ }
+
+ return p;
+}
+
+// This function is simply a wrapper to establish the connection
+// to the server. It's a bit more complicated than ::connect
+// because we first have to check to see if the user specified
+// a port, and if so use it, otherwise we check to see if there
+// is a port specified in /etc/services, and if so use that
+// otherwise as a last resort use the supplied default port.
+bool TCPSlaveBase::connectToHost( const TQString &host,
+ unsigned int _port,
+ bool sendError )
+{
+#ifdef Q_OS_UNIX
+ unsigned short int p;
+ KExtendedSocket ks;
+
+ d->userAborted = false;
+
+ // - leaving SSL - warn before we even connect
+ if (metaData("main_frame_request") == "TRUE" &&
+ metaData("ssl_activate_warnings") == "TRUE" &&
+ metaData("ssl_was_in_use") == "TRUE" &&
+ !m_bIsSSL) {
+ KSSLSettings kss;
+ if (kss.warnOnLeave()) {
+ int result = messageBox( i18n("You are about to leave secure "
+ "mode. Transmissions will no "
+ "longer be encrypted.\nThis "
+ "means that a third party could "
+ "observe your data in transit."),
+ WarningContinueCancel,
+ i18n("Security Information"),
+ i18n("C&ontinue Loading"), TQString::null,
+ "WarnOnLeaveSSLMode" );
+
+ // Move this setting into KSSL instead
+ TDEConfig *config = new TDEConfig("tdeioslaverc");
+ config->setGroup("Notification Messages");
+
+ if (!config->readBoolEntry("WarnOnLeaveSSLMode", true)) {
+ config->deleteEntry("WarnOnLeaveSSLMode");
+ config->sync();
+ kss.setWarnOnLeave(false);
+ kss.save();
+ }
+ delete config;
+
+ if ( result == KMessageBox::Cancel ) {
+ d->userAborted = true;
+ return false;
+ }
+ }
+ }
+
+ d->status = -1;
+ d->host = host;
+ d->needSSLHandShake = m_bIsSSL;
+ p = port(_port);
+ ks.setAddress(host, p);
+ if ( d->timeout > -1 )
+ ks.setTimeout( d->timeout );
+
+ if (ks.connect() < 0)
+ {
+ d->status = ks.status();
+ if ( sendError )
+ {
+ if (d->status == IO_LookupError)
+ error( ERR_UNKNOWN_HOST, host);
+ else if ( d->status != -1 )
+ error( ERR_COULD_NOT_CONNECT, host);
+ }
+ return false;
+ }
+
+ m_iSock = ks.fd();
+
+ // store the IP for later
+ const TDESocketAddress *sa = ks.peerAddress();
+ if (sa)
+ d->ip = sa->nodeName();
+ else
+ d->ip = "";
+
+ ks.release(); // KExtendedSocket no longer applicable
+
+ if ( d->block != ks.blockingMode() )
+ ks.setBlockingMode( d->block );
+
+ m_iPort=p;
+
+ if (m_bIsSSL && !d->useSSLTunneling) {
+ if ( !doSSLHandShake( sendError ) )
+ return false;
+ }
+ else
+ setMetaData("ssl_in_use", "FALSE");
+
+ // Since we want to use stdio on the socket,
+ // we must fdopen it to get a file pointer,
+ // if it fails, close everything up
+ if ((fp = KDE_fdopen(m_iSock, "w+")) == 0) {
+ closeDescriptor();
+ return false;
+ }
+
+ return true;
+#else //!Q_OS_UNIX
+ return false;
+#endif //Q_OS_UNIX
+}
+
+void TCPSlaveBase::closeDescriptor()
+{
+ stopTLS();
+ if (fp) {
+ fclose(fp);
+ fp=0;
+ m_iSock=-1;
+ if (m_bIsSSL)
+ d->kssl->close();
+ }
+ if (m_iSock != -1) {
+ close(m_iSock);
+ m_iSock=-1;
+ }
+ d->ip = "";
+ d->host = "";
+}
+
+bool TCPSlaveBase::initializeSSL()
+{
+ if (m_bIsSSL) {
+ if (KSSL::doesSSLWork()) {
+ d->kssl = new KSSL;
+ return true;
+ }
+ }
+return false;
+}
+
+void TCPSlaveBase::cleanSSL()
+{
+ delete d->cc;
+
+ if (m_bIsSSL) {
+ delete d->kssl;
+ d->kssl = 0;
+ }
+ d->militantSSL = false;
+}
+
+bool TCPSlaveBase::atEnd()
+{
+ return feof(fp);
+}
+
+int TCPSlaveBase::startTLS()
+{
+ if (d->usingTLS || d->useSSLTunneling || m_bIsSSL || !KSSL::doesSSLWork())
+ return false;
+
+ d->kssl = new KSSL(false);
+ if (!d->kssl->TLSInit()) {
+ delete d->kssl;
+ return -1;
+ }
+
+ if ( !d->realHost.isEmpty() )
+ {
+ kdDebug(7029) << "Setting real hostname: " << d->realHost << endl;
+ d->kssl->setPeerHost(d->realHost);
+ } else {
+ kdDebug(7029) << "Setting real hostname: " << d->host << endl;
+ d->kssl->setPeerHost(d->host);
+ }
+
+ if (hasMetaData("ssl_session_id")) {
+ KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
+ if (s) {
+ d->kssl->setSession(s);
+ delete s;
+ }
+ }
+ certificatePrompt();
+
+ int rc = d->kssl->connect(m_iSock);
+ if (rc < 0) {
+ delete d->kssl;
+ return -2;
+ }
+
+ setMetaData("ssl_session_id", d->kssl->session()->toString());
+
+ d->usingTLS = true;
+ setMetaData("ssl_in_use", "TRUE");
+
+ if (!d->kssl->reusingSession()) {
+ rc = verifyCertificate();
+ if (rc != 1) {
+ setMetaData("ssl_in_use", "FALSE");
+ d->usingTLS = false;
+ delete d->kssl;
+ return -3;
+ }
+ }
+
+ d->savedMetaData = mOutgoingMetaData;
+ return (d->usingTLS ? 1 : 0);
+}
+
+
+void TCPSlaveBase::stopTLS()
+{
+ if (d->usingTLS) {
+ delete d->kssl;
+ d->usingTLS = false;
+ setMetaData("ssl_in_use", "FALSE");
+ }
+}
+
+
+void TCPSlaveBase::setSSLMetaData() {
+ if (!(d->usingTLS || d->useSSLTunneling || m_bIsSSL))
+ return;
+
+ mOutgoingMetaData = d->savedMetaData;
+}
+
+
+bool TCPSlaveBase::canUseTLS()
+{
+ if (m_bIsSSL || d->needSSLHandShake || !KSSL::doesSSLWork())
+ return false;
+
+ KSSLSettings kss;
+ return kss.tlsv1();
+}
+
+
+void TCPSlaveBase::certificatePrompt()
+{
+TQString certname; // the cert to use this session
+bool send = false, prompt = false, save = false, forcePrompt = false;
+KSSLCertificateHome::KSSLAuthAction aa;
+
+ setMetaData("ssl_using_client_cert", "FALSE"); // we change this if needed
+
+ if (metaData("ssl_no_client_cert") == "TRUE") return;
+ forcePrompt = (metaData("ssl_force_cert_prompt") == "TRUE");
+
+ // Delete the old cert since we're certainly done with it now
+ if (d->pkcs) {
+ delete d->pkcs;
+ d->pkcs = NULL;
+ }
+
+ if (!d->kssl) return;
+
+ // Look for a general certificate
+ if (!forcePrompt) {
+ certname = KSSLCertificateHome::getDefaultCertificateName(&aa);
+ switch(aa) {
+ case KSSLCertificateHome::AuthSend:
+ send = true; prompt = false;
+ break;
+ case KSSLCertificateHome::AuthDont:
+ send = false; prompt = false;
+ certname = TQString::null;
+ break;
+ case KSSLCertificateHome::AuthPrompt:
+ send = false; prompt = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ TQString ourHost;
+ if (!d->realHost.isEmpty()) {
+ ourHost = d->realHost;
+ } else {
+ ourHost = d->host;
+ }
+
+ // Look for a certificate on a per-host basis as an override
+ TQString tmpcn = KSSLCertificateHome::getDefaultCertificateName(ourHost, &aa);
+ if (aa != KSSLCertificateHome::AuthNone) { // we must override
+ switch (aa) {
+ case KSSLCertificateHome::AuthSend:
+ send = true;
+ prompt = false;
+ certname = tmpcn;
+ break;
+ case KSSLCertificateHome::AuthDont:
+ send = false;
+ prompt = false;
+ certname = TQString::null;
+ break;
+ case KSSLCertificateHome::AuthPrompt:
+ send = false;
+ prompt = true;
+ certname = tmpcn;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Finally, we allow the application to override anything.
+ if (hasMetaData("ssl_demand_certificate")) {
+ certname = metaData("ssl_demand_certificate");
+ if (!certname.isEmpty()) {
+ forcePrompt = false;
+ prompt = false;
+ send = true;
+ }
+ }
+
+ if (certname.isEmpty() && !prompt && !forcePrompt) return;
+
+ // Ok, we're supposed to prompt the user....
+ if (prompt || forcePrompt) {
+ TQStringList certs = KSSLCertificateHome::getCertificateList();
+
+ for (TQStringList::Iterator it = certs.begin(); it != certs.end(); ++it) {
+ KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(*it);
+ if (pkcs && (!pkcs->getCertificate() ||
+ !pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())) {
+ certs.remove(*it);
+ }
+ delete pkcs;
+ }
+
+ if (certs.isEmpty()) return; // we had nothing else, and prompt failed
+
+ if (!d->dcc) {
+ d->dcc = new DCOPClient;
+ d->dcc->attach();
+ if (!d->dcc->isApplicationRegistered("tdeio_uiserver")) {
+ TDEApplication::startServiceByDesktopPath("tdeio_uiserver.desktop",
+ TQStringList() );
+ }
+ }
+
+ TQByteArray data, retval;
+ TQCString rettype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << ourHost;
+ arg << certs;
+ arg << metaData("window-id").toInt();
+ bool rc = d->dcc->call("tdeio_uiserver", "UIServer",
+ "showSSLCertDialog(TQString, TQStringList,int)",
+ data, rettype, retval);
+
+ if (rc && rettype == "KSSLCertDlgRet") {
+ TQDataStream retStream(retval, IO_ReadOnly);
+ KSSLCertDlgRet drc;
+ retStream >> drc;
+ if (drc.ok) {
+ send = drc.send;
+ save = drc.save;
+ certname = drc.choice;
+ }
+ }
+ }
+
+ // The user may have said to not send the certificate,
+ // but to save the choice
+ if (!send) {
+ if (save) {
+ KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
+ false, false);
+ }
+ return;
+ }
+
+ // We're almost committed. If we can read the cert, we'll send it now.
+ KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(certname);
+ if (!pkcs && KSSLCertificateHome::hasCertificateByName(certname)) { // We need the password
+ TDEIO::AuthInfo ai;
+ bool first = true;
+ do {
+ ai.prompt = i18n("Enter the certificate password:");
+ ai.caption = i18n("SSL Certificate Password");
+ ai.url.setProtocol("kssl");
+ ai.url.setHost(certname);
+ ai.username = certname;
+ ai.keepPassword = true;
+
+ bool showprompt;
+ if (first)
+ showprompt = !checkCachedAuthentication(ai);
+ else
+ showprompt = true;
+ if (showprompt) {
+ if (!openPassDlg(ai, first ? TQString::null :
+ i18n("Unable to open the certificate. Try a new password?")))
+ break;
+ }
+
+ first = false;
+ pkcs = KSSLCertificateHome::getCertificateByName(certname, ai.password);
+ } while (!pkcs);
+
+ }
+
+ // If we could open the certificate, let's send it
+ if (pkcs) {
+ if (!d->kssl->setClientCertificate(pkcs)) {
+ messageBox(Information, i18n("The procedure to set the "
+ "client certificate for the session "
+ "failed."), i18n("SSL"));
+ delete pkcs; // we don't need this anymore
+ pkcs = 0L;
+ } else {
+ kdDebug(7029) << "Client SSL certificate is being used." << endl;
+ setMetaData("ssl_using_client_cert", "TRUE");
+ if (save) {
+ KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
+ true, false);
+ }
+ }
+ d->pkcs = pkcs;
+ }
+}
+
+
+
+bool TCPSlaveBase::usingTLS() const
+{
+ return d->usingTLS;
+}
+
+// ### remove this for KDE4 (misses const):
+bool TCPSlaveBase::usingTLS()
+{
+ return d->usingTLS;
+}
+
+
+// Returns 0 for failed verification, -1 for rejected cert and 1 for ok
+int TCPSlaveBase::verifyCertificate()
+{
+ int rc = 0;
+ bool permacache = false;
+ bool isChild = false;
+ bool _IPmatchesCN = false;
+ int result;
+ bool doAddHost = false;
+ TQString ourHost;
+
+ if (!d->realHost.isEmpty())
+ ourHost = d->realHost;
+ else ourHost = d->host;
+
+ TQString theurl = TQString(m_sServiceName)+"://"+ourHost+":"+TQString::number(m_iPort);
+
+ if (!hasMetaData("ssl_militant") || metaData("ssl_militant") == "FALSE")
+ d->militantSSL = false;
+ else if (metaData("ssl_militant") == "TRUE")
+ d->militantSSL = true;
+
+ if (!d->cc) d->cc = new KSSLCertificateCache;
+
+ KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
+
+ KSSLCertificate::KSSLValidationList ksvl = pc.validateVerbose(KSSLCertificate::SSLServer);
+
+ _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
+ if (!_IPmatchesCN) {
+#ifndef Q_WS_WIN //temporary
+ KNetwork::KResolverResults res = KNetwork::KResolver::resolve(d->kssl->peerInfo().peerHost(), "80", KNetwork::KResolver::CanonName);
+ if (!res.isEmpty()) {
+ TQString old = d->kssl->peerInfo().peerHost();
+ d->kssl->peerInfo().setPeerHost(res[0].canonicalName());
+ _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
+ if (!_IPmatchesCN) {
+ d->kssl->peerInfo().setPeerHost(old);
+ }
+ }
+#endif
+ if (!_IPmatchesCN && !d->militantSSL) { // force this if the user wants it
+ if (d->cc->getHostList(pc).contains(ourHost)) {
+ _IPmatchesCN = true;
+ }
+ }
+ }
+
+ if (!_IPmatchesCN) {
+ ksvl << KSSLCertificate::InvalidHost;
+ }
+
+ KSSLCertificate::KSSLValidation ksv = KSSLCertificate::Ok;
+ if (!ksvl.isEmpty())
+ ksv = ksvl.first();
+
+ /* Setting the various bits of meta-info that will be needed. */
+ setMetaData("ssl_cipher", d->kssl->connectionInfo().getCipher());
+ setMetaData("ssl_cipher_desc",
+ d->kssl->connectionInfo().getCipherDescription());
+ setMetaData("ssl_cipher_version",
+ d->kssl->connectionInfo().getCipherVersion());
+ setMetaData("ssl_cipher_used_bits",
+ TQString::number(d->kssl->connectionInfo().getCipherUsedBits()));
+ setMetaData("ssl_cipher_bits",
+ TQString::number(d->kssl->connectionInfo().getCipherBits()));
+ setMetaData("ssl_peer_ip", d->ip);
+ if (!d->realHost.isEmpty()) {
+ setMetaData("ssl_proxied", "true");
+ }
+
+ TQString errorStr;
+ for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
+ it != ksvl.end(); ++it)
+ {
+ errorStr += TQString::number(*it)+":";
+ }
+ setMetaData("ssl_cert_errors", errorStr);
+ setMetaData("ssl_peer_certificate", pc.toString());
+
+ if (pc.chain().isValid() && pc.chain().depth() > 1) {
+ TQString theChain;
+ TQPtrList<KSSLCertificate> chain = pc.chain().getChain();
+ chain.setAutoDelete(true);
+ for (KSSLCertificate *c = chain.first(); c; c = chain.next()) {
+ theChain += c->toString();
+ theChain += "\n";
+ }
+ setMetaData("ssl_peer_chain", theChain);
+ } else setMetaData("ssl_peer_chain", "");
+
+ setMetaData("ssl_cert_state", TQString::number(ksv));
+
+ if (ksv == KSSLCertificate::Ok) {
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ }
+
+ kdDebug(7029) << "SSL HTTP frame the parent? " << metaData("main_frame_request") << endl;
+ if (!hasMetaData("main_frame_request") || metaData("main_frame_request") == "TRUE") {
+ // Since we're the parent, we need to teach the child.
+ setMetaData("ssl_parent_ip", d->ip);
+ setMetaData("ssl_parent_cert", pc.toString());
+ // - Read from cache and see if there is a policy for this
+ KSSLCertificateCache::KSSLCertificatePolicy cp =
+ d->cc->getPolicyByCertificate(pc);
+
+ // - validation code
+ if (ksv != KSSLCertificate::Ok) {
+ if (d->militantSSL) {
+ return -1;
+ }
+
+ if (cp == KSSLCertificateCache::Unknown ||
+ cp == KSSLCertificateCache::Ambiguous) {
+ cp = KSSLCertificateCache::Prompt;
+ } else {
+ // A policy was already set so let's honor that.
+ permacache = d->cc->isPermanent(pc);
+ }
+
+ if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
+ cp = KSSLCertificateCache::Prompt;
+// ksv = KSSLCertificate::Ok;
+ }
+
+ // Precondition: cp is one of Reject, Accept or Prompt
+ switch (cp) {
+ case KSSLCertificateCache::Accept:
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ break;
+ case KSSLCertificateCache::Reject:
+ rc = -1;
+ setMetaData("ssl_action", "reject");
+ break;
+ case KSSLCertificateCache::Prompt:
+ {
+ do {
+ if (ksv == KSSLCertificate::InvalidHost) {
+ TQString msg = i18n("The IP address of the host %1 "
+ "does not match the one the "
+ "certificate was issued to.");
+ result = messageBox( WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ i18n("Co&ntinue") );
+ } else {
+ TQString msg = i18n("The server certificate failed the "
+ "authenticity test (%1).");
+ result = messageBox( WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ i18n("Co&ntinue") );
+ }
+
+ if (result == KMessageBox::Yes) {
+ if (!d->dcc) {
+ d->dcc = new DCOPClient;
+ d->dcc->attach();
+ if (!d->dcc->isApplicationRegistered("tdeio_uiserver")) {
+ TDEApplication::startServiceByDesktopPath("tdeio_uiserver.desktop",
+ TQStringList() );
+ }
+
+ }
+ TQByteArray data, ignore;
+ TQCString ignoretype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << theurl << mOutgoingMetaData;
+ arg << metaData("window-id").toInt();
+ d->dcc->call("tdeio_uiserver", "UIServer",
+ "showSSLInfoDialog(TQString,TDEIO::MetaData,int)",
+ data, ignoretype, ignore);
+ }
+ } while (result == KMessageBox::Yes);
+
+ if (result == KMessageBox::No) {
+ setMetaData("ssl_action", "accept");
+ rc = 1;
+ cp = KSSLCertificateCache::Accept;
+ doAddHost = true;
+ result = messageBox( WarningYesNo,
+ i18n("Would you like to accept this "
+ "certificate forever without "
+ "being prompted?"),
+ i18n("Server Authentication"),
+ i18n("&Forever"),
+ i18n("&Current Sessions Only"));
+ if (result == KMessageBox::Yes)
+ permacache = true;
+ else
+ permacache = false;
+ } else {
+ setMetaData("ssl_action", "reject");
+ rc = -1;
+ cp = KSSLCertificateCache::Prompt;
+ }
+ break;
+ }
+ default:
+ kdDebug(7029) << "TCPSlaveBase/SSL error in cert code."
+ << "Please report this to kfm-devel@kde.org."
+ << endl;
+ break;
+ }
+ }
+
+
+ // - cache the results
+ d->cc->addCertificate(pc, cp, permacache);
+ if (doAddHost) d->cc->addHost(pc, ourHost);
+ } else { // Child frame
+ // - Read from cache and see if there is a policy for this
+ KSSLCertificateCache::KSSLCertificatePolicy cp =
+ d->cc->getPolicyByCertificate(pc);
+ isChild = true;
+
+ // Check the cert and IP to make sure they're the same
+ // as the parent frame
+ bool certAndIPTheSame = (d->ip == metaData("ssl_parent_ip") &&
+ pc.toString() == metaData("ssl_parent_cert"));
+
+ if (ksv == KSSLCertificate::Ok) {
+ if (certAndIPTheSame) { // success
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ } else {
+ /*
+ if (d->militantSSL) {
+ return -1;
+ }
+ result = messageBox(WarningYesNo,
+ i18n("The certificate is valid but does not appear to have been assigned to this server. Do you wish to continue loading?"),
+ i18n("Server Authentication"));
+ if (result == KMessageBox::Yes) { // success
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ } else { // fail
+ rc = -1;
+ setMetaData("ssl_action", "reject");
+ }
+ */
+ setMetaData("ssl_action", "accept");
+ rc = 1; // Let's accept this now. It's bad, but at least the user
+ // will see potential attacks in KDE3 with the pseudo-lock
+ // icon on the toolbar, and can investigate with the RMB
+ }
+ } else {
+ if (d->militantSSL) {
+ return -1;
+ }
+
+ if (cp == KSSLCertificateCache::Accept) {
+ if (certAndIPTheSame) { // success
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ } else { // fail
+ result = messageBox(WarningYesNo,
+ i18n("You have indicated that you wish to accept this certificate, but it is not issued to the server who is presenting it. Do you wish to continue loading?"),
+ i18n("Server Authentication"));
+ if (result == KMessageBox::Yes) {
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ d->cc->addHost(pc, ourHost);
+ } else {
+ rc = -1;
+ setMetaData("ssl_action", "reject");
+ }
+ }
+ } else if (cp == KSSLCertificateCache::Reject) { // fail
+ messageBox(Information, i18n("SSL certificate is being rejected as requested. You can disable this in the TDE Control Center."),
+ i18n("Server Authentication"));
+ rc = -1;
+ setMetaData("ssl_action", "reject");
+ } else {
+ do {
+ TQString msg = i18n("The server certificate failed the "
+ "authenticity test (%1).");
+ result = messageBox(WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ i18n("Co&nnect"));
+ if (result == KMessageBox::Yes) {
+ if (!d->dcc) {
+ d->dcc = new DCOPClient;
+ d->dcc->attach();
+ if (!d->dcc->isApplicationRegistered("tdeio_uiserver")) {
+ TDEApplication::startServiceByDesktopPath("tdeio_uiserver.desktop",
+ TQStringList() );
+ }
+ }
+ TQByteArray data, ignore;
+ TQCString ignoretype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << theurl << mOutgoingMetaData;
+ arg << metaData("window-id").toInt();
+ d->dcc->call("tdeio_uiserver", "UIServer",
+ "showSSLInfoDialog(TQString,TDEIO::MetaData,int)",
+ data, ignoretype, ignore);
+ }
+ } while (result == KMessageBox::Yes);
+
+ if (result == KMessageBox::No) {
+ setMetaData("ssl_action", "accept");
+ rc = 1;
+ cp = KSSLCertificateCache::Accept;
+ result = messageBox(WarningYesNo,
+ i18n("Would you like to accept this "
+ "certificate forever without "
+ "being prompted?"),
+ i18n("Server Authentication"),
+ i18n("&Forever"),
+ i18n("&Current Sessions Only"));
+ permacache = (result == KMessageBox::Yes);
+ d->cc->addCertificate(pc, cp, permacache);
+ d->cc->addHost(pc, ourHost);
+ } else {
+ setMetaData("ssl_action", "reject");
+ rc = -1;
+ cp = KSSLCertificateCache::Prompt;
+ d->cc->addCertificate(pc, cp, permacache);
+ }
+ }
+ }
+ }
+
+
+ if (rc == -1) {
+ return rc;
+ }
+
+ if (metaData("ssl_activate_warnings") == "TRUE") {
+ // - entering SSL
+ if (!isChild && metaData("ssl_was_in_use") == "FALSE" &&
+ d->kssl->settings()->warnOnEnter()) {
+ int result;
+ do {
+ result = messageBox( i18n("You are about to "
+ "enter secure mode. "
+ "All transmissions "
+ "will be encrypted "
+ "unless otherwise "
+ "noted.\nThis means "
+ "that no third party "
+ "will be able to "
+ "easily observe your "
+ "data in transit."),
+ WarningYesNo,
+ i18n("Security Information"),
+ i18n("Display SSL "
+ "&Information"),
+ i18n("C&onnect"),
+ "WarnOnEnterSSLMode" );
+ // Move this setting into KSSL instead
+ TDEConfig *config = new TDEConfig("tdeioslaverc");
+ config->setGroup("Notification Messages");
+
+ if (!config->readBoolEntry("WarnOnEnterSSLMode", true)) {
+ config->deleteEntry("WarnOnEnterSSLMode");
+ config->sync();
+ d->kssl->settings()->setWarnOnEnter(false);
+ d->kssl->settings()->save();
+ }
+ delete config;
+
+ if ( result == KMessageBox::Yes )
+ {
+ if (!d->dcc) {
+ d->dcc = new DCOPClient;
+ d->dcc->attach();
+ if (!d->dcc->isApplicationRegistered("tdeio_uiserver")) {
+ TDEApplication::startServiceByDesktopPath("tdeio_uiserver.desktop",
+ TQStringList() );
+ }
+ }
+ TQByteArray data, ignore;
+ TQCString ignoretype;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << theurl << mOutgoingMetaData;
+ arg << metaData("window-id").toInt();
+ d->dcc->call("tdeio_uiserver", "UIServer",
+ "showSSLInfoDialog(TQString,TDEIO::MetaData,int)",
+ data, ignoretype, ignore);
+ }
+ } while (result != KMessageBox::No);
+ }
+
+ } // if ssl_activate_warnings
+
+
+ kdDebug(7029) << "SSL connection information follows:" << endl
+ << "+-----------------------------------------------" << endl
+ << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
+ << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
+ << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
+ << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
+ << " of " << d->kssl->connectionInfo().getCipherBits()
+ << " bits used." << endl
+ << "| PEER:" << endl
+ << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
+ << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
+ << "| Validation: " << (int)ksv << endl
+ << "| Certificate matches IP: " << _IPmatchesCN << endl
+ << "+-----------------------------------------------"
+ << endl;
+
+ // sendMetaData(); Do not call this function!!
+ return rc;
+}
+
+
+bool TCPSlaveBase::isConnectionValid()
+{
+ if ( m_iSock == -1 )
+ return false;
+
+ fd_set rdfs;
+ FD_ZERO(&rdfs);
+ FD_SET(m_iSock , &rdfs);
+
+ struct timeval tv;
+ tv.tv_usec = 0;
+ tv.tv_sec = 0;
+ int retval;
+#ifdef Q_OS_UNIX
+ do {
+ retval = KSocks::self()->select(m_iSock+1, &rdfs, NULL, NULL, &tv);
+ if (wasKilled())
+ return false; // Beam us out of here
+ } while ((retval == -1) && (errno == EAGAIN));
+#else
+ retval = -1;
+#endif
+ // retval == -1 ==> Error
+ // retval == 0 ==> Connection Idle
+ // retval >= 1 ==> Connection Active
+ //kdDebug(7029) << "TCPSlaveBase::isConnectionValid: select returned: "
+ // << retval << endl;
+
+ if (retval == -1)
+ return false;
+
+ if (retval == 0)
+ return true;
+
+ // Connection is active, check if it has closed.
+ char buffer[100];
+#ifdef Q_OS_UNIX
+ do {
+ retval = KSocks::self()->recv(m_iSock, buffer, 80, MSG_PEEK);
+
+ } while ((retval == -1) && (errno == EAGAIN));
+#else
+ retval = -1;
+#endif
+ //kdDebug(7029) << "TCPSlaveBase::isConnectionValid: recv returned: "
+ // << retval << endl;
+ if (retval <= 0)
+ return false; // Error or connection closed.
+
+ return true; // Connection still valid.
+}
+
+
+bool TCPSlaveBase::waitForResponse( int t )
+{
+ fd_set rd;
+ struct timeval timeout;
+
+ if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling && d->kssl )
+ if (d->kssl->pending() > 0)
+ return true;
+
+ FD_ZERO(&rd);
+ FD_SET(m_iSock, &rd);
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = t;
+ time_t startTime;
+
+ int rc;
+ int n = t;
+
+reSelect:
+ startTime = time(NULL);
+#ifdef Q_OS_UNIX
+ rc = KSocks::self()->select(m_iSock+1, &rd, NULL, NULL, &timeout);
+#else
+ rc = -1;
+#endif
+ if (wasKilled())
+ return false; // We're dead.
+
+ if (rc == -1)
+ return false;
+
+ if (FD_ISSET(m_iSock, &rd))
+ return true;
+
+ // Well it returned but it wasn't set. Let's see if it
+ // returned too early (perhaps from an errant signal) and
+ // start over with the remaining time
+ int timeDone = time(NULL) - startTime;
+ if (timeDone < n)
+ {
+ n -= timeDone;
+ timeout.tv_sec = n;
+ goto reSelect;
+ }
+
+ return false; // Timed out!
+}
+
+int TCPSlaveBase::connectResult()
+{
+ return d->status;
+}
+
+void TCPSlaveBase::setBlockConnection( bool b )
+{
+ d->block = b;
+}
+
+void TCPSlaveBase::setConnectTimeout( int t )
+{
+ d->timeout = t;
+}
+
+bool TCPSlaveBase::isSSLTunnelEnabled()
+{
+ return d->useSSLTunneling;
+}
+
+void TCPSlaveBase::setEnableSSLTunnel( bool enable )
+{
+ d->useSSLTunneling = enable;
+}
+
+void TCPSlaveBase::setRealHost( const TQString& realHost )
+{
+ d->realHost = realHost;
+}
+
+bool TCPSlaveBase::doSSLHandShake( bool sendError )
+{
+ kdDebug(7029) << "TCPSlaveBase::doSSLHandShake: " << endl;
+ TQString msgHost = d->host;
+
+ d->kssl->reInitialize();
+
+ if (hasMetaData("ssl_session_id")) {
+ KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
+ if (s) {
+ d->kssl->setSession(s);
+ delete s;
+ }
+ }
+ certificatePrompt();
+
+ if ( !d->realHost.isEmpty() )
+ {
+ msgHost = d->realHost;
+ }
+
+ kdDebug(7029) << "Setting real hostname: " << msgHost << endl;
+ d->kssl->setPeerHost(msgHost);
+
+ d->status = d->kssl->connect(m_iSock);
+ if (d->status < 0)
+ {
+ closeDescriptor();
+ if ( sendError )
+ error( ERR_COULD_NOT_CONNECT, msgHost);
+ return false;
+ }
+
+ setMetaData("ssl_session_id", d->kssl->session()->toString());
+ setMetaData("ssl_in_use", "TRUE");
+
+ if (!d->kssl->reusingSession()) {
+ int rc = verifyCertificate();
+ if ( rc != 1 ) {
+ d->status = -1;
+ closeDescriptor();
+ if ( sendError )
+ error( ERR_COULD_NOT_CONNECT, msgHost);
+ return false;
+ }
+ }
+
+ d->needSSLHandShake = false;
+
+ d->savedMetaData = mOutgoingMetaData;
+ return true;
+}
+
+
+bool TCPSlaveBase::userAborted() const
+{
+ return d->userAborted;
+}
+
+void TCPSlaveBase::virtual_hook( int id, void* data )
+{ SlaveBase::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/tcpslavebase.h b/tdeio/tdeio/tcpslavebase.h
new file mode 100644
index 000000000..4903dd7ac
--- /dev/null
+++ b/tdeio/tdeio/tcpslavebase.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net>
+ * Copyright (C) 2001 George Staikos <staikos@kde.org>
+ * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
+ *
+ * This file is part of the KDE project
+ *
+ * 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 _TCP_SLAVEBASE_H
+#define _TCP_SLAVEBASE_H
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <kextsock.h>
+#include <tdeio/slavebase.h>
+
+
+namespace TDEIO {
+
+/**
+ * There are two classes that specifies the protocol between application (job)
+ * and tdeioslave. SlaveInterface is the class to use on the application end,
+ * SlaveBase is the one to use on the slave end.
+ *
+ * Slave implementations should simply inherit SlaveBase
+ *
+ * A call to foo() results in a call to slotFoo() on the other end.
+ */
+class TDEIO_EXPORT TCPSlaveBase : public SlaveBase
+{
+public:
+ TCPSlaveBase(unsigned short int defaultPort, const TQCString &protocol,
+ const TQCString &poolSocket, const TQCString &appSocket);
+
+ TCPSlaveBase(unsigned short int defaultPort, const TQCString &protocol,
+ const TQCString &poolSocket, const TQCString &appSocket,
+ bool useSSL);
+
+ virtual ~TCPSlaveBase();
+
+protected:
+
+#ifndef KDE_NO_COMPAT
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED ssize_t Write(const void *data, ssize_t len) { return write( data, len ); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED ssize_t Read(void *data, ssize_t len) { return read( data, len ); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED ssize_t ReadLine(char *data, ssize_t len) { return readLine( data, len ); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED unsigned short int GetPort(unsigned short int p) { return port(p); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED bool ConnectToHost( const TQString &host, unsigned int port,
+ bool sendError ) { return connectToHost( host, port, sendError ); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED void CloseDescriptor() { closeDescriptor(); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED bool AtEOF() { return atEnd(); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED bool InitializeSSL() { return initializeSSL(); }
+
+ /**
+ * @deprecated Due to inconsistency with KDE naming convention.
+ */
+ KDE_DEPRECATED void CleanSSL() { cleanSSL(); }
+#endif
+
+ /**
+ * This function acts like standard write function call
+ * except it is also capable of making SSL or SOCKS
+ * connections.
+ *
+ * @param data info to be sent to remote machine
+ * @param len the length of the data to be sent
+ *
+ * @return the actual size of the data that was sent
+ */
+ ssize_t write(const void *data, ssize_t len);
+
+ /**
+ * This function acts like standard read function call
+ * except it is also capable of deciphering SSL data as
+ * well as handling data over SOCKSified connections.
+ *
+ * @param data storage for the info read from server
+ * @param len length of the info to read from the server
+ *
+ * @return the actual size of data that was obtained
+ */
+ ssize_t read(void *data, ssize_t len);
+
+ /**
+ * Same as above except it reads data one line at a time.
+ */
+ ssize_t readLine(char *data, ssize_t len);
+
+ /**
+ * Sets the maximum size of blocks read in during calls to readLine().
+ * This allows a slave to optimize for the protocol which it implements.
+ * Ideally this should be (common_line_length+1) or so.
+ * Making this too large will have adverse effects on performance.
+ * Initial/default value is 256(bytes)
+ */
+ void setBlockSize(int sz);
+
+ /**
+ * Determines the appropriate port to use.
+ *
+ * This functions attempts to discover the appropriate port.
+ *
+ * @param _port the port to try, if it works, it is returned
+ * @return the default port if the given port doesn't work
+ */
+ unsigned short int port(unsigned short int _port);
+
+ /**
+ * Performs the initial TCP connection stuff and/or
+ * SSL handshaking as necessary.
+ *
+ * Please note that unlike its deprecated counterpart, this
+ * function allows you to disable any error message from being
+ * sent back to the calling application! You can then use the
+ * connectResult() function to determine the result of the
+ * request for connection.
+ *
+ * @param host hostname
+ * @param port port number to connect to
+ * @param sendError if true sends error message to calling app.
+ *
+ * @return on succes, true is returned.
+ * on failure, false is returned and an appropriate
+ * error message is send to the application.
+ */
+ bool connectToHost( const TQString &host, unsigned int port,
+ bool sendError = true );
+
+ /**
+ * Are we using SSL?
+ *
+ * @return if so, true is returned.
+ * if not, true isn't returned.
+ * @since 3.2
+ */
+ bool usingSSL() const { return m_bIsSSL; }
+
+ /**
+ * Are we using TLS?
+ *
+ * @return if so, true is returned.
+ * if not, true isn't returned.
+ * @since 3.2
+ */
+ bool usingTLS() const;
+
+ /**
+ * @obsolete kept for binary compatibility
+ * Are we using TLS?
+ *
+ * @return if so, true is returned.
+ * if not, true isn't returned.
+ */
+ bool usingTLS();
+
+ /**
+ * Can we use TLS?
+ *
+ * @return if so, true is returned.
+ * if not, true isn't returned.
+ */
+ bool canUseTLS();
+
+ /**
+ * Start using TLS on the connection.
+ *
+ * @return on success, 1 is returned.
+ * on failure, 0 is returned.
+ * on TLS init failure, -1 is returned.
+ * on connect failure, -2 is returned.
+ * on certificate failure, -3 is returned.
+ */
+ int startTLS();
+
+ /**
+ * Stop using TLS on the connection.
+ */
+ void stopTLS();
+
+ /**
+ * Closes the current file descriptor.
+ *
+ * Call this function to properly close up the socket
+ * since it also takes care to prroperly close the stdio
+ * fstream stuff, as well as sets the socket back to -1
+ */
+ void closeDescriptor();
+
+
+ /**
+ * Returns true when end of data is reached
+ */
+ bool atEnd();
+
+
+ /**
+ * Call this if you use persistent connections and want all the
+ * metadata restored. This is particularly important for SSL
+ * sessions since the app needs to know the state of connection,
+ * certificates, etc.
+ */
+ void setSSLMetaData();
+
+
+ /**
+ * Initializs all SSL variables
+ */
+ bool initializeSSL();
+
+
+ /**
+ * Cleans up all SSL settings.
+ */
+ void cleanSSL();
+
+ /**
+ * Determines whether or not we are still connected
+ * to the remote machine.
+ *
+ * This method may fail to detect a closed SSL connection.
+ *
+ * return @p true if the socket is still active or
+ * false otherwise.
+ */
+ bool isConnectionValid();
+
+ /**
+ * Returns the status of the connection.
+ *
+ * This function allows you to invoke ConnectToHost
+ * with the @p sendError flag set to false so that you
+ * can send the appropriate error message back to the
+ * calling io-slave.
+ *
+ * @return the status code as returned by KExtendedSocket.
+ */
+ int connectResult();
+
+ /**
+ * Wait for some type of activity on the socket
+ * for the period specified by @p t.
+ *
+ * @param t length of time in seconds that we should monitor the
+ * socket before timing out.
+ *
+ * @return true if any activity was seen on the socket before the
+ * timeout value was reached, false otherwise.
+ */
+ bool waitForResponse( int t );
+
+ /**
+ * Sets the mode of the connection to blocking or non-blocking.
+ *
+ * Be sure to call this function before calling connectToHost.
+ * Otherwise, this setting will not have any effect until the next
+ * @p connectToHost.
+ *
+ * @param b true to make the connection a blocking one, false otherwise.
+ */
+ void setBlockConnection( bool b );
+
+ /**
+ * Sets how long to wait for orignally connecting to
+ * the requested before timinig out.
+ *
+ * Be sure to call this function before calling ConnectToHost,
+ * otherwise the setting will not take effect until the next call
+ * to @p ConnectToHost.
+ *
+ * @param t timeout value
+ */
+ void setConnectTimeout( int t );
+
+ /**
+ * Returns true if SSL tunneling is enabled.
+ *
+ * @see setEnableSSlTunnel
+ */
+ bool isSSLTunnelEnabled();
+
+ /**
+ * Set up SSL tunneling mode.
+ *
+ * Calling this function with a @p true argument will allow
+ * you to temprarly ignore the @p m_bIsSSL flag setting and
+ * make a non-SSL connection. It is mostly useful for making
+ * connections to SSL sites through a non-transparent proxy
+ * server (i.e. most proxy servers out there).
+ *
+ * Note that once you have successfully "tunneled" through the
+ * proxy server you must call this function with its argument
+ * set to false to properly connect to the SSL site.
+ *
+ * @param enable if true SSL Tunneling will be enabled
+ */
+ void setEnableSSLTunnel( bool enable );
+
+ /**
+ * Sets up the the real hostname for an SSL connection
+ * that goes through a proxy server.
+ *
+ * This function is essential in making sure that the
+ * real hostname is used for validating certificates from
+ * SSL sites!
+ *
+ * @param realHost the actual host name we are connecting to
+ */
+ void setRealHost( const TQString& realHost );
+
+ // don't use me!
+ void doConstructorStuff();
+
+ // For the certificate verification code
+ int verifyCertificate();
+
+ // For prompting for the certificate to use
+ void certificatePrompt();
+
+ // Did the user abort (as the reason for connectToHost returning false)
+ bool userAborted() const;
+
+protected:
+ int m_iSock;
+ bool m_bIsSSL;
+ unsigned short int m_iPort;
+ unsigned short int m_iDefaultPort;
+ TQCString m_sServiceName;
+ FILE *fp;
+
+private:
+ bool doSSLHandShake( bool sendError );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class TcpSlaveBasePrivate;
+ TcpSlaveBasePrivate *d;
+};
+
+}
+
+#endif
diff --git a/tdeio/tdeio/tdefilefilter.cpp b/tdeio/tdeio/tdefilefilter.cpp
new file mode 100644
index 000000000..310b86221
--- /dev/null
+++ b/tdeio/tdeio/tdefilefilter.cpp
@@ -0,0 +1,134 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2001,2002 Carsten Pfeiffer <pfeiffer@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 (LGPL) 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 <tqregexp.h>
+
+#include <tdefileitem.h>
+#include <kglobal.h>
+
+#include "tdefilefilter.h"
+
+KSimpleFileFilter::KSimpleFileFilter()
+ : m_filterDotFiles( true ),
+ m_filterSpecials( true ),
+ m_modeFilter( 0 )
+{
+ m_nameFilters.setAutoDelete( true );
+}
+
+KSimpleFileFilter::~KSimpleFileFilter()
+{
+}
+
+void KSimpleFileFilter::setFilterDotFiles( bool filter )
+{
+ m_filterDotFiles = filter;
+}
+
+void KSimpleFileFilter::setFilterSpecials( bool filter )
+{
+ m_filterSpecials = filter;
+}
+
+void KSimpleFileFilter::setNameFilters( const TQString& nameFilters )
+{
+ // KDE 3.0 defaults
+ setNameFilters( nameFilters, false, ' ' );
+}
+
+void KSimpleFileFilter::setNameFilters( const TQString& nameFilters,
+ bool caseSensitive,
+ const TQChar& separator )
+{
+ m_nameFilters.clear();
+
+ // Split on white space
+ TQStringList list = TQStringList::split(separator, nameFilters);
+
+ TQStringList::ConstIterator it = list.begin();
+ for ( ; it != list.end(); ++it )
+ m_nameFilters.append(new TQRegExp(*it, caseSensitive, true ));
+}
+
+void KSimpleFileFilter::setMimeFilters( const TQStringList& mimeFilters )
+{
+ m_mimeFilters = mimeFilters;
+}
+
+void KSimpleFileFilter::setModeFilter( mode_t mode )
+{
+ m_modeFilter = mode;
+}
+
+bool KSimpleFileFilter::passesFilter( const KFileItem *item ) const
+{
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ const TQString& name = item->name();
+
+ if ( m_filterDotFiles && item->isHidden() )
+ return false;
+
+ if ( m_filterSpecials && (name == dot || name == dotdot) )
+ return false;
+
+ if ( m_modeFilter && !(m_modeFilter & item->mode()) )
+ return false;
+
+ if ( !m_mimeFilters.isEmpty() ) {
+ // correct or guessed mimetype -- we don't mind
+ KMimeType::Ptr mime = item->mimeTypePtr();
+ bool ok = false;
+
+ TQStringList::ConstIterator it = m_mimeFilters.begin();
+ for ( ; it != m_mimeFilters.end(); ++it ) {
+ if ( mime->is(*it) ) { // match!
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return false;
+ }
+
+ if ( !m_nameFilters.isEmpty() ) {
+ bool ok = false;
+
+ TQPtrListIterator<TQRegExp> it( m_nameFilters );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->exactMatch( name ) ) { // match!
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return false;
+ }
+
+ return true; // passes the filter!
+}
+
+void KFileFilter::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KSimpleFileFilter::virtual_hook( int id, void* data )
+{ KFileFilter::virtual_hook( id, data ); }
+
diff --git a/tdeio/tdeio/tdefilefilter.h b/tdeio/tdeio/tdefilefilter.h
new file mode 100644
index 000000000..2891e800e
--- /dev/null
+++ b/tdeio/tdeio/tdefilefilter.h
@@ -0,0 +1,170 @@
+/* This file is part of the KDE libraries
+
+ Copyright (c) 2001,2002 Carsten Pfeiffer <pfeiffer@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 (LGPL) 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 KFILEFILTER_H
+#define KFILEFILTER_H
+
+#include <tqptrlist.h>
+#include <tqstringlist.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <tdelibs_export.h>
+
+class TQRegExp;
+class KFileItem;
+
+/**
+ * A KFileFilter is a simple base class for file filters. Just
+ * reimplement passesFilter().
+ * @short Base class for file filters.
+ */
+class TDEIO_EXPORT KFileFilter
+{
+public:
+ /**
+ * Checks the given @p item.
+ * @param item the item to filter
+ * @return true if the @p item passes the filter, false otherwise
+ */
+ virtual bool passesFilter( const KFileItem *item ) const = 0;
+protected:
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * A simple file filter that can filter hidden dot files, by name,
+ * by mime type and by mode.
+ * @short A simple file filter.
+ */
+class TDEIO_EXPORT KSimpleFileFilter : public KFileFilter
+{
+public:
+ /**
+ * Creates a new filter. By default, it filters only hidden dot files
+ * and "." and "..".
+ */
+ KSimpleFileFilter();
+ virtual ~KSimpleFileFilter();
+
+ /**
+ * Enable or disable filtering hidden dot files.
+ * This option is enabled by default.
+ * @param filter true to enable filtering dot files, false to
+ * disable
+ * @see filterDotFiles
+ */
+ virtual void setFilterDotFiles( bool filter );
+ /**
+ * Checks whether filtering dot files is enabled.
+ * This option is enabled by default.
+ * @return true if filtering is enabled, false otherwise
+ * @see setFilterDotFiles
+ */
+ bool filterDotFiles() const { return m_filterDotFiles; }
+
+ /**
+ * Filters "." and "..", default is true.
+ * @param filter true to enable, false otherwise
+ */
+ virtual void setFilterSpecials( bool filter );
+ /**
+ * Checks whether it filters "." and "..", default is true.
+ * @return true if enabled, false otherwise
+ */
+ bool filterSpecials() const { return m_filterSpecials; }
+
+ // ### KDE4 make virtual and bool caseSensitive = false
+ /**
+ * Sets a list of regular expressions to filter by name.
+ * The file will only pass if its name matches one of the regular
+ * expressions.
+ * @param nameFilters a list of regular expressions, separated by
+ * the character @p separator
+ * @param caseSensitive if true, matches case sensitive. False
+ * otherwise
+ * @param separator the separator in the @p nameFilter
+ * @since 3.1
+ */
+ void setNameFilters( const TQString& nameFilters, bool caseSensitive,
+ const TQChar& separator = ' ' );
+ /**
+ * Sets a list of regular expressions to filter by name.
+ * The file will only pass if its name matches one of the regular
+ * expressions.
+ * @param nameFilters a list of regular expressions, separated by
+ * space (' ')
+ */
+ virtual void setNameFilters( const TQString& nameFilters );
+
+ /**
+ * Sets a list of mime filters. A file can only pass if its
+ * mime type is contained in this list.
+ * @param mimeFilters the list of mime types
+ * @see setMimeFilter
+ */
+ virtual void setMimeFilters( const TQStringList& mimeFilters );
+ /**
+ * Returns the list of mime types.
+ * @return the list of mime types
+ * @see mimeFilter
+ */
+ TQStringList mimeFilters() const { return m_mimeFilters; }
+
+ /**
+ * Sets the mode filter. If the @p mode is 0, the filter is
+ * disabled.
+ * When enabled, a file will only pass if the files mode
+ * ANDed with @p mode is not zero.
+ * @param mode the new mode. 0 to disable
+ * @see modeFilter
+ */
+ virtual void setModeFilter( mode_t mode );
+ /**
+ * Returns the mode filter, as set by setModeFilter().
+ * @return the mode filter, 0 if disabled
+ * @see setModeFilter
+ */
+ mode_t modeFilter() const { return m_modeFilter; }
+
+ /**
+ * Checks the given @p item.
+ * @param item the item to filter
+ * @return true if the @p item passes the filter, false otherwise
+ */
+ virtual bool passesFilter( const KFileItem *item ) const;
+
+protected:
+ TQPtrList<TQRegExp> m_nameFilters;
+
+private:
+ TQStringList m_mimeFilters;
+ bool m_filterDotFiles :1;
+ bool m_filterSpecials :1;
+ mode_t m_modeFilter;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KSimpleFileFilterPrivate* d;
+};
+
+#endif // KFILEFILTER_H
diff --git a/tdeio/tdeio/tdefileitem.cpp b/tdeio/tdeio/tdefileitem.cpp
new file mode 100644
index 000000000..bd043504a
--- /dev/null
+++ b/tdeio/tdeio/tdefileitem.cpp
@@ -0,0 +1,1202 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ 2001 Carsten Pfeiffer <pfeiffer@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.
+*/
+// $Id$
+
+#include <config.h>
+
+#include <sys/time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <unistd.h>
+
+#include "tdefileitem.h"
+
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqmap.h>
+#include <tqstylesheet.h>
+#include <tqimage.h>
+
+#include <kdebug.h>
+#include <tdefilemetainfo.h>
+#include <ksambashare.h>
+#include <knfsshare.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klargefile.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <krun.h>
+
+#ifdef HAVE_ELFICON
+#include "tdelficon.h"
+#endif // HAVE_ELFICON
+
+class KFileItem::KFileItemPrivate {
+ public:
+ TQString iconName;
+};
+
+KFileItem::KFileItem( const TDEIO::UDSEntry& _entry, const KURL& _url,
+ bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) :
+ m_entry( _entry ),
+ m_url( _url ),
+ m_pMimeType( 0 ),
+ m_fileMode( KFileItem::Unknown ),
+ m_permissions( KFileItem::Unknown ),
+ m_bMarked( false ),
+ m_bLink( false ),
+ m_bIsLocalURL( _url.isLocalFile() ),
+ m_bMimeTypeKnown( false ),
+ m_hidden( Auto ),
+ d(0)
+{
+ readUDSEntry( _urlIsDirectory );
+ init( _determineMimeTypeOnDemand );
+}
+
+KFileItem::KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url, bool _determineMimeTypeOnDemand ) :
+ m_entry(), // warning !
+ m_url( _url ),
+ m_strName( _url.fileName() ),
+ m_strText( TDEIO::decodeFileName( m_strName ) ),
+ m_pMimeType( 0 ),
+ m_fileMode ( _mode ),
+ m_permissions( _permissions ),
+ m_bMarked( false ),
+ m_bLink( false ),
+ m_bIsLocalURL( _url.isLocalFile() ),
+ m_bMimeTypeKnown( false ),
+ m_hidden( Auto ),
+ d(0)
+{
+ init( _determineMimeTypeOnDemand );
+}
+
+KFileItem::KFileItem( const KURL &url, const TQString &mimeType, mode_t mode )
+: m_url( url ),
+ m_strName( url.fileName() ),
+ m_strText( TDEIO::decodeFileName( m_strName ) ),
+ m_pMimeType( 0 ),
+ m_fileMode( mode ),
+ m_permissions( KFileItem::Unknown ),
+ m_bMarked( false ),
+ m_bLink( false ),
+ m_bIsLocalURL( url.isLocalFile() ),
+ m_bMimeTypeKnown( !mimeType.isEmpty() ),
+ m_hidden( Auto ),
+ d(0)
+{
+ if (m_bMimeTypeKnown)
+ m_pMimeType = KMimeType::mimeType( mimeType );
+
+ init( false );
+}
+
+KFileItem::KFileItem( const KFileItem & item ) :
+ d(0)
+{
+ assign( item );
+}
+
+KFileItem& KFileItem::operator=( const KFileItem & item )
+{
+ assign( item );
+ return *this;
+}
+
+KFileItem::~KFileItem()
+{
+ delete d;
+}
+
+void KFileItem::init( bool _determineMimeTypeOnDemand )
+{
+ m_access = TQString::null;
+ m_size = (TDEIO::filesize_t) -1;
+ // metaInfo = KFileMetaInfo();
+ for ( int i = 0; i < NumFlags; i++ )
+ m_time[i] = (time_t) -1;
+
+ // determine mode and/or permissions if unknown
+ if ( m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown )
+ {
+ mode_t mode = 0;
+ if ( m_url.isLocalFile() )
+ {
+ /* directories may not have a slash at the end if
+ * we want to stat() them; it requires that we
+ * change into it .. which may not be allowed
+ * stat("/is/unaccessible") -> rwx------
+ * stat("/is/unaccessible/") -> EPERM H.Z.
+ * This is the reason for the -1
+ */
+ KDE_struct_stat buf;
+ TQCString path = TQFile::encodeName(m_url.path( -1 ));
+ if ( KDE_lstat( path.data(), &buf ) == 0 )
+ {
+ mode = buf.st_mode;
+ if ( S_ISLNK( mode ) )
+ {
+ m_bLink = true;
+ if ( KDE_stat( path.data(), &buf ) == 0 )
+ mode = buf.st_mode;
+ else // link pointing to nowhere (see tdeio/file/file.cc)
+ mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ // While we're at it, store the times
+ m_time[ Modification ] = buf.st_mtime;
+ m_time[ Access ] = buf.st_atime;
+ if ( m_fileMode == KFileItem::Unknown )
+ m_fileMode = mode & S_IFMT; // extract file type
+ if ( m_permissions == KFileItem::Unknown )
+ m_permissions = mode & 07777; // extract permissions
+ }
+ }
+ }
+
+ // determine the mimetype
+ if (!m_pMimeType && !m_url.isEmpty())
+ {
+ bool accurate = false;
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL,
+ // use fast mode if not mimetype on demand
+ _determineMimeTypeOnDemand, &accurate );
+ //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl;
+ // if we didn't use fast mode, or if we got a result, then this is the mimetype
+ // otherwise, determineMimeType will be able to do better.
+ m_bMimeTypeKnown = (!_determineMimeTypeOnDemand) || accurate;
+ }
+}
+
+void KFileItem::readUDSEntry( bool _urlIsDirectory )
+{
+ // extract the mode and the filename from the TDEIO::UDS Entry
+ bool UDS_URL_seen = false;
+
+ if (&m_entry == NULL) return;
+
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it ) {
+ switch ((*it).m_uds) {
+
+ case TDEIO::UDS_FILE_TYPE:
+ m_fileMode = (mode_t)((*it).m_long);
+ break;
+
+ case TDEIO::UDS_ACCESS:
+ m_permissions = (mode_t)((*it).m_long);
+ break;
+
+ case TDEIO::UDS_USER:
+ m_user = ((*it).m_str);
+ break;
+
+ case TDEIO::UDS_GROUP:
+ m_group = ((*it).m_str);
+ break;
+
+ case TDEIO::UDS_NAME:
+ m_strName = (*it).m_str;
+ m_strText = TDEIO::decodeFileName( m_strName );
+ break;
+
+ case TDEIO::UDS_URL:
+ UDS_URL_seen = true;
+ m_url = KURL((*it).m_str);
+ if ( m_url.isLocalFile() )
+ m_bIsLocalURL = true;
+ break;
+
+ case TDEIO::UDS_MIME_TYPE:
+ m_pMimeType = KMimeType::mimeType((*it).m_str);
+ m_bMimeTypeKnown = true;
+ break;
+
+ case TDEIO::UDS_GUESSED_MIME_TYPE:
+ m_guessedMimeType = (*it).m_str;
+ break;
+
+ case TDEIO::UDS_LINK_DEST:
+ m_bLink = !(*it).m_str.isEmpty(); // we don't store the link dest
+ break;
+
+ case TDEIO::UDS_ICON_NAME:
+ if ( !d )
+ d = new KFileItemPrivate();
+ d->iconName = (*it).m_str;
+ break;
+
+ case TDEIO::UDS_HIDDEN:
+ if ( (*it).m_long )
+ m_hidden = Hidden;
+ else
+ m_hidden = Shown;
+ break;
+ }
+ }
+
+ // avoid creating these QStrings again and again
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ if ( _urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != dot )
+ m_url.addPath( m_strName );
+}
+
+void KFileItem::refresh()
+{
+ m_fileMode = KFileItem::Unknown;
+ m_permissions = KFileItem::Unknown;
+ m_pMimeType = 0L;
+ m_user = TQString::null;
+ m_group = TQString::null;
+ m_metaInfo = KFileMetaInfo();
+ m_hidden = Auto;
+
+ // Basically, we can't trust any information we got while listing.
+ // Everything could have changed...
+ // Clearing m_entry makes it possible to detect changes in the size of the file,
+ // the time information, etc.
+ m_entry = TDEIO::UDSEntry();
+ init( false );
+}
+
+void KFileItem::refreshMimeType()
+{
+ m_pMimeType = 0L;
+ init( false ); // Will determine the mimetype
+}
+
+void KFileItem::setURL( const KURL &url )
+{
+ m_url = url;
+ setName( url.fileName() );
+}
+
+void KFileItem::setName( const TQString& name )
+{
+ m_strName = name;
+ m_strText = TDEIO::decodeFileName( m_strName );
+}
+
+TQString KFileItem::linkDest() const
+{
+ if (&m_entry == NULL) return TQString::null;
+
+ // Extract it from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it )
+ if ( (*it).m_uds == TDEIO::UDS_LINK_DEST )
+ return (*it).m_str;
+ // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL]
+ if ( m_bIsLocalURL )
+ {
+ char buf[1000];
+ int n = readlink( TQFile::encodeName(m_url.path( -1 )), buf, sizeof(buf)-1 );
+ if ( n != -1 )
+ {
+ buf[ n ] = 0;
+ return TQFile::decodeName( buf );
+ }
+ }
+ return TQString::null;
+}
+
+TQString KFileItem::localPath() const
+{
+ if ( m_bIsLocalURL )
+ {
+ return m_url.path();
+ }
+ else
+ {
+ if (&m_entry == NULL) return TQString::null;
+
+ // Extract the local path from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ const TDEIO::UDSEntry::ConstIterator end = m_entry.end();
+ for( ; it != end; ++it )
+ if ( (*it).m_uds == TDEIO::UDS_LOCAL_PATH )
+ return (*it).m_str;
+ }
+
+ return TQString::null;
+}
+
+TDEIO::filesize_t KFileItem::size(bool &exists) const
+{
+ exists = true;
+ if ( m_size != (TDEIO::filesize_t) -1 )
+ return m_size;
+
+ if (&m_entry == NULL) return 0L;
+
+ // Extract it from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it )
+ if ( (*it).m_uds == TDEIO::UDS_SIZE ) {
+ m_size = (*it).m_long;
+ return m_size;
+ }
+ // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
+ if ( m_bIsLocalURL )
+ {
+ KDE_struct_stat buf;
+ if ( KDE_stat( TQFile::encodeName(m_url.path( -1 )), &buf ) == 0 )
+ return buf.st_size;
+ }
+ exists = false;
+ return 0L;
+}
+
+bool KFileItem::hasExtendedACL() const
+{
+ if (&m_entry == NULL) return false;
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); it++ )
+ if ( (*it).m_uds == TDEIO::UDS_EXTENDED_ACL ) {
+ return true;
+ }
+ return false;
+}
+
+KACL KFileItem::ACL() const
+{
+ if ( hasExtendedACL() ) {
+ if (&m_entry == NULL) return KACL( m_permissions );
+
+ // Extract it from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it )
+ if ( (*it).m_uds == TDEIO::UDS_ACL_STRING )
+ return KACL((*it).m_str);
+ }
+ // create one from the basic permissions
+ return KACL( m_permissions );
+}
+
+KACL KFileItem::defaultACL() const
+{
+ if (&m_entry == NULL) return KACL();
+
+ // Extract it from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it )
+ if ( (*it).m_uds == TDEIO::UDS_DEFAULT_ACL_STRING )
+ return KACL((*it).m_str);
+ return KACL();
+}
+
+TDEIO::filesize_t KFileItem::size() const
+{
+ bool exists;
+ return size(exists);
+}
+
+time_t KFileItem::time( unsigned int which ) const
+{
+ bool hasTime;
+ return time(which, hasTime);
+}
+time_t KFileItem::time( unsigned int which, bool &hasTime ) const
+{
+ hasTime = true;
+ unsigned int mappedWhich = 0;
+
+ switch( which ) {
+ case TDEIO::UDS_MODIFICATION_TIME:
+ mappedWhich = Modification;
+ break;
+ case TDEIO::UDS_ACCESS_TIME:
+ mappedWhich = Access;
+ break;
+ case TDEIO::UDS_CREATION_TIME:
+ mappedWhich = Creation;
+ break;
+ }
+
+ if ( m_time[mappedWhich] != (time_t) -1 )
+ return m_time[mappedWhich];
+
+ if (&m_entry == NULL) return static_cast<time_t>(0);
+
+ // Extract it from the TDEIO::UDSEntry
+ TDEIO::UDSEntry::ConstIterator it = m_entry.begin();
+ for( ; it != m_entry.end(); ++it )
+ if ( (*it).m_uds == which ) {
+ m_time[mappedWhich] = static_cast<time_t>((*it).m_long);
+ return m_time[mappedWhich];
+ }
+
+ // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
+ if ( m_bIsLocalURL )
+ {
+ KDE_struct_stat buf;
+ if ( KDE_stat( TQFile::encodeName(m_url.path(-1)), &buf ) == 0 )
+ {
+ if(which == TDEIO::UDS_CREATION_TIME) {
+ // We can't determine creation time for local files
+ hasTime = false;
+ m_time[mappedWhich] = static_cast<time_t>(0);
+ return m_time[mappedWhich];
+ }
+ m_time[mappedWhich] = (which == TDEIO::UDS_MODIFICATION_TIME) ?
+ buf.st_mtime :
+ /* which == TDEIO::UDS_ACCESS_TIME)*/
+ buf.st_atime;
+ return m_time[mappedWhich];
+ }
+ }
+ hasTime = false;
+ return static_cast<time_t>(0);
+}
+
+
+TQString KFileItem::user() const
+{
+ if ( m_user.isEmpty() && m_bIsLocalURL )
+ {
+ KDE_struct_stat buff;
+ if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link
+ {
+ struct passwd *user = getpwuid( buff.st_uid );
+ if ( user != 0L )
+ m_user = TQString::fromLocal8Bit(user->pw_name);
+ }
+ }
+ return m_user;
+}
+
+TQString KFileItem::group() const
+{
+#ifdef Q_OS_UNIX
+ if (m_group.isEmpty() && m_bIsLocalURL )
+ {
+ KDE_struct_stat buff;
+ if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link
+ {
+ struct group *ge = getgrgid( buff.st_gid );
+ if ( ge != 0L ) {
+ m_group = TQString::fromLocal8Bit(ge->gr_name);
+ if (m_group.isEmpty())
+ m_group.sprintf("%d",ge->gr_gid);
+ } else
+ m_group.sprintf("%d",buff.st_gid);
+ }
+ }
+#endif
+ return m_group;
+}
+
+TQString KFileItem::mimetype() const
+{
+ KFileItem * that = const_cast<KFileItem *>(this);
+ return that->determineMimeType()->name();
+}
+
+KMimeType::Ptr KFileItem::determineMimeType()
+{
+ if ( !m_pMimeType || !m_bMimeTypeKnown )
+ {
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL );
+ //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl;
+ m_bMimeTypeKnown = true;
+ }
+
+ return m_pMimeType;
+}
+
+bool KFileItem::isMimeTypeKnown() const
+{
+ // The mimetype isn't known if determineMimeType was never called (on-demand determination)
+ // or if this fileitem has a guessed mimetype (e.g. ftp symlink) - in which case
+ // it always remains "not fully determined"
+ return m_bMimeTypeKnown && m_guessedMimeType.isEmpty();
+}
+
+TQString KFileItem::mimeComment()
+{
+ KMimeType::Ptr mType = determineMimeType();
+
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ TQString comment = mType->comment( url, isLocalURL );
+ //kdDebug() << "finding comment for " << url.url() << " : " << m_pMimeType->name() << endl;
+ if (!comment.isEmpty())
+ return comment;
+ else
+ return mType->name();
+}
+
+TQString KFileItem::iconName()
+{
+ if (d && (!d->iconName.isEmpty())) return d->iconName;
+
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ //kdDebug() << "finding icon for " << url.url() << " : " << m_pMimeType->name() << endl;
+ return determineMimeType()->icon(url, isLocalURL);
+}
+
+int KFileItem::overlays() const
+{
+ int _state = 0;
+ if ( m_bLink )
+ _state |= KIcon::LinkOverlay;
+
+ if ( !S_ISDIR( m_fileMode ) // Locked dirs have a special icon, use the overlay for files only
+ && !isReadable())
+ _state |= KIcon::LockOverlay;
+
+ if ( isHidden() )
+ _state |= KIcon::HiddenOverlay;
+
+ if( S_ISDIR( m_fileMode ) && m_bIsLocalURL)
+ {
+ if (KSambaShare::instance()->isDirectoryShared( m_url.path() ) ||
+ KNFSShare::instance()->isDirectoryShared( m_url.path() ))
+ {
+ //kdDebug()<<"KFileShare::isDirectoryShared : "<<m_url.path()<<endl;
+ _state |= KIcon::ShareOverlay;
+ }
+ }
+
+ if ( m_pMimeType->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" )
+ _state |= KIcon::ZipOverlay;
+ return _state;
+}
+
+TQPixmap KFileItem::pixmap( int _size, int _state ) const
+{
+ if (d && (!d->iconName.isEmpty()))
+ return DesktopIcon(d->iconName,_size,_state);
+
+ if ( !m_pMimeType )
+ {
+ static const TQString & defaultFolderIcon =
+ TDEGlobal::staticQString(KMimeType::mimeType( "inode/directory" )->KServiceType::icon());
+
+ if ( S_ISDIR( m_fileMode ) )
+ return DesktopIcon( defaultFolderIcon, _size, _state );
+
+ return DesktopIcon( "unknown", _size, _state );
+ }
+
+ _state |= overlays();
+
+ KMimeType::Ptr mime;
+ // Use guessed mimetype if the main one hasn't been determined for sure
+ if ( !m_bMimeTypeKnown && !m_guessedMimeType.isEmpty() )
+ mime = KMimeType::mimeType( m_guessedMimeType );
+ else
+ mime = m_pMimeType;
+
+ // Support for gzipped files: extract mimetype of contained file
+ // See also the relevant code in overlays, which adds the zip overlay.
+ if ( mime->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" )
+ {
+ KURL sf;
+ sf.setPath( m_url.path().left( m_url.path().length() - 3 ) );
+ //kdDebug() << "KFileItem::pixmap subFileName=" << subFileName << endl;
+ mime = KMimeType::findByURL( sf, 0, m_bIsLocalURL );
+ }
+
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ TQPixmap p = mime->pixmap( url, KIcon::Desktop, _size, _state );
+ //kdDebug() << "finding pixmap for " << url.url() << " : " << mime->name() << endl;
+ if (p.isNull())
+ kdWarning() << "Pixmap not found for mimetype " << m_pMimeType->name() << endl;
+
+ if ( mime->name() == "application/x-executable" ) {
+ // At first glance it might seem to be a good idea to
+ // look for .desktop files for this executable before resorting to the embedded icon
+ // in the same fashion as the minicli, but on close examination this is NOT A GOOD IDEA.
+ // Specifically it allows one executable to mimic another purely based on filename,
+ // which could at certain times fool any user regardless of experience level.
+#ifdef HAVE_ELFICON
+ // Check for an embedded icon
+ unsigned int icon_size;
+ libr_icon *icon = NULL;
+ libr_file *handle = NULL;
+ libr_access_t access = LIBR_READ;
+
+ if((handle = libr_open(const_cast<char*>(url.path().ascii()), access)) == NULL)
+ {
+ kdWarning() << "failed to open file" << url.path() << endl;
+ return p;
+ }
+
+ icon_size = _size;
+ icon = libr_icon_geticon_bysize(handle, icon_size);
+
+ // See if the embedded icon name matches any icon file names already on the system
+ // If it does, use the system icon instead of the embedded one
+ int iconresnamefound = 0;
+ iconentry *entry = NULL;
+ iconlist icons;
+ if(!get_iconlist(handle, &icons))
+ {
+ // Failed to obtain a list of ELF icons
+ kdWarning() << "failed to obtain ELF icon: " << libr_errmsg() << endl;
+
+ // See if there is a system icon we can use
+ TQString sysIconName = elf_get_resource(handle, ".metadata_sysicon");
+ if (!sysIconName.isEmpty()) {
+ if (TDEGlobal::iconLoader()->iconPath(sysIconName.ascii(), 0, true) != "") {
+ p = DesktopIcon( sysIconName.ascii(), _size, _state );
+ }
+ }
+
+ libr_close(handle);
+ return p;
+ }
+ else {
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(icon == NULL)
+ {
+ // Try loading this icon as fallback
+ icon = libr_icon_geticon_byname(handle, entry->name);
+ }
+ if (TDEGlobal::iconLoader()->iconPath(entry->name, 0, true) != "") {
+ iconresnamefound = 1;
+ p = DesktopIcon( entry->name, _size, _state );
+ break;
+ }
+ }
+ }
+
+ if ((iconresnamefound == 0) && (icon)) {
+ // Extract the embedded icon
+ size_t icon_data_length;
+ char* icondata = libr_icon_malloc(icon, &icon_data_length);
+ p.loadFromData(static_cast<uchar*>(static_cast<void*>(icondata)), icon_data_length); // EVIL CAST
+ if (icon_size != 0) {
+ TQImage ip = p.convertToImage();
+ ip = ip.smoothScale(icon_size, icon_size);
+ p.convertFromImage(ip);
+ }
+ free(icondata);
+ libr_icon_close(icon);
+ }
+
+ libr_close(handle);
+#endif // HAVE_ELFICON
+ }
+
+ return p;
+}
+
+bool KFileItem::isReadable() const
+{
+ /*
+ struct passwd * user = getpwuid( geteuid() );
+ bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user);
+ // This gets ugly for the group....
+ // Maybe we want a static TQString for the user and a static QStringList
+ // for the groups... then we need to handle the deletion properly...
+ */
+
+ if ( m_permissions != KFileItem::Unknown ) {
+ // No read permission at all
+ if ( !(S_IRUSR & m_permissions) && !(S_IRGRP & m_permissions) && !(S_IROTH & m_permissions) )
+ return false;
+
+ // Read permissions for all: save a stat call
+ if ( (S_IRUSR|S_IRGRP|S_IROTH) & m_permissions )
+ return true;
+ }
+
+ // Or if we can't read it [using ::access()] - not network transparent
+ if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), R_OK ) == -1 )
+ return false;
+
+ return true;
+}
+
+bool KFileItem::isWritable() const
+{
+ /*
+ struct passwd * user = getpwuid( geteuid() );
+ bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user);
+ // This gets ugly for the group....
+ // Maybe we want a static TQString for the user and a static QStringList
+ // for the groups... then we need to handle the deletion properly...
+ */
+
+ if ( m_permissions != KFileItem::Unknown ) {
+ // No write permission at all
+ if ( !(S_IWUSR & m_permissions) && !(S_IWGRP & m_permissions) && !(S_IWOTH & m_permissions) )
+ return false;
+ }
+
+ // Or if we can't read it [using ::access()] - not network transparent
+ if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), W_OK ) == -1 )
+ return false;
+
+ return true;
+}
+
+bool KFileItem::isHidden() const
+{
+ if ( m_hidden != Auto )
+ return m_hidden == Hidden;
+
+ if ( !m_url.isEmpty() )
+ return m_url.fileName()[0] == '.';
+ else // should never happen
+ return m_strName[0] == '.';
+}
+
+bool KFileItem::isDir() const
+{
+ if ( m_fileMode == KFileItem::Unknown )
+ {
+ kdDebug() << " KFileItem::isDir can't say -> false " << endl;
+ return false; // can't say for sure, so no
+ }
+ return (S_ISDIR(m_fileMode));
+/*
+ if (!S_ISDIR(m_fileMode)) {
+ if (m_url.isLocalFile()) {
+ KMimeType::Ptr ptr=KMimeType::findByURL(m_url,0,true,true);
+ if ((ptr!=0) && (ptr->is("directory/inode"))) return true;
+ }
+ return false
+ } else return true;*/
+}
+
+bool KFileItem::acceptsDrops()
+{
+ // A directory ?
+ if ( S_ISDIR( mode() ) ) {
+ return isWritable();
+ }
+
+ // But only local .desktop files and executables
+ if ( !m_bIsLocalURL )
+ return false;
+
+ if (( mimetype() == "application/x-desktop") ||
+ ( mimetype() == "media/builtin-mydocuments") ||
+ ( mimetype() == "media/builtin-mycomputer") ||
+ ( mimetype() == "media/builtin-mynetworkplaces") ||
+ ( mimetype() == "media/builtin-printers") ||
+ ( mimetype() == "media/builtin-trash") ||
+ ( mimetype() == "media/builtin-webbrowser"))
+ return true;
+
+ // Executable, shell script ... ?
+ if ( ::access( TQFile::encodeName(m_url.path()), X_OK ) == 0 )
+ return true;
+
+ return false;
+}
+
+TQString KFileItem::getStatusBarInfo()
+{
+ TQString text = m_strText;
+
+ if ( m_bLink )
+ {
+ TQString comment = determineMimeType()->comment( m_url, m_bIsLocalURL );
+ TQString tmp;
+ if ( comment.isEmpty() )
+ tmp = i18n ( "Symbolic Link" );
+ else
+ tmp = i18n("%1 (Link)").arg(comment);
+ text += "->";
+ text += linkDest();
+ text += " ";
+ text += tmp;
+ }
+ else if ( S_ISREG( m_fileMode ) )
+ {
+ bool hasSize;
+ TDEIO::filesize_t sizeValue = size(hasSize);
+ if(hasSize)
+ text += TQString(" (%1) ").arg( TDEIO::convertSize( sizeValue ) );
+ text += mimeComment();
+ }
+ else if ( S_ISDIR ( m_fileMode ) )
+ {
+ text += "/ ";
+ text += mimeComment();
+ }
+ else
+ {
+ text += " ";
+ text += mimeComment();
+ }
+ text.replace('\n', " "); // replace any newlines with a space, so the statusbar doesn't get a two-line string which messes the display up, Alex
+ return text;
+}
+
+TQString KFileItem::getToolTipText(int maxcount)
+{
+ // we can return TQString::null if no tool tip should be shown
+ TQString tip;
+ KFileMetaInfo info = metaInfo();
+
+ // the font tags are a workaround for the fact that the tool tip gets
+ // screwed if the color scheme uses white as default text color
+ const char* start = "<tr><td><nobr><font color=\"black\">";
+ const char* mid = "</font></nobr></td><td><nobr><font color=\"black\">";
+ const char* end = "</font></nobr></td></tr>";
+
+ tip = "<table cellspacing=0 cellpadding=0>";
+
+ tip += start + i18n("Name:") + mid + text() + end;
+ tip += start + i18n("Type:") + mid;
+
+ TQString type = TQStyleSheet::escape(mimeComment());
+ if ( m_bLink ) {
+ tip += i18n("Link to %1 (%2)").arg(linkDest(), type) + end;
+ } else
+ tip += type + end;
+
+ if ( !S_ISDIR ( m_fileMode ) ) {
+ bool hasSize;
+ TDEIO::filesize_t sizeValue = size(hasSize);
+ if(hasSize)
+ tip += start + i18n("Size:") + mid +
+ TDEIO::convertSizeWithBytes(sizeValue) + end;
+ }
+ TQString timeStr = timeString( TDEIO::UDS_MODIFICATION_TIME);
+ if(!timeStr.isEmpty())
+ tip += start + i18n("Modified:") + mid +
+ timeStr + end;
+#ifndef Q_WS_WIN //TODO: show win32-specific permissions
+ TQString userStr = user();
+ TQString groupStr = group();
+ if(!userStr.isEmpty() || !groupStr.isEmpty())
+ tip += start + i18n("Owner:") + mid + userStr + " - " + groupStr + end +
+ start + i18n("Permissions:") + mid +
+ parsePermissions(m_permissions) + end;
+#endif
+
+ if (info.isValid() && !info.isEmpty() )
+ {
+ tip += "<tr><td colspan=2><center><s>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</s></center></td></tr>";
+ TQStringList keys = info.preferredKeys();
+
+ // now the rest
+ TQStringList::Iterator it = keys.begin();
+ for (int count = 0; count<maxcount && it!=keys.end() ; ++it)
+ {
+ KFileMetaInfoItem item = info.item( *it );
+ if ( item.isValid() )
+ {
+ TQString s = item.string();
+ if ( ( item.attributes() & KFileMimeTypeInfo::SqueezeText )
+ && s.length() > 50) {
+ s.truncate(47);
+ s.append("...");
+ }
+ if ( !s.isEmpty() )
+ {
+ count++;
+ tip += start +
+ TQStyleSheet::escape( item.translatedKey() ) + ":" +
+ mid +
+ TQStyleSheet::escape( s ) +
+ end;
+ }
+
+ }
+ }
+ }
+ tip += "</table>";
+
+ //kdDebug() << "making this the tool tip rich text:\n";
+ //kdDebug() << tip << endl;
+
+ return tip;
+}
+
+void KFileItem::run()
+{
+ // It might be faster to pass skip that when we know the mimetype,
+ // and just call KRun::runURL. But then we need to use mostLocalURL()
+ // for application/x-desktop files, to be able to execute them.
+ (void) new KRun( m_url, m_fileMode, m_bIsLocalURL );
+}
+
+bool KFileItem::cmp( const KFileItem & item )
+{
+ bool hasSize1,hasSize2,hasTime1,hasTime2;
+ hasSize1 = hasSize2 = hasTime1 = hasTime2 = false;
+ return ( m_strName == item.m_strName
+ && m_bIsLocalURL == item.m_bIsLocalURL
+ && m_fileMode == item.m_fileMode
+ && m_permissions == item.m_permissions
+ && m_user == item.m_user
+ && m_group == item.m_group
+ && m_bLink == item.m_bLink
+ && m_hidden == item.m_hidden
+ && size(hasSize1) == item.size(hasSize2)
+ && hasSize1 == hasSize2
+ && time(TDEIO::UDS_MODIFICATION_TIME, hasTime1) == item.time(TDEIO::UDS_MODIFICATION_TIME, hasTime2)
+ && hasTime1 == hasTime2
+ && (!d || !item.d || d->iconName == item.d->iconName) );
+
+ // Don't compare the mimetypes here. They might not be known, and we don't want to
+ // do the slow operation of determining them here.
+}
+
+void KFileItem::assign( const KFileItem & item )
+{
+ if ( this == &item )
+ return;
+ m_entry = item.m_entry;
+ m_url = item.m_url;
+ m_bIsLocalURL = item.m_bIsLocalURL;
+ m_strName = item.m_strName;
+ m_strText = item.m_strText;
+ m_fileMode = item.m_fileMode;
+ m_permissions = item.m_permissions;
+ m_user = item.m_user;
+ m_group = item.m_group;
+ m_bLink = item.m_bLink;
+ m_pMimeType = item.m_pMimeType;
+ m_strLowerCaseName = item.m_strLowerCaseName;
+ m_bMimeTypeKnown = item.m_bMimeTypeKnown;
+ m_hidden = item.m_hidden;
+ m_guessedMimeType = item.m_guessedMimeType;
+ m_access = item.m_access;
+ m_metaInfo = item.m_metaInfo;
+ for ( int i = 0; i < NumFlags; i++ )
+ m_time[i] = item.m_time[i];
+ m_size = item.m_size;
+ // note: m_extra is NOT copied, as we'd have no control over who is
+ // deleting the data or not.
+
+ // We had a mimetype previously (probably), so we need to re-determine it
+ determineMimeType();
+
+ if ( item.d ) {
+ if ( !d )
+ d = new KFileItemPrivate;
+ d->iconName = item.d->iconName;
+ } else {
+ delete d;
+ d = 0;
+ }
+}
+
+void KFileItem::setUDSEntry( const TDEIO::UDSEntry& _entry, const KURL& _url,
+ bool _determineMimeTypeOnDemand, bool _urlIsDirectory )
+{
+ m_entry = _entry;
+ m_url = _url;
+ m_strName = TQString::null;
+ m_strText = TQString::null;
+ m_user = TQString::null;
+ m_group = TQString::null;
+ m_strLowerCaseName = TQString::null;
+ m_pMimeType = 0;
+ m_fileMode = KFileItem::Unknown;
+ m_permissions = KFileItem::Unknown;
+ m_bMarked = false;
+ m_bLink = false;
+ m_bIsLocalURL = _url.isLocalFile();
+ m_bMimeTypeKnown = false;
+ m_hidden = Auto;
+ m_guessedMimeType = TQString::null;
+ m_metaInfo = KFileMetaInfo();
+
+ if ( d )
+ d->iconName = TQString::null;
+
+ readUDSEntry( _urlIsDirectory );
+ init( _determineMimeTypeOnDemand );
+}
+
+void KFileItem::setFileMode( mode_t m )
+{
+ m_fileMode = m;
+}
+
+void KFileItem::setMimeType( const TQString& mimetype )
+{
+ m_pMimeType = KMimeType::mimeType( mimetype );
+}
+
+void KFileItem::setExtraData( const void *key, void *value )
+{
+ if ( !key )
+ return;
+
+ m_extra.replace( key, value );
+}
+
+const void * KFileItem::extraData( const void *key ) const
+{
+ TQMapConstIterator<const void*,void*> it = m_extra.find( key );
+ if ( it != m_extra.end() )
+ return it.data();
+ return 0L;
+}
+
+void * KFileItem::extraData( const void *key )
+{
+ TQMapIterator<const void*,void*> it = m_extra.find( key );
+ if ( it != m_extra.end() )
+ return it.data();
+ return 0L;
+}
+
+void KFileItem::removeExtraData( const void *key )
+{
+ m_extra.remove( key );
+}
+
+TQString KFileItem::permissionsString() const
+{
+ if (m_access.isNull())
+ m_access = parsePermissions( m_permissions );
+
+ return m_access;
+}
+
+TQString KFileItem::parsePermissions(mode_t perm) const
+{
+ char p[] = "---------- ";
+
+ if (isDir())
+ p[0]='d';
+ else if (isLink())
+ p[0]='l';
+
+ if (perm & TQFileInfo::ReadUser)
+ p[1]='r';
+ if (perm & TQFileInfo::WriteUser)
+ p[2]='w';
+ if ((perm & TQFileInfo::ExeUser) && !(perm & S_ISUID)) p[3]='x';
+ else if ((perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='s';
+ else if (!(perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='S';
+
+ if (perm & TQFileInfo::ReadGroup)
+ p[4]='r';
+ if (perm & TQFileInfo::WriteGroup)
+ p[5]='w';
+ if ((perm & TQFileInfo::ExeGroup) && !(perm & S_ISGID)) p[6]='x';
+ else if ((perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='s';
+ else if (!(perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='S';
+
+ if (perm & TQFileInfo::ReadOther)
+ p[7]='r';
+ if (perm & TQFileInfo::WriteOther)
+ p[8]='w';
+ if ((perm & TQFileInfo::ExeOther) && !(perm & S_ISVTX)) p[9]='x';
+ else if ((perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='t';
+ else if (!(perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='T';
+
+ if (hasExtendedACL())
+ p[10]='+';
+
+ return TQString::fromLatin1(p);
+}
+
+// check if we need to cache this
+TQString KFileItem::timeString( unsigned int which ) const
+{
+ bool hasTime;
+ time_t time_ = time(which, hasTime);
+ if(!hasTime) return TQString::null;
+
+ TQDateTime t;
+ t.setTime_t( time_);
+ return TDEGlobal::locale()->formatDateTime( t );
+}
+
+void KFileItem::setMetaInfo( const KFileMetaInfo & info )
+{
+ m_metaInfo = info;
+}
+
+const KFileMetaInfo & KFileItem::metaInfo(bool autoget, int) const
+{
+ bool isLocalURL;
+ KURL url = mostLocalURL(isLocalURL);
+
+ if ( autoget && !m_metaInfo.isValid() &&
+ TDEGlobalSettings::showFilePreview(url) )
+ {
+ m_metaInfo = KFileMetaInfo( url, mimetype() );
+ }
+
+ return m_metaInfo;
+}
+
+KURL KFileItem::mostLocalURL(bool &local) const
+{
+ TQString local_path = localPath();
+
+ if ( !local_path.isEmpty() )
+ {
+ local = true;
+ KURL url;
+ url.setPath(local_path);
+ return url;
+ }
+ else
+ {
+ local = m_bIsLocalURL;
+ return m_url;
+ }
+}
+
+void KFileItem::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+TQDataStream & operator<< ( TQDataStream & s, const KFileItem & a )
+{
+ // We don't need to save/restore anything that refresh() invalidates,
+ // since that means we can re-determine those by ourselves.
+ s << a.m_url;
+ s << a.m_strName;
+ s << a.m_strText;
+ return s;
+}
+
+TQDataStream & operator>> ( TQDataStream & s, KFileItem & a )
+{
+ s >> a.m_url;
+ s >> a.m_strName;
+ s >> a.m_strText;
+ a.m_bIsLocalURL = a.m_url.isLocalFile();
+ a.m_bMimeTypeKnown = false;
+ a.refresh();
+ return s;
+}
diff --git a/tdeio/tdeio/tdefileitem.h b/tdeio/tdeio/tdefileitem.h
new file mode 100644
index 000000000..7097d7bc5
--- /dev/null
+++ b/tdeio/tdeio/tdefileitem.h
@@ -0,0 +1,671 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 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 __tdefileitem_h__
+#define __tdefileitem_h__
+
+#include <tqstringlist.h>
+#include <sys/stat.h>
+
+#include <tqptrlist.h>
+#include <tdeio/global.h>
+#include <kurl.h>
+#include <kacl.h>
+#include <kmimetype.h>
+#include <tdefilemetainfo.h>
+
+#define KFILEITEM_HAS_ISWRITABLE // only used in libkonq/konq_iconviewwidget.cc, will be removed for 3.4
+
+/**
+ * A KFileItem is a generic class to handle a file, local or remote.
+ * In particular, it makes it easier to handle the result of TDEIO::listDir
+ * (UDSEntry isn't very friendly to use).
+ * It includes many file attributes such as mimetype, icon, text, mode, link...
+ */
+class TDEIO_EXPORT KFileItem
+{
+public:
+ enum { Unknown = (mode_t) - 1 };
+
+ /**
+ * Creates an item representing a file, from a UDSEntry.
+ * This is the preferred constructor when using TDEIO::listDir().
+ *
+ * @param _entry the KIO entry used to get the file, contains info about it
+ * @param _url the file url
+ * @param _determineMimeTypeOnDemand specifies if the mimetype of the given
+ * URL should be determined immediately or on demand
+ * @param _urlIsDirectory specifies if the url is just the directory of the
+ * fileitem and the filename from the UDSEntry should be used.
+ */
+ KFileItem( const TDEIO::UDSEntry& _entry, const KURL& _url,
+ bool _determineMimeTypeOnDemand = false,
+ bool _urlIsDirectory = false );
+
+ /**
+ * Creates an item representing a file, from all the necessary info for it.
+ * @param _mode the file mode (according to stat() (e.g. S_IFDIR...)
+ * Set to KFileItem::Unknown if unknown. For local files, KFileItem will use stat().
+ * @param _permissions the access permissions
+ * If you set both the mode and the permissions, you save a ::stat() for
+ * local files.
+ * Set to KFileItem::Unknown if you don't know the mode or the permission.
+ * @param _url the file url
+ *
+ * @param _determineMimeTypeOnDemand specify if the mimetype of the given URL
+ * should be determined immediately or on demand
+ */
+ KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url,
+ bool _determineMimeTypeOnDemand = false );
+
+ /**
+ * Creates an item representing a file, for which the mimetype is already known.
+ * @param url the file url
+ * @param mimeType the name of the file's mimetype
+ * @param mode the mode (S_IFDIR...)
+ */
+ KFileItem( const KURL &url, const TQString &mimeType, mode_t mode );
+
+ /**
+ * Copy constructor. Note that extra-data set via setExtraData() is not
+ * deeply copied -- just the pointers are copied.
+ */
+ KFileItem( const KFileItem &item );
+
+ /**
+ * Destructs the KFileItem. Extra data set via setExtraData()
+ * is not deleted.
+ */
+ virtual ~KFileItem();
+
+ /**
+ * Throw away and re-read (for local files) all information about the file.
+ * This is called when the _file_ changes.
+ */
+ void refresh();
+
+ /**
+ * Re-reads mimetype information.
+ * This is called when the mimetype database changes.
+ */
+ void refreshMimeType();
+
+ /**
+ * Returns the url of the file.
+ * @return the url of the file
+ */
+ const KURL & url() const { return m_url; }
+
+ /**
+ * Sets the item's URL. Do not call unless you know what you are doing!
+ * (used for example when an item got renamed).
+ * @param url the item's URL
+ */
+ void setURL( const KURL &url );
+
+ /**
+ * Sets the item's name (i.e. the filename).
+ * This is automatically done by setURL, to set the name from the URL's fileName().
+ * This method is provided for some special cases like relative paths as names (KFindPart)
+ * @param name the item's name
+ */
+ void setName( const TQString &name );
+
+ /**
+ * Returns the permissions of the file (stat.st_mode containing only permissions).
+ * @return the permissions of the file
+ */
+ mode_t permissions() const { return m_permissions; }
+
+ /**
+ * Returns the access permissions for the file as a string.
+ * @return the access persmission as string
+ */
+ TQString permissionsString() const;
+
+ /**
+ * Tells if the file has extended access level information ( Posix ACL )
+ * @return true if the file has extend ACL information or false if it hasn't
+ * @since 3.5
+ */
+ bool hasExtendedACL() const;
+
+ /**
+ * Returns the access control list for the file.
+ * @return the access control list as a KACL
+ * @since 3.5
+ */
+ KACL ACL() const;
+
+ /**
+ * Returns the default access control list for the directory.
+ * @return the default access control list as a KACL
+ * @since 3.5
+ */
+ KACL defaultACL() const;
+
+ /**
+ * Returns the file type (stat.st_mode containing only S_IFDIR, S_IFLNK, ...).
+ * @return the file type
+ */
+ mode_t mode() const { return m_fileMode; }
+
+ /**
+ * Returns the owner of the file.
+ * @return the file's owner
+ */
+ TQString user() const;
+
+ /**
+ * Returns the group of the file.
+ * @return the file's group
+ */
+ TQString group() const;
+
+ /**
+ * Returns true if this item represents a link in the UNIX sense of
+ * a link.
+ * @return true if the file is a link
+ */
+ bool isLink() const { return m_bLink; }
+
+ /**
+ * Returns true if this item represents a directory.
+ * @return true if the item is a directory
+ */
+ bool isDir() const;
+
+ /**
+ * Returns true if this item represents a file (and not a a directory)
+ * @return true if the item is a file
+ */
+ bool isFile() const { return !isDir(); }
+
+ /**
+ * Checks whether the file or directory is readable. In some cases
+ * (remote files), we may return true even though it can't be read.
+ * @return true if the file can be read - more precisely,
+ * false if we know for sure it can't
+ */
+ bool isReadable() const;
+
+ /**
+ * Checks whether the file or directory is writable. In some cases
+ * (remote files), we may return true even though it can't be written to.
+ * @return true if the file or directory can be written to - more precisely,
+ * false if we know for sure it can't
+ * @since 3.4
+ */
+ bool isWritable() const;
+
+ /**
+ * Checks whether the file is hidden.
+ * @return true if the file is hidden.
+ */
+ bool isHidden() const;
+
+ /**
+ * Returns the link destination if isLink() == true.
+ * @return the link destination. TQString::null if the item is not a link
+ */
+ TQString linkDest() const;
+
+ /**
+ * Returns the local path if isLocalFile() == true or the KIO item has
+ * a UDS_LOCAL_PATH atom.
+ * @return the item local path, or TQString::null if not known
+ * @since 3.4
+ */
+ TQString localPath() const;
+
+ //FIXME KDE4 deprecate this in favor of size(bool &hasSize)
+ /**
+ * Returns the size of the file, if known.
+ * @return the file size, or 0 if not known
+ */
+ TDEIO::filesize_t size() const;
+
+ /**
+ * Returns the size of the file, if known, and sets @p hasSize to false if not known
+ * @param @hasSize This is set to true if the size is known, and false if not known
+ * @return the file size, or 0 if not known
+ */
+ TDEIO::filesize_t size(bool &hasSize) const;
+
+ //FIXME KDE4 deprecate this in favor of time(unsigned int which, bool &hasSize)
+ /**
+ * Requests the modification, access or creation time, depending on @p which.
+ * @param which UDS_MODIFICATION_TIME, UDS_ACCESS_TIME or UDS_CREATION_TIME
+ * @return the time asked for, (time_t)0 if not available
+ * @see timeString()
+ */
+ time_t time( unsigned int which ) const;
+
+ /**
+ * Requests the modification, access or creation time, depending on @p which.
+ * @param which UDS_MODIFICATION_TIME, UDS_ACCESS_TIME or UDS_CREATION_TIME
+ * @param hasTime This is set to true is the time is known, and false if not known
+ * @return the time asked for, (time_t)0 if not known/available
+ * @see timeString()
+ */
+ time_t time( unsigned int which, bool &hasTime ) const;
+
+ /**
+ * Requests the modification, access or creation time as a string, depending
+ * on @p which.
+ * @param which UDS_MODIFICATION_TIME, UDS_ACCESS_TIME or UDS_CREATION_TIME
+ * @returns a formatted string of the requested time, TQString::null if time is not known
+ * @see time
+ */
+ TQString timeString( unsigned int which = TDEIO::UDS_MODIFICATION_TIME ) const;
+
+ /**
+ * Returns true if the file is a local file.
+ * @return true if the file is local, false otherwise
+ */
+ bool isLocalFile() const { return m_bIsLocalURL; }
+
+ /**
+ * Returns the text of the file item.
+ * It's not exactly the filename since some decoding happens ('%2F'->'/').
+ * @return the text of the file item
+ */
+ const TQString& text() const { return m_strText; }
+
+ /**
+ * Return the name of the file item (without a path).
+ * Similar to text(), but unencoded, i.e. the original name.
+ * @param lowerCase if true, the name will be returned in lower case,
+ * which is useful to speed up sorting by name, case insensitively.
+ * @return the file's name
+ */
+ const TQString& name( bool lowerCase = false ) const {
+ if ( !lowerCase )
+ return m_strName;
+ else
+ if ( m_strLowerCaseName.isNull() )
+ m_strLowerCaseName = m_strName.lower();
+ return m_strLowerCaseName;
+ }
+
+ /**
+ * Returns the mimetype of the file item.
+ * If @p _determineMimeTypeOnDemand was used in the constructor, this will determine
+ * the mimetype first. Equivalent to determineMimeType()->name()
+ * @return the mime type of the file
+ */
+ TQString mimetype() const;
+
+ /**
+ * Returns the mimetype of the file item.
+ * If _determineMimeTypeOnDemand was used in the constructor, this will determine
+ * the mimetype first.
+ * @return the mime type
+ */
+ KMimeType::Ptr determineMimeType();
+
+ /**
+ * Returns the currently known mimetype of the file item.
+ * This will not try to determine the mimetype if unknown.
+ * @return the known mime type
+ */
+ KMimeType::Ptr mimeTypePtr() const { return m_pMimeType; }
+
+ bool isMimeTypeKnown() const;
+ /**
+ * Returns the descriptive comment for this mime type, or
+ * the mime type itself if none is present.
+ * @return the mime type description, or the mime type itself
+ */
+ TQString mimeComment();
+
+ /**
+ * Returns the full path name to the icon that represents
+ * this mime type.
+ * @return iconName the name of the file's icon
+ */
+ TQString iconName();
+
+ /**
+ * Returns a pixmap representing the file.
+ * @param _size Size for the pixmap in pixels. Zero will return the
+ * globally configured default size.
+ * @param _state The state of the icon: KIcon::DefaultState,
+ * KIcon::ActiveState or KIcon::DisabledState.
+ * @return the pixmap
+ */
+ TQPixmap pixmap( int _size, int _state=0 ) const;
+
+ /**
+ * Returns the overlays (bitfield of KIcon::*Overlay flags) that are used
+ * for this item's pixmap. Overlays are used to show for example, whether
+ * a file can be modified.
+ * @return the overlays of the pixmap
+ */
+ int overlays() const;
+
+ /**
+ * Returns the string to be displayed in the statusbar,
+ * e.g. when the mouse is over this item
+ * @return the status bar information
+ */
+ TQString getStatusBarInfo();
+
+ /**
+ * Returns the string to be displayed in the tool tip when the mouse
+ * is over this item. This may load a plugin to determine additional
+ * information specific to the mimetype of the file.
+ *
+ * @param maxcount the maximum number of entries shown
+ * @return the tool tip string
+ */
+ TQString getToolTipText(int maxcount = 6);
+
+ /**
+ * Returns true if files can be dropped over this item.
+ * Contrary to popular belief, not only dirs will return true :)
+ * Executables, .desktop files, will do so as well.
+ * @return true if you can drop files over the item
+ */
+ bool acceptsDrops( );
+
+ /**
+ * Let's "KRun" this file !
+ * (e.g. when file is clicked or double-clicked or return is pressed)
+ */
+ void run();
+
+ /**
+ * Returns the UDS entry. Used by the tree view to access all details
+ * by position.
+ * @return the UDS entry
+ */
+ const TDEIO::UDSEntry & entry() const { return m_entry; }
+
+ /**
+ * Used when updating a directory. marked == seen when refreshing.
+ * @return true if the file item is marked
+ */
+ bool isMarked() const { return m_bMarked; }
+ /**
+ * Marks the item.
+ * @see isMarked()
+ */
+ void mark() { m_bMarked = true; }
+ /**
+ * Unmarks the item.
+ * @see isMarked()
+ */
+ void unmark() { m_bMarked = false; }
+
+ /**
+ * Somewhat like a comparison operator, but more explicit.
+ * @param item the item to compare
+ * @return true if all values are equal
+ */
+ bool cmp( const KFileItem & item );
+
+ /**
+ * This allows to associate some "extra" data to a KFileItem. As one
+ * KFileItem can be used by several objects (often views) which all need
+ * to add some data, you have to use a key to reference your extra data
+ * within the KFileItem.
+ *
+ * That way a KFileItem can hold and provide access to all those views
+ * separately.
+ *
+ * I.e. a KFileIconView that associates a KFileIconViewItem (an item suitable
+ * for use with TQIconView) does
+ *
+ * \code
+ * tdefileItem->setExtraData( this, iconViewItem );
+ * \endcode
+ *
+ * and can later access the iconViewItem by doing
+ *
+ * \code
+ * KFileIconViewItem *iconViewItem = static_cast<KFileIconViewItem*>( tdefileItem->extraData( this ));
+ * \endcode
+ *
+ * This is usually more efficient then having every view associate data to
+ * items by using a separate TQDict or TQMap.
+ *
+ * Note: you have to remove and destroy the data you associated yourself
+ * when you don't need it anymore!
+ *
+ * @param key the key of the extra data
+ * @param value the value of the extra data
+ * @see extraData
+ * @see removeExtraData
+ */
+ virtual void setExtraData( const void *key, void *value );
+
+ /**
+ * Retrieves the extra data with the given @p key.
+ * @param key the key of the extra data
+ * @return the extra data associated to an item with @p key via
+ * setExtraData. 0L if nothing was associated with @p key.
+ * @see extraData
+ */
+ virtual const void * extraData( const void *key ) const;
+
+ /**
+ * Retrieves the extra data with the given @p key.
+ * @param key the key of the extra data
+ * @return the extra data associated to an item with @p key via
+ * setExtraData. 0L if nothing was associated with @p key.
+ * @see extraData
+ */
+ virtual void * extraData( const void *key );
+
+ /**
+ * Removes the extra data associated with an item via @p key.
+ * @param key the key of the extra data to remove
+ */
+ virtual void removeExtraData( const void *key );
+
+ /**
+ * Sets the metainfo of this item to @p info.
+ * @param info the new meta info
+ */
+ void setMetaInfo( const KFileMetaInfo & info );
+
+ /**
+ * Sets the file type (stat.st_mode containing only S_IFDIR, S_IFLNK, ...).
+ * @param m the new file type
+ * @since 3.5.0
+ * @todo Actually explain what this does -- does setting S_IFDIR
+ * mean the file type is set to Directory?
+ */
+ void setFileMode( mode_t m );
+
+ /**
+ * Sets new mimetype for item
+ * @param mimetype the new mimetype
+ * @since 3.5.0
+ */
+ void setMimeType( const TQString& mimetype );
+
+ /**
+ * Returns the metainfo of this item.
+ * @param autoget if true, the metainfo will automatically be created
+ * @param what ignored
+ */
+ const KFileMetaInfo & metaInfo(bool autoget = true,
+ int what = KFileMetaInfo::Fastest) const;
+
+ /**
+ * Somewhat like an assignment operator, but more explicit.
+ * Note: extra-data set with setExtraData() is not copied, so be careful
+ * what you do!
+ *
+ * @param item the item to copy
+ */
+ void assign( const KFileItem & item );
+
+ /**
+ * Reinitialize KFileItem with a new UDSEntry.
+ *
+ * Note: extra-data set with setExtraData() is not changed or deleted, so
+ * be careful what you do!
+ *
+ * KDirListerCache uses it to save new/delete calls by updating existing
+ * items that are otherwise not needed anymore.
+ *
+ * @param entry the UDSEntry to assign to this KFileItem
+ * @param url the file url
+ * @param determineMimeTypeOnDemand specifies if the mimetype of the given
+ * URL should be determined immediately or on demand
+ * @param urlIsDirectory specifies if the url is just the directory of the
+ * fileitem and the filename from the UDSEntry should be used.
+ * @since 3.4.1
+ */
+ void setUDSEntry( const TDEIO::UDSEntry& entry, const KURL& url,
+ bool determineMimeTypeOnDemand = false,
+ bool urlIsDirectory = false );
+
+ /**
+ * Assignment operator, calls assign()
+ */
+ KFileItem& operator=( const KFileItem& );
+
+ /**
+ * Tries to give a local URL for this file item if possible.
+ * The given boolean indicates if the returned url is local or not.
+ */
+ KURL mostLocalURL(bool &local) const;
+
+ /////////////
+
+protected:
+ /**
+ * Computes the text, mode, and mimetype from the UDSEntry
+ * Called by constructor, but can be called again later
+ */
+ void init( bool _determineMimeTypeOnDemand );
+
+ /**
+ * Extracts the data from the UDSEntry member and updates the KFileItem
+ * accordingly.
+ * @since 3.4.1
+ */
+ void readUDSEntry( bool _urlIsDirectory );
+
+ /**
+ * Parses the given permission set and provides it for access()
+ */
+ TQString parsePermissions( mode_t perm ) const;
+
+private:
+ /**
+ * We keep a copy of the UDSEntry since we need it for getStatusBarInfo
+ */
+ TDEIO::UDSEntry m_entry;
+ /**
+ * The url of the file
+ */
+ KURL m_url;
+
+ /**
+ * The text for this item, i.e. the file name without path,
+ */
+ TQString m_strName;
+
+ /**
+ * The text for this item, i.e. the file name without path, decoded
+ * ('%%' becomes '%', '%2F' becomes '/')
+ */
+ TQString m_strText;
+
+ /**
+ * the user and group assigned to the file.
+ */
+ mutable TQString m_user, m_group;
+
+ /**
+ * The filename in lower case (to speed up sorting)
+ */
+ mutable TQString m_strLowerCaseName;
+
+ /**
+ * The mimetype of the file
+ */
+ KMimeType::Ptr m_pMimeType;
+
+ /**
+ * The file mode
+ */
+ mode_t m_fileMode;
+ /**
+ * The permissions
+ */
+ mode_t m_permissions;
+
+ /**
+ * Marked : see mark()
+ */
+ bool m_bMarked:1;
+ /**
+ * Whether the file is a link
+ */
+ bool m_bLink:1;
+ /**
+ * True if local file
+ */
+ bool m_bIsLocalURL:1;
+
+ bool m_bMimeTypeKnown:1;
+
+ // Auto: check leading dot.
+ enum { Auto, Hidden, Shown } m_hidden:3;
+
+ // For special case like link to dirs over FTP
+ TQString m_guessedMimeType;
+ mutable TQString m_access;
+ TQMap<const void*, void*> m_extra;
+ mutable KFileMetaInfo m_metaInfo;
+
+ enum { Modification = 0, Access = 1, Creation = 2, NumFlags = 3 };
+ mutable time_t m_time[3];
+ mutable TDEIO::filesize_t m_size;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFileItemPrivate;
+ KFileItemPrivate * d;
+ TDEIO_EXPORT friend TQDataStream & operator<< ( TQDataStream & s, const KFileItem & a );
+ TDEIO_EXPORT friend TQDataStream & operator>> ( TQDataStream & s, KFileItem & a );
+};
+
+/**
+ * List of KFileItems
+ */
+typedef TQPtrList<KFileItem> KFileItemList;
+
+/**
+ * Iterator for KFileItemList
+ */
+typedef TQPtrListIterator<KFileItem> KFileItemListIterator;
+
+TDEIO_EXPORT TQDataStream & operator<< ( TQDataStream & s, const KFileItem & a );
+TDEIO_EXPORT TQDataStream & operator>> ( TQDataStream & s, KFileItem & a );
+
+
+#endif
diff --git a/tdeio/tdeio/tdefilemetainfo.cpp b/tdeio/tdeio/tdefilemetainfo.cpp
new file mode 100644
index 000000000..4943dea93
--- /dev/null
+++ b/tdeio/tdeio/tdefilemetainfo.cpp
@@ -0,0 +1,1859 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001-2002 Rolf Magnus <ramagnus@kde.org>
+ * Copyright (C) 2001-2002 Carsten Pfeiffer <pfeiffer@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 version 2.0.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include <assert.h>
+
+#include <tqshared.h>
+#include <tqdict.h>
+
+#include <ktrader.h>
+#include <kstaticdeleter.h>
+#include <tdeparts/componentfactory.h>
+#include <kuserprofile.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kdatastream.h> // needed for serialization of bool
+#include <klocale.h>
+#include <tdeio/global.h>
+
+#include "tdefilemetainfo.h"
+
+// shared data of a KFileMetaInfoItem
+class KFileMetaInfoItem::Data : public TQShared
+{
+public:
+ Data( const KFileMimeTypeInfo::ItemInfo* mti, const TQString& _key,
+ const TQVariant& _value )
+ : TQShared(),
+ mimeTypeInfo( mti ),
+ key( _key ),
+ value( _value ),
+ dirty( false ),
+ added( false ),
+ removed( false )
+ {}
+
+ // we use this one for the streaming operators
+ Data() : mimeTypeInfo( 0L )
+ {}
+
+ ~Data()
+ {
+ if ( this == null ) // only the null item owns its mimeTypeInfo
+ delete mimeTypeInfo;
+ }
+
+ const KFileMimeTypeInfo::ItemInfo* mimeTypeInfo;
+ // mimeTypeInfo has the key, too, but only for non-variable ones
+ TQString key;
+ TQVariant value;
+ bool dirty :1;
+ bool added :1;
+ bool removed :1;
+
+ static Data* null;
+ static Data* makeNull();
+};
+
+//this is our null data
+KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::null = 0L;
+static KStaticDeleter<KFileMetaInfoItem::Data> sd_KFileMetaInfoItemData;
+
+KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::makeNull()
+{
+ if (!null)
+ {
+ // We deliberately do not reset "null" after it has been destroyed!
+ // Otherwise we will run into problems later in ~KFileMetaInfoItem
+ // where the d-pointer is compared against null.
+
+ KFileMimeTypeInfo::ItemInfo* info = new KFileMimeTypeInfo::ItemInfo();
+ null = new Data(info, TQString::null, TQVariant());
+ sd_KFileMetaInfoItemData.setObject( null );
+ }
+ return null;
+}
+
+KFileMetaInfoItem::KFileMetaInfoItem( const KFileMimeTypeInfo::ItemInfo* mti,
+ const TQString& key, const TQVariant& value )
+ : d( new Data( mti, key, value ) )
+{
+}
+
+KFileMetaInfoItem::KFileMetaInfoItem( const KFileMetaInfoItem& item )
+{
+ // operator= does everything that's necessary
+ d = Data::makeNull();
+ *this = item;
+}
+
+KFileMetaInfoItem::KFileMetaInfoItem()
+{
+ d = Data::makeNull();
+}
+
+KFileMetaInfoItem::~KFileMetaInfoItem()
+{
+ deref();
+}
+
+const KFileMetaInfoItem& KFileMetaInfoItem::operator=
+ (const KFileMetaInfoItem & item )
+{
+ if (d != item.d)
+ {
+ // first deref the old one
+ deref();
+ d = item.d;
+ // and now ref the new one
+ ref();
+ }
+
+ return *this;
+}
+
+bool KFileMetaInfoItem::setValue( const TQVariant& value )
+{
+ // We don't call makeNull here since it isn't necassery, see deref()
+ if ( d == Data::null ) return false;
+
+ if ( ! (d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable ) ||
+ ! (value.canCast(d->mimeTypeInfo->type())))
+ {
+ kdDebug(7033) << "setting the value of " << key() << "failed\n";
+ return false;
+ }
+
+// kdDebug(7033) << key() << ".setValue()\n";
+
+ if ( d->value == value )
+ return true;
+
+ d->dirty = true;
+ d->value = value;
+ // If we don't cast (and test for canCast in the above if), TQVariant is
+ // very picky about types (e.g. TQString vs. TQCString or int vs. uint)
+ d->value.cast(d->mimeTypeInfo->type());
+
+ return true;
+}
+
+bool KFileMetaInfoItem::isRemoved() const
+{
+ return d->removed;
+}
+
+TQString KFileMetaInfoItem::key() const
+{
+ return d->key;
+}
+
+TQString KFileMetaInfoItem::translatedKey() const
+{
+ // are we a variable key?
+ if (d->mimeTypeInfo->key().isNull())
+ {
+ // then try if we have luck with i18n()
+ return i18n(d->key.utf8());
+ }
+
+ return d->mimeTypeInfo->translatedKey();
+}
+
+const TQVariant& KFileMetaInfoItem::value() const
+{
+ return d->value;
+}
+
+TQString KFileMetaInfoItem::string( bool mangle ) const
+{
+ return d->mimeTypeInfo->string(d->value, mangle);
+}
+
+TQVariant::Type KFileMetaInfoItem::type() const
+{
+ return d->mimeTypeInfo->type();
+}
+
+uint KFileMetaInfoItem::unit() const
+{
+ return d->mimeTypeInfo->unit();
+}
+
+bool KFileMetaInfoItem::isModified() const
+{
+ return d->dirty;
+}
+
+TQString KFileMetaInfoItem::prefix() const
+{
+ return d->mimeTypeInfo->prefix();
+}
+
+TQString KFileMetaInfoItem::suffix() const
+{
+ return d->mimeTypeInfo->suffix();
+}
+
+uint KFileMetaInfoItem::hint() const
+{
+ return d->mimeTypeInfo->hint();
+}
+
+uint KFileMetaInfoItem::attributes() const
+{
+ return d->mimeTypeInfo->attributes();
+}
+
+bool KFileMetaInfoItem::isEditable() const
+{
+ return d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable;
+}
+
+bool KFileMetaInfoItem::isValid() const
+{
+ // We don't call makeNull here since it isn't necassery:
+ // If d is equal to null it means that null is initialized already.
+ // null is 0L when it hasn't been initialized and d is never 0L.
+ return d != Data::null;
+}
+
+void KFileMetaInfoItem::setAdded()
+{
+ d->added = true;
+}
+
+void KFileMetaInfoItem::setRemoved()
+{
+ d->removed = true;
+}
+
+void KFileMetaInfoItem::ref()
+{
+ if (d != Data::null) d->ref();
+}
+
+void KFileMetaInfoItem::deref()
+{
+ // We don't call makeNull here since it isn't necassery:
+ // If d is equal to null it means that null is initialized already.
+ // null is 0L when it hasn't been initialized and d is never 0L.
+ if ((d != Data::null) && d->deref())
+ {
+// kdDebug(7033) << "item " << d->key
+// << " is finally deleted\n";
+ delete d;
+ d = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+// shared data of a KFileMetaInfo
+class KFileMetaInfo::Data : public TQShared
+{
+public:
+ Data(const KURL& _url, uint _what)
+ : TQShared(),
+ url(_url),
+ what(_what),
+ mimeTypeInfo( 0L )
+ {}
+
+ // wee use this one for the streaming operators
+ Data() {};
+
+ KURL url;
+ uint what;
+ TQMap<TQString, KFileMetaInfoGroup> groups;
+ const KFileMimeTypeInfo* mimeTypeInfo;
+ TQStringList removedGroups;
+
+ static Data* null;
+ static Data* makeNull();
+
+};
+
+KFileMetaInfo::KFileMetaInfo( const TQString& path, const TQString& mimeType,
+ uint what )
+{
+ KURL u;
+
+ u.setPath(path);
+ init(u, mimeType, what);
+}
+
+KFileMetaInfo::KFileMetaInfo( const KURL& url, const TQString& mimeType,
+ uint what )
+{
+ init(url, mimeType, what);
+}
+
+void KFileMetaInfo::init( const KURL& url, const TQString& mimeType,
+ uint what )
+{
+ d = new Data( url, what );
+
+ TQString mT;
+ if (mimeType.isEmpty())
+ mT = KMimeType::findByURL(url)->name();
+ else
+ mT = mimeType;
+
+ // let's "share our property"
+ KFileMetaInfo item(*this);
+
+ //kdDebug() << k_funcinfo << mT << " " << url << endl;
+
+ d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo( mT, url.protocol() );
+ if ( d->mimeTypeInfo )
+ {
+ //kdDebug(7033) << "Found mimetype info for " << mT /* or protocol*/ << endl;
+ KFilePlugin *p = plugin();
+ Q_ASSERT( p );
+ if ( p && !p->readInfo( item, what) )
+ {
+ deref();
+ d = Data::makeNull();
+ }
+ }
+ else
+ {
+// kdDebug(7033) << "No mimetype info for " << mimeType << endl;
+ deref();
+ d = Data::makeNull();
+ }
+}
+
+KFileMetaInfo::KFileMetaInfo( const KFileMetaInfo& original )
+{
+ // operator= does everything that's necessary
+ d = Data::makeNull();
+ *this = original;
+}
+
+KFileMetaInfo::KFileMetaInfo()
+{
+ d = Data::makeNull();
+}
+
+KFileMetaInfo::~KFileMetaInfo()
+{
+ deref();
+}
+
+TQStringList KFileMetaInfo::supportedGroups() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->supportedGroups();
+}
+
+TQStringList KFileMetaInfo::supportedKeys() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->supportedKeys();
+}
+
+TQStringList KFileMetaInfo::groups() const
+{
+ TQStringList list;
+ TQMapConstIterator<TQString, KFileMetaInfoGroup> it = d->groups.begin();
+ for ( ; it != d->groups.end(); ++it )
+ list += (*it).name();
+
+ return list;
+}
+
+TQStringList KFileMetaInfo::editableGroups() const
+{
+ TQStringList list;
+ TQStringList supported = supportedGroups();
+ TQStringList::ConstIterator it = supported.begin();
+ for ( ; it != supported.end(); ++it ) {
+ const KFileMimeTypeInfo::GroupInfo * groupInfo = d->mimeTypeInfo->groupInfo( *it );
+ if ( groupInfo && groupInfo->attributes() &
+ (KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable) )
+ list.append( *it );
+ }
+
+ return list;
+}
+
+TQStringList KFileMetaInfo::preferredGroups() const
+{
+ assert(isValid());
+ TQStringList list = groups();
+ TQStringList newlist;
+ TQStringList preferred = d->mimeTypeInfo->preferredGroups();
+ TQStringList::Iterator pref;
+
+ // move all keys from the preferred groups that are in our list to a new list
+ for ( pref = preferred.begin(); pref != preferred.end(); ++pref )
+ {
+ TQStringList::Iterator group = list.find(*pref);
+ if ( group != list.end() )
+ {
+ newlist.append( *group );
+ list.remove(group);
+ }
+ }
+
+ // now the old list only contains the non-preferred items, so we
+ // add the remaining ones to newlist
+ newlist += list;
+
+ return newlist;
+}
+
+TQStringList KFileMetaInfo::preferredKeys() const
+{
+ TQStringList newlist;
+
+ TQStringList list = preferredGroups();
+ for (TQStringList::Iterator git = list.begin(); git != list.end(); ++git)
+ {
+ newlist += d->groups[*git].preferredKeys();
+ }
+
+ return newlist;
+}
+
+KFileMetaInfoGroup KFileMetaInfo::group(const TQString& key) const
+{
+ TQMapIterator<TQString,KFileMetaInfoGroup> it = d->groups.find( key );
+ if ( it != d->groups.end() )
+ return it.data();
+ else
+ return KFileMetaInfoGroup();
+}
+
+bool KFileMetaInfo::addGroup( const TQString& name )
+{
+ assert(isValid());
+ if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
+ ! d->groups.contains(name) )
+ {
+ KFileMetaInfoGroup group( name, d->mimeTypeInfo );
+
+ // add all the items that can't be added by the user later
+ const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(name);
+ Q_ASSERT(ginfo);
+ if (!ginfo) return false;
+
+ TQStringList keys = ginfo->supportedKeys();
+ for (TQStringList::Iterator it = keys.begin(); it != keys.end(); ++it)
+ {
+ const KFileMimeTypeInfo::ItemInfo* iteminfo = ginfo->itemInfo(*it);
+ Q_ASSERT(ginfo);
+ if (!iteminfo) return false;
+
+ if ( !(iteminfo->attributes() & KFileMimeTypeInfo::Addable) &&
+ (iteminfo->attributes() & KFileMimeTypeInfo::Modifiable))
+ {
+ // append it now or never
+ group.appendItem(iteminfo->key(), TQVariant());
+ }
+
+ }
+
+ d->groups.insert(name, group);
+ group.setAdded();
+ return true;
+ }
+
+ return false;
+}
+
+bool KFileMetaInfo::removeGroup( const TQString& name )
+{
+ TQMapIterator<TQString, KFileMetaInfoGroup> it = d->groups.find(name);
+ if ( (it==d->groups.end()) ||
+ !((*it).attributes() & KFileMimeTypeInfo::Removable))
+ return false;
+
+ d->groups.remove(it);
+ d->removedGroups.append(name);
+ return true;
+}
+
+TQStringList KFileMetaInfo::removedGroups()
+{
+ return d->removedGroups;
+}
+
+const KFileMetaInfo& KFileMetaInfo::operator= (const KFileMetaInfo& info )
+{
+ if (d != info.d)
+ {
+ deref();
+ // first deref the old one
+ d = info.d;
+ // and now ref the new one
+ ref();
+ }
+ return *this;
+}
+
+bool KFileMetaInfo::isValid() const
+{
+ // We don't call makeNull here since it isn't necassery, see deref()
+ return d != Data::null;
+}
+
+bool KFileMetaInfo::isEmpty() const
+{
+ for (TQMapIterator<TQString, KFileMetaInfoGroup> it = d->groups.begin();
+ it!=d->groups.end(); ++it)
+ if (!(*it).isEmpty())
+ return false;
+ return true;
+}
+
+bool KFileMetaInfo::applyChanges()
+{
+ return applyChanges( path() );
+}
+
+bool KFileMetaInfo::applyChanges( const TQString& path )
+{
+ bool doit = false;
+
+// kdDebug(7033) << "KFileMetaInfo::applyChanges()\n";
+
+ // look up if we need to write to the file
+ TQMapConstIterator<TQString, KFileMetaInfoGroup> it;
+ for (it = d->groups.begin(); it!=d->groups.end() && !doit; ++it)
+ {
+ if ( (*it).isModified() )
+ doit = true;
+
+ else
+ {
+ TQStringList keys = it.data().keys();
+ for (TQStringList::Iterator it2 = keys.begin(); it2!=keys.end(); ++it2)
+ {
+ if ( (*it)[*it2].isModified() )
+ {
+ doit = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!doit)
+ {
+ kdDebug(7033) << "Don't need to write, nothing changed\n";
+ return true;
+ }
+
+ KFilePlugin* p = plugin();
+ if (!p) return false;
+
+// kdDebug(7033) << "Ok, trying to write the info\n";
+
+ KURL savedURL = url();
+ d->url = KURL();
+ d->url.setPath( path );
+
+ bool ret = p->writeInfo(*this);
+
+ d->url = savedURL;
+ return ret;
+}
+
+KFilePlugin * KFileMetaInfo::plugin() const
+{
+ assert(isValid());
+ KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
+ return prov->plugin( d->mimeTypeInfo->mimeType(), d->url.protocol() );
+}
+
+TQString KFileMetaInfo::mimeType() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->mimeType();
+}
+
+bool KFileMetaInfo::contains(const TQString& key) const
+{
+ TQStringList glist = groups();
+ for (TQStringList::Iterator it = glist.begin(); it != glist.end(); ++it)
+ {
+ KFileMetaInfoGroup g = d->groups[*it];
+ if (g.contains(key)) return true;
+ }
+ return false;
+}
+
+bool KFileMetaInfo::containsGroup(const TQString& key) const
+{
+ return groups().contains(key);
+}
+
+KFileMetaInfoItem KFileMetaInfo::item( const TQString& key) const
+{
+ TQStringList groups = preferredGroups();
+ for (TQStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
+ {
+ KFileMetaInfoItem i = d->groups[*it][key];
+ if (i.isValid()) return i;
+ }
+ return KFileMetaInfoItem();
+}
+
+KFileMetaInfoItem KFileMetaInfo::item(const KFileMetaInfoItem::Hint hint) const
+{
+ TQStringList groups = preferredGroups();
+ TQStringList::ConstIterator it;
+ for (it = groups.begin(); it != groups.end(); ++it)
+ {
+ KFileMetaInfoItem i = d->groups[*it].item(hint);
+ if (i.isValid()) return i;
+ }
+ return KFileMetaInfoItem();
+}
+
+KFileMetaInfoItem KFileMetaInfo::saveItem( const TQString& key,
+ const TQString& preferredGroup,
+ bool createGroup )
+{
+ assert(isValid());
+ // try the preferred groups first
+ if ( !preferredGroup.isEmpty() ) {
+ TQMapIterator<TQString,KFileMetaInfoGroup> it =
+ d->groups.find( preferredGroup );
+
+ // try to create the preferred group, if necessary
+ if ( it == d->groups.end() && createGroup ) {
+ const KFileMimeTypeInfo::GroupInfo *groupInfo =
+ d->mimeTypeInfo->groupInfo( preferredGroup );
+ if ( groupInfo && groupInfo->supportedKeys().contains( key ) ) {
+ if ( addGroup( preferredGroup ) )
+ it = d->groups.find( preferredGroup );
+ }
+ }
+
+ if ( it != d->groups.end() ) {
+ KFileMetaInfoItem item = it.data().addItem( key );
+ if ( item.isValid() )
+ return item;
+ }
+ }
+
+ TQStringList groups = preferredGroups();
+
+ KFileMetaInfoItem item;
+
+ TQStringList::ConstIterator groupIt = groups.begin();
+ for ( ; groupIt != groups.end(); ++groupIt )
+ {
+ TQMapIterator<TQString,KFileMetaInfoGroup> it = d->groups.find( *groupIt );
+ if ( it != d->groups.end() )
+ {
+ KFileMetaInfoGroup group = it.data();
+ item = findEditableItem( group, key );
+ if ( item.isValid() )
+ return item;
+ }
+ else // not existant -- try to create the group
+ {
+ const KFileMimeTypeInfo::GroupInfo *groupInfo =
+ d->mimeTypeInfo->groupInfo( *groupIt );
+ if ( groupInfo && groupInfo->supportedKeys().contains( key ) )
+ {
+ if ( addGroup( *groupIt ) )
+ {
+ KFileMetaInfoGroup group = d->groups[*groupIt];
+ KFileMetaInfoItem item = group.addItem( key );
+ if ( item.isValid() )
+ return item;
+// else ### add when removeGroup() is implemented :)
+// removeGroup( *groupIt ); // couldn't add item -> remove
+ }
+ }
+ }
+ }
+
+ // finally check for variable items
+
+ return item;
+}
+
+KFileMetaInfoItem KFileMetaInfo::findEditableItem( KFileMetaInfoGroup& group,
+ const TQString& key )
+{
+ assert(isValid());
+ KFileMetaInfoItem item = group.addItem( key );
+ if ( item.isValid() && item.isEditable() )
+ return item;
+
+ if ( (d->mimeTypeInfo->groupInfo( group.name() )->attributes() & KFileMimeTypeInfo::Addable) )
+ return item;
+
+ return KFileMetaInfoItem();
+}
+
+KFileMetaInfoGroup KFileMetaInfo::appendGroup(const TQString& name)
+{
+ assert(isValid());
+ if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
+ ! d->groups.contains(name) )
+ {
+ KFileMetaInfoGroup group( name, d->mimeTypeInfo );
+ d->groups.insert(name, group);
+ return group;
+ }
+
+ else {
+ kdWarning(7033) << "Someone's trying to add a KFileMetaInfoGroup which is not supported or already existing: " << name << endl;
+ return KFileMetaInfoGroup();
+ }
+}
+
+TQString KFileMetaInfo::path() const
+{
+ return d->url.isLocalFile() ? d->url.path() : TQString::null;
+}
+
+KURL KFileMetaInfo::url() const
+{
+ return d->url;
+}
+
+void KFileMetaInfo::ref()
+{
+ if (d != Data::null) d->ref();
+
+}
+
+void KFileMetaInfo::deref()
+{
+ // We don't call makeNull here since it isn't necassery:
+ // If d is equal to null it means that null is initialized already.
+ // null is 0L when it hasn't been initialized and d is never 0L.
+ if ((d != Data::null) && d->deref())
+ {
+// kdDebug(7033) << "metainfo object for " << d->url.path << " is finally deleted\n";
+ delete d;
+ d = 0;
+ }
+
+}
+
+
+KFileMetaInfo::Data* KFileMetaInfo::Data::null = 0L;
+static KStaticDeleter<KFileMetaInfo::Data> sd_KFileMetaInfoData;
+
+KFileMetaInfo::Data* KFileMetaInfo::Data::makeNull()
+{
+ if (!null)
+ // We deliberately do not reset "null" after it has been destroyed!
+ // Otherwise we will run into problems later in ~KFileMetaInfoItem
+ // where the d-pointer is compared against null.
+ null = sd_KFileMetaInfoData.setObject( new KFileMetaInfo::Data(KURL(), 0) );
+ return null;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+KFilePlugin::KFilePlugin( TQObject *parent, const char *name,
+ const TQStringList& /*args*/)
+ : TQObject( parent, name )
+{
+// kdDebug(7033) << "loaded a plugin for " << name << endl;
+}
+
+KFilePlugin::~KFilePlugin()
+{
+// kdDebug(7033) << "unloaded a plugin for " << name() << endl;
+}
+
+KFileMimeTypeInfo * KFilePlugin::addMimeTypeInfo( const TQString& mimeType )
+{
+ return KFileMetaInfoProvider::self()->addMimeTypeInfo( mimeType );
+}
+
+void KFilePlugin::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+
+KFileMimeTypeInfo::GroupInfo* KFilePlugin::addGroupInfo(KFileMimeTypeInfo* info,
+ const TQString& key, const TQString& translatedKey) const
+{
+ return info->addGroupInfo(key, translatedKey);
+}
+
+void KFilePlugin::setAttributes(KFileMimeTypeInfo::GroupInfo* gi, uint attr) const
+{
+ gi->m_attr = attr;
+}
+
+void KFilePlugin::addVariableInfo(KFileMimeTypeInfo::GroupInfo* gi,
+ TQVariant::Type type, uint attr) const
+{
+ gi->addVariableInfo(type, attr);
+}
+
+KFileMimeTypeInfo::ItemInfo* KFilePlugin::addItemInfo(KFileMimeTypeInfo::GroupInfo* gi,
+ const TQString& key,
+ const TQString& translatedKey,
+ TQVariant::Type type)
+{
+ return gi->addItemInfo(key, translatedKey, type);
+}
+
+void KFilePlugin::setAttributes(KFileMimeTypeInfo::ItemInfo* item, uint attr)
+{
+ item->m_attr = attr;
+}
+
+void KFilePlugin::setHint(KFileMimeTypeInfo::ItemInfo* item, uint hint)
+{
+ item->m_hint = hint;
+}
+
+void KFilePlugin::setUnit(KFileMimeTypeInfo::ItemInfo* item, uint unit)
+{
+ item->m_unit = unit;
+ // set prefix and suffix
+ switch (unit)
+ {
+ case KFileMimeTypeInfo::Seconds:
+ item->m_suffix = i18n("s"); break;
+
+ case KFileMimeTypeInfo::MilliSeconds:
+ item->m_suffix = i18n("ms"); break;
+
+ case KFileMimeTypeInfo::BitsPerSecond:
+ item->m_suffix = i18n("bps"); break;
+
+ case KFileMimeTypeInfo::Pixels:
+ item->m_suffix = i18n("pixels"); break;
+
+ case KFileMimeTypeInfo::Inches:
+ item->m_suffix = i18n("in"); break;
+
+ case KFileMimeTypeInfo::Centimeters:
+ item->m_suffix = i18n("cm"); break;
+
+ case KFileMimeTypeInfo::Bytes:
+ item->m_suffix = i18n("B"); break;
+
+ case KFileMimeTypeInfo::KiloBytes:
+ item->m_suffix = i18n("KB"); break;
+
+ case KFileMimeTypeInfo::FramesPerSecond:
+ item->m_suffix = i18n("fps"); break;
+
+ case KFileMimeTypeInfo::DotsPerInch:
+ item->m_suffix = i18n("dpi"); break;
+
+ case KFileMimeTypeInfo::BitsPerPixel:
+ item->m_suffix = i18n("bpp"); break;
+
+ case KFileMimeTypeInfo::Hertz:
+ item->m_suffix = i18n("Hz"); break;
+
+ case KFileMimeTypeInfo::Millimeters:
+ item->m_suffix = i18n("mm");
+ }
+}
+
+void KFilePlugin::setPrefix(KFileMimeTypeInfo::ItemInfo* item, const TQString& prefix)
+{
+ item->m_prefix = prefix;
+}
+
+void KFilePlugin::setSuffix(KFileMimeTypeInfo::ItemInfo* item, const TQString& suffix)
+{
+ item->m_suffix = suffix;
+}
+
+KFileMetaInfoGroup KFilePlugin::appendGroup(KFileMetaInfo& info, const TQString& key)
+{
+ return info.appendGroup(key);
+}
+
+void KFilePlugin::appendItem(KFileMetaInfoGroup& group, const TQString& key, TQVariant value)
+{
+ group.appendItem(key, value);
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+KFileMetaInfoProvider * KFileMetaInfoProvider::s_self;
+static KStaticDeleter<KFileMetaInfoProvider> sd;
+
+KFileMetaInfoProvider * KFileMetaInfoProvider::self()
+{
+ if ( !s_self )
+ s_self = sd.setObject( s_self, new KFileMetaInfoProvider() );
+
+ return s_self;
+}
+
+KFileMetaInfoProvider::KFileMetaInfoProvider()
+{
+ m_plugins.setAutoDelete( true );
+}
+
+KFileMetaInfoProvider::~KFileMetaInfoProvider()
+{
+ m_plugins.clear();
+ sd.setObject( 0 );
+}
+
+KFilePlugin* KFileMetaInfoProvider::loadPlugin( const TQString& mimeType, const TQString& protocol )
+{
+ //kdDebug() << "loadPlugin: mimeType=" << mimeType << " protocol=" << protocol << endl;
+ // Currently the idea is: either the mimetype is set or the protocol, but not both.
+ // We need PNG fileinfo, and trash: fileinfo, but not "PNG in the trash".
+ TQString queryMimeType, query;
+ if ( !mimeType.isEmpty() ) {
+ query = "(not exist [X-TDE-Protocol])";
+ queryMimeType = mimeType;
+ } else {
+ query = TQString::fromLatin1( "[X-TDE-Protocol] == '%1'" ).arg(protocol);
+ // querying for a protocol: we have no mimetype, so we need to use KFilePlugin as one
+ queryMimeType = "KFilePlugin";
+ // hopefully using KFilePlugin as genericMimeType too isn't a problem
+ }
+ const KTrader::OfferList offers = KTrader::self()->query( queryMimeType, "KFilePlugin", query, TQString::null );
+ if ( offers.isEmpty() )
+ return 0;
+ KService::Ptr service = *(offers.begin());
+ Q_ASSERT( service && service->isValid() );
+ if ( !service || !service->isValid() )
+ return 0;
+
+ KFilePlugin* plugin = KParts::ComponentFactory::createInstanceFromService<KFilePlugin>
+ ( service, TQT_TQOBJECT(this), mimeType.local8Bit() );
+ if (!plugin)
+ kdWarning(7033) << "error loading the plugin from " << service->desktopEntryPath() << endl;
+
+ return plugin;
+}
+
+KFilePlugin* KFileMetaInfoProvider::loadAndRegisterPlugin( const TQString& mimeType, const TQString& protocol )
+{
+ Q_ASSERT( m_pendingMimetypeInfos.isEmpty() );
+ m_pendingMimetypeInfos.clear();
+
+ KFilePlugin* plugin = loadPlugin( mimeType, protocol );
+ if ( !plugin ) {
+ // No plugin found. Remember that, to save time.
+ m_plugins.insert( protocol.isEmpty() ? mimeType : protocol, new CachedPluginInfo );
+ return 0;
+ }
+
+ if ( !protocol.isEmpty() ) {
+ // Protocol-metainfo: only one entry
+ Q_ASSERT( m_pendingMimetypeInfos.count() == 1 );
+ KFileMimeTypeInfo* info = m_pendingMimetypeInfos[ protocol ];
+ Q_ASSERT( info );
+ m_plugins.insert( protocol, new CachedPluginInfo( plugin, info, true ) );
+ } else {
+ // Mimetype-metainfo: the plugin can register itself for multiple mimetypes, remember them all
+ bool first = true;
+ TQDictIterator<KFileMimeTypeInfo> it( m_pendingMimetypeInfos );
+ for( ; it.current(); ++it ) {
+ KFileMimeTypeInfo* info = it.current();
+ m_plugins.insert( it.currentKey(), new CachedPluginInfo( plugin, info, first ) );
+ first = false;
+ }
+ // Hopefully the above includes the mimetype we asked for!
+ if ( m_pendingMimetypeInfos.find( mimeType ) == 0 )
+ kdWarning(7033) << plugin->className() << " was created for " << mimeType << " but doesn't call addMimeTypeInfo for it!" << endl;
+ }
+ m_pendingMimetypeInfos.clear();
+ return plugin;
+}
+
+KFilePlugin * KFileMetaInfoProvider::plugin(const TQString& mimeType)
+{
+ return plugin( mimeType, TQString::null );
+}
+
+KFilePlugin * KFileMetaInfoProvider::plugin(const TQString& mimeType, const TQString& protocol)
+{
+ //kdDebug(7033) << "plugin() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
+
+ if ( !protocol.isEmpty() ) {
+ CachedPluginInfo *cache = m_plugins.find( protocol );
+ if ( cache && cache->plugin ) {
+ return cache->plugin;
+ }
+ if ( !cache ) {
+ KFilePlugin* plugin = loadAndRegisterPlugin( TQString::null, protocol );
+ if ( plugin )
+ return plugin;
+ }
+ }
+
+ CachedPluginInfo *cache = m_plugins.find( mimeType );
+ if ( cache ) {
+ return cache->plugin;
+ }
+
+ KFilePlugin* plugin = loadAndRegisterPlugin( mimeType, TQString::null );
+
+#if 0
+ kdDebug(7033) << "currently loaded plugins:\n";
+
+ TQDictIterator<CachedPluginInfo> it( m_plugins );
+ for( ; it.current(); ++it ) {
+ CachedPluginInfo* cache = it.current();
+ kdDebug(7033)
+ << it.currentKey() // mimetype or protocol
+ << " : " << (cache->plugin ? cache->plugin->className() : "(no plugin)") << endl; // plugin
+ // TODO print cache->mimeTypeInfo
+ }
+#endif
+
+ return plugin;
+}
+
+TQStringList KFileMetaInfoProvider::preferredKeys( const TQString& mimeType ) const
+{
+ KService::Ptr service =
+ KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
+
+ if ( !service || !service->isValid() )
+ {
+// kdDebug(7033) << "no valid service found\n";
+ return TQStringList();
+ }
+ return service->property("PreferredItems").toStringList();
+}
+
+TQStringList KFileMetaInfoProvider::preferredGroups( const TQString& mimeType ) const
+{
+ KService::Ptr service =
+ KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
+
+ if ( !service || !service->isValid() )
+ {
+// kdDebug(7033) << "no valid service found\n";
+ return TQStringList();
+ }
+ return service->property("PreferredGroups").toStringList();
+}
+
+const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const TQString& mimeType )
+{
+ return mimeTypeInfo( mimeType, TQString::null );
+}
+
+const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const TQString& mimeType, const TQString& protocol )
+{
+ //kdDebug(7033) << "mimeTypeInfo() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
+ if ( !protocol.isEmpty() ) {
+ CachedPluginInfo *cache = m_plugins.find( protocol );
+ if ( cache && cache->mimeTypeInfo ) {
+ return cache->mimeTypeInfo;
+ }
+
+ if ( !cache ) {
+ loadAndRegisterPlugin( TQString::null, protocol );
+ cache = m_plugins.find( protocol );
+ if ( cache && cache->mimeTypeInfo ) {
+ return cache->mimeTypeInfo;
+ }
+ }
+ }
+
+ CachedPluginInfo *cache = m_plugins.find( mimeType );
+ if ( cache ) {
+ return cache->mimeTypeInfo;
+ }
+
+ loadAndRegisterPlugin( mimeType, TQString::null );
+ cache = m_plugins.find( mimeType );
+ if ( cache ) {
+ return cache->mimeTypeInfo;
+ }
+ return 0;
+}
+
+KFileMimeTypeInfo * KFileMetaInfoProvider::addMimeTypeInfo(
+ const TQString& mimeType )
+{
+
+ KFileMimeTypeInfo *info = m_pendingMimetypeInfos.find( mimeType );
+ Q_ASSERT( !info );
+ if ( !info )
+ {
+ info = new KFileMimeTypeInfo( mimeType );
+ m_pendingMimetypeInfos.insert( mimeType, info );
+ }
+
+ info->m_preferredKeys = preferredKeys( mimeType );
+ info->m_preferredGroups = preferredGroups( mimeType );
+
+ return info;
+}
+
+TQStringList KFileMetaInfoProvider::supportedMimeTypes() const
+{
+ TQStringList allMimeTypes;
+ TQString tdefilePlugin = "KFilePlugin";
+
+ KTrader::OfferList offers = KTrader::self()->query( "KFilePlugin" );
+ KTrader::OfferListIterator it = offers.begin();
+ for ( ; it != offers.end(); ++it )
+ {
+ const TQStringList mimeTypes = (*it)->serviceTypes();
+ TQStringList::ConstIterator it2 = mimeTypes.begin();
+ for ( ; it2 != mimeTypes.end(); ++it2 )
+ if ( allMimeTypes.find( *it2 ) == allMimeTypes.end() &&
+ *it2 != tdefilePlugin ) // also in serviceTypes()
+ allMimeTypes.append( *it2 );
+ }
+
+ return allMimeTypes;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+// shared data of a KFileMetaInfoGroup
+class KFileMetaInfoGroup::Data : public TQShared
+{
+public:
+ Data(const TQString& _name)
+ : TQShared(),
+ name(_name),
+ mimeTypeInfo(0L),
+ dirty( false ),
+ added( false )
+ {}
+
+ // we use this one for the streaming operators
+ Data() : mimeTypeInfo(0L) {}
+ ~Data() {
+ if ( this == null )
+ delete mimeTypeInfo;
+ };
+
+ TQString name;
+ TQMap<TQString, KFileMetaInfoItem> items;
+ const KFileMimeTypeInfo* mimeTypeInfo;
+ TQStringList removedItems;
+ bool dirty :1;
+ bool added :1;
+
+ static Data* null;
+ static Data* makeNull();
+
+};
+
+KFileMetaInfoGroup::KFileMetaInfoGroup( const TQString& name,
+ const KFileMimeTypeInfo* info )
+ : d(new Data( name ) )
+{
+ d->mimeTypeInfo = info;
+}
+
+KFileMetaInfoGroup::KFileMetaInfoGroup( const KFileMetaInfoGroup& original )
+{
+ // operator= does everything that's necessary
+ d = Data::makeNull();
+ *this = original;
+}
+
+KFileMetaInfoGroup::KFileMetaInfoGroup()
+{
+ d = Data::makeNull();
+}
+
+KFileMetaInfoGroup::~KFileMetaInfoGroup()
+{
+ deref();
+}
+
+const KFileMetaInfoGroup& KFileMetaInfoGroup::operator= (const KFileMetaInfoGroup& info )
+{
+ if (d != info.d)
+ {
+ deref();
+ // first deref the old one
+ d = info.d;
+ // and now ref the new one
+ ref();
+ }
+ return *this;
+}
+
+bool KFileMetaInfoGroup::isValid() const
+{
+ // We don't call makeNull here since it isn't necassery, see deref()
+ return d != Data::null;
+}
+
+bool KFileMetaInfoGroup::isEmpty() const
+{
+ return d->items.isEmpty();
+}
+
+TQStringList KFileMetaInfoGroup::preferredKeys() const
+{
+ assert(isValid());
+ TQStringList list = keys();
+ TQStringList newlist;
+ TQStringList preferredKeys = d->mimeTypeInfo->preferredKeys();
+ TQStringList::Iterator pref;
+ TQStringList::Iterator begin = preferredKeys.begin();
+ TQStringList::Iterator end = preferredKeys.end();
+
+ // move all keys from the preferred keys that are in our list to a new list
+ for ( pref = begin; pref!=end; ++pref )
+ {
+ TQStringList::Iterator item = list.find(*pref);
+ if ( item != list.end() )
+ {
+ newlist.append( *item );
+ list.remove(item);
+ }
+ }
+
+ // now the old list only contains the non-preferred items, so we
+ // add the remaining ones to newlist
+ newlist += list;
+
+ return newlist;
+}
+
+TQStringList KFileMetaInfoGroup::keys() const
+{
+ if (d == Data::makeNull())
+ kdWarning(7033) << "attempt to get the keys of "
+ "an invalid metainfo group";
+
+ TQStringList list;
+
+ // make a TQStringList with all available keys
+ TQMapConstIterator<TQString, KFileMetaInfoItem> it;
+ for (it = d->items.begin(); it!=d->items.end(); ++it)
+ {
+ list.append(it.data().key());
+// kdDebug(7033) << "Item " << it.data().key() << endl;
+ }
+ return list;
+}
+
+TQString KFileMetaInfoGroup::translatedName() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->groupInfo(d->name)->translatedName();
+}
+
+TQStringList KFileMetaInfoGroup::supportedKeys() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->groupInfo(d->name)->supportedKeys();
+}
+
+bool KFileMetaInfoGroup::supportsVariableKeys() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->groupInfo(d->name)->supportsVariableKeys();
+}
+
+bool KFileMetaInfoGroup::contains( const TQString& key ) const
+{
+ return d->items.contains(key);
+}
+
+KFileMetaInfoItem KFileMetaInfoGroup::item( const TQString& key) const
+{
+ TQMapIterator<TQString,KFileMetaInfoItem> it = d->items.find( key );
+ if ( it != d->items.end() )
+ return it.data();
+
+ return KFileMetaInfoItem();
+}
+
+KFileMetaInfoItem KFileMetaInfoGroup::item(uint hint) const
+{
+ TQMapIterator<TQString, KFileMetaInfoItem> it;
+
+ for (it = d->items.begin(); it!=d->items.end(); ++it)
+ if (it.data().hint() == hint)
+ return it.data();
+
+ return KFileMetaInfoItem();
+}
+
+TQString KFileMetaInfoGroup::name() const
+{
+ return d->name;
+}
+
+uint KFileMetaInfoGroup::attributes() const
+{
+ assert(isValid());
+ return d->mimeTypeInfo->groupInfo(d->name)->attributes();
+}
+
+void KFileMetaInfoGroup::setAdded()
+{
+ d->added = true;
+}
+
+bool KFileMetaInfoGroup::isModified() const
+{
+ return d->dirty;
+}
+
+void KFileMetaInfoGroup::ref()
+{
+ if (d != Data::null) d->ref();
+
+}
+
+void KFileMetaInfoGroup::deref()
+{
+ // We don't call makeNull here since it isn't necassery:
+ // If d is equal to null it means that null is initialized already.
+ // null is 0L when it hasn't been initialized and d is never 0L.
+ if ((d != Data::null) && d->deref())
+ {
+// kdDebug(7033) << "metainfo group " << d->name
+// << " is finally deleted\n";
+ delete d;
+ d = 0;
+ }
+
+}
+
+KFileMetaInfoItem KFileMetaInfoGroup::addItem( const TQString& key )
+{
+ assert(isValid());
+ TQMapIterator<TQString,KFileMetaInfoItem> it = d->items.find( key );
+ if ( it != d->items.end() )
+ return it.data();
+
+ const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
+
+ if ( !ginfo ) {
+ Q_ASSERT( ginfo );
+ return KFileMetaInfoItem();
+ }
+
+ const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
+
+ if ( !info ) {
+ Q_ASSERT( info );
+ return KFileMetaInfoItem();
+ }
+
+ KFileMetaInfoItem item;
+
+ if (info->isVariableItem())
+ item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, TQVariant());
+ else
+ item = KFileMetaInfoItem(info, key, TQVariant());
+
+ d->items.insert(key, item);
+ item.setAdded(); // mark as added
+ d->dirty = true; // mark ourself as dirty, too
+ return item;
+}
+
+bool KFileMetaInfoGroup::removeItem( const TQString& key )
+{
+ if (!isValid())
+ {
+ kdDebug(7033) << "trying to remove an item from an invalid group\n";
+ return false;
+ }
+
+ TQMapIterator<TQString, KFileMetaInfoItem> it = d->items.find(key);
+ if ( it==d->items.end() )
+ {
+ kdDebug(7033) << "trying to remove the non existant item " << key << "\n";
+ return false;
+ }
+
+ if (!((*it).attributes() & KFileMimeTypeInfo::Removable))
+ {
+ kdDebug(7033) << "trying to remove a non removable item\n";
+ return false;
+ }
+
+ (*it).setRemoved();
+ d->items.remove(it);
+ d->removedItems.append(key);
+ d->dirty = true;
+ return true;
+}
+
+TQStringList KFileMetaInfoGroup::removedItems()
+{
+ return d->removedItems;
+}
+
+KFileMetaInfoItem KFileMetaInfoGroup::appendItem(const TQString& key,
+ const TQVariant& value)
+{
+ //KDE4 enforce (value.type() == d->mimeTypeInfo->type())
+ assert(isValid());
+ const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
+ if ( !ginfo ) {
+ kdWarning() << "Trying to append a Metadata item for a non-existant group:" << d->name << endl;
+ return KFileMetaInfoItem();
+ }
+ const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
+ if ( !info ) {
+ kdWarning() << "Trying to append a Metadata item for an unknown key (no ItemInfo): " << key << endl;
+ return KFileMetaInfoItem();
+ }
+
+ KFileMetaInfoItem item;
+
+ if (info->key().isNull())
+ item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, value);
+ else
+ item = KFileMetaInfoItem(info, key, value);
+
+ kdDebug(7033) << "KFileMetaInfogroup inserting a " << key << endl;
+
+ d->items.insert(key, item);
+ return item;
+}
+
+KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::null = 0L;
+static KStaticDeleter<KFileMetaInfoGroup::Data> sd_KFileMetaInfoGroupData;
+
+KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::makeNull()
+{
+ if (!null)
+ {
+ // We deliberately do not reset "null" after it has been destroyed!
+ // Otherwise we will run into problems later in ~KFileMetaInfoItem
+ // where the d-pointer is compared against null.
+ null = new Data(TQString::null);
+ null->mimeTypeInfo = new KFileMimeTypeInfo();
+ sd_KFileMetaInfoGroupData.setObject( null );
+ }
+ return null;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+KFileMimeTypeInfo::KFileMimeTypeInfo( const TQString& mimeType )
+ : m_mimeType( mimeType )
+{
+ m_groups.setAutoDelete( true );
+}
+
+KFileMimeTypeInfo::~KFileMimeTypeInfo()
+{
+}
+
+const KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::groupInfo( const TQString& group ) const
+{
+ return m_groups.find( group );
+}
+
+KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::addGroupInfo(
+ const TQString& name, const TQString& translatedName )
+{
+ GroupInfo* group = new GroupInfo( name, translatedName );
+ m_groups.insert(name, group);
+ return group;
+}
+
+TQStringList KFileMimeTypeInfo::supportedGroups() const
+{
+ TQStringList list;
+ TQDictIterator<GroupInfo> it( m_groups );
+ for ( ; it.current(); ++it )
+ list.append( it.current()->name() );
+
+ return list;
+}
+
+TQStringList KFileMimeTypeInfo::translatedGroups() const
+{
+ TQStringList list;
+ TQDictIterator<GroupInfo> it( m_groups );
+ for ( ; it.current(); ++it )
+ list.append( it.current()->translatedName() );
+
+ return list;
+}
+
+TQStringList KFileMimeTypeInfo::supportedKeys() const
+{
+ // not really efficient, but not those are not large lists, probably.
+ // maybe cache the result?
+ TQStringList keys;
+ TQStringList::ConstIterator lit;
+ TQDictIterator<GroupInfo> it( m_groups );
+ for ( ; it.current(); ++it ) { // need to nuke dupes
+ TQStringList list = it.current()->supportedKeys();
+ for ( lit = list.begin(); lit != list.end(); ++lit ) {
+ if ( keys.find( *lit ) == keys.end() )
+ keys.append( *lit );
+ }
+ }
+
+ return keys;
+}
+
+TQValidator * KFileMimeTypeInfo::createValidator(const TQString& group,
+ const TQString& key,
+ TQObject *parent,
+ const char *name) const
+{
+ KFilePlugin* plugin = KFileMetaInfoProvider::self()->plugin(m_mimeType);
+ if (plugin) return plugin->createValidator(mimeType(), group, key,
+ parent, name);
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+KFileMimeTypeInfo::GroupInfo::GroupInfo( const TQString& name,
+ const TQString& translatedName )
+ : m_name( name ),
+ m_translatedName( translatedName ),
+ m_attr( 0 ),
+ m_variableItemInfo( 0 )
+
+{
+ m_itemDict.setAutoDelete( true );
+}
+
+KFileMimeTypeInfo::GroupInfo::~GroupInfo()
+{
+ delete m_variableItemInfo;
+}
+
+const KFileMimeTypeInfo::ItemInfo * KFileMimeTypeInfo::GroupInfo::itemInfo( const TQString& key ) const
+{
+ ItemInfo* item = m_itemDict.find( key );
+
+ // if we the item isn't found and variable keys are supported, we need to
+ // return the default variable key iteminfo.
+ if (!item && m_variableItemInfo)
+ {
+ return m_variableItemInfo;
+ }
+ return item;
+}
+
+KFileMimeTypeInfo::ItemInfo* KFileMimeTypeInfo::GroupInfo::addItemInfo(
+ const TQString& key, const TQString& translatedKey,
+ TQVariant::Type type)
+{
+// kdDebug(7034) << key << "(" << translatedKey << ") -> " << TQVariant::typeToName(type) << endl;
+
+ ItemInfo* item = new ItemInfo(key, translatedKey, type);
+ m_supportedKeys.append(key);
+ m_itemDict.insert(key, item);
+ return item;
+}
+
+
+void KFileMimeTypeInfo::GroupInfo::addVariableInfo( TQVariant::Type type,
+ uint attr )
+{
+ // just make sure that it's not already there
+ delete m_variableItemInfo;
+ m_variableItemInfo = new ItemInfo(TQString::null, TQString::null, type);
+ m_variableItemInfo->m_attr = attr;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+TQString KFileMimeTypeInfo::ItemInfo::string(const TQVariant& value, bool mangle) const
+{
+ TQString s;
+
+ switch (value.type())
+ {
+ case TQVariant::Invalid :
+ return "---";
+
+ case TQVariant::Bool :
+ s = value.toBool() ? i18n("Yes") : i18n("No");
+ break;
+
+ case TQVariant::Int :
+ if (unit() == KFileMimeTypeInfo::Seconds)
+ {
+ int seconds = value.toInt() % 60;
+ int minutes = value.toInt() / 60 % 60;
+ int hours = value.toInt() / 3600;
+ s = hours ? TQString().sprintf("%d:%02d:%02d",hours, minutes, seconds)
+ : TQString().sprintf("%02d:%02d", minutes, seconds);
+ return s; // no suffix wanted
+ }
+ else if (unit() == KFileMimeTypeInfo::Bytes)
+ {
+ // convertSize already adds the correct suffix
+ return TDEIO::convertSize(value.toInt());
+ }
+ else if (unit() == KFileMimeTypeInfo::KiloBytes)
+ {
+ // convertSizeFromKB already adds the correct suffix
+ return TDEIO::convertSizeFromKB(value.toInt());
+ }
+ else
+ s = TDEGlobal::locale()->formatNumber( value.toInt() , 0);
+ break;
+
+ case TQVariant::LongLong :
+ s = TDEGlobal::locale()->formatNumber( value.toLongLong(), 0 );
+ break;
+
+ case TQVariant::ULongLong :
+ if ( unit() == KFileMimeTypeInfo::Bytes )
+ return TDEIO::convertSize( value.toULongLong() );
+ else if ( unit() == KFileMimeTypeInfo::KiloBytes )
+ return TDEIO::convertSizeFromKB( value.toULongLong() );
+ else
+ s = TDEGlobal::locale()->formatNumber( value.toULongLong(), 0 );
+ break;
+
+ case TQVariant::UInt :
+ s = TDEGlobal::locale()->formatNumber( value.toUInt() , 0);
+ break;
+
+ case TQVariant::Double :
+ s = TDEGlobal::locale()->formatNumber( value.toDouble(), 3);
+ break;
+
+ case TQVariant::Date :
+ s = TDEGlobal::locale()->formatDate( value.toDate(), true );
+ break;
+
+ case TQVariant::Time :
+ s = TDEGlobal::locale()->formatTime( value.toTime(), true );
+ break;
+
+ case TQVariant::DateTime :
+ s = TDEGlobal::locale()->formatDateTime( value.toDateTime(),
+ true, true );
+ break;
+
+ case TQVariant::Size :
+ s = TQString("%1 x %2").arg(value.toSize().width())
+ .arg(value.toSize().height());
+ break;
+
+ case TQVariant::Point :
+ s = TQString("%1/%2").arg(value.toSize().width())
+ .arg(value.toSize().height());
+ break;
+
+ default:
+ s = value.toString();
+ }
+
+ if (mangle && !s.isNull())
+ {
+ s.prepend(prefix());
+ s.append(" " + suffix());
+ }
+ return s;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+
+// stream operators
+
+/* serialization of a KFileMetaInfoItem:
+ first a bool that says if the items is valid, and if yes,
+ all the elements of the Data
+*/
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoItem& item )
+{
+
+ KFileMetaInfoItem::Data* d = item.d;
+
+ // if the object is invalid, put only a char in the stream
+ bool isValid = item.isValid();
+ s << isValid;
+ // ### what do about mimetypeInfo ?
+ if (isValid)
+ s << d->key
+ << d->value
+ << d->dirty
+ << d->added
+ << d->removed;
+
+ return s;
+}
+
+
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoItem& item )
+{
+ bool isValid;
+ s >> isValid;
+
+ if (!isValid)
+ {
+ item = KFileMetaInfoItem();
+ return s;
+ }
+
+ // we need a new object for our data
+ item.deref();
+ item.d = new KFileMetaInfoItem::Data();
+
+ // ### what do about mimetypeInfo ?
+ bool dirty, added, removed;
+ s >> item.d->key
+ >> item.d->value
+ >> dirty
+ >> added
+ >> removed;
+ item.d->dirty = dirty;
+ item.d->added = added;
+ item.d->removed = removed;
+
+ return s;
+}
+
+
+// serialization of a KFileMetaInfoGroup
+// we serialize the name of the mimetype here instead of the mimetype info
+// on the other side, we can simply use this to ask the provider for the info
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoGroup& group )
+{
+ KFileMetaInfoGroup::Data* d = group.d;
+
+ // if the object is invalid, put only a byte in the stream
+ bool isValid = group.isValid();
+
+ s << isValid;
+ if (isValid)
+ {
+ s << d->name
+ << d->items
+ << d->mimeTypeInfo->mimeType();
+ }
+ return s;
+}
+
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoGroup& group )
+{
+ TQString mimeType;
+ bool isValid;
+ s >> isValid;
+
+ // if it's invalid, there is not much to do
+ if (!isValid)
+ {
+ group = KFileMetaInfoGroup();
+ return s;
+ }
+
+ // we need a new object for our data
+ group.deref();
+ group.d = new KFileMetaInfoGroup::Data();
+
+ s >> group.d->name
+ >> group.d->items
+ >> mimeType;
+
+ group.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
+
+ // we need to set the item info for the items here
+ TQMapIterator<TQString, KFileMetaInfoItem> it = group.d->items.begin();
+ for ( ; it != group.d->items.end(); ++it)
+ {
+ (*it).d->mimeTypeInfo = group.d->mimeTypeInfo->groupInfo(group.d->name)
+ ->itemInfo((*it).key());
+ }
+
+ return s;
+}
+
+// serialization of a KFileMetaInfo object
+// we serialize the name of the mimetype here instead of the mimetype info
+// on the other side, we can simply use this to ask the provider for the info
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfo& info )
+{
+ KFileMetaInfo::Data* d = info.d;
+
+ // if the object is invalid, put only a byte that tells this
+ bool isValid = info.isValid();
+
+ s << isValid;
+ if (isValid)
+ {
+ s << d->url
+ << d->what
+ << d->groups
+ << d->mimeTypeInfo->mimeType();
+ }
+ return s;
+}
+
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfo& info )
+{
+ TQString mimeType;
+ bool isValid;
+ s >> isValid;
+
+ // if it's invalid, there is not much to do
+ if (!isValid)
+ {
+ info = KFileMetaInfo();
+ return s;
+ }
+
+ // we need a new object for our data
+ info.deref();
+ info.d = new KFileMetaInfo::Data();
+
+ s >> info.d->url
+ >> info.d->what
+ >> info.d->groups
+ >> mimeType;
+ info.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
+
+ return s;
+}
+
+#include "tdefilemetainfo.moc"
diff --git a/tdeio/tdeio/tdefilemetainfo.h b/tdeio/tdeio/tdefilemetainfo.h
new file mode 100644
index 000000000..8cc3fdbdf
--- /dev/null
+++ b/tdeio/tdeio/tdefilemetainfo.h
@@ -0,0 +1,1738 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2001-2002 Rolf Magnus <ramagnus@kde.org>
+ * Copyright (C) 2001-2002 Carsten Pfeiffer <pfeiffer@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 version 2.0.
+ *
+ * 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 KILEMETAINFO_H
+#define KILEMETAINFO_H
+
+/* Hack for HPUX: Namespace pollution
+ m_unit is a define in <sys/sysmacros.h> */
+#define m_unit outouftheway_m_unit
+
+#include <tqdict.h>
+#include <tqvariant.h>
+#include <tqobject.h>
+#include <tqstring.h>
+#include <kurl.h>
+
+#undef m_unit
+
+class TQValidator;
+class KFilePlugin;
+class KFileMetaInfoGroup;
+
+/**
+ * @brief Represents the capabilities of a KFilePlugin for a given mimetype
+ *
+ * This class provides information about the capabilities that a
+ * KFilePlugin for a given mimetype has. It includes a list of metainfo
+ * groups and items together with their type, a prefix, suffix and some other
+ * information about how to use, display or edit the items.
+ *
+ * @author Rolf Magnus
+ * @author Carsten Pfeiffer
+ */
+class TDEIO_EXPORT KFileMimeTypeInfo
+{
+ // the plugin needs to be a friend because it puts the data into the object,
+ // and it should be the only one allowed to do this.
+ friend class KFilePlugin;
+ friend class KFileMetaInfoProvider;
+
+public:
+ KFileMimeTypeInfo() {}
+
+ /**
+ * This enum is used to specify some attributes that an item can have,
+ * which fit neither in the Hint nor in the Unit enum.
+ */
+ enum Attributes
+ {
+ Addable = 1, ///< The item or group can be added by a user
+ Removable = 2, ///< It can be removed
+ Modifiable = 4, ///< The value can be edited (no meaning for a group)
+ Cumulative = 8, /**< If an application wants to display information
+ for more than one file, it may add up the values
+ for this item (e.g. play time of an mp3 file) */
+ Cummulative = Cumulative, ///< @deprecated Use Cumulative instead
+ Averaged = 16, /**< Similar to Cumulative, but the average should
+ be calculated instead of the sum */
+ MultiLine = 32, /**< This attribute says that a string item is likely
+ to be more than one line long, so for editing, a
+ widget capable for multline text should be used
+ @since 3.1 */
+ SqueezeText = 64 /**< If the text for this item is very long, it
+ should be squeezed to the size of the widget
+ where it's displayed
+ @since 3.1 */
+ };
+
+ /**
+ * This enum is mainly for items that have a special meaning for some
+ * applications.
+ */
+ enum Hint {
+ NoHint = 0, ///< No hint
+ Name = 1, ///< The name or title of the document
+ Author = 2, ///< The one who created the contents of it
+ Description = 3, ///< Description Some information about the document
+ Width = 4, ///< The width in pixels
+ Height = 5, ///< The height in pixels
+ Size = 6, ///< The size in pixels (width and height)
+ Bitrate = 7, ///< For media files
+ Length = 8, ///< The length of the file, also for media files
+ Hidden = 9, ///< The item is usually not shown to the user
+ Thumbnail = 10 ///< The item is a thumbnail picture of the file
+
+ };
+
+ /**
+ * This enum exists so that you can specify units for items, which you
+ * can usually use for integer items, so an application knows how to
+ * display it (e.g. a time in seconds in a hh:mm:ss form). You can either
+ * use one of those units, or if you don't find one that fits, you can
+ * add it yourself using a prefix and/or suffix.
+ */
+ enum Unit {
+ NoUnit = 0, ///< None of the listed units
+ Seconds = 1, ///< The item represents a time in seconds
+ MilliSeconds = 2, ///< The item represents a time in milliseconds
+ BitsPerSecond = 3, ///< A bit rate
+ Pixels = 4, ///< For image dimensions and similar
+ Inches = 5, ///< Sizes
+ Centimeters = 6, ///< Sizes
+ Bytes = 7, ///< Some data/file size in bytes
+ FramesPerSecond = 8, ///< A frame rate @since 3.1
+ DotsPerInch = 9, ///< Resolution in DPI @since 3.1
+ BitsPerPixel = 10, ///< A bit depth @since 3.1
+ Hertz = 11, ///< Sample rates and similar @since 3.1
+ KiloBytes = 12, ///< Some data/file size in kilobytes @since 3.1
+ Millimeters = 13 ///< Sizes @since 3.3
+ };
+
+
+ class ItemInfo;
+
+ /**
+ * @brief Information about a meta information group
+ *
+ * This is the class for one group of items of a KFileMimeTypeInfo.
+ * It contains, among other things, the information about the group's name
+ * and a list of supported items.
+ */
+ class TDEIO_EXPORT GroupInfo
+ {
+
+ friend class KFilePlugin;
+ friend class KFileMimeTypeInfo;
+ public:
+ /**
+ * Use this method to get a list of keys in the specified group that
+ * the plugin knows about. No variable keys.
+ * For a group that doesn't support variable keys, all keys that this
+ * group may have are returned. For a group that does support them, the
+ * non-variable ones are returned. See KFileMetaInfo about variable
+ * keys
+ *
+ * @return the list of keys supported for this mimetype
+ **/
+ TQStringList supportedKeys() const
+ {
+ return m_supportedKeys;
+ }
+
+ /**
+ * Use this method to get the name of the group. This string doesn't
+ * depend on the user's locale settings
+ *
+ * @return the group name
+ */
+ const TQString& name() const
+ {
+ return m_name;
+ }
+
+ /**
+ * Use this method to get the string to display to the user as group
+ * name. This may be different to name() and it returns the
+ * name in the user's language
+ *
+ * @return the translated group name
+ */
+ const TQString& translatedName() const
+ {
+ return m_translatedName;
+ }
+
+ /**
+ * A group object can contain several item objects (of which you can
+ * get the names with supportedKeys() . With this method, you can
+ * get one of those item objects. See ItemInfo
+ *
+ * @return a pointer to the item info. Don't delete this object!
+ */
+ const ItemInfo * itemInfo( const TQString& key ) const;
+
+ /**
+ * Get the attributes of this group (see Attributes)
+ *
+ * @return the attributes
+ */
+ uint attributes() const
+ {
+ return m_attr;
+ }
+
+ /**
+ * @return true if this group supports adding or removing arbitrary
+ * keys, false if not.
+ **/
+ bool supportsVariableKeys() const
+ {
+ return m_variableItemInfo;
+ }
+
+ /**
+ * If the group supports variable keys, you can query their item
+ * info with this method. The main reason for this is that you can
+ * get the type and attributes of variable keys.
+ *
+ * @return a pointer to the item info. Don't delete this object!
+ **/
+ const ItemInfo* variableItemInfo( ) const
+ {
+ return m_variableItemInfo;
+ }
+
+ /** @internal */
+ ~GroupInfo();
+ private:
+ /** @internal */
+ GroupInfo( const TQString& name, const TQString& translatedName);
+
+ /** @internal */
+ KFileMimeTypeInfo::ItemInfo* addItemInfo( const TQString& key,
+ const TQString& translatedKey,
+ TQVariant::Type type);
+
+ /** @internal */
+ void addVariableInfo( TQVariant::Type type, uint attr );
+
+ TQString m_name;
+ TQString m_translatedName;
+ TQStringList m_supportedKeys;
+ uint m_attr;
+ ItemInfo* m_variableItemInfo;
+ TQDict<ItemInfo> m_itemDict;
+
+ };
+
+ /**
+ * This is the class for one item of a KFileMimeTypeInfo.
+ * It contains every information about a KFileMetaInfoItem that this
+ * item has in common for each file of a specific mimetype.
+ **/
+ class TDEIO_EXPORT ItemInfo
+ {
+ friend class KFilePlugin;
+ friend class GroupInfo;
+ public:
+ /** @internal */
+ ItemInfo() {} // ### should be private?
+
+ /**
+ *
+ * This method returns a translated prefix to be displayed before the
+ * value. Think e.g. of the $ in $30
+ *
+ * @return the prefix
+ */
+ const TQString& prefix() const
+ {
+ return m_prefix;
+ }
+
+ /**
+ * This method returns a translated suffix to be displayed after the
+ * value. Think of the kbps in 128kbps
+ *
+ * @return the prefix
+ */
+ const TQString& suffix() const
+ {
+ return m_suffix;
+ }
+
+ /**
+ * The items for a file are stored as a TQVariant and this method
+ * can be used to get the data type of this item.
+ *
+ * @return the TQVariant type
+ */
+ TQVariant::Type type() const
+ {
+ return m_type;
+ }
+
+ /**
+ * Returns the name of the item.
+ * @return the name of the item
+ */
+ const TQString& key() const
+ {
+ return m_key;
+ }
+
+ /**
+ * Returns a string for the specified @p value, if possible. If not,
+ * TQString::null is returned. This can be used by programs if they want
+ * to display a sum or an average of some item for a list of files.
+ *
+ * @param value the value to convert
+ * @param mangle if true, the string will already contain prefix and
+ * suffix
+ * @return the converted string, or TQString::null if not possible
+ * @since 3.1
+ */
+ TQString string( const TQVariant& value, bool mangle = true ) const;
+
+ /**
+ * Is this item the variable item?
+ *
+ * @return true if it is, false if not
+ */
+ bool isVariableItem() const
+ {
+ // every valid item is supposed to have a non-null key
+ return key().isNull();
+ }
+
+ /**
+ * Returns a translation of the key for displaying to the user. If the
+ * plugin provides translation to the key, it's also in the user's
+ * language.
+ * @return the translated key
+ */
+ const TQString& translatedKey() const
+ {
+ return m_translatedKey;
+ }
+
+ /**
+ * Return the attributes of the item. See
+ * KFileMimeTypeInfo::Attributes.
+ * @return the attributes
+ */
+ uint attributes() const
+ {
+ return m_attr;
+ }
+
+ /**
+ * Return the hints for the item. See
+ * KFileMimeTypeInfo::Hint
+ * @return the hint
+ */
+ uint hint() const
+ {
+ return m_hint;
+ }
+
+ /**
+ * Return the unit of the item. See
+ * KFileMimeTypeInfo::Unit
+ * @return the unit
+ */
+ uint unit() const
+ {
+ return m_unit;
+ }
+
+ private:
+ /** @internal */
+ ItemInfo(const TQString& key, const TQString& translatedKey,
+ TQVariant::Type type)
+ : m_key(key), m_translatedKey(translatedKey),
+ m_type(type),
+ m_attr(0), m_unit(NoUnit), m_hint(NoHint),
+ m_prefix(TQString::null), m_suffix(TQString::null)
+ {}
+
+ TQString m_key;
+ TQString m_translatedKey;
+ TQVariant::Type m_type;
+ uint m_attr;
+ uint m_unit;
+ uint m_hint;
+ TQString m_prefix;
+ TQString m_suffix;
+ };
+
+ // ### could it be made private? Would this be BC?
+ ~KFileMimeTypeInfo();
+
+ /**
+ * Creates a validator for this item. Make sure to supply a proper
+ * @p parent argument or delete the validator yourself.
+ *
+ * @param group the group of the item
+ * @param key the key of the item
+ * @param parent the parent of the TQObject, or 0 for a parent-less object
+ * @param name the name of the TQObject, can be 0
+ * @return the validator. You are responsible for deleting it. 0 if
+ * creation failed
+ */
+ TQValidator * createValidator(const TQString& group, const TQString& key,
+ TQObject *parent = 0, const char *name = 0) const;
+
+ /**
+ * Returns the list of all groups that the plugin for this mimetype
+ * supports.
+ *
+ * @return the list of groups
+ */
+ TQStringList supportedGroups() const;
+
+ /**
+ * Same as the above function, but returns the strings to display to the
+ * user.
+ *
+ * @return the list of groups
+ */
+ TQStringList translatedGroups() const;
+
+ /**
+ * This returns the list of groups in the preferred order that's specified
+ * in the .desktop file.
+ *
+ * @return the list of groups
+ */
+ TQStringList preferredGroups() const
+ {
+ return m_preferredGroups;
+ }
+
+ /**
+ * Returns the mimetype to which this info belongs.
+ *
+ * @return the mimetype of this info
+ */
+ TQString mimeType() const {return m_mimeType;}
+
+ /**
+ * Get the group info for a specific group.
+ *
+ * @param group the group whose group info should be retrieved
+ * @return a pointer to the info. 0 if it does not
+ * exist. Don't delete this object!
+ */
+ const GroupInfo * groupInfo( const TQString& group ) const;
+
+ // always returning stringlists which the user has to iterate and use them
+ // to look up the real items sounds strange to me. I think we should add
+ // our own iterators some time (somewhere in the future ;)
+
+ /**
+ * Return a list of all supported keys without looking for a specific
+ * group
+ *
+ * @return the list of keys
+ */
+ TQStringList supportedKeys() const;
+
+ /**
+ * Return a list of all supported keys in preference order
+ *
+ * @return the list of keys
+ */
+ TQStringList preferredKeys() const
+ {
+ return m_preferredKeys;
+ }
+
+ // ### shouldn't this be private? BC?
+ GroupInfo * addGroupInfo( const TQString& name,
+ const TQString& translatedName);
+
+ TQString m_translatedName;
+ TQStringList m_supportedKeys;
+ uint m_attr;
+ // bool m_supportsVariableKeys : 1;
+ TQDict<ItemInfo> m_itemDict;
+
+// ### this should be made private instead, but this would be BIC
+protected:
+ /** @internal */
+ KFileMimeTypeInfo( const TQString& mimeType );
+
+ TQDict<GroupInfo> m_groups;
+ TQString m_mimeType;
+ TQStringList m_preferredKeys; // same as KFileMetaInfoProvider::preferredKeys()
+ TQStringList m_preferredGroups; // same as KFileMetaInfoProvider::preferredKeys()
+};
+
+
+/**
+ * @brief A meta information item about a file
+ *
+ * This is one item of the meta information about a file (see
+ * KFileMetaInfo).
+ */
+class TDEIO_EXPORT KFileMetaInfoItem
+{
+public:
+ class Data;
+ typedef KFileMimeTypeInfo::Hint Hint;
+ typedef KFileMimeTypeInfo::Unit Unit;
+ typedef KFileMimeTypeInfo::Attributes Attributes;
+
+ /**
+ * @internal
+ * You usually don't need to use this constructor yourself. Let
+ * KFileMetaInfo do it for you.
+ **/
+ // ### hmm, then it should be private
+ KFileMetaInfoItem( const KFileMimeTypeInfo::ItemInfo* mti,
+ const TQString& key, const TQVariant& value);
+
+ /**
+ * Copy constructor
+ **/
+ KFileMetaInfoItem( const KFileMetaInfoItem & item );
+
+ /**
+ * The assignment operator, so you can do:
+ * @code
+ * KFileMetaInfoItem item = info.item("Title");
+ * @endcode
+ *
+ * This will create a shared copy of the object. The actual data
+ * is automatically deleted if all copies go out of scope
+ **/
+ const KFileMetaInfoItem& operator= (const KFileMetaInfoItem & item );
+
+ /**
+ * Default constructor. This creates an "invalid" item
+ */
+ KFileMetaInfoItem();
+
+ ~KFileMetaInfoItem();
+
+ /**
+ * Returns the key of the item.
+ *
+ * @return the key of this item
+ */
+ TQString key() const;
+
+ /**
+ * Returns a translation of the key for displaying to the user. If the
+ * plugin provides translation to the key, it's also in the user's language
+ *
+ * @return the translated key
+ */
+ TQString translatedKey() const;
+
+ /**
+ * Returns the value of the item.
+ *
+ * @return the value of the item.
+ */
+ const TQVariant& value() const;
+
+ /**
+ * Returns a string containing the value, if possible. If not,
+ * TQString::null is returned.
+ *
+ * @param mangle if true, the string will already contain prefix and
+ * suffix
+ * @return the value string, or TQString::null if not possible
+ */
+ TQString string( bool mangle = true ) const;
+
+ /**
+ * Changes the value of the item.
+ *
+ * @param value the new value
+ * @return true if successful, false otherwise
+ */
+ bool setValue( const TQVariant& value );
+
+ /**
+ * Return the type of the item.
+ *
+ * @return the type of the item
+ */
+ TQVariant::Type type() const;
+
+ /**
+ * You can query if the application can edit the item and write it back to
+ * the file with this method.
+ *
+ * @note This doesn't ensure that you have write access to the file and
+ * that enough space is available.
+ *
+ * @return true if the item's value can be changed, false if not
+ */
+ bool isEditable() const;
+
+ /**
+ * If you remove an item, it is only marked for removal for the file. On
+ * the next KFileMetaInfo::applyChanges() , it will be removed from
+ * the file. With this method, you can ask if the item is marked for
+ * removal.
+ *
+ * @return true if the item was removed, false if not
+ */
+ bool isRemoved() const;
+
+ /**
+ * If you change an item, it is marked as "dirty". On the next
+ * KFileMetaInfo::applyChanges() , the change will be written to the
+ * file. With this method, you can ask if this item is dirty.
+ *
+ * @return true if the item contains changes that have not yet been written
+ * back into the file. Removing or adding an item counts as such a change
+ */
+ bool isModified() const;
+
+ /**
+ * This method returns a translated prefix to be displayed before the
+ * value. Think e.g. of the $ in $30
+ *
+ * @return the prefix
+ */
+ TQString prefix() const;
+
+ /**
+ * This method returns a translated suffix to be displayed after the
+ * value. Think of the kbps in 128kbps
+ *
+ * @return the suffix
+ */
+ TQString suffix() const;
+
+ /**
+ * Returns the hint for this item. See KFileMimeTypeInfo::Hint.
+ *
+ * @return the hint
+ **/
+ uint hint() const;
+
+ /**
+ * Returns the unit for this item. See KFileMimeTypeInfo::Unit.
+ *
+ * @return the unit
+ * @since 3.2
+ **/
+ uint unit() const;
+
+ /**
+ * Returns the attributes for this item. See
+ * KFileMimeTypeInfo::Attributes.
+ *
+ * @return the attributes
+ **/
+ uint attributes() const;
+
+ /**
+ * Return true if the item is valid, i.e. if it contains data, false
+ * if it's invalid (created with the default constructor and not been
+ * assigned anything), or if KFileMetaInfoGroup::item() didn't find
+ * your requested item).
+ *
+ * @return true if valid, false if invalid
+ */
+ bool isValid() const;
+
+ TDEIO_EXPORT friend TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoItem& );
+ TDEIO_EXPORT friend TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoGroup& );
+ TDEIO_EXPORT friend TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoItem& );
+ friend class KFileMetaInfoGroup;
+
+protected:
+ void setAdded();
+ void setRemoved();
+
+ void ref();
+ void deref();
+
+ Data *d;
+};
+
+/**
+ * @brief A group of meta information items about a file
+ *
+ * This is one group of meta information items about a file (see
+ * KFileMetaInfo).
+ */
+class TDEIO_EXPORT KFileMetaInfoGroup
+{
+ friend class KFilePlugin;
+ friend class KFileMetaInfo;
+ TDEIO_EXPORT friend TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoGroup& );
+ TDEIO_EXPORT friend TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoGroup& );
+
+public:
+ class Data;
+ /**
+ * @internal
+ * You usually don't need to use this constructor yourself. Let
+ * KFileMetaInfo do it for you.
+ **/
+ // ### hmm, then it should be private
+ KFileMetaInfoGroup( const TQString& name, const KFileMimeTypeInfo* info );
+
+ /**
+ * Copy constructor
+ **/
+ KFileMetaInfoGroup( const KFileMetaInfoGroup& original );
+
+ /**
+ * The assignment operator, so you can do:
+ * @code
+ * KFileMetaInfoGroup group = info.group("Technical");
+ * @endcode
+ *
+ * This will create a shared copy of the object. The actual data
+ * is automatically deleted if all copies go out of scope
+ **/
+ const KFileMetaInfoGroup& operator= (const KFileMetaInfoGroup& info );
+
+ /**
+ * Default constructor. This creates an "invalid" item
+ *
+ * @since 3.1
+ */
+ KFileMetaInfoGroup();
+
+ ~KFileMetaInfoGroup();
+
+ /**
+ * Returns true if the item is valid, i.e. if it contains data, false
+ * if it's invalid (created with the default constructor and not been
+ * assigned anything), or if KFileMetaInfoGroup::item() didn't find
+ * your requested item).
+ *
+ * @return true if valid, false if invalid
+ */
+ bool isValid() const;
+
+ /**
+ * Returns false if the object contains data, true if it's empty. An
+ * empty group is a group with no items (amazing, isn't it?).
+ *
+ * @return true if empty, false otherwise
+ */
+ bool isEmpty() const;
+
+ /**
+ * Returns true if an item as added or removed from the group.
+ *
+ * @return true if an item was added or removed from the group, otherwise
+ * false.
+ *
+ * @since 3.1
+ */
+ bool isModified() const;
+
+ /**
+ * Operator for convenience. It does the same as item(),
+ * but you cannot specify a group to search in
+ */
+ KFileMetaInfoItem operator[]( const TQString& key ) const
+ { return item( key ); }
+
+ /**
+ * This method searches for the specified item.
+ *
+ * @param key the key of the item to search
+ * @return the specified item if found, an invalid item, if not
+ **/
+ KFileMetaInfoItem item( const TQString& key ) const;
+
+ /**
+ * Returns the item with the given @p hint.
+ *
+ * @param hint the hint of the item
+ * @return the item with the specified @p hint
+ **/
+ KFileMetaInfoItem item( uint hint ) const;
+
+ /**
+ * Convenience function. Returns the value of the specified key.
+ * It does the same as item(key).value().
+ *
+ * @param key the key of the item to search
+ * @return the value with the given key
+ */
+ const TQVariant value( const TQString& key ) const
+ {
+ const KFileMetaInfoItem &i = item( key );
+ return i.value();
+ }
+
+ /**
+ * Use this method to get a list of keys in the specified group that
+ * the plugin knows about. No variable keys.
+ * For a group that doesn't support variable keys, all keys that this
+ * group may have are returned. For a group that does support them, the
+ * non-variable ones are returned. See KFileMetaInfo about variable
+ * keys
+ *
+ * @return the list of keys supported for this mimetype
+ **/
+ TQStringList supportedKeys() const;
+
+ /**
+ * Returns true if this group supports adding or removing arbitrary
+ * keys, false if not.
+ *
+ * @return true is variable keys are supported, false otherwise
+ **/
+ bool supportsVariableKeys() const;
+
+ /**
+ * Checks whether an item with the given @p key exists.
+ *
+ * @return true if an item for this @p key exists.
+ */
+ bool contains( const TQString& key ) const;
+
+ /**
+ * Returns a list of all keys.
+ *
+ * @return a list of all keys in the order they were inserted.
+ **/
+ TQStringList keys() const;
+
+ /**
+ * Returns a list of all keys in preference order.
+ *
+ * @return a list of all keys in preference order.
+ **/
+ TQStringList preferredKeys() const;
+
+ /**
+ * @return the list of possible types that the value for the specified key
+ * can be. You can use this to determine the possible types for new
+ * keys before you add them.
+ *
+ **/
+ // ### do we really want to support that?
+ // let's not waste time on thinking about it. Let's just kick it for now
+ // and add it in 4.0 if needed ;)
+// const TQMemArray<TQVariant::Type>& types( const TQString& key ) const;
+
+ /**
+ * Add an item to the info. This is only possible if the specified @p key
+ * is in the supportedKeys list and not yet defined or if
+ * the group supports variable keys.
+ *
+ * @param key the key of the item
+ * @return the KFileMetaInfoItem for the given @p key
+ **/
+ KFileMetaInfoItem addItem( const TQString& key );
+
+ /**
+ * Remove this item from the meta info of the file. You cannot query
+ * KFileMetaInfo for a removed object, but you can query for a list of
+ * removed items with removedItems() if you need to.
+ * If you re-add it, its value will be cleared.
+ *
+ * @param key the key of the removed item
+ * @return true if successful, false otherwise
+ */
+ bool removeItem(const TQString& key);
+
+ /**
+ * Returns a list of all removed items.
+ *
+ * @return a list of all removed items
+ */
+ TQStringList removedItems();
+
+ /**
+ * The name of this group.
+ *
+ * @return the name of this group
+ */
+ TQString name() const;
+
+ /**
+ * The translated name of this group.
+ *
+ * @return the translated name of this group
+ *
+ * @since 3.2
+ */
+ TQString translatedName() const;
+
+ /**
+ * Returns the attributes of this item.
+ *
+ * @return the attributes
+ */
+ uint attributes() const;
+
+protected:
+ void setAdded();
+ KFileMetaInfoItem appendItem( const TQString& key, const TQVariant& value);
+
+ Data* d;
+ void ref();
+ void deref();
+
+};
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+/**
+ * @brief Meta Information about a file
+ *
+ * This is the class for objects that hold meta information about a file.
+ * The information is kept in form of a system of key/value pairs. See also
+ * KFileMetaInfoItem.
+ * This information is retrieved from the file through a plugin system, and
+ * this class is the main interface to it.
+ * If you want to write your own plugin, have a look at KFilePlugin.
+ * There are basically two different kinds of meta information: Fixed ones
+ * that the plugin knows about (e.g. an mp3 id3v1 tag has a well defined
+ * fixed list of fields), and variable keys that exist in mimetypes that
+ * support their own key/value system (comments in png files are of this type).
+ * Almost every file has fixed keys, but some also have variable keys.
+ *
+ * The groups and the What enum are not yet supported, but already added to
+ * the interface so that adding support doesn't break compatibility.
+ */
+class TDEIO_EXPORT KFileMetaInfo
+{
+public:
+ typedef KFileMimeTypeInfo::Hint Hint;
+ typedef KFileMimeTypeInfo::Unit Unit;
+ typedef KFileMimeTypeInfo::Attributes Attributes;
+ class Data;
+
+ /**
+ * This is used to specify what a KFileMetaInfo object should read, so
+ * you can specify if you want to read "expensive" items or not.
+ */
+ enum What
+ {
+ Fastest = 0x1, /**< do the fastest possible read and omit all items
+ that might need a significantly longer time
+ than the others */
+ DontCare = 0x2, ///< let the plugin decide what to read
+
+ TechnicalInfo = 0x4, /**< extract technical details about the file, like
+ e.g. play time, resolution or a compressioni
+ type */
+ ContentInfo = 0x8, /**< read information about the content of the file,
+ like comments or id3 tags */
+ ExtenedAttr = 0x10, /**< read filesystem based extended attributes if
+ they are supported for the filesystem */
+ Thumbnail = 0x20, /**< only read the file's thumbnail, if it contains
+ one */
+ Preferred = 0x40, ///< get at least the preferred items
+ Everything = 0xffff ///< read everything, even if it might take a while
+
+ };
+
+ /**
+ * The constructor.
+ *
+ * creating a KFileMetaInfo item through this will autoload the plugin
+ * belonging to the mimetype and try to get meta information about
+ * the specified file.
+ *
+ * If no info is available, you'll get an empty (not invalid) object.
+ * You can test for it with the isEmpty() method.
+ *
+ * @param path The file name. This must be the path to a local file.
+ * @param mimeType The name of the file's mimetype. If ommited, the
+ * mimetype is autodetected
+ * @param what one or more of the What enum values. It gives some
+ * hint to the plugin what information is desired. The plugin
+ * may still return more items.
+ *
+ * @note This version will @b only work for @b local (file:/) files.
+ *
+ **/
+ KFileMetaInfo( const TQString& path,
+ const TQString& mimeType = TQString::null,
+ uint what = Fastest);
+
+ /**
+ * Another constructor
+ *
+ * Similar to the above, but takes a URL so that meta-data may be retrieved
+ * over other protocols (ftp, etc.)
+ *
+ **/
+ KFileMetaInfo( const KURL& url,
+ const TQString& mimeType = TQString::null,
+ uint what = Fastest);
+
+ /**
+ * Default constructor. This will create an invalid object (see
+ * isValid().
+ **/
+ KFileMetaInfo();
+
+ /**
+ * Copy constructor. This creates a copy of the original object, but
+ * that copy will point to the same data, so if you change the original,
+ * the copy will be changed, too. After all, they are referring to the same
+ * file.
+ **/
+ KFileMetaInfo( const KFileMetaInfo& original);
+
+ ~KFileMetaInfo();
+
+ /**
+ * The assignment operator, so you can do e.g.:
+ * @code
+ * KFileMetaInfo info;
+ * if (something) info = KFileMetaInfo("/the/file");
+ * @endcode
+ *
+ * This will create a shared copy of the object. The actual data
+ * is automatically deleted if all copies go out of scope.
+ **/
+ const KFileMetaInfo& operator= (const KFileMetaInfo& info );
+
+
+ /**
+ * Returns a list of all groups.
+ *
+ * @return the keys of the groups that the file has.
+ */
+ TQStringList groups() const;
+
+ /**
+ * Returns a list of all supported groups.
+ *
+ * @return the supported keys of the groups that the file has.
+ */
+ TQStringList supportedGroups() const;
+
+ /**
+ * Returns a list of the preferred groups.
+ *
+ * @return the keys of the preferred groups that the file has.
+ */
+ TQStringList preferredGroups() const;
+
+ /**
+ * Returns a list of all preferred keys.
+ *
+ * @return a list of all preferred keys.
+ */
+ TQStringList preferredKeys() const;
+
+ /**
+ * Returns a list of supported keys.
+ *
+ * @return a list of supported keys
+ */
+ TQStringList supportedKeys() const;
+
+ /**
+ * Returns the list of groups that you can add or remove from the file.
+ *
+ * @return the groups can be added or removed
+ */
+ TQStringList editableGroups() const;
+
+ // I'd like to keep those for lookup without group, at least the hint
+ // version
+ /**
+ * Returns the KFileMetaInfoItem with the given @p key.
+ *
+ * @param key the key of the item
+ * @return the item. Invalid if there is no item with the given @p key.
+ */
+ KFileMetaInfoItem item(const TQString& key) const;
+ /**
+ * Returns the KFileMetaInfoItem with the given @p hint.
+ *
+ * @param hint the hint of the item
+ * @return the item. Invalid if there is no item with the given @p hint.
+ */
+ KFileMetaInfoItem item(const KFileMetaInfoItem::Hint hint) const;
+
+ /**
+ * Saves the item with the given @p key.
+ *
+ * @param key the key of the item
+ * @param preferredGroup the preferred group, or TQString::null
+ * @param createGroup true to create the group if necessary
+ * @return the saved item
+ */
+ KFileMetaInfoItem saveItem( const TQString& key,
+ const TQString& preferredGroup = TQString::null,
+ bool createGroup = true );
+
+ /**
+ * Returns the KFileMetaInfoGroup with the given @p key.
+ *
+ * @param key the key of the item
+ * @return the group. Invalid if there is no group with the given @p key.
+ */
+ KFileMetaInfoGroup group(const TQString& key) const;
+
+ /**
+ * Returns the KFileMetaInfoGroup with the given @p key.
+ *
+ * @param key the key of the item
+ * @return the group. Invalid if there is no group with the given @p key.
+ */
+ KFileMetaInfoGroup operator[] (const TQString& key) const
+ {
+ return group(key);
+ }
+
+ /**
+ * Try to add the specified group. This will only succeed if it is
+ * in the list of editableGroups().
+ *
+ * @note that all non-variable items that belong to this group are
+ * automatically added as empty item.
+ *
+ * @param name the name of the group to add
+ * @return true if successful, false if not
+ */
+ bool addGroup( const TQString& name );
+
+ /**
+ * Remove the specified group. This will only succeed if it is
+ * in the list of editableGroups(). Beware that this also
+ * removes all the items in that group, so always ask the user
+ * before removing it!
+ *
+ * @param name the name of the group to remove
+ * @return true if successful, false if not
+ */
+ bool removeGroup( const TQString& name );
+
+ /**
+ * Returns a list of removed groups.
+ *
+ * @return a list of removed groups.
+ */
+ TQStringList removedGroups();
+
+ /**
+ * This method writes all pending changes of the meta info back to the file.
+ * If any items are marked as removed, they are really removed from the
+ * list. The info object as well as all items are updated.
+ *
+ * @return true if successful, false if not
+ */
+ bool applyChanges();
+
+ /**
+ * This method writes all pending changes of the meta info to the file @p path.
+ * If any items are marked as removed, they are really removed from the
+ * list. The info object as well as all items are updated.
+ *
+ * @return true if successful, false if not
+ */
+ bool applyChanges(const TQString& path);
+
+ /**
+ * Checks whether an item with the given @p key exists.
+ *
+ * @param key the key to check
+ * @return whether an item for this @p key exists.
+ */
+ bool contains( const TQString& key ) const;
+
+ /**
+ * Checks whether a group with the given @p key exists.
+ *
+ * @param key the key to check
+ * @return whether a group with this name exists.
+ */
+ bool containsGroup( const TQString& key ) const;
+
+ /**
+ * Returns the value with the given @p key.
+ *
+ * @param key the key to retrieve
+ * @return the value. Invalid if it does not exist
+ */
+ const TQVariant value( const TQString& key ) const
+ {
+ return item(key).value();
+ }
+
+
+ /**
+ * Returns true if the item is valid, i.e. if actually represents the info
+ * about a file, false if the object is uninitialized.
+ *
+ * @return true if valid, false otherwise
+ */
+ bool isValid() const;
+
+ /**
+ * Returns false if the object contains data, true if it's empty. You'll
+ * get an empty object if no plugin for the file could be found.
+ *
+ * @return true if empty, false otherwise
+ */
+ bool isEmpty() const;
+
+ /**
+ * Returns the mime type of file.
+ *
+ * @return the file's mime type
+ */
+ TQString mimeType() const;
+
+ /**
+ * Returns the path of file - or TQString::null if file is non-local
+ *
+ * @return the file's path - or TQString::null if file is non-local
+ */
+ TQString path() const;
+
+ /**
+ * Returns the url of file
+ *
+ * @return the file's url
+ */
+ KURL url() const;
+
+ TDEIO_EXPORT friend TQDataStream& operator >>(TQDataStream& s, KFileMetaInfo& );
+ TDEIO_EXPORT friend TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfo& );
+ friend class KFilePlugin;
+
+protected:
+ KFileMetaInfoGroup appendGroup(const TQString& name);
+
+ /**
+ * @return a pointer to the plugin that belogs to this object's mimetype.
+ * It will be auto-loaded if it's currently not loaded
+ **/
+ KFilePlugin * plugin() const;
+
+ void ref();
+ void deref();
+
+ Data* d;
+
+private:
+ KFileMetaInfoItem findEditableItem( KFileMetaInfoGroup& group,
+ const TQString& key );
+
+ void init( const KURL& url,
+ const TQString& mimeType = TQString::null,
+ uint what = Fastest);
+};
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+/**
+ * @brief Base class for a meta information plugin
+ *
+ * Meta information plugins are used to extract useful information from files
+ * of a given type. These plugins are used in Konqueror's file properties
+ * dialog, for example.
+ *
+ * If you want to write your own plugin, you need to derive from this class.
+ *
+ * In the constructor of your class, you need to call addMimeTypeInfo() to tell
+ * the KFile framework which mimetype(s) your plugin supports. For each
+ * mimetype, use the addGroupInfo() and addItemInfo() methods to declare the
+ * meta information items the plugin calculates and to group them accordingly.
+ * For groups, use setAttributes() to customize your group (see
+ * KFileMimeTypeInfo::Attributes). For items, use setAttributes() to define the
+ * behaviour of the item; use setHint() to define the meaning of the item; use
+ * setUnit() to define the Unit, such as KFileMimeTypeInfo::Seconds or
+ * KFileMimeTypeInfo::KiloBytes. In short, the constructor defines the data
+ * structure of the meta information supported by your plugin.
+ *
+ * Example:
+ * @code
+ * FooPlugin::FooPlugin(TQObject *parent, const char *name,
+ * const TQStringList &args)
+ * : KFilePlugin(parent, name, args)
+ * {
+ * KFileMimeTypeInfo* info = addMimeTypeInfo( "application/x-foo" );
+ *
+ * // our new group
+ * KFileMimeTypeInfo::GroupInfo* group = 0L;
+ * group = addGroupInfo(info, "FooInfo", i18n("Foo Information"));
+ *
+ * KFileMimeTypeInfo::ItemInfo* item;
+ *
+ * // our new items in the group
+ * item = addItemInfo(group, "Items", i18n("Items"), TQVariant::Int);
+ * item = addItemInfo(group, "Size", i18n("Size"), TQVariant::Int);
+ * setUnit(item, KFileMimeTypeInfo::KiloBytes);
+ *
+ * // strings are possible, too:
+ * //addItemInfo(group, "Document Type", i18n("Document type"), TQVariant::String);
+ * }
+ * @endcode
+ *
+ * Some meta information items are likely to be available in several different
+ * file formats, such as @c "Author", @c "Title" (for documents), and
+ * @c "Length" (for multimedia files). Be sure to use the naming scheme from
+ * existing plugins for your meta information items if possible. If, for
+ * example, the meta information of a group of files is shown in a table view,
+ * this will allow two files to share the same column (say "Length") even if
+ * they are of a different file type.
+ *
+ * You must overwrite the readInfo() method. In this method you need to extract
+ * the meta information of the given file. You can use a third-party library to
+ * achieve this task. This might be the best way for binary files, since a
+ * change in the file format is likely to be supported by subsequent releases
+ * of that library. Alternatively, for text-based file formats, you can use
+ * TQTextStream to parse the file. For simple file formats, TQRegExp can be of
+ * great help, too.
+ *
+ * After you extracted the relevant information, use appendGroup() and
+ * appendItem() to fill the meta information data structure (as defined in the
+ * constructor) with values. Note that you can leave out groups or items
+ * which are not appropriate for a particular file.
+ *
+ * Example:
+ * @code
+ * bool FooPlugin::readInfo( KFileMetaInfo& info, uint what)
+ * {
+ * int numItems = 0;
+ * int size = 0;
+ *
+ * // do your calculations here, e.g. using a third-party
+ * // library or by writing an own parser using e.g. QTextStream
+ *
+ * // calculate numItems and size ...
+ *
+ * // note: use the same key strings as in the constructor
+ * KFileMetaInfoGroup group = appendGroup(info, "FooInfo");
+ *
+ * appendItem(group, "Items", numItems);
+ * appendItem(group, "Size", size);
+ *
+ * return true;
+ * }
+ * @endcode
+ *
+ * If you want to define mutable meta information items, you need to overwrite
+ * the writeInfo() method. In this method, you can use third-party library
+ * (appropriate mostly for binary files, see above) or TQTextStream to write the
+ * information back to the file. If you use TQTextStream, be sure to write all
+ * file contents back.
+ *
+ * For some items, it might be that not all possible values are allowed. You
+ * can overwrite the createValidator() method to define constraints for a meta
+ * information item. For example, the @c "Year" field for an MP3 file could
+ * reject values outside the range 1500 - 2050 (at least for now). The
+ * validator is used to check values before the writeInfo() method is called so
+ * that writeInfo() is only provided correct values.
+ *
+ * In your plugin, you need to create a factory for the KFilePlugin
+ *
+ * Example:
+ * @code
+ * typedef KGenericFactory<FooPlugin> FooFactory;
+ * K_EXPORT_COMPONENT_FACTORY(tdefile_foo, FooFactory("tdefile_foo"));
+ * @endcode
+ *
+ * To make your plugin available within KDE, you also need to provide a
+ * @c .desktop file which describes your plugin. The required fields in the
+ * file are:
+ *
+ * - @c Type: must be @c "Service"
+ * - @c Name: the name of the plugin
+ * - @c ServiceTypes: must contain @c "KFilePlugin"
+ * - @c X-TDE-Library: the name of the library containing the KFile plugin
+ * - @c MimeType: the mimetype(s) which are supported by the plugin
+ * - @c PreferredGroups: a comma-separated list of the most important groups.
+ * This list defines the order in which the meta information groups should be
+ * displayed
+ * - @c PreferredItems: a comma-separated list of the most important items.
+ * This list defines the order in which the meta information items should be
+ * displayed
+ *
+ * Example:
+ * @code
+ * [Desktop Entry]
+ * Encoding=UTF-8
+ * Type=Service
+ * Name=Foo Info
+ * ServiceTypes=KFilePlugin
+ * X-TDE-Library=tdefile_foo
+ * MimeType=application/x-foo
+ * PreferredGroups=FooInfo
+ * PreferredItems=Items,Size
+ * @endcode
+ **/
+class TDEIO_EXPORT KFilePlugin : public TQObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Creates a new KFilePlugin instance. You need to implement a constructor
+ * with the same argument list as this is required by KGenericFactory
+ *
+ * @param parent the parent of the TQObject, can be @c 0
+ * @param name the name of the TQObject, can be @c 0
+ * @param args currently ignored
+ *
+ * @see addMimeTypeInfo()
+ * @see addGroupInfo()
+ * @see addItemInfo()
+ * @see TQObject()
+ **/
+ KFilePlugin( TQObject *parent, const char *name,
+ const TQStringList& args );
+
+ /**
+ * Destructor
+ */
+ virtual ~KFilePlugin();
+
+ /**
+ * Read the info from the file in this method and insert it into the
+ * provided KFileMetaInfo object. You can get the path to the file with
+ * KFileMetaInfo::path(). Use appendGroup() and appendItem() to fill
+ * @p info with the extracted values
+ *
+ * @param info the information will be written here
+ * @param what defines what to read, see KFileMetaInfo::What
+ * @return @c true if successful, @c false if it failed
+ *
+ * @see writeInfo()
+ **/
+ virtual bool readInfo( KFileMetaInfo& info,
+ uint what = KFileMetaInfo::Fastest ) = 0;
+
+ /**
+ * Similar to the readInfo() but for writing the info back to the file.
+ * If you don't have any writable keys, don't implement this method
+ *
+ * @param info the information that will be written
+ * @return @c true if successful, @c false if it failed
+ **/
+ virtual bool writeInfo( const KFileMetaInfo& info ) const
+ {
+ Q_UNUSED(info);
+ return true;
+ }
+
+ /**
+ * This method should create an appropriate validator for the specified
+ * item if it's editable or return a null pointer if not. If you don't have
+ * any editable items, you don't need to implement this method.
+ *
+ * If you you don't need any validation, e.g. you accept any input, you can
+ * simply return @c 0L, or not reimplement this method at all.
+ *
+ * @param mimeType the mime type
+ * @param group the group name of the validator item
+ * @param key the key name of the validator item
+ * @param parent the TQObject parent, can be @c 0
+ * @param name the name of the TQObject, can be @c 0
+ **/
+ virtual TQValidator* createValidator( const TQString& mimeType,
+ const TQString& group,
+ const TQString& key,
+ TQObject* parent,
+ const char* name) const
+ {
+ Q_UNUSED(mimeType); Q_UNUSED(group);Q_UNUSED(key);
+ Q_UNUSED(parent);Q_UNUSED(name);
+ return 0;
+ }
+
+protected:
+
+ /**
+ * Call this from within your constructor to tell the KFile framework what
+ * mimetypes your plugin supports.
+ *
+ * @param mimeType a string containing the mimetype, e.g. @c "text/html"
+ * @return a KFileMimeTypeInfo object, to be used with addGroupInfo()
+ **/
+ KFileMimeTypeInfo * addMimeTypeInfo( const TQString& mimeType );
+ // ### do we need this, if it only calls the provider?
+ // IMHO the Plugin shouldn't call its provider.
+ // DF: yes we need this. A plugin can create more than one mimetypeinfo.
+ // What sucks though, is to let plugins do that in their ctor.
+ // Would be much simpler to have a virtual init method for that,
+ // so that the provider can set up stuff with the plugin pointer first!
+
+ /**
+ * Creates a meta information group for KFileMimeTypeInfo object returned
+ * by addMimeTypeInfo().
+ *
+ * @param info the object returned by addMimeTypeInfo()
+ * @param key a unique string identifiing this group. For simplicity it is
+ * recommended to use the same string as for the translatedKey
+ * parameter
+ * @param translatedKey the translated version of the key string for
+ * displaying in user interfaces. Use i18n() to translate the string
+ * @return a GroupInfo object. Pass this object to addItemInfo to add meta
+ * information attributed to this group.
+ *
+ * @see setAttributes()
+ * @see addItemInfo()
+ **/
+ KFileMimeTypeInfo::GroupInfo* addGroupInfo(KFileMimeTypeInfo* info,
+ const TQString& key, const TQString& translatedKey) const;
+
+ /**
+ * Sets attributes of the GroupInfo object returned by addGroupInfo().
+ *
+ * @param gi the object returned by addGroupInfo()
+ * @param attr the attributes for this group; these are values of type
+ * KFileMimeTypeInfo::Attributes, or'ed together
+ **/
+ void setAttributes(KFileMimeTypeInfo::GroupInfo* gi, uint attr) const;
+
+ void addVariableInfo(KFileMimeTypeInfo::GroupInfo* gi, TQVariant::Type type,
+ uint attr) const;
+
+ /**
+ * Adds a meta information item to a GroupInfo object as returned by
+ * addGroupInfo().
+ *
+ * @param gi the GroupInfo object to add a new item to
+ * @param key a unique string to identify this item. For simplicity it is
+ * recommended to use the same string as for the translatedKey
+ * parameter
+ * @param translatedKey the translated version of the key string for
+ * displaying in user interfaces. Use i18n() to translate the string
+ * @param type the type of the meta information item, e.g. TQVariant::Int
+ * or TQVariant::String.
+ * @return an ItemInfo object. Pass this object to setAttributes()
+ **/
+ KFileMimeTypeInfo::ItemInfo* addItemInfo(KFileMimeTypeInfo::GroupInfo* gi,
+ const TQString& key,
+ const TQString& translatedKey,
+ TQVariant::Type type);
+
+ /**
+ * Sets some attributes for a meta information item. The attributes
+ * describe if the item is mutable, how it should be computed for a list of
+ * files, and how it should be displayed
+ *
+ * @param item the ItemInfo object as returned by addItemInfo()
+ * @param attr the attributes for this item; these are values of type
+ * KFileMimeTypeInfo::Attributes, or'ed together
+ **/
+ void setAttributes(KFileMimeTypeInfo::ItemInfo* item, uint attr);
+
+ /**
+ * Defines the meaning of the meta information item. Some applications make
+ * use of this information, so be sure to check KFileMimeTypeInfo::Hint to
+ * see if an item's meaning is in the list.
+ *
+ * @param item the ItemInfo object as returned by addItemInfo()
+ * @param hint the item's meaning. See KFileMimeTypeInfo::Hint for a list
+ * of available meanings
+ **/
+ void setHint(KFileMimeTypeInfo::ItemInfo* item, uint hint);
+
+ /**
+ * Sets the unit used in the meta information item. This unit is used to
+ * format the value and to make large values human-readable. For example,
+ * if the item's unit is KFileMimeTypeInfo::Seconds and the value is 276,
+ * it will be displayed as 4:36.
+ *
+ * @param item the ItemInfo object as returned by addItemInfo()
+ * @param unit the item's unit. See KFileMimeTypeInfo::Unit for a list of
+ * available units
+ **/
+ void setUnit(KFileMimeTypeInfo::ItemInfo* item, uint unit);
+
+ /**
+ * Sets a prefix string which is displayed before the item's value. Use
+ * this string if no predefined unit fits the item's unit. Be sure to
+ * translate the string with i18n()
+ *
+ * @param item the ItemInfo object as returned by addItemInfo()
+ * @param prefix the prefix string to display
+ **/
+ void setPrefix(KFileMimeTypeInfo::ItemInfo* item, const TQString& prefix);
+
+ /**
+ * Sets a suffix string which is displayed before the item's value. Use
+ * this string if no predefined unit fits the item's unit. Be sure to
+ * translate the string with i18n()
+ *
+ * @param item the ItemInfo object as returned by addItemInfo()
+ * @param suffix the suffix string to display
+ **/
+ void setSuffix(KFileMimeTypeInfo::ItemInfo* item, const TQString& suffix);
+
+ /**
+ * Call this method from within readInfo() to indicate that you wish to
+ * fill meta information items of the group identified by @p key with
+ * values.
+ *
+ * @param info the KFileMetaInfo object. Use the parameter of the
+ * readInfo() method
+ * @param key the key string to identify the group. Use the string that you
+ * defined in your class' constructor
+ * @return a KFileMetaInfoGroup object, to be used in appendItem()
+ **/
+ KFileMetaInfoGroup appendGroup(KFileMetaInfo& info, const TQString& key);
+
+ /**
+ * Call this method from within readInfo() to fill the meta information item
+ * identified by @p key with a @p value
+ *
+ * @param group the KFileMetaInfoGroup object, as returned by appendGroup()
+ * @param key the key string to identify the item.
+ * @param value the value of the meta information item
+ **/
+ void appendItem(KFileMetaInfoGroup& group, const TQString& key, TQVariant value);
+
+ TQStringList m_preferredKeys;
+ TQStringList m_preferredGroups;
+
+protected:
+ /**
+ * Helper method to allow binary compatible extensions when needing
+ * "new virtual methods"
+ *
+ * @param id the identifier of the new "virtual" method
+ * @param data any parameter data the new "virtual" method needs
+ */
+ virtual void virtual_hook( int id, void* data );
+private:
+ class KFilePluginPrivate;
+ KFilePluginPrivate *d;
+};
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+/**
+ * @internal
+ * Synchronous access to metadata of a local file. Usually, you don't want
+ * to use this class for getting metainfo from a file. Use KFileMetaInfo
+ * directly. However, if you want to find out if a specific mimetype is
+ * supported and which groups and items are provided for it, you can ask
+ * the KFileMetainfoProvider for it.
+ **/
+class TDEIO_EXPORT KFileMetaInfoProvider: private QObject
+{
+ friend class KFilePlugin;
+
+ Q_OBJECT
+public:
+ virtual ~KFileMetaInfoProvider();
+
+ static KFileMetaInfoProvider * self();
+
+ /**
+ * @return a pointer to the plugin that belongs to the specified mimetype,
+ * which means also load the plugin if it's not in memory
+ */
+ KFilePlugin * plugin( const TQString& mimeType ); // KDE4: merge with method below
+
+ /**
+ * @return a pointer to the plugin that belongs to the specified mimetype,
+ * for the given protocol.
+ * This loads the plugin if it's not in memory yet.
+ */
+ KFilePlugin * plugin( const TQString& mimeType, const TQString& protocol );
+
+ const KFileMimeTypeInfo * mimeTypeInfo( const TQString& mimeType ); // KDE4: merge with below
+ const KFileMimeTypeInfo * mimeTypeInfo( const TQString& mimeType, const TQString& protocol );
+
+ TQStringList preferredKeys( const TQString& mimeType ) const;
+ TQStringList preferredGroups( const TQString& mimeType ) const;
+
+ /// @since 3.1
+ TQStringList supportedMimeTypes() const;
+
+protected: // ## should be private, right?
+ KFileMetaInfoProvider();
+
+private:
+
+ // Data structure:
+ // Mimetype or Protocol -> { Plugin and MimeTypeInfo }
+ // The {} struct is CachedPluginInfo
+ struct CachedPluginInfo
+ {
+ CachedPluginInfo() : plugin( 0 ), mimeTypeInfo( 0 ), ownsPlugin( false ) {}
+ CachedPluginInfo( KFilePlugin* p, KFileMimeTypeInfo* i, bool owns )
+ : plugin( p ), mimeTypeInfo( i ), ownsPlugin( owns ) {}
+ // auto-delete behavior
+ ~CachedPluginInfo() {
+ if ( ownsPlugin ) delete plugin;
+ delete mimeTypeInfo;
+ }
+
+ // If plugin and mimeTypeInfo are 0, means that no plugin is available.
+ KFilePlugin* plugin;
+ KFileMimeTypeInfo* mimeTypeInfo;
+ // The problem here is that plugin can be shared in multiple instances,
+ // so the memory management isn't easy. KDE4 solution: use KSharedPtr?
+ // For now we flag one copy of the KFilePlugin pointer as being "owned".
+ bool ownsPlugin;
+ };
+
+ // The key is either a mimetype or a protocol. Those things don't look the same
+ // so there's no need for two QDicts.
+ TQDict<CachedPluginInfo> m_plugins;
+
+ // This data is aggregated during the creation of a plugin,
+ // before being moved to the appropriate CachedPluginInfo(s)
+ // At any other time than during the loading of a plugin, this dict is EMPTY.
+ // Same key as in m_plugins: mimetype or protocol
+ TQDict<KFileMimeTypeInfo> m_pendingMimetypeInfos;
+
+private:
+ static KFileMetaInfoProvider * s_self;
+
+ KFilePlugin* loadPlugin( const TQString& mimeType, const TQString& protocol );
+ KFilePlugin* loadAndRegisterPlugin( const TQString& mimeType, const TQString& protocol );
+ KFileMimeTypeInfo * addMimeTypeInfo( const TQString& mimeType );
+
+ class KFileMetaInfoProviderPrivate;
+ KFileMetaInfoProviderPrivate *d;
+
+};
+
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoItem& );
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoItem& );
+
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoGroup& );
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoGroup& );
+
+TDEIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfo& );
+TDEIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfo& );
+
+
+#endif // KILEMETAINFO_H
diff --git a/tdeio/tdeio/tdefileshare.cpp b/tdeio/tdeio/tdefileshare.cpp
new file mode 100644
index 000000000..fe6e0bd15
--- /dev/null
+++ b/tdeio/tdeio/tdefileshare.cpp
@@ -0,0 +1,346 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ 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 "tdefileshare.h"
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqregexp.h>
+#include <kprocess.h>
+#include <kprocio.h>
+#include <klocale.h>
+#include <kstaticdeleter.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <kdirnotify_stub.h>
+#include <ksimpleconfig.h>
+#include <kuser.h>
+
+KFileShare::Authorization KFileShare::s_authorization = NotInitialized;
+//TQStringList* KFileShare::s_shareList = 0L;
+//static KStaticDeleter<TQStringList> sdShareList;
+TQMap<TQString,TQString>* KFileShare::s_shareMap = 0L;
+static KStaticDeleter<TQMap<TQString,TQString> > sdShareMap;
+
+KFileShare::ShareMode KFileShare::s_shareMode;
+bool KFileShare::s_sambaEnabled;
+bool KFileShare::s_nfsEnabled;
+bool KFileShare::s_restricted;
+TQString KFileShare::s_fileShareGroup;
+bool KFileShare::s_sharingEnabled;
+
+
+#define FILESHARECONF "/etc/security/fileshare.conf"
+
+KFileSharePrivate::KFileSharePrivate()
+{
+ KDirWatch::self()->addFile(FILESHARECONF);
+ connect(KDirWatch::self(), TQT_SIGNAL(dirty (const TQString&)),this,
+ TQT_SLOT(slotFileChange(const TQString &)));
+ connect(KDirWatch::self(), TQT_SIGNAL(created(const TQString&)),this,
+ TQT_SLOT(slotFileChange(const TQString &)));
+ connect(KDirWatch::self(), TQT_SIGNAL(deleted(const TQString&)),this,
+ TQT_SLOT(slotFileChange(const TQString &)));
+}
+
+KFileSharePrivate::~KFileSharePrivate()
+{
+ KDirWatch::self()->removeFile(FILESHARECONF);
+}
+
+KFileSharePrivate *KFileSharePrivate::_self=0L;
+
+static KStaticDeleter<KFileSharePrivate> kstFileShare;
+
+KFileSharePrivate* KFileSharePrivate::self()
+{
+ if (!_self)
+ _self = kstFileShare.setObject(_self, new KFileSharePrivate());
+ return _self;
+}
+
+void KFileSharePrivate::slotFileChange(const TQString &file)
+{
+ if(file==FILESHARECONF) {
+ KFileShare::readConfig();
+ KFileShare::readShareList();
+ }
+}
+
+void KFileShare::readConfig() // static
+{
+ // Create KFileSharePrivate instance
+ KFileSharePrivate::self();
+ KSimpleConfig config(TQString::fromLatin1(FILESHARECONF),true);
+
+ s_sharingEnabled = config.readEntry("FILESHARING", "yes") == "yes";
+ s_restricted = config.readEntry("RESTRICT", "yes") == "yes";
+ s_fileShareGroup = config.readEntry("FILESHAREGROUP", "fileshare");
+
+
+ if (!s_sharingEnabled)
+ s_authorization = UserNotAllowed;
+ else
+ if (!s_restricted )
+ s_authorization = Authorized;
+ else {
+ // check if current user is in fileshare group
+ KUserGroup shareGroup(s_fileShareGroup);
+ if (shareGroup.users().findIndex(KUser()) > -1 )
+ s_authorization = Authorized;
+ else
+ s_authorization = UserNotAllowed;
+ }
+
+ if (config.readEntry("SHARINGMODE", "simple") == "simple")
+ s_shareMode = Simple;
+ else
+ s_shareMode = Advanced;
+
+
+ s_sambaEnabled = config.readEntry("SAMBA", "yes") == "yes";
+ s_nfsEnabled = config.readEntry("NFS", "yes") == "yes";
+}
+
+KFileShare::ShareMode KFileShare::shareMode() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_shareMode;
+}
+
+bool KFileShare::sharingEnabled() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_sharingEnabled;
+}
+
+bool KFileShare::isRestricted() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_restricted;
+}
+
+TQString KFileShare::fileShareGroup() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_fileShareGroup;
+}
+
+
+bool KFileShare::sambaEnabled() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_sambaEnabled;
+}
+
+bool KFileShare::nfsEnabled() {
+ if ( s_authorization == NotInitialized )
+ readConfig();
+
+ return s_nfsEnabled;
+}
+
+
+void KFileShare::readShareList()
+{
+ KFileSharePrivate::self();
+ if ( !s_shareMap )
+ sdShareMap.setObject( s_shareMap, new TQMap<TQString,TQString> );
+ else
+ s_shareMap->clear();
+
+ // /usr/sbin on Mandrake, $PATH allows flexibility for other distributions
+ TQString exe = findExe( "filesharelist" );
+ if (exe.isEmpty()) {
+ s_authorization = ErrorNotFound;
+ return;
+ }
+ KProcIO proc;
+ proc << exe;
+ if ( !proc.start( TDEProcess::Block ) ) {
+ kdError() << "Can't run " << exe << endl;
+ s_authorization = ErrorNotFound;
+ return;
+ }
+
+ // Reading code shamelessly stolen from khostname.cpp ;)
+ TQString line;
+ TQString options;
+ TQString path;
+ int length;
+ TQRegExp rx_line("([^\\s]+)\\s+(.*)");
+ do {
+ length = proc.readln(line, true);
+ if ( length > 0 )
+ {
+ if ( line[length-1] != '/' )
+ line += '/';
+ if( rx_line.search( line ) != -1 ) {
+ options = rx_line.cap(1);
+ path = rx_line.cap(2);
+ (*s_shareMap)[path] = options;
+ }
+ kdDebug(7000) << "Shared dir:" << line << endl;
+ }
+ } while (length > -1);
+}
+
+
+int KFileShare::isDirectoryShared( const TQString& _path )
+{
+ int ret(0);
+
+ if ( ! s_shareMap )
+ readShareList();
+
+ TQString path( _path );
+ if ( path[path.length()-1] != '/' )
+ path += '/';
+ //return s_shareList && s_shareList->contains( path );
+ if( (*s_shareMap).contains(path) && !((*s_shareMap)[path].isEmpty()) ) {
+ ret+=1;
+ if( (*s_shareMap)[path].find("readwrite") != -1 )
+ ret+=2;
+ }
+
+ return ret;
+}
+
+KFileShare::Authorization KFileShare::authorization()
+{
+ // The app should do this on startup, but if it doesn't, let's do here.
+ if ( s_authorization == NotInitialized )
+ readConfig();
+ return s_authorization;
+}
+
+TQString KFileShare::findExe( const char* exeName )
+{
+ // /usr/sbin on Mandrake, $PATH allows flexibility for other distributions
+ TQString path = TQString::fromLocal8Bit(getenv("PATH")) + TQString::fromLatin1(":/usr/sbin");
+ TQString exe = KStandardDirs::findExe( exeName, path );
+ if (exe.isEmpty())
+ kdError() << exeName << " not found in " << path << endl;
+ return exe;
+}
+
+bool KFileShare::setShared( const TQString& path, bool shared )
+{
+ return SuSEsetShared( path, shared, false );
+}
+
+bool KFileShare::SuSEsetShared( const TQString& path, bool shared, bool rw )
+{
+ if (! KFileShare::sharingEnabled() ||
+ KFileShare::shareMode() == Advanced)
+ return false;
+
+ TQString exe = KFileShare::findExe( "fileshareset" );
+ if (exe.isEmpty())
+ return false;
+
+ // we want to share, so we kick it first - just to be sure
+ TDEProcess proc;
+ proc << exe;
+ proc << "--remove";
+ proc << path;
+ proc.start( TDEProcess::Block );
+ proc.clearArguments();
+
+ proc << exe;
+ if( rw )
+ proc << "--rw";
+ if ( shared )
+ proc << "--add";
+ else
+ proc << "--remove";
+ proc << path;
+ proc.start( TDEProcess::Block ); // should be ok, the perl script terminates fast
+ bool ok = proc.normalExit() && (proc.exitStatus() == 0);
+ kdDebug(7000) << "KFileSharePropsPlugin::setShared normalExit="
+ << proc.normalExit() << endl;
+ kdDebug(7000) << "KFileSharePropsPlugin::setShared exitStatus="
+ << proc.exitStatus() << endl;
+ if ( proc.normalExit() ) {
+ switch( proc.exitStatus() ) {
+ case 1:
+ // User is not authorized
+ break;
+ case 3:
+ // Called script with --add, but path was already shared before.
+ // Result is nevertheless what the client wanted, so
+ // this is alright.
+ ok = true;
+ break;
+ case 4:
+ // Invalid mount point
+ break;
+ case 5:
+ // Called script with --remove, but path was not shared before.
+ // Result is nevertheless what the client wanted, so
+ // this is alright.
+ ok = true;
+ break;
+ case 6:
+ // There is no export method
+ break;
+ case 7:
+ // file sharing is disabled
+ break;
+ case 8:
+ // advanced sharing is enabled
+ break;
+ case 255:
+ // Abitrary error
+ break;
+ }
+ }
+
+ return ok;
+}
+
+bool KFileShare::sambaActive()
+{
+ // rcsmb is not executable by users, try ourselves
+ int status = system( "/sbin/checkproc -p /var/run/samba/smbd.pid /usr/sbin/smbd" );
+ return status != -1 && WIFEXITED( status ) && WEXITSTATUS( status ) == 0;
+}
+
+bool KFileShare::nfsActive()
+{
+ // rcnfsserver is not executable by users, try ourselves
+ int status = system( "/sbin/checkproc /usr/sbin/rpc.mountd" );
+ if( status != -1 && WIFEXITED( status ) && WEXITSTATUS( status ) == 0 )
+ {
+ status = system( "/sbin/checkproc -n nfsd" );
+ if( status != -1 && WIFEXITED( status ) && WEXITSTATUS( status ) == 0 )
+ return true;
+ }
+ return false;
+}
+
+#include "tdefileshare.moc"
diff --git a/tdeio/tdeio/tdefileshare.h b/tdeio/tdeio/tdefileshare.h
new file mode 100644
index 000000000..e18749972
--- /dev/null
+++ b/tdeio/tdeio/tdefileshare.h
@@ -0,0 +1,165 @@
+/* This file is part of the KDE project
+ Copyright (c) 2001 David Faure <david@mandrakesoft.com>
+ Copyright (c) 2001 Laurent Montel <lmontel@mandrakesoft.com>
+
+ 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 tdefileshare_h
+#define tdefileshare_h
+#include <tqobject.h>
+
+#include <tdelibs_export.h>
+
+class KDirWatch;
+
+/**
+ * @internal
+ * Do not use, ever.
+ */
+class KFileSharePrivate : public TQObject
+{
+ Q_OBJECT
+
+public:
+ KFileSharePrivate();
+ ~KFileSharePrivate();
+ KDirWatch* m_watchFile;
+ static KFileSharePrivate *self();
+ static KFileSharePrivate *_self;
+protected slots: // this is why this class needs to be in the .h
+ void slotFileChange(const TQString &);
+};
+
+/**
+ * Common functionality for the file sharing
+ * (communication with the backend)
+ * @since 3.1
+ */
+class TDEIO_EXPORT KFileShare
+{
+
+
+public:
+ /**
+ * Reads the file share configuration file
+ */
+ static void readConfig();
+
+ /**
+ * Reads the list of shared folders
+ */
+ static void readShareList();
+
+
+ /**
+ * Call this to know if a directory is currently shared
+ */
+ static int isDirectoryShared( const TQString& path );
+
+ enum Authorization { NotInitialized, ErrorNotFound, Authorized, UserNotAllowed };
+ /**
+ * Call this to know if the current user is authorized to share directories
+ */
+ static Authorization authorization();
+
+ static TQString findExe( const char* exeName );
+
+ /**
+ * Uses a suid perl script to share the given path
+ * with NFS and Samba
+ * @param path the path to share
+ * @param shared whether the path should be shared or not
+ * @returns whether the perl script was successful
+ */
+ static bool setShared( const TQString& path, bool shared );
+
+ /*
+ * SuSE only enhancement for now
+ */
+ static bool SuSEsetShared( const TQString& path, bool shared, bool ro );
+
+ /**
+ * The used share mode.
+ * Simple means that the simple sharing dialog is used and
+ * users can share only folders from there HOME folder.
+ * Advanced means that the advanced sharing dialog is used and
+ * users can share any folder.
+ */
+ enum ShareMode { Simple, Advanced };
+
+ /**
+ * Returns whether sharing is enabled
+ * If this is false, file sharing is disabled and
+ * nobody can share files.
+ */
+ static bool sharingEnabled();
+
+ /**
+ * Returns whether file sharing is restricted.
+ * If it is not restricted every user can shar files.
+ * If it is restricted only users in the configured
+ * file share group can share files.
+ */
+ static bool isRestricted();
+
+ /**
+ * Returns the group that is used for file sharing.
+ * That is, all users in that group are allowed to
+ * share files if file sharing is restricted.
+ */
+ static TQString fileShareGroup();
+
+ /**
+ * Returns the configured share mode
+ */
+ static ShareMode shareMode();
+
+ /**
+ * Returns whether Samba is enabled
+ */
+ static bool sambaEnabled();
+
+ /**
+ * Returns whether NFS is enabled
+ */
+ static bool nfsEnabled();
+
+ /**
+ * Returns whether Samba is active (service is running)
+ * @internal
+ */
+ static bool sambaActive();
+
+ /**
+ * Returns whether NFS is active (service is running)
+ * @internal
+ */
+ static bool nfsActive();
+
+private:
+ static Authorization s_authorization;
+// static TQStringList* s_shareList;
+ static TQMap<TQString,TQString>* s_shareMap;
+ static ShareMode s_shareMode;
+ static bool s_sambaEnabled;
+ static bool s_nfsEnabled;
+ static bool s_restricted;
+ static TQString s_fileShareGroup;
+ static bool s_sharingEnabled;
+
+};
+
+#endif
diff --git a/tdeio/tdeio/tdelficon.cpp b/tdeio/tdeio/tdelficon.cpp
new file mode 100644
index 000000000..49ceffd24
--- /dev/null
+++ b/tdeio/tdeio/tdelficon.cpp
@@ -0,0 +1,89 @@
+#include "tdelficon.h"
+
+#include <cstring>
+
+/*
+ * Obtain an existing icon resource list
+ */
+int get_iconlist(libr_file *file_handle, iconlist *icons)
+{
+ if(icons == NULL)
+ {
+ /* Need to be able to return SOMETHING */
+ return false;
+ }
+ /* Obtain the icon resource list */
+ icons->buffer = libr_malloc(file_handle, ICON_SECTION, &(icons->size));
+ if(icons->buffer == NULL)
+ return false;
+ return true;
+}
+
+/*
+ * Get the next entry in an icon resource list
+ */
+iconentry *get_nexticon(iconlist *icons, iconentry *last_entry)
+{
+ size_t i;
+
+ /* The icon list is needed both for the data buffer and for a call-specific iconentry instance */
+ if(icons == NULL)
+ return NULL;
+ /* If this is the first call (last_entry == NULL) then return the first entry */
+ if(last_entry == NULL)
+ icons->entry.offset = sizeof(uint32_t)+sizeof(UUID);
+ else
+ icons->entry.offset += icons->entry.entry_size;
+ /* Check to see if we've run out of entries */
+ if(icons->entry.offset >= icons->size)
+ return NULL;
+ i = icons->entry.offset;
+ memcpy(&(icons->entry.entry_size), &(icons->buffer[i]), sizeof(uint32_t));
+ i += sizeof(uint32_t);
+ icons->entry.type = (libr_icontype_t)icons->buffer[i];
+ i += sizeof(unsigned char);
+ switch(icons->entry.type)
+ {
+ case LIBR_SVG:
+ icons->entry.icon_size = 0;
+ icons->entry.name = &(icons->buffer[i]);
+ break;
+ case LIBR_PNG:
+ memcpy(&(icons->entry.icon_size), &(icons->buffer[i]), sizeof(uint32_t));
+ i += sizeof(uint32_t);
+ icons->entry.name = &(icons->buffer[i]);
+ break;
+ default:
+ /* Invalid entry type */
+ return NULL;
+ }
+ return &(icons->entry);
+}
+
+TQString elf_get_resource(libr_file *handle, char *section_name)
+{
+ size_t buffer_size = 0;
+ char *buffer = NULL;
+ TQString result;
+
+ /* Get the resource from the ELF binary */
+ if(!libr_size(handle, section_name, &buffer_size))
+ {
+// kdWarning() << "failed to obtain ELF resource size: " << libr_errmsg() << endl;
+ return result;
+ }
+ /* Get the resource from the ELF file */
+ buffer = (char *) malloc(buffer_size+1);
+ buffer[buffer_size] = 0;
+ if(!libr_read(handle, section_name, buffer))
+ {
+// kdWarning() << "failed to obtain ELF resource: " << libr_errmsg() << endl;
+ goto fail;
+ }
+ result = buffer;
+
+fail:
+ free(buffer);
+
+ return result;
+}
diff --git a/tdeio/tdeio/tdelficon.h b/tdeio/tdeio/tdelficon.h
new file mode 100644
index 000000000..7a962bdaa
--- /dev/null
+++ b/tdeio/tdeio/tdelficon.h
@@ -0,0 +1,54 @@
+#include <alloca.h>
+#include <stdint.h>
+#include <cstdlib>
+
+#include <tqdict.h>
+#include <tqvalidator.h>
+#include <tqcstring.h>
+#include <tqfile.h>
+#include <tqdatetime.h>
+
+extern "C" {
+ #include <libr-icons.h>
+
+ // BEGIN HACK
+ // libr does not export these structures and defines,
+ // but we need access to them to make the UI behave sanely
+ // Keep them in sync with libr and all should be OK
+
+ // Valid for libr version 0.6.0
+ // See libr detection code in ConfigureChecks.cmake
+
+ typedef uint32_t ID8;
+ typedef uint16_t ID4;
+ typedef struct {uint64_t p:48;} __attribute__((__packed__)) ID12;
+
+ typedef struct {
+ ID8 g1;
+ ID4 g2;
+ ID4 g3;
+ ID4 g4;
+ ID12 g5;
+ } __attribute__((__packed__)) UUID;
+
+ typedef struct {
+ char *name;
+ size_t offset;
+ size_t entry_size;
+ libr_icontype_t type;
+ unsigned int icon_size;
+ } iconentry;
+
+ typedef struct{
+ size_t size;
+ char *buffer;
+ iconentry entry;
+ } iconlist;
+
+ #define ICON_SECTION ".icon"
+ // END HACK
+}
+
+int get_iconlist(libr_file *file_handle, iconlist *icons);
+iconentry *get_nexticon(iconlist *icons, iconentry *last_entry);
+TQString elf_get_resource(libr_file *handle, char *section_name); \ No newline at end of file
diff --git a/tdeio/tdeio/thumbcreator.h b/tdeio/tdeio/thumbcreator.h
new file mode 100644
index 000000000..756dd0cf9
--- /dev/null
+++ b/tdeio/tdeio/thumbcreator.h
@@ -0,0 +1,124 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License 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 _THUMBCREATOR_H_
+#define _THUMBCREATOR_H_
+
+#include <tqstring.h>
+
+class TQString;
+class TQImage;
+/**
+ * This is the baseclass for "thumbnail-plugins" in KDE. Using the class
+ * TDEIO::PreviewJob allows you to generate small images (thumbnails)
+ * for any kind of file, where a "ThumbCreator" is available. Have a look
+ * at tdebase/tdeioslave/thumbnail/ for existing ThumbCreators.
+ *
+ * What you need to do to create and register a ThumbCreator:
+ * @li Inherit from this class and reimplement the create() method to
+ * generate a thumbnail for the given file-path.
+ * @li Provide a factory method in your implementation file to instantiate
+ * your plugin, e.g.:
+ * \code
+ * extern "C"
+ * {
+ * ThumbCreator *new_creator()
+ * {
+ * return new YourThumbCreator();
+ * }
+ * };
+ * \endcode
+ *
+ * Compile your ThumbCreator as a module. The contents of Makefile.am
+ * need to look like this:
+ * \code
+ * INCLUDES = $(all_includes)
+ * kde_module_LTLIBRARIES = yourthumbcreator.la
+ * yourthumbcreator_la_SOURCES = yourthumbcreator.cpp
+ * yourthumbcreator_la_LIBADD = $(LIB_KIO)
+ * yourthumbcreator_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+ * kde_services_DATA = yourthumbcreator.desktop
+ * \endcode
+ *
+ * @li Create a file yourthumbcreator.desktop with the following contents:
+ * \code
+ * [Desktop Entry]
+ * Encoding=UTF-8
+ * Type=Service
+ * Name=Name of the type of files your ThumbCreator supports
+ * ServiceTypes=ThumbCreator
+ * MimeTypes=application/x-somemimetype
+ * CacheThumbnail=true
+ * X-TDE-Library=yourthumbcreator
+ * \endcode
+ *
+ * You can supply a comma-separated list of mimetypes to the MimeTypes entry,
+ * naming all mimetypes your ThumbCreator supports. You can also use simple
+ * wildcards, like (where you see [slash], put a /)
+ * \code
+ * text[slash]* or image[slash]*.
+ * \endcode
+ *
+ * If your plugin is rather inexpensive (e.g. like the text preview ThumbCreator),
+ * you can set CacheThumbnail=false to prevent your thumbnails from being cached
+ * on disk.
+ *
+ * @short Baseclass for thumbnail-generating plugins.
+ */
+class ThumbCreator
+{
+public:
+ /**
+ * The flags of this plugin.
+ * @see flags()
+ */
+ enum Flags { None = 0, DrawFrame = 1, BlendIcon = 2 };
+ virtual ~ThumbCreator() {}
+
+ /**
+ * Creates a thumbnail
+ * Note that the width and height parameters should not be used
+ * for scaling. Only plugins that create an image "from scratch",
+ * like the TextCreator should directly use the specified size.
+ * If the resulting preview is larger than width x height, it will be
+ * scaled down.
+ *
+ * @param path the (always local) file path to create a preview for
+ * @param width maximum width for the preview
+ * @param height maximum height for the preview
+ * @param img this image will contain the preview on success
+ *
+ * @return true if preview generation succeeded
+ */
+ virtual bool create(const TQString &path, int width, int height, TQImage &img) = 0;
+
+ /**
+ * The flags of this plugin:
+ * @li None nothing special
+ * @li DrawFrame a frame should be painted around the preview
+ * @li BlendIcon the mimetype icon should be blended over the preview
+ *
+ * @return flags for this plugin
+ */
+ virtual Flags flags() const { return None; }
+};
+
+typedef ThumbCreator *(*newCreator)();
+
+#endif
diff --git a/tdeio/tdeio/yacc.c b/tdeio/tdeio/yacc.c
new file mode 100644
index 000000000..a6fa63428
--- /dev/null
+++ b/tdeio/tdeio/yacc.c
@@ -0,0 +1,1522 @@
+/* A Bison parser, made by GNU Bison 2.0. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with 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.
+*/
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse kiotraderparse
+#define yylex kiotraderlex
+#define yyerror kiotradererror
+#define yylval kiotraderlval
+#define yychar kiotraderchar
+#define yydebug kiotraderdebug
+#define yynerrs kiotradernerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ NOT = 258,
+ EQ = 259,
+ NEQ = 260,
+ LEQ = 261,
+ GEQ = 262,
+ LE = 263,
+ GR = 264,
+ OR = 265,
+ AND = 266,
+ TOKEN_IN = 267,
+ EXIST = 268,
+ MAX = 269,
+ MIN = 270,
+ VAL_BOOL = 271,
+ VAL_STRING = 272,
+ VAL_ID = 273,
+ VAL_NUM = 274,
+ VAL_FLOAT = 275
+ };
+#endif
+#define NOT 258
+#define EQ 259
+#define NEQ 260
+#define LEQ 261
+#define GEQ 262
+#define LE 263
+#define GR 264
+#define OR 265
+#define AND 266
+#define TOKEN_IN 267
+#define EXIST 268
+#define MAX 269
+#define MIN 270
+#define VAL_BOOL 271
+#define VAL_STRING 272
+#define VAL_ID 273
+#define VAL_NUM 274
+#define VAL_FLOAT 275
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "yacc.y"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "ktraderparse.h"
+
+void yyerror(const char *s);
+int yylex();
+void KTraderParse_initFlex( const char *s );
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 13 "yacc.y"
+typedef union YYSTYPE {
+ char valb;
+ int vali;
+ double vald;
+ char *name;
+ void *ptr;
+} YYSTYPE;
+/* Line 190 of yacc.c. */
+#line 143 "yacc.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 213 of yacc.c. */
+#line 155 "yacc.tab.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+# define YYFREE free
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# else
+# define YYSTACK_ALLOC alloca
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 27
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 55
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 28
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 12
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 36
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 57
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 275
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 26, 27, 24, 22, 2, 23, 2, 25, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 21, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 4, 6, 8, 12, 14, 18, 20,
+ 24, 28, 32, 36, 40, 44, 46, 50, 52, 56,
+ 58, 62, 66, 68, 72, 76, 78, 81, 83, 87,
+ 90, 92, 94, 96, 98, 100, 103
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 29, 0, -1, -1, 30, -1, 31, -1, 32, 10,
+ 31, -1, 32, -1, 33, 11, 32, -1, 33, -1,
+ 34, 4, 34, -1, 34, 5, 34, -1, 34, 7,
+ 34, -1, 34, 6, 34, -1, 34, 8, 34, -1,
+ 34, 9, 34, -1, 34, -1, 35, 12, 18, -1,
+ 35, -1, 36, 21, 36, -1, 36, -1, 36, 22,
+ 37, -1, 36, 23, 37, -1, 37, -1, 37, 24,
+ 38, -1, 37, 25, 38, -1, 38, -1, 3, 39,
+ -1, 39, -1, 26, 31, 27, -1, 13, 18, -1,
+ 18, -1, 19, -1, 20, -1, 17, -1, 16, -1,
+ 14, 18, -1, 15, 18, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned char yyrline[] =
+{
+ 0, 56, 56, 57, 60, 63, 64, 67, 68, 71,
+ 72, 73, 74, 75, 76, 77, 80, 81, 84, 85,
+ 88, 89, 90, 93, 94, 95, 98, 99, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "NOT", "EQ", "NEQ", "LEQ", "GEQ", "LE",
+ "GR", "OR", "AND", "TOKEN_IN", "EXIST", "MAX", "MIN", "VAL_BOOL",
+ "VAL_STRING", "VAL_ID", "VAL_NUM", "VAL_FLOAT", "'~'", "'+'", "'-'",
+ "'*'", "'/'", "'('", "')'", "$accept", "constraint", "bool", "bool_or",
+ "bool_and", "bool_compare", "expr_in", "expr_twiddle", "expr", "term",
+ "factor_non", "factor", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 126, 43, 45, 42, 47, 40, 41
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 28, 29, 29, 30, 31, 31, 32, 32, 33,
+ 33, 33, 33, 33, 33, 33, 34, 34, 35, 35,
+ 36, 36, 36, 37, 37, 37, 38, 38, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 1, 1, 3, 1, 3, 1, 3,
+ 3, 3, 3, 3, 3, 1, 3, 1, 3, 1,
+ 3, 3, 1, 3, 3, 1, 2, 1, 3, 2,
+ 1, 1, 1, 1, 1, 2, 2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 0, 0, 0, 34, 33, 30, 31, 32,
+ 0, 0, 3, 4, 6, 8, 15, 17, 19, 22,
+ 25, 27, 26, 29, 35, 36, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 28, 5, 7, 9, 10, 12, 11, 13,
+ 14, 16, 18, 20, 21, 23, 24
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -17
+static const yysigned_char yypact[] =
+{
+ -3, 11, 0, 18, 28, -17, -17, -17, -17, -17,
+ -3, 47, -17, -17, 38, 39, -2, 37, -1, -16,
+ -17, -17, -17, -17, -17, -17, 24, -17, -3, -3,
+ -3, -3, -3, -3, -3, -3, 34, -3, -3, -3,
+ -3, -3, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, 10, -16, -16, -17, -17
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -17, -17, -17, -9, 25, -17, 8, -17, 16, -4,
+ 4, 54
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 1, 26, 30, 31, 32, 33, 34, 35, 40, 41,
+ 2, 3, 4, 5, 6, 7, 8, 9, 23, 43,
+ 37, 38, 39, 10, 2, 3, 4, 5, 6, 7,
+ 8, 9, 38, 39, 53, 54, 24, 10, 45, 46,
+ 47, 48, 49, 50, 55, 56, 25, 27, 28, 36,
+ 29, 42, 51, 52, 44, 22
+};
+
+static const unsigned char yycheck[] =
+{
+ 3, 10, 4, 5, 6, 7, 8, 9, 24, 25,
+ 13, 14, 15, 16, 17, 18, 19, 20, 18, 28,
+ 21, 22, 23, 26, 13, 14, 15, 16, 17, 18,
+ 19, 20, 22, 23, 38, 39, 18, 26, 30, 31,
+ 32, 33, 34, 35, 40, 41, 18, 0, 10, 12,
+ 11, 27, 18, 37, 29, 1
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 3, 13, 14, 15, 16, 17, 18, 19, 20,
+ 26, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 39, 18, 18, 18, 31, 0, 10, 11,
+ 4, 5, 6, 7, 8, 9, 12, 21, 22, 23,
+ 24, 25, 27, 31, 32, 34, 34, 34, 34, 34,
+ 34, 18, 36, 37, 37, 38, 38
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ register short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+
+ yyvsp[0] = yylval;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a look-ahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 56 "yacc.y"
+ { KTraderParse_setParseTree( 0L ); ;}
+ break;
+
+ case 3:
+#line 57 "yacc.y"
+ { KTraderParse_setParseTree( (yyvsp[0].ptr) ); ;}
+ break;
+
+ case 4:
+#line 60 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 5:
+#line 63 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newOR( (yyvsp[-2].ptr), (yyvsp[0].ptr) ); ;}
+ break;
+
+ case 6:
+#line 64 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 7:
+#line 67 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newAND( (yyvsp[-2].ptr), (yyvsp[0].ptr) ); ;}
+ break;
+
+ case 8:
+#line 68 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 9:
+#line 71 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 1 ); ;}
+ break;
+
+ case 10:
+#line 72 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 2 ); ;}
+ break;
+
+ case 11:
+#line 73 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 3 ); ;}
+ break;
+
+ case 12:
+#line 74 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 4 ); ;}
+ break;
+
+ case 13:
+#line 75 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 5 ); ;}
+ break;
+
+ case 14:
+#line 76 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCMP( (yyvsp[-2].ptr), (yyvsp[0].ptr), 6 ); ;}
+ break;
+
+ case 15:
+#line 77 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 16:
+#line 80 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newIN( (yyvsp[-2].ptr), KTraderParse_newID( (yyvsp[0].name) ) ); ;}
+ break;
+
+ case 17:
+#line 81 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 18:
+#line 84 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newMATCH( (yyvsp[-2].ptr), (yyvsp[0].ptr) ); ;}
+ break;
+
+ case 19:
+#line 85 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 20:
+#line 88 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCALC( (yyvsp[-2].ptr), (yyvsp[0].ptr), 1 ); ;}
+ break;
+
+ case 21:
+#line 89 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCALC( (yyvsp[-2].ptr), (yyvsp[0].ptr), 2 ); ;}
+ break;
+
+ case 22:
+#line 90 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 23:
+#line 93 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCALC( (yyvsp[-2].ptr), (yyvsp[0].ptr), 3 ); ;}
+ break;
+
+ case 24:
+#line 94 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newCALC( (yyvsp[-2].ptr), (yyvsp[0].ptr), 4 ); ;}
+ break;
+
+ case 25:
+#line 95 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 26:
+#line 98 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newNOT( (yyvsp[0].ptr) ); ;}
+ break;
+
+ case 27:
+#line 99 "yacc.y"
+ { (yyval.ptr) = (yyvsp[0].ptr); ;}
+ break;
+
+ case 28:
+#line 102 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newBRACKETS( (yyvsp[-1].ptr) ); ;}
+ break;
+
+ case 29:
+#line 103 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newEXIST( (yyvsp[0].name) ); ;}
+ break;
+
+ case 30:
+#line 104 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newID( (yyvsp[0].name) ); ;}
+ break;
+
+ case 31:
+#line 105 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newNUM( (yyvsp[0].vali) ); ;}
+ break;
+
+ case 32:
+#line 106 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newFLOAT( (yyvsp[0].vald) ); ;}
+ break;
+
+ case 33:
+#line 107 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newSTRING( (yyvsp[0].name) ); ;}
+ break;
+
+ case 34:
+#line 108 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newBOOL( (yyvsp[0].valb) ); ;}
+ break;
+
+ case 35:
+#line 109 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newMAX2( (yyvsp[0].name) ); ;}
+ break;
+
+ case 36:
+#line 110 "yacc.y"
+ { (yyval.ptr) = KTraderParse_newMIN2( (yyvsp[0].name) ); ;}
+ break;
+
+
+ }
+
+/* Line 1037 of yacc.c. */
+#line 1281 "yacc.tab.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
+ }
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
+ if (yychar == YYEOF)
+ for (;;)
+ {
+
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ yydestruct ("Error: popping",
+ yystos[*yyssp], yyvsp);
+ }
+ }
+ else
+ {
+ yydestruct ("Error: discarding", yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
+ goto yyerrorlab;
+#endif
+
+yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping", yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yydestruct ("Error: discarding lookahead",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 115 "yacc.y"
+
+
+void yyerror ( const char *s ) /* Called by yyparse on error */
+{
+ KTraderParse_error( s );
+}
+
+void KTraderParse_mainParse( const char *_code )
+{
+ KTraderParse_initFlex( _code );
+ yyparse();
+}
+
diff --git a/tdeio/tdeio/yacc.h b/tdeio/tdeio/yacc.h
new file mode 100644
index 000000000..ca84fb025
--- /dev/null
+++ b/tdeio/tdeio/yacc.h
@@ -0,0 +1,93 @@
+/* A Bison parser, made by GNU Bison 1.875. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ NOT = 258,
+ EQ = 259,
+ NEQ = 260,
+ LEQ = 261,
+ GEQ = 262,
+ LE = 263,
+ GR = 264,
+ OR = 265,
+ AND = 266,
+ TOKEN_IN = 267,
+ EXIST = 268,
+ MAX = 269,
+ MIN = 270,
+ VAL_BOOL = 271,
+ VAL_STRING = 272,
+ VAL_ID = 273,
+ VAL_NUM = 274,
+ VAL_FLOAT = 275
+ };
+#endif
+#define NOT 258
+#define EQ 259
+#define NEQ 260
+#define LEQ 261
+#define GEQ 262
+#define LE 263
+#define GR 264
+#define OR 265
+#define AND 266
+#define TOKEN_IN 267
+#define EXIST 268
+#define MAX 269
+#define MIN 270
+#define VAL_BOOL 271
+#define VAL_STRING 272
+#define VAL_ID 273
+#define VAL_NUM 274
+#define VAL_FLOAT 275
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 13 "yacc.y"
+typedef union YYSTYPE {
+ char valb;
+ int vali;
+ double vald;
+ char *name;
+ void *ptr;
+} YYSTYPE;
+/* Line 1240 of yacc.c. */
+#line 84 "yacc.tab.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE kiotraderlval;
+
+
+
diff --git a/tdeio/tdeio/yacc.y b/tdeio/tdeio/yacc.y
new file mode 100644
index 000000000..1b86f4737
--- /dev/null
+++ b/tdeio/tdeio/yacc.y
@@ -0,0 +1,126 @@
+%{
+#include <stdlib.h>
+#include <stdio.h>
+#include "ktraderparse.h"
+
+void yyerror(const char *s);
+int yylex();
+void KTraderParse_initFlex( const char *s );
+
+%}
+
+%union
+{
+ char valb;
+ int vali;
+ double vald;
+ char *name;
+ void *ptr;
+}
+
+%token NOT
+%token EQ
+%token NEQ
+%token LEQ
+%token GEQ
+%token LE
+%token GR
+%token OR
+%token AND
+%token TOKEN_IN
+%token EXIST
+%token MAX
+%token MIN
+
+%token <valb> VAL_BOOL
+%token <name> VAL_STRING
+%token <name> VAL_ID
+%token <vali> VAL_NUM
+%token <vald> VAL_FLOAT
+
+%type <ptr> bool
+%type <ptr> bool_or
+%type <ptr> bool_and
+%type <ptr> bool_compare
+%type <ptr> expr_in
+%type <ptr> expr_twiddle
+%type <ptr> expr
+%type <ptr> term
+%type <ptr> factor_non
+%type <ptr> factor
+
+/* Grammar follows */
+
+%%
+
+constraint: /* empty */ { KTraderParse_setParseTree( 0L ); }
+ | bool { KTraderParse_setParseTree( $<ptr>1 ); }
+;
+
+bool: bool_or { $$ = $<ptr>1; }
+;
+
+bool_or: bool_and OR bool_or { $$ = KTraderParse_newOR( $<ptr>1, $<ptr>3 ); }
+ | bool_and { $$ = $<ptr>1; }
+;
+
+bool_and: bool_compare AND bool_and { $$ = KTraderParse_newAND( $<ptr>1, $<ptr>3 ); }
+ | bool_compare { $$ = $<ptr>1; }
+;
+
+bool_compare: expr_in EQ expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 1 ); }
+ | expr_in NEQ expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 2 ); }
+ | expr_in GEQ expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 3 ); }
+ | expr_in LEQ expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 4 ); }
+ | expr_in LE expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 5 ); }
+ | expr_in GR expr_in { $$ = KTraderParse_newCMP( $<ptr>1, $<ptr>3, 6 ); }
+ | expr_in { $$ = $<ptr>1; }
+;
+
+expr_in: expr_twiddle TOKEN_IN VAL_ID { $$ = KTraderParse_newIN( $<ptr>1, KTraderParse_newID( $<name>3 ) ); }
+ | expr_twiddle { $$ = $<ptr>1; }
+;
+
+expr_twiddle: expr '~' expr { $$ = KTraderParse_newMATCH( $<ptr>1, $<ptr>3 ); }
+ | expr { $$ = $<ptr>1; }
+;
+
+expr: expr '+' term { $$ = KTraderParse_newCALC( $<ptr>1, $<ptr>3, 1 ); }
+ | expr '-' term { $$ = KTraderParse_newCALC( $<ptr>1, $<ptr>3, 2 ); }
+ | term { $$ = $<ptr>1; }
+;
+
+term: term '*' factor_non { $$ = KTraderParse_newCALC( $<ptr>1, $<ptr>3, 3 ); }
+ | term '/' factor_non { $$ = KTraderParse_newCALC( $<ptr>1, $<ptr>3, 4 ); }
+ | factor_non { $$ = $<ptr>1; }
+;
+
+factor_non: NOT factor { $$ = KTraderParse_newNOT( $<ptr>2 ); }
+ | factor { $$ = $<ptr>1; }
+;
+
+factor: '(' bool_or ')' { $$ = KTraderParse_newBRACKETS( $<ptr>2 ); }
+ | EXIST VAL_ID { $$ = KTraderParse_newEXIST( $<name>2 ); }
+ | VAL_ID { $$ = KTraderParse_newID( $<name>1 ); }
+ | VAL_NUM { $$ = KTraderParse_newNUM( $<vali>1 ); }
+ | VAL_FLOAT { $$ = KTraderParse_newFLOAT( $<vald>1 ); }
+ | VAL_STRING { $$ = KTraderParse_newSTRING( $<name>1 ); }
+ | VAL_BOOL { $$ = KTraderParse_newBOOL( $<valb>1 ); }
+ | MAX VAL_ID { $$ = KTraderParse_newMAX2( $<name>2 ); }
+ | MIN VAL_ID { $$ = KTraderParse_newMIN2( $<name>2 ); }
+;
+
+/* End of grammar */
+
+%%
+
+void yyerror ( const char *s ) /* Called by yyparse on error */
+{
+ KTraderParse_error( s );
+}
+
+void KTraderParse_mainParse( const char *_code )
+{
+ KTraderParse_initFlex( _code );
+ yyparse();
+}
diff --git a/tdeio/tdeioexec/CMakeLists.txt b/tdeio/tdeioexec/CMakeLists.txt
new file mode 100644
index 000000000..b0cdf0b52
--- /dev/null
+++ b/tdeio/tdeioexec/CMakeLists.txt
@@ -0,0 +1,42 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeui
+ ${CMAKE_SOURCE_DIR}/tdeio
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### tdeioexec ###################################
+
+set( target tdeioexec )
+
+set( ${target}_SRCS
+ main.cpp
+)
+
+tde_add_executable( ${target} AUTOMOC
+ SOURCES ${${target}_SRCS}
+ LINK tdeio-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
+
+tde_install_symlink( ${target} ${BIN_INSTALL_DIR}/kfmexec )
diff --git a/tdeio/tdeioexec/Makefile.am b/tdeio/tdeioexec/Makefile.am
new file mode 100644
index 000000000..2879342ff
--- /dev/null
+++ b/tdeio/tdeioexec/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = $(all_includes)
+
+bin_PROGRAMS = tdeioexec
+
+tdeioexec_SOURCES = main.cpp
+tdeioexec_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+tdeioexec_LDADD = $(LIB_KIO)
+
+noinst_HEADERS = main.h
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) $(tdeioexec_SOURCES) -o $(podir)/tdeioexec.pot
+
+install-exec-local:
+ @rm -f $(DESTDIR)$(bindir)/kfmexec
+ @$(LN_S) tdeioexec $(DESTDIR)$(bindir)/kfmexec
+
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/tdeio/tdeioexec/README b/tdeio/tdeioexec/README
new file mode 100644
index 000000000..daaa38bdb
--- /dev/null
+++ b/tdeio/tdeioexec/README
@@ -0,0 +1,26 @@
+kfmexec is launched when the user wants to open a remote file with
+an application that only supports local files.
+
+For this it does the following:
+- downloads a remote file to a temp location
+- starts a 'local' application with that temp file as argument
+- wait fors application to be exited
+- if the modification time of the file is different from the original one,
+(because the file was modified) then it offers re-uploading the modified version.
+This is how you offer network transparency to apps that don't have it.
+
+BUT: with KUniqueApplication, this breaks, because the app returns at once,
+so we have no way to know when the user finished editing the file...
+
+Conclusion: if the application has network transparency built-in, it should
+put "%u" in its desktop file - and kfmexec isn't used -. If it doesn't, either
+it's a TDEApplication and kfmexec does its job, or it's a KUniqueApplication
+and... kfmexec can't see modifications to the file. Be warned.
+
+From Waldo: "The program doesn't return _at once_. It returns
+after "newInstance()" returns. So if you open the file there it will still work.
+(Or rename it)"
+
+David Faure <faure@kde.org>
+20-May-2000
+
diff --git a/tdeio/tdeioexec/main.cpp b/tdeio/tdeioexec/main.cpp
new file mode 100644
index 000000000..9f7bd9faa
--- /dev/null
+++ b/tdeio/tdeioexec/main.cpp
@@ -0,0 +1,294 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <tdeio/job.h>
+#include <krun.h>
+#include <tdeio/netaccess.h>
+#include <kprocess.h>
+#include <kservice.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kstartupinfo.h>
+#include <kshell.h>
+#include <kde_file.h>
+
+
+#include "main.h"
+
+
+static const char description[] =
+ I18N_NOOP("KIO Exec - Opens remote files, watches modifications, asks for upload");
+
+static KCmdLineOptions options[] =
+{
+ { "tempfiles", I18N_NOOP("Treat URLs as local files and delete them afterwards"), 0 },
+ { "suggestedfilename <file name>", I18N_NOOP("Suggested file name for the downloaded file"), 0 },
+ { "+command", I18N_NOOP("Command to execute"), 0 },
+ { "+[URLs]", I18N_NOOP("URL(s) or local file(s) used for 'command'"), 0 },
+ KCmdLineLastOption
+};
+
+
+int jobCounter = 0;
+
+TQPtrList<TDEIO::Job>* jobList = 0L;
+
+KIOExec::KIOExec()
+{
+ jobList = new TQPtrList<TDEIO::Job>;
+ jobList->setAutoDelete( false ); // jobs autodelete themselves
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ if (args->count() < 1)
+ TDECmdLineArgs::usage(i18n("'command' expected.\n"));
+
+ tempfiles = args->isSet("tempfiles");
+ if ( args->isSet( "suggestedfilename" ) )
+ suggestedFileName = TQString::fromLocal8Bit( args->getOption( "suggestedfilename" ) );
+ expectedCounter = 0;
+ command = args->arg(0);
+ kdDebug() << "command=" << command << endl;
+
+ for ( int i = 1; i < args->count(); i++ )
+ {
+ KURL url = args->url(i);
+ // we need to map system:/ etc to make sure we get this right
+ url = TDEIO::NetAccess::mostLocalURL( url, 0 );
+
+ //kdDebug() << "url=" << url.url() << " filename=" << url.fileName() << endl;
+ // A local file, not an URL ?
+ // => It is not encoded and not shell escaped, too.
+ if ( url.isLocalFile() )
+ {
+ fileInfo file;
+ file.path = url.path();
+ file.url = url;
+ fileList.append(file);
+ }
+ // It is an URL
+ else
+ {
+ if ( !url.isValid() )
+ KMessageBox::error( 0L, i18n( "The URL %1\nis malformed" ).arg( url.url() ) );
+ else if ( tempfiles )
+ KMessageBox::error( 0L, i18n( "Remote URL %1\nnot allowed with --tempfiles switch" ).arg( url.url() ) );
+ else
+ // We must fetch the file
+ {
+ TQString fileName = TDEIO::encodeFileName( url.fileName() );
+ if ( !suggestedFileName.isEmpty() )
+ fileName = suggestedFileName;
+ // Build the destination filename, in ~/.trinity/cache-*/krun/
+ // Unlike KDE-1.1, we put the filename at the end so that the extension is kept
+ // (Some programs rely on it)
+ TQString tmp = TDEGlobal::dirs()->saveLocation( "cache", "krun/" ) +
+ TQString("%1.%2.%3").arg(getpid()).arg(jobCounter++).arg(fileName);
+ fileInfo file;
+ file.path = tmp;
+ file.url = url;
+ fileList.append(file);
+
+ expectedCounter++;
+ KURL dest;
+ dest.setPath( tmp );
+ kdDebug() << "Copying " << url.prettyURL() << " to " << dest << endl;
+ TDEIO::Job *job = TDEIO::file_copy( url, dest );
+ jobList->append( job );
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+ }
+ }
+ }
+ args->clear();
+
+ if ( tempfiles ) {
+ // #113991
+ TQTimer::singleShot( 0, this, TQT_SLOT( slotRunApp() ) );
+ //slotRunApp(); // does not return
+ return;
+ }
+
+ counter = 0;
+ if ( counter == expectedCounter )
+ slotResult( 0L );
+}
+
+void KIOExec::slotResult( TDEIO::Job * job )
+{
+ if (job && job->error())
+ {
+ // That error dialog would be queued, i.e. not immediate...
+ //job->showErrorDialog();
+ if ( (job->error() != TDEIO::ERR_USER_CANCELED) )
+ KMessageBox::error( 0L, job->errorString() );
+
+ TQString path = static_cast<TDEIO::FileCopyJob*>(job)->destURL().path();
+
+ TQValueList<fileInfo>::Iterator it = fileList.begin();
+ for(;it != fileList.end(); ++it)
+ {
+ if ((*it).path == path)
+ break;
+ }
+
+ if ( it != fileList.end() )
+ fileList.remove( it );
+ else
+ kdDebug() << static_cast<TDEIO::FileCopyJob*>(job)->destURL().path() << " not found in list" << endl;
+ }
+
+ counter++;
+
+ if ( counter < expectedCounter )
+ return;
+
+ kdDebug() << "All files downloaded, will call slotRunApp shortly" << endl;
+ // We know we can run the app now - but let's finish the job properly first.
+ TQTimer::singleShot( 0, this, TQT_SLOT( slotRunApp() ) );
+
+ jobList->clear();
+}
+
+void KIOExec::slotRunApp()
+{
+ if ( fileList.isEmpty() ) {
+ kdDebug() << k_funcinfo << "No files downloaded -> exiting" << endl;
+ exit(1);
+ }
+
+ KService service("dummy", command, TQString::null);
+
+ KURL::List list;
+ // Store modification times
+ TQValueList<fileInfo>::Iterator it = fileList.begin();
+ for ( ; it != fileList.end() ; ++it )
+ {
+ KDE_struct_stat buff;
+ (*it).time = KDE_stat( TQFile::encodeName((*it).path), &buff ) ? 0 : buff.st_mtime;
+ KURL url;
+ url.setPath((*it).path);
+ list << url;
+ }
+
+ TQStringList params = KRun::processDesktopExec(service, list, false /*no shell*/);
+
+ kdDebug() << "EXEC " << KShell::joinArgs( params ) << endl;
+
+#ifdef Q_WS_X11
+ // propagate the startup indentification to the started process
+ KStartupInfoId id;
+ id.initId( kapp->startupId());
+ id.setupStartupEnv();
+#endif
+
+ TDEProcess proc;
+ proc << params;
+ proc.start( TDEProcess::Block );
+
+#ifdef Q_WS_X11
+ KStartupInfo::resetStartupEnv();
+#endif
+
+ kdDebug() << "EXEC done" << endl;
+
+ // Test whether one of the files changed
+ it = fileList.begin();
+ for( ;it != fileList.end(); ++it )
+ {
+ KDE_struct_stat buff;
+ TQString src = (*it).path;
+ KURL dest = (*it).url;
+ if ( (KDE_stat( TQFile::encodeName(src), &buff ) == 0) &&
+ ((*it).time != buff.st_mtime) )
+ {
+ if ( tempfiles )
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n( "The supposedly temporary file\n%1\nhas been modified.\nDo you still want to delete it?" ).arg(dest.prettyURL()),
+ i18n( "File Changed" ), KStdGuiItem::del(), i18n("Do Not Delete") ) != KMessageBox::Yes )
+ continue; // don't delete the temp file
+ }
+ else if ( ! dest.isLocalFile() ) // no upload when it's already a local file
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n( "The file\n%1\nhas been modified.\nDo you want to upload the changes?" ).arg(dest.prettyURL()),
+ i18n( "File Changed" ), i18n("Upload"), i18n("Do Not Upload") ) == KMessageBox::Yes )
+ {
+ kdDebug() << TQString(TQString("src='%1' dest='%2'").arg(src).arg(dest.url())).ascii() << endl;
+ // Do it the synchronous way.
+ if ( !TDEIO::NetAccess::upload( src, dest, 0 ) )
+ {
+ KMessageBox::error( 0L, TDEIO::NetAccess::lastErrorString() );
+ continue; // don't delete the temp file
+ }
+ }
+ }
+ }
+
+ if ( !dest.isLocalFile() || tempfiles ) {
+ // Wait for a reasonable time so that even if the application forks on startup (like OOo or amarok)
+ // it will have time to start up and read the file before it gets deleted. #130709.
+ kdDebug() << "sleeping..." << endl;
+ sleep(180); // 3 mn
+ kdDebug() << "about to delete " << src << endl;
+ unlink( TQFile::encodeName(src) );
+ }
+ }
+
+ //kapp->quit(); not efficient enough
+ exit(0);
+}
+
+int main( int argc, char **argv )
+{
+ TDEAboutData aboutData( "tdeioexec", I18N_NOOP("KIOExec"),
+ VERSION, description, TDEAboutData::License_GPL,
+ "(c) 1998-2000,2003 The KFM/Konqueror Developers");
+ aboutData.addAuthor("David Faure",0, "faure@kde.org");
+ aboutData.addAuthor("Stephan Kulow",0, "coolo@kde.org");
+ aboutData.addAuthor("Bernhard Rosenkraenzer",0, "bero@arklinux.org");
+ aboutData.addAuthor("Waldo Bastian",0, "bastian@kde.org");
+ aboutData.addAuthor("Oswald Buddenhagen",0, "ossi@kde.org");
+
+ TDECmdLineArgs::init( argc, argv, &aboutData );
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app;
+
+ KIOExec exec;
+
+ kdDebug() << "Constructor returned..." << endl;
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tdeio/tdeioexec/main.h b/tdeio/tdeioexec/main.h
new file mode 100644
index 000000000..beb6a2297
--- /dev/null
+++ b/tdeio/tdeioexec/main.h
@@ -0,0 +1,35 @@
+#ifndef _main_h
+#define _main_h
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqstrlist.h>
+#include <tqtimer.h>
+
+namespace TDEIO { class Job; }
+
+class KIOExec : public TQObject
+{
+ Q_OBJECT
+public:
+ KIOExec();
+
+public slots:
+ void slotResult( TDEIO::Job * );
+ void slotRunApp();
+
+protected:
+ bool tempfiles;
+ TQString suggestedFileName;
+ int counter;
+ int expectedCounter;
+ TQString command;
+ struct fileInfo {
+ TQString path;
+ KURL url;
+ int time;
+ };
+ TQValueList<fileInfo> fileList;
+};
+
+#endif
diff --git a/tdeio/tdeioslave.upd b/tdeio/tdeioslave.upd
new file mode 100644
index 000000000..cd4972741
--- /dev/null
+++ b/tdeio/tdeioslave.upd
@@ -0,0 +1,18 @@
+# Hello world
+Id=kde2.2/r1
+File=tdeioslaverc,kio_httprc
+Group=Cache Settings,
+Key=MaxCacheSize
+Key=MaxCacheAge
+Key=UseCache
+File=tdeioslaverc
+Group=Browser Settings/UserAgent,UserAgent
+AllKeys
+Id=kde2.2/r2
+File=tdeioslaverc,kio_httprc
+Group=UserAgent
+Script=useragent.pl,perl
+Id=kde2.2/r3
+File=tdeioslaverc
+Group=Proxy Settings
+Script=proxytype.pl,perl
diff --git a/tdeio/tests/CMakeLists.txt b/tdeio/tests/CMakeLists.txt
new file mode 100644
index 000000000..a9f6bd4ef
--- /dev/null
+++ b/tdeio/tests/CMakeLists.txt
@@ -0,0 +1,36 @@
+#################################################
+#
+# (C) 2010 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include_directories(
+ ${TQT_INCLUDE_DIRS}
+ ${CMAKE_BINARY_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdecore
+ ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+)
+
+
+##### tdetradertest ###############################
+
+set( target tdetradertest )
+
+set( ${target}_SRCS
+ tdetradertest.cpp
+)
+
+tde_add_executable( ${target}
+ SOURCES ${${target}_SRCS}
+ LINK tdeio-shared
+ DESTINATION ${BIN_INSTALL_DIR}
+)
diff --git a/tdeio/tests/Makefile.am b/tdeio/tests/Makefile.am
new file mode 100644
index 000000000..138d0f0d2
--- /dev/null
+++ b/tdeio/tests/Makefile.am
@@ -0,0 +1,91 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 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.
+
+INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/tdeio $(all_includes)
+LDADD = $(LIB_KIO)
+AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor
+
+check_PROGRAMS = tdesycocatest getalltest kruntest ktartest kziptest\
+ tdeioslavetest kdirwatchtest kshredtest speed kurifiltertest \
+ kdefaultprogresstest kmimemagictest \
+ kfiltertest kiopassdlgtest kscantest kdirlistertest \
+ previewtest kionetrctest kdcopcheck metatest \
+ kmimefromext kpropsdlgtest kmfitest dataprotocoltest \
+ kprotocolinfotest tdesycocaupdatetest netaccesstest jobtest \
+ kurlcompletiontest kmimetypetest kacltest
+
+# Unfortunately some tests depend on the network settings, it seems
+#check: kurifiltertest
+# ./kurifiltertest
+check-local: kziptest
+ ./kziptest list $(srcdir)/wronglocalsizes.zip
+
+TESTS = kmimetypetest
+
+bin_PROGRAMS = tdetradertest
+
+METASOURCES = AUTO
+
+speed_SOURCES = speed.cpp
+tdeioslavetest_SOURCES = tdeioslavetest.cpp
+kshredtest_SOURCES = kshredtest.cpp
+kdefaultprogresstest_SOURCES = kdefaultprogresstest.cpp
+kionetrctest_SOURCES = kionetrctest.cpp
+kiopassdlgtest_SOURCES = kiopassdlgtest.cpp
+kurifiltertest_SOURCES = kurifiltertest.cpp
+tdesycocatest_SOURCES = tdesycocatest.cpp
+kdcopcheck_SOURCES = kdcopcheck.cpp
+getalltest_SOURCES = getalltest.cpp
+kruntest_SOURCES = kruntest.cpp
+kdirwatchtest_SOURCES = kdirwatchtest.cpp
+tdetradertest_SOURCES = tdetradertest.cpp
+kmimemagictest_SOURCES = kmimemagictest.cpp
+kfiltertest_SOURCES = kfiltertest.cpp
+kscantest_SOURCES = kscantest.cpp
+kdirlistertest_SOURCES = kdirlistertest.cpp
+previewtest_SOURCES = previewtest.cpp
+ktartest_SOURCES = ktartest.cpp
+kziptest_SOURCES = kziptest.cpp
+metatest_SOURCES = metatest.cpp
+kmimefromext_SOURCES = kmimefromext.cpp
+kpropsdlgtest_SOURCES = kpropsdlgtest.cpp
+kmfitest_SOURCES = kmfitest.cpp
+dataprotocoltest_SOURCES = dataprotocoltest.cpp
+kprotocolinfotest_SOURCES = kprotocolinfotest.cpp
+tdesycocaupdatetest_SOURCES = tdesycocaupdatetest.cpp
+netaccesstest_SOURCES = netaccesstest.cpp
+jobtest_SOURCES = jobtest.cpp
+kurlcompletiontest_SOURCES = kurlcompletiontest.cpp
+kmimetypetest_SOURCES = kmimetypetest.cpp
+kacltest_SOURCES = kacltest.cpp
+
+
+check_LTLIBRARIES = tdeunittest_kdirwatch.la
+tdeunittest_kdirwatch_la_SOURCES = kdirwatchunittest.cpp
+tdeunittest_kdirwatch_la_LIBADD = $(LIB_KUNITTEST) $(LIB_KIO)
+tdeunittest_kdirwatch_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN)
+
+# tdefile meta stuff. Comment this in, if you want a small
+# metadata plugin test and "make install".
+#kde_module_LTLIBRARIES = dummymeta.la
+#dummymeta_la_SOURCES = dummymeta.cpp
+#dummymeta_la_LIBADD = $(LIB_KIO)
+#dummymeta_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+#services_DATA = dummymeta.desktop
+#servicesdir = $(kde_servicesdir)
diff --git a/tdeio/tests/dataprotocoltest.cpp b/tdeio/tests/dataprotocoltest.cpp
new file mode 100644
index 000000000..e236a2d7c
--- /dev/null
+++ b/tdeio/tests/dataprotocoltest.cpp
@@ -0,0 +1,287 @@
+// testing the data tdeioslave
+// (C) 2002, 2003 Leo Savernik
+//
+// invoke "make dataprotocoltest" to generate the binary inside KDE CVS
+// invoke "make test" to generate the binary outside KDE CVS
+
+// fix the symptoms, not the illness ;-)
+#ifdef QT_NO_ASCII_CAST
+# undef QT_NO_ASCII_CAST
+#endif
+
+#ifdef DATAKIOSLAVE
+# undef DATAKIOSLAVE
+#endif
+#ifndef TESTKIO
+# define TESTKIO
+#endif
+
+#include <tdeio/global.h>
+
+#include <tqcstring.h>
+#include <tqstring.h>
+
+#include <iostream.h>
+
+class KURL;
+
+class TestSlave {
+public:
+ TestSlave() {
+ }
+ virtual ~TestSlave() {
+ }
+
+ virtual void get(const KURL &) = 0;
+ virtual void mimetype(const KURL &) = 0;
+
+ void mimeType(const TQString &type) {
+ testStrings("MIME Type: ",mime_type_expected,type);
+ }
+
+ void totalSize(TDEIO::filesize_t bytes) {
+// cout << "content size: " << bytes << " bytes" << endl;
+ }
+
+ void setMetaData(const TQString &key, const TQString &value) {
+// meta_data[key] = value;
+// cout << "§ " << key << " = " << value << endl;
+ TQString prefix = "Metadata[\""+key+"\"]: ";
+ TDEIO::MetaData::Iterator it = attributes_expected.find(key);
+ if (it != attributes_expected.end()) {
+ testStrings(prefix,it.data(),value);
+ // remove key from map
+ attributes_expected.remove(it);
+ } else {
+ cout << endl << prefix << " no such key expected";
+ total++;
+ }
+ }
+
+ void sendMetaData() {
+ // check here if attributes_expected contains any excess keys
+ TDEIO::MetaData::ConstIterator it = attributes_expected.begin();
+ TDEIO::MetaData::ConstIterator end = attributes_expected.end();
+ for (; it != end; ++it) {
+ cout << endl << "Metadata[\"" << it.key()
+ << "\"] was expected but not defined";
+ total++;
+ }
+ }
+
+ void data(const TQByteArray &a) {
+ if (a.isEmpty())
+/* cout << "<no more data>" << endl*/;
+ else {
+ testStrings("Content: ",content_expected,a);
+ }/*end if*/
+ }
+
+ void finished() {
+ }
+
+ void dispatchLoop() {
+ // dummy to make kde_main happy
+ }
+
+ // == stuff for regression testing
+private:
+ int testcaseno; // number of testcase
+ bool failure; // true if any testcase failed
+ TQMap<int,bool> failed_testcases;
+
+ // -- testcase related members
+ TQString mime_type_expected; // expected mime type
+ /** contains all attributes and values the testcase has to set */
+ TDEIO::MetaData attributes_expected;
+ /** contains the content as it is expected to be returned */
+ TQByteArray content_expected;
+ int passed; // # of passed tests
+ int total; // # of total tests
+
+ /**
+ * compares two strings, printing an error message if they don't match.
+ * @param prefix prefix string for output in case of mismatch
+ * @param templat template string
+ * @param s string to compare to template
+ * @param casesensitive true if case sensitive compare (currently not used)
+ */
+ void testStrings(const TQString &prefix, const TQString &templat,
+ const TQString &s, bool /*casesensitive*/ = true) {
+ if (templat == s)
+ passed++;
+ else {
+ cout << endl << prefix << "expected \"" << templat << "\", found \""
+ << s << "\"";
+ failure = true;
+ }/*end if*/
+ total++;
+ }
+
+public:
+ /** begins a testrun over all testcases */
+ void initTestrun() {
+ testcaseno = 0;
+ failure = false;
+ }
+
+ /** reuturns true if any testcase failed
+ */
+ bool hasFailedTestcases() const { return failure; }
+
+ /**
+ * sets up a new testcase
+ * @param name screen name for testcase
+ */
+ void beginTestcase(const char *name) {
+ passed = 0;
+ total = 0;
+ testcaseno++;
+ cout << "Testcase " << testcaseno << ": [" << name << "] ";
+ }
+
+ /**
+ * sets the mime type that this testcase is expected to return
+ */
+ void setExpectedMimeType(const TQString &mime_type) {
+ mime_type_expected = mime_type;
+ }
+
+ /**
+ * sets all attribute-value pairs the testcase must deliver.
+ */
+ void setExpectedAttributes(const TDEIO::MetaData &attres) {
+ attributes_expected = attres;
+ }
+
+ /**
+ * sets content as expected to be delivered by the testcase.
+ */
+ void setExpectedContent(const TQByteArray &content) {
+ content_expected = content;
+ }
+
+ /**
+ * closes testcase, printing out stats
+ */
+ void endTestcase() {
+ bool failed = passed < total;
+ if (failed) {
+ failure = true;
+ failed_testcases[testcaseno] = true;
+ cout << endl;
+ }
+ cout << "(" << passed << " of " << total << ") " << (failed ? "failed"
+ : "passed") << endl;
+ }
+
+ void endTestrun() {
+ if (failure) {
+ TQMap<int,bool>::ConstIterator it = failed_testcases.begin();
+ for (; it != failed_testcases.end(); ++it) {
+ cout << "Testcase " << it.key() << " failed" << endl;
+ }
+ }
+ }
+};
+
+#include "dataprotocol.cpp" // we need access to static data & functions
+
+// == general functionality
+const struct {
+const char * const name;
+const char * const exp_mime_type; // 0 means "text/plain"
+const struct {
+ const char * const key;
+ const char * const value;
+} exp_attrs[10]; // ended with a key==0, value==0 pair
+const char * const exp_content;
+const char * const url;
+} testcases[] = {
+ // -----------------------------------------------------------------
+ { "escape resolving", 0, {}, "blah blah", "data:,blah%20blah" },
+ // --------------------
+ { "mime type, escape resolving", "text/html", {},
+ "<div style=\"border:thin orange solid;padding:1ex;background-color:"
+ "yellow;color:black\">Rich <b>text</b></div>",
+ "data:text/html,<div%20style=\"border:thin%20orange%20solid;"
+ "padding:1ex;background-color:yellow;color:black\">Rich%20<b>text</b>"
+ "</div>" },
+ // -------------------- whitespace test I
+ { "whitespace test I", "text/css", {
+ { "charset", "iso-8859-15" }, { 0,0 } },
+ " body { color: yellow; background:darkblue; font-weight:bold }",
+ "data:text/css ; charset = iso-8859-15 , body { color: yellow; "
+ "background:darkblue; font-weight:bold }" },
+ // -------------------- out of spec argument order, base64 decoding,
+ // whitespace test II
+ { "out of spec argument order, base64 decoding, whitespace test II",
+ 0, {
+ { "charset", "iso-8859-1" }, { 0,0 } },
+ "paaaaaaaasd!!\n",
+ "data: ; base64 ; charset = \"iso-8859-1\" ,cGFhYWFhYWFhc2QhIQo=" },
+ // -------------------- arbitrary keys, reserved names as keys,
+ // whitespace test III
+ { "arbitrary keys, reserved names as keys, whitespace test III", 0, {
+ { "base64", "nospace" }, { "key", "onespaceinner" },
+ { "key2", "onespaceouter" }, { "charset", "utf8" },
+ { "<<empty>>", "" }, { 0,0 } },
+ "Die, Allied Schweinehund (C) 1990 Wolfenstein 3D",
+ "data: ;base64=nospace;key = onespaceinner; key2=onespaceouter ;"
+ " charset = utf8 ; <<empty>>= ,Die, Allied Schweinehund "
+ "(C) 1990 Wolfenstein 3D" },
+ // -------------------- string literal with escaped chars, testing
+ // delimiters within string
+ { "string literal with escaped chars, testing delimiters within "
+ "string", 0, {
+ { "fortune-cookie", "Master Leep say: \"Rabbit is humble, "
+ "Rabbit is gentle; follow the Rabbit\"" }, { 0,0 } },
+ "(C) 1997 Shadow Warrior ;-)",
+ "data:;fortune-cookie=\"Master Leep say: \\\"Rabbit is humble, "
+ "Rabbit is gentle; follow the Rabbit\\\"\",(C) 1997 Shadow Warrior "
+ ";-)" },
+};
+
+#if 0
+// == charset tests
+ // -------------------- string
+const QChar
+const TQChar * const charset_urls[] = {
+#endif
+
+int main(int /*argc*/,char* /*argv*/[]) {
+ DataProtocol kio_data;
+
+ kio_data.initTestrun();
+ for (uint i = 0; i < sizeof testcases/sizeof testcases[0]; i++) {
+ kio_data.beginTestcase(testcases[i].name);
+ kio_data.setExpectedMimeType(testcases[i].exp_mime_type != 0
+ ? testcases[i].exp_mime_type : "text/plain");
+
+ bool has_charset = false;
+ MetaData exp_attrs;
+ if (testcases[i].exp_attrs != 0) {
+ for (uint j = 0; testcases[i].exp_attrs[j].key != 0; j++) {
+ exp_attrs[testcases[i].exp_attrs[j].key] = testcases[i].exp_attrs[j].value;
+ if (strcmp(testcases[i].exp_attrs[j].key,"charset") == 0)
+ has_charset = true;
+ }/*next j*/
+ }
+ if (!has_charset) exp_attrs["charset"] = "us-ascii";
+ kio_data.setExpectedAttributes(exp_attrs);
+
+ TQByteArray exp_content;
+ uint exp_content_len = strlen(testcases[i].exp_content);
+ exp_content.setRawData(testcases[i].exp_content,exp_content_len);
+ kio_data.setExpectedContent(exp_content);
+
+ kio_data.get(testcases[i].url);
+
+ kio_data.endTestcase();
+ exp_content.resetRawData(testcases[i].exp_content,exp_content_len);
+ }/*next i*/
+ kio_data.endTestrun();
+
+ return kio_data.hasFailedTestcases() ? 1 : 0;
+}
+
diff --git a/tdeio/tests/dummymeta.cpp b/tdeio/tests/dummymeta.cpp
new file mode 100644
index 000000000..938b4d00b
--- /dev/null
+++ b/tdeio/tests/dummymeta.cpp
@@ -0,0 +1,20 @@
+#include <kgenericfactory.h>
+
+#include "dummymeta.h"
+
+K_EXPORT_COMPONENT_FACTORY( dummymeta, KGenericFactory<DummyMeta> )
+
+DummyMeta::DummyMeta( TQObject *parent, const char *name,
+ const TQStringList &preferredItems )
+ : KFilePlugin( parent, name, preferredItems )
+{
+ tqDebug("---- DummyMeta::DummyMeta: got %i preferred items.", preferredItems.count());
+}
+
+bool DummyMeta::readInfo( KFileMetaInfo::Internal & info )
+{
+ tqDebug("#### DummyMeta:: readInfo: %s", info.path().latin1() );
+ return 0L;
+}
+
+#include "dummymeta.moc"
diff --git a/tdeio/tests/dummymeta.desktop b/tdeio/tests/dummymeta.desktop
new file mode 100644
index 000000000..6d2748c82
--- /dev/null
+++ b/tdeio/tests/dummymeta.desktop
@@ -0,0 +1,54 @@
+[Desktop Entry]
+Type=Service
+Name=Dummy Meta
+Name[af]=Fop Meta
+Name[az]=Ä°ÅŸÉ™ Yaramayan Meta
+Name[be]=ÐŸÐ°Ñ€Ð¾Ð¶Ð½Ñ–Ñ Ð·Ð²ÐµÑткі
+Name[bn]=ডামি মেটা
+Name[cs]=Prázdné meta
+Name[csb]=Testowé pòdôwczi
+Name[cy]=Meta Dymi
+Name[da]=Dummy-meta
+Name[el]=Εικονικό Meta
+Name[eo]=Stulta Meto
+Name[et]=Dummy meta
+Name[fa]=Ùراساختگی
+Name[fi]=Tyhjä meta
+Name[fr]=Données factices
+Name[ga]=Meitea Caoch
+Name[hi]=डमी मेटा
+Name[hr]=Ogledni meta podatak
+Name[hu]=Ãœres (dummy) metaadat
+Name[it]=Informazioni aggiuntive posticce
+Name[ko]=가짜 메타
+Name[lb]=Dummy-Meta
+Name[lt]=Netikras Meta
+Name[ms]=Meta Olok-olok
+Name[mt]=Meta fittizju
+Name[ne]=डमी मेटा
+Name[nso]=Meta wa Dummy
+Name[pa]=ਫ਼ਰਜੀ ਮੈਟਾ
+Name[pl]=Dane testowe
+Name[ro]=Test Meta
+Name[rw]=Ikiragi Kidasanzwe
+Name[sk]=Prázdne meta
+Name[sl]=Slepi Meta
+Name[sr]=Лажни мета
+Name[sr@Latn]=Lažni meta
+Name[sv]=Testmeta
+Name[ta]=வெறà¯à®±à¯ மீடà¯à®Ÿà®¾
+Name[te]=à°¡à°®à±à°®à°¿ మెటా
+Name[tg]=Meta-и Ғайрикорӣ
+Name[tr]=Kukla Meta
+Name[uk]=Макет метаданих
+Name[uz]=Maʼnosiz meta
+Name[uz@cyrillic]=МаъноÑиз мета
+Name[ven]=Meta isa tshili
+Name[vi]=Siêu giả
+Name[zh_CN]=å“‘å…ƒ
+Name[zh_HK]=空的資料定義
+Name[zh_TW]=空的資料定義
+ServiceTypes=KFilePlugin
+X-TDE-Library=dummymeta
+MimeType=text/plain
+PreferredItems=Author,Title,Date
diff --git a/tdeio/tests/dummymeta.h b/tdeio/tests/dummymeta.h
new file mode 100644
index 000000000..4cefcc01d
--- /dev/null
+++ b/tdeio/tests/dummymeta.h
@@ -0,0 +1,20 @@
+#ifndef DUMMYMETA_H
+#define DUMMYMETA_H
+
+#include <tdefilemetainfo.h>
+
+class KFileMetaInfo;
+
+class DummyMeta : public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ DummyMeta( TQObject *parent, const char *name, const TQStringList &args );
+ ~DummyMeta() {}
+
+ virtual bool readInfo( KFileMetaInfo::Internal& info );
+
+};
+
+#endif
diff --git a/tdeio/tests/getalltest.cpp b/tdeio/tests/getalltest.cpp
new file mode 100644
index 000000000..07d8723ed
--- /dev/null
+++ b/tdeio/tests/getalltest.cpp
@@ -0,0 +1,44 @@
+#include <kservice.h>
+#include <kmimetype.h>
+#include <kservicetype.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+int main(int argc, char *argv[])
+{
+ TDEApplication k(argc,argv,"getalltest",false/*noGUI*/); // KMessageBox needs KApp for makeStdCaption
+
+//for (int i = 0 ; i < 2 ; ++i ) { // test twice to see if they got deleted
+ kdDebug() << "All services" << endl;
+ KService::List services = KService::allServices();
+ kdDebug() << "got " << services.count() << " services" << endl;
+ TQValueListIterator<KService::Ptr> s = services.begin();
+ for ( ; s != services.end() ; ++s )
+ {
+ kdDebug() << (*s)->name() << " " << (*s)->desktopEntryPath() << endl;
+ }
+//}
+
+ kdDebug() << "All mimeTypes" << endl;
+ KMimeType::List mimeTypes = KMimeType::allMimeTypes();
+ kdDebug() << "got " << mimeTypes.count() << " mimeTypes" << endl;
+ TQValueListIterator<KMimeType::Ptr> m = mimeTypes.begin();
+ for ( ; m != mimeTypes.end() ; ++m )
+ {
+ kdDebug() << (*m)->name() << endl;
+ }
+
+ kdDebug() << "All service types" << endl;
+ KServiceType::List list = KServiceType::allServiceTypes();
+ kdDebug() << "got " << list.count() << " service types" << endl;
+ TQValueListIterator<KServiceType::Ptr> st = list.begin();
+ for ( ; st != list.end() ; ++st )
+ {
+ kdDebug() << (*st)->name() << endl;
+ }
+
+ kdDebug() << "done" << endl;
+
+ return 0;
+}
diff --git a/tdeio/tests/jobtest.cpp b/tdeio/tests/jobtest.cpp
new file mode 100644
index 000000000..12f106cd2
--- /dev/null
+++ b/tdeio/tests/jobtest.cpp
@@ -0,0 +1,613 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-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 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 "jobtest.h"
+
+#include <config.h>
+
+#include <kurl.h>
+#include <kapplication.h>
+#include <klargefile.h>
+#include <tdeio/netaccess.h>
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+#include <kprotocolinfo.h>
+
+#include <tqfileinfo.h>
+#include <tqeventloop.h>
+#include <tqdir.h>
+#include <tqfileinfo.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <utime.h>
+
+// The code comes partly from tdebase/tdeioslave/trash/testtrash.cpp
+
+static bool check(const TQString& txt, TQString a, TQString b)
+{
+ if (a.isEmpty())
+ a = TQString::null;
+ if (b.isEmpty())
+ b = TQString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ TDEApplication::disableAutoDcopRegistration();
+ TDECmdLineArgs::init(argc,argv,"jobtest", 0, 0, 0, 0);
+ TDEApplication app;
+
+ JobTest test;
+ test.setup();
+ test.runAll();
+ test.cleanup();
+ kdDebug() << "All tests OK." << endl;
+ return 0; // success. The exit(1) in check() is what happens in case of failure.
+}
+
+TQString JobTest::homeTmpDir() const
+{
+ return TQDir::homeDirPath() + "/.trinity/jobtest/";
+}
+
+TQString JobTest::otherTmpDir() const
+{
+ // This one needs to be on another partition
+ return "/tmp/jobtest/";
+}
+
+KURL JobTest::systemTmpDir() const
+{
+ return "system:/home/.trinity/jobtest-system/";
+}
+
+TQString JobTest::realSystemPath() const
+{
+ return TQDir::homeDirPath() + "/.trinity/jobtest-system/";
+}
+
+void JobTest::setup()
+{
+ // Start with a clean base dir
+ cleanup();
+ TQDir dir; // TT: why not a static method?
+ bool ok = dir.mkdir( homeTmpDir() );
+ if ( !ok )
+ kdFatal() << "Couldn't create " << homeTmpDir() << endl;
+ ok = dir.mkdir( otherTmpDir() );
+ if ( !ok )
+ kdFatal() << "Couldn't create " << otherTmpDir() << endl;
+ ok = dir.mkdir( realSystemPath() );
+ if ( !ok )
+ kdFatal() << "Couldn't create " << realSystemPath() << endl;
+}
+
+void JobTest::runAll()
+{
+ get();
+ copyFileToSamePartition();
+ copyDirectoryToSamePartition();
+ copyDirectoryToExistingDirectory();
+ copyFileToOtherPartition();
+ copyDirectoryToOtherPartition();
+ listRecursive();
+ moveFileToSamePartition();
+ moveDirectoryToSamePartition();
+ moveFileToOtherPartition();
+ moveSymlinkToOtherPartition();
+ moveDirectoryToOtherPartition();
+ moveFileNoPermissions();
+ moveDirectoryNoPermissions();
+
+ copyFileToSystem();
+}
+
+void JobTest::cleanup()
+{
+ TDEIO::NetAccess::del( homeTmpDir(), 0 );
+ TDEIO::NetAccess::del( otherTmpDir(), 0 );
+ TDEIO::NetAccess::del( systemTmpDir(), 0 );
+}
+
+static void setTimeStamp( const TQString& path )
+{
+#ifdef Q_OS_UNIX
+ // Put timestamp in the past so that we can check that the
+ // copy actually preserves it.
+ struct timeval tp;
+ gettimeofday( &tp, 0 );
+ struct utimbuf utbuf;
+ utbuf.actime = tp.tv_sec - 30; // 30 seconds ago
+ utbuf.modtime = tp.tv_sec - 60; // 60 second ago
+ utime( TQFile::encodeName( path ), &utbuf );
+ tqDebug( "Time changed for %s", path.latin1() );
+#endif
+}
+
+static void createTestFile( const TQString& path )
+{
+ TQFile f( path );
+ if ( !f.open( IO_WriteOnly ) )
+ kdFatal() << "Can't create " << path << endl;
+ f.tqwriteBlock( "Hello world", 11 );
+ f.close();
+ setTimeStamp( path );
+}
+
+static void createTestSymlink( const TQString& path )
+{
+ // Create symlink if it doesn't exist yet
+ KDE_struct_stat buf;
+ if ( KDE_lstat( TQFile::encodeName( path ), &buf ) != 0 ) {
+ bool ok = symlink( "/IDontExist", TQFile::encodeName( path ) ) == 0; // broken symlink
+ if ( !ok )
+ kdFatal() << "couldn't create symlink: " << strerror( errno ) << endl;
+ }
+}
+
+static void createTestDirectory( const TQString& path )
+{
+ TQDir dir;
+ bool ok = dir.mkdir( path );
+ if ( !ok && !dir.exists() )
+ kdFatal() << "couldn't create " << path << endl;
+ createTestFile( path + "/testfile" );
+ createTestSymlink( path + "/testlink" );
+ setTimeStamp( path );
+}
+
+void JobTest::get()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "fileFromHome";
+ createTestFile( filePath );
+ KURL u; u.setPath( filePath );
+ m_result = -1;
+ TDEIO::StoredTransferJob* job = TDEIO::storedGet( u );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job* ) ),
+ this, TQT_SLOT( slotGetResult( TDEIO::Job* ) ) );
+ kapp->eventLoop()->enterLoop();
+ assert( m_result == 0 ); // no error
+ assert( m_data.size() == 11 );
+ assert( TQCString( m_data ) == "Hello world" );
+}
+
+void JobTest::slotGetResult( TDEIO::Job* job )
+{
+ m_result = job->error();
+ m_data = static_cast<TDEIO::StoredTransferJob *>(job)->data();
+ kapp->eventLoop()->exitLoop();
+}
+
+////
+
+void JobTest::copyLocalFile( const TQString& src, const TQString& dest )
+{
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ // copy the file with file_copy
+ bool ok = TDEIO::NetAccess::file_copy( u, d );
+ assert( ok );
+ assert( TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) ); // still there
+
+ {
+ // check that the timestamp is the same (#24443)
+ // Note: this only works because of copy() in kio_file.
+ // The datapump solution ignores mtime, the app has to call FileCopyJob::setModificationTime()
+ TQFileInfo srcInfo( src );
+ TQFileInfo destInfo( dest );
+ assert( srcInfo.lastModified() == destInfo.lastModified() );
+ }
+
+ // cleanup and retry with TDEIO::copy()
+ TQFile::remove( dest );
+ ok = TDEIO::NetAccess::dircopy( u, d, 0 );
+ assert( ok );
+ assert( TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) ); // still there
+ {
+ // check that the timestamp is the same (#24443)
+ TQFileInfo srcInfo( src );
+ TQFileInfo destInfo( dest );
+ assert( srcInfo.lastModified() == destInfo.lastModified() );
+ }
+}
+
+void JobTest::copyLocalDirectory( const TQString& src, const TQString& _dest, int flags )
+{
+ assert( TQFileInfo( src ).isDir() );
+ assert( TQFileInfo( src + "/testfile" ).isFile() );
+ KURL u;
+ u.setPath( src );
+ TQString dest( _dest );
+ KURL d;
+ d.setPath( dest );
+ if ( flags & AlreadyExists )
+ assert( TQFile::exists( dest ) );
+ else
+ assert( !TQFile::exists( dest ) );
+
+ bool ok = TDEIO::NetAccess::dircopy( u, d, 0 );
+ assert( ok );
+
+ if ( flags & AlreadyExists ) {
+ dest += "/" + u.fileName();
+ //kdDebug() << "Expecting dest=" << dest << endl;
+ }
+
+ assert( TQFile::exists( dest ) );
+ assert( TQFileInfo( dest ).isDir() );
+ assert( TQFileInfo( dest + "/testfile" ).isFile() );
+ assert( TQFile::exists( src ) ); // still there
+ {
+ // check that the timestamp is the same (#24443)
+ TQFileInfo srcInfo( src );
+ TQFileInfo destInfo( dest );
+ assert( srcInfo.lastModified() == destInfo.lastModified() );
+ }
+}
+
+void JobTest::copyFileToSamePartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "fileFromHome";
+ const TQString dest = homeTmpDir() + "fileFromHome_copied";
+ createTestFile( filePath );
+ copyLocalFile( filePath, dest );
+}
+
+void JobTest::copyDirectoryToSamePartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = homeTmpDir() + "dirFromHome";
+ const TQString dest = homeTmpDir() + "dirFromHome_copied";
+ createTestDirectory( src );
+ copyLocalDirectory( src, dest );
+}
+
+void JobTest::copyDirectoryToExistingDirectory()
+{
+ kdDebug() << k_funcinfo << endl;
+ // just the same as copyDirectoryToSamePartition, but it means that
+ // this time dest exists.
+ const TQString src = homeTmpDir() + "dirFromHome";
+ const TQString dest = homeTmpDir() + "dirFromHome_copied";
+ createTestDirectory( src );
+ copyLocalDirectory( src, dest, AlreadyExists );
+}
+
+void JobTest::copyFileToOtherPartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "fileFromHome";
+ const TQString dest = otherTmpDir() + "fileFromHome_copied";
+ createTestFile( filePath );
+ copyLocalFile( filePath, dest );
+}
+
+void JobTest::copyDirectoryToOtherPartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = homeTmpDir() + "dirFromHome";
+ const TQString dest = otherTmpDir() + "dirFromHome_copied";
+ // src is already created by copyDirectoryToSamePartition()
+ // so this is just in case someone calls this method only
+ if ( !TQFile::exists( src ) )
+ createTestDirectory( src );
+ copyLocalDirectory( src, dest );
+}
+
+void JobTest::moveLocalFile( const TQString& src, const TQString& dest )
+{
+ assert( TQFile::exists( src ) );
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ // move the file with file_move
+ bool ok = TDEIO::NetAccess::file_move( u, d );
+ assert( ok );
+ assert( TQFile::exists( dest ) );
+ assert( !TQFile::exists( src ) ); // not there anymore
+
+ // move it back with TDEIO::move()
+ ok = TDEIO::NetAccess::move( d, u, 0 );
+ assert( ok );
+ assert( !TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) ); // it's back
+}
+
+static void moveLocalSymlink( const TQString& src, const TQString& dest )
+{
+ KDE_struct_stat buf;
+ assert ( KDE_lstat( TQFile::encodeName( src ), &buf ) == 0 );
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ // move the symlink with move, NOT with file_move
+ bool ok = TDEIO::NetAccess::move( u, d );
+ if ( !ok )
+ kdWarning() << TDEIO::NetAccess::lastError() << endl;
+ assert( ok );
+ assert ( KDE_lstat( TQFile::encodeName( dest ), &buf ) == 0 );
+ assert( !TQFile::exists( src ) ); // not there anymore
+
+ // move it back with TDEIO::move()
+ ok = TDEIO::NetAccess::move( d, u, 0 );
+ assert( ok );
+ assert ( KDE_lstat( TQFile::encodeName( dest ), &buf ) != 0 ); // doesn't exist anymore
+ assert ( KDE_lstat( TQFile::encodeName( src ), &buf ) == 0 ); // it's back
+}
+
+void JobTest::moveLocalDirectory( const TQString& src, const TQString& dest )
+{
+ assert( TQFile::exists( src ) );
+ assert( TQFileInfo( src ).isDir() );
+ assert( TQFileInfo( src + "/testfile" ).isFile() );
+ assert( TQFileInfo( src + "/testlink" ).isSymLink() );
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ bool ok = TDEIO::NetAccess::move( u, d, 0 );
+ assert( ok );
+ assert( TQFile::exists( dest ) );
+ assert( TQFileInfo( dest ).isDir() );
+ assert( TQFileInfo( dest + "/testfile" ).isFile() );
+ assert( !TQFile::exists( src ) ); // not there anymore
+
+ assert( TQFileInfo( dest + "/testlink" ).isSymLink() );
+}
+
+void JobTest::moveFileToSamePartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "fileFromHome";
+ const TQString dest = homeTmpDir() + "fileFromHome_moved";
+ createTestFile( filePath );
+ moveLocalFile( filePath, dest );
+}
+
+void JobTest::moveDirectoryToSamePartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = homeTmpDir() + "dirFromHome";
+ const TQString dest = homeTmpDir() + "dirFromHome_moved";
+ createTestDirectory( src );
+ moveLocalDirectory( src, dest );
+}
+
+void JobTest::moveFileToOtherPartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "fileFromHome";
+ const TQString dest = otherTmpDir() + "fileFromHome_moved";
+ createTestFile( filePath );
+ moveLocalFile( filePath, dest );
+}
+
+void JobTest::moveSymlinkToOtherPartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString filePath = homeTmpDir() + "testlink";
+ const TQString dest = otherTmpDir() + "testlink_moved";
+ createTestSymlink( filePath );
+ moveLocalSymlink( filePath, dest );
+}
+
+void JobTest::moveDirectoryToOtherPartition()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = homeTmpDir() + "dirFromHome";
+ const TQString dest = otherTmpDir() + "dirFromHome_moved";
+ createTestDirectory( src );
+ moveLocalDirectory( src, dest );
+}
+
+void JobTest::moveFileNoPermissions()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = "/etc/passwd";
+ const TQString dest = homeTmpDir() + "passwd";
+ assert( TQFile::exists( src ) );
+ assert( TQFileInfo( src ).isFile() );
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ TDEIO::CopyJob* job = TDEIO::move( u, d, 0 );
+ job->setInteractive( false ); // no skip dialog, thanks
+ TQMap<TQString, TQString> metaData;
+ bool ok = TDEIO::NetAccess::synchronousRun( job, 0, 0, 0, &metaData );
+ assert( !ok );
+ assert( TDEIO::NetAccess::lastError() == TDEIO::ERR_ACCESS_DENIED );
+ // OK this is fishy. Just like mv(1), KIO's behavior depends on whether
+ // a direct rename(2) was used, or a full copy+del. In the first case
+ // there is no destination file created, but in the second case the
+ // destination file remains.
+ // In fact we assume /home is a separate partition, in this test, so:
+ assert( TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) );
+}
+
+void JobTest::moveDirectoryNoPermissions()
+{
+ kdDebug() << k_funcinfo << endl;
+ const TQString src = "/etc/init.d";
+ const TQString dest = homeTmpDir() + "init.d";
+ assert( TQFile::exists( src ) );
+ assert( TQFileInfo( src ).isDir() );
+ KURL u;
+ u.setPath( src );
+ KURL d;
+ d.setPath( dest );
+
+ TDEIO::CopyJob* job = TDEIO::move( u, d, 0 );
+ job->setInteractive( false ); // no skip dialog, thanks
+ TQMap<TQString, TQString> metaData;
+ bool ok = TDEIO::NetAccess::synchronousRun( job, 0, 0, 0, &metaData );
+ assert( !ok );
+ assert( TDEIO::NetAccess::lastError() == TDEIO::ERR_ACCESS_DENIED );
+ assert( TQFile::exists( dest ) ); // see moveFileNoPermissions
+ assert( TQFile::exists( src ) );
+}
+
+void JobTest::listRecursive()
+{
+ const TQString src = homeTmpDir();
+ KURL u;
+ u.setPath( src );
+ TDEIO::ListJob* job = TDEIO::listRecursive( u );
+ connect( job, TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList& ) ),
+ TQT_SLOT( slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList& ) ) );
+ bool ok = TDEIO::NetAccess::synchronousRun( job, 0 );
+ assert( ok );
+ m_names.sort();
+ check( "listRecursive", m_names.join( "," ), ".,..,"
+ "dirFromHome,dirFromHome/testfile,dirFromHome/testlink,dirFromHome_copied,"
+ "dirFromHome_copied/dirFromHome,dirFromHome_copied/dirFromHome/testfile,dirFromHome_copied/dirFromHome/testlink,"
+ "dirFromHome_copied/testfile,dirFromHome_copied/testlink,"
+ "fileFromHome,fileFromHome_copied" );
+}
+
+void JobTest::slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList& lst )
+{
+ for( TDEIO::UDSEntryList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
+ TDEIO::UDSEntry::ConstIterator it2 = (*it).begin();
+ TQString displayName;
+ KURL url;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch ((*it2).m_uds) {
+ case TDEIO::UDS_NAME:
+ displayName = (*it2).m_str;
+ break;
+ case TDEIO::UDS_URL:
+ url = (*it2).m_str;
+ break;
+ }
+ }
+ m_names.append( displayName );
+ }
+}
+
+void JobTest::copyFileToSystem()
+{
+ if ( !KProtocolInfo::isKnownProtocol( TQString::fromLatin1( "system" ) ) ) {
+ kdDebug() << k_funcinfo << "no kio_system, skipping test" << endl;
+ return;
+ }
+
+ // First test with support for UDS_LOCAL_PATH
+ copyFileToSystem( true );
+
+ TQString dest = realSystemPath() + "fileFromHome_copied";
+ TQFile::remove( dest );
+
+ // Then disable support for UDS_LOCAL_PATH, i.e. test what would
+ // happen for ftp, smb, http etc.
+ copyFileToSystem( false );
+}
+
+void JobTest::copyFileToSystem( bool resolve_local_urls )
+{
+ kdDebug() << k_funcinfo << resolve_local_urls << endl;
+ extern TDEIO_EXPORT bool kio_resolve_local_urls;
+ kio_resolve_local_urls = resolve_local_urls;
+
+ const TQString src = homeTmpDir() + "fileFromHome";
+ createTestFile( src );
+ KURL u;
+ u.setPath( src );
+ KURL d = systemTmpDir();
+ d.addPath( "fileFromHome_copied" );
+
+ kdDebug() << "copying " << u << " to " << d << endl;
+
+ // copy the file with file_copy
+ TDEIO::FileCopyJob* job = TDEIO::file_copy( u, d );
+ connect( job, TQT_SIGNAL(mimetype(TDEIO::Job*,const TQString&)),
+ this, TQT_SLOT(slotMimetype(TDEIO::Job*,const TQString&)) );
+ bool ok = TDEIO::NetAccess::synchronousRun( job, 0 );
+ assert( ok );
+
+ TQString dest = realSystemPath() + "fileFromHome_copied";
+
+ assert( TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) ); // still there
+
+ {
+ // do NOT check that the timestamp is the same.
+ // It can't work with file_copy when it uses the datapump,
+ // unless we use setModificationTime in the app code.
+ }
+
+ // Check mimetype
+ kdDebug() << m_mimetype << endl;
+ // There's no mimemagic determination in kio_file in trinity. Fixing this for kde4...
+ assert( m_mimetype == "application/octet-stream" );
+ //assert( m_mimetype == "text/plain" );
+
+ // cleanup and retry with TDEIO::copy()
+ TQFile::remove( dest );
+ ok = TDEIO::NetAccess::dircopy( u, d, 0 );
+ assert( ok );
+ assert( TQFile::exists( dest ) );
+ assert( TQFile::exists( src ) ); // still there
+ {
+ // check that the timestamp is the same (#79937)
+ TQFileInfo srcInfo( src );
+ TQFileInfo destInfo( dest );
+ assert( srcInfo.lastModified() == destInfo.lastModified() );
+ }
+
+ // restore normal behavior
+ kio_resolve_local_urls = true;
+}
+
+void JobTest::slotMimetype(TDEIO::Job* job, const TQString& type)
+{
+ assert( job );
+ m_mimetype = type;
+}
+
+#include "jobtest.moc"
diff --git a/tdeio/tests/jobtest.h b/tdeio/tests/jobtest.h
new file mode 100644
index 000000000..aeaceff0d
--- /dev/null
+++ b/tdeio/tests/jobtest.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 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 JOBTEST_H
+#define JOBTEST_H
+
+#include <tqstring.h>
+#include <tqobject.h>
+#include <tdeio/job.h>
+
+class JobTest : public TQObject
+{
+ Q_OBJECT
+
+public:
+ JobTest() {}
+ void setup();
+ void runAll();
+ void cleanup();
+
+ // Local tests (kio_file only)
+ void get();
+ void copyFileToSamePartition();
+ void copyDirectoryToSamePartition();
+ void copyDirectoryToExistingDirectory();
+ void copyFileToOtherPartition();
+ void copyDirectoryToOtherPartition();
+ void listRecursive();
+ void moveFileToSamePartition();
+ void moveDirectoryToSamePartition();
+ void moveFileToOtherPartition();
+ void moveSymlinkToOtherPartition();
+ void moveDirectoryToOtherPartition();
+ void moveFileNoPermissions();
+ void moveDirectoryNoPermissions();
+
+ // Remote tests
+ void copyFileToSystem();
+
+private slots:
+ void slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList& lst );
+ void slotGetResult( TDEIO::Job* );
+ void slotMimetype(TDEIO::Job*,const TQString&);
+
+private:
+ TQString homeTmpDir() const;
+ TQString otherTmpDir() const;
+ TQString realSystemPath() const;
+ KURL systemTmpDir() const;
+ enum { AlreadyExists = 1 };
+ void copyLocalFile( const TQString& src, const TQString& dest );
+ void copyLocalDirectory( const TQString& src, const TQString& dest, int flags = 0 );
+ void moveLocalFile( const TQString& src, const TQString& dest );
+ void moveLocalDirectory( const TQString& src, const TQString& dest );
+ void copyFileToSystem( bool resolve_local_urls );
+
+ int m_result;
+ TQByteArray m_data;
+ TQStringList m_names;
+ TQString m_mimetype;
+};
+
+#endif
diff --git a/tdeio/tests/kacltest.cpp b/tdeio/tests/kacltest.cpp
new file mode 100644
index 000000000..b55aedce8
--- /dev/null
+++ b/tdeio/tests/kacltest.cpp
@@ -0,0 +1,309 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Till Adam <adam@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 "kacltest.h"
+
+#include <config.h>
+
+#include <kacl.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+
+#include <tqfileinfo.h>
+#include <tqeventloop.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <tqdir.h>
+
+// The code comes partly from tdebase/tdeioslave/trash/testtrash.cpp
+
+static bool check(const TQString& txt, TQString a, TQString b)
+{
+ if (a.isEmpty())
+ a = TQString::null;
+ if (b.isEmpty())
+ b = TQString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+template<typename T>
+static bool check(const TQString& txt, T a, T b)
+{
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
+ exit(1);
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ TDEApplication::disableAutoDcopRegistration();
+ TDECmdLineArgs::init(argc,argv,"kacltest", 0, 0, 0, 0);
+ TDEApplication app;
+
+ KACLTest test;
+ test.setup();
+ test.runAll();
+ test.cleanup();
+ kdDebug() << "All tests OK." << endl;
+ return 0; // success. The exit(1) in check() is what happens in case of failure.
+}
+
+#ifdef Q_OS_FREEBSD
+static const TQString s_group1 = TQString::fromLatin1("staff");
+static const TQString s_group2 = TQString::fromLatin1("guest");
+#else
+static const TQString s_group1 = TQString::fromLatin1("audio");
+static const TQString s_group2 = TQString::fromLatin1("users");
+#endif
+
+static const TQString s_testACL = TQString::fromLatin1( "user::rw-\nuser:bin:rwx\ngroup::rw-\nmask::rwx\nother::r--\n" );
+static const TQString s_testACL2 = TQString::fromLatin1( "user::rwx\nuser:bin:rwx\ngroup::rw-\n") +
+ TQString::fromLatin1( "group:" ) + s_group1 + TQString::fromLatin1( ":--x\n" ) +
+ TQString::fromLatin1( "group:" ) + s_group2 + TQString::fromLatin1( ":r--\n" ) +
+ TQString::fromLatin1( "mask::r-x\nother::r--\n" );
+static const TQString s_testACLEffective = TQString::fromLatin1( "user::rwx\nuser:bin:rwx #effective:r-x\ngroup::rw- #effective:r--\n" ) +
+ TQString::fromLatin1( "group:" ) + s_group1 + TQString::fromLatin1( ":--x\n" ) +
+ TQString::fromLatin1( "group:" ) + s_group2 + TQString::fromLatin1( ":r--\n" ) +
+ TQString::fromLatin1( "mask::r-x\nother::r--\n" );
+
+KACLTest::KACLTest()
+:m_acl( s_testACL )
+{
+}
+
+void KACLTest::setup()
+{
+}
+
+void KACLTest::runAll()
+{
+ testAsString();
+ testGetOwnerPermissions();
+ testGetOwningGroupPermissions();
+ testGetOthersPermissions();
+
+ testGetMaskPermissions();
+ testGetAllUserPermissions();
+
+ testIsExtended();
+
+ // from here on we operate with the second test string
+ testSetACL();
+ testGetAllGroupsPermissions();
+
+ testOperators();
+ testSettingBasic();
+ testSettingExtended();
+ testSettingErrorHandling();
+
+ testNewMask();
+}
+
+void KACLTest::cleanup()
+{
+}
+
+void KACLTest::testAsString()
+{
+ check( "asString: ", m_acl.asString(), s_testACL );
+}
+
+void KACLTest::testSetACL()
+{
+ m_acl.setACL( s_testACL2 );
+ check( "setACL: ", m_acl.asString().simplifyWhiteSpace().remove(" "), s_testACLEffective.simplifyWhiteSpace().remove(" ") );
+}
+
+void KACLTest::testGetOwnerPermissions()
+{
+ check( "Owner permissions: ", TQString::number( m_acl.ownerPermissions() ), "6" );
+}
+
+void KACLTest::testGetOwningGroupPermissions()
+{
+ check( "Owning group permissions: ", TQString::number( m_acl.owningGroupPermissions() ), "6" );
+}
+
+void KACLTest::testGetOthersPermissions()
+{
+ check( "Others permissions: ", TQString::number( m_acl.othersPermissions() ), "4" );
+}
+
+void KACLTest::testGetMaskPermissions()
+{
+ bool exists = false;
+ unsigned short mask = m_acl.maskPermissions( exists );
+ check( "Mask permissions: ", TQString::number( mask ), "7" );
+ check( "Mask permissions: ", exists, true );
+}
+
+void KACLTest::testGetAllUserPermissions()
+{
+ ACLUserPermissionsList list = m_acl.allUserPermissions();
+ ACLUserPermissionsConstIterator it = list.begin();
+ TQString name;
+ unsigned short permissions;
+ int count = 0;
+ while ( it != list.end() ) {
+ name = ( *it ).first;
+ permissions = ( *it ).second;
+ ++it;
+ ++count;
+ }
+ check( "All users count: ", TQString::number( count ), "1" );
+ check( "All users name: ", name, "bin" );
+ check( "All users permissions: ", TQString::number( permissions ), "7" );
+}
+
+void KACLTest::testGetAllGroupsPermissions()
+{
+ ACLGroupPermissionsList list = m_acl.allGroupPermissions();
+ ACLGroupPermissionsConstIterator it = list.begin();
+ TQString name;
+ unsigned short permissions;
+ int count = 0;
+ while ( it != list.end() ) {
+ name = ( *it ).first;
+ permissions = ( *it ).second;
+ // setACL sorts them alphabetically ...
+ if ( count == 0 ) {
+ check( "All groups name: ", name, s_group1 );
+ check( "All groups permissions: ", TQString::number( permissions ), "1" );
+ } else if ( count == 1 ) {
+ check( "All groups name: ", name, s_group2 );
+ check( "All groups permissions: ", TQString::number( permissions ), "4" );
+ }
+ ++it;
+ ++count;
+ }
+ check( "All users count: ", TQString::number( count ), "2" );
+}
+
+void KACLTest::testIsExtended()
+{
+ KACL dukeOfMonmoth( s_testACL );
+ check( "isExtended on an extended one: ", dukeOfMonmoth.isExtended(), true );
+ KACL earlOfUpnor( "user::r--\ngroup::r--\nother::r--\n" );
+ check( "isExtended on a not extended one: ", earlOfUpnor.isExtended(), false );
+}
+
+void KACLTest::testOperators()
+{
+ KACL dukeOfMonmoth( s_testACL );
+ KACL JamesScott( s_testACL );
+ KACL earlOfUpnor( s_testACL2 );
+ check( "operator== on different ones: ", dukeOfMonmoth == earlOfUpnor, false );
+ check( "operator== on identical ones: ", dukeOfMonmoth == JamesScott, true );
+ check( "operator!= on diffenrent ones: ", dukeOfMonmoth != earlOfUpnor, true );
+ check( "operator!=: on identical ones: ", dukeOfMonmoth != JamesScott, false );
+}
+
+void KACLTest::testSettingBasic()
+{
+ KACL CharlesII( s_testACL );
+ CharlesII.setOwnerPermissions( 7 ); // clearly
+ CharlesII.setOwningGroupPermissions( 0 );
+ CharlesII.setOthersPermissions( 0 );
+ check( "setOwnerPermissions: ", TQString::number( CharlesII.ownerPermissions() ),"7" );
+ check( "setOwningGroupPermissions: ", TQString::number( CharlesII.owningGroupPermissions() ),"0" );
+ check( "setOthersPermissions: ", TQString::number( CharlesII.othersPermissions() ),"0" );
+}
+
+void KACLTest::testSettingExtended()
+{
+ KACL CharlesII( s_testACL );
+ CharlesII.setMaskPermissions( 7 ); // clearly
+ bool dummy = false;
+ check( "setMaskPermissions: ", TQString::number( CharlesII.maskPermissions( dummy ) ),"7" );
+
+ const TQString expected( "user::rw-\nuser:root:rwx\nuser:bin:r--\ngroup::rw-\nmask::rwx\nother::r--\n" );
+
+ ACLUserPermissionsList users;
+ ACLUserPermissions user = qMakePair( TQString( "root" ), ( unsigned short )7 );
+ users.append( user );
+ user = qMakePair( TQString( "bin" ), ( unsigned short )4 );
+ users.append( user );
+ CharlesII.setAllUserPermissions( users );
+ check( "setAllUserPermissions: ", CharlesII.asString(), expected );
+
+ CharlesII.setACL( s_testACL ); // reset
+ // it already has an entry for bin, let's change it
+ CharlesII.setNamedUserPermissions( TQString("bin"), 4 );
+ CharlesII.setNamedUserPermissions( TQString( "root" ), 7 );
+ check( "setNamedUserPermissions: ", CharlesII.asString(), expected );
+
+ // groups, all and named
+
+ const TQString expected2 = TQString::fromLatin1( "user::rw-\nuser:bin:rwx\ngroup::rw-\ngroup:" ) + s_group1 +
+ TQString::fromLatin1( ":-wx\ngroup:" ) + s_group2 + TQString::fromLatin1(":r--\nmask::rwx\nother::r--\n" );
+ CharlesII.setACL( s_testACL ); // reset
+ ACLGroupPermissionsList groups;
+ ACLGroupPermissions group = qMakePair( s_group1, ( unsigned short )3 );
+ groups.append( group );
+ group = qMakePair( s_group2, ( unsigned short )4 );
+ groups.append( group );
+ CharlesII.setAllGroupPermissions( groups );
+ check( "setAllGroupPermissions: ", CharlesII.asString(), expected2 );
+
+ CharlesII.setACL( s_testACL ); // reset
+ CharlesII.setNamedGroupPermissions( s_group1, 3 );
+ CharlesII.setNamedGroupPermissions( s_group2, 4 );
+ check( "setNamedGroupPermissions: ", CharlesII.asString(), expected2 );
+}
+
+void KACLTest::testSettingErrorHandling()
+{
+ KACL foo( s_testACL );
+ bool v = foo.setNamedGroupPermissions( s_group1, 7 ); // existing group
+ check( "Existing group: ", v, true );
+ v = foo.setNamedGroupPermissions( "jongel", 7 ); // non-existing group
+ check( "Non-existing group: ", v, false );
+
+ v = foo.setNamedUserPermissions( "bin", 7 ); // existing user
+ check( "Existing user: ", v, true );
+ v = foo.setNamedUserPermissions( "jongel", 7 ); // non-existing user
+ check( "Non-existing user: ", v, false );
+}
+
+void KACLTest::testNewMask()
+{
+ KACL CharlesII( "user::rw-\ngroup::rw-\nother::rw\n" );
+ bool dummy = false;
+ CharlesII.maskPermissions( dummy );
+ check( "mask exists: ", dummy, false );
+
+ CharlesII.setMaskPermissions( 6 );
+ check( "new mask set: ", TQString::number( CharlesII.maskPermissions( dummy ) ), "6" );
+ check( "mask exists now: ", dummy, true );
+}
diff --git a/tdeio/tests/kacltest.h b/tdeio/tests/kacltest.h
new file mode 100644
index 000000000..1a85e4109
--- /dev/null
+++ b/tdeio/tests/kacltest.h
@@ -0,0 +1,53 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Till Adam <adam@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 KACLTEST_H
+#define KACLTEST_H
+
+#include <tqobject.h>
+#include <kacl.h>
+
+class KACLTest
+{
+public:
+ KACLTest();
+ void setup();
+ void runAll();
+ void cleanup();
+
+ void testAsString();
+ void testSetACL();
+ void testGetOwnerPermissions();
+ void testGetOwningGroupPermissions();
+ void testGetOthersPermissions();
+ void testGetMaskPermissions();
+ void testGetAllUserPermissions();
+ void testGetAllGroupsPermissions();
+ void testIsExtended();
+ void testOperators();
+ void testSettingBasic();
+ void testSettingExtended();
+ void testSettingErrorHandling();
+ void testNewMask();
+
+private:
+ KACL m_acl;
+};
+
+#endif
diff --git a/tdeio/tests/kdcopcheck.cpp b/tdeio/tests/kdcopcheck.cpp
new file mode 100644
index 000000000..79f050f51
--- /dev/null
+++ b/tdeio/tests/kdcopcheck.cpp
@@ -0,0 +1,132 @@
+#include <kuserprofile.h>
+#include <ktrader.h>
+#include <kservice.h>
+#include <kmimetype.h>
+#include <assert.h>
+#include <kstandarddirs.h>
+#include <kservicegroup.h>
+#include <kimageio.h>
+#include <kprotocolinfo.h>
+#include <kprocess.h>
+#include <tqtimer.h>
+
+#include "kdcopcheck.h"
+#include <dcopclient.h>
+
+#include <kapplication.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void debug(TQString txt)
+{
+ fprintf(stderr, "%s\n", txt.ascii());
+}
+
+void debug(const char *txt)
+{
+ fprintf(stderr, "%s\n", txt);
+}
+void debug(const char *format, const char *txt)
+{
+ fprintf(stderr, format, txt);
+ fprintf(stderr, "\n");
+}
+
+TestService::TestService(const TQString &exec)
+{
+ m_exec = exec;
+ proc << exec;
+
+ proc.start();
+
+ connect(kapp->dcopClient(), TQT_SIGNAL( applicationRegistered(const TQCString&)),
+ this, TQT_SLOT(newApp(const TQCString&)));
+ connect(kapp->dcopClient(), TQT_SIGNAL( applicationRemoved(const TQCString&)),
+ this, TQT_SLOT(endApp(const TQCString&)));
+ connect(&proc, TQT_SIGNAL(processExited(TDEProcess *)),
+ this, TQT_SLOT(appExit()));
+
+ TQTimer::singleShot(20*1000, this, TQT_SLOT(stop()));
+ result = KService::DCOP_None;
+}
+
+void TestService::newApp(const TQCString &appId)
+{
+ TQString id = appId;
+ if (id == m_exec)
+ {
+ result = KService::DCOP_Unique;
+ stop();
+ }
+ else if (id.startsWith(m_exec))
+ {
+ result = KService::DCOP_Multi;
+ stop();
+ }
+ tqWarning("Register %s", appId.data());
+}
+
+void TestService::endApp(const TQCString &appId)
+{
+ tqWarning("Unegister %s", appId.data());
+}
+
+void TestService::appExit()
+{
+ tqWarning("Exit");
+}
+
+void TestService::stop()
+{
+ kapp->exit_loop();
+}
+
+int TestService::exec()
+{
+ kapp->enter_loop();
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ putenv("IGNORE_SYCOCA_VERSION=true");
+ TDEApplication k(argc,argv,"whatever",false/*noGUI*/); // KMessageBox needs KApp for makeStdCaption
+
+ k.dcopClient()->setNotifications(true);
+
+ KService::List list = KService::allServices();
+
+ tqWarning("I found %d services.", list.count());
+ int i = 0;
+ for(KService::List::ConstIterator it = list.begin(); it != list.end(); ++it)
+ {
+ if (((*it)->DCOPServiceType() == KService::DCOP_None) &&
+ !(*it)->desktopEntryPath().startsWith("SuSE") &&
+ (*it)->hasServiceType("Application"))
+ {
+ if ((*it)->exec().startsWith((*it)->desktopEntryName()))
+ {
+ i++;
+
+ TestService *test = new TestService((*it)->desktopEntryName());
+ int n = test->exec();
+ delete test;
+
+ TQString result;
+ if (n == KService::DCOP_None)
+ result = "None";
+ else if (n == KService::DCOP_Unique)
+ result = "Unique";
+ else if (n == KService::DCOP_Multi)
+ result = "Multi";
+
+ tqWarning("%s %s", (*it)->desktopEntryPath().latin1(),
+ result.latin1());
+ }
+ }
+ }
+ tqWarning("%d left after filtering.", i);
+}
+
+#include "kdcopcheck.moc"
diff --git a/tdeio/tests/kdcopcheck.h b/tdeio/tests/kdcopcheck.h
new file mode 100644
index 000000000..593dbba1e
--- /dev/null
+++ b/tdeio/tests/kdcopcheck.h
@@ -0,0 +1,28 @@
+#ifndef _BLA_H_
+#define _BLA_H_
+
+#include <kprocess.h>
+#include <tqstring.h>
+#include <tqobject.h>
+
+class TestService : public TQObject
+{
+ Q_OBJECT
+public:
+ TestService(const TQString &exec);
+
+ int exec();
+
+public slots:
+ void newApp(const TQCString &appId);
+ void endApp(const TQCString &appId);
+ void appExit();
+ void stop();
+
+protected:
+ int result;
+ TQString m_exec;
+ TDEProcess proc;
+};
+
+#endif
diff --git a/tdeio/tests/kdefaultprogresstest.cpp b/tdeio/tests/kdefaultprogresstest.cpp
new file mode 100644
index 000000000..7e77611ed
--- /dev/null
+++ b/tdeio/tests/kdefaultprogresstest.cpp
@@ -0,0 +1,39 @@
+#include <kapplication.h>
+#include <tdeio/defaultprogress.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+using namespace TDEIO;
+
+int main(int argc, char **argv)
+{
+ TDEApplication app(argc, argv, "kdefaultprogresstest");
+
+ DefaultProgress* dlg = new DefaultProgress();
+ KURL src("http://this.host.doesn't.exist/this/dir/neither/andthisfileneither");
+ KURL dest("file:/tmp/dest");
+ dlg->slotCopying( 0L, src, dest );
+ dlg->slotTotalSize( 0L, 12000 );
+ dlg->slotTotalFiles( 0L, 12 );
+ dlg->slotTotalDirs( 0L, 1 );
+
+ dlg->slotSpeed( 0L, 55 );
+ dlg->slotInfoMessage( 0L, TQString::fromLatin1( "Starting..." ) );
+
+ int files = 0;
+ for ( int size = 0 ; size < 12000 ; size += 1 )
+ {
+ dlg->slotProcessedSize( 0L, size );
+ dlg->slotPercent( 0L, 100 * size / 12000 );
+ if ( size % 1000 == 0 )
+ {
+ dlg->slotProcessedFiles( 0L, ++files );
+ }
+ kapp->processEvents();
+ }
+ dlg->slotInfoMessage( 0L, TQString::fromLatin1( "Done." ) );
+
+ delete dlg;
+ return 0;
+}
+
diff --git a/tdeio/tests/kdirlistertest.cpp b/tdeio/tests/kdirlistertest.cpp
new file mode 100644
index 000000000..000fb200c
--- /dev/null
+++ b/tdeio/tests/kdirlistertest.cpp
@@ -0,0 +1,162 @@
+/* This file is part of the KDE desktop environment
+
+ Copyright (C) 2001, 2002 Michael Brade <brade@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 <tqlayout.h>
+#include <tqpushbutton.h>
+
+#include <kapplication.h>
+#include <kdirlister.h>
+#include <kdebug.h>
+
+#include "kdirlistertest.h"
+
+#include <cstdlib>
+
+
+KDirListerTest::KDirListerTest( TQWidget *parent, const char *name )
+ : TQWidget( parent, name )
+{
+ lister = new KDirLister( false /* true */ );
+ debug = new PrintSignals;
+
+ TQVBoxLayout* layout = new TQVBoxLayout( this );
+
+ TQPushButton* startH = new TQPushButton( "Start listing $HOME", this );
+ TQPushButton* startR= new TQPushButton( "Start listing /", this );
+ TQPushButton* test = new TQPushButton( "Many", this );
+ TQPushButton* startT = new TQPushButton( "tarfile", this );
+
+ layout->addWidget( startH );
+ layout->addWidget( startR );
+ layout->addWidget( startT );
+ layout->addWidget( test );
+ resize( layout->sizeHint() );
+
+ connect( startR, TQT_SIGNAL( clicked() ), TQT_SLOT( startRoot() ) );
+ connect( startH, TQT_SIGNAL( clicked() ), TQT_SLOT( startHome() ) );
+ connect( startT, TQT_SIGNAL( clicked() ), TQT_SLOT( startTar() ) );
+ connect( test, TQT_SIGNAL( clicked() ), TQT_SLOT( test() ) );
+
+ connect( lister, TQT_SIGNAL( started( const KURL & ) ),
+ debug, TQT_SLOT( started( const KURL & ) ) );
+ connect( lister, TQT_SIGNAL( completed() ),
+ debug, TQT_SLOT( completed() ) );
+ connect( lister, TQT_SIGNAL( completed( const KURL & ) ),
+ debug, TQT_SLOT( completed( const KURL & ) ) );
+ connect( lister, TQT_SIGNAL( canceled() ),
+ debug, TQT_SLOT( canceled() ) );
+ connect( lister, TQT_SIGNAL( canceled( const KURL & ) ),
+ debug, TQT_SLOT( canceled( const KURL & ) ) );
+ connect( lister, TQT_SIGNAL( redirection( const KURL & ) ),
+ debug, TQT_SLOT( redirection( const KURL & ) ) );
+ connect( lister, TQT_SIGNAL( redirection( const KURL &, const KURL & ) ),
+ debug, TQT_SLOT( redirection( const KURL &, const KURL & ) ) );
+ connect( lister, TQT_SIGNAL( clear() ),
+ debug, TQT_SLOT( clear() ) );
+ connect( lister, TQT_SIGNAL( newItems( const KFileItemList & ) ),
+ debug, TQT_SLOT( newItems( const KFileItemList & ) ) );
+ connect( lister, TQT_SIGNAL( itemsFilteredByMime( const KFileItemList & ) ),
+ debug, TQT_SLOT( itemsFilteredByMime( const KFileItemList & ) ) );
+ connect( lister, TQT_SIGNAL( deleteItem( KFileItem * ) ),
+ debug, TQT_SLOT( deleteItem( KFileItem * ) ) );
+ connect( lister, TQT_SIGNAL( refreshItems( const KFileItemList & ) ),
+ debug, TQT_SLOT( refreshItems( const KFileItemList & ) ) );
+ connect( lister, TQT_SIGNAL( infoMessage( const TQString& ) ),
+ debug, TQT_SLOT( infoMessage( const TQString& ) ) );
+ connect( lister, TQT_SIGNAL( percent( int ) ),
+ debug, TQT_SLOT( percent( int ) ) );
+ connect( lister, TQT_SIGNAL( totalSize( TDEIO::filesize_t ) ),
+ debug, TQT_SLOT( totalSize( TDEIO::filesize_t ) ) );
+ connect( lister, TQT_SIGNAL( processedSize( TDEIO::filesize_t ) ),
+ debug, TQT_SLOT( processedSize( TDEIO::filesize_t ) ) );
+ connect( lister, TQT_SIGNAL( speed( int ) ),
+ debug, TQT_SLOT( speed( int ) ) );
+
+ connect( lister, TQT_SIGNAL( completed() ),
+ this, TQT_SLOT( completed() ) );
+}
+
+KDirListerTest::~KDirListerTest()
+{
+ delete lister;
+}
+
+void KDirListerTest::startHome()
+{
+ KURL home( getenv( "HOME" ) );
+ lister->openURL( home, false, false );
+// lister->stop();
+}
+
+void KDirListerTest::startRoot()
+{
+ KURL root( "file:/" );
+ lister->openURL( root, true, true );
+// lister->stop( root );
+}
+
+void KDirListerTest::startTar()
+{
+ KURL root( "file:/home/jowenn/aclocal_1.tgz" );
+ lister->openURL( root, true, true );
+// lister->stop( root );
+}
+
+void KDirListerTest::test()
+{
+ KURL home( getenv( "HOME" ) );
+ KURL root( "file:/" );
+/* lister->openURL( home, true, false );
+ lister->openURL( root, true, true );
+ lister->openURL( KURL("file:/etc"), true, true );
+ lister->openURL( root, true, true );
+ lister->openURL( KURL("file:/dev"), true, true );
+ lister->openURL( KURL("file:/tmp"), true, true );
+ lister->openURL( KURL("file:/usr/include"), true, true );
+ lister->updateDirectory( KURL("file:/usr/include") );
+ lister->updateDirectory( KURL("file:/usr/include") );
+ lister->openURL( KURL("file:/usr/"), true, true );
+*/
+ lister->openURL( KURL("file:/dev"), true, true );
+}
+
+void KDirListerTest::completed()
+{
+ if ( lister->url().path() == "/")
+ {
+ KFileItem* item = lister->findByURL( "/tmp" );
+ if ( item )
+ kdDebug() << "Found /tmp: " << item << endl;
+ else
+ kdWarning() << "/tmp not found! Bug in findByURL?" << endl;
+ }
+}
+
+int main ( int argc, char *argv[] )
+{
+ TDEApplication app( argc, argv, "kdirlistertest" );
+
+ KDirListerTest *test = new KDirListerTest( 0 );
+ test->show();
+ app.setMainWidget( test );
+ return app.exec();
+}
+
+#include "kdirlistertest.moc"
diff --git a/tdeio/tests/kdirlistertest.h b/tdeio/tests/kdirlistertest.h
new file mode 100644
index 000000000..484121eef
--- /dev/null
+++ b/tdeio/tests/kdirlistertest.h
@@ -0,0 +1,120 @@
+/* This file is part of the KDE desktop environment
+
+ Copyright (C) 2001, 2002 Michael Brade <brade@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 _KDIRLISTERTEST_H_
+#define _KDIRLISTERTEST_H_
+
+#include <tqwidget.h>
+#include <tqstring.h>
+
+#include <kurl.h>
+#include <tdefileitem.h>
+
+#include <iostream>
+
+using namespace std;
+
+class PrintSignals : public TQObject
+{
+ Q_OBJECT
+public:
+ PrintSignals() : TQObject() { }
+
+public slots:
+ void started( const KURL &url )
+ {
+ cout << "*** started( " << url.url().local8Bit() << " )" << endl;
+ }
+ void canceled() { cout << "canceled()" << endl; }
+ void canceled( const KURL& url )
+ {
+ cout << "*** canceled( " << url.prettyURL().local8Bit() << " )" << endl;
+ }
+ void completed() { cout << "*** completed()" << endl; }
+ void completed( const KURL& url )
+ {
+ cout << "*** completed( " << url.prettyURL().local8Bit() << " )" << endl;
+ }
+ void redirection( const KURL& url )
+ {
+ cout << "*** redirection( " << url.prettyURL().local8Bit() << " )" << endl;
+ }
+ void redirection( const KURL& src, const KURL& dest )
+ {
+ cout << "*** redirection( " << src.prettyURL().local8Bit() << ", "
+ << dest.prettyURL().local8Bit() << " )" << endl;
+ }
+ void clear() { cout << "*** clear()" << endl; }
+ void newItems( const KFileItemList& items )
+ {
+ cout << "*** newItems: " << endl;
+ for ( KFileItemListIterator it( items ) ; it.current() ; ++it )
+ cout << it.current() << " " << it.current()->name().local8Bit() << endl;
+ }
+ void deleteItem( KFileItem* item )
+ {
+ cout << "*** deleteItem: " << item->url().prettyURL().local8Bit() << endl;
+ }
+ void itemsFilteredByMime( const KFileItemList& )
+ {
+ cout << "*** itemsFilteredByMime: " << endl;
+ // TODO
+ }
+ void refreshItems( const KFileItemList& )
+ {
+ cout << "*** refreshItems: " << endl;
+ // TODO
+ }
+ void infoMessage( const TQString& msg )
+ { cout << "*** infoMessage: " << msg.local8Bit() << endl; }
+
+ void percent( int percent )
+ { cout << "*** percent: " << percent << endl; }
+
+ void totalSize( TDEIO::filesize_t size )
+ { cout << "*** totalSize: " << (long)size << endl; }
+
+ void processedSize( TDEIO::filesize_t size )
+ { cout << "*** processedSize: " << (long)size << endl; }
+
+ void speed( int bytes_per_second )
+ { cout << "*** speed: " << bytes_per_second << endl; }
+};
+
+class KDirListerTest : public TQWidget
+{
+ Q_OBJECT
+public:
+ KDirListerTest( TQWidget *parent=0, const char *name=0 );
+ ~KDirListerTest();
+
+public slots:
+ void startRoot();
+ void startHome();
+ void startTar();
+ void test();
+ void completed();
+
+private:
+ KDirLister *lister;
+ PrintSignals *debug;
+};
+
+#endif
diff --git a/tdeio/tests/kdirwatchtest.cpp b/tdeio/tests/kdirwatchtest.cpp
new file mode 100644
index 000000000..c741b20f0
--- /dev/null
+++ b/tdeio/tests/kdirwatchtest.cpp
@@ -0,0 +1,82 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ Copyright 1998 Sven Radej <sven@lisa.exp.univie.ac.at>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#include <tqfile.h>
+
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+
+#include "kdirwatchtest.h"
+
+static const KCmdLineOptions options[] =
+{
+ {"+[directory ...]", "Directory(ies) to watch", 0},
+ KCmdLineLastOption
+};
+
+
+int main (int argc, char **argv)
+{
+ TDECmdLineArgs::init(argc, argv, "KDirWatchTest",
+ "Test for KDirWatch", "1.0");
+ TDECmdLineArgs::addCmdLineOptions( options );
+ TDEApplication::addCmdLineOptions();
+
+ TDEApplication a;
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ myTest testObject;
+
+ KDirWatch *dirwatch1 = KDirWatch::self();
+ KDirWatch *dirwatch2 = new KDirWatch;
+
+ testObject.connect(dirwatch1, TQT_SIGNAL( dirty( const TQString &)), TQT_SLOT( dirty( const TQString &)) );
+ testObject.connect(dirwatch1, TQT_SIGNAL( created( const TQString &)), TQT_SLOT( created( const TQString &)) );
+ testObject.connect(dirwatch1, TQT_SIGNAL( deleted( const TQString &)), TQT_SLOT( deleted( const TQString &)) );
+
+ if (args->count() >0) {
+ for(int i = 0; i < args->count(); i++) {
+ kdDebug() << "Watching: " << args->arg(i) << endl;
+ dirwatch2->addDir( TQFile::decodeName( args->arg(i)));
+ }
+ }
+
+ TQString home = TQString(getenv ("HOME")) + "/";
+ TQString desk = home + "Desktop/";
+ kdDebug() << "Watching: " << home << endl;
+ dirwatch1->addDir(home);
+ kdDebug() << "Watching file: " << home << "foo " << endl;
+ dirwatch1->addFile(home+"foo");
+ kdDebug() << "Watching: " << desk << endl;
+ dirwatch1->addDir(desk);
+ TQString test = home + "test/";
+ kdDebug() << "Watching: (but skipped) " << test << endl;
+ dirwatch1->addDir(test);
+
+ dirwatch1->startScan();
+ dirwatch2->startScan();
+
+ if(!dirwatch1->stopDirScan(home))
+ kdDebug() << "stopDirscan: " << home << " error!" << endl;
+ if(!dirwatch1->restartDirScan(home))
+ kdDebug() << "restartDirScan: " << home << "error!" << endl;
+ if (!dirwatch1->stopDirScan(test))
+ kdDebug() << "stopDirScan: error" << endl;
+
+ KDirWatch::statistics();
+
+ delete dirwatch2;
+
+ KDirWatch::statistics();
+
+ return a.exec();
+}
+#include "kdirwatchtest.moc"
diff --git a/tdeio/tests/kdirwatchtest.h b/tdeio/tests/kdirwatchtest.h
new file mode 100644
index 000000000..24dc94a91
--- /dev/null
+++ b/tdeio/tests/kdirwatchtest.h
@@ -0,0 +1,33 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ Copyright 1998 Sven Radej <sven@lisa.exp.univie.ac.at>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#ifndef _KDIRWATCHTEST_H_
+#define _KDIRWATCHTEST_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <tqobject.h>
+
+#include "kdirwatch.h"
+#include "kapplication.h"
+
+class myTest : public TQObject
+{
+ Q_OBJECT
+public:
+ myTest() { };
+public slots:
+ void dirty(const TQString &a) { printf("Dirty: %s\n", a.ascii()); };
+ void created(const TQString& f) { printf("Created: %s\n", f.ascii()); }
+ void deleted(const TQString& f) { printf("Deleted: %s\n", f.ascii()); }
+};
+
+#endif
diff --git a/tdeio/tests/kdirwatchunittest.cpp b/tdeio/tests/kdirwatchunittest.cpp
new file mode 100644
index 000000000..3d7505a3f
--- /dev/null
+++ b/tdeio/tests/kdirwatchunittest.cpp
@@ -0,0 +1,180 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ (c) 2006 Dirk Mueller <mueller@kde.org>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#include <unistd.h>
+
+#include <tqfile.h>
+#include <tqdir.h>
+
+#include <kdebug.h>
+
+#include "kdirwatchunittest.h"
+
+void KDirWatchTest::VERIFY_NOTHING()
+{
+ unsigned m_s[3];
+ for(int i = 0; i < 3; ++i)
+ m_s[i] = m_signals[i];
+
+ for (int i = 0; i < 20; ++i) {
+ usleep(100*1000);
+ tqApp->processEvents();
+ }
+
+ bool nothing_failed = true;
+ for (int i = 0; i < 3; ++i)
+ if (m_s[i] != m_signals[i])
+ nothing_failed = false;
+
+ KDirWatch::statistics();
+
+ VERIFY (nothing_failed);
+}
+
+void KDirWatchTest::VERIFY_DIRTY(const TQString& alert)
+{
+ unsigned m_s[3];
+ for(int i = 0; i < 3; ++i)
+ m_s[i] = m_signals[i];
+
+ for (int i = 0; i < 20; ++i) {
+ usleep(100*1000);
+ tqApp->processEvents();
+ }
+
+ VERIFY (m_s[sigCreated] == m_signals[sigCreated] &&
+ m_s[sigDeleted] == m_signals[sigDeleted] &&
+ m_s[sigDirty] + 1 == m_signals[sigDirty] &&
+ m_lastSignal == alert);
+}
+
+void KDirWatchTest::VERIFY_CREATED(const TQString& alert)
+{
+ unsigned m_s[3];
+ for(int i = 0; i < 3; ++i)
+ m_s[i] = m_signals[i];
+
+ for (int i = 0; i < 20; ++i) {
+ usleep(100*1000);
+ tqApp->processEvents();
+ }
+
+ VERIFY (m_s[sigDirty] == m_signals[sigDirty] &&
+ m_s[sigDeleted] == m_signals[sigDeleted] &&
+ m_s[sigCreated] + 1 == m_signals[sigCreated] &&
+ m_lastSignal == alert);
+}
+
+void KDirWatchTest::VERIFY_DELETED(const TQString& alert)
+{
+ unsigned m_s[3];
+ for(int i = 0; i < 3; ++i)
+ m_s[i] = m_signals[i];
+
+ for (int i = 0; i < 20; ++i) {
+ usleep(100*1000);
+ tqApp->processEvents();
+ }
+
+ VERIFY (m_s[sigDirty] == m_signals[sigDirty] &&
+ m_s[sigCreated] == m_signals[sigCreated] &&
+ m_s[sigDeleted] + 1 == m_signals[sigDeleted] &&
+ m_lastSignal == alert);
+}
+
+void KDirWatchTest::remove_file (const TQString& file)
+{
+ ::unlink (TQFile::encodeName(file));
+}
+
+void KDirWatchTest::touch_file (const TQString& file)
+{
+ TQFile f(file);
+ f.open(IO_WriteOnly);
+}
+
+void KDirWatchTest::rename_file(const TQString& from, const TQString& to)
+{
+ ::rename(TQFile::encodeName(from), TQFile::encodeName(to));
+}
+
+KUNITTEST_MODULE ( tdeunittest_kdirwatch, "KDirWatchTest" )
+KUNITTEST_MODULE_REGISTER_TESTER (KDirWatchTest)
+
+#define SLEEP() TQApplication::processEvents();
+
+void KDirWatchTest::allTests()
+{
+ for(int loop=0; loop<3; ++loop) {
+ d = new KDirWatch;
+ VERIFY (d != 0);
+
+ TQDir* dir = new TQDir(m_workingDir);
+ VERIFY (dir != 0);
+
+ connect(d, TQT_SIGNAL (dirty( const TQString &)), TQT_SLOT( slotDirty( const TQString &)) );
+ connect(d, TQT_SIGNAL (created( const TQString &)), TQT_SLOT( slotCreated( const TQString &)) );
+ connect(d, TQT_SIGNAL (deleted( const TQString &)), TQT_SLOT( slotDeleted( const TQString &)) );
+
+ VERIFY (dir->mkdir (m_workingDir));
+
+ d->addDir (m_workingDir);
+ VERIFY_NOTHING();
+ dir->mkdir ("does");
+ VERIFY_DIRTY (m_workingDir);
+ touch_file (m_workingDir + "/file");
+ VERIFY_DIRTY (m_workingDir);
+ VERIFY_NOTHING ();
+ remove_file (m_workingDir + "/file");
+ d->addDir (m_workingDir + "/does/not/exist");
+ d->removeDir (m_workingDir);
+ VERIFY_NOTHING();
+
+ dir->mkdir ("does/not");
+ VERIFY_NOTHING();
+ dir->mkdir ("does/not/exist");
+ VERIFY_CREATED (m_workingDir + "/does/not/exist");
+
+ dir->rmdir ("does/not/exist");
+ VERIFY_DELETED (m_workingDir + "/does/not/exist");
+ dir->rmdir ("does/not");
+ VERIFY_NOTHING();
+ dir->rmdir ("does");
+ VERIFY_NOTHING();
+
+ d->addFile(m_workingDir + "/a");
+ touch_file(m_workingDir + "/a");
+ VERIFY_CREATED (m_workingDir + "/a");
+
+ rename_file (m_workingDir + "/a", m_workingDir + "/b");
+ VERIFY_DELETED (m_workingDir + "/a");
+ VERIFY_NOTHING();
+
+ touch_file (m_workingDir + "/a");
+ VERIFY_CREATED (m_workingDir + "/a");
+ VERIFY_NOTHING();
+
+ touch_file (m_workingDir + "/a");
+ VERIFY_DIRTY (m_workingDir + "/a");
+
+ remove_file (m_workingDir + "/b");
+ VERIFY_NOTHING();
+
+ d->removeFile(m_workingDir + "/a");
+
+ remove_file(m_workingDir + "/a");
+
+ VERIFY (dir->rmdir (m_workingDir));
+ delete d;
+ }
+}
+
+#include "kdirwatchunittest.moc"
diff --git a/tdeio/tests/kdirwatchunittest.h b/tdeio/tests/kdirwatchunittest.h
new file mode 100644
index 000000000..42222a787
--- /dev/null
+++ b/tdeio/tests/kdirwatchunittest.h
@@ -0,0 +1,66 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ Copyright 1998 Sven Radej <sven@lisa.exp.univie.ac.at>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#ifndef _KDIRWATCHTEST_H_
+#define _KDIRWATCHTEST_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <tqobject.h>
+
+#include "kdirwatch.h"
+#include "kapplication.h"
+
+#include <tdeunittest/tester.h>
+#include <tdeunittest/module.h>
+
+class KDirWatchTest : public KUnitTest::Tester
+{
+ Q_OBJECT
+
+public:
+ enum { sigDirty, sigCreated, sigDeleted };
+
+ KDirWatchTest()
+ {
+ m_signals[sigDirty] = m_signals[sigCreated] = m_signals[sigDeleted] = 0;
+ m_workingDir = "/tmp/kdirwatchtest";
+ }
+
+ virtual void allTests();
+
+private slots:
+ void slotDirty (const TQString& s) { m_signals[sigDirty]++; m_lastSignal = s; }
+ void slotCreated (const TQString& s) { m_signals[sigCreated]++; m_lastSignal = s; }
+ void slotDeleted (const TQString& s) { m_signals[sigDeleted]++; m_lastSignal = s; }
+
+private:
+ unsigned m_signals[3];
+
+ /* verify nothing happens */
+ void VERIFY_NOTHING();
+ /* verify that dirty got emitted */
+ void VERIFY_DIRTY (const TQString&);
+ /* verify that created got emitted */
+ void VERIFY_CREATED (const TQString&);
+ /* verify that deleted got emitted */
+ void VERIFY_DELETED (const TQString&);
+
+ void touch_file (const TQString& file);
+ void remove_file (const TQString& file);
+ void rename_file (const TQString& from, const TQString& to);
+
+ TQString m_lastSignal;
+ TQString m_workingDir;
+ KDirWatch* d;
+};
+
+#endif
diff --git a/tdeio/tests/kfiltertest.cpp b/tdeio/tests/kfiltertest.cpp
new file mode 100644
index 000000000..1922e207e
--- /dev/null
+++ b/tdeio/tests/kfiltertest.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2002, 2003 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 <unistd.h>
+#include <limits.h>
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <kdebug.h>
+#include <kinstance.h>
+
+void test_block( const TQString & fileName )
+{
+ TQIODevice * dev = KFilterDev::deviceForFile( fileName );
+ if (!dev) { kdWarning() << "dev=0" << endl; return; }
+ if ( !dev->open( IO_ReadOnly ) ) { kdWarning() << "open failed " << endl; return; }
+
+ // This is what KGzipDev::readAll could do, if TQIODevice::readAll was virtual....
+
+ TQByteArray array(1024);
+ int n;
+ while ( ( n = dev->tqreadBlock( array.data(), array.size() ) ) )
+ {
+ kdDebug() << "readBlock returned " << n << endl << endl;
+ // TQCString s(array,n+1); // Terminate with 0 before printing
+ // printf("%s", s.data());
+
+ kdDebug() << "dev.at = " << dev->at() << endl;
+ //kdDebug() << "f.at = " << f.at() << endl;
+ }
+ dev->close();
+ delete dev;
+}
+
+void test_block_write( const TQString & fileName )
+{
+ TQIODevice * dev = KFilterDev::deviceForFile( fileName );
+ if (!dev) { kdWarning() << "dev=0" << endl; return; }
+ if ( !dev->open( IO_WriteOnly ) ) { kdWarning() << "open failed " << endl; return; }
+
+ TQCString s("hello\n");
+ int ret = dev->tqwriteBlock( s, s.size()-1 );
+ kdDebug() << "writeBlock ret=" << ret << endl;
+ //ret = dev->tqwriteBlock( s, s.size()-1 );
+ //kdDebug() << "writeBlock ret=" << ret << endl;
+ dev->close();
+ delete dev;
+}
+
+void test_getch( const TQString & fileName )
+{
+ TQIODevice * dev = KFilterDev::deviceForFile( fileName );
+ if (!dev) { kdWarning() << "dev=0" << endl; return; }
+ if ( !dev->open( IO_ReadOnly ) ) { kdWarning() << "open failed " << endl; return; }
+ int ch;
+ while ( ( ch = dev->getch() ) != -1 )
+ printf("%c",ch);
+ dev->close();
+ delete dev;
+}
+
+void test_textstream( const TQString & fileName )
+{
+ TQIODevice * dev = KFilterDev::deviceForFile( fileName );
+ if (!dev) { kdWarning() << "dev=0" << endl; return; }
+ if ( !dev->open( IO_ReadOnly ) ) { kdWarning() << "open failed " << endl; return; }
+ TQTextStream ts( dev );
+ printf("%s\n", ts.read().latin1());
+ dev->close();
+ delete dev;
+}
+
+int main()
+{
+ TDEInstance instance("kfiltertest");
+
+ char currentdir[PATH_MAX+1];
+ getcwd( currentdir, PATH_MAX );
+ TQString pathgz = TQFile::decodeName(currentdir) + "/test.gz";
+ TQString pathbz2 = TQFile::decodeName(currentdir) + "/test.bz2";
+
+ kdDebug() << " -- test_block_write gzip -- " << endl;
+ test_block_write(pathgz);
+ kdDebug() << " -- test_block_write bzip2 -- " << endl;
+ test_block_write(pathbz2);
+
+ kdDebug() << " -- test_block gzip -- " << endl;
+ test_block(pathgz);
+ kdDebug() << " -- test_getch gzip -- " << endl;
+ test_getch(pathgz);
+ kdDebug() << " -- test_textstream gzip -- " << endl;
+ test_textstream(pathgz);
+
+ kdDebug() << " -- test_block bzip2 -- " << endl;
+ test_block(pathbz2);
+ kdDebug() << " -- test_getch bzip2 -- " << endl;
+ test_getch(pathbz2);
+ kdDebug() << " -- test_textstream bzip2 -- " << endl;
+ test_textstream(pathbz2);
+
+ return 0;
+}
diff --git a/tdeio/tests/kionetrctest.cpp b/tdeio/tests/kionetrctest.cpp
new file mode 100644
index 000000000..2d96c8495
--- /dev/null
+++ b/tdeio/tests/kionetrctest.cpp
@@ -0,0 +1,71 @@
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+
+#include "authinfo.h"
+
+void output( const KURL& u )
+{
+ kdDebug() << "Looking up auto login for: " << u.url() << endl;
+ TDEIO::NetRC::AutoLogin l;
+ bool result = TDEIO::NetRC::self()->lookup( u, l, true );
+ if ( !result )
+ {
+ kdDebug() << "Either no .netrc and/or .kionetrc file was "
+ "found or there was problem when attempting to "
+ "read from them! Please make sure either or both "
+ "of the above files exist and have the correct "
+ "permission, i.e. a regular file owned by you with "
+ "with a read/write permission (0600)" << endl;
+ return;
+ }
+
+ kdDebug() << "Type: " << l.type << endl
+ << "Machine: " << l.machine << endl
+ << "Login: " << l.login << endl
+ << "Password: " << l.password << endl;
+
+ TQMap<TQString,TQStringList>::ConstIterator it = l.macdef.begin();
+ for ( ; it != l.macdef.end(); ++it )
+ {
+ kdDebug() << "Macro: " << it.key() << "= "
+ << it.data().join(" ") << endl;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ const char *version = "0.5";
+ const char *description = "Unit test for .netrc and kionetrc parser.";
+ KCmdLineOptions options[] =
+ {
+ { "+command", "[url1,url2 ,...]", 0 },
+ KCmdLineLastOption
+ };
+
+ TDECmdLineArgs::init( argc, argv, "kionetrctest", description, version );
+ TDECmdLineArgs::addCmdLineOptions( options );
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ int count = args->count();
+ TDEApplication app;
+
+ if ( !count )
+ args->usage();
+ else
+ {
+ KURL u;
+ for( int i=0 ; i < count; i++ )
+ {
+ u = args->arg(i);
+ if ( !u.isValid() )
+ {
+ kdDebug() << u.url() << " is invalid! Ignoring..." << endl;
+ continue;
+ }
+ output( u );
+ }
+ }
+ args->clear();
+ return 0;
+}
diff --git a/tdeio/tests/kiopassdlgtest.cpp b/tdeio/tests/kiopassdlgtest.cpp
new file mode 100644
index 000000000..adb14a306
--- /dev/null
+++ b/tdeio/tests/kiopassdlgtest.cpp
@@ -0,0 +1,32 @@
+#include <kapplication.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kmessagebox.h>
+#include <kcmdlineargs.h>
+
+#include "passdlg.h"
+
+int main ( int argc, char** argv )
+{
+ TDEAboutData aboutData("kiopassdlgtest", "KIO Password Dialog Test", "1.0");
+ TDECmdLineArgs::init(argc, argv, &aboutData);
+ TDEApplication app;
+
+ TQString usr, pass, comment, label;
+ label = "Site:";
+ comment = "<b>localhost</b>";
+ int res = TDEIO::PasswordDialog::getNameAndPassword( usr, pass, 0L,
+ TQString::null, false,
+ TQString::null, comment,
+ label );
+ if ( res == TQDialog::Accepted )
+ KMessageBox::information( 0L, TQString("You entered:\n"
+ " Username: %1\n"
+ " Password: %2").arg(usr).arg(pass),
+ "Test Result");
+ else
+ KMessageBox::information( 0L, "Password dialog was canceled!",
+ "Test Result");
+
+ return 0;
+}
diff --git a/tdeio/tests/kmfitest.cpp b/tdeio/tests/kmfitest.cpp
new file mode 100644
index 000000000..a2ec91717
--- /dev/null
+++ b/tdeio/tests/kmfitest.cpp
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <tqdir.h>
+#include <tqfile.h>
+#include <kinstance.h>
+#include <kurl.h>
+#include <tdefilemetainfo.h>
+#include <kmimetype.h>
+
+int main (int argc, char **argv)
+{
+ TDEInstance ins("kmfitest");
+
+ if (argc < 2) {
+ printf("usage: %s <file>\n", argv[0]);
+ return 1;
+ }
+
+ for (int i = 1; i < argc; i++) {
+ TQString file = TQFile::decodeName(argv[i]);
+ tqWarning("File: %s", file.local8Bit().data());
+ KMimeType::Ptr p;
+ p = KMimeType::findByPath(file);
+ tqWarning("Mime type (findByPath): %s", p->name().latin1());
+ KFileMetaInfo meta(file, TQString::null, KFileMetaInfo::TechnicalInfo | KFileMetaInfo::ContentInfo);
+ }
+
+ return 0;
+}
diff --git a/tdeio/tests/kmimefromext.cpp b/tdeio/tests/kmimefromext.cpp
new file mode 100644
index 000000000..026d4173b
--- /dev/null
+++ b/tdeio/tests/kmimefromext.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 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 <ktrader.h>
+#include <kmimetype.h>
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+
+#include <stdio.h>
+
+static KCmdLineOptions options[] =
+{
+ { "+filename", "the filename to test", 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ TDECmdLineArgs::init( argc, argv, "kmimefromext", "A mimetype testing tool, gives the mimetype for a given filename", "0.0" );
+
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app;
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ TQString fileName = args->arg( 0 );
+
+ // The "true" here means only the filename will be looked at.
+ // "Mime-magic" will not interfer. The file doesn't exist.
+ // TODO: a cmd line parameter for controlling this bool ;)
+ KMimeType::Ptr mime = KMimeType::findByPath( fileName, 0, true );
+ if ( mime && mime->name() != KMimeType::defaultMimeType() )
+ printf( "%s\n", mime->name().latin1());
+ else
+ return 1; // error
+
+ return 0;
+}
diff --git a/tdeio/tests/kmimemagictest.cpp b/tdeio/tests/kmimemagictest.cpp
new file mode 100644
index 000000000..00c545c3c
--- /dev/null
+++ b/tdeio/tests/kmimemagictest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2002 David Faure <faure@kde.org>
+ * Copyright (C) 2003 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 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 <kmimetype.h>
+#include <kmimemagic.h>
+#include <kinstance.h>
+#include <stdio.h>
+
+int main( int argc, char** argv )
+{
+ if (argc != 2)
+ {
+ printf("\n"
+ "Usage : ./kmimemagictest file\n");
+ return 1;
+ }
+ TDEInstance blah("kmimemagictest");
+
+ TQString file = TQString::fromLocal8Bit( argv[1] );
+
+ KMimeMagicResult * result = KMimeMagic::self()->findFileType( file );
+
+ if ( result->isValid() )
+ printf( "Found %s, accuracy %d\n", result->mimeType().latin1(), result->accuracy() );
+ else
+ printf( "Invalid result\n");
+
+ KMimeType::Format f = KMimeType::findFormatByFileContent( file );
+ if (f.text)
+ printf("Text\n");
+ else
+ printf("Binary\n");
+
+ if (f.compression == KMimeType::Format::GZipCompression)
+ printf("GZipped\n");
+
+ return 0;
+}
diff --git a/tdeio/tests/kmimetypetest.cpp b/tdeio/tests/kmimetypetest.cpp
new file mode 100644
index 000000000..5d963c81c
--- /dev/null
+++ b/tdeio/tests/kmimetypetest.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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 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 <kmimetype.h>
+#include <kinstance.h>
+#include <ktempdir.h>
+#include <kprotocolinfo.h>
+#include <tqdir.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void checkIcon( const KURL& url, const TQString& expectedIcon )
+{
+ TQString icon = KMimeType::iconForURL( url );
+ if ( icon == expectedIcon )
+ tqDebug( "icon for %s is %s, OK", url.prettyURL().latin1(), icon.latin1() );
+ else {
+ tqDebug( "ERROR: icon for %s is %s, expected %s!", url.prettyURL().latin1(), icon.latin1(), expectedIcon.latin1() );
+ exit(1);
+ }
+}
+
+int main( int argc, char** argv )
+{
+ TDEInstance blah("kmimetypetest");
+
+ // Obviously those tests will need to be fixed if we ever change the name of the icons
+ // but at least they unit-test KMimeType::iconForURL.
+ KURL url;
+
+ // safely check a "regular" folder
+ url.setPath( TQDir::homeDirPath() );
+ checkIcon( url, "folder" );
+
+ // safely check a non-readable folder
+ if (0 != geteuid()) { // can't do this test if we're root
+ KTempDir tmp( TQString::null, 0 );
+ tmp.setAutoDelete( true );
+ url.setPath( tmp.name() );
+ checkIcon( url, "folder_locked" );
+ chmod( TQFile::encodeName( tmp.name() ), 0500 ); // so we can 'rm -rf' it
+ }
+
+ // safely check the trash folder
+ if ( KProtocolInfo::isKnownProtocol( TQString("trash") ) ) {
+ checkIcon( "trash:/", "trashcan_full" ); // #100321
+ checkIcon( "trash:/foo/", "folder" );
+ }
+
+ TQString pdf;
+ KMimeType::diagnoseFileName("foo.pdf", pdf);
+ tqDebug("extension: '%s'", pdf.latin1());
+ assert(pdf == TQString("*.pdf"));
+ TQString ps;
+ KMimeType::diagnoseFileName("foo.ps", ps);
+ tqDebug("extension: '%s'", ps.latin1());
+ assert(ps == TQString("*.ps"));
+
+ return 0;
+}
diff --git a/tdeio/tests/kpropsdlgtest.cpp b/tdeio/tests/kpropsdlgtest.cpp
new file mode 100644
index 000000000..811f03923
--- /dev/null
+++ b/tdeio/tests/kpropsdlgtest.cpp
@@ -0,0 +1,35 @@
+#include <kapplication.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kpropertiesdialog.h>
+#include <kcmdlineargs.h>
+
+
+static KCmdLineOptions options[] =
+{
+ { "+url", "the path or url to the file/dir for which to show properties", 0 },
+ KCmdLineLastOption
+};
+
+int main ( int argc, char** argv )
+{
+ TDEAboutData aboutData("kpropertiesdialogtest", "KIO Properties Dialog Test", "1.0");
+ TDECmdLineArgs::init(argc, argv, &aboutData);
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app;
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+ if ( args->count() < 1 )
+ TDECmdLineArgs::usage();
+ KURL u = args->url( 0 );
+
+ // This is the test for the KPropertiesDialog constructor that is now
+ // documented to NOT work. Passing only a URL means a TDEIO::stat will happen,
+ // and asking for the dialog to be modal too creates problems.
+ // (A non-modal, URL-only dialog is the one kicker uses for app buttons, no problem there)
+ KPropertiesDialog* dlg = new KPropertiesDialog( u, 0, 0, true /*modal*/, false /*we do exec ourselves*/ );
+ dlg->exec();
+
+ return 0;
+}
diff --git a/tdeio/tests/kprotocolinfotest.cpp b/tdeio/tests/kprotocolinfotest.cpp
new file mode 100644
index 000000000..845f3367c
--- /dev/null
+++ b/tdeio/tests/kprotocolinfotest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2002 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 <kprotocolinfo.h>
+#include <kprotocolmanager.h>
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <assert.h>
+
+int main(int argc, char **argv) {
+ TDEAboutData aboutData("kprotocolinfotest", "KProtocolinfo Test",
+ "1.0");
+
+ TDECmdLineArgs::init(argc, argv, &aboutData);
+ TDEApplication app;
+
+ KURL url;
+ url.setPath("/tmp");
+ assert( KProtocolInfo::supportsListing( KURL( "ftp://10.1.1.10") ) );
+ assert( KProtocolInfo::inputType(url) == KProtocolInfo::T_NONE );
+ assert( KProtocolInfo::outputType(url) == KProtocolInfo::T_FILESYSTEM );
+ assert( KProtocolInfo::supportsReading(url) == true );
+ KProtocolInfo::ExtraFieldList extraFields = KProtocolInfo::extraFields(url);
+ KProtocolInfo::ExtraFieldList::Iterator extraFieldsIt = extraFields.begin();
+ for ( ; extraFieldsIt != extraFields.end() ; ++extraFieldsIt )
+ kdDebug() << (*extraFieldsIt).name << " " << (*extraFieldsIt).type << endl;
+
+ assert( KProtocolInfo::showFilePreview( "file" ) == true );
+ assert( KProtocolInfo::showFilePreview( "audiocd" ) == false );
+ assert( TDEGlobalSettings::showFilePreview( "audiocd:/" ) == false );
+
+ TQString proxy;
+ TQString protocol = KProtocolManager::slaveProtocol( "http://bugs.kde.org", proxy );
+ assert( protocol == "http" );
+
+ TQStringList capabilities = KProtocolInfo::capabilities( "imap" );
+ kdDebug() << "kio_imap capabilities: " << capabilities << endl;
+ //assert(capabilities.contains("ACL"));
+
+ return 0;
+}
diff --git a/tdeio/tests/kruntest.cpp b/tdeio/tests/kruntest.cpp
new file mode 100644
index 000000000..d8f47859b
--- /dev/null
+++ b/tdeio/tests/kruntest.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2002 David Faure <faure@kde.org>
+ * Copyright (C) 2003 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 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.
+ */
+
+// ------ this test works only if your terminal application is set to "x-term" ------
+
+#include "kruntest.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kshell.h>
+#include <kservice.h>
+#include <kde_file.h>
+
+#include <tqpushbutton.h>
+#include <tqlayout.h>
+#include <tqdir.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+const int MAXKRUNS = 100;
+
+testKRun * myArray[MAXKRUNS];
+
+void testKRun::foundMimeType( const TQString& _type )
+{
+ kdDebug() << "testKRun::foundMimeType " << _type << endl;
+ kdDebug() << "testKRun::foundMimeType URL=" << m_strURL.url() << endl;
+ m_bFinished = true;
+ m_timer.start( 0, true );
+ return;
+}
+
+Receiver::Receiver()
+{
+ TQVBoxLayout *lay = new TQVBoxLayout(this);
+ lay->setAutoAdd(true);
+ TQPushButton * h = new TQPushButton( "Press here to terminate", this );
+ start = new TQPushButton( "Launch KRuns", this );
+ stop = new TQPushButton( "Stop those KRuns", this );
+ stop->setEnabled(false);
+ TQObject::connect( h, TQT_SIGNAL(clicked()), kapp, TQT_SLOT(quit()) );
+ TQObject::connect( start, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotStart()) );
+ TQObject::connect( stop, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotStop()) );
+
+ adjustSize();
+ show();
+}
+
+void Receiver::slotStop()
+{
+ for (int i = 0 ; i < MAXKRUNS ; i++ )
+ {
+ kdDebug() << " deleting krun " << i << endl;
+ delete myArray[i];
+ }
+ start->setEnabled(true);
+ stop->setEnabled(false);
+}
+
+
+void Receiver::slotStart()
+{
+ for (int i = 0 ; i < MAXKRUNS ; i++ )
+ {
+ kdDebug() << "creating testKRun " << i << endl;
+ myArray[i] = new testKRun( KURL("file:/tmp"), 0, true, false /* no autodelete */ );
+ }
+ start->setEnabled(false);
+ stop->setEnabled(true);
+}
+
+void check(TQString txt, TQString a, TQString b)
+{
+ if (a.isEmpty())
+ a = TQString::null;
+ if (b.isEmpty())
+ b = TQString::null;
+ if (a == b)
+ kdDebug() << txt << " : '" << a << "' - ok" << endl;
+ else {
+ kdDebug() << txt << " : '" << a << "' but expected '" << b << "' - KO!" << endl;
+ exit(1);
+ }
+}
+
+const char *bt(bool tr) { return tr?"true":"false"; }
+
+void checkBN(TQString a, bool tr, TQString b)
+{
+ check( TQString().sprintf("binaryName('%s', %s)", a.latin1(), bt(tr)), KRun::binaryName(a, tr), b);
+}
+
+void checkPDE(const KService &service, const KURL::List &urls, bool hs, bool tf, TQString b)
+{
+ check(
+ TQString().sprintf("processDesktopExec( "
+ "service = {\nexec = %s\nterminal = %s, terminalOptions = %s\nsubstituteUid = %s, user = %s },"
+ "\nURLs = { %s },\nhas_shell = %s, temp_files = %s )",
+ service.exec().latin1(), bt(service.terminal()), service.terminalOptions().latin1(), bt(service.substituteUid()), service.username().latin1(),
+ KShell::joinArgs(urls.toStringList()).latin1(), bt(hs), bt(tf)),
+ KShell::joinArgs(KRun::processDesktopExec(service,urls,hs,tf)), b);
+}
+
+int main(int argc, char **argv)
+{
+ TDEApplication app( argc, argv, "kruntest", true /* it _has_ a GUI ! */);
+
+ // First some non-interactive tests
+ checkBN( "/usr/bin/ls", true, "ls");
+ checkBN( "/usr/bin/ls", false, "/usr/bin/ls");
+ checkBN( "/path/to/wine \"long argument with path\"", true, "wine" );
+ checkBN( "/path/with/a/sp\\ ace/exe arg1 arg2", true, "exe" );
+ checkBN( "\"progname\" \"arg1\"", true, "progname" );
+ checkBN( "'quoted' \"arg1\"", true, "quoted" );
+ checkBN( " 'leading space' arg1", true, "leading space" );
+
+ KURL::List l0;
+ KURL::List l1; l1 << "file:/tmp";
+ KURL::List l2; l2 << "http://localhost/foo";
+ KURL::List l3; l3 << "file:/local/file" << "http://remotehost.org/bar";
+
+ static const char
+ *execs[] = { "Exec=date -u", "Exec=echo $$PWD" },
+ *terms[] = { "Terminal=false", "Terminal=true\nTerminalOptions=-T \"%f - %c\"" },
+ *sus[] = { "X-TDE-SubstituteUID=false", "X-TDE-SubstituteUID=true\nX-TDE-Username=sprallo" },
+ *rslts[] = {
+"'date' '-u'", // 0
+"'/bin/sh' '-c' 'echo $PWD '", // 1
+"'x-term' '-T' ' - just_a_test' '-e' 'date' '-u'", // 2
+"'x-term' '-T' ' - just_a_test' '-e' '/bin/sh' '-c' 'echo $PWD '", // 3
+"'tdesu' '-u' 'sprallo' '-c' 'date -u '", // 4
+"'tdesu' '-u' 'sprallo' '-c' '/bin/sh -c '\\''echo $PWD '\\'''", // 5
+"'x-term' '-T' ' - just_a_test' '-e' 'su' 'sprallo' '-c' 'date -u '", // 6
+"'x-term' '-T' ' - just_a_test' '-e' 'su' 'sprallo' '-c' '/bin/sh -c '\\''echo $PWD '\\'''", // 7
+"'date -u '", // 8
+"'echo $PWD '", // 9
+"'x-term -T \" - just_a_test\"' '-e' 'date -u '", // a
+"'x-term -T \" - just_a_test\"' '-e' '/bin/sh -c '\\''echo $PWD '\\'''", // b
+"'tdesu' '-u' 'sprallo' '-c' ''\\''date -u '\\'''", // c
+"'tdesu' '-u' 'sprallo' '-c' ''\\''/bin/sh -c '\\''\\'\\'''\\''echo $PWD '\\''\\'\\'''\\'''\\'''", // d
+"'x-term -T \" - just_a_test\"' '-e' 'su' 'sprallo' '-c' ''\\''date -u '\\'''", // e
+"'x-term -T \" - just_a_test\"' '-e' 'su' 'sprallo' '-c' ''\\''/bin/sh -c '\\''\\'\\'''\\''echo $PWD '\\''\\'\\'''\\'''\\'''", // f
+ };
+ for (int hs = 0; hs < 2; hs++)
+ for (int su = 0; su < 2; su++)
+ for (int te = 0; te < 2; te++)
+ for (int ex = 0; ex < 2; ex++) {
+ int fd = creat("kruntest.desktop", 0666);
+ FILE *f;
+ if (fd < 0) abort();
+ f = KDE_fdopen(fd, "w");
+ fprintf(f, "[Desktop Entry]\n"
+ "Type=Application\n"
+ "Name=just_a_test\n"
+ "Icon=~/icon.png\n"
+ "%s\n%s\n%s\n",execs[ex],terms[te],sus[su]);
+ close(fd);
+ fclose(f);
+ KService s(TQDir::currentDirPath() + "/kruntest.desktop");
+ unlink("kruntest.desktop");
+ checkPDE( s, l0, hs, false, rslts[ex+te*2+su*4+hs*8]);
+ }
+
+ KService s1("dummy", "kate %U", "app");
+ checkPDE( s1, l0, false, false, "'kate'");
+ checkPDE( s1, l1, false, false, "'kate' '/tmp'");
+ checkPDE( s1, l2, false, false, "'kate' 'http://localhost/foo'");
+ checkPDE( s1, l3, false, false, "'kate' '/local/file' 'http://remotehost.org/bar'");
+ KService s2("dummy", "kate %u", "app");
+ checkPDE( s2, l0, false, false, "'kate'");
+ checkPDE( s2, l1, false, false, "'kate' '/tmp'");
+ checkPDE( s2, l2, false, false, "'kate' 'http://localhost/foo'");
+ checkPDE( s2, l3, false, false, "'kate'");
+ KService s3("dummy", "kate %F", "app");
+ checkPDE( s3, l0, false, false, "'kate'");
+ checkPDE( s3, l1, false, false, "'kate' '/tmp'");
+ checkPDE( s3, l2, false, false, "'kfmexec' 'kate %F' 'http://localhost/foo'");
+ checkPDE( s3, l3, false, false, "'kfmexec' 'kate %F' 'file:/local/file' 'http://remotehost.org/bar'");
+
+ checkPDE( s3, l1, false, true, "'kfmexec' '--tempfiles' 'kate %F' 'file:/tmp'");
+ checkPDE( s3, l1, true, true, "''\\''kfmexec'\\'' '\\''--tempfiles'\\'' '\\''kate %F'\\'' '\\''file:/tmp'\\'''");
+
+ KService s4("dummy", "sh -c \"kate \"'\\\"'\"%F\"'\\\"'", "app");
+ checkPDE( s4, l1, false, false, "'kate' '\"/tmp\"'");
+
+ Receiver receiver;
+ app.setMainWidget(&receiver);
+ return app.exec();
+}
+
+#include "kruntest.moc"
diff --git a/tdeio/tests/kruntest.h b/tdeio/tests/kruntest.h
new file mode 100644
index 000000000..68e7a7280
--- /dev/null
+++ b/tdeio/tests/kruntest.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 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 _kruntest_h
+#define _kruntest_h
+
+#include <krun.h>
+
+#include <tqwidget.h>
+
+class testKRun : public KRun
+{
+ Q_OBJECT
+public:
+
+ testKRun( const KURL& _url, mode_t _mode = 0,
+ bool _is_local_file = false, bool _auto_delete = true )
+ : KRun( _url, _mode, _is_local_file, _auto_delete ) {}
+
+ virtual ~testKRun() {}
+
+ virtual void foundMimeType( const TQString& _type );
+
+};
+
+
+class TQPushButton;
+class Receiver : public TQWidget
+{
+ Q_OBJECT
+public:
+ Receiver();
+ ~Receiver() {}
+public slots:
+ void slotStart();
+ void slotStop();
+private:
+ TQPushButton * start;
+ TQPushButton * stop;
+
+};
+
+#endif
diff --git a/tdeio/tests/kscantest.cpp b/tdeio/tests/kscantest.cpp
new file mode 100644
index 000000000..14abd1b33
--- /dev/null
+++ b/tdeio/tests/kscantest.cpp
@@ -0,0 +1,16 @@
+#include <kapplication.h>
+#include <kscan.h>
+
+int main( int argc, char **argv )
+{
+ TDEApplication app( argc, argv, "kscantest" );
+ KScanDialog *dlg = KScanDialog::getScanDialog();
+ if ( !dlg ) {
+ tqDebug("*** EEK, no Scan-service available, aborting!");
+ return 0;
+ }
+
+ dlg->show();
+
+ return app.exec();
+}
diff --git a/tdeio/tests/kshredtest.cpp b/tdeio/tests/kshredtest.cpp
new file mode 100644
index 000000000..76e87fca4
--- /dev/null
+++ b/tdeio/tests/kshredtest.cpp
@@ -0,0 +1,74 @@
+/*--------------------------------------------------------------------------*
+ KShred.h Copyright (c) 2000 MieTerra LLC.
+ Credits: Andreas F. Pour <bugs@mieterra.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "kshred.h"
+#include <tqstring.h>
+
+int main(int argc, char **argv)
+
+{
+ if (argc < 3)
+ {
+ fprintf(stderr, "Error, usage is '%s FILE MODE'\n", argv[0]);
+ exit(-1);
+ }
+
+ //if (!shred(argv[1]))
+ //printf("ERROR shredding %s\n", argv[1]);
+ //exit(1);
+
+ KShred::shred(argv[1]);
+ printf("Done\n");
+ exit(1);
+
+ KShred *shredder = new KShred(argv[1]);
+
+ switch (argv[2][0])
+ {
+ case '0':
+ if (!shredder->fill0s())
+ fprintf(stderr, "ERROR in filling 0s\n");
+ break;
+ case '1':
+ if (!shredder->fill1s())
+ fprintf(stderr, "ERROR in filling 1s\n");
+ break;
+ case 'r':
+ if (!shredder->fillrandom())
+ fprintf(stderr, "ERROR in filling random\n");
+ break;
+ case 'b':
+ if (!shredder->fillbyte((uint) argv[2][1]))
+ fprintf(stderr, "ERROR in filling byte '%c'\n", argv[2][1]);
+ break;
+ case 's':
+ if (!shredder->shred())
+ fprintf(stderr, "ERROR in shredding\n");
+ break;
+ default:
+ if (!shredder->fillpattern((unsigned char*)(argv[2]), strlen(argv[2])))
+ fprintf(stderr, "ERROR in filling with pattern '%s'\n", argv[2]);
+ break;
+ }
+ fprintf(stdout, "Done\n");
+ return 0;
+}
diff --git a/tdeio/tests/ktartest.cpp b/tdeio/tests/ktartest.cpp
new file mode 100644
index 000000000..2c470f6e4
--- /dev/null
+++ b/tdeio/tests/ktartest.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2002, 2003 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 "ktar.h"
+#include <stdio.h>
+#include <kinstance.h>
+#include <tqfile.h>
+
+#include <assert.h>
+
+void recursive_print( const KTarDirectory * dir, const TQString & path )
+{
+ TQStringList l = dir->entries();
+ TQStringList::Iterator it = l.begin();
+ for( ; it != l.end(); ++it )
+ {
+ const KTarEntry* entry = dir->entry( (*it) );
+ printf("mode=%07o %s %s %s%s %d isdir=%d\n", entry->permissions(), entry->user().latin1(), entry->group().latin1(), path.latin1(), (*it).latin1(),
+ entry->isFile() ? static_cast<const KArchiveFile *>(entry)->size() : 0,
+ entry->isDirectory());
+ if (entry->isDirectory())
+ recursive_print( (KTarDirectory *)entry, path+(*it)+"/" );
+ }
+}
+
+int main( int argc, char** argv )
+{
+ if (argc != 3)
+ {
+ printf("\n"
+ " Usage :\n"
+ " ./ktartest list /path/to/existing_file.tar.gz tests listing an existing tar.gz\n"
+ " ./ktartest readwrite newfile.tar.gz will create the tar.gz, then close and reopen it.\n"
+ " ./ktartest maxlength newfile.tar.gz tests the maximum filename length allowed.\n"
+ " ./ktartest iodevice /path/to/existing_file.tar.gz tests KArchiveFile::device()\n");
+ return 1;
+ }
+ TDEInstance instance("ktartest");
+ TQString command = argv[1];
+ if ( command == "list" )
+ {
+ KTarGz tar( argv[2] );
+
+ if ( !tar.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+
+ const KTarDirectory* dir = tar.directory();
+
+ //printf("calling recursive_print\n");
+ recursive_print( dir, "" );
+ //printf("recursive_print called\n");
+
+ tar.close();
+
+ return 0;
+ }
+ else if (command == "readwrite" )
+ {
+ KTarGz tar( argv[2] );
+
+ if ( !tar.open( IO_WriteOnly ) )
+ {
+ printf("Could not open %s for writing\n", argv[1]);
+ return 1;
+ }
+
+ tar.writeFile( "empty", "weis", "users", 0, "" );
+ tar.writeFile( "test1", "weis", "users", 5, "Hallo" );
+ tar.writeFile( "test2", "weis", "users", 8, "Hallo Du" );
+ tar.writeFile( "mydir/test3", "weis", "users", 13, "Noch so einer" );
+ tar.writeFile( "my/dir/test3", "dfaure", "hackers", 29, "I don't speak German (David)" );
+
+#define SIZE1 100
+ // Now a medium file : 100 null bytes
+ char medium[ SIZE1 ];
+ memset( medium, 0, SIZE1 );
+ tar.writeFile( "mediumfile", "user", "group", SIZE1, medium );
+ // Another one, with an absolute path
+ tar.writeFile( "/dir/subdir/mediumfile2", "user", "group", SIZE1, medium );
+
+ // Now a huge file : 20000 null bytes
+ int n = 20000;
+ char * huge = new char[ n ];
+ memset( huge, 0, n );
+ tar.writeFile( "hugefile", "user", "group", n, huge );
+ delete [] huge;
+
+ tar.close();
+
+ printf("-----------------------\n");
+
+ if ( !tar.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[1] );
+ return 1;
+ }
+
+ const KTarDirectory* dir = tar.directory();
+ recursive_print(dir, "");
+
+ const KTarEntry* e = dir->entry( "mydir/test3" );
+ Q_ASSERT( e && e->isFile() );
+ const KTarFile* f = (KTarFile*)e;
+
+ TQByteArray arr( f->data() );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+ printf("DATA=%s\n", str.latin1());
+
+ tar.close();
+
+ return 0;
+ }
+ else if ( command == "maxlength" )
+ {
+ KTarGz tar( argv[2] );
+
+ if ( !tar.open( IO_WriteOnly ) )
+ {
+ printf("Could not open %s for writing\n", argv[1]);
+ return 1;
+ }
+ // Generate long filenames of each possible length bigger than 98...
+ // Also exceed 512 byte block size limit to see how well the ././@LongLink
+ // implementation fares
+ for (int i = 98; i < 514 ; i++ )
+ {
+ TQString str, num;
+ str.fill( 'a', i-10 );
+ num.setNum( i );
+ num = num.rightJustify( 10, '0' );
+ tar.writeFile( str+num, "testu", "testg", 3, "hum" );
+ }
+ // Result of this test : works perfectly now (failed at 482 formerly and
+ // before that at 154).
+ tar.close();
+ printf("Now run 'tar tvzf %s'\n", argv[2]);
+ return 0;
+ }
+ else if ( command == "iodevice" )
+ {
+ KTarGz tar( argv[2] );
+ if ( !tar.open( IO_ReadOnly ) )
+ return 1;
+ const KTarDirectory* dir = tar.directory();
+ assert(dir);
+ const KTarEntry* entry = dir->entry( "my/dir/test3" );
+ if ( entry && entry->isFile() )
+ {
+ TQIODevice *dev = static_cast<const KTarFile *>(entry)->device();
+ TQByteArray contents = dev->readAll();
+ printf("contents='%s'\n", TQCString(contents, contents.size()+1 ).data());
+ } else
+ printf("entry=%p - not found if 0, otherwise not a file\n", (void*)entry);
+ return 0;
+ }
+ else
+ printf("Unknown command\n");
+}
+
diff --git a/tdeio/tests/kurifiltertest.cpp b/tdeio/tests/kurifiltertest.cpp
new file mode 100644
index 000000000..473ba6840
--- /dev/null
+++ b/tdeio/tests/kurifiltertest.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2002, 2003 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 "kurifilter.h"
+
+#include <config.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+#include <kstandarddirs.h>
+#include <ksimpleconfig.h>
+
+#include <tqdir.h>
+#include <tqregexp.h>
+#include <tdeio/netaccess.h>
+
+static const char * const s_uritypes[] = { "NET_PROTOCOL", "LOCAL_FILE", "LOCAL_DIR", "EXECUTABLE", "HELP", "SHELL", "BLOCKED", "ERROR", "UNKNOWN" };
+#define NO_FILTERING -2
+
+void filter( const char* u, const char * expectedResult = 0, int expectedUriType = -1, TQStringList list = TQStringList(), const char * abs_path = 0, bool checkForExecutables = true )
+{
+ TQString a = TQString::fromUtf8( u );
+ KURIFilterData * m_filterData = new KURIFilterData;
+ m_filterData->setData( a );
+ m_filterData->setCheckForExecutables( checkForExecutables );
+
+ if( abs_path )
+ {
+ m_filterData->setAbsolutePath( TQString::fromLatin1( abs_path ) );
+ kdDebug() << "Filtering: " << a << " with abs_path=" << abs_path << endl;
+ }
+ else
+ kdDebug() << "Filtering: " << a << endl;
+
+ if (KURIFilter::self()->filterURI(*m_filterData, list))
+ {
+ // Copied from minicli...
+ TQString cmd;
+ KURL uri = m_filterData->uri();
+
+ if ( uri.isLocalFile() && !uri.hasRef() && uri.query().isEmpty() )
+ cmd = uri.path();
+ else
+ cmd = uri.url();
+
+ switch( m_filterData->uriType() )
+ {
+ case KURIFilterData::LOCAL_FILE:
+ case KURIFilterData::LOCAL_DIR:
+ case KURIFilterData::HELP:
+ kdDebug() << "*** Result: Local Resource => '"
+ << m_filterData->uri().url() << "'" << endl;
+ break;
+ case KURIFilterData::NET_PROTOCOL:
+ kdDebug() << "*** Result: Network Resource => '"
+ << m_filterData->uri().url() << "'" << endl;
+ break;
+ case KURIFilterData::SHELL:
+ case KURIFilterData::EXECUTABLE:
+ if( m_filterData->hasArgsAndOptions() )
+ cmd += m_filterData->argsAndOptions();
+ kdDebug() << "*** Result: Executable/Shell => '" << cmd << "'"<< endl;
+ break;
+ case KURIFilterData::ERROR:
+ kdDebug() << "*** Result: Encountered error. See reason below." << endl;
+ break;
+ default:
+ kdDebug() << "*** Result: Unknown or invalid resource." << endl;
+ }
+
+ if ( expectedUriType != -1 && expectedUriType != m_filterData->uriType() )
+ {
+ kdError() << " Got URI type " << s_uritypes[m_filterData->uriType()]
+ << " expected " << s_uritypes[expectedUriType] << endl;
+ ::exit(1);
+ }
+
+ if ( expectedResult )
+ {
+ // Hack for other locales than english, normalize google hosts to google.com
+ cmd = cmd.replace( TQRegExp( "www\\.google\\.[^/]*/" ), "www.google.com/" );
+ if ( cmd != TQString::fromLatin1( expectedResult ) )
+ {
+ kdError() << " Got " << cmd << " expected " << expectedResult << endl;
+ ::exit(1);
+ }
+ }
+ }
+ else
+ {
+ if ( expectedUriType == NO_FILTERING )
+ kdDebug() << "*** No filtering required." << endl;
+ else
+ {
+ kdDebug() << "*** Could not be filtered." << endl;
+ if( expectedUriType != m_filterData->uriType() )
+ {
+ kdError() << " Got URI type " << s_uritypes[m_filterData->uriType()]
+ << " expected " << s_uritypes[expectedUriType] << endl;
+ ::exit(1);
+ }
+ }
+ }
+
+ delete m_filterData;
+ kdDebug() << "-----" << endl;
+}
+
+void testLocalFile( const TQString& filename )
+{
+ TQFile tmpFile( filename ); // Yeah, I know, security risk blah blah. This is a test prog!
+
+ if ( tmpFile.open( IO_ReadWrite ) )
+ {
+ TQCString fname = TQFile::encodeName( tmpFile.name() );
+ filter(fname, fname, KURIFilterData::LOCAL_FILE);
+ tmpFile.close();
+ tmpFile.remove();
+ }
+ else
+ kdDebug() << "Couldn't create " << tmpFile.name() << ", skipping test" << endl;
+}
+
+static const char appName[] = "kurifiltertest";
+static const char programName[] = I18N_NOOP("kurifiltertest");
+static const char description[] = I18N_NOOP("Unit test for the URI filter plugin framework.");
+static const char version[] = "1.5";
+
+static const KCmdLineOptions options[] =
+{
+ { "s", I18N_NOOP("Use space as keyword delimeter for web shortcuts"), 0},
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ // Ensure that user configuration doesn't change the results of those tests
+ // TDEHOME needs to be writable though, for a tdesycoca database
+ setenv( "TDEHOME", TQFile::encodeName( TQDir::homeDirPath() + "/.tde-kurifiltertest" ), true );
+ setenv( "TDE_FORK_SLAVES", "yes", true ); // simpler, for the final cleanup
+
+ TDEAboutData aboutData(appName, programName, version, description);
+ TDECmdLineArgs::init(argc, argv, &aboutData);
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app;
+ app.disableAutoDcopRegistration();
+
+ // Allow testing of the search engine using both delimiters...
+ char delimiter = TDECmdLineArgs::parsedArgs()->isSet("s") ? ' ' : ':';
+
+ // Many tests check the "default search engine" feature.
+ // There is no default search engine by default (since it was annoying when making typos),
+ // so the user has to set it up, which we do here.
+ {
+ KSimpleConfig cfg( "kuriikwsfilterrc" );
+ cfg.setGroup( "General" );
+ cfg.writeEntry( "DefaultSearchEngine", "google" );
+ cfg.writeEntry( "Verbose", true );
+ cfg.writeEntry( "KeywordDelimiter", delimiter );
+ cfg.sync();
+ }
+
+ // Enable verbosity for debugging
+ {
+ KSimpleConfig cfg( "kshorturifilterrc" );
+ cfg.writeEntry( "Verbose", true );
+ cfg.sync();
+ }
+
+ TQStringList minicliFilters;
+ minicliFilters << "kshorturifilter" << "kurisearchfilter" << "localdomainurifilter";
+
+ // URI that should require no filtering
+ filter( "http://www.kde.org", "http://www.kde.org", KURIFilterData::NET_PROTOCOL );
+ filter( "http://www.kde.org/developer//index.html", "http://www.kde.org/developer//index.html", KURIFilterData::NET_PROTOCOL );
+ // URL with reference
+ filter( "http://www.kde.org/index.html#q8", "http://www.kde.org/index.html#q8", KURIFilterData::NET_PROTOCOL );
+ // local file with reference
+ filter( "file:/etc/passwd#q8", "file:///etc/passwd#q8", KURIFilterData::LOCAL_FILE );
+ filter( "file:///etc/passwd#q8", "file:///etc/passwd#q8", KURIFilterData::LOCAL_FILE );
+ filter( "/etc/passwd#q8", "file:///etc/passwd#q8", KURIFilterData::LOCAL_FILE );
+ // local file with query (can be used by javascript)
+ filter( "file:/etc/passwd?foo=bar", "file:///etc/passwd?foo=bar", KURIFilterData::LOCAL_FILE );
+ testLocalFile( "/tmp/kurifiltertest?foo" ); // local file with ? in the name (#58990)
+ testLocalFile( "/tmp/kurlfiltertest#foo" ); // local file with '#' in the name
+ testLocalFile( "/tmp/kurlfiltertest#foo?bar" ); // local file with both
+ testLocalFile( "/tmp/kurlfiltertest?foo#bar" ); // local file with both, the other way round
+
+ // hostnames are lowercased by KURL
+ filter( "http://www.myDomain.commyPort/ViewObjectRes//Default:name=hello",
+ "http://www.mydomain.commyport/ViewObjectRes//Default:name=hello", KURIFilterData::NET_PROTOCOL);
+ filter( "ftp://ftp.kde.org", "ftp://ftp.kde.org", KURIFilterData::NET_PROTOCOL );
+ filter( "ftp://username@ftp.kde.org:500", "ftp://username@ftp.kde.org:500", KURIFilterData::NET_PROTOCOL );
+
+ // ShortURI/LocalDomain filter tests. NOTE: any of these tests can fail
+ // if you have specified your own patterns in kshorturifilterrc. For
+ // examples, see $TDEDIR/share/config/kshorturifilterrc .
+ filter( "linuxtoday.com", "http://linuxtoday.com", KURIFilterData::NET_PROTOCOL );
+ filter( "LINUXTODAY.COM", "http://linuxtoday.com", KURIFilterData::NET_PROTOCOL );
+ filter( "kde.org", "http://kde.org", KURIFilterData::NET_PROTOCOL );
+ filter( "ftp.kde.org", "ftp://ftp.kde.org", KURIFilterData::NET_PROTOCOL );
+ filter( "ftp.kde.org:21", "ftp://ftp.kde.org:21", KURIFilterData::NET_PROTOCOL );
+ filter( "cr.yp.to", "http://cr.yp.to", KURIFilterData::NET_PROTOCOL );
+ filter( "user@192.168.1.0:3128", "http://user@192.168.1.0:3128", KURIFilterData::NET_PROTOCOL );
+ filter( "127.0.0.1", "http://127.0.0.1", KURIFilterData::NET_PROTOCOL );
+ filter( "127.0.0.1:3128", "http://127.0.0.1:3128", KURIFilterData::NET_PROTOCOL );
+ filter( "foo@bar.com", "mailto:foo@bar.com", KURIFilterData::NET_PROTOCOL );
+ filter( "firstname.lastname@x.foo.bar", "mailto:firstname.lastname@x.foo.bar", KURIFilterData::NET_PROTOCOL );
+ filter( "www.123.foo", "http://www.123.foo", KURIFilterData::NET_PROTOCOL );
+ filter( "user@www.123.foo:3128", "http://user@www.123.foo:3128", KURIFilterData::NET_PROTOCOL );
+
+ // Exotic IPv4 address formats...
+ filter( "127.1", "http://127.1", KURIFilterData::NET_PROTOCOL );
+ filter( "127.0.1", "http://127.0.1", KURIFilterData::NET_PROTOCOL );
+
+ // Local domain filter - If you uncomment these test, make sure you
+ // you adjust it based on the localhost entry in your /etc/hosts file.
+ // filter( "localhost:3128", "http://localhost.localdomain:3128", KURIFilterData::NET_PROTOCOL );
+ // filter( "localhost", "http://localhost.localdomain", KURIFilterData::NET_PROTOCOL );
+ // filter( "localhost/~blah", "http://localhost.localdomain/~blah", KURIFilterData::NET_PROTOCOL );
+
+ filter( "/", "/", KURIFilterData::LOCAL_DIR );
+ filter( "/", "/", KURIFilterData::LOCAL_DIR, "kshorturifilter" );
+ filter( "~/.bashrc", TQDir::homeDirPath().local8Bit()+"/.bashrc", KURIFilterData::LOCAL_FILE, "kshorturifilter" );
+ filter( "~", TQDir::homeDirPath().local8Bit(), KURIFilterData::LOCAL_DIR, "kshorturifilter", "/tmp" );
+ filter( "~foobar", 0, KURIFilterData::ERROR, "kshorturifilter" );
+ filter( "user@host.domain", "mailto:user@host.domain", KURIFilterData::NET_PROTOCOL ); // new in KDE-3.2
+
+ // Windows style SMB (UNC) URL. Should be converted into the valid smb format...
+ filter( "\\\\mainserver\\share\\file", "smb://mainserver/share/file" , KURIFilterData::NET_PROTOCOL );
+
+ // Should not be filtered at all. All valid protocols of this form will be ignored.
+ filter( "ftp:" , "ftp:", KURIFilterData::UNKNOWN );
+ filter( "http:" , "http:", KURIFilterData::UNKNOWN );
+
+ /*
+ Automatic searching tests. NOTE: If the Default search engine is set to 'None',
+ this stuff will fail as the status returned will then be KURIFilterData::UNKNOWN.
+ */
+ filter( "gg:", 0 , KURIFilterData::NET_PROTOCOL );
+ filter( "KDE", 0 , KURIFilterData::NET_PROTOCOL );
+ filter( "FTP", 0 , KURIFilterData::NET_PROTOCOL );
+
+ // If your default search engine is set to 'Google', you can uncomment the test below.
+ filter( "gg:", "http://www.google.com/search?q=gg%3A&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( "KDE", "http://www.google.com/search?q=KDE&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( "FTP", "http://www.google.com/search?q=FTP&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+
+ // Typing 'cp' or any other valid unix command in konq's location bar should result in
+ // a search using the default search engine
+ // 'ls' is a bit of a special case though, due to the toplevel domain called 'ls'
+ filter( "cp", "http://www.google.com/search?q=cp&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL,
+ TQStringList(), 0, false /* don't check for executables, see konq_misc.cc */ );
+
+ // Executable tests - No IKWS in minicli
+ filter( "cp", "cp", KURIFilterData::EXECUTABLE, minicliFilters );
+ filter( "kfmclient", "kfmclient", KURIFilterData::EXECUTABLE, minicliFilters );
+ filter( "xwininfo", "xwininfo", KURIFilterData::EXECUTABLE, minicliFilters );
+ filter( "KDE", "KDE", NO_FILTERING, minicliFilters );
+ filter( "I/dont/exist", "I/dont/exist", NO_FILTERING, minicliFilters );
+ filter( "/I/dont/exist", 0, KURIFilterData::ERROR, minicliFilters );
+ filter( "/I/dont/exist#a", 0, KURIFilterData::ERROR, minicliFilters );
+ filter( "kfmclient --help", "kfmclient --help", KURIFilterData::EXECUTABLE, minicliFilters ); // the args are in argsAndOptions()
+ filter( "/usr/bin/gs", "/usr/bin/gs", KURIFilterData::EXECUTABLE, minicliFilters );
+ filter( "/usr/bin/gs -q -option arg1", "/usr/bin/gs -q -option arg1", KURIFilterData::EXECUTABLE, minicliFilters ); // the args are in argsAndOptions()
+
+ // ENVIRONMENT variable
+ setenv( "SOMEVAR", "/somevar", 0 );
+ setenv( "ETC", "/etc", 0 );
+
+ TQCString qtdir=getenv("QTDIR");
+ TQCString home = getenv("HOME");
+ TQCString tdehome = getenv("TDEHOME");
+
+ filter( "$SOMEVAR/tdelibs/tdeio", 0, KURIFilterData::ERROR ); // note: this dir doesn't exist...
+ filter( "$ETC/passwd", "/etc/passwd", KURIFilterData::LOCAL_FILE );
+ filter( "$QTDIR/doc/html/functions.html#s", TQCString("file://")+qtdir+"/doc/html/functions.html#s", KURIFilterData::LOCAL_FILE );
+ filter( "http://www.kde.org/$USER", "http://www.kde.org/$USER", KURIFilterData::NET_PROTOCOL ); // no expansion
+
+ // Assume the default (~/.trinity) if
+ if (tdehome.isEmpty())
+ {
+ tdehome += "$HOME/.trinity";
+ setenv("TDEHOME", tdehome.data(), 0);
+ }
+
+ filter( "$TDEHOME/share", tdehome+"/share", KURIFilterData::LOCAL_DIR );
+ KStandardDirs::makeDir( tdehome+"/a+plus" );
+ filter( "$TDEHOME/a+plus", tdehome+"/a+plus", KURIFilterData::LOCAL_DIR );
+
+ // BR 27788
+ KStandardDirs::makeDir( tdehome+"/share/Dir With Space" );
+ filter( "$TDEHOME/share/Dir With Space", tdehome+"/share/Dir With Space", KURIFilterData::LOCAL_DIR );
+
+ // support for name filters (BR 93825)
+ filter( "$TDEHOME/*.txt", tdehome+"/*.txt", KURIFilterData::LOCAL_DIR );
+ filter( "$TDEHOME/[a-b]*.txt", tdehome+"/[a-b]*.txt", KURIFilterData::LOCAL_DIR );
+ filter( "$TDEHOME/a?c.txt", tdehome+"/a?c.txt", KURIFilterData::LOCAL_DIR );
+ filter( "$TDEHOME/?c.txt", tdehome+"/?c.txt", KURIFilterData::LOCAL_DIR );
+ // but let's check that a directory with * in the name still works
+ KStandardDirs::makeDir( tdehome+"/share/Dir*With*Stars" );
+ filter( "$TDEHOME/share/Dir*With*Stars", tdehome+"/share/Dir*With*Stars", KURIFilterData::LOCAL_DIR );
+ KStandardDirs::makeDir( tdehome+"/share/Dir?QuestionMark" );
+ filter( "$TDEHOME/share/Dir?QuestionMark", tdehome+"/share/Dir?QuestionMark", KURIFilterData::LOCAL_DIR );
+ KStandardDirs::makeDir( tdehome+"/share/Dir[Bracket" );
+ filter( "$TDEHOME/share/Dir[Bracket", tdehome+"/share/Dir[Bracket", KURIFilterData::LOCAL_DIR );
+
+ filter( "$HOME/$TDEDIR/tdebase/kcontrol/ebrowsing", 0, KURIFilterData::ERROR );
+ filter( "$1/$2/$3", "http://www.google.com/search?q=$1/$2/$3&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL ); // can be used as bogus or valid test. Currently triggers default search, i.e. google
+ filter( "$$$$", "http://www.google.com/search?q=$$$$&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL ); // worst case scenarios.
+
+ // Replaced the match testing with a 0 since
+ // the shortURI filter will return the string
+ // itself if the requested environment variable
+ // is not already set.
+ filter( "$QTDIR", 0, KURIFilterData::LOCAL_DIR, "kshorturifilter" ); //use specific filter.
+ filter( "$HOME", home, KURIFilterData::LOCAL_DIR, "kshorturifilter" ); //use specific filter.
+
+
+ TQCString sc;
+ filter( sc.sprintf("gg%cfoo bar",delimiter), "http://www.google.com/search?q=foo+bar&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( sc.sprintf("bug%c55798", delimiter), "http://bugs.kde.org/show_bug.cgi?id=55798", KURIFilterData::NET_PROTOCOL );
+
+ filter( sc.sprintf("gg%cC++", delimiter), "http://www.google.com/search?q=C%2B%2B&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( sc.sprintf("ya%cfoo bar was here", delimiter), 0, -1 ); // this triggers default search, i.e. google
+ filter( sc.sprintf("gg%cwww.kde.org", delimiter), "http://www.google.com/search?q=www.kde.org&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( sc.sprintf("av%c+rock +sample", delimiter), "http://www.altavista.com/cgi-bin/query?pg=q&kl=XX&stype=stext&q=%2Brock+%2Bsample", KURIFilterData::NET_PROTOCOL );
+ filter( sc.sprintf("gg%cé", delimiter) /*eaccent in utf8*/, "http://www.google.com/search?q=%C3%A9&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+ filter( sc.sprintf("gg%cпрйвет", delimiter) /* greetings in russian utf-8*/, "http://www.google.com/search?q=%D0%BF%D1%80%D0%B9%D0%B2%D0%B5%D1%82&ie=UTF-8&oe=UTF-8", KURIFilterData::NET_PROTOCOL );
+
+ // Absolute Path tests for kshorturifilter
+ filter( "./", tdehome+"/share", KURIFilterData::LOCAL_DIR, "kshorturifilter", tdehome+"/share/" ); // cleanDirPath removes the trailing slash
+ filter( "../", tdehome, KURIFilterData::LOCAL_DIR, "kshorturifilter", tdehome+"/share" );
+ filter( "config", tdehome+"/share/config", KURIFilterData::LOCAL_DIR, "kshorturifilter", tdehome+"/share" );
+
+ // Clean up
+ TDEIO::NetAccess::del( tdehome, 0 );
+
+ kdDebug() << "All tests done. Go home..." << endl;
+ return 0;
+}
diff --git a/tdeio/tests/kurlcompletiontest.cpp b/tdeio/tests/kurlcompletiontest.cpp
new file mode 100644
index 000000000..c8dc99595
--- /dev/null
+++ b/tdeio/tests/kurlcompletiontest.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2004 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 <kapplication.h>
+#include <kurlcompletion.h>
+#include <kdebug.h>
+#include <tqdir.h>
+#include <assert.h>
+#include <tqfile.h>
+#include <ktempdir.h>
+#include <kcmdlineargs.h>
+#include <unistd.h>
+
+class KURLCompletionTest
+{
+public:
+ KURLCompletionTest() {}
+ ~KURLCompletionTest() { teardown(); }
+ void setup( bool setDirAsURL );
+ void teardown();
+ void testLocalRelativePath();
+ void testLocalAbsolutePath();
+ void testLocalURL();
+
+private:
+ void waitForCompletion();
+ KURLCompletion* m_completion;
+ KTempDir* m_tempDir;
+ KURL m_dirURL;
+ TQString m_dir;
+};
+
+void KURLCompletionTest::setup( bool setDirAsURL )
+{
+ kdDebug() << k_funcinfo << endl;
+ m_completion = new KURLCompletion;
+ m_tempDir = new KTempDir;
+ m_tempDir->setAutoDelete( true );
+ m_dir = m_tempDir->name();
+ kdDebug() << "m_dir=" << m_dir << endl;
+ Q_ASSERT( m_dir.endsWith( "/" ) );
+ if ( setDirAsURL ) {
+ KURL d; d.setPath( m_dir );
+ m_completion->setDir( d.url() );
+ } else {
+ m_completion->setDir( m_dir );
+ }
+ m_dirURL.setPath( m_dir );
+
+ TQFile f1( m_dir + "/file1" );
+ bool ok = f1.open( IO_WriteOnly );
+ assert( ok );
+ f1.close();
+
+ TQFile f2( m_dir + "/file#a" );
+ ok = f2.open( IO_WriteOnly );
+ assert( ok );
+ f2.close();
+}
+
+void KURLCompletionTest::teardown()
+{
+ delete m_completion;
+ m_completion = 0;
+ delete m_tempDir;
+ m_tempDir = 0;
+}
+void KURLCompletionTest::waitForCompletion()
+{
+ while ( m_completion->isRunning() ) {
+ kdDebug() << "waiting for thread..." << endl;
+ usleep( 10 );
+ }
+}
+
+void KURLCompletionTest::testLocalRelativePath()
+{
+ kdDebug() << k_funcinfo << endl;
+ // Completion from relative path, with two matches
+ m_completion->makeCompletion( "f" );
+ waitForCompletion();
+ TQStringList comp1all = m_completion->allMatches();
+ assert( comp1all.count() == 2 );
+ assert( comp1all.find( "file1" ) != comp1all.end() );
+ assert( comp1all.find( "file#a" ) != comp1all.end() );
+ TQString comp1 = m_completion->replacedPath( "file1" ); // like KURLRequester does
+ assert( comp1 == "file1" );
+
+ // Completion from relative path
+ kdDebug() << endl << k_funcinfo << "now completing on 'file#'" << endl;
+ m_completion->makeCompletion( "file#" );
+ waitForCompletion();
+ TQStringList compall = m_completion->allMatches();
+ kdDebug() << compall << endl;
+ assert( compall.count() == 1 );
+ assert( compall.first() == "file#a" );
+ TQString comp2 = m_completion->replacedPath( compall.first() ); // like KURLRequester does
+ assert( comp2 == "file#a" );
+}
+
+void KURLCompletionTest::testLocalAbsolutePath()
+{
+ // Completion from absolute path
+ kdDebug() << k_funcinfo << m_dir+"file#" << endl;
+ m_completion->makeCompletion( m_dir + "file#" );
+ waitForCompletion();
+ TQStringList compall = m_completion->allMatches();
+ kdDebug() << compall << endl;
+ assert( compall.count() == 1 );
+ TQString comp = compall.first();
+ assert( comp == m_dir + "file#a" );
+ comp = m_completion->replacedPath( comp ); // like KURLRequester does
+ assert( comp == m_dir + "file#a" );
+}
+
+void KURLCompletionTest::testLocalURL()
+{
+ // Completion from URL
+ kdDebug() << k_funcinfo << endl;
+ KURL url = KURL::fromPathOrURL( m_dirURL.path() + "file" );
+ m_completion->makeCompletion( url.prettyURL() );
+ waitForCompletion();
+ TQStringList comp1all = m_completion->allMatches();
+ kdDebug() << comp1all << endl;
+ assert( comp1all.count() == 2 );
+ assert( comp1all.find( m_dirURL.url() + "file1" ) != comp1all.end() );
+ TQString filehash = m_dirURL.url() + "file%23a";
+ assert( comp1all.find( filehash ) != comp1all.end() );
+ TQString filehashPath = m_completion->replacedPath( filehash ); // note that it returns a path!!
+ kdDebug() << filehashPath << endl;
+ assert( filehashPath == m_dirURL.path() + "file#a" );
+
+ // Completion from URL with no match
+ url = KURL::fromPathOrURL( m_dirURL.path() + "foobar" );
+ kdDebug() << k_funcinfo << "makeCompletion(" << url << ")" << endl;
+ TQString comp2 = m_completion->makeCompletion( url.prettyURL() );
+ assert( comp2.isEmpty() );
+ waitForCompletion();
+ assert( m_completion->allMatches().isEmpty() );
+
+ // Completion from URL with a ref -> no match
+ url = KURL::fromPathOrURL( m_dirURL.path() + "f" );
+ url.setRef( "ref" );
+ kdDebug() << k_funcinfo << "makeCompletion(" << url << ")" << endl;
+ m_completion->makeCompletion( url.prettyURL() );
+ waitForCompletion();
+ assert( m_completion->allMatches().isEmpty() );
+}
+
+int main( int argc, char **argv )
+{
+ TDEApplication::disableAutoDcopRegistration();
+ TDECmdLineArgs::init(argc,argv,"kurlcompletiontest", 0, 0, 0, 0);
+ TDEApplication app;
+
+ {
+ KURLCompletionTest test;
+ test.setup( false );
+ test.testLocalRelativePath();
+ test.testLocalAbsolutePath();
+ test.testLocalURL();
+ test.teardown();
+
+ // Try again, with another KTempDir (to check that the caching doesn't give us wrong results)
+ test.setup( true );
+ test.testLocalRelativePath();
+ test.testLocalAbsolutePath();
+ test.testLocalURL();
+ test.teardown();
+ }
+ tqDebug( "All tests OK." );
+
+ return 0;
+}
diff --git a/tdeio/tests/kziptest.cpp b/tdeio/tests/kziptest.cpp
new file mode 100644
index 000000000..84d38d134
--- /dev/null
+++ b/tdeio/tests/kziptest.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2002, 2003 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 "kzip.h"
+#include <stdio.h>
+#include <kinstance.h>
+#include <kdebug.h>
+#include <tqfile.h>
+
+#include <assert.h>
+
+void recursive_print( const KArchiveDirectory * dir, const TQString & path )
+{
+ TQStringList l = dir->entries();
+ TQStringList::Iterator it = l.begin();
+ for( ; it != l.end(); ++it )
+ {
+ const KArchiveEntry* entry = dir->entry( (*it) );
+ printf("mode=%07o %s %s size: %d pos: %d %s%s isdir=%d%s", entry->permissions(),
+ entry->user().latin1(), entry->group().latin1(),
+ entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->size(),
+ entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->position(),
+ path.latin1(), (*it).latin1(), entry->isDirectory(),
+ !entry->symlink() ? "" : TQString(" symlink: %1").arg(entry->symlink()).latin1() );
+
+// if (!entry->isDirectory()) printf("%d", ((KArchiveFile*)entry)->size());
+ printf("\n");
+ if (entry->isDirectory())
+ recursive_print( (KArchiveDirectory *)entry, path+(*it)+"/" );
+ }
+}
+
+
+void recursive_transfer(const KArchiveDirectory * dir,
+ const TQString & path, KZip * zip)
+{
+ TQStringList l = dir->entries();
+ TQStringList::Iterator it = l.begin();
+ for( ; it != l.end(); ++it )
+ {
+ const KArchiveEntry* e = dir->entry( (*it) );
+ kdDebug() << "actual file: " << e->name() << endl;
+ if (e->isFile())
+ {
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+ printf("FILE=%s\n", e->name().latin1());
+
+ TQByteArray arr( f->data() );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+ printf("DATA=%s\n", str.latin1());
+
+ if (e->symlink().isEmpty()) {
+ zip->writeFile( path+e->name().latin1(),
+ "holgi", "holgrp",
+ arr.size() , f->data() );
+ } else
+ zip->writeSymLink(path+e->name(), e->symlink(), "leo", "leo",
+ 0120777, 1000000000l, 1000000000l, 1000000000l);
+ }
+ else if (e->isDirectory())
+ {
+ recursive_transfer((KArchiveDirectory *)e ,
+ path+e->name()+"/", zip);
+ }
+ }
+}
+
+int main( int argc, char** argv )
+{
+ if (argc < 3)
+ {
+ printf("\n"
+ " Usage :\n"
+ " ./kziptest list /path/to/existing_file.zip tests listing an existing zip\n"
+ " ./kziptest readwrite newfile.zip will create the zip, then close and reopen it.\n"
+ " ./kziptest maxlength newfile.zip tests the maximum filename length allowed.\n"
+ " ./kziptest print file.zip prints contents of all files.\n"
+ " ./kziptest print2 file.zip filename prints contents of one file.\n"
+ " ./kziptest update file.zip filename updates contents of one file.\n"
+ " ./kziptest transfer file.zip newfile.zip complete transfer.\n"
+ " ./kziptest iodevice /path/to/existing_file.zip tests KArchiveFile::device()\n");
+ return 1;
+ }
+ TDEInstance instance("kziptest");
+ TQString command = argv[1];
+ if ( command == "list" )
+ {
+ KZip zip( argv[2] );
+
+ if ( !zip.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+
+ const KArchiveDirectory* dir = zip.directory();
+
+ //printf("calling recursive_print\n");
+ recursive_print( dir, "" );
+ //printf("recursive_print called\n");
+
+ zip.close();
+
+ return 0;
+ }
+ else if (command == "readwrite" )
+ {
+ KZip zip( argv[2] );
+
+ if ( !zip.open( IO_WriteOnly ) )
+ {
+ printf("Could not open %s for writing\n", argv[2]);
+ return 1;
+ }
+
+ zip.setCompression( KZip::NoCompression );
+ zip.writeFile( "typeid", "", "", 19, "application/x-kword" );
+ zip.setCompression( KZip::DeflateCompression );
+ zip.writeFile( "empty", "weis", "users", 0, "" );
+ zip.writeFile( "test1", "weis", "users", 5, "Hallo" );
+ zip.writeFile( "test2", "weis", "users", 8, "Hallo Du" );
+ zip.writeFile( "mydir/test3", "weis", "users", 13, "Noch so einer" );
+ zip.writeFile( "my/dir/test3", "dfaure", "hackers", 29, "I don't speak German (David)" );
+ zip.writeSymLink( "a_link", "mydir/test3", "leo", "leo", 0120777,
+ 1000000000l, 1000000000l, 1000000000l);
+
+#define SIZE1 100
+ // Now a medium file : 100 null bytes
+ char medium[ SIZE1 ];
+ memset( medium, 0, SIZE1 );
+ zip.writeFile( "mediumfile", "user", "group", SIZE1, medium );
+ // Another one, with an absolute path
+ zip.writeFile( "/dir/subdir/mediumfile2", "user", "group", SIZE1, medium );
+
+ // Now a huge file : 20000 null bytes
+ int n = 20000;
+ char * huge = new char[ n ];
+ memset( huge, 0, n );
+ zip.writeFile( "hugefile", "user", "group", n, huge );
+ delete [] huge;
+
+ // Now a file from the harddisk
+ zip.addLocalFile( ".libs/lt-kziptest", "lt-kziptest" );
+
+ printf( "calling close\n" );
+
+ zip.close();
+
+ printf("-----------------------\n");
+
+ if ( !zip.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+
+ const KArchiveDirectory* dir = zip.directory();
+ recursive_print(dir, "");
+
+ const KArchiveEntry* e = dir->entry( "mydir/test3" );
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+
+ TQByteArray arr( f->data() );
+ Q_ASSERT( arr.size() == 13 );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+ Q_ASSERT( str == "Noch so einer" );
+ printf("DATA=%s\n", str.latin1());
+
+ e = dir->entry( "mediumfile" );
+ Q_ASSERT( e && e->isFile() );
+ f = (KArchiveFile*)e;
+ Q_ASSERT( f->data().size() == SIZE1 );
+
+ e = dir->entry( "hugefile" );
+ Q_ASSERT( e && e->isFile() );
+ f = (KArchiveFile*)e;
+ Q_ASSERT( f->data().size() == 20000 );
+
+ zip.close();
+
+ return 0;
+ }
+ else if ( command == "maxlength" )
+ {
+ KZip zip( argv[2] );
+
+ if ( !zip.open( IO_WriteOnly ) )
+ {
+ printf("Could not open %s for writing\n", argv[2]);
+ return 1;
+ }
+ // Generate long filenames of each possible length bigger than 98...
+ for (int i = 98; i < 500 ; i++ )
+ {
+ TQString str, num;
+ str.fill( 'a', i-10 );
+ num.setNum( i );
+ num = num.rightJustify( 10, '0' );
+ zip.writeFile( str+num, "testu", "testg", 3, "hum" );
+ }
+ // Result of this test : it fails at 482 (instead of 154 previously).
+ // Ok, I think we can do with that :)
+ zip.close();
+ printf("Now run 'unzip -l %s'\n", argv[2]);
+ return 0;
+ }
+ else if ( command == "iodevice" )
+ {
+ KZip zip( argv[2] );
+ if ( !zip.open( IO_ReadOnly ) )
+ return 1;
+ const KArchiveDirectory* dir = zip.directory();
+ assert(dir);
+ const KArchiveEntry* entry = dir->entry( "my/dir/test3" );
+ if ( entry && entry->isFile() )
+ {
+ TQIODevice *dev = static_cast<const KZipFileEntry *>(entry)->device();
+ if ( dev ) {
+ TQByteArray contents = dev->readAll();
+ printf("contents='%s'\n", TQCString(contents, contents.size()+1).data());
+ }
+ } else
+ printf("entry=%p - not found if 0, otherwise not a file\n", (void*)entry);
+ return 0;
+ }
+ else if (command == "print" )
+ {
+ KZip zip( argv[2] );
+ kdDebug() << "Opening zip file" << endl;
+ if ( !zip.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+ const KArchiveDirectory* dir = zip.directory();
+ kdDebug() << "Listing toplevel of zip file" << endl;
+ TQStringList l = dir->entries();
+ TQStringList::Iterator it = l.begin();
+ for( ; it != l.end(); ++it )
+ {
+ const KArchiveEntry* e = dir->entry( (*it) );
+ kdDebug() << "Printing " << (*it) << endl;
+ if (e->isFile())
+ {
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+
+ TQByteArray arr( f->data() );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+ printf("DATA=%s\n", str.latin1());
+ }
+ }
+ zip.close();
+ return 0;
+ }
+ else if (command == "print2" )
+ {
+ if (argc != 4)
+ {
+ printf("usage: kziptest print2 archivename filename");
+ return 1;
+ }
+ KZip zip( argv[2] );
+ if ( !zip.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+ const KArchiveDirectory* dir = zip.directory();
+ const KArchiveEntry* e = dir->entry( argv[3] );
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+
+ TQByteArray arr( f->data() );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+// printf("DATA=%s\n", str.latin1());
+ printf("%s", str.latin1());
+ zip.close();
+
+ return 0;
+
+ }
+ else if (command == "update" )
+ {
+ if (argc != 4)
+ {
+ printf("usage: kziptest update archivename filename");
+ return 1;
+ }
+ KZip zip( argv[2] );
+ if ( !zip.open( IO_ReadWrite ) )
+ {
+ printf("Could not open %s for read/write\n", argv[2] );
+ return 1;
+ }
+ const KArchiveEntry* e = zip.directory()->entry( argv[3] );
+// Q_ASSERT( e && e->isFile() );
+// const KArchiveFile* f = (KArchiveFile*)e;
+
+// TQCString data( "This is some new data that goes into " );
+ // data += argv[3];
+ TQFile f ( argv[3] );
+ if (!f.open( IO_ReadOnly ))
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+
+ TQDataStream s( &f );
+
+
+// zip.writeFile( argv[3], "", "", data.size(), data.data() );
+ zip.writeFile( argv[3], "", "", f.size(), f.readAll() );
+ zip.close();
+
+ return 0;
+
+ }
+ else if (command == "transfer" )
+ {
+ if (argc != 4)
+ {
+ printf("usage: kziptest transfer sourcefile destfile");
+ return 1;
+ }
+ KZip zip1( argv[2] );
+ KZip zip2( argv[3] );
+ if ( !zip1.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+ if ( !zip2.open( IO_WriteOnly ) )
+ {
+ printf("Could not open %s for writing\n", argv[3] );
+ return 1;
+ }
+ const KArchiveDirectory* dir1 = zip1.directory();
+
+ recursive_transfer(dir1, "", &zip2 );
+
+ zip1.close();
+ zip2.close();
+
+/*
+ zip.writeFile( "empty", "weis", "users", 0, "" );
+ zip.writeFile( "test1", "weis", "users", 5, "Hallo" );
+ zip.writeFile( "test2", "weis", "users", 8, "Hallo Du" );
+ zip.writeFile( "mydir/test3", "weis", "users", 13, "Noch so einer" );
+ zip.writeFile( "my/dir/test3", "dfaure", "hackers", 29, "I don't speak German (David)" );
+
+#define SIZE1 100
+ // Now a medium file : 100 null bytes
+ char medium[ SIZE1 ];
+ memset( medium, 0, SIZE1 );
+ zip.writeFile( "mediumfile", "user", "group", SIZE1, medium );
+ // Another one, with an absolute path
+ zip.writeFile( "/dir/subdir/mediumfile2", "user", "group", SIZE1, medium );
+
+ // Now a huge file : 20000 null bytes
+ int n = 20000;
+ char * huge = new char[ n ];
+ memset( huge, 0, n );
+ zip.writeFile( "hugefile", "user", "group", n, huge );
+ delete [] huge;
+
+ zip.close();
+
+ printf("-----------------------\n");
+
+ if ( !zip.open( IO_ReadOnly ) )
+ {
+ printf("Could not open %s for reading\n", argv[2] );
+ return 1;
+ }
+
+ const KArchiveDirectory* dir = zip.directory();
+ recursive_print(dir, "");
+
+ const KArchiveEntry* e = dir->entry( "mydir/test3" );
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+
+ TQByteArray arr( f->data() );
+ printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+ printf("DATA=%s\n", str.latin1());
+
+ zip.close();
+
+ return 0;
+
+
+
+
+
+ const KArchiveEntry* e = dir1->entry( argv[3] );
+ Q_ASSERT( e && e->isFile() );
+ const KArchiveFile* f = (KArchiveFile*)e;
+
+ TQByteArray arr( f->data() );
+// printf("SIZE=%i\n",arr.size() );
+ TQString str( arr );
+// printf("DATA=%s\n", str.latin1());
+ printf("%s", str.latin1());
+ zip.close();
+
+*/
+ return 0;
+
+ }
+ else
+ printf("Unknown command\n");
+}
diff --git a/tdeio/tests/metatest.cpp b/tdeio/tests/metatest.cpp
new file mode 100644
index 000000000..ee1d38201
--- /dev/null
+++ b/tdeio/tests/metatest.cpp
@@ -0,0 +1,321 @@
+#include <kapplication.h>
+#include <tdefilemetainfo.h>
+#include <kcmdlineargs.h>
+#include <tqstringlist.h>
+#include <tqimage.h>
+#include <kdebug.h>
+#include <tqlabel.h>
+#include <tqvalidator.h>
+
+#define I18N_NOOP
+
+ static KCmdLineOptions options[] =
+ {
+ { "+file", "File name", 0 },
+ { "addgroup ", "Add a group to a file", 0},
+ { "removegroup ", "Remove a group from a file", 0},
+ { "removeitem ", "Remove the item from --group from a file", 0},
+ { "group ", "Specify a group to work on", 0},
+ { "validator", "Create a validator for an item and show its class", 0},
+ { "item ", "Specify an item to work on", 0},
+ { "add ", "Add the --item to the --group and set the value", 0},
+ { "autogroupadd", "Automatically add a group if none is found", 0},
+ { "set ", "Set the value of --item in --group", 0},
+ { "groups", "list the groups of this file", 0 },
+ { "mimetypeinfo ", "the mimetype info for a mimetype", 0 },
+ KCmdLineLastOption
+ };
+
+void printKeyValues(KFileMetaInfo& info)
+{
+ TQStringList l = info.preferredKeys();
+ kdDebug() << "found " << l.size() << " keys\n";
+
+ TQString s;
+ TQStringList::Iterator it;
+ for (it = l.begin(); it!=l.end(); ++it)
+ {
+ s +=" - " + *it;
+ }
+ kdDebug() << "keys: " << s << endl;
+
+ for (it = l.begin(); it!=l.end(); ++it)
+ {
+ KFileMetaInfoItem item = info.item(*it);
+ if ( item.isValid() && item.value().canCast(TQVariant::String)) {
+ kdDebug() << item.key() << "(" << item.translatedKey() << ") -> "
+ << item.string() << endl;
+ }
+ }
+}
+
+void printMimeTypeInfo(TQString mimetype)
+{
+ const KFileMimeTypeInfo* info = KFileMetaInfoProvider::self()->mimeTypeInfo(mimetype);
+
+ if (!info) return;
+ kdDebug() << "Preferred groups:\n";
+ kdDebug() << "=================\n";
+ TQStringList groups = info->preferredGroups();
+
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ {
+ kdDebug() << *it << endl;
+ }
+
+ kdDebug() << endl;
+ kdDebug() << "Supported groups:\n";
+ kdDebug() << "=================\n";
+ groups = info->supportedGroups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ {
+ kdDebug() << *it << endl;
+ }
+
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ {
+ const KFileMimeTypeInfo::GroupInfo* groupinfo = info->groupInfo(*it);
+
+ kdDebug() << endl;
+ kdDebug() << "Group \"" << *it << "\"\n";
+ kdDebug() << "==================\n";
+
+ if (!groupinfo) kdDebug() << "argh! no group info\n";
+
+ kdDebug() << endl;
+ kdDebug() << " Supported keys:\n";
+ TQStringList keys = groupinfo->supportedKeys();
+ if (!keys.count()) kdDebug() << " none\n";
+ for (TQStringList::Iterator kit=keys.begin(); kit!=keys.end(); ++kit)
+ {
+ kdDebug() << " " << *kit << endl;
+
+ const KFileMimeTypeInfo::ItemInfo* iti = groupinfo->itemInfo(*kit);
+ kdDebug() << " Key: " << iti->key() << endl;
+ kdDebug() << " Translated: " << iti->key() << endl;
+ kdDebug() << " Type: " << TQVariant::typeToName(iti->type()) << endl;
+ kdDebug() << " Unit: " << iti->unit() << endl;
+ kdDebug() << " Hint: " << iti->hint() << endl;
+ kdDebug() << " Attributes: " << iti->attributes() << endl;
+ kdDebug() << " Prefix: " << iti->prefix() << endl;
+ kdDebug() << " Suffix: " << iti->suffix() << endl;
+ }
+
+ kdDebug() << " name: " << groupinfo->name() << endl;
+ kdDebug() << " translated: " << groupinfo->translatedName() << endl;
+ kdDebug() << " attributes: " << groupinfo->attributes() << endl;
+ kdDebug() << " variable keys: " << (groupinfo->supportsVariableKeys() ? "Yes" : "No") << endl;
+ if (groupinfo->supportsVariableKeys())
+ {
+ const KFileMimeTypeInfo::ItemInfo* iti = groupinfo->variableItemInfo();
+ kdDebug() << " variable key type/attr: " << TQVariant::typeToName(iti->type()) << " / " << iti->attributes() << endl;
+ }
+ }
+
+ kdDebug() << endl;
+ kdDebug() << "Preferred keys:\n";
+ kdDebug() << "===============\n";
+ TQStringList prefKeys = info->preferredKeys();
+ if (!prefKeys.count()) kdDebug() << " none\n";
+ for (TQStringList::Iterator kit=prefKeys.begin(); kit!=prefKeys.end(); ++kit)
+ {
+ kdDebug() << *kit << endl;
+ }
+
+ kdDebug() << endl;
+ kdDebug() << "Supported keys:\n";
+ kdDebug() << "===============\n";
+ TQStringList supKeys = info->supportedKeys();
+ if (!supKeys.count()) kdDebug() << " none\n";
+ for (TQStringList::Iterator kit=supKeys.begin(); kit!=supKeys.end(); ++kit)
+ {
+ kdDebug() << *kit << endl;
+ }
+}
+
+void addGroup(KFileMetaInfo& info, TQString group)
+{
+ kdDebug() << "trying to add group " << group << endl;
+
+ kdDebug() << "groups before: \n";
+ TQStringList groups = info.groups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ kdDebug() << " " << *it << endl;
+
+ if (info.addGroup(group))
+ kdDebug() << "addGroup succeeded\n";
+ else
+ kdDebug() << "addGroup failed\n";
+
+ kdDebug() << "trying another addGroup to see what happens\n";
+
+ if (info.addGroup(group))
+ kdDebug() << "addGroup succeeded\n";
+ else
+ kdDebug() << "addGroup failed\n";
+
+
+ kdDebug() << "and afterwards: \n";
+ groups = info.groups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ kdDebug() << " " << *it << endl;
+}
+
+void removeGroup(KFileMetaInfo& info, TQString group)
+{
+ kdDebug() << "trying to remove group " << group << endl;
+
+ kdDebug() << "groups before: \n";
+ TQStringList groups = info.groups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ kdDebug() << " " << *it << endl;
+
+ info.removeGroup(group);
+
+ kdDebug() << "and afterwards: \n";
+ groups = info.groups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ kdDebug() << " " << *it << endl;
+}
+
+int main( int argc, char **argv )
+{
+ // Initialize command line args
+ TDECmdLineArgs::init(argc, argv, "tdefilemetatest", "testing kfilmetainfo", "X");
+
+ // Tell which options are supported
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ // Add options from other components
+ TDEApplication::addCmdLineOptions();
+
+ TDEApplication app;
+
+ TDECmdLineArgs* args = TDECmdLineArgs::parsedArgs();
+
+ TQCString ov;
+ ov = args->getOption("mimetypeinfo");
+ if (ov)
+ {
+ printMimeTypeInfo(ov);
+ return 0;
+ }
+
+ if (!args->count()) return 1;
+
+ KFileMetaInfo info( args->url(0), TQString::null, KFileMetaInfo::Everything);
+
+ if (args->isSet("groups"))
+ {
+ TQStringList groups = info.groups();
+ for (TQStringList::Iterator it=groups.begin() ; it!=groups.end(); ++it)
+ {
+ kdDebug() << "group " << *it << endl;
+ }
+ return 0;
+ }
+
+ TQString group, item;
+
+ ov = args->getOption("addgroup");
+ if (ov) addGroup(info, ov);
+
+ ov = args->getOption("removegroup");
+ if (ov) removeGroup(info, ov);
+
+ ov = args->getOption("group");
+ if (ov) group = ov;
+
+ ov = args->getOption("item");
+ if (ov) item = ov;
+
+ ov = args->getOption("add");
+ if (ov && !group.isNull() && !item.isNull())
+ {
+ KFileMetaInfoGroup g = info[group];
+ if (!g.isValid() && args->isSet("autogroupadd"))
+ {
+ kdDebug() << "group is not there, adding it\n";
+ info.addGroup(group);
+ }
+ // add the item
+ KFileMetaInfoItem i = info[group].addItem(item);
+ if (i.isValid())
+ kdDebug() << "additem success\n";
+ else
+ kdDebug() << "additem failed\n";
+
+ if (i.setValue(ov))
+ kdDebug() << "setValue success\n";
+ else
+ kdDebug() << "setValue failed\n";
+ }
+
+ ov = args->getOption("set");
+ if (ov && !group.isNull() && !item.isNull())
+ {
+ if (info[group][item].setValue(TQString(ov)))
+ kdDebug() << "setValue success\n";
+ else
+ kdDebug() << "setValue failed\n";
+ }
+
+ ov = args->getOption("removeitem");
+ if (ov && !group.isNull())
+ {
+ if (info[group].removeItem(ov))
+ kdDebug() << "removeitem success\n";
+ else
+ kdDebug() << "removeitem failed\n";
+ }
+
+ if (args->isSet("validator") && !group.isNull() && !item.isNull())
+ {
+ const KFileMimeTypeInfo* kfmti = KFileMetaInfoProvider::self()->mimeTypeInfo(info.mimeType());
+ TQValidator* v = kfmti->createValidator(group, item);
+ if (!v)
+ kdDebug() << "got no validator\n";
+ else
+ {
+ kdDebug() << "validator is a " << v->className() << endl;
+ delete v;
+ }
+
+ }
+
+ kdDebug() << "is it valid?\n";
+
+ if (!info.isValid()) return 1;
+
+ kdDebug() << "it is!\n";
+
+ printKeyValues(info);
+
+
+ kdDebug() << "========= again after applyChanges() =========\n";
+
+ info.applyChanges();
+
+ printKeyValues(info);
+
+ KFileMetaInfoItem thumbitem = info.item(KFileMimeTypeInfo::Thumbnail);
+// KFileMetaInfoItem thumbitem = info.item("Thumbnail");
+
+ if (!thumbitem.isValid()) kdDebug() << "no thumbnail\n";
+ else
+ kdDebug() << "type of thumbnail is " << thumbitem.value().typeName() << endl;
+
+
+ if (thumbitem.isValid() && thumbitem.value().canCast(TQVariant::Image))
+ {
+ TQLabel* label = new TQLabel(0);
+ app.setMainWidget(label);
+ TQPixmap pix;
+ pix.convertFromImage(thumbitem.value().toImage());
+ label->setPixmap(pix);
+ label->show();
+ app.exec();
+ }
+
+ return 0;
+}
diff --git a/tdeio/tests/netaccesstest.cpp b/tdeio/tests/netaccesstest.cpp
new file mode 100644
index 000000000..1a5de205d
--- /dev/null
+++ b/tdeio/tests/netaccesstest.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004 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 <kapplication.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <tdeio/netaccess.h>
+#include <tqfile.h>
+
+int main(int argc, char **argv)
+{
+ TDEApplication app( argc, argv, "netaccesstest", true /* it _has_ a GUI ! */);
+
+ KURL srcURL( "ftp://ftp.kde.org/pub/kde/README" );
+ KURL tmpURL( "file:/tmp/netaccesstest_README" );
+
+ for ( uint i = 0; i < 4 ; ++i ) {
+ kdDebug() << "file_copy" << endl;
+ if ( !TDEIO::NetAccess::file_copy(srcURL, tmpURL, -1, true, false, 0) )
+ kdError() << "file_copy failed: " << TDEIO::NetAccess::lastErrorString() << endl;
+ else {
+ TQFile f( tmpURL.path() );
+ if (!f.open(IO_ReadOnly))
+ kdFatal() << "Cannot open: " << f.name() << ". The error was: " << f.errorString() << endl;
+ else {
+ f.close();
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/tdeio/tests/previewtest.cpp b/tdeio/tests/previewtest.cpp
new file mode 100644
index 000000000..87bdd326d
--- /dev/null
+++ b/tdeio/tests/previewtest.cpp
@@ -0,0 +1,64 @@
+
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klineedit.h>
+
+#include <tdeio/previewjob.h>
+
+#include "previewtest.moc"
+
+PreviewTest::PreviewTest()
+ :TQWidget()
+{
+ TQGridLayout *layout = new TQGridLayout(this, 2, 2);
+ m_url = new KLineEdit(this);
+ m_url->setText("/home/malte/gore_bush.jpg");
+ layout->addWidget(m_url, 0, 0);
+ TQPushButton *btn = new TQPushButton("Generate", this);
+ connect(btn, TQT_SIGNAL(clicked()), TQT_SLOT(slotGenerate()));
+ layout->addWidget(btn, 0, 1);
+ m_preview = new TQLabel(this);
+ m_preview->setMinimumSize(400, 300);
+ layout->addMultiCellWidget(m_preview, 1, 1, 0, 1);
+}
+
+void PreviewTest::slotGenerate()
+{
+ KURL::List urls;
+ urls.append(m_url->text());
+ TDEIO::PreviewJob *job = TDEIO::filePreview(urls, m_preview->width(), m_preview->height(), true, 48);
+ connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotResult(TDEIO::Job*)));
+ connect(job, TQT_SIGNAL(gotPreview(const KFileItem *, const TQPixmap &)), TQT_SLOT(slotPreview(const KFileItem *, const TQPixmap &)));
+ connect(job, TQT_SIGNAL(failed(const KFileItem *)), TQT_SLOT(slotFailed()));
+}
+
+void PreviewTest::slotResult(TDEIO::Job*)
+{
+ kdDebug() << "PreviewTest::slotResult(...)" << endl;
+}
+
+void PreviewTest::slotPreview(const KFileItem *, const TQPixmap &pix)
+{
+ kdDebug() << "PreviewTest::slotPreview()" << endl;
+ m_preview->setPixmap(pix);
+}
+
+void PreviewTest::slotFailed()
+{
+ kdDebug() << "PreviewTest::slotFailed()" << endl;
+ m_preview->setText("failed");
+}
+
+int main(int argc, char **argv)
+{
+ TDEApplication app(argc, argv, "previewtest");
+ PreviewTest *w = new PreviewTest;
+ w->show();
+ app.setMainWidget(w);
+ return app.exec();
+}
+
diff --git a/tdeio/tests/previewtest.h b/tdeio/tests/previewtest.h
new file mode 100644
index 000000000..5ef82916d
--- /dev/null
+++ b/tdeio/tests/previewtest.h
@@ -0,0 +1,25 @@
+
+#include <tqwidget.h>
+#include <tdeio/job.h>
+
+class KLineEdit;
+class TQLabel;
+class KFileItem;
+
+class PreviewTest : public TQWidget
+{
+ Q_OBJECT
+public:
+ PreviewTest();
+
+private slots:
+ void slotGenerate();
+ void slotResult(TDEIO::Job *);
+ void slotPreview( const KFileItem *, const TQPixmap & );
+ void slotFailed();
+
+private:
+ KLineEdit *m_url;
+ TQLabel *m_preview;
+};
+
diff --git a/tdeio/tests/speed.cpp b/tdeio/tests/speed.cpp
new file mode 100644
index 000000000..978845669
--- /dev/null
+++ b/tdeio/tests/speed.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2002, 2003 Stephan Kulow <coolo@kde.org>
+ * Copyright (C) 2003 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 <kdebug.h>
+#include <kapplication.h>
+#include <time.h>
+#include "speed.h"
+#include <tdeio/job.h>
+#include <kcmdlineargs.h>
+#include <tqdir.h>
+#include <tdeio/global.h>
+
+using namespace TDEIO;
+
+SpeedTest::SpeedTest( const KURL & url )
+ : TQObject(0, "speed")
+{
+ Job *job = listRecursive( url );
+ //Job *job = del( KURL("file:" + TQDir::currentDirPath()) ); DANGEROUS !
+ connect(job, TQT_SIGNAL( result( TDEIO::Job*)),
+ TQT_SLOT( finished( TDEIO::Job* ) ));
+ /*connect(job, TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)),
+ TQT_SLOT( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)));
+ */
+}
+
+void SpeedTest::entries(TDEIO::Job*, const UDSEntryList& list) {
+
+ UDSEntryListConstIterator it=list.begin();
+ for (; it != list.end(); ++it) {
+ UDSEntry::ConstIterator it2 = (*it).begin();
+ for( ; it2 != (*it).end(); it2++ ) {
+ if ((*it2).m_uds == UDS_NAME)
+ kdDebug() << ( *it2 ).m_str << endl;
+ }
+ }
+}
+
+
+void SpeedTest::finished(Job*) {
+ kdDebug() << "job finished" << endl;
+ kapp->quit();
+}
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", "the URL to list", 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv) {
+
+ TDECmdLineArgs::init( argc, argv, "speedapp", "A TDEIO::listRecursive testing tool", "0.0" );
+
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app;
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ KURL url;
+ if ( args->count() == 1 )
+ url = args->url(0);
+ else
+ url = "file:" + TQDir::currentDirPath();
+
+ kdDebug() << url.url() << " is probably " << (TDEIO::probably_slow_mounted(url.path()) ? "slow" : "normal") << " mounted\n";
+ kdDebug() << url.url() << " is " << (TDEIO::manually_mounted(url.path()) ? "manually" : "system") << " mounted\n";
+ TQString mp = TDEIO::findDeviceMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for device " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for device " << url.url() << endl;
+
+ mp = TDEIO::findPathMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for path " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for path " << url.url() << endl;
+ // SpeedTest test( url );
+ // app.exec();
+
+ mp = TDEIO::findPathMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for path " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for path " << url.url() << endl;
+ // SpeedTest test( url );
+ // app.exec();
+
+ url.setPath(TQDir::homeDirPath());
+
+ mp = TDEIO::findPathMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for path " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for path " << url.url() << endl;
+ // SpeedTest test( url );
+ // app.exec();
+
+ mp = TDEIO::findPathMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for path " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for path " << url.url() << endl;
+ // SpeedTest test( url );
+ // app.exec();
+
+ if ( args->count() == 1 )
+ url = args->url(0);
+ else
+ url = "file:" + TQDir::currentDirPath();
+
+ mp = TDEIO::findPathMountPoint(url.path());
+ if (mp.isEmpty()) {
+ kdDebug() << "no mount point for path " << url.url() << " found\n";
+ } else
+ kdDebug() << mp << " is the mount point for path " << url.url() << endl;
+ // SpeedTest test( url );
+ // app.exec();
+
+}
+
+#include "speed.moc"
diff --git a/tdeio/tests/speed.h b/tdeio/tests/speed.h
new file mode 100644
index 000000000..d7801ae47
--- /dev/null
+++ b/tdeio/tests/speed.h
@@ -0,0 +1,24 @@
+// -*- c++ -*-
+#ifndef _SPEED_H
+#define _SPEED_H
+
+#include <tdeio/global.h>
+#include <kurl.h>
+
+namespace TDEIO {
+ class Job;
+}
+
+class SpeedTest : public TQObject {
+ Q_OBJECT
+
+public:
+ SpeedTest(const KURL & url);
+
+private slots:
+ void entries( TDEIO::Job *, const TDEIO::UDSEntryList& );
+ void finished( TDEIO::Job *job );
+
+};
+
+#endif
diff --git a/tdeio/tests/tdeioslavetest.cpp b/tdeio/tests/tdeioslavetest.cpp
new file mode 100644
index 000000000..5fa19073c
--- /dev/null
+++ b/tdeio/tests/tdeioslavetest.cpp
@@ -0,0 +1,555 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ Copyright 1999 Matt Koss <koss@miesto.sk>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#include <tqlayout.h>
+#include <tqmessagebox.h>
+#include <tqdir.h>
+
+#include <kacl.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kstatusbar.h>
+#include <tdeio/job.h>
+#include <tdeio/scheduler.h>
+#include <kprotocolinfo.h>
+
+#include "tdeioslavetest.h"
+
+using namespace TDEIO;
+
+KioslaveTest::KioslaveTest( TQString src, TQString dest, uint op, uint pr )
+ : KMainWindow(0, "")
+{
+
+ job = 0L;
+
+ main_widget = new TQWidget( this, "");
+ TQBoxLayout *topLayout = new TQVBoxLayout( main_widget, 10, 5 );
+
+ TQGridLayout *grid = new TQGridLayout( 2, 2, 10 );
+ topLayout->addLayout( grid );
+
+ grid->setRowStretch(0,1);
+ grid->setRowStretch(1,1);
+
+ grid->setColStretch(0,1);
+ grid->setColStretch(1,100);
+
+ lb_from = new TQLabel( "From:", main_widget );
+ grid->addWidget( lb_from, 0, 0 );
+
+ le_source = new TQLineEdit( main_widget );
+ grid->addWidget( le_source, 0, 1 );
+ le_source->setText( src );
+
+ lb_to = new TQLabel( "To:", main_widget );
+ grid->addWidget( lb_to, 1, 0 );
+
+ le_dest = new TQLineEdit( main_widget );
+ grid->addWidget( le_dest, 1, 1 );
+ le_dest->setText( dest );
+
+ // Operation groupbox & buttons
+ opButtons = new TQButtonGroup( "Operation", main_widget );
+ topLayout->addWidget( opButtons, 10 );
+ connect( opButtons, TQT_SIGNAL(clicked(int)), TQT_SLOT(changeOperation(int)) );
+
+ TQBoxLayout *hbLayout = new TQHBoxLayout( opButtons, 15 );
+
+ rbList = new TQRadioButton( "List", opButtons );
+ opButtons->insert( rbList, List );
+ hbLayout->addWidget( rbList, 5 );
+
+ rbListRecursive = new TQRadioButton( "ListRecursive", opButtons );
+ opButtons->insert( rbListRecursive, ListRecursive );
+ hbLayout->addWidget( rbListRecursive, 5 );
+
+ rbStat = new TQRadioButton( "Stat", opButtons );
+ opButtons->insert( rbStat, Stat );
+ hbLayout->addWidget( rbStat, 5 );
+
+ rbGet = new TQRadioButton( "Get", opButtons );
+ opButtons->insert( rbGet, Get );
+ hbLayout->addWidget( rbGet, 5 );
+
+ rbPut = new TQRadioButton( "Put", opButtons );
+ opButtons->insert( rbPut, Put );
+ hbLayout->addWidget( rbPut, 5 );
+
+ rbCopy = new TQRadioButton( "Copy", opButtons );
+ opButtons->insert( rbCopy, Copy );
+ hbLayout->addWidget( rbCopy, 5 );
+
+ rbMove = new TQRadioButton( "Move", opButtons );
+ opButtons->insert( rbMove, Move );
+ hbLayout->addWidget( rbMove, 5 );
+
+ rbDelete = new TQRadioButton( "Delete", opButtons );
+ opButtons->insert( rbDelete, Delete );
+ hbLayout->addWidget( rbDelete, 5 );
+
+ rbShred = new TQRadioButton( "Shred", opButtons );
+ opButtons->insert( rbShred, Shred );
+ hbLayout->addWidget( rbShred, 5 );
+
+ rbMkdir = new TQRadioButton( "Mkdir", opButtons );
+ opButtons->insert( rbMkdir, Mkdir );
+ hbLayout->addWidget( rbMkdir, 5 );
+
+ rbMimetype = new TQRadioButton( "Mimetype", opButtons );
+ opButtons->insert( rbMimetype, Mimetype );
+ hbLayout->addWidget( rbMimetype, 5 );
+
+ opButtons->setButton( op );
+ changeOperation( op );
+
+ // Progress groupbox & buttons
+ progressButtons = new TQButtonGroup( "Progress dialog mode", main_widget );
+ topLayout->addWidget( progressButtons, 10 );
+ connect( progressButtons, TQT_SIGNAL(clicked(int)), TQT_SLOT(changeProgressMode(int)) );
+
+ hbLayout = new TQHBoxLayout( progressButtons, 15 );
+
+ rbProgressNone = new TQRadioButton( "None", progressButtons );
+ progressButtons->insert( rbProgressNone, ProgressNone );
+ hbLayout->addWidget( rbProgressNone, 5 );
+
+ rbProgressDefault = new TQRadioButton( "Default", progressButtons );
+ progressButtons->insert( rbProgressDefault, ProgressDefault );
+ hbLayout->addWidget( rbProgressDefault, 5 );
+
+ rbProgressStatus = new TQRadioButton( "Status", progressButtons );
+ progressButtons->insert( rbProgressStatus, ProgressStatus );
+ hbLayout->addWidget( rbProgressStatus, 5 );
+
+ progressButtons->setButton( pr );
+ changeProgressMode( pr );
+
+ // statusbar progress widget
+ statusProgress = new StatusbarProgress( statusBar() );
+ statusBar()->addWidget( statusProgress, 0, true );
+
+ // run & stop butons
+ hbLayout = new TQHBoxLayout( topLayout, 15 );
+
+ pbStart = new TQPushButton( "&Start", main_widget );
+ pbStart->setFixedSize( pbStart->sizeHint() );
+ connect( pbStart, TQT_SIGNAL(clicked()), TQT_SLOT(startJob()) );
+ hbLayout->addWidget( pbStart, 5 );
+
+ pbStop = new TQPushButton( "Sto&p", main_widget );
+ pbStop->setFixedSize( pbStop->sizeHint() );
+ pbStop->setEnabled( false );
+ connect( pbStop, TQT_SIGNAL(clicked()), TQT_SLOT(stopJob()) );
+ hbLayout->addWidget( pbStop, 5 );
+
+ // close button
+ close = new TQPushButton( "&Close", main_widget );
+ close->setFixedSize( close->sizeHint() );
+ connect(close, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotQuit()));
+
+ topLayout->addWidget( close, 5 );
+
+ main_widget->setMinimumSize( main_widget->sizeHint() );
+ setCentralWidget( main_widget );
+
+ slave = 0;
+// slave = TDEIO::Scheduler::getConnectedSlave(KURL("ftp://ftp.kde.org"));
+ TDEIO::Scheduler::connect(TQT_SIGNAL(slaveConnected(TDEIO::Slave*)),
+ this, TQT_SLOT(slotSlaveConnected()));
+ TDEIO::Scheduler::connect(TQT_SIGNAL(slaveError(TDEIO::Slave*,int,const TQString&)),
+ this, TQT_SLOT(slotSlaveError()));
+}
+
+
+void KioslaveTest::closeEvent( TQCloseEvent * ){
+ slotQuit();
+}
+
+
+void KioslaveTest::slotQuit(){
+ if ( job ) {
+ job->kill( true ); // kill the job quietly
+ }
+ if (slave)
+ TDEIO::Scheduler::disconnectSlave(slave);
+ kapp->quit();
+}
+
+
+void KioslaveTest::changeOperation( int id ) {
+ // only two urls for copy and move
+ bool enab = rbCopy->isChecked() || rbMove->isChecked();
+
+ le_dest->setEnabled( enab );
+
+ selectedOperation = id;
+}
+
+
+void KioslaveTest::changeProgressMode( int id ) {
+ progressMode = id;
+
+ if ( progressMode == ProgressStatus ) {
+ statusBar()->show();
+ } else {
+ statusBar()->hide();
+ }
+}
+
+
+void KioslaveTest::startJob() {
+ TQString sCurrent = TQDir::currentDirPath()+"/";
+ KURL::encode_string(sCurrent);
+ TQString sSrc( le_source->text() );
+ KURL src( sCurrent, sSrc );
+
+ if ( !src.isValid() ) {
+ TQMessageBox::critical(this, "Kioslave Error Message", "Source URL is malformed" );
+ return;
+ }
+
+ TQString sDest( le_dest->text() );
+ KURL dest( sCurrent, sDest );
+
+ if ( !dest.isValid() &&
+ ( selectedOperation == Copy || selectedOperation == Move ) ) {
+ TQMessageBox::critical(this, "Kioslave Error Message",
+ "Destination URL is malformed" );
+ return;
+ }
+
+ pbStart->setEnabled( false );
+
+ bool observe = true;
+ if (progressMode != ProgressDefault) {
+ observe = false;
+ }
+
+ SimpleJob *myJob = 0;
+
+ switch ( selectedOperation ) {
+ case List:
+ myJob = TDEIO::listDir( src );
+ connect(myJob, TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)),
+ TQT_SLOT( slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList&)));
+ break;
+
+ case ListRecursive:
+ myJob = TDEIO::listRecursive( src );
+ connect(myJob, TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)),
+ TQT_SLOT( slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList&)));
+ break;
+
+ case Stat:
+ myJob = TDEIO::stat( src, false, 2 );
+ break;
+
+ case Get:
+ myJob = TDEIO::get( src, true );
+ connect(myJob, TQT_SIGNAL( data( TDEIO::Job*, const TQByteArray &)),
+ TQT_SLOT( slotData( TDEIO::Job*, const TQByteArray &)));
+ break;
+
+ case Put:
+ putBuffer = 0;
+ myJob = TDEIO::put( src, -1, true, false);
+ connect(myJob, TQT_SIGNAL( dataReq( TDEIO::Job*, TQByteArray &)),
+ TQT_SLOT( slotDataReq( TDEIO::Job*, TQByteArray &)));
+ break;
+
+ case Copy:
+ job = TDEIO::copy( src, dest, observe );
+ break;
+
+ case Move:
+ job = TDEIO::move( src, dest, observe );
+ break;
+
+ case Delete:
+ job = TDEIO::del( src, false, observe );
+ break;
+
+ case Shred:
+ job = TDEIO::del(src, true, observe);
+ break;
+
+ case Mkdir:
+ myJob = TDEIO::mkdir( src );
+ break;
+
+ case Mimetype:
+ myJob = TDEIO::mimetype( src );
+ break;
+ }
+ if (myJob)
+ {
+ if (slave)
+ TDEIO::Scheduler::assignJobToSlave(slave, myJob);
+ job = myJob;
+ }
+
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+
+ connect( job, TQT_SIGNAL( canceled( TDEIO::Job * ) ),
+ TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+
+ if (progressMode == ProgressStatus) {
+ statusProgress->setJob( job );
+ }
+
+ pbStop->setEnabled( true );
+}
+
+
+void KioslaveTest::slotResult( TDEIO::Job * _job )
+{
+ if ( _job->error() )
+ {
+ _job->showErrorDialog();
+ }
+ else if ( selectedOperation == Stat )
+ {
+ UDSEntry entry = ((TDEIO::StatJob*)_job)->statResult();
+ printUDSEntry( entry );
+ }
+ else if ( selectedOperation == Mimetype )
+ {
+ kdDebug() << "mimetype is " << ((TDEIO::MimetypeJob*)_job)->mimetype() << endl;
+ }
+
+ if (job == _job)
+ job = 0L;
+ pbStart->setEnabled( true );
+ pbStop->setEnabled( false );
+}
+
+void KioslaveTest::slotSlaveConnected()
+{
+ kdDebug() << "Slave connected." << endl;
+}
+
+void KioslaveTest::slotSlaveError()
+{
+ kdDebug() << "Error connected." << endl;
+ slave = 0;
+}
+
+static void printACL( const TQString& acl )
+{
+ KACL kacl( acl );
+ kdDebug() << "According to KACL: " << endl << kacl.asString() << endl;
+ kdDebug() << "Owner: " << kacl.ownerPermissions() << endl;
+ kdDebug() << "Owning group: " << kacl.owningGroupPermissions() << endl;
+ kdDebug() << "Others: " << kacl.othersPermissions() << endl;
+}
+
+
+void KioslaveTest::printUDSEntry( const TDEIO::UDSEntry & entry )
+{
+ TDEIO::UDSEntry::ConstIterator it = entry.begin();
+ for( ; it != entry.end(); it++ ) {
+ switch ((*it).m_uds) {
+ case TDEIO::UDS_FILE_TYPE:
+ kdDebug() << "File Type : " << (mode_t)((*it).m_long) << endl;
+ if ( S_ISDIR( (mode_t)((*it).m_long) ) )
+ {
+ kdDebug() << "is a dir" << endl;
+ }
+ break;
+ case TDEIO::UDS_ACCESS:
+ kdDebug() << "Access permissions : " << (*it).m_long << endl;
+ break;
+ case TDEIO::UDS_EXTENDED_ACL:
+ if( (*it).m_long == 1 )
+ kdDebug() << "Has extended ACL information." << endl;
+ break;
+ case TDEIO::UDS_ACL_STRING:
+ kdDebug() << "ACL: " << ( (*it).m_str.ascii() ) << endl;
+ printACL( (*it).m_str );
+ break;
+ case TDEIO::UDS_DEFAULT_ACL_STRING:
+ kdDebug() << "Default ACL: " << ( (*it).m_str.ascii() ) << endl;
+ printACL( (*it).m_str );
+ break;
+ case TDEIO::UDS_USER:
+ kdDebug() << "User : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case TDEIO::UDS_GROUP:
+ kdDebug() << "Group : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case TDEIO::UDS_NAME:
+ kdDebug() << "Name : " << ((*it).m_str.ascii() ) << endl;
+ //m_strText = decodeFileName( (*it).m_str );
+ break;
+ case TDEIO::UDS_URL:
+ kdDebug() << "URL : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case TDEIO::UDS_MIME_TYPE:
+ kdDebug() << "MimeType : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case TDEIO::UDS_LINK_DEST:
+ kdDebug() << "LinkDest : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case TDEIO::UDS_SIZE:
+ kdDebug() << "Size: " << TDEIO::convertSize((*it).m_long) << endl;
+ break;
+ }
+ }
+}
+
+void KioslaveTest::slotEntries(TDEIO::Job* job, const TDEIO::UDSEntryList& list) {
+
+ KURL url = static_cast<TDEIO::ListJob*>( job )->url();
+ KProtocolInfo::ExtraFieldList extraFields = KProtocolInfo::extraFields(url);
+ UDSEntryListConstIterator it=list.begin();
+ for (; it != list.end(); ++it) {
+ // For each file...
+ KProtocolInfo::ExtraFieldList::Iterator extraFieldsIt = extraFields.begin();
+ UDSEntry::ConstIterator it2 = (*it).begin();
+ for( ; it2 != (*it).end(); it2++ ) {
+ if ((*it2).m_uds == UDS_NAME)
+ kdDebug() << "" << ( *it2 ).m_str << endl;
+ else if ( (*it2).m_uds == UDS_EXTRA) {
+ Q_ASSERT( extraFieldsIt != extraFields.end() );
+ TQString column = (*extraFieldsIt).name;
+ //TQString type = (*extraFieldsIt).type;
+ kdDebug() << " Extra data (" << column << ") :" << ( *it2 ).m_str << endl;
+ ++extraFieldsIt;
+ }
+ }
+ }
+}
+
+void KioslaveTest::slotData(TDEIO::Job*, const TQByteArray &data)
+{
+ if (data.size() == 0)
+ {
+ kdDebug(0) << "Data: <End>" << endl;
+ }
+ else
+ {
+ kdDebug(0) << "Data: \"" << TQCString(data, data.size()+1) << "\"" << endl;
+ }
+}
+
+void KioslaveTest::slotDataReq(TDEIO::Job*, TQByteArray &data)
+{
+ const char *fileDataArray[] =
+ {
+ "Hello world\n",
+ "This is a test file\n",
+ "You can safely delete it.\n",
+ "BIG\n",
+ 0
+ };
+ const char *fileData = fileDataArray[putBuffer++];
+
+ if (!fileData)
+ {
+ kdDebug(0) << "DataReq: <End>" << endl;
+ return;
+ }
+ if (!strcmp(fileData, "BIG\n"))
+ data.fill(0, 29*1024*1024);
+ else
+ data.duplicate(fileData, strlen(fileData));
+ kdDebug(0) << "DataReq: \"" << fileData << "\"" << endl;
+}
+
+void KioslaveTest::stopJob() {
+ kdDebug() << "KioslaveTest::stopJob()" << endl;
+ job->kill();
+ job = 0L;
+
+ pbStop->setEnabled( false );
+ pbStart->setEnabled( true );
+}
+
+static const char version[] = "v0.0.0 0000"; // :-)
+static const char description[] = "Test for tdeioslaves";
+static KCmdLineOptions options[] =
+{
+ { "s", 0, 0 },
+ { "src <src>", "Source URL", "" },
+ { "d", 0, 0 },
+ { "dest <dest>", "Destination URL", "" },
+ { "o", 0, 0 },
+ { "operation <operation>", "Operation (list,listrecursive,stat,get,put,copy,move,del,shred,mkdir)", "copy" },
+ { "p", 0, 0 },
+ { "progress <progress>", "Progress Type (none,default,status)", "default" },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv) {
+ TDECmdLineArgs::init( argc, argv, "tdeioslavetest", description, version );
+ TDECmdLineArgs::addCmdLineOptions( options );
+ TDEApplication app;
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ TQString src = args->getOption("src");
+ TQString dest = args->getOption("dest");
+
+ uint op = 0;
+ uint pr = 0;
+
+ TQString tmps;
+
+ tmps = args->getOption("operation");
+ if ( tmps == "list") {
+ op = KioslaveTest::List;
+ } else if ( tmps == "listrecursive") {
+ op = KioslaveTest::ListRecursive;
+ } else if ( tmps == "stat") {
+ op = KioslaveTest::Stat;
+ } else if ( tmps == "get") {
+ op = KioslaveTest::Get;
+ } else if ( tmps == "put") {
+ op = KioslaveTest::Put;
+ } else if ( tmps == "copy") {
+ op = KioslaveTest::Copy;
+ } else if ( tmps == "move") {
+ op = KioslaveTest::Move;
+ } else if ( tmps == "del") {
+ op = KioslaveTest::Delete;
+ } else if ( tmps == "shred") {
+ op = KioslaveTest::Shred;
+ } else if ( tmps == "mkdir") {
+ op = KioslaveTest::Mkdir;
+ } else TDECmdLineArgs::usage("unknown operation");
+
+ tmps = args->getOption("progress");
+ if ( tmps == "none") {
+ pr = KioslaveTest::ProgressNone;
+ } else if ( tmps == "default") {
+ pr = KioslaveTest::ProgressDefault;
+ } else if ( tmps == "status") {
+ pr = KioslaveTest::ProgressStatus;
+ } else TDECmdLineArgs::usage("unknown progress mode");
+
+ args->clear(); // Free up memory
+
+ KioslaveTest test( src, dest, op, pr );
+ test.show();
+ // Bug in KTMW / Qt / layouts ?
+ test.resize( test.sizeHint() );
+
+ app.setMainWidget(&test);
+ app.exec();
+}
+
+
+#include "tdeioslavetest.moc"
diff --git a/tdeio/tests/tdeioslavetest.h b/tdeio/tests/tdeioslavetest.h
new file mode 100644
index 000000000..f2cb32af1
--- /dev/null
+++ b/tdeio/tests/tdeioslavetest.h
@@ -0,0 +1,108 @@
+ /*
+ This file is or will be part of KDE desktop environment
+
+ Copyright 1999 Matt Koss <koss@miesto.sk>
+
+ It is licensed under GPL version 2.
+
+ If it is part of KDE libraries than this file is licensed under
+ LGPL version 2.
+ */
+
+#ifndef _KIOSLAVETEST_H
+#define _KIOSLAVETEST_H
+
+#include <tqlabel.h>
+#include <tqlineedit.h>
+#include <tqradiobutton.h>
+#include <tqpushbutton.h>
+#include <tqbuttongroup.h>
+#include <tqwidget.h>
+
+#include <kmainwindow.h>
+
+#include "tdeio/job.h"
+#include "tdeio/global.h"
+#include "tdeio/statusbarprogress.h"
+#include "tdeio/slave.h"
+
+class KioslaveTest : public KMainWindow {
+ Q_OBJECT
+
+public:
+ KioslaveTest( TQString src, TQString dest, uint op, uint pr );
+ ~KioslaveTest() {}
+
+ enum Operations { List, ListRecursive, Stat, Get, Put, Copy, Move, Delete, Shred, Mkdir, Mimetype };
+
+ enum ProgressModes { ProgressNone, ProgressDefault, ProgressStatus };
+
+protected:
+
+ void closeEvent( TQCloseEvent * );
+
+ void printUDSEntry( const TDEIO::UDSEntry & entry );
+
+ // info stuff
+ TQLabel *lb_from;
+ TQLineEdit *le_source;
+
+ TQLabel *lb_to;
+ TQLineEdit *le_dest;
+
+ // operation stuff
+ TQButtonGroup *opButtons;
+
+ TQRadioButton *rbList;
+ TQRadioButton *rbListRecursive;
+ TQRadioButton *rbStat;
+ TQRadioButton *rbGet;
+ TQRadioButton *rbPut;
+ TQRadioButton *rbCopy;
+ TQRadioButton *rbMove;
+ TQRadioButton *rbDelete;
+ TQRadioButton *rbShred;
+ TQRadioButton *rbMkdir;
+ TQRadioButton *rbMimetype;
+
+ // progress stuff
+ TQButtonGroup *progressButtons;
+
+ TQRadioButton *rbProgressNone;
+ TQRadioButton *rbProgressDefault;
+ TQRadioButton *rbProgressStatus;
+
+ TQPushButton *pbStart;
+ TQPushButton *pbStop;
+
+ TQPushButton *close;
+
+protected slots:
+ void changeOperation( int id );
+ void changeProgressMode( int id );
+
+ void startJob();
+ void stopJob();
+
+ void slotResult( TDEIO::Job * );
+ void slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList& );
+ void slotData( TDEIO::Job *, const TQByteArray &data );
+ void slotDataReq( TDEIO::Job *, TQByteArray &data );
+
+ void slotQuit();
+ void slotSlaveConnected();
+ void slotSlaveError();
+
+private:
+ TDEIO::Job *job;
+ TQWidget *main_widget;
+
+ TDEIO::StatusbarProgress *statusProgress;
+
+ int selectedOperation;
+ int progressMode;
+ int putBuffer;
+ TDEIO::Slave *slave;
+};
+
+#endif // _KIOSLAVETEST_H
diff --git a/tdeio/tests/tdesycocatest.cpp b/tdeio/tests/tdesycocatest.cpp
new file mode 100644
index 000000000..45f94ac3c
--- /dev/null
+++ b/tdeio/tests/tdesycocatest.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2002, 2003 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 <kdebug.h>
+#include <kuserprofile.h>
+#include <ktrader.h>
+#include <kservice.h>
+#include <kmimetype.h>
+#include <assert.h>
+#include <kstandarddirs.h>
+#include <kservicegroup.h>
+#include <kimageio.h>
+#include <kprotocolinfo.h>
+#include <kiconloader.h>
+
+#include <kapplication.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+bool check(TQString txt, TQString a, TQString b)
+{
+ if (a.isEmpty())
+ a = TQString::null;
+ if (b.isEmpty())
+ b = TQString::null;
+ if (a == b) {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
+ }
+ else {
+ kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl
+;
+ exit(1);
+ }
+ return true;
+}
+
+void debug(TQString txt)
+{
+ fprintf(stderr, "%s\n", txt.ascii());
+}
+
+void debug(const char *txt)
+{
+ fprintf(stderr, "%s\n", txt);
+}
+void debug(const char *format, const char *txt)
+{
+ fprintf(stderr, format, txt);
+ fprintf(stderr, "\n");
+}
+
+int main(int argc, char *argv[])
+{
+ TDEApplication k(argc,argv,"whatever",false/*noGUI*/); // KMessageBox needs KApp for makeStdCaption
+
+ TQCString instname = "kword";
+ TQString desktopPath = TQString::fromLatin1( "Office/%1.desktop" ).arg( instname );
+ tqDebug( "Looking for %s", desktopPath.latin1() );
+ KService::Ptr service = KService::serviceByDesktopPath( desktopPath );
+ if ( service )
+ tqDebug( "found: %s", service->desktopEntryPath().latin1() );
+ else
+ tqDebug( "not found" );
+
+ tqDebug( "Looking for desktop name = %s", instname.data() );
+ service = KService::serviceByDesktopName( instname );
+ if ( service )
+ tqDebug( "found: %s", service->desktopEntryPath().latin1() );
+ else
+ tqDebug( "not found" );
+
+ debug("Trying to look for text/plain");
+ KMimeType::Ptr s1 = KMimeType::mimeType("text/plain");
+ if ( s1 )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(s1->comment(KURL(),false)));
+ }
+ else
+ {
+ debug("Not found !");
+ exit(1);
+ }
+
+ debug("Trying to look for application/x-zerosize");
+ KMimeType::Ptr s0 = KMimeType::mimeType("application/x-zerosize");
+ if ( s0 )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(s0->comment(KURL(),false)));
+ }
+ else
+ {
+ debug("Not found !");
+ exit(1);
+ }
+
+ debug("Trying to look for Desktop Pager");
+ KService::Ptr se = KService::serviceByName("Desktop Pager");
+ if ( se )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(se->comment()));
+ }
+ else
+ {
+ debug("Not found !");
+ }
+
+ debug("Trying to look for kpager");
+ se = KService::serviceByDesktopName("kpager");
+ if ( se )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(se->comment()));
+ TQVariant qv = se->property("DocPath");
+ debug(TQString("Property type is %1").arg(qv.typeName()));
+ debug(TQString("Property value is %1").arg(qv.toString()));
+ }
+ else
+ {
+ debug("Not found !");
+ }
+
+ debug("Trying to look for System/kpager.desktop");
+ se = KService::serviceByDesktopPath("System/kpager.desktop");
+ if ( se )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(se->comment()));
+ }
+ else
+ {
+ debug("Not found !");
+ }
+
+ debug("Trying to look for System/fake-entry.desktop");
+ se = KService::serviceByDesktopPath("System/fake-entry.desktop");
+ if ( se )
+ {
+ debug("Found it !");
+ debug(TQString("Comment is %1").arg(se->comment()));
+ }
+ else
+ {
+ debug("Not found !");
+ }
+
+#if 1
+ debug("Querying userprofile for services associated with text/plain");
+ KServiceTypeProfile::OfferList offers = KServiceTypeProfile::offers("text/plain");
+ debug(TQString("got %1 offers").arg(offers.count()));
+ KServiceTypeProfile::OfferList::Iterator it = offers.begin();
+ for ( ; it != offers.end() ; it++ )
+ {
+ debug((*it).service()->name());
+ }
+
+ debug("Querying userprofile for services associated with KOfficeFilter");
+ offers = KServiceTypeProfile::offers("KOfficeFilter");
+ debug(TQString("got %1 offers").arg(offers.count()));
+ it = offers.begin();
+ for ( ; it != offers.end() ; it++ )
+ {
+ debug((*it).service()->name());
+ }
+
+ debug("Querying trader for Konqueror/Plugin");
+ KTrader::OfferList traderoffers = KTrader::self()->query("Konqueror/Plugin");
+ debug(TQString("got %1 offers").arg(traderoffers.count()));
+ KTrader::OfferList::Iterator trit = traderoffers.begin();
+ for ( ; trit != traderoffers.end() ; trit++ )
+ {
+ debug((*trit)->name());
+ }
+#endif
+
+
+ //
+ debug("\nTrying findByURL for $TDEDIR/bin/kdesktop");
+ KMimeType::Ptr mf = KMimeType::findByURL( KStandardDirs::findExe( "kdesktop" ), 0,
+ true, false );
+ assert( mf );
+ check( "A binary's mimetype", mf->name(), "application/x-executable" );
+
+ //
+ debug("\nTrying findByURL for folder_home.png");
+ TQString fh;
+ (void)k.iconLoader()->loadIcon("folder_home.png",KIcon::Desktop,0,KIcon::DefaultState,&fh);
+ mf = KMimeType::findByURL( fh, 0, true, false );
+ assert( mf );
+ check( "A PNG's mimetype", mf->name(), "image/png" );
+
+ //
+ //debug("\nTrying findByURL for Makefile.am");
+ //mf = KMimeType::findByURL( KURL("/tmp/Makefile.am"), 0, true, false );
+ //assert( mf );
+ //debug(TQString("Name is %1").arg(mf->name()));
+ //debug(TQString("Comment is %1").arg(mf->comment(KURL(),false)));
+
+ debug("\nTrying findByURL for man:/ls");
+ mf = KMimeType::findByURL( KURL("man:/ls") );
+ assert( mf );
+ check( "man:/ls", mf->name(), "text/html" );
+ check( "man:/ls/", mf->name(), "text/html" );
+
+ mf = KMimeType::findByURL( KURL("http://foo/bar.png") );
+ check( "HTTP URL", mf->name(), "application/octet-stream" ); // HTTP can't know before downloading
+
+#if 1
+ KMimeType::List mtl;
+
+ mtl = KMimeType::allMimeTypes( );
+ assert( mtl.count() );
+ debug(TQString("Found %1 mime types.").arg(mtl.count()));
+ for(int i = 0; i < (int)mtl.count(); i++)
+ {
+ debug(TQString("Mime type %1: %2.").arg(i).arg(mtl[i]->name()));
+ }
+
+ KService::List sl;
+
+ sl = KService::allServices( );
+ assert( sl.count() );
+ debug(TQString("Found %1 services.").arg(sl.count()));
+
+ KServiceGroup::Ptr root = KServiceGroup::root();
+ KServiceGroup::List list = root->entries();
+ //KServiceGroup::Ptr topGroup = KServiceGroup::childGroup( "kview" );
+ //Q_ASSERT( topGroup );
+ //KServiceGroup::List list = topGroup->entries();
+
+ KServiceGroup::Ptr first;
+
+ debug(TQString("Found %1 entries").arg(list.count()));
+ for( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+ debug(service->name());
+ debug(service->desktopEntryPath());
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+ debug(TQString(" %1 -->").arg(serviceGroup->caption()));
+ if (!first) first = serviceGroup;
+ }
+ else
+ {
+ debug("KServiceGroup: Unexpected object in list!");
+ }
+ }
+
+ if (first)
+ {
+ list = first->entries();
+ debug(TQString("Found %1 entries").arg(list.count()));
+ for( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *service = static_cast<KService *>(p);
+ debug(TQString(" %1").arg(service->name()));
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
+ debug(TQString(" %1 -->").arg(serviceGroup->caption()));
+ }
+ else
+ {
+ debug("KServiceGroup: Unexpected object in list!");
+ }
+ }
+ }
+
+ debug("--services that require initialisation--");
+ sl = KService::allInitServices();
+ for( KService::List::ConstIterator it = sl.begin();
+ it != sl.end(); it++)
+ {
+ KService *service = static_cast<KService *>(*it);
+ debug(service->name());
+ }
+ debug("--End of list--");
+
+ debug("--protocols--");
+ TQStringList stringL = KProtocolInfo::protocols();
+ for( TQStringList::ConstIterator it = stringL.begin();
+ it != stringL.end(); it++)
+ {
+ debug((*it).ascii());
+ }
+ debug("--End of list--");
+#endif
+
+#if 0
+ KImageIO::registerFormats();
+
+ TQStringList types;
+ types = KImageIO::types(KImageIO::Reading);
+ debug("Can read:");
+ for(TQStringList::ConstIterator it = types.begin();
+ it != types.end(); ++it)
+ debug(TQString(" %1").arg((*it)));
+
+ types = KImageIO::types(KImageIO::Writing);
+ debug("Can write:");
+ for(TQStringList::ConstIterator it = types.begin();
+ it != types.end(); ++it)
+ debug(TQString(" %1").arg((*it)));
+
+
+ TQString rPattern = KImageIO::pattern( KImageIO::Reading );
+ debug("Read pattern:\n%s", rPattern.ascii());
+
+ TQString wPattern = KImageIO::pattern( KImageIO::Writing );
+ debug("Write pattern:\n%s", wPattern.ascii());
+
+ TQString suffix = KImageIO::suffix("JPEG");
+ debug("Standard suffix for JPEG: %s", suffix.ascii());
+
+ types = KImageIO::mimeTypes(KImageIO::Reading);
+ debug("Can read (mimetypes):");
+ for(TQStringList::ConstIterator it = types.begin();
+ it != types.end(); ++it)
+ debug(" %s", (*it).ascii());
+
+ types = KImageIO::mimeTypes(KImageIO::Writing);
+ debug("Can write (mimetypes):");
+ for(TQStringList::ConstIterator it = types.begin();
+ it != types.end(); ++it)
+ debug(" %s", (*it).ascii());
+
+ debug("done");
+#endif
+ return 0;
+}
diff --git a/tdeio/tests/tdesycocaupdatetest.cpp b/tdeio/tests/tdesycocaupdatetest.cpp
new file mode 100644
index 000000000..e7778e056
--- /dev/null
+++ b/tdeio/tests/tdesycocaupdatetest.cpp
@@ -0,0 +1,11 @@
+#include <kservice.h>
+
+#include <kapplication.h>
+
+int main(int argc, char *argv[])
+{
+ TDEApplication k(argc,argv,"whatever"); // KMessageBox needs KApp for makeStdCaption
+
+ KService::rebuildKSycoca(0);
+ return 0;
+}
diff --git a/tdeio/tests/tdetradertest.cpp b/tdeio/tests/tdetradertest.cpp
new file mode 100644
index 000000000..c0092f76d
--- /dev/null
+++ b/tdeio/tests/tdetradertest.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2002, 2003 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 <kcmdlineargs.h>
+#include <ktrader.h>
+#include <kmimetype.h>
+#include <kapplication.h>
+#include <stdio.h>
+
+static KCmdLineOptions options[] =
+{
+ { "+query", "the query", 0 },
+ { "+[genericServiceType]", "Application (default), or KParts/ReadOnlyPart", 0 },
+ { "+[constraint]", "constraint", 0 },
+ { "+[preference]", "preference", 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char **argv )
+{
+ TDECmdLineArgs::init( argc, argv, "tdetradertest", "KTradertest", "A KTrader testing tool", "0.0" );
+
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ TDEApplication app( false, false ); // no GUI
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ if ( args->count() < 1 )
+ TDECmdLineArgs::usage();
+
+ TQString query = TQString::fromLocal8Bit( args->arg( 0 ) );
+
+ TQString genericServiceType, constraint, preference;
+
+ if ( args->count() >= 2 )
+ genericServiceType = TQString::fromLocal8Bit( args->arg( 1 ) );
+
+ if ( args->count() >= 3 )
+ constraint = TQString::fromLocal8Bit( args->arg( 2 ) );
+
+ if ( args->count() == 4 )
+ preference = TQString::fromLocal8Bit( args->arg( 3 ) );
+
+ printf( "query is : %s\n", query.local8Bit().data() );
+ printf( "genericServiceType is : %s\n", genericServiceType.local8Bit().data() );
+ printf( "constraint is : %s\n", constraint.local8Bit().data() );
+ printf( "preference is : %s\n", preference.local8Bit().data() );
+
+ KTrader::OfferList offers = KTrader::self()->query( query, genericServiceType, constraint, preference );
+
+ printf("got %d offers.\n", offers.count());
+
+ int i = 0;
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+ for (; it != end; ++it, ++i )
+ {
+ printf("---- Offer %d ----\n", i);
+ TQStringList props = (*it)->propertyNames();
+ TQStringList::ConstIterator propIt = props.begin();
+ TQStringList::ConstIterator propEnd = props.end();
+ for (; propIt != propEnd; ++propIt )
+ {
+ TQVariant prop = (*it)->property( *propIt );
+
+ if ( !prop.isValid() )
+ {
+ printf("Invalid property %s\n", (*propIt).local8Bit().data());
+ continue;
+ }
+
+ TQString outp = *propIt;
+ outp += " : '";
+
+ switch ( prop.type() )
+ {
+ case TQVariant::StringList:
+ outp += prop.toStringList().join(" - ");
+ break;
+ case TQVariant::Bool:
+ outp += prop.toBool() ? "TRUE" : "FALSE";
+ break;
+ default:
+ outp += prop.toString();
+ break;
+ }
+
+ if ( !outp.isEmpty() )
+ printf("%s'\n", outp.local8Bit().data());
+ }
+ }
+}
diff --git a/tdeio/tests/wronglocalsizes.zip b/tdeio/tests/wronglocalsizes.zip
new file mode 100644
index 000000000..3f76738ba
--- /dev/null
+++ b/tdeio/tests/wronglocalsizes.zip
Binary files differ
diff --git a/tdeio/useragent.pl b/tdeio/useragent.pl
new file mode 100755
index 000000000..f31e31e1d
--- /dev/null
+++ b/tdeio/useragent.pl
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+# the script is called with interpreter, so don't worry about the path
+
+while(<>)
+{
+ if (($key, $domain, $useragent, $comment) = ($_ =~ /(Entry\d)=\.?([^:]+)::([^:]+)::([^\n]+)/))
+ {
+ printf ("[%s]\n", $domain);
+ printf ("UserAgent=%s\n", $useragent);
+ printf ("# DELETE %s\n", $key);
+ }
+}
+printf ("# DELETE EntriesCount\n");