diff options
Diffstat (limited to 'kio/misc')
68 files changed, 12665 insertions, 0 deletions
diff --git a/kio/misc/Makefile.am b/kio/misc/Makefile.am new file mode 100644 index 000000000..5dab3a23e --- /dev/null +++ b/kio/misc/Makefile.am @@ -0,0 +1,60 @@ +# This file is part of the KDE libraries +# Copyright (C) 1997 Torben Weis ([email protected]) + +# 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 = . ksendbugmail kpac kdesasl kssld kfile kwalletd kntlm + +lib_LTLIBRARIES = +kdeinit_LTLIBRARIES = kio_uiserver.la +bin_PROGRAMS = kmailservice ktelnetservice + +observer_DIR = $(top_srcdir)/kio/kio + +kio_uiserver_la_SOURCES = uiserver.cpp uiserver.skel observer.stub +kio_uiserver_la_LIBADD = $(LIB_KIO) +kio_uiserver_la_LDFLAGS = $(all_libraries) -module -avoid-version + +METASOURCES = AUTO + +kde_services_DATA = kio_uiserver.desktop + +kmailservice_SOURCES = kmailservice.cpp +kmailservice_LDADD = $(LIB_KDECORE) +kmailservice_LDFLAGS = $(KDE_RPATH) $(all_libraries) + +ktelnetservice_SOURCES = ktelnetservice.cpp +ktelnetservice_LDADD = $(LIB_KDEUI) +ktelnetservice_LDFLAGS = $(KDE_RPATH) $(all_libraries) + +protocol_DATA = kmailservice.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)/kio +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/kio/misc/fileshareset b/kio/misc/fileshareset new file mode 100755 index 000000000..f73e5f008 --- /dev/null +++ b/kio/misc/fileshareset @@ -0,0 +1,425 @@ +#!/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 ([email protected]) +# +# This program is free software; you can redistribute 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; + system('/etc/init.d/nfs', $_) 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/kio/misc/kdesasl/Makefile.am b/kio/misc/kdesasl/Makefile.am new file mode 100644 index 000000000..854757d37 --- /dev/null +++ b/kio/misc/kdesasl/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES=$(all_includes) + +lib_LTLIBRARIES = libkdesasl.la +METASOURCES = AUTO + +kdesaslincludedir = $(includedir)/kio +kdesaslinclude_HEADERS = kdesasl.h + +libkdesasl_la_SOURCES = kdesasl.cpp +libkdesasl_la_LDFLAGS = $(all_libraries) -version-info 3:0:2 -no-undefined +libkdesasl_la_LIBADD = $(LIB_KDECORE) + diff --git a/kio/misc/kdesasl/kdesasl.cpp b/kio/misc/kdesasl/kdesasl.cpp new file mode 100644 index 000000000..c59d157b8 --- /dev/null +++ b/kio/misc/kdesasl/kdesasl.cpp @@ -0,0 +1,285 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001-2002 Michael H�ckel <[email protected]> + $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 "kdesasl.h" + +#include <kmdcodec.h> +#include <kurl.h> + +#include <qstrlist.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 QString &aUser, const QString &aPass, + const QString &aProtocol) +{ + mProtocol = aProtocol; + mUser = aUser; + mPass = aPass; + mFirst = true; +} + +KDESasl::~KDESasl() { +} + +QCString KDESasl::chooseMethod(const QStrIList 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 = QCString(); + return mMethod; +} + +void KDESasl::setMethod(const QCString &aMethod) +{ + mMethod = aMethod.upper(); +} + +QByteArray KDESasl::getPlainResponse() +{ + QCString user = mUser.utf8(); + QCString pass = mPass.utf8(); + int userlen = user.length(); + int passlen = pass.length(); + // result = $user\0$user\0$pass (no trailing \0) + QByteArray 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; +} + +QByteArray KDESasl::getLoginResponse() +{ + QByteArray result = (mFirst) ? mUser.utf8() : mPass.utf8(); + mFirst = !mFirst; + if (result.size()) result.resize(result.size() - 1); + return result; +} + +QByteArray KDESasl::getCramMd5Response(const QByteArray &aChallenge) +{ + uint i; + QByteArray 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; + QByteArray XorOpad(64); + for (i = 0; i < 64; i++) XorOpad[i] = secret[i] ^ 0x5C; + QByteArray 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); + QByteArray result = mUser.utf8(); + len = mUser.utf8().length(); + result.resize(len + 33); + result[len] = ' '; + QCString ch = md5a.hexDigest(); + for (i = 0; i < 32; i++) result[i+len+1] = *(ch.data() + i); + return result; +} + +QByteArray KDESasl::getDigestMd5Response(const QByteArray &aChallenge) +{ + mFirst = !mFirst; + if (mFirst) return QByteArray(); + QCString str, realm, nonce, qop, algorithm, charset; + QCString 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 = QCString(aChallenge.data() + c, d - c + 1); + if (qstrnicmp(aChallenge.data() + a, "realm=", 6) == 0) realm = str; + else if (qstrnicmp(aChallenge.data() + a, "nonce=", 6) == 0) nonce = str; + else if (qstrnicmp(aChallenge.data() + a, "qop=", 4) == 0) qop = str; + else if (qstrnicmp(aChallenge.data() + a, "algorithm=", 10) == 0) + algorithm = str; + else if (qstrnicmp(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 = qstricmp(charset, "utf-8") == 0; + QCString digestUri = QCString(mProtocol.latin1()) + "/" + realm; + + /* Calculate the response */ + /* Code based on code from the http io-slave + Copyright (C) 2000,2001 Dawit Alemayehu <[email protected]> + Copyright (C) 2000,2001 Waldo Bastian <[email protected]> + Copyright (C) 2000,2001 George Staikos <[email protected]> */ + KMD5 md, md2; + QCString HA1, HA2; + QCString cnonce; + cnonce.setNum((1 + static_cast<int>(100000.0*rand()/(RAND_MAX+1.0)))); + cnonce = KCodecs::base64Encode( cnonce ); + + // Calculate H(A1) + QCString authStr = (utf8) ? mUser.utf8() : QCString(mUser.latin1()); + authStr += ':'; + authStr += realm; + authStr += ':'; + authStr += (utf8) ? mPass.utf8() : QCString(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 ); + QCString response = md.hexDigest(); + /* End of response calculation */ + + QCString result; + if (utf8) + { + result = "charset=utf-8,username=\"" + mUser.utf8(); + } else { + result = "charset=iso-8859-1,username=\"" + QCString(mUser.latin1()); + } + result += "\",realm=\"" + realm + "\",nonce=\"" + nonce; + result += "\",nc=" + nc + ",cnonce=\"" + cnonce; + result += "\",digest-uri=\"" + digestUri; + result += "\",response=" + response + ",qop=" + qop; + QByteArray ba; + ba.duplicate(result.data(), result.length()); + return ba; +} + +QByteArray KDESasl::getBinaryResponse(const QByteArray &aChallenge, bool aBase64) +{ + if (aBase64) + { + QByteArray ba; + KCodecs::base64Decode(aChallenge, ba); + KCodecs::base64Encode(getBinaryResponse(ba, false), ba); + return ba; + } + if (qstricmp(mMethod, "PLAIN") == 0) return getPlainResponse(); + if (qstricmp(mMethod, "LOGIN") == 0) return getLoginResponse(); + if (qstricmp(mMethod, "CRAM-MD5") == 0) + return getCramMd5Response(aChallenge); + if (qstricmp(mMethod, "DIGEST-MD5") == 0) + return getDigestMd5Response(aChallenge); +// return getDigestMd5Response(QCString("realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8")); + return QByteArray(); +} + +QCString KDESasl::getResponse(const QByteArray &aChallenge, bool aBase64) +{ + QByteArray ba = getBinaryResponse(aChallenge, aBase64); + return QCString(ba.data(), ba.size() + 1); +} + +QCString 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/kio/misc/kdesasl/kdesasl.h b/kio/misc/kdesasl/kdesasl.h new file mode 100644 index 000000000..834c83913 --- /dev/null +++ b/kio/misc/kdesasl/kdesasl.h @@ -0,0 +1,169 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001-2002 Michael H�ckel <[email protected]> + $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 KDESASL_H +#define KDESASL_H + +#include <qstring.h> + +#include <kdelibs_export.h> + +class KURL; +class QStrIList; + +/** + * 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 ) { + * QByteArray challenge = myRecvChallenge(); + * mySendResponse( sasl.getResponse( challenge ) ); + * } + * return myCheckSuccess(); + * \endcode + * + * @author Michael H�ckel <[email protected]> + * @version $Id$ + */ + +class KIO_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 QString &aUser, const QString &aPass, const QString &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 QCString chooseMethod(const QStrIList aMethods); + /** + * Explicitely set the SASL method used. + */ + virtual void setMethod(const QCString &aMethod); + /** + * @return the SASL method used. + * @since 3.2 + */ + QCString 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. + */ + QCString getResponse(const QByteArray &aChallenge=QByteArray(), bool aBase64 = true); + /** + * Create a response as above but place it in a QByteArray + */ + QByteArray getBinaryResponse(const QByteArray &aChallenge=QByteArray(), 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 QByteArray getPlainResponse(); + /** + * LOGIN authentication + */ + virtual QByteArray getLoginResponse(); + /** + * CRAM-MD5 authentication as described in RFC 2195 + */ + virtual QByteArray getCramMd5Response(const QByteArray &aChallenge); + /** + * DIGEST-MD5 authentication as described in RFC 2831 + */ + virtual QByteArray getDigestMd5Response(const QByteArray &aChallenge); + +private: + QString mProtocol, mUser, mPass; + QCString mMethod; + bool mFirst; +}; + +#endif diff --git a/kio/misc/kfile/Makefile.am b/kio/misc/kfile/Makefile.am new file mode 100644 index 000000000..94c7dada9 --- /dev/null +++ b/kio/misc/kfile/Makefile.am @@ -0,0 +1,10 @@ +METASOURCES = AUTO + +noinst_HEADERS = fileprops.h +INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/kio/kio $(all_includes) + +bin_PROGRAMS = kfile +kfile_SOURCES = fileprops.cpp +kfile_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kfile_LDADD = $(LIB_KIO) + diff --git a/kio/misc/kfile/README b/kio/misc/kfile/README new file mode 100644 index 000000000..d063b6d58 --- /dev/null +++ b/kio/misc/kfile/README @@ -0,0 +1,4 @@ +This is a commandline frontend to KFileMetaInfo. It allows +to read and write meta information of files. + +Carsten Pfeiffer <[email protected]> diff --git a/kio/misc/kfile/fileprops.cpp b/kio/misc/kfile/fileprops.cpp new file mode 100644 index 000000000..9b7f75380 --- /dev/null +++ b/kio/misc/kfile/fileprops.cpp @@ -0,0 +1,480 @@ +/* This file is part of the KDE libraries + Copyright (C) 2002,2003 Carsten Pfeiffer <[email protected]> + + 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 <qfile.h> +#include <qptrlist.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kfilemetainfo.h> +#include <klocale.h> +#include <kpropertiesdialog.h> + +#include "fileprops.h" + +#define KFILEVERSION "0.2" +#define INDENT "\t" + +using namespace std; + +static QString beatifyValue( const QString& value ) +{ + if ( value.isNull() ) + return QString("(no value for key available)"); + else if ( value.isEmpty() ) + return QString("(empty)"); + + return value; +} + +FileProps::FileProps( const QString& path, const QStringList& suppliedGroups ) + : m_dirty( false ) +{ + m_info = new KFileMetaInfo(path, QString::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(); +} + +QStringList FileProps::supportedGroups() const +{ + return m_info->supportedGroups(); +} + +QStringList FileProps::availableGroups() const +{ + return m_info->groups(); +} + +QStringList FileProps::supportedKeys( const QString& group ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + return g.supportedKeys(); +} + +QStringList FileProps::availableKeys( const QString& group ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + QStringList allKeys = g.keys(); + QStringList ret; + QStringList::ConstIterator it = allKeys.begin(); + for ( ; it != allKeys.end(); ++it ) + { + if ( g.item( *it ).isValid() ) + ret.append( *it ); + } + + return ret; +} + +QStringList FileProps::preferredKeys( const QString& group ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + return g.preferredKeys(); +} + +QString FileProps::getValue( const QString& group, + const QString& key ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + return FileProps::createKeyValue( g, key ); +} + +bool FileProps::setValue( const QString& group, + const QString& key, const QString &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; +} + +QStringList FileProps::allValues( const QString& group ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + return FileProps::createKeyValueList( g, g.keys() ); +} + +QStringList FileProps::preferredValues( const QString& group ) const +{ + KFileMetaInfoGroup g = m_info->group( group ); + return FileProps::createKeyValueList( g, g.preferredKeys() ); +} + +// static helper: +// creates strings like +// "group: translatedKey: value" +QString FileProps::createKeyValue( const KFileMetaInfoGroup& g, + const QString& key ) +{ + static const int MAX_SPACE = 25; + KFileMetaInfoItem item = g.item( key ); + + QString result("%1"); + result = result.arg( (item.isValid() ? item.translatedKey() : key) + ":", + -MAX_SPACE ); + result.append( beatifyValue( item.string() ) ); + + QString group("%1"); + group = group.arg( g.translatedName() + ":", -MAX_SPACE ); + result.prepend( group ); + + return result; +} + +// static +QStringList FileProps::createKeyValueList( const KFileMetaInfoGroup& g, + const QStringList& keys ) +{ + QStringList result; + QStringList::ConstIterator it = keys.begin(); + + for ( ; it != keys.end(); ++it ) + result.append( FileProps::createKeyValue( g, *it ) ); + + return result; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + + +// kfile --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 KDE 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() +{ + QStringList allMimeTypes = KFileMetaInfoProvider::self()->supportedMimeTypes(); + if ( allMimeTypes.isEmpty() ) + { + cout << + i18n("No support for metadata extraction found.").local8Bit() + << endl; + return; + } + + cout << i18n("Supported MimeTypes:").local8Bit() << endl; + + QStringList::ConstIterator it = allMimeTypes.begin(); + for ( ; it != allMimeTypes.end(); it++ ) + cout << (*it).local8Bit() << endl; +} + +// caller needs to delete the returned list! +static KFileItemList * fileItemList( const KCmdLineArgs *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 KCmdLineArgs *args ) +{ + KFileItemList *items = fileItemList( args ); + new KPropertiesDialog( *items, 0L, "props dialog", true ); + delete items; +} + +static void printMimeTypes( const KCmdLineArgs *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() << " (" + << mt->name().local8Bit() << ")" << endl; + } +} + +static void printList( const QStringList& list ) +{ + QStringList::ConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) + cout << (*it).local8Bit() << endl; + cout << endl; +} + +static void processMetaDataOptions( const QPtrList<FileProps> propList, + KCmdLineArgs *args ) +{ +// kfile --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 + + QString line("-- -------------------------------------------------------"); + FileProps *props; + QPtrListIterator<FileProps> it( propList ); + for ( ; (props = it.current()); ++it ) + { + QString file = props->fileName() + " "; + QString fileString = line.replace( 3, file.length(), file ); + cout << QFile::encodeName( fileString ) << 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; + QStringList groups = props->availableGroups(); + QStringList::ConstIterator git = groups.begin(); + for ( ; git != groups.end(); ++git ) + { + cout << "Group: " << (*git).local8Bit() << endl; + printList( props->availableKeys( *git ) ); + } + } +// if ( args->isSet( "listwritable" ) ) +// { +// cout << "TODO :)" << endl; +// } + if ( args->isSet( "getValue" ) ) + { + cout << "=Value=" << endl; + QString key = QString::fromLocal8Bit( args->getOption("getValue")); + QStringList::ConstIterator git = props->groupsToUse().begin(); + for ( ; git != props->groupsToUse().end(); ++git ) + cout << props->getValue( *git, key ).local8Bit() << endl; + } + + if ( args->isSet( "setValue" ) ) + { + // separate key and value from the line "key=value" + QString cmd = QString::fromLocal8Bit( args->getOption("setValue")); + QString key = cmd.section( '=', 0, 0 ); + QString value = cmd.section( '=', 1 ); + + // either use supplied groups or all supported groups + // (not only the available!) + QStringList groups = props->userSuppliedGroups() ? + props->groupsToUse() : + props->supportedGroups(); + + QStringList::ConstIterator git = groups.begin(); + for ( ; git != groups.end(); ++git ) + props->setValue( *git, key, value ); + } + + if ( args->isSet( "allValues" ) ) + { + cout << "=All Values=" << endl; + QStringList groups = props->availableGroups(); + QStringList::ConstIterator group = groups.begin(); + for ( ; group != groups.end(); ++group ) + printList( props->allValues( *group ) ); + } + if ( args->isSet( "preferredValues" ) && !args->isSet("allValues") ) + { + cout << "=Preferred Values=" << endl; + QStringList groups = props->availableGroups(); + QStringList::ConstIterator group = groups.begin(); + for ( ; group != groups.end(); ++group ) + printList( props->preferredValues( *group ) ); + } + } + +} + +int main( int argc, char **argv ) +{ + KAboutData about( + "kfile", I18N_NOOP( "kfile" ), KFILEVERSION, + I18N_NOOP("A commandline tool to read and modify metadata of files." ), + KAboutData::License_LGPL, "(c) 2002, Carsten Pfeiffer", + 0 /*text*/, "http://devel-home.kde.org/~pfeiffer/", + "[email protected]" ); + + about.addAuthor( "Carsten Pfeiffer", 0, "[email protected]", + "http://devel-home.kde.org/~pfeiffer/" ); + + KCmdLineArgs::init( argc, argv, &about ); + + KCmdLineArgs::addCmdLineOptions( options ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + bool useGUI = args->isSet( "dialog" ); + + KApplication app( useGUI, useGUI ); + + QPtrList<FileProps> m_props; + m_props.setAutoDelete( true ); + + bool quiet = args->isSet( "quiet" ); + + if ( args->isSet( "supportedMimetypes" ) ) + printSupportedMimeTypes(); + + int files = args->count(); + if ( files == 0 ) + KCmdLineArgs::usage( i18n("No files specified") ); // exit()s + + if ( args->isSet( "dialog" ) ) + { + showPropertiesDialog( args ); + return true; + } + + QStringList groupsToUse; + QCStringList suppliedGroups = args->getOptionList( "groups" ); + QCStringList::ConstIterator it = suppliedGroups.begin(); + for ( ; it != suppliedGroups.end(); ++it ) + groupsToUse.append( QString::fromLocal8Bit( (*it) ) ); + + QString 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() << endl; + } + delete props; + } + } + + + processMetaDataOptions( m_props, args ); + + m_props.clear(); // force destruction/sync of props + cout.flush(); + + return 0; +} diff --git a/kio/misc/kfile/fileprops.h b/kio/misc/kfile/fileprops.h new file mode 100644 index 000000000..a26c1d3bb --- /dev/null +++ b/kio/misc/kfile/fileprops.h @@ -0,0 +1,74 @@ +/* This file is part of the KDE libraries + Copyright (C) 2002 Carsten Pfeiffer <[email protected]> + + 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 <qstring.h> + +#include <kfilemetainfo.h> + +class FileProps +{ +public: + FileProps( const QString& path, const QStringList& suppliedGroups ); + virtual ~FileProps(); + + bool isValid() const; + + QString fileName() const { return m_info->path(); } + + QStringList supportedGroups() const; + QStringList availableGroups() const; + QStringList translatedGroups(); + + const QStringList& groupsToUse() const { return m_groupsToUse; } + bool userSuppliedGroups() const { return m_userSuppliedGroups; } + + QStringList supportedKeys( const QString& group ) const; + QStringList availableKeys( const QString& group ) const; + QStringList preferredKeys( const QString& group ) const; + + QStringList supportedKeys() const { return m_info->supportedKeys(); } + QStringList preferredKeys() const { return m_info->preferredKeys(); } + + QString getValue( const QString& group, const QString& key ) const; + bool setValue( const QString& group, + const QString& key, const QString &value ); + + QStringList allValues( const QString& group ) const; + QStringList preferredValues( const QString& group ) const; + + bool isReadOnly( const QString& group, const QString& key ); + +private: + static QString createKeyValue( const KFileMetaInfoGroup& g, + const QString& key ); + static QStringList createKeyValueList( const KFileMetaInfoGroup&, + const QStringList& ); + bool sync(); + + KFileMetaInfo *m_info; + bool m_dirty; + bool m_userSuppliedGroups; + + QStringList m_groupsToUse; + +}; + +#endif // KFILEPROPS_H diff --git a/kio/misc/kio_uiserver.desktop b/kio/misc/kio_uiserver.desktop new file mode 100644 index 000000000..e002d74b0 --- /dev/null +++ b/kio/misc/kio_uiserver.desktop @@ -0,0 +1,100 @@ +[Desktop Entry] +Type=Service +Name=kio_uiserver +Name[de]=Server der graphischen Oberfläche +Name[fy]=Kio_uiserver +Name[ja]=kio_uiサーバ +Name[mn]=График гадаргуугийн сервер +Name[nds]=kio_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=kio_uiserver +Comment=KDE's Progress Info UI server +Comment[af]=KDE se vordering inligting UI bediener +Comment[ar]=خادم معلومات تقدم واجهة كيدي +Comment[az]=KDE'nin İrəliləmə Bilgisi İstifadaçi Ara Üz Vericisi +Comment[be]=Сервер паведамленняў аб выкананні дзеянняў +Comment[bg]=Сървър за отчитане на прогреса (KDE's Progress Info UI server) +Comment[bn]=কে.ডি.ই. অগ্রগতি তথ্য UI সার্ভার +Comment[br]=Servijer stlenn EA Progress KDE +Comment[bs]=KDEov Progess Info UI server +Comment[ca]=Servidor d'informació de progrés del KDE +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 KDE i Ddangos Cynnydd +Comment[da]=KDE's fremgangsinfo-UI-server +Comment[de]=Ein UI-Server, der Fortschrittsinformationen darstellt +Comment[el]=Εξυπηρετητής πληροφοριών προόδου περιβάλλοντος χρήσης του KDE +Comment[eo]=Progresinforma servo +Comment[es]=Servidor UI de información de progreso de KDE +Comment[et]=KDE edenemise info UI server +Comment[eu]=KDEren aurrerapen-informazioen UI zerbitzaria +Comment[fa]=اطلاعات پیشرفت کارساز UI KDE +Comment[fi]=KDE:n edistymispalkin käyttöliittymäpalvelin +Comment[fr]=Serveur graphique d'infos de progression de KDE +Comment[fy]=KDE's tsjinner foar ynformaasje oer de fuortgong +Comment[gl]=Servidor UI de Información de Progreso de KDE +Comment[he]=שרת ממשק מידע ההתקדמות של KDE +Comment[hi]=केडीई का प्रोग्रेस जानकारी UI सर्वर +Comment[hr]=KDEov Progess Info UI poslužitelj +Comment[hu]=KDE folyamatinformációs kiszolgáló +Comment[id]=Perkembangan KDE mengenai info server UI +Comment[is]=Þjónn sem sýnir framvindu ferla +Comment[it]=Server informazioni avanzamento di KDE +Comment[ja]=KDE 進捗情報 UI サーバ +Comment[ka]=KDE-ს მონაცემთა გადაცემის სერვერი +Comment[kk]=KDE деректерді алу-беруді бақылау сервері +Comment[km]=ម៉ាស៊ីនបម្រើ UI នៃព័ត៌មានវឌ្ឍនភាពរបស់ KDE +Comment[ko]=KDE에서 보다 발전된 정보 UI 서버 +Comment[lb]=UI-Server vu KDE, dee Fortschrëttsinformatiounen uweist +Comment[lt]=KDE eigos informacijos UI serveris +Comment[lv]=KDE Progresa Info UI serveris +Comment[mk]=KDE сервер за информации за прогресот +Comment[mn]=Прогресс мэдээллээр дүрслэгдсэн хэрэглэгчийн харьцах хэсгийн сервер +Comment[ms]=Pelayan Info UI KDE +Comment[mt]=Server tal-progress tal-UI KDE +Comment[nb]=KDE UI-tjener for framgangsinfo +Comment[nds]=Server för graafsche Vörankamen-Informatschonen +Comment[ne]=KDE को प्रगति सूचना UI सर्भर +Comment[nl]=KDE's server voor informatie over de voortgang. +Comment[nn]=KDE UI-tenar for framgangsinfo +Comment[nso]=Seabi sa UI ya Tshedimoso ya Tswelopele ya KDE +Comment[oc]=Servor d'informacion de progress KDE +Comment[pa]=KDE ਦੀ ਤਰੱਕੀ ਜਾਣਕਾਰੀ 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 KDE +Comment[ro]=Server informaţii de progres KDE +Comment[ru]=Сервер монитора передачи данных KDE +Comment[rw]=Amakuru y'Aho bigeze ya KDE Seriveri UI +Comment[se]=KDE:a ovdánandieđuid UI-bálvá +Comment[sk]=KDE Progres Info UI server +Comment[sl]=Strežnik KDE's Progress Info UI +Comment[sq]=UI Shërbyesi për Informimin e Progresit të KDEs +Comment[sr]=KDE-ов UI сервер информација о напретку +Comment[sr@Latn]=KDE-ov UI server informacija o napretku +Comment[sv]=KDE:s server för förloppsinformation +Comment[ta]=கேடிஇயின் முன்னேற்ற தகவல் முகப்புப் சேவையகம் +Comment[te]=కెడిఈ యొక్క ప్రగతి సమాచార యూఐ సెర్వర్ +Comment[tg]=Инкишофи KDE's Info UI Сервер +Comment[th]=เซิร์ฟเวอร์แสดงข้อมูลความคืบหน้าของ KDE +Comment[tr]=KDE'nin İlerleme Bilgisi arayüz sunucusu +Comment[tt]=KDE'nıñ Alğakiteşne Küzätü servere +Comment[uk]=Сервер графічного інтерфейсу інформації про розвиток KDE +Comment[uz]=KDE'ning maʼlumot uzatishni nazorat qilish serveri +Comment[uz@cyrillic]=KDE'нинг маълумот узатишни назорат қилиш сервери +Comment[ven]=UI siva ya mafhungo a mwelaphanda a KDE +Comment[vi]=Trình phục vụ giao diện người dùng cho thông tin tiến hành của KDE. +Comment[xh]=Umcedisi we UI Wenqubela Yenkcukacha we KDE +Comment[zh_CN]=KDE 的进度信息用户界面服务器 +Comment[zh_HK]=KDE 的進度資訊介面伺服程式 +Comment[zh_TW]=KDE 的進度資訊使用者介面伺服器 +Comment[zu]=Umlekeleli we-UI Yolwazi Lwenqubo lwe-KDE +ServiceTypes= +# It is a server +X-DCOP-ServiceType=Unique +X-KDE-StartupNotify=false diff --git a/kio/misc/kmailservice.cpp b/kio/misc/kmailservice.cpp new file mode 100644 index 000000000..35d829515 --- /dev/null +++ b/kio/misc/kmailservice.cpp @@ -0,0 +1,45 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Simon Hausmann <[email protected]> + + 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("kdelibs"); + KCmdLineArgs::init( argc, argv, "kmailservice", I18N_NOOP("KMailService"), I18N_NOOP("Mail service"), "unknown" ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication a( false, false ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->count() != 1 ) + return 1; + + a.invokeMailer(KURL(args->arg(0)), a.startupId(), true); + + return 0; +} diff --git a/kio/misc/kmailservice.protocol b/kio/misc/kmailservice.protocol new file mode 100644 index 000000000..46a3054a6 --- /dev/null +++ b/kio/misc/kmailservice.protocol @@ -0,0 +1,15 @@ +[Protocol] +exec=kmailservice %u +protocol=mailto +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +DocPath=kioslave/mailto.html +Icon=mail_new +Class=:internet +URIMode=mailto diff --git a/kio/misc/kntlm/Makefile.am b/kio/misc/kntlm/Makefile.am new file mode 100644 index 000000000..192ddc0af --- /dev/null +++ b/kio/misc/kntlm/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES=$(all_includes) + +lib_LTLIBRARIES = libkntlm.la +METASOURCES = AUTO + +kntlmincludedir = $(includedir)/kio +kntlminclude_HEADERS = kntlm.h + +libkntlm_la_SOURCES = kntlm.cpp des.cpp +libkntlm_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined +libkntlm_la_LIBADD = $(LIB_KDECORE) + diff --git a/kio/misc/kntlm/des.cpp b/kio/misc/kntlm/des.cpp new file mode 100644 index 000000000..b6683ac34 --- /dev/null +++ b/kio/misc/kntlm/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 Q_UINT32 f (DES_KEY * key, Q_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) +{ + Q_UINT32 left, right; + char *knp; + Q_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 Q_UINT32 +f (DES_KEY * key, Q_UINT32 r, char *subkey) +{ + Q_UINT32 *spp; + Q_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 = (Q_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; + Q_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/kio/misc/kntlm/des.h b/kio/misc/kntlm/des.h new file mode 100644 index 000000000..4125791b3 --- /dev/null +++ b/kio/misc/kntlm/des.h @@ -0,0 +1,19 @@ +#ifndef KNTLM_DES_H +#define KNTLM_DES_H + +#include <qglobal.h> + +typedef struct des_key +{ + char kn[16][8]; + Q_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/kio/misc/kntlm/kntlm.cpp b/kio/misc/kntlm/kntlm.cpp new file mode 100644 index 000000000..20c9f2a0c --- /dev/null +++ b/kio/misc/kntlm/kntlm.cpp @@ -0,0 +1,389 @@ +/* This file is part of the KDE libraries + Copyright (c) 2004 Szombathelyi Gy�gy <[email protected]> + + 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 <qdatetime.h> +#include <kapplication.h> +#include <kswap.h> +#include <kmdcodec.h> +#include <kdebug.h> + +#include "des.h" +#include "kntlm.h" + +QString KNTLM::getString( const QByteArray &buf, const SecBuf &secbuf, bool unicode ) +{ + //watch for buffer overflows + Q_UINT32 offset; + Q_UINT16 len; + offset = KFromToLittleEndian((Q_UINT32)secbuf.offset); + len = KFromToLittleEndian(secbuf.len); + if ( offset > buf.size() || + offset + len > buf.size() ) return QString::null; + + QString str; + const char *c = buf.data() + offset; + + if ( unicode ) { + str = UnicodeLE2QString( (QChar*) c, len >> 1 ); + } else { + str = QString::fromLatin1( c, len ); + } + return str; +} + +QByteArray KNTLM::getBuf( const QByteArray &buf, const SecBuf &secbuf ) +{ + QByteArray ret; + Q_UINT32 offset; + Q_UINT16 len; + offset = KFromToLittleEndian((Q_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( QByteArray &buf, SecBuf &secbuf, const QString &str, bool unicode ) +{ + QByteArray 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( QByteArray &buf, SecBuf &secbuf, QByteArray &data ) +{ + Q_UINT32 offset; + Q_UINT16 len, maxlen; + offset = (buf.size() + 1) & 0xfffffffe; + len = data.size(); + maxlen = data.size(); + + secbuf.offset = KFromToLittleEndian((Q_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( QByteArray &negotiate, const QString &domain, const QString &workstation, Q_UINT32 flags ) +{ + QByteArray rbuf( sizeof(Negotiate) ); + + rbuf.fill( 0 ); + memcpy( rbuf.data(), "NTLMSSP", 8 ); + ((Negotiate*) rbuf.data())->msgType = KFromToLittleEndian( (Q_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( QByteArray &auth, const QByteArray &challenge, const QString &user, + const QString &password, const QString &domain, const QString &workstation, + bool forceNTLM, bool forceNTLMv2 ) +{ + QByteArray rbuf( sizeof(Auth) ); + Challenge *ch = (Challenge *) challenge.data(); + QByteArray response; + uint chsize = challenge.size(); + bool unicode = false; + QString 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( (Q_UINT32)3 ); + ((Auth*) rbuf.data())->flags = ch->flags; + QByteArray 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; +} + +QByteArray KNTLM::getLMResponse( const QString &password, const unsigned char *challenge ) +{ + QByteArray hash, answer; + + hash = lmHash( password ); + hash.resize( 21 ); + memset( hash.data() + 16, 0, 5 ); + answer = lmResponse( hash, challenge ); + hash.fill( 0 ); + return answer; +} + +QByteArray KNTLM::lmHash( const QString &password ) +{ + QByteArray keyBytes( 14 ); + QByteArray 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; +} + +QByteArray KNTLM::lmResponse( const QByteArray &hash, const unsigned char *challenge ) +{ + DES_KEY ks; + QByteArray 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; +} + +QByteArray KNTLM::getNTLMResponse( const QString &password, const unsigned char *challenge ) +{ + QByteArray hash, answer; + + hash = ntlmHash( password ); + hash.resize( 21 ); + memset( hash.data() + 16, 0, 5 ); + answer = lmResponse( hash, challenge ); + hash.fill( 0 ); + return answer; +} + +QByteArray KNTLM::ntlmHash( const QString &password ) +{ + KMD4::Digest digest; + QByteArray ret, unicode; + unicode = QString2UnicodeLE( password ); + + KMD4 md4( unicode ); + md4.rawDigest( digest ); + ret.duplicate( (const char*) digest, sizeof( digest ) ); + return ret; +} + +QByteArray KNTLM::getNTLMv2Response( const QString &target, const QString &user, + const QString &password, const QByteArray &targetInformation, + const unsigned char *challenge ) +{ + QByteArray hash = ntlmv2Hash( target, user, password ); + QByteArray blob = createBlob( targetInformation ); + return lmv2Response( hash, blob, challenge ); +} + +QByteArray KNTLM::getLMv2Response( const QString &target, const QString &user, + const QString &password, const unsigned char *challenge ) +{ + QByteArray hash = ntlmv2Hash( target, user, password ); + QByteArray clientChallenge( 8 ); + for ( uint i = 0; i<8; i++ ) { + clientChallenge.data()[i] = KApplication::random() % 0xff; + } + return lmv2Response( hash, clientChallenge, challenge ); +} + +QByteArray KNTLM::ntlmv2Hash( const QString &target, const QString &user, const QString &password ) +{ + QByteArray hash1 = ntlmHash( password ); + QByteArray key, ret; + QString id = user.upper() + target.upper(); + key = QString2UnicodeLE( id ); + ret = hmacMD5( key, hash1 ); + return ret; +} + +QByteArray KNTLM::lmv2Response( const QByteArray &hash, + const QByteArray &clientData, const unsigned char *challenge ) +{ + QByteArray data( 8 + clientData.size() ); + memcpy( data.data(), challenge, 8 ); + memcpy( data.data() + 8, clientData.data(), clientData.size() ); + QByteArray mac = hmacMD5( data, hash ); + mac.resize( 16 + clientData.size() ); + memcpy( mac.data() + 16, clientData.data(), clientData.size() ); + return mac; +} + +QByteArray KNTLM::createBlob( const QByteArray &targetinfo ) +{ + QByteArray blob( sizeof(Blob) + 4 + targetinfo.size() ); + blob.fill( 0 ); + + Blob *bl = (Blob *) blob.data(); + bl->signature = KFromToBigEndian( (Q_UINT32) 0x01010000 ); + Q_UINT64 now = QDateTime::currentDateTime().toTime_t(); + now += (Q_UINT64)3600*(Q_UINT64)24*(Q_UINT64)134774; + now *= (Q_UINT64)10000000; + bl->timestamp = KFromToLittleEndian( now ); + for ( uint i = 0; i<8; i++ ) { + bl->challenge[i] = KApplication::random() % 0xff; + } + memcpy( blob.data() + sizeof(Blob), targetinfo.data(), targetinfo.size() ); + return blob; +} + +QByteArray KNTLM::hmacMD5( const QByteArray &data, const QByteArray &key ) +{ + Q_UINT8 ipad[64], opad[64]; + KMD5::Digest digest; + QByteArray 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]; + } + + QByteArray 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)); +} + +QByteArray KNTLM::QString2UnicodeLE( const QString &target ) +{ + QByteArray unicode( target.length() * 2 ); + for ( uint i = 0; i < target.length(); i++ ) { + ((Q_UINT16*)unicode.data())[ i ] = KFromToLittleEndian( target[i].unicode() ); + } + return unicode; +} + +QString KNTLM::UnicodeLE2QString( const QChar* data, uint len ) +{ + QString ret; + for ( uint i = 0; i < len; i++ ) { + ret += KFromToLittleEndian( data[ i ].unicode() ); + } + return ret; +} diff --git a/kio/misc/kntlm/kntlm.h b/kio/misc/kntlm/kntlm.h new file mode 100644 index 000000000..6dbb62139 --- /dev/null +++ b/kio/misc/kntlm/kntlm.h @@ -0,0 +1,233 @@ +/* + This file is part of the KDE libraries. + Copyright (c) 2004 Szombathelyi Gy�rgy <[email protected]> + + 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 <qglobal.h> +#include <qcstring.h> +#include <qstring.h> + +#include <kdelibs_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 KIO_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 + { + Q_UINT16 len; + Q_UINT16 maxlen; + Q_UINT32 offset; + } SecBuf; + + /** + * The NTLM Type 1 structure + */ + typedef struct + { + char signature[8]; /* "NTLMSSP\0" */ + Q_UINT32 msgType; /* 1 */ + Q_UINT32 flags; + SecBuf domain; + SecBuf workstation; + } Negotiate; + + /** + * The NTLM Type 2 structure + */ + typedef struct + { + char signature[8]; + Q_UINT32 msgType; /* 2 */ + SecBuf targetName; + Q_UINT32 flags; + Q_UINT8 challengeData[8]; + Q_UINT32 context[2]; + SecBuf targetInfo; + } Challenge; + + /** + * The NTLM Type 3 structure + */ + typedef struct + { + char signature[8]; + Q_UINT32 msgType; /* 3 */ + SecBuf lmResponse; + SecBuf ntResponse; + SecBuf domain; + SecBuf user; + SecBuf workstation; + SecBuf sessionKey; + Q_UINT32 flags; + } Auth; + + typedef struct + { + Q_UINT32 signature; + Q_UINT32 reserved; + Q_UINT64 timestamp; + Q_UINT8 challenge[8]; + Q_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( QByteArray &negotiate, const QString &domain = QString::null, + const QString &workstation = QString::null, + Q_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( QByteArray &auth, const QByteArray &challenge, const QString &user, + const QString &password, const QString &domain = QString::null, + const QString &workstation = QString::null, bool forceNTLM = false, bool forceNTLMv2 = false ); + + /** + * Returns the LanManager response from the password and the server challenge. + */ + static QByteArray getLMResponse( const QString &password, const unsigned char *challenge ); + /** + * Calculates the LanManager hash of the specified password. + */ + static QByteArray lmHash( const QString &password ); + /** + * Calculates the LanManager response from the LanManager hash and the server challenge. + */ + static QByteArray lmResponse( const QByteArray &hash, const unsigned char *challenge ); + + /** + * Returns the NTLM response from the password and the server challenge. + */ + static QByteArray getNTLMResponse( const QString &password, const unsigned char *challenge ); + /** + * Returns the NTLM hash (MD4) from the password. + */ + static QByteArray ntlmHash( const QString &password ); + + /** + * Calculates the NTLMv2 response. + */ + static QByteArray getNTLMv2Response( const QString &target, const QString &user, + const QString &password, const QByteArray &targetInformation, + const unsigned char *challenge ); + + /** + * Calculates the LMv2 response. + */ + static QByteArray getLMv2Response( const QString &target, const QString &user, + const QString &password, const unsigned char *challenge ); + + /** + * Returns the NTLMv2 hash. + */ + static QByteArray ntlmv2Hash( const QString &target, const QString &user, const QString &password ); + + /** + * Calculates the LMv2 response. + */ + static QByteArray lmv2Response( const QByteArray &hash, + const QByteArray &clientData, const unsigned char *challenge ); + + /** + * Extracts a string field from an NTLM structure. + */ + static QString getString( const QByteArray &buf, const SecBuf &secbuf, bool unicode ); + /** + * Extracts a byte array from an NTLM structure. + */ + static QByteArray getBuf( const QByteArray &buf, const SecBuf &secbuf ); + + static QByteArray createBlob( const QByteArray &targetinfo ); + + static QByteArray hmacMD5( const QByteArray &data, const QByteArray &key ); +private: + static QByteArray QString2UnicodeLE( const QString &target ); + static QString UnicodeLE2QString( const QChar* data, uint len ); + + static void addBuf( QByteArray &buf, SecBuf &secbuf, QByteArray &data ); + static void addString( QByteArray &buf, SecBuf &secbuf, const QString &str, bool unicode = false ); + static void convertKey( unsigned char *key_56, void* ks ); +}; + +#endif /* KNTLM_H */ diff --git a/kio/misc/kntlm/kswap.h b/kio/misc/kntlm/kswap.h new file mode 100644 index 000000000..e9db968ed --- /dev/null +++ b/kio/misc/kntlm/kswap.h @@ -0,0 +1,428 @@ +/* + This file is part of the KDE libraries. + Copyright (c) 2004 Szombathelyi Gy�rgy <[email protected]> + + 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 <qglobal.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 Q_UINT16 KSWAP_16( Q_UINT16 b ) { return bswap_16( b ); } + inline Q_INT16 KSWAP_16( Q_INT16 b ) { return bswap_16( (Q_UINT16)b ); } + inline Q_UINT32 KSWAP_32( Q_UINT32 b ) { return bswap_32( b ); } + inline Q_INT32 KSWAP_32( Q_INT32 b ) { return bswap_32( (Q_UINT32)b ); } + inline Q_UINT64 KSWAP_64( Q_UINT64 b ) { return bswap_64( b ); } + inline Q_INT64 KSWAP_64( Q_INT64 b ) { return bswap_64( (Q_UINT64)b ); } + +#else /* HAVE_BYTESWAP_H */ +#ifdef WORDS_BIGENDIAN + inline Q_UINT16 KSWAP_16( Q_UINT16 b ) + { + return (((b) & 0x00ff) << 8 | ((b) & 0xff00) >> 8); + } + + inline Q_INT16 KSWAP_16( Q_INT16 b ) + { + return ((((Q_UINT16)b) & 0x00ff) << 8 | (((Q_UINT16)b) & 0xff00) >> 8); + } + + inline Q_UINT32 KSWAP_32( Q_UINT32 b ) + { + return + ((((b) & 0xff000000) >> 24) | (((b) & 0x00ff0000) >> 8) | \ + (((b) & 0x0000ff00) << 8) | (((b) & 0x000000ff) << 24)); + } + + inline Q_INT32 KSWAP_32( Q_INT32 b ) + { + return + (((((Q_UINT32)b) & 0xff000000) >> 24) | ((((Q_UINT32)b) & 0x00ff0000) >> 8) | \ + ((((Q_UINT32)b) & 0x0000ff00) << 8) | ((((Q_UINT32)b) & 0x000000ff) << 24)); + } +#else /* WORDS_BIGENDIAN */ +#include <sys/types.h> +#include <netinet/in.h> + + inline Q_UINT16 KSWAP_16( Q_UINT16 b ) { return htons(b); } + inline Q_INT16 KSWAP_16( Q_INT16 b ) { return htons((Q_UINT16)b); } + inline Q_UINT32 KSWAP_32( Q_UINT32 b ) { return htonl(b); } + inline Q_INT32 KSWAP_32( Q_INT32 b ) { return htonl((Q_UINT32)b); } +#endif + inline Q_UINT64 KSWAP_64( Q_UINT64 b ) + { + union { + Q_UINT64 ll; + Q_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 Q_INT64 KSWAP_64( Q_INT64 b ) + { + union { + Q_UINT64 ll; + Q_UINT32 l[2]; + } w, r; + w.ll = (Q_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 Q_UINT16 KFromToBigEndian( Q_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( Q_UINT16 *out, Q_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 Q_UINT32 KFromToBigEndian( Q_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( Q_UINT32 *out, Q_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 Q_UINT64 KFromToBigEndian( Q_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( Q_UINT64 *out, Q_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 Q_INT16 KFromToBigEndian( Q_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( Q_INT16 *out, Q_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 Q_INT32 KFromToBigEndian( Q_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( Q_INT32 *out, Q_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 Q_INT64 KFromToBigEndian( Q_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( Q_INT64 *out, Q_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 Q_UINT16 KFromToLittleEndian( Q_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( Q_UINT16 *out, Q_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 Q_UINT32 KFromToLittleEndian( Q_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( Q_UINT32 *out, Q_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 Q_UINT64 KFromToLittleEndian( Q_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( Q_UINT64 *out, Q_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 Q_INT16 KFromToLittleEndian( Q_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( Q_INT16 *out, Q_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 Q_INT32 KFromToLittleEndian( Q_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( Q_INT32 *out, Q_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 Q_INT64 KFromToLittleEndian( Q_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( Q_INT64 *out, Q_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/kio/misc/kpac/Makefile.am b/kio/misc/kpac/Makefile.am new file mode 100644 index 000000000..173071318 --- /dev/null +++ b/kio/misc/kpac/Makefile.am @@ -0,0 +1,29 @@ + +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)/kdecore/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) + +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/kio/misc/kpac/README b/kio/misc/kpac/README new file mode 100644 index 000000000..d211ae07b --- /dev/null +++ b/kio/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/kio/misc/kpac/README.wpad b/kio/misc/kpac/README.wpad new file mode 100644 index 000000000..f63d25764 --- /dev/null +++ b/kio/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 <[email protected]> diff --git a/kio/misc/kpac/TODO b/kio/misc/kpac/TODO new file mode 100644 index 000000000..ce5cd6a11 --- /dev/null +++ b/kio/misc/kpac/TODO @@ -0,0 +1 @@ +* Make use of badProxy() in KProtocolManager to enable fallbacks diff --git a/kio/misc/kpac/configure.in.in b/kio/misc/kpac/configure.in.in new file mode 100644 index 000000000..a65b9a1c8 --- /dev/null +++ b/kio/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/kio/misc/kpac/dhcp.h b/kio/misc/kpac/dhcp.h new file mode 100644 index 000000000..41643ae3a --- /dev/null +++ b/kio/misc/kpac/dhcp.h @@ -0,0 +1,78 @@ +/* This file is part of the KDE Libraries + Copyright (c) 2001 Malte Starostik <[email protected]> + + 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/kio/misc/kpac/discovery.cpp b/kio/misc/kpac/discovery.cpp new file mode 100644 index 000000000..06709241b --- /dev/null +++ b/kio/misc/kpac/discovery.cpp @@ -0,0 +1,147 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qtimer.h> + +#include <klocale.h> +#include <kprocio.h> +#include <kurl.h> + +#include "discovery.moc" + +namespace KPAC +{ + Discovery::Discovery( QObject* parent ) + : Downloader( parent ), + m_helper( new KProcIO ) + { + connect( m_helper, SIGNAL( readReady( KProcIO* ) ), SLOT( helperOutput() ) ); + connect( m_helper, SIGNAL( processExited( KProcess* ) ), SLOT( failed() ) ); + *m_helper << "kpac_dhcp_helper"; + + if ( !m_helper->start() ) + QTimer::singleShot( 0, this, SLOT( failed() ) ); + } + + bool Discovery::initHostName() + { + struct utsname uts; + + if (uname (&uts) > -1) + { + struct hostent *hent = gethostbyname (uts.nodename); + if (hent != 0) + m_hostname = QString::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 = QString::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 ); + QString line; + m_helper->readln( line ); + download( KURL( line.stripWhiteSpace() ) ); + } +} + +// vim: ts=4 sw=4 et diff --git a/kio/misc/kpac/discovery.h b/kio/misc/kpac/discovery.h new file mode 100644 index 000000000..b9c657924 --- /dev/null +++ b/kio/misc/kpac/discovery.h @@ -0,0 +1,55 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qobject.h> + +#include "downloader.h" + +class KProcIO; + +namespace KPAC +{ + class Discovery : public Downloader + { + Q_OBJECT + public: + Discovery( QObject* ); + + protected slots: + virtual void failed(); + + private slots: + void helperOutput(); + + private: + bool initHostName(); + bool checkDomain() const; + + KProcIO* m_helper; + QString m_hostname; + }; +} + +#endif // KPAC_DISCOVERY_H + +// vim: ts=4 sw=4 et diff --git a/kio/misc/kpac/downloader.cpp b/kio/misc/kpac/downloader.cpp new file mode 100644 index 000000000..6d4e62409 --- /dev/null +++ b/kio/misc/kpac/downloader.cpp @@ -0,0 +1,89 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qtextcodec.h> + +#include <kcharsets.h> +#include <kglobal.h> +#include <klocale.h> +#include <kio/job.h> + +#include "downloader.moc" + +namespace KPAC +{ + Downloader::Downloader( QObject* parent ) + : QObject( parent ) + { + } + + void Downloader::download( const KURL& url ) + { + m_data.resize( 0 ); + m_script = QString::null; + m_scriptURL = url; + + KIO::TransferJob* job = KIO::get( url, false, false ); + connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), + SLOT( data( KIO::Job*, const QByteArray& ) ) ); + connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( result( KIO::Job* ) ) ); + } + + void Downloader::failed() + { + emit result( false ); + } + + void Downloader::setError( const QString& error ) + { + m_error = error; + } + + void Downloader::data( KIO::Job*, const QByteArray& 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( KIO::Job* job ) + { + if ( !job->error() && !static_cast< KIO::TransferJob* >( job )->isErrorPage() ) + { + bool dummy; + m_script = KGlobal::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/kio/misc/kpac/downloader.h b/kio/misc/kpac/downloader.h new file mode 100644 index 000000000..7869d7102 --- /dev/null +++ b/kio/misc/kpac/downloader.h @@ -0,0 +1,64 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qobject.h> + +#include <kurl.h> + +namespace KIO { class Job; } + +namespace KPAC +{ + class Downloader : public QObject + { + Q_OBJECT + public: + Downloader( QObject* ); + + void download( const KURL& ); + const KURL& scriptURL() { return m_scriptURL; } + const QString& script() { return m_script; } + const QString& error() { return m_error; } + + signals: + void result( bool ); + + protected: + virtual void failed(); + void setError( const QString& ); + + private slots: + void data( KIO::Job*, const QByteArray& ); + void result( KIO::Job* ); + + private: + QByteArray m_data; + KURL m_scriptURL; + QString m_script; + QString m_error; + }; +} + +#endif // KPAC_DOWNLOADER_H + +// vim: ts=4 sw=4 et diff --git a/kio/misc/kpac/eventsrc b/kio/misc/kpac/eventsrc new file mode 100644 index 000000000..c44443a03 --- /dev/null +++ b/kio/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/kio/misc/kpac/kpac_dhcp_helper.c b/kio/misc/kpac/kpac_dhcp_helper.c new file mode 100644 index 000000000..906e89dfa --- /dev/null +++ b/kio/misc/kpac/kpac_dhcp_helper.c @@ -0,0 +1,229 @@ +/* This file is part of the KDE Libraries + Copyright (c) 2001 Malte Starostik <[email protected]> + + 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/kio/misc/kpac/kpactest.pac b/kio/misc/kpac/kpactest.pac new file mode 100644 index 000000000..69e5aaad7 --- /dev/null +++ b/kio/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 <[email protected]> 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/kio/misc/kpac/proxyscout.cpp b/kio/misc/kpac/proxyscout.cpp new file mode 100644 index 000000000..06d860615 --- /dev/null +++ b/kio/misc/kpac/proxyscout.cpp @@ -0,0 +1,196 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 QCString& name ) + : KDEDModule( name ), + m_instance( new KInstance( "proxyscout" ) ), + m_downloader( 0 ), + m_script( 0 ), + m_suspendTime( 0 ) + { + } + + ProxyScout::~ProxyScout() + { + delete m_script; + delete m_instance; + } + + QString 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 QString::null; + } + else return "DIRECT"; + } + + ASYNC ProxyScout::blackListProxy( const QString& 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, SIGNAL( result( bool ) ), + 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 ) + { + QCString type = "QString"; + QByteArray data; + QDataStream ds( data, IO_WriteOnly ); + if ( success ) ds << handleRequest( ( *it ).url ); + else ds << QString( "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 ); + } + + QString ProxyScout::handleRequest( const KURL& url ) + { + try + { + QString result = m_script->evaluate( url ); + QStringList proxies = QStringList::split( ';', result ); + for ( QStringList::ConstIterator it = proxies.begin(); + it != proxies.end(); ++it ) + { + QString 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 QCString& name ) + { + return new ProxyScout( name ); + } +} + +// vim: ts=4 sw=4 et diff --git a/kio/misc/kpac/proxyscout.desktop b/kio/misc/kpac/proxyscout.desktop new file mode 100644 index 000000000..2f1b28f84 --- /dev/null +++ b/kio/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-KDE-ModuleType=Library +X-KDE-Library=proxyscout +X-KDE-FactoryName=proxyscout +X-KDE-Kded-autoload=false +X-KDE-Kded-load-on-demand=true diff --git a/kio/misc/kpac/proxyscout.h b/kio/misc/kpac/proxyscout.h new file mode 100644 index 000000000..afd7968ab --- /dev/null +++ b/kio/misc/kpac/proxyscout.h @@ -0,0 +1,82 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qmap.h> + +#include <kdedmodule.h> +#include <kurl.h> + +#include <time.h> + +class DCOPClientTransaction; +class KInstance; + +namespace KPAC +{ + class Downloader; + class Script; + + class ProxyScout : public KDEDModule + { + Q_OBJECT + K_DCOP + public: + ProxyScout( const QCString& ); + virtual ~ProxyScout(); + + k_dcop: + QString proxyForURL( const KURL& url ); + ASYNC blackListProxy( const QString& proxy ); + ASYNC reset(); + + private slots: + void downloadResult( bool ); + + private: + bool startDownload(); + QString handleRequest( const KURL& url ); + + KInstance* m_instance; + Downloader* m_downloader; + Script* m_script; + + struct QueuedRequest + { + QueuedRequest() : transaction( 0 ) {} + QueuedRequest( const KURL& ); + + DCOPClientTransaction* transaction; + KURL url; + }; + typedef QValueList< QueuedRequest > RequestQueue; + RequestQueue m_requestQueue; + + typedef QMap< QString, time_t > BlackList; + BlackList m_blackList; + time_t m_suspendTime; + }; +} + +#endif // KPAC_PROXYSCOUT_H + +// vim: ts=4 sw=4 et diff --git a/kio/misc/kpac/script.cpp b/kio/misc/kpac/script.cpp new file mode 100644 index 000000000..39d6d3f8e --- /dev/null +++ b/kio/misc/kpac/script.cpp @@ -0,0 +1,465 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qregexp.h> +#include <qstring.h> + +#include <kurl.h> +#include <kjs/object.h> +#include <kresolver.h> + +#include "script.h" + +using namespace KJS; + +QString UString::qstring() const +{ + return QString( reinterpret_cast< const QChar* >( data() ), size() ); +} + +UString::UString( const QString &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 QString& host, bool numeric ) + { + int flags = 0; + + if ( numeric ) + flags = KNetwork::KResolver::NoResolve; + + KNetwork::KResolverResults addresses = + KNetwork::KResolver::resolve( host, QString::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(); + QString host = args[ 0 ].toString( exec ).qstring().lower(); + QString 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(); + QRegExp 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 QString& 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() ); + } + + QString 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/kio/misc/kpac/script.h b/kio/misc/kpac/script.h new file mode 100644 index 000000000..2f5314e9a --- /dev/null +++ b/kio/misc/kpac/script.h @@ -0,0 +1,56 @@ +/* + Copyright (c) 2003 Malte Starostik <[email protected]> + + 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 <qstring.h> + +#include <kjs/interpreter.h> + +class KURL; + +namespace KPAC +{ + class Script + { + public: + class Error + { + public: + Error( const QString& message ) + : m_message( message ) {} + const QString& message() const { return m_message; } + + private: + QString m_message; + }; + + Script( const QString& code ); + QString evaluate( const KURL& ); + + private: + KJS::Interpreter m_interpreter; + }; +} + +#endif // KPAC_SCRIPT_H + +// vim: ts=4 sw=4 et diff --git a/kio/misc/ksendbugmail/Makefile.am b/kio/misc/ksendbugmail/Makefile.am new file mode 100644 index 000000000..f2bb2aebc --- /dev/null +++ b/kio/misc/ksendbugmail/Makefile.am @@ -0,0 +1,26 @@ +# This file is part of the KDE libraries +# Copyright (C) 2000 Stephan Kulow <[email protected]> + +# 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 = ksendbugmail +INCLUDES= -I$(srcdir)/.. $(all_includes) + +ksendbugmail_SOURCES = main.cpp smtp.cpp +ksendbugmail_LDFLAGS = $(all_libraries) $(KDE_RPATH) +ksendbugmail_LDADD = ../../libkio.la + +METASOURCES = AUTO diff --git a/kio/misc/ksendbugmail/main.cpp b/kio/misc/ksendbugmail/main.cpp new file mode 100644 index 000000000..0d12f9e93 --- /dev/null +++ b/kio/misc/ksendbugmail/main.cpp @@ -0,0 +1,142 @@ +// $Id$ + +#include <sys/types.h> +#include "main.h" +#include <pwd.h> +#include <stdlib.h> +#include <unistd.h> + +#include <qtextstream.h> + +#include <kapplication.h> +#include <kemailsettings.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kdebug.h> +#include <kconfig.h> + +#include "smtp.h" + +static KCmdLineOptions options[] = { + { "subject <argument>", I18N_NOOP("Subject line"), 0 }, + { "recipient <argument>", I18N_NOOP("Recipient"), "[email protected]" }, + KCmdLineLastOption +}; + +void BugMailer::slotError(int errornum) { + kdDebug() << "slotError\n"; + QString 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("kdelibs"); + KAboutData d("ksendbugmail", I18N_NOOP("KSendBugMail"), "1.0", + I18N_NOOP("Sends a short bug report to [email protected]"), + KAboutData::License_GPL, "(c) 2000 Stephan Kulow"); + d.addAuthor("Stephan Kulow", I18N_NOOP("Author"), "[email protected]"); + + KCmdLineArgs::init(argc, argv, &d); + KCmdLineArgs::addCmdLineOptions(options); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KApplication a(false, false); + + QCString recipient = args->getOption("recipient"); + if (recipient.isEmpty()) + recipient = "[email protected]"; + else { + if (recipient.at(0) == '\'') { + recipient = recipient.mid(1).left(recipient.length() - 2); + } + } + kdDebug() << "recp \"" << recipient << "\"\n"; + + QCString subject = args->getOption("subject"); + if (subject.isEmpty()) + subject = "(no subject)"; + else { + if (subject.at(0) == '\'') + subject = subject.mid(1).left(subject.length() - 2); + } + QTextIStream input(stdin); + QString text, line; + while (!input.eof()) { + line = input.readLine(); + text += line + "\r\n"; + } + kdDebug() << text << endl; + + KEMailSettings emailConfig; + emailConfig.setProfile(emailConfig.defaultProfileName()); + QString fromaddr = emailConfig.getSetting(KEMailSettings::EmailAddress); + if (!fromaddr.isEmpty()) { + QString name = emailConfig.getSetting(KEMailSettings::RealName); + if (!name.isEmpty()) + fromaddr = name + QString::fromLatin1(" <") + fromaddr + QString::fromLatin1(">"); + } else { + struct passwd *p; + p = getpwuid(getuid()); + fromaddr = QString::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; + + QString server = emailConfig.getSetting(KEMailSettings::OutServer); + if (server.isEmpty()) + server=QString::fromLatin1("bugs.kde.org"); + + SMTP *sm = new SMTP; + BugMailer bm(sm); + + QObject::connect(sm, SIGNAL(messageSent()), &bm, SLOT(slotSend())); + QObject::connect(sm, SIGNAL(error(int)), &bm, SLOT(slotError(int))); + sm->setServerHost(server); + sm->setPort(25); + sm->setSenderAddress(fromaddr); + sm->setRecipientAddress(recipient); + sm->setMessageSubject(subject); + sm->setMessageHeader(QString::fromLatin1("From: %1\r\nTo: %2\r\n").arg(fromaddr).arg(recipient)); + sm->setMessageBody(text); + sm->sendMessage(); + + int r = a.exec(); + kdDebug() << "execing " << r << endl; + delete sm; + return r; +} + +#include "main.moc" diff --git a/kio/misc/ksendbugmail/main.h b/kio/misc/ksendbugmail/main.h new file mode 100644 index 000000000..cd7de398d --- /dev/null +++ b/kio/misc/ksendbugmail/main.h @@ -0,0 +1,20 @@ +#ifndef BUG_MAILER_H +#define BUG_MAILER_H "$Id$" + +#include <qobject.h> + +class SMTP; + +class BugMailer : public QObject { + Q_OBJECT +public: + BugMailer(SMTP* s) : QObject(0, "mailer"), sm(s) {} + +public slots: + void slotError(int); + void slotSend(); +private: + SMTP *sm; +}; + +#endif diff --git a/kio/misc/ksendbugmail/smtp.cpp b/kio/misc/ksendbugmail/smtp.cpp new file mode 100644 index 000000000..fd8211281 --- /dev/null +++ b/kio/misc/ksendbugmail/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 = "[email protected]"; + recipientAddress = "[email protected]"; + 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, SIGNAL(timeout()), this, SLOT(connectTimerTick())); + connect(&timeOutTimer, SIGNAL(timeout()), this, SLOT(connectTimedOut())); + connect(&interactTimer, SIGNAL(timeout()), this, SLOT(interactTimedOut())); + + // some sendmail will give 'duplicate helo' error, quick fix for now + connect(this, SIGNAL(messageSent()), SLOT(closeConnection())); +} + +SMTP::~SMTP() +{ + if(sock){ + delete sock; + sock = 0L; + } + connectTimer.stop(); + timeOutTimer.stop(); +} + +void SMTP::setServerHost(const QString& serverhost) +{ + serverHost = serverhost; +} + +void SMTP::setPort(unsigned short int port) +{ + hostPort = port; +} + +void SMTP::setTimeOut(int timeout) +{ + timeOut = timeout; +} + +void SMTP::setSenderAddress(const QString& 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 QString& recipient) +{ + recipientAddress = recipient; +} + +void SMTP::setMessageSubject(const QString& subject) +{ + messageSubject = subject; +} + +void SMTP::setMessageBody(const QString& message) +{ + messageBody = message; +} + +void SMTP::setMessageHeader(const QString &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 = QString::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 KSocket(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, SIGNAL(readEvent(KSocket *)), this, SLOT(socketRead(KSocket *))); + connect(sock, SIGNAL(closeEvent(KSocket *)), this, SLOT(socketClose(KSocket *))); + // 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(KSocket *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(KSocket *socket) +{ + timeOutTimer.stop(); + disconnect(sock, SIGNAL(readEvent(KSocket *)), this, SLOT(socketRead(KSocket *))); + disconnect(sock, SIGNAL(closeEvent(KSocket *)), this, SLOT(socketClose(KSocket *))); + socket->enableRead(false); + kdDebug() << "connection terminated" << endl; + connected = false; + if(socket){ + delete socket; + socket = 0L; + sock = 0L; + } + emit connectionClosed(); +} + +void SMTP::processLine(QString *line) +{ + int i, stat; + QString 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 = QString::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 = QString::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 = QString::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 = QString::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 = QString::fromLatin1("Subject: %1\r\n").arg(messageSubject); + writeString += messageHeader; + writeString += "\r\n"; + writeString += messageBody; + writeString += QString::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/kio/misc/ksendbugmail/smtp.h b/kio/misc/ksendbugmail/smtp.h new file mode 100644 index 000000000..71a464e98 --- /dev/null +++ b/kio/misc/ksendbugmail/smtp.h @@ -0,0 +1,144 @@ +/* $Id$ */ + +#ifndef SMTP_H +#define SMTP_H + +#include <qobject.h> +#include <qtimer.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 QString& serverhost); + void setPort(unsigned short int port); + void setTimeOut(int timeout); + + bool isConnected(){return connected;}; + bool isFinished(){return finished;}; + QString getLastLine(){return lastLine;}; + + void setSenderAddress(const QString& sender); + void setRecipientAddress(const QString& recipient); + void setMessageSubject(const QString& subject); + void setMessageBody(const QString& message); + void setMessageHeader(const QString &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(QString *line); + +public slots: + void openConnection(); + void sendMessage(); + void closeConnection(); + + void connectTimerTick(); + void connectTimedOut(); + void interactTimedOut(); + + void socketRead(KSocket *); + void socketClose(KSocket *); + +signals: + void connectionClosed(); + void messageSent(); + void error(int); + +private: + QString serverHost; + unsigned short int hostPort; + int timeOut; + + bool connected; + bool finished; + + QString senderAddress; + QString recipientAddress; + QString messageSubject; + QString messageBody, messageHeader; + + SMTPClientStatus state; + SMTPClientStatus lastState; + SMTPServerStatus serverState; + + QString domainName; + + KSocket *sock; + QTimer connectTimer; + QTimer timeOutTimer; + QTimer interactTimer; + + char readBuffer[SMTP_READ_BUFFER_SIZE]; + QString lineBuffer; + QString lastLine; + QString writeString; +}; +#endif diff --git a/kio/misc/kssld/Makefile.am b/kio/misc/kssld/Makefile.am new file mode 100644 index 000000000..63252f46c --- /dev/null +++ b/kio/misc/kssld/Makefile.am @@ -0,0 +1,33 @@ +# This file is part of the KDE libraries +# Copyright (C) 2001 George Staikos <[email protected]> + +# 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)/kio/kssl -I$(top_builddir)/kio/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) +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/kio/misc/kssld/kssld.cpp b/kio/misc/kssld/kssld.cpp new file mode 100644 index 000000000..ff96681e2 --- /dev/null +++ b/kio/misc/kssld/kssld.cpp @@ -0,0 +1,1027 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2001-2005 George Staikos <[email protected]> + + 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 <qtimer.h> + +#include "kssld.h" +#include <kconfig.h> +#include <ksimpleconfig.h> +#include <ksslcertchain.h> +#include <ksslcertificate.h> +#include <ksslcertificatehome.h> +#include <ksslpkcs12.h> +#include <ksslx509map.h> +#include <qptrlist.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <pwd.h> +#include <unistd.h> +#include <qfile.h> +#include <qsortedlist.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <qdatetime.h> + +#include <kmdcodec.h> +#include <kopenssl.h> + +// See design notes at end + +extern "C" { + KDE_EXPORT KDEDModule *create_kssld(const QCString &name) { + return new KSSLD(name); + } + + KDE_EXPORT void *__kde_do_unload; +} + + +static void updatePoliciesConfig(KConfig *cfg) { + QStringList groups = cfg->groupList(); + + for (QStringList::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") < QDateTime::currentDateTime()) { + cfg->deleteGroup(*i); + continue; + } + + QString encodedCertStr = cfg->readEntry("Certificate"); + QCString 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"); + QDateTime expires = cfg->readDateTimeEntry("Expires"); + QStringList hosts = cfg->readListEntry("Hosts"); + QStringList 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 QCString &name) : KDEDModule(name) +{ +// ----------------------- FOR THE CACHE ------------------------------------ + cfg = new KSimpleConfig("ksslpolicies", false); + cfg->setGroup("General"); + if (2 != cfg->readNumEntry("policies version", 0)) { + ::updatePoliciesConfig(cfg); + } + KGlobal::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; + QDateTime expires; + QStringList 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 > QDateTime::currentDateTime()) { + // First convert to a binary format and then write the + // kconfig 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 + QStringList qsl; + QPtrList<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 + QString cfgName(KGlobal::dirs()->findResource("config", "ksslpolicies")); + + if (!cfgName.isEmpty()) { + ::chmod(QFile::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() { +QStringList groups = cfg->groupList(); + + for (QStringList::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") < + QDateTime::currentDateTime()) { + cfg->deleteGroup(*i); + continue; + } + + QCString 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 = QDateTime::currentDateTime(); + // FIXME: make this configurable + node->expires = 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 = QDateTime::currentDateTime(); + n->expires = n->expires.addSecs(3600); + } + + searchAddCert(n->cert); + cacheSaveToDisk(); +} + + +KSSLCertificateCache::KSSLCertificatePolicy KSSLD::cacheGetPolicyByCN(QString cn) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + if (!node->permanent && + node->expires < QDateTime::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 < QDateTime::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(QString cn) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) { + if (!node->permanent && + node->expires < QDateTime::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 < QDateTime::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 < + QDateTime::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(QString 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(QString 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(QString cn, + KSSLCertificateCache::KSSLCertificatePolicy policy, bool permanent, + QDateTime 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, + QDateTime 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; +} + + +QStringList KSSLD::cacheGetHostList(KSSLCertificate cert) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::currentDateTime()) { + certList.remove(node); + cfg->deleteGroup(node->cert->getMD5Digest()); + searchRemoveCert(node->cert); + delete node; + cacheSaveToDisk(); + return QStringList(); + } + + certList.remove(node); + certList.prepend(node); + return node->hosts; + } + } + +return QStringList(); +} + + +bool KSSLD::cacheAddHost(KSSLCertificate cert, QString 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 < + QDateTime::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, QString host) { +KSSLCNode *node; + + for (node = certList.first(); node; node = certList.next()) { + if (cert == *(node->cert)) { + if (!node->permanent && node->expires < + QDateTime::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() { + QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt"; + if (!QFile::exists(path)) + return; + + cfg->setGroup(QString::null); + Q_UINT32 newStamp = KGlobal::dirs()->calcResourceHash("config", "ksslcalist", true); + Q_UINT32 oldStamp = cfg->readUnsignedNumEntry("ksslcalistStamp"); + if (oldStamp != newStamp) + { + caRegenerate(); + cfg->writeEntry("ksslcalistStamp", newStamp); + cfg->sync(); + } +} + +bool KSSLD::caRegenerate() { +QString path = KGlobal::dirs()->saveLocation("kssl") + "/ca-bundle.crt"; + +QFile out(path); + + if (!out.open(IO_WriteOnly)) + return false; + +KConfig cfg("ksslcalist", true, false); + +QStringList x = cfg.groupList(); + + for (QStringList::Iterator i = x.begin(); + i != x.end(); + ++i) { + if ((*i).isEmpty() || *i == "<default>") continue; + + cfg.setGroup(*i); + + if (!cfg.readBoolEntry("site", false)) continue; + + QString 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(QString certificate, bool ssl, bool email, bool code) { +KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit()); + + if (!x) return false; + +KConfig 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 QStringList caReadCerticatesFromFile(QString filename) { + + QStringList certificates; + QString certificate, temp; + QFile file(filename); + + if (!file.open(IO_ReadOnly)) + return certificates; + + while (!file.atEnd()) { + file.readLine(temp, 999); + if (temp.startsWith("-----BEGIN CERTIFICATE-----")) { + certificate = QString::null; + continue; + } + + if (temp.startsWith("-----END CERTIFICATE-----")) { + certificates.append(certificate); + certificate = QString::null; + continue; + } + + certificate += temp.stripWhiteSpace(); + } + + file.close(); + + return certificates; +} + +bool KSSLD::caAddFromFile(QString filename, bool ssl, bool email, bool code) { + + QStringList certificates; + certificates = caReadCerticatesFromFile(filename); + if (certificates.isEmpty()) + return false; + + bool ok = true; + + for (QStringList::Iterator it = certificates.begin(); + it != certificates.end(); ++it ) { + ok &= caAdd(*it, ssl, email, code); + } + + return ok; +} + +bool KSSLD::caRemoveFromFile(QString filename) { + + QStringList certificates; + certificates = caReadCerticatesFromFile(filename); + if (certificates.isEmpty()) + return false; + + bool ok = true; + + for (QStringList::Iterator it = certificates.begin(); + it != certificates.end(); ++it ) { + QString certificate = *it; + KSSLCertificate *x = KSSLCertificate::fromString(certificate.local8Bit()); + ok &= x && caRemove(x->getSubject()); + delete x; + } + + return ok; +} + + +QStringList KSSLD::caList() { +QStringList x; +KConfig cfg("ksslcalist", true, false); + + x = cfg.groupList(); + x.remove("<default>"); + +return x; +} + + +bool KSSLD::caUseForSSL(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("site", false); +} + + + +bool KSSLD::caUseForEmail(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("email", false); +} + + + +bool KSSLD::caUseForCode(QString subject) { +KConfig cfg("ksslcalist", true, false); + + if (!cfg.hasGroup(subject)) + return false; + + cfg.setGroup(subject); +return cfg.readBoolEntry("code", false); +} + + +bool KSSLD::caRemove(QString subject) { +KConfig cfg("ksslcalist", false, false); + if (!cfg.hasGroup(subject)) + return false; + + cfg.deleteGroup(subject); + cfg.sync(); + +return true; +} + + +QString KSSLD::caGetCert(QString subject) { +KConfig cfg("ksslcalist", true, false); + if (!cfg.hasGroup(subject)) + return QString::null; + + cfg.setGroup(subject); + +return cfg.readEntry("x509", QString::null); +} + + +bool KSSLD::caSetUse(QString subject, bool ssl, bool email, bool code) { +KConfig 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); + + QStringList mails; + cert->getEmails(mails); + for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) { + QString email = static_cast<const QString &>(*iter).lower(); + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email); + + if (it == skEmail.end()) + it = skEmail.insert(email, QPtrVector<KSSLCertificate>()); + + QPtrVector<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()); + + QStringList mails; + cert->getEmails(mails); + for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); ++iter) { + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(static_cast<const QString &>(*iter).lower()); + + if (it == skEmail.end()) + break; + + QPtrVector<KSSLCertificate> &elem = *it; + + int n = elem.findRef(cert); + if (n != -1) + elem.remove(n); + } +} + + +QStringList KSSLD::getKDEKeyByEmail(const QString &email) { + QStringList rc; + QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = skEmail.find(email.lower()); + + kdDebug() << "GETKDEKey " << email.latin1() << endl; + + if (it == skEmail.end()) + return rc; + + QPtrVector<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 QString &key) { + QMap<QString, 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 +// + +QStringList KSSLD::getHomeCertificateList() { + return KSSLCertificateHome::getCertificateList(); +} + +bool KSSLD::addHomeCertificateFile(QString filename, QString password, bool storePass) { + return KSSLCertificateHome::addCertificate(filename, password, storePass); +} + +bool KSSLD::addHomeCertificatePKCS12(QString base64cert, QString passToStore) { + bool ok; + KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, passToStore); + ok = KSSLCertificateHome::addCertificate(pkcs12, passToStore); + delete pkcs12; + return ok; +} + +bool KSSLD::deleteHomeCertificateByFile(QString filename, QString password) { + return KSSLCertificateHome::deleteCertificate(filename, password); +} + +bool KSSLD::deleteHomeCertificateByPKCS12(QString base64cert, QString password) { + bool ok; + KSSLPKCS12 *pkcs12 = KSSLPKCS12::fromString(base64cert, password); + ok = KSSLCertificateHome::deleteCertificate(pkcs12); + delete pkcs12; + return ok; +} + +bool KSSLD::deleteHomeCertificateByName(QString 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 QPtrList 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/kio/misc/kssld/kssld.desktop b/kio/misc/kssld/kssld.desktop new file mode 100644 index 000000000..bbabf17a1 --- /dev/null +++ b/kio/misc/kssld/kssld.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Type=Service +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=kssld +X-KDE-FactoryName=kssld +X-KDE-Kded-autoload=false +X-KDE-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 KDE +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 KDE +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/kio/misc/kssld/kssld.h b/kio/misc/kssld/kssld.h new file mode 100644 index 000000000..94cbe3972 --- /dev/null +++ b/kio/misc/kssld/kssld.h @@ -0,0 +1,154 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2001-2005 George Staikos <[email protected]> + + 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 <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qmap.h> +#include <qptrvector.h> + + +class KSimpleConfig; +class KSSLCNode; +class KOpenSSLProxy; + +class KSSLD : public KDEDModule +{ + Q_OBJECT + K_DCOP + +public: + + KSSLD(const QCString &name); + + virtual ~KSSLD(); + +k_dcop: + // + // Certificate Cache methods + // + void cacheAddCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent = true); + KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCN(QString cn); + + KSSLCertificateCache::KSSLCertificatePolicy cacheGetPolicyByCertificate(KSSLCertificate cert); + + bool cacheSeenCN(QString cn); + bool cacheSeenCertificate(KSSLCertificate cert); + + bool cacheRemoveByCN(QString cn); + bool cacheRemoveBySubject(QString subject); + bool cacheRemoveByCertificate(KSSLCertificate cert); + + bool cacheIsPermanent(KSSLCertificate cert); + + void cacheReload(); + + bool cacheModifyByCN(QString cn, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent, + QDateTime expires); + + bool cacheModifyByCertificate(KSSLCertificate cert, + KSSLCertificateCache::KSSLCertificatePolicy policy, + bool permanent, + QDateTime expires); + + QStringList cacheGetHostList(KSSLCertificate cert); + + bool cacheAddHost(KSSLCertificate cert, QString host); + + bool cacheRemoveHost(KSSLCertificate cert, QString host); + + /* Certificate Authorities */ + void caVerifyUpdate(); + bool caRegenerate(); + + QStringList caList(); + + bool caUseForSSL(QString subject); + + bool caUseForEmail(QString subject); + + bool caUseForCode(QString subject); + + bool caAdd(QString certificate, bool ssl, bool email, bool code); + + bool caAddFromFile(QString filename, bool ssl, bool email, bool code); + + bool caRemove(QString subject); + + bool caRemoveFromFile(QString filename); + + QString caGetCert(QString subject); + + bool caSetUse(QString subject, bool ssl, bool email, bool code); + + QStringList getKDEKeyByEmail(const QString &email); + + KSSLCertificate getCertByMD5Digest(const QString &key); + + // + // Certificate Home methods + // + + QStringList getHomeCertificateList(); + + bool addHomeCertificateFile(QString filename, QString password, bool storePass /*=false*/); + + bool addHomeCertificatePKCS12(QString base64cert, QString passToStore); + + bool deleteHomeCertificateByFile(QString filename, QString password); + + bool deleteHomeCertificateByPKCS12(QString base64cert, QString password); + + bool deleteHomeCertificateByName(QString name); + +private: + + void cacheClearList(); + void cacheSaveToDisk(); + void cacheLoadDefaultPolicies(); + + // for the cache portion: + KSimpleConfig *cfg; + QPtrList<KSSLCNode> certList; + + // Our pointer to OpenSSL + KOpenSSLProxy *kossl; + + // + void searchAddCert(KSSLCertificate *cert); + void searchRemoveCert(KSSLCertificate *cert); + + QMap<QString, QPtrVector<KSSLCertificate> > skEmail; + QMap<QString, KSSLCertificate *> skMD5Digest; +}; + + +#endif diff --git a/kio/misc/ktelnetservice.cpp b/kio/misc/ktelnetservice.cpp new file mode 100644 index 000000000..41635b053 --- /dev/null +++ b/kio/misc/ktelnetservice.cpp @@ -0,0 +1,112 @@ +/* + Copyright (c) 2001 Malte Starostik <[email protected]> + based on kmailservice.cpp, + Copyright (c) 2000 Simon Hausmann <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the 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("kdelibs"); + KCmdLineArgs::init(argc, argv, "ktelnetservice", I18N_NOOP("telnet service"), + I18N_NOOP("telnet protocol handler"), "unknown"); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->count() != 1) + return 1; + + KConfig *config = new KConfig("kdeglobals", true); + config->setGroup("General"); + QString terminal = config->readPathEntry("TerminalApplication", "konsole"); + + KURL url(args->arg(0)); + QStringList 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(); + } + + QString 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" << QString::number(url.port()); + else + cmd << QString::number(url.port()); + } + + app.kdeinitExec(terminal, cmd); + + return 0; +} + +// vim: ts=4 sw=4 noet diff --git a/kio/misc/kwalletd/Makefile.am b/kio/misc/kwalletd/Makefile.am new file mode 100644 index 000000000..f57f2c692 --- /dev/null +++ b/kio/misc/kwalletd/Makefile.am @@ -0,0 +1,35 @@ +# This file is part of the KDE libraries +# Copyright (C) 2002 George Staikos <[email protected]> + +# 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)/kwallet/backend -I$(top_builddir)/kwallet/backend -I$(top_srcdir)/kwallet/client -I$(top_builddir)/kwallet/client $(all_includes) + +kde_module_LTLIBRARIES = kded_kwalletd.la + +kded_kwalletd_la_LDFLAGS = $(all_libraries) -module -avoid-version +kded_kwalletd_la_LIBADD = $(LIB_KIO) ../../../kwallet/backend/libkwalletbackend.la ../../../kwallet/client/libkwalletclient.la $(LIB_KDED) +kded_kwalletd_la_SOURCES = kwalletd.cpp kwalletd.skel ktimeout.cpp kwalletwizard.ui kbetterthankdialogbase.ui + +METASOURCES = AUTO + +noinst_HEADERS = kwalletd.h ktimeout.h kwalletwizard.ui.h + +services_DATA = kwalletd.desktop +servicesdir = $(kde_servicesdir)/kded + +kwalletwizard.lo: kwalletwizard.ui kwalletwizard.ui.h +kbetterthankdialogbase.lo: kbetterthankdialogbase.ui kbetterthankdialogbase.ui.h diff --git a/kio/misc/kwalletd/kbetterthankdialogbase.ui b/kio/misc/kwalletd/kbetterthankdialogbase.ui new file mode 100644 index 000000000..ecf2d236f --- /dev/null +++ b/kio/misc/kwalletd/kbetterthankdialogbase.ui @@ -0,0 +1,154 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KBetterThanKDialogBase</class> +<widget class="QDialog"> + <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="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>_allowOnce</cstring> + </property> + <property name="text"> + <string>Allow &Once</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>_allowAlways</cstring> + </property> + <property name="text"> + <string>Allow &Always</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>_deny</cstring> + </property> + <property name="text"> + <string>&Deny</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>_denyForever</cstring> + </property> + <property name="text"> + <string>Deny &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> +<slots> + <slot access="private">clicked()</slot> + <slot>setLabel( const QString & label )</slot> + <slot access="private">init()</slot> + <slot access="protected">accept()</slot> + <slot access="protected">reject()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> +</includehints> +</UI> diff --git a/kio/misc/kwalletd/kbetterthankdialogbase.ui.h b/kio/misc/kwalletd/kbetterthankdialogbase.ui.h new file mode 100644 index 000000000..565e0880e --- /dev/null +++ b/kio/misc/kwalletd/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 QString & label ) +{ + _label->setText(label); +} + + +void KBetterThanKDialogBase::init() +{ + _allowOnce->setFocus(); +} + + +void KBetterThanKDialogBase::accept() +{ + setResult(0); +} + + +void KBetterThanKDialogBase::reject() +{ + QDialog::reject(); + setResult(2); +} diff --git a/kio/misc/kwalletd/ktimeout.cpp b/kio/misc/kwalletd/ktimeout.cpp new file mode 100644 index 000000000..1827b8bba --- /dev/null +++ b/kio/misc/kwalletd/ktimeout.cpp @@ -0,0 +1,84 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2003 George Staikos <[email protected]> + + 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) +: QObject(), _timers(size) { + _timers.setAutoDelete(true); +} + + +KTimeout::~KTimeout() { + clear(); +} + + +void KTimeout::clear() { + _timers.clear(); +} + + +void KTimeout::removeTimer(int id) { + QTimer *t = _timers.find(id); + if (t != 0L) { + _timers.remove(id); // autodeletes + } +} + + +void KTimeout::addTimer(int id, int timeout) { + if (_timers.find(id) != 0L) { + return; + } + + QTimer *t = new QTimer; + connect(t, SIGNAL(timeout()), this, SLOT(timeout())); + t->start(timeout); + _timers.insert(id, t); +} + + +void KTimeout::resetTimer(int id, int timeout) { + QTimer *t = _timers.find(id); + if (t) { + t->changeInterval(timeout); + } +} + + +void KTimeout::timeout() { + const QTimer *t = static_cast<const QTimer*>(sender()); + if (t) { + QIntDictIterator<QTimer> it(_timers); + for (; it.current(); ++it) { + if (it.current() == t) { + emit timedOut(it.currentKey()); + return; + } + } + } +} + + +#include "ktimeout.moc" + diff --git a/kio/misc/kwalletd/ktimeout.h b/kio/misc/kwalletd/ktimeout.h new file mode 100644 index 000000000..287de44cb --- /dev/null +++ b/kio/misc/kwalletd/ktimeout.h @@ -0,0 +1,52 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2003 George Staikos <[email protected]> + + 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 <qintdict.h> +#include <qobject.h> +#include <qtimer.h> + +// @internal +class KTimeout : public QObject { + 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: + QIntDict<QTimer> _timers; +}; + +#endif diff --git a/kio/misc/kwalletd/kwalletd.cpp b/kio/misc/kwalletd/kwalletd.cpp new file mode 100644 index 000000000..686a99d6f --- /dev/null +++ b/kio/misc/kwalletd/kwalletd.cpp @@ -0,0 +1,1428 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2002-2004 George Staikos <[email protected]> + + 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 "kwalletwizard.h" +#include "kwalletd.h" +#include "ktimeout.h" + +#include <dcopclient.h> +#include <dcopref.h> +#include <kactivelabel.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kdirwatch.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpassdlg.h> +#include <kstandarddirs.h> +#include <kwalletentry.h> +#include <kwin.h> + +#include <qdir.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qregexp.h> +#include <qstylesheet.h> +#include <qvbox.h> + +#include <assert.h> + +extern "C" { + KDE_EXPORT KDEDModule *create_kwalletd(const QCString &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; + QCString rawappid, returnObject; + QCString appid; + uint wId; + QString wallet; + bool modal; +}; + + +KWalletD::KWalletD(const QCString &name) +: KDEDModule(name), _failed(0) { + srand(time(0)); + _showingFailureNotify = false; + _transactions.setAutoDelete(true); + _timeouts = new KTimeout(17); + _closeIdle = false; + _idleTime = 0; + connect(_timeouts, SIGNAL(timedOut(int)), this, SLOT(timedOut(int))); + reconfigure(); + KGlobal::dirs()->addResourceType("kwallet", "share/apps/kwallet"); + connect(KApplication::dcopClient(), + SIGNAL(applicationRemoved(const QCString&)), + this, + SLOT(slotAppUnregistered(const QCString&))); + _dw = new KDirWatch(this, "KWallet Directory Watcher"); + _dw->addDir(KGlobal::dirs()->saveLocation("kwallet")); + _dw->startScan(true); + connect(_dw, SIGNAL(dirty(const QString&)), this, 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(); + QCString 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) { + QPtrListIterator<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) { + QByteArray replyData; + QDataStream stream(replyData, IO_WriteOnly); + stream << res; + xact->client->endTransaction(xact->transaction, replyType, replyData); + } + _transactions.removeRef(xact); + } + + processing = false; +} + + +void KWalletD::openAsynchronous(const QString& wallet, const QCString& returnObject, uint wId) { + DCOPClient *dc = callingDcopClient(); + if (!dc) { + return; + } + + QCString appid = dc->senderId(); + if (!_enabled || + !QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) { + DCOPRef(appid, returnObject).send("walletOpenResult", -1); + return; + } + + QCString 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); + + QTimer::singleShot(0, this, SLOT(processTransactions())); + checkActiveDialog(); +} + + +int KWalletD::openPath(const QString& path, uint wId) { + if (!_enabled) { // guard + return -1; + } + + // FIXME: setup transaction + int rc = internalOpen(friendlyDCOPPeerName(), path, true, wId); + return rc; +} + + +int KWalletD::open(const QString& wallet, uint wId) { + if (!_enabled) { // guard + return -1; + } + + if (!QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) { + return -1; + } + + QCString 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 + QTimer::singleShot(0, this, SLOT(processTransactions())); + checkActiveDialog(); + return 0; // process later +} + + +// Sets up a dialog that will be shown by kwallet. +void KWalletD::setupDialog( QWidget* dialog, WId wId, const QCString& appid, bool modal ) { + if( wId != 0 ) + KWin::setMainWindow( dialog, wId ); // correct, set dialog parent + else { + if( appid.isEmpty()) + kdWarning() << "Using kwallet without parent window!" << endl; + else + kdWarning() << "Application '" << appid << "' using kwallet 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 QCString& appid, const QString& 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 == QDialog::Accepted) { + KConfig cfg("kwalletrc"); + 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()); + QByteArray 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) { + KConfig cfg("kwalletrc"); + _firstUse = false; + cfg.setGroup("Wallet"); + cfg.writeEntry("First Use", false); + cfg.sync(); + } + + int rc = internalOpen(appid, wallet, false, wId, modal); + return rc; +} + + +int KWalletD::internalOpen(const QCString& appid, const QString& wallet, bool isPath, WId w, bool modal) { + int rc = -1; + bool brandNew = false; + + QCString thisApp; + if (appid.isEmpty()) { + thisApp = "KDE System"; + } else { + thisApp = appid; + } + + if (implicitDeny(wallet, thisApp)) { + return -1; + } + + for (QIntDictIterator<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 && QFile::exists(wallet)) || (!isPath && KWallet::Backend::exists(wallet))) { + int pwless = b->open(QByteArray()); + 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>KDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.").arg(QStyleSheet::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(QStyleSheet::escape(appid)).arg(QStyleSheet::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("KDE 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 KDE 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(QStyleSheet::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>KDE 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(QStyleSheet::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(QStyleSheet::escape(appid)).arg(QStyleSheet::escape(wallet))); + } + brandNew = true; + kpd->setButtonOK(KGuiItem(i18n("C&reate"),"filenew")); + } + + if (kpd) { + kpd->setCaption(i18n("KDE 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(QByteArray().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(QStyleSheet::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); + } + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << wallet; + if (brandNew) { + emitDCOPSignal("walletCreated(QString)", data); + } + emitDCOPSignal("walletOpened(QString)", data); + if (_wallets.count() == 1 && _launchManager) { + KApplication::startServiceByDesktopName("kwalletmanager-kwalletd"); + } + } 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 QCString& appid, const QString& wallet, WId w) { + int response = 0; + + QCString thisApp; + if (appid.isEmpty()) { + thisApp = "KDE System"; + } else { + thisApp = appid; + } + + if (!implicitAllow(wallet, thisApp)) { + KBetterThanKDialogBase *dialog = new KBetterThanKDialogBase; + if (appid.isEmpty()) { + dialog->setLabel(i18n("<qt>KDE has requested access to the open wallet '<b>%1</b>'.").arg(QStyleSheet::escape(wallet))); + } else { + dialog->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.").arg(QStyleSheet::escape(QString(appid))).arg(QStyleSheet::escape(wallet))); + } + setupDialog( dialog, w, appid, false ); + response = dialog->exec(); + delete dialog; + } + + if (response == 0 || response == 1) { + if (response == 1) { + KConfig cfg("kwalletrc"); + cfg.setGroup("Auto Allow"); + QStringList apps = cfg.readListEntry(wallet); + if (!apps.contains(thisApp)) { + apps += thisApp; + _implicitAllowMap[wallet] += thisApp; + cfg.writeEntry(wallet, apps); + cfg.sync(); + } + } + } else if (response == 3) { + KConfig cfg("kwalletrc"); + cfg.setGroup("Auto Deny"); + QStringList 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 QString& wallet) { + QString path = KGlobal::dirs()->saveLocation("kwallet") + QDir::separator() + wallet + ".kwl"; + + if (QFile::exists(path)) { + close(wallet, true); + QFile::remove(path); + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << wallet; + emitDCOPSignal("walletDeleted(QString)", data); + return 0; + } + + return -1; +} + + +void KWalletD::changePassword(const QString& wallet, uint wId) { + QCString 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); + + QTimer::singleShot(0, this, SLOT(processTransactions())); + checkActiveDialog(); +} + + +void KWalletD::doTransactionChangePassword(const QCString& appid, const QString& wallet, uint wId) { + QIntDictIterator<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("KDE 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(QStyleSheet::escape(wallet))); + kpd->setCaption(i18n("KDE 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; + QByteArray 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("KDE 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("KDE Wallet Service")); + reclose = true; + } + } + } + } + + delete kpd; + + if (reclose) { + close(handle, true); + } +} + + +int KWalletD::close(const QString& wallet, bool force) { + int handle = -1; + KWallet::Backend *w = 0L; + + for (QIntDictIterator<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 QString& 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(QByteArray().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) { + QCString 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(QByteArray().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 QString& wallet) const { + for (QIntDictIterator<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; + QTimer::singleShot(0, this, SLOT(notifyFailures())); + } else if (rc != 0) { + _failed = 0; + } + + return rc != 0; +} + + +QStringList KWalletD::wallets() const { + QString path = KGlobal::dirs()->saveLocation("kwallet"); + QDir dir(path, "*.kwl"); + QStringList rc; + + dir.setFilter(QDir::Files | QDir::NoSymLinks); + + const QFileInfoList *list = dir.entryInfoList(); + QFileInfoListIterator it(*list); + QFileInfo *fi; + while ((fi = it.current()) != 0L) { + QString 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))) { + QByteArray p; + QString wallet = b->walletName(); + p.duplicate(_passwords[wallet].data(), _passwords[wallet].length()); + b->sync(p); + p.fill(0); + } +} + + +QStringList KWalletD::folderList(int handle) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + return b->folderList(); + } + + return QStringList(); +} + + +bool KWalletD::hasFolder(int handle, const QString& f) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + return b->hasFolder(f); + } + + return false; +} + + +bool KWalletD::removeFolder(int handle, const QString& f) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + bool rc = b->removeFolder(f); + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << b->walletName(); + emitDCOPSignal("folderListUpdated(QString)", data); + return rc; + } + + return false; +} + + +bool KWalletD::createFolder(int handle, const QString& f) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + bool rc = b->createFolder(f); + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << b->walletName(); + emitDCOPSignal("folderListUpdated(QString)", data); + return rc; + } + + return false; +} + + +QByteArray KWalletD::readMap(int handle, const QString& folder, const QString& 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 QByteArray(); +} + + +QMap<QString,QByteArray> KWalletD::readMapList(int handle, const QString& folder, const QString& key) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + QPtrList<KWallet::Entry> e = b->readEntryList(key); + QMap<QString, QByteArray> rc; + QPtrListIterator<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 QMap<QString, QByteArray>(); +} + + +QByteArray KWalletD::readEntry(int handle, const QString& folder, const QString& key) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + KWallet::Entry *e = b->readEntry(key); + if (e) { + return e->value(); + } + } + + return QByteArray(); +} + + +QMap<QString, QByteArray> KWalletD::readEntryList(int handle, const QString& folder, const QString& key) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + QPtrList<KWallet::Entry> e = b->readEntryList(key); + QMap<QString, QByteArray> rc; + QPtrListIterator<KWallet::Entry> it(e); + KWallet::Entry *entry; + while ((entry = it.current())) { + rc.insert(entry->key(), entry->value()); + ++it; + } + return rc; + } + + return QMap<QString, QByteArray>(); +} + + +QStringList KWalletD::entryList(int handle, const QString& folder) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + return b->entryList(); + } + + return QStringList(); +} + + +QString KWalletD::readPassword(int handle, const QString& folder, const QString& 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 QString::null; +} + + +QMap<QString, QString> KWalletD::readPasswordList(int handle, const QString& folder, const QString& key) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + QPtrList<KWallet::Entry> e = b->readEntryList(key); + QMap<QString, QString> rc; + QPtrListIterator<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 QMap<QString, QString>(); +} + + +int KWalletD::writeMap(int handle, const QString& folder, const QString& key, const QByteArray& 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); + emitFolderUpdated(b->walletName(), folder); + return 0; + } + + return -1; +} + + +int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& 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); + emitFolderUpdated(b->walletName(), folder); + return 0; + } + + return -1; +} + + +int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& 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); + emitFolderUpdated(b->walletName(), folder); + return 0; + } + + return -1; +} + + +int KWalletD::writePassword(int handle, const QString& folder, const QString& key, const QString& 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); + emitFolderUpdated(b->walletName(), folder); + return 0; + } + + return -1; +} + + +int KWalletD::entryType(int handle, const QString& folder, const QString& 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 QString& folder, const QString& 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 QString& folder, const QString& key) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + if (!b->hasFolder(folder)) { + return 0; + } + b->setFolder(folder); + bool rc = b->removeEntry(key); + emitFolderUpdated(b->walletName(), folder); + return rc ? 0 : -3; + } + + return -1; +} + + +void KWalletD::slotAppUnregistered(const QCString& app) { + if (_handles.contains(app)) { + QValueList<int> l = _handles[app]; + for (QValueList<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 (QMap<QCString,QValueList<int> >::Iterator i = _handles.begin(); + i != _handles.end(); + ++i) { + i.data().remove(handle); + } +} + + +KWallet::Backend *KWalletD::getWallet(const QCString& 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; + QTimer::singleShot(0, this, 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("KDE Wallet Service")); + _showingFailureNotify = false; + } +} + + +void KWalletD::doCloseSignals(int handle, const QString& wallet) { + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << handle; + emitDCOPSignal("walletClosed(int)", data); + + QByteArray data2; + QDataStream ds2(data2, IO_WriteOnly); + ds2 << wallet; + emitDCOPSignal("walletClosed(QString)", data2); + + if (_wallets.isEmpty()) { + emitDCOPSignal("allWalletsClosed()", QByteArray()); + } +} + + +int KWalletD::renameEntry(int handle, const QString& folder, const QString& oldName, const QString& newName) { + KWallet::Backend *b; + + if ((b = getWallet(friendlyDCOPPeerName(), handle))) { + b->setFolder(folder); + int rc = b->renameEntry(oldName, newName); + emitFolderUpdated(b->walletName(), folder); + return rc; + } + + return -1; +} + + +QStringList KWalletD::users(const QString& wallet) const { + QStringList rc; + + for (QIntDictIterator<KWallet::Backend> it(_wallets); + it.current(); + ++it) { + if (it.current()->walletName() == wallet) { + for (QMap<QCString,QValueList<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 QString& wallet, const QCString& application) { + for (QIntDictIterator<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); + } + + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << wallet; + ds << application; + emitDCOPSignal("applicationDisconnected(QString,QCString)", data); + + return true; + } + } + } + + return false; +} + + +void KWalletD::emitFolderUpdated(const QString& wallet, const QString& folder) { + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << wallet; + ds << folder; + emitDCOPSignal("folderUpdated(QString,QString)", data); +} + + +void KWalletD::emitWalletListDirty() { + emitDCOPSignal("walletListDirty()", QByteArray()); +} + + +void KWalletD::reconfigure() { + KConfig cfg("kwalletrc"); + 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 + QIntDictIterator<KWallet::Backend> it(_wallets); + for (; it.current(); ++it) { + _timeouts->resetTimer(it.currentKey(), _idleTime); + } + } + + if (!idleSave) { // add timers for all the wallets + QIntDictIterator<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"); + QStringList entries = cfg.entryMap("Auto Allow").keys(); + for (QStringList::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 (QStringList::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()) { + QIntDictIterator<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 QString& wallet, const QString& folder) { + if (!wallets().contains(wallet)) { + return true; + } + + for (QIntDictIterator<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(QByteArray()); + bool rc = b->folderDoesNotExist(folder); + delete b; + return rc; +} + + +bool KWalletD::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key) { + if (!wallets().contains(wallet)) { + return true; + } + + for (QIntDictIterator<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(QByteArray()); + bool rc = b->entryDoesNotExist(folder, key); + delete b; + return rc; +} + + +bool KWalletD::implicitAllow(const QString& wallet, const QCString& app) { + return _implicitAllowMap[wallet].contains(QString::fromLocal8Bit(app)); +} + + +bool KWalletD::implicitDeny(const QString& wallet, const QCString& app) { + return _implicitDenyMap[wallet].contains(QString::fromLocal8Bit(app)); +} + + +QCString KWalletD::friendlyDCOPPeerName() { + DCOPClient *dc = callingDcopClient(); + if (!dc) { + return ""; + } + return dc->senderId().replace(QRegExp("-[0-9]+$"), ""); +} + + +void KWalletD::timedOut(int id) { + KWallet::Backend *w = _wallets.find(id); + if (w) { + closeWallet(w, id, true); + } +} + + +void KWalletD::closeAllWallets() { + QIntDict<KWallet::Backend> tw = _wallets; + + for (QIntDictIterator<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 (QMap<QString,QCString>::Iterator it = _passwords.begin(); + it != _passwords.end(); + ++it) { + it.data().fill(0); + } + _passwords.clear(); +} + + +QString KWalletD::networkWallet() { + return KWallet::Wallet::NetworkWallet(); +} + + +QString KWalletD::localWallet() { + return KWallet::Wallet::LocalWallet(); +} + + +#include "kwalletd.moc" diff --git a/kio/misc/kwalletd/kwalletd.desktop b/kio/misc/kwalletd/kwalletd.desktop new file mode 100644 index 000000000..b33851ceb --- /dev/null +++ b/kio/misc/kwalletd/kwalletd.desktop @@ -0,0 +1,151 @@ +[Desktop Entry] +Type=Service +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=kwalletd +X-KDE-FactoryName=kwalletd +X-KDE-Kded-autoload=false +X-KDE-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]=KDE 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 მოდული KDE-სთვის +Comment[kk]=KDE KWallet әмиянін басқару қызметтің модулі +Comment[km]=ម៉ូឌុល daemon KWallet សម្រាប់ KDED +Comment[lb]=KWallet-Dämonmodul fir KDED +Comment[lt]=KDE 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 KDE +Comment[ro]=Modul demon KWallet pentru KDED +Comment[ru]=Управление бумажником KDE +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/kio/misc/kwalletd/kwalletd.h b/kio/misc/kwalletd/kwalletd.h new file mode 100644 index 000000000..afa999f24 --- /dev/null +++ b/kio/misc/kwalletd/kwalletd.h @@ -0,0 +1,195 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2002-2004 George Staikos <[email protected]> + + 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 <qintdict.h> +#include <qstring.h> +#include <qwidget.h> +#include <qguardedptr.h> +#include "kwalletbackend.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 QCString &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 QString& wallet, uint wId); + + // Open and unlock the wallet with this path + virtual int openPath(const QString& path, uint wId); + + // Asynchronous open - must give the object to return the handle + // to. + virtual void openAsynchronous(const QString& wallet, const QCString& 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 QString& 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 QString& wallet); + + // Returns true if the wallet is open + virtual bool isOpen(const QString& wallet) const; + virtual bool isOpen(int handle); + + // List the users of this wallet + virtual QStringList users(const QString& wallet) const; + + // Change the password of this wallet + virtual void changePassword(const QString& wallet, uint wId); + + // A list of all wallets + virtual QStringList wallets() const; + + // A list of all folders in this wallet + virtual QStringList folderList(int handle); + + // Does this wallet have this folder? + virtual bool hasFolder(int handle, const QString& folder); + + // Create this folder + virtual bool createFolder(int handle, const QString& folder); + + // Remove this folder + virtual bool removeFolder(int handle, const QString& folder); + + // List of entries in this folder + virtual QStringList entryList(int handle, const QString& 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 QByteArray readEntry(int handle, const QString& folder, const QString& key); + virtual QByteArray readMap(int handle, const QString& folder, const QString& key); + virtual QString readPassword(int handle, const QString& folder, const QString& key); + virtual QMap<QString, QByteArray> readEntryList(int handle, const QString& folder, const QString& key); + virtual QMap<QString, QByteArray> readMapList(int handle, const QString& folder, const QString& key); + virtual QMap<QString, QString> readPasswordList(int handle, const QString& folder, const QString& key); + + // Rename an entry. rc=0 on success. + virtual int renameEntry(int handle, const QString& folder, const QString& oldName, const QString& newName); + + // Write an entry. rc=0 on success. + virtual int writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value, int entryType); + virtual int writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value); + virtual int writeMap(int handle, const QString& folder, const QString& key, const QByteArray& value); + virtual int writePassword(int handle, const QString& folder, const QString& key, const QString& value); + + // Does the entry exist? + virtual bool hasEntry(int handle, const QString& folder, const QString& key); + + // What type is the entry? + virtual int entryType(int handle, const QString& folder, const QString& key); + + // Remove an entry. rc=0 on success. + virtual int removeEntry(int handle, const QString& folder, const QString& key); + + // Disconnect an app from a wallet + virtual bool disconnectApplication(const QString& wallet, const QCString& application); + + virtual void reconfigure(); + + // Determine + virtual bool folderDoesNotExist(const QString& wallet, const QString& folder); + virtual bool keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key); + + virtual void closeAllWallets(); + + virtual QString networkWallet(); + + virtual QString localWallet(); + + private slots: + void slotAppUnregistered(const QCString& app); + void emitWalletListDirty(); + void timedOut(int); + void notifyFailures(); + void processTransactions(); + + private: + int internalOpen(const QCString& appid, const QString& wallet, bool isPath = false, WId w = 0, bool modal = false); + bool isAuthorizedApp(const QCString& appid, const QString& wallet, WId w); + // This also validates the handle. May return NULL. + KWallet::Backend* getWallet(const QCString& appid, int handle); + // Generate a new unique handle. + int generateHandle(); + // Invalidate a handle (remove it from the QMap) + void invalidateHandle(int handle); + // Emit signals about closing wallets + void doCloseSignals(int,const QString&); + void emitFolderUpdated(const QString&, const QString&); + // Internal - close this wallet. + int closeWallet(KWallet::Backend *w, int handle, bool force); + // Implicitly allow access for this application + bool implicitAllow(const QString& wallet, const QCString& app); + bool implicitDeny(const QString& wallet, const QCString& app); + QCString friendlyDCOPPeerName(); + + void doTransactionChangePassword(const QCString& appid, const QString& wallet, uint wId); + int doTransactionOpen(const QCString& appid, const QString& wallet, uint wId, bool modal); + + void setupDialog( QWidget* dialog, WId wId, const QCString& appid, bool modal ); + void checkActiveDialog(); + + QIntDict<KWallet::Backend> _wallets; + QMap<QCString,QValueList<int> > _handles; + QMap<QString,QCString> _passwords; + KDirWatch *_dw; + int _failed; + + bool _leaveOpen, _closeIdle, _launchManager, _enabled; + bool _openPrompt, _firstUse, _showingFailureNotify; + int _idleTime; + QMap<QString,QStringList> _implicitAllowMap, _implicitDenyMap; + KTimeout *_timeouts; + + QPtrList<KWalletTransaction> _transactions; + QGuardedPtr< QWidget > activeDialog; +}; + + +#endif diff --git a/kio/misc/kwalletd/kwalletwizard.ui b/kio/misc/kwalletd/kwalletwizard.ui new file mode 100644 index 000000000..609508e11 --- /dev/null +++ b/kio/misc/kwalletd/kwalletwizard.ui @@ -0,0 +1,545 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KWalletWizard</class> +<widget class="QWizard"> + <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="QWidget"> + <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="QLabel" 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><u>KWallet</u> - The KDE Wallet System</string> + </property> + <property name="textFormat"> + <enum>RichText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignCenter</set> + </property> + </widget> + <widget class="QLabel" 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="QButtonGroup" 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="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>_basic</cstring> + </property> + <property name="text"> + <string>&Basic setup (recommended)</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>_advanced</cstring> + </property> + <property name="text"> + <string>&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="QWidget"> + <property name="name"> + <cstring>page4</cstring> + </property> + <attribute name="title"> + <string>Information</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" 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 <i>wallet</i> 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="QWidget"> + <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="QLabel" 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 <i>cannot</i> 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="QLayoutWidget" row="3" column="1"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <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="QLabel"> + <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="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>_pass1</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + </widget> + <widget class="QLineEdit"> + <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="QCheckBox" 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="QLabel" 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="QWidget"> + <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="QLabel" 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="QCheckBox" 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="QCheckBox" 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 QString&)</signal> + <receiver>KWalletWizard</receiver> + <slot>passwordPageUpdate()</slot> + </connection> + <connection> + <sender>_pass2</sender> + <signal>textChanged(const QString&)</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">qcheckbox.h</include> + <include location="global" impldecl="in implementation">klocale.h</include> + <include location="local" impldecl="in implementation">kwalletwizard.ui.h</include> +</includes> +<slots> + <slot access="private">passwordPageUpdate()</slot> + <slot access="private">init()</slot> + <slot>setAdvanced()</slot> + <slot>setBasic()</slot> + <slot access="private">destroy()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kio/misc/kwalletd/kwalletwizard.ui.h b/kio/misc/kwalletd/kwalletwizard.ui.h new file mode 100644 index 000000000..95346355a --- /dev/null +++ b/kio/misc/kwalletd/kwalletwizard.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(QString::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/kio/misc/mms.protocol b/kio/misc/mms.protocol new file mode 100644 index 000000000..8fde7c000 --- /dev/null +++ b/kio/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/kio/misc/mmst.protocol b/kio/misc/mmst.protocol new file mode 100644 index 000000000..1f0f7636b --- /dev/null +++ b/kio/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/kio/misc/mmsu.protocol b/kio/misc/mmsu.protocol new file mode 100644 index 000000000..deda935fc --- /dev/null +++ b/kio/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/kio/misc/pnm.protocol b/kio/misc/pnm.protocol new file mode 100644 index 000000000..3ca3a7d23 --- /dev/null +++ b/kio/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/kio/misc/rlogin.protocol b/kio/misc/rlogin.protocol new file mode 100644 index 000000000..0757e88ab --- /dev/null +++ b/kio/misc/rlogin.protocol @@ -0,0 +1,13 @@ +[Protocol] +exec=ktelnetservice %u +protocol=rlogin +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +DocPath=kioslave/rlogin.html +Icon=konsole diff --git a/kio/misc/rtsp.protocol b/kio/misc/rtsp.protocol new file mode 100644 index 000000000..301312260 --- /dev/null +++ b/kio/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/kio/misc/rtspt.protocol b/kio/misc/rtspt.protocol new file mode 100644 index 000000000..9e4fe9626 --- /dev/null +++ b/kio/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/kio/misc/rtspu.protocol b/kio/misc/rtspu.protocol new file mode 100644 index 000000000..9cc9299f6 --- /dev/null +++ b/kio/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/kio/misc/ssh.protocol b/kio/misc/ssh.protocol new file mode 100644 index 000000000..f31a6f4a2 --- /dev/null +++ b/kio/misc/ssh.protocol @@ -0,0 +1,13 @@ +[Protocol] +exec=ktelnetservice %u +protocol=ssh +input=none +output=none +helper=true +listing=false +reading=false +writing=false +makedir=false +deleting=false +Icon=konsole + diff --git a/kio/misc/telnet.protocol b/kio/misc/telnet.protocol new file mode 100644 index 000000000..810011594 --- /dev/null +++ b/kio/misc/telnet.protocol @@ -0,0 +1,13 @@ +[Protocol] +exec=ktelnetservice %u +protocol=telnet +input=none +output=none +helper=true +listing= +reading=false +writing=false +makedir=false +deleting=false +DocPath=kioslave/telnet.html +Icon=konsole diff --git a/kio/misc/uiserver.cpp b/kio/misc/uiserver.cpp new file mode 100644 index 000000000..1948d57d4 --- /dev/null +++ b/kio/misc/uiserver.cpp @@ -0,0 +1,1413 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Matej Koss <[email protected]> + David Faure <[email protected]> + 2001 George Staikos <[email protected]> + + 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 <qtimer.h> + +#include <qregexp.h> +#include <qheader.h> +#include <qevent.h> + +#include <ksqueezedtextlabel.h> +#include <kconfig.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 <kdesu/client.h> +#include <kwin.h> +#include <kdialog.h> +#include <ksystemtray.h> +#include <kpopupmenu.h> +#include <kaction.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpopupmenu.h> +#include <qheader.h> + +#include "observer_stub.h" +#include "observer.h" // for static methods only +#include "kio/defaultprogress.h" +#include "kio/jobclasses.h" +#include "uiserver.h" +#include "passdlg.h" +#include "kio/renamedlg.h" +#include "kio/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, SLOT(slotConfigure())); + pop->insertItem(i18n("Remove"), uis, SLOT(slotRemoveSystemTrayIcon())); + setPixmap(loadIcon("filesave")); + //actionCollection()->action("file_quit")->setEnabled(true); + KStdAction::quit(uis, SLOT(slotQuit()), actionCollection()); + } +}; + +class ProgressConfigDialog:public KDialogBase +{ + public: + ProgressConfigDialog(QWidget* parent); + ~ProgressConfigDialog() {} + void setChecked(int i, bool on); + bool isChecked(int i) const; + friend class UIServer; + private: + QCheckBox *m_showSystemTrayCb; + QCheckBox *m_keepOpenCb; + QCheckBox *m_toolBarCb; + QCheckBox *m_statusBarCb; + QCheckBox *m_headerCb; + QCheckBox *m_fixedWidthCb; + KListView *m_columns; + QCheckListItem *(m_items[ListProgress::TB_MAX]); +}; + +ProgressConfigDialog::ProgressConfigDialog(QWidget *parent) +:KDialogBase(KDialogBase::Plain,i18n("Configure Network Operation Window"),KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, + KDialogBase::Ok, parent, "configprog", false) +{ + QVBoxLayout *layout=new QVBoxLayout(plainPage(),spacingHint()); + m_showSystemTrayCb=new QCheckBox(i18n("Show system tray icon"), plainPage()); + m_keepOpenCb=new QCheckBox(i18n("Keep network operation window always open"), plainPage()); + m_headerCb=new QCheckBox(i18n("Show column headers"), plainPage()); + m_toolBarCb=new QCheckBox(i18n("Show toolbar"), plainPage()); + m_statusBarCb=new QCheckBox(i18n("Show statusbar"), plainPage()); + m_fixedWidthCb=new QCheckBox(i18n("Column widths are user adjustable"), plainPage()); + QLabel *label=new QLabel(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 QCheckListItem(m_columns, i18n("URL"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_REMAINING_TIME] =new QCheckListItem(m_columns, i18n("Remaining Time", "Rem. Time"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_SPEED] =new QCheckListItem(m_columns, i18n("Speed"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_TOTAL] =new QCheckListItem(m_columns, i18n("Size"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_PROGRESS] =new QCheckListItem(m_columns, i18n("%"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_COUNT] =new QCheckListItem(m_columns, i18n("Count"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_RESUME] =new QCheckListItem(m_columns, i18n("Resume", "Res."), QCheckListItem::CheckBox); + m_items[ListProgress::TB_LOCAL_FILENAME] =new QCheckListItem(m_columns, i18n("Local Filename"), QCheckListItem::CheckBox); + m_items[ListProgress::TB_OPERATION] =new QCheckListItem(m_columns, i18n("Operation"), QCheckListItem::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, QListViewItem *after, QCString app_id, int job_id, + bool showDefault ) + : QListViewItem( 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 KIO::DefaultProgress( false ); + defaultProgress->setOnlyClean( true ); + connect ( defaultProgress, SIGNAL( stopped() ), this, SLOT( slotCanceled() ) ); + connect ( &m_showTimer, SIGNAL( timeout() ), this, 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( KIO::filesize_t size ) { + m_iTotalSize = size; + + // It's already in the % column... + //setText( listProgress->lv_total, KIO::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( KIO::filesize_t size ) { + m_iProcessedSize = size; + + setText( ListProgress::TB_TOTAL, KIO::convertSize( size ) ); + + defaultProgress->slotProcessedSize( 0, size ); +} + + +void ProgressItem::setProcessedFiles( unsigned long files ) { + m_iProcessedFiles = files; + + QString 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 QString tmps = KIO::DefaultProgress::makePercentString( percent, m_iTotalSize, m_iTotalFiles ); + setText( ListProgress::TB_PROGRESS, tmps ); + + defaultProgress->slotPercent( 0, percent ); +} + +void ProgressItem::setInfoMessage( const QString & msg ) { + QString plainTextMsg(msg); + plainTextMsg.replace( QRegExp( "</?b>" ), QString::null ); + plainTextMsg.replace( QRegExp( "<img.*>" ), QString::null ); + setText( ListProgress::TB_PROGRESS, plainTextMsg ); + + defaultProgress->slotInfoMessage( 0, msg ); +} + +void ProgressItem::setSpeed( unsigned long bytes_per_second ) { + m_iSpeed = bytes_per_second; + m_remainingSeconds = KIO::calculateRemainingSeconds( m_iTotalSize, m_iProcessedSize, m_iSpeed ); + + QString tmps, tmps2; + if ( m_iSpeed == 0 ) { + tmps = i18n( "Stalled"); + tmps2 = tmps; + } else { + tmps = i18n( "%1/s").arg( KIO::convertSize( m_iSpeed )); + tmps2 = KIO::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 QString& text) +{ + if (listProgress->m_lpcc[field].enabled) + { + QString 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(); + } + QListViewItem::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 QString& dev, const QString & 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 QString & point ) { + setText( ListProgress::TB_OPERATION, i18n("Unmounting") ); + setText( ListProgress::TB_ADDRESS, point ); // ? + setText( ListProgress::TB_LOCAL_FILENAME, "" ); // ? + + defaultProgress->slotUnmounting( 0, point ); +} + +void ProgressItem::setCanResume( KIO::filesize_t offset ) { + /* + QString 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 (QWidget *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(),SIGNAL(sizeChange(int,int,int)),this,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() { + KConfig config("uiserverrc"); + + // read listview geometry properties + config.setGroup( "ProgressList" ); + for ( int i = 0; i < TB_MAX; i++ ) { + QString tmps="Col"+QString::number(i); + m_lpcc[i].width=config.readNumEntry( tmps, 0); + if (m_lpcc[i].width==0) m_lpcc[i].width=defaultColumnWidth[i]; + + tmps="Enabled"+QString::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 (QListViewItem* lvi=firstChild(); lvi!=0; lvi=lvi->nextSibling()) + { + ProgressItem *pi=(ProgressItem*)lvi; + pi->setText(TB_ADDRESS,pi->fullLengthAddress()); + } + } + writeSettings(); +} + +void ListProgress::writeSettings() { + KConfig config("uiserverrc"); + + // write listview geometry properties + config.setGroup( "ProgressList" ); + for ( int i = 0; i < TB_MAX; i++ ) { + if (!m_lpcc[i].enabled) { + QString tmps= "Enabled" + QString::number(i); + config.writeEntry( tmps, false ); + continue; + } + m_lpcc[i].width=columnWidth(m_lpcc[i].index); + QString tmps="Col"+QString::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, + SIGNAL(clicked()), this, + SLOT(slotCancelCurrent()), FALSE, i18n("Cancel")); + toolBar()->insertButton("configure", TOOL_CONFIGURE, + SIGNAL(clicked()), this, + 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, SIGNAL( selectionChanged() ), + SLOT( slotSelection() ) ); + connect( listProgress, SIGNAL( executed( QListViewItem* ) ), + SLOT( slotToggleDefaultProgress( QListViewItem* ) ) ); + connect( listProgress, SIGNAL( contextMenu( KListView*, QListViewItem *, const QPoint &)), + SLOT(slotShowContextMenu(KListView*, QListViewItem *, const QPoint&))); + + + // setup animation timer + updateTimer = new QTimer( this ); + connect( updateTimer, SIGNAL( timeout() ), + 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*, QListViewItem* item, const QPoint& pos) +{ + if (m_contextMenu==0) + { + m_contextMenu=new QPopupMenu(this); + m_idCancelItem = m_contextMenu->insertItem(i18n("Cancel Job"), this, SLOT(slotCancelCurrent())); +// m_contextMenu->insertItem(i18n("Toggle Progress"), this, SLOT(slotToggleDefaultProgress())); + m_contextMenu->insertSeparator(); + m_contextMenu->insertItem(i18n("Settings..."), this, SLOT(slotConfigure())); + } + if ( item ) + item->setSelected( true ); + bool enabled = false; + QListViewItemIterator 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,SIGNAL(cancelClicked()), this, SLOT(slotCancelConfig())); + connect(m_configDialog,SIGNAL(okClicked()), this, SLOT(slotApplyConfig())); + connect(m_configDialog,SIGNAL(applyClicked()), this, 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( QCString observerAppId, bool showProgress ) +{ + kdDebug(7024) << "UIServer::newJob observerAppId=" << observerAppId << ". " + << "Giving id=" << s_jobId+1 << endl; + + QListViewItemIterator 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, SIGNAL( jobCanceled( ProgressItem* ) ), + SLOT( slotJobCanceled( ProgressItem* ) ) ); + + if ( m_bShowList && !updateTimer->isActive() ) + updateTimer->start( 1000 ); + + m_bUpdateNewJob=true; + + return s_jobId; +} + + +ProgressItem* UIServer::findItem( int id ) +{ + QListViewItemIterator 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, KIO::filesize_t size ) +{ +// kdDebug(7024) << "UIServer::totalSize " << id << " " << KIO::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, KIO::filesize_t size ) +{ + //kdDebug(7024) << "UIServer::processedSize " << id << " " << KIO::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 QString & 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, KIO::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, QString dev, QString point ) +{ + kdDebug(7024) << "UIServer::mounting " << id << " " << dev << " " << point << endl; + + ProgressItem *item = findItem( id ); + if ( item ) { + item->setMounting( dev, point ); + } +} + +void UIServer::unmounting( int id, QString point ) +{ + kdDebug(7024) << "UIServer::unmounting " << id << " " << point << endl; + + ProgressItem *item = findItem( id ); + if ( item ) { + item->setUnmounting( point ); + } +} + +void UIServer::killJob( QCString observerAppId, int progressId ) +{ + // Contact the object "KIO::Observer" in the application <appId> + Observer_stub observer( observerAppId, "KIO::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() ); + + // KIO::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 + QListViewItemIterator 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; + KIO::filesize_t iTotalSize = 0; + int iTotalSpeed = 0; + unsigned int totalRemTime = 0; // in seconds + + ProgressItem *item; + + // count totals for statusbar + QListViewItemIterator 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( KIO::convertSize( iTotalSize ) ), + ID_TOTAL_SIZE); + statusBar()->changeItem( i18n( "Remaining Time", " Rem. Time: %1 ").arg( KIO::convertSeconds( totalRemTime ) ), + ID_TOTAL_TIME); + statusBar()->changeItem( i18n( " %1/s ").arg( KIO::convertSize( iTotalSpeed ) ), + ID_TOTAL_SPEED); + +} + +void UIServer::setListMode( bool list ) +{ + m_bShowList = list; + QListViewItemIterator 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( QListViewItem *item ) { + ((ProgressItem*) item )->slotToggleDefaultProgress(); +} + + +void UIServer::slotSelection() { + QListViewItemIterator 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 kio_uiserver). +QByteArray UIServer::openPassDlg( const KIO::AuthInfo &info ) +{ + kdDebug(7024) << "UIServer::openPassDlg: User= " << info.username + << ", Msg= " << info.prompt << endl; + KIO::AuthInfo inf(info); + int result = KIO::PasswordDialog::getNameAndPassword( inf.username, inf.password, + &inf.keepPassword, inf.prompt, + inf.readOnly, inf.caption, + inf.comment, inf.commentLabel ); + QByteArray data; + QDataStream stream( data, IO_WriteOnly ); + if ( result == QDialog::Accepted ) + inf.setModified( true ); + else + inf.setModified( false ); + stream << inf; + return data; +} + +int UIServer::messageBox( int progressId, int type, const QString &text, const QString &caption, const QString &buttonYes, const QString &buttonNo ) +{ + return Observer::messageBox( progressId, type, text, caption, buttonYes, buttonNo ); +} + +void UIServer::showSSLInfoDialog(const QString &url, const KIO::MetaData &meta) +{ + return showSSLInfoDialog(url,meta,0); +} + +void UIServer::showSSLInfoDialog(const QString &url, const KIO::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 + QStringList cl = + QStringList::split(QString("\n"), meta["ssl_peer_chain"]); + QPtrList<KSSLCertificate> ncl; + + ncl.setAutoDelete(true); + for (QStringList::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"]); + QString 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 QString& host, const QStringList& certList) +{ + return showSSLCertDialog( host, certList, 0 ); +} + +KSSLCertDlgRet UIServer::showSSLCertDialog(const QString& host, const QStringList& 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; +} + + +QByteArray UIServer::open_RenameDlg( int id, + const QString & caption, + const QString& src, const QString & 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); } + + +QByteArray UIServer::open_RenameDlg64( int id, + const QString & caption, + const QString& src, const QString & dest, + int mode, + KIO::filesize_t sizeSrc, + KIO::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 ); + QString newDest; + kdDebug(7024) << "Calling KIO::open_RenameDlg" << endl; + KIO::RenameDlg_Result result = KIO::open_RenameDlg( caption, src, dest, + (KIO::RenameDlg_Mode) mode, newDest, + sizeSrc, sizeDest, + (time_t)ctimeSrc, (time_t)ctimeDest, + (time_t)mtimeSrc, (time_t)mtimeDest ); + kdDebug(7024) << "KIO::open_RenameDlg done" << endl; + QByteArray data; + QDataStream stream( data, IO_WriteOnly ); + stream << Q_UINT8(result) << newDest; + if ( item && result != KIO::R_CANCEL ) + setItemVisible( item, true ); + return data; +} + +int UIServer::open_SkipDlg( int id, + int /*bool*/ multi, + const QString & error_text ) +{ + // Hide existing dialog box if any + ProgressItem *item = findItem( id ); + if ( item ) + setItemVisible( item, false ); + kdDebug(7024) << "Calling KIO::open_SkipDlg" << endl; + KIO::SkipDlg_Result result = KIO::open_SkipDlg( (bool)multi, error_text ); + if ( item && result != KIO::S_CANCEL ) + setItemVisible( item, true ); + return (KIO::SkipDlg_Result) result; +} + + +void UIServer::readSettings() { + KConfig 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() { + KConfig 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() { + QListViewItemIterator 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(QResizeEvent* 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("kdelibs"); + // GS 5/2001 - I changed the name to "KDE" to make it look better + // in the titles of dialogs which are displayed. + KAboutData aboutdata("kio_uiserver", I18N_NOOP("KDE"), + "0.8", I18N_NOOP("KDE Progress Information UI Server"), + KAboutData::License_GPL, "(C) 2000, David Faure & Matt Koss"); + // Who's the maintainer ? :) + aboutdata.addAuthor("David Faure",I18N_NOOP("Developer"),"[email protected]"); + aboutdata.addAuthor("Matej Koss",I18N_NOOP("Developer"),"[email protected]"); + + KCmdLineArgs::init( argc, argv, &aboutdata ); + // KCmdLineArgs::addCmdLineOptions( options ); + KUniqueApplication::addCmdLineOptions(); + + if (!KUniqueApplication::start()) + { + kdDebug(7024) << "kio_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/kio/misc/uiserver.h b/kio/misc/uiserver.h new file mode 100644 index 000000000..e676bb7a0 --- /dev/null +++ b/kio/misc/uiserver.h @@ -0,0 +1,430 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Matej Koss <[email protected]> + David Faure <[email protected]> + + 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_uiserver_h__ +#define __kio_uiserver_h__ + +#include <qintdict.h> +#include <qdatetime.h> +#include <qtimer.h> + +#include <dcopobject.h> +#include <kio/global.h> +#include <kio/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 KIO { + class Job; + class DefaultProgress; +} + + +struct ListProgressColumnConfig +{ + QString title; + int index; + int width; + bool enabled; +}; + +/** +* List view in the UIServer. +* @internal +*/ +class KIO_EXPORT ListProgress : public KListView { + + Q_OBJECT + +public: + + ListProgress (QWidget *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 KIO_EXPORT ProgressItem : public QObject, public QListViewItem { + + Q_OBJECT + +public: + ProgressItem( ListProgress* view, QListViewItem *after, QCString app_id, int job_id, + bool showDefault = true ); + ~ProgressItem(); + + QCString 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( KIO::filesize_t bytes ); + void setTotalFiles( unsigned long files ); + void setTotalDirs( unsigned long dirs ); + + void setProcessedSize( KIO::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 QString & 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 QString & dev, const QString & point ); + void setUnmounting( const QString & point ); + + void setCanResume( KIO::filesize_t offset ); + + KIO::filesize_t totalSize() { return m_iTotalSize; } + unsigned long totalFiles() { return m_iTotalFiles; } + KIO::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 QString& fullLengthAddress() const {return m_fullLengthAddress;} + void setText(ListProgress::ListProgressFields field, const QString& 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 + QCString 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 + KIO::DefaultProgress *defaultProgress; + + // we store these values for calculation of totals ( for statusbar ) + KIO::filesize_t m_iTotalSize; + unsigned long m_iTotalFiles; + KIO::filesize_t m_iProcessedSize; + unsigned long m_iProcessedFiles; + unsigned long m_iSpeed; + int m_remainingSeconds; + QTimer m_showTimer; + QString m_fullLengthAddress; +}; + +class QResizeEvent; +class QHideEvent; +class QShowEvent; +class ProgressConfigDialog; +class QPopupMenu; +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 <[email protected]> + * @author Matej Koss <[email protected]> + * + * @internal + */ +class KIO_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 KIO::Observer::newJob + * @param showProgress whether to popup the progress for the job. + * Usually true, but may be false when we use kio_uiserver for + * other things, like SSL dialogs. + * @return the job id + */ + int newJob( QCString appId, bool showProgress ); + + ASYNC jobFinished( int id ); + + ASYNC totalSize( int id, unsigned long size ); + ASYNC totalSize64( int id, KIO::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, KIO::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 QString & 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, QString dev, QString point ); + ASYNC unmounting( int id, QString point ); + + ASYNC canResume( int id, unsigned long offset ); + ASYNC canResume64( int id, KIO::filesize_t offset ); + + /** + * @deprecated (it blocks other apps). + * Use KIO::PasswordDialog::getNameAndPassword instead. + * To be removed in KDE 4.0. + */ + QByteArray openPassDlg( const KIO::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 QString &text, const QString &caption, + const QString &buttonYes, const QString &buttonNo ); + + /** + * @deprecated (it blocks other apps). + * Use KIO::open_RenameDlg instead. + * To be removed in KDE 4.0. + */ + QByteArray open_RenameDlg64( int id, + const QString & caption, + const QString& src, const QString & dest, + int /* KIO::RenameDlg_Mode */ mode, + KIO::filesize_t sizeSrc, + KIO::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 KIO::open_RenameDlg instead. + * To be removed in KDE 4.0. + */ + QByteArray open_RenameDlg( int id, + const QString & caption, + const QString& src, const QString & dest, + int /* KIO::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 KIO::open_SkipDlg instead. + * To be removed in KDE 4.0. + */ + int open_SkipDlg( int id, + int /*bool*/ multi, + const QString & 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 QString &url, const KIO::MetaData &data, int mainwindow); + + /** + * @deprecated + */ + void showSSLInfoDialog(const QString &url, const KIO::MetaData &data); + + /* + * Show an SSL Certificate Selection Dialog + */ + KSSLCertDlgRet showSSLCertDialog(const QString& host, const QStringList& certList, int mainwindow); + + /* + * @deprecated + */ + KSSLCertDlgRet showSSLCertDialog(const QString& host, const QStringList& certList); + +public slots: + void slotConfigure(); + void slotRemoveSystemTrayIcon(); +protected slots: + + void slotUpdate(); + void slotQuit(); + + void slotCancelCurrent(); + + void slotToggleDefaultProgress( QListViewItem * ); + void slotSelection(); + + void slotJobCanceled( ProgressItem * ); + void slotApplyConfig(); + void slotShowContextMenu(KListView*, QListViewItem *item, const QPoint& pos); + +protected: + + ProgressItem* findItem( int id ); + + virtual void resizeEvent(QResizeEvent* e); + virtual bool queryClose(); + + void setItemVisible( ProgressItem * item, bool visible ); + + QTimer* updateTimer; + ListProgress* listProgress; + + KToolBar::BarPosition toolbarPos; + QString properties; + + void applySettings(); + void readSettings(); + void writeSettings(); +private: + + void killJob( QCString 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; + QPopupMenu* m_contextMenu; + UIServerSystemTray *m_systemTray; + + static int s_jobId; + friend class no_bogus_warning_from_gcc; +}; + +// -*- mode: c++; c-basic-offset: 2 -*- +#endif |