Added iconv support and doc cleanups.

This commit is contained in:
Werner Koch 2006-09-22 18:15:18 +00:00
parent c9f8a69f0f
commit 2db8df0ba3
12 changed files with 487 additions and 480 deletions

5
NEWS
View File

@ -1,6 +1,9 @@
Noteworthy changes in version 1.9.24
Noteworthy changes in version 1.9.90
-------------------------------------------------
* Made readline work for gpg.
* Cleanups und minor bug fixes.
Noteworthy changes in version 1.9.23 (2006-09-18)

16
TODO
View File

@ -77,10 +77,6 @@ might want to have an agent context for each service request
** Add a test to check the extkeyusage.
* doc/
** Explain how to setup a root CA key as trusted
** Explain how trustlist.txt might be managed.
* Windows port
** gpgsm's LISTKEYS does not yet work
Fix is to change everything to libestream
@ -90,12 +86,10 @@ might want to have an agent context for each service request
* sm/
** check that we issue NO_SECKEY xxx if a -u key was not found
We don't. The messages retruned are also wrong (recipient vs. signer).
We don't. The messages returned are also wrong (recipient vs. signer).
* jnlib/
** provide jnlib_malloc and try to remove all jnlib_xmalloc.
** Extend utf8conv.c to make use of iconv.
Need to merge with the code in 1.4/util/strgutil.c.
* g10/
** issue a NO_SECKEY xxxx if a -u key was not found.
@ -109,13 +103,5 @@ might want to have an agent context for each service request
As soon as we switch to libgcrypt 1.3 we should remove the hard
coded constant in random_is_faked.
* common/
** ttyio
Add completion support.
** yesno
Update to gpg 1.4.3 version
* Extend selinux support to other modules

View File

@ -895,9 +895,6 @@ fi
AC_HEADER_STDC
AC_CHECK_HEADERS([string.h unistd.h langinfo.h termio.h locale.h getopt.h])
AC_CHECK_HEADERS([pwd.h inttypes.h])
# Note that we do not check for iconv here because this is done anyway
# by the gettext checks and thus it allows us to disable the use of
# iconv by using --disable-nls.
#

View File

@ -1,5 +1,9 @@
2006-09-22 Werner Koch <wk@g10code.com>
* instguide.texi (Installation): New.
* assuan.texi (Assuan): Removed. Use the libassuan manual instead.
* gnupg.texi: Reflect these changes.
* gpg.texi: Make some parts depend on the "gpgone" set
command. This allows us to use the same source for gpg1 and gpg2.

View File

@ -40,7 +40,7 @@ info_TEXINFOS = gnupg.texi
dist_pkgdata_DATA = qualified.txt FAQ faq.html com-certs.pem
gnupg_TEXINFOS = \
gpg.texi gpgsm.texi gpg-agent.texi scdaemon.texi assuan.texi \
gpg.texi gpgsm.texi gpg-agent.texi scdaemon.texi instguide.texi \
tools.texi debugging.texi glossary.texi contrib.texi gpl.texi \
sysnotes.texi gnupg-card-architecture.fig

View File

@ -1,193 +0,0 @@
@c Copyright (C) 2002 Free Software Foundation, Inc.
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@node Assuan
@appendix Description of the Assuan protocol.
@cindex Assuan, IPC
The architecture of the modular GnuPG system is based on a couple of
highly specialized modules which make up a network of client server
communication. A common framework for intermodule communication is
therefore needed and should be implemented in a library.
@appendixsubsec Goals
@itemize @bullet
@item Common framework for module communication
@item Easy debugging
@item Easy module testing
@item Extendible
@item Optional authentication and encryption facility
@item Usable to access external hardware
@end itemize
@appendixsubsec Design criteria
@itemize @bullet
@item Client Server with back channel
@item Use a mainly text based protocol
@item Escape certain control characters
@item Allow indefinite data length
@item Request confidentiality for parts of the communication
@item Dummy module should allow direct linking of client and server.
@item Inline data or descriptor passing for bulk data
@item No protection against DoS needed
@item Subliminal channels are not an issue
@end itemize
@appendixsubsec Implementation
@noindent
The implementation is line based with a maximum line size of 1000
octects. The default IPC mechanism are Unix Domain Sockets.
On a connect request the server responds either with an okay or an error
status. For authentication check the server may send an Inquiry
Response prior to the first Okay, it may also issue Status messages.
The server must check that the client is allowed to connect, this is
done by requesting the credentials for the peer and comparing them to
those of the server. This avoids attacks based on wrong socket
permissions.
It may choose to delay the first response in case of an error. The
server never closes the connection - however the lower protocol may do
so after some time of inactivity or when the connection is in an error
state.
All textual messages are assumed to be in UTF-8 unless otherwise noted.
@appendixsubsec Server responses
@table @code
@item OK [<arbitary debugging information>]
Request was successful.
@item ERR @var{errorcode} [<human readable error description>]
Request could not be fulfilled. The error codes are mostly application
specific except for a few common ones.
@item S @var{keyword} <status information depending on keyword>
Informational output by the server, still processing the request.
@item # <string>
Comment line issued only for debugging purposes. Totally ignored.
@item D <raw data>
Raw data returned to client. There must be exactly one space after the
'D'. The values for '%', CR and LF must be percent escaped; this is
encoded as %25, %0D and %0A. Only uppercase letters should be used in
the hexadecimal representation. Other characters may be percent escaped
for easier debugging. All these Data lines are considered one data
stream up to the OK or ERR response. Status and Inquiry Responses
may be mixed with the Data lines.
@item INQUIRE @var{keyword}> <parameters>
Server needs further information from the client. The client should
answer with a command which is allowed after an inquiry. Note that the
server does not confirm that client command but either continues
processing or ends processing with an error status. Not all commands
are allowed.
@end table
A client should only check the first letter of each line and then skip
over to the next token (except for data lines where the raw data starts
exactly after 2 bytes). Lines larger than 1000 bytes should be
treated as a communication error. (The rationale for having a line
length limit is to allow for easier multiplexing of multiple channels).
@appendixsubsec Client requests
The server waits for client requests after he sent an Okay or Error.
The client should not issue a request in other cases with the
exception of the CANCEL command.
@example
@var{command} <parameters>
@end example
@var{command} is a one word string without preceding white space.
Parameters are command specific, CR, LF and the percent signs should be
percent escaped as described above. To send a backslash as the last
character it should also be percent escaped. Percent escaping is
allowed anywhere in the parameters but not in the command. The line
ends with a CR, LF or just a LF.
Not yet implemented feature: If there is a need for a parameter list
longer than the line length limit (1000 characters including command and
CR, LF), the last character of the line (right before the CR/LF or LF)
must be a non-escape encoded backslash. The following line is then
expected to be a continuation of the line with the backslash replaced by
a blank and the line ending removed.
@example
D <raw data>
@end example
Raw data to the server. There must be exactly one space after the 'D'.
The values for '%', CR and LF must be percent escaped; this is encoded
as %25, %0D and %0A. Only uppercase letters should be used in the
hexadecimal representation. Other characters may be percent escaped for
easier debugging. All these Data lines are considered one data stream
up to the OKAY or ERROR response. Status and Inquiry Responses may be
mixed with the Data lines.
@example
END
@end example
Lines beginning with a @code{#} or empty lines are ignored. This is
useful to comment test scripts.
Although the commands are application specific, some of them are used by
all protocols and partly directly supported by the Assuan library:
@table @code
@item CANCEL
his is the one special command which aborts the current request. it can
be sent at any time and the server will stop its operation right before
it would send the next response line (of any type).
@item BYE
Close the connect, the server will reply with an @code{OK}.
@item AUTH
Not yet specified as we don't implement it in the first phase. See my
mail to gpa-dev on 2001-10-25 about the rationale for measurements
against local attacks.
@item RESET
Reset the connection but not any existing authentication. The server
should release all resources associated with the connection.
@item END
Used by a client to mark the end of raw data. The server may send END
to indicate a partial end of data.
@end table
@appendixsubsec Error Codes
Here we keep a list of error codes used in any Assuan based
protocol. The format is the string @code{ERR}, white space, the error
number, white space, a textual description of the error.
@table @code
@item 100 Unknown Command
@item 101 Not Implemented
@item 301 certificate has been revoked [DirMngr]
@item 302 no CRL known for this certificate [DirMngr]
@item 303 CRL is too old and a new one could not be retrieved [DirMngr]
@end table

View File

@ -13,7 +13,7 @@
certificates.
@item CRL
The @emph{Certificate Revocation List} is a list containing
The @emph{Certificate Revocation List} is a list containing
certificates revoked by the issuer.
@item Keygrip

View File

@ -114,6 +114,8 @@ the administration and the architecture.
@end ifnottex
@menu
* Installation:: A short installation guide.
* Invoking GPG:: Using the OpenPGP protocol.
* Invoking GPGSM:: Using the S/MIME protocol.
* Invoking GPG-AGENT:: How to launch the secret key daemon.
@ -124,7 +126,7 @@ the administration and the architecture.
* System Notes:: Notes pertaining to certain OSes.
* Debugging:: How to solve problems
* Assuan:: Description of the Assuan protocol.
* Copying:: GNU General Public License says
how you can copy and share GnuPG
* Contributors:: People who have contributed to GnuPG.
@ -148,6 +150,8 @@ the administration and the architecture.
@end ifhtml
@include instguide.texi
@include gpg.texi
@include gpgsm.texi
@include gpg-agent.texi
@ -165,7 +169,6 @@ the administration and the architecture.
@include debugging.texi
@include assuan.texi
@include gpl.texi
@include contrib.texi

19
doc/instguide.texi Normal file
View File

@ -0,0 +1,19 @@
@c instguide.texi - Installation guide for GnuPG
@c Copyright (C) 2006 Free Software Foundation, Inc.
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@node Installation
@chapter A short installation guide.
[to be written]
Tell how to setup the system, install certificates, how dirmngr relates
to GnuPG etc.
** Explain how to setup a root CA key as trusted
** Explain how trustlist.txt might be managed.

View File

@ -1,3 +1,9 @@
2006-09-22 Werner Koch <wk@g10code.com>
* utf8conv.c: Reworked to match the gnupg 1.4.5 code. This now
requires iconv support but this is reasonable for all modern
systems.
2006-08-29 Werner Koch <wk@g10code.com>
* logging.c (do_logv): Emit a missing LF for fatal errors.

View File

@ -28,101 +28,225 @@
#ifdef HAVE_LANGINFO_CODESET
#include <langinfo.h>
#endif
#include <errno.h>
#include <iconv.h>
#include "libjnlib-config.h"
#include "stringhelp.h"
#include "utf8conv.h"
static ushort koi8_unicode[128] = {
0x2500, 0x2502, 0x250c, 0x2510, 0x2514, 0x2518, 0x251c, 0x2524,
0x252c, 0x2534, 0x253c, 0x2580, 0x2584, 0x2588, 0x258c, 0x2590,
0x2591, 0x2592, 0x2593, 0x2320, 0x25a0, 0x2219, 0x221a, 0x2248,
0x2264, 0x2265, 0x00a0, 0x2321, 0x00b0, 0x00b2, 0x00b7, 0x00f7,
0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556,
0x2557, 0x2558, 0x2559, 0x255a, 0x255b, 0x255c, 0x255d, 0x255e,
0x255f, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565,
0x2566, 0x2567, 0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x00a9,
0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a
};
static ushort latin2_unicode[128] = {
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
};
#ifndef MB_LEN_MAX
#define MB_LEN_MAX 16
#endif
static const char *active_charset_name = "iso-8859-1";
static ushort *active_charset = NULL;
static int no_translation = 0;
static unsigned short *active_charset;
static int no_translation; /* Set to true if we let simply pass through. */
static int use_iconv; /* iconv comversion fucntions required. */
/* Error handler for iconv failures. This is needed to not clutter the
output with repeated diagnostics about a missing conversion. */
static void
handle_iconv_error (const char *to, const char *from, int use_fallback)
{
if (errno == EINVAL)
{
static int shown1, shown2;
int x;
if (to && !strcmp (to, "utf-8"))
{
x = shown1;
shown1 = 1;
}
else
{
x = shown2;
shown2 = 1;
}
if (!x)
log_info (_("conversion from `%s' to `%s' not available\n"),
from, to);
}
else
{
static int shown;
if (!shown)
log_info (_("iconv_open failed: %s\n"), strerror (errno));
shown = 1;
}
if (use_fallback)
{
/* To avoid further error messages we fallback to Latin-1 for the
native encoding. This is justified as one can expect that on a
utf-8 enabled system nl_langinfo() will work and thus we won't
never get to here. Thus Latin-1 seems to be a reasonable
default. */
active_charset_name = "iso-8859-1";
no_translation = 0;
active_charset = NULL;
use_iconv = 0;
}
}
int
set_native_charset (const char *newset)
{
if (!newset)
#ifdef HAVE_LANGINFO_CODESET
newset = nl_langinfo (CODESET);
#else
newset = "8859-1";
#endif
const char *full_newset;
if (!newset)
{
#ifdef HABE_W32_SYSTEM
static char codepage[30];
unsigned int cpno;
const char *aliases;
/* We are a console program thus we need to use the
GetConsoleOutputCP function and not the the GetACP which
would give the codepage for a GUI program. Note this is not
a bulletproof detection because GetConsoleCP might return a
different one for console input. Not sure how to cope with
that. If the console Code page is not known we fall back to
the system code page. */
cpno = GetConsoleOutputCP ();
if (!cpno)
cpno = GetACP ();
sprintf (codepage, "CP%u", cpno );
/* Resolve alias. We use a long string string and not the usual
array to optimize if the code is taken to a DSO. Taken from
libiconv 1.9.2. */
newset = codepage;
for (aliases = ("CP936" "\0" "GBK" "\0"
"CP1361" "\0" "JOHAB" "\0"
"CP20127" "\0" "ASCII" "\0"
"CP20866" "\0" "KOI8-R" "\0"
"CP21866" "\0" "KOI8-RU" "\0"
"CP28591" "\0" "ISO-8859-1" "\0"
"CP28592" "\0" "ISO-8859-2" "\0"
"CP28593" "\0" "ISO-8859-3" "\0"
"CP28594" "\0" "ISO-8859-4" "\0"
"CP28595" "\0" "ISO-8859-5" "\0"
"CP28596" "\0" "ISO-8859-6" "\0"
"CP28597" "\0" "ISO-8859-7" "\0"
"CP28598" "\0" "ISO-8859-8" "\0"
"CP28599" "\0" "ISO-8859-9" "\0"
"CP28605" "\0" "ISO-8859-15" "\0"
"CP65001" "\0" "UTF-8" "\0");
*aliases;
aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
{
if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1]))
{
newset = aliases + strlen (aliases) + 1;
break;
}
}
#else /*!HAVE_W32_SYSTEM*/
#ifdef HAVE_LANGINFO_CODESET
newset = nl_langinfo (CODESET);
#else /*!HAVE_LANGINFO_CODESET*/
/* Try to get the used charset from environment variables. */
static char codepage[30];
const char *lc, *dot, *mod;
strcpy (codepage, "iso-8859-1");
lc = getenv ("LC_ALL");
if (!lc || !*lc)
{
lc = getenv ("LC_CTYPE");
if (!lc || !*lc)
lc = getenv ("LANG");
}
if (lc && *lc)
{
dot = strchr (lc, '.');
if (dot)
{
mod = strchr (++dot, '@');
if (!mod)
mod = dot + strlen (dot);
if (mod - dot < sizeof codepage && dot != mod)
{
memcpy (codepage, dot, mod - dot);
codepage [mod - dot] = 0;
}
}
}
newset = codepage;
#endif /*!HAVE_LANGINFO_CODESET*/
#endif /*!HAVE_W32_SYSTEM*/
}
full_newset = newset;
if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
{
newset += 3;
if (*newset == '-' || *newset == '_')
newset++;
newset++;
}
if (!*newset
|| !ascii_strcasecmp (newset, "8859-1")
|| !ascii_strcasecmp (newset, "8859-15"))
/* Note that we silently assume that plain ASCII is actually meant
as Latin-1. This makes sense because many Unix system don't have
their locale set up properly and thus would get annoying error
messages and we have to handle all the "bug" reports. Latin-1 has
always been the character set used for 8 bit characters on Unix
systems. */
if ( !*newset
|| !ascii_strcasecmp (newset, "8859-1" )
|| !ascii_strcasecmp (newset, "646" )
|| !ascii_strcasecmp (newset, "ASCII" )
|| !ascii_strcasecmp (newset, "ANSI_X3.4-1968" )
)
{
active_charset_name = "iso-8859-1";
no_translation = 0;
active_charset = NULL;
use_iconv = 0;
}
else if (!ascii_strcasecmp (newset, "8859-2"))
{
active_charset_name = "iso-8859-2";
no_translation = 0;
active_charset = latin2_unicode;
}
else if (!ascii_strcasecmp (newset, "koi8-r"))
{
active_charset_name = "koi8-r";
no_translation = 0;
active_charset = koi8_unicode;
}
else if (!ascii_strcasecmp (newset, "utf8")
|| !ascii_strcasecmp (newset, "utf-8"))
else if ( !ascii_strcasecmp (newset, "utf8" )
|| !ascii_strcasecmp(newset, "utf-8") )
{
active_charset_name = "utf-8";
no_translation = 1;
active_charset = NULL;
use_iconv = 0;
}
else
return -1;
{
iconv_t cd;
#ifdef HAVE_W32_SYSTEM
if (load_libiconv ())
return -1;
#endif /*HAVE_W32_SYSTEM*/
cd = iconv_open (full_newset, "utf-8");
if (cd == (iconv_t)-1)
{
handle_iconv_error (full_newset, "utf-8", 0);
return -1;
}
iconv_close (cd);
cd = iconv_open ("utf-8", full_newset);
if (cd == (iconv_t)-1)
{
handle_iconv_error ("utf-8", full_newset, 0);
return -1;
}
iconv_close (cd);
active_charset_name = full_newset;
no_translation = 0;
active_charset = NULL;
use_iconv = 1;
}
return 0;
}
@ -132,10 +256,9 @@ get_native_charset ()
return active_charset_name;
}
/****************
* Convert string, which is in native encoding to UTF8 and return the
* new allocated UTF8 string.
*/
/* Convert string, which is in native encoding to UTF8 and return a
new allocated UTF-8 string. */
char *
native_to_utf8 (const char *orig_string)
{
@ -147,41 +270,12 @@ native_to_utf8 (const char *orig_string)
if (no_translation)
{
/* Already utf-8 encoded. */
buffer = jnlib_xstrdup (orig_string);
}
else if (active_charset)
{
for (s = string; *s; s++)
{
length++;
if (*s & 0x80)
length += 2; /* we may need 3 bytes */
}
buffer = jnlib_xmalloc (length + 1);
for (p = (unsigned char *)buffer, s = string; *s; s++)
{
if ((*s & 0x80))
{
ushort val = active_charset[*s & 0x7f];
if (val < 0x0800)
{
*p++ = 0xc0 | ((val >> 6) & 0x1f);
*p++ = 0x80 | (val & 0x3f);
}
else
{
*p++ = 0xe0 | ((val >> 12) & 0x0f);
*p++ = 0x80 | ((val >> 6) & 0x3f);
*p++ = 0x80 | (val & 0x3f);
}
}
else
*p++ = *s;
}
*p = 0;
}
else
else if (!active_charset && !use_iconv)
{
/* For Latin-1 we can avoid the iconv overhead. */
for (s = string; *s; s++)
{
length++;
@ -191,7 +285,7 @@ native_to_utf8 (const char *orig_string)
buffer = jnlib_xmalloc (length + 1);
for (p = (unsigned char *)buffer, s = string; *s; s++)
{
if (*s & 0x80)
if ( (*s & 0x80 ))
{
*p++ = 0xc0 | ((*s >> 6) & 3);
*p++ = 0x80 | (*s & 0x3f);
@ -201,22 +295,68 @@ native_to_utf8 (const char *orig_string)
}
*p = 0;
}
else
{
/* Need to use iconv. */
iconv_t cd;
const char *inptr;
char *outptr;
size_t inbytes, outbytes;
cd = iconv_open ("utf-8", active_charset_name);
if (cd == (iconv_t)-1)
{
handle_iconv_error ("utf-8", active_charset_name, 1);
return native_to_utf8 (string);
}
for (s=string; *s; s++ )
{
length++;
if ((*s & 0x80))
length += 5; /* We may need up to 6 bytes for the utf8 output. */
}
buffer = jnlib_xmalloc (length + 1);
inptr = string;
inbytes = strlen (string);
outptr = buffer;
outbytes = length;
if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
&outptr, &outbytes) == (size_t)-1)
{
static int shown;
if (!shown)
log_info (_("conversion from `%s' to `%s' failed: %s\n"),
active_charset_name, "utf-8", strerror (errno));
shown = 1;
/* We don't do any conversion at all but use the strings as is. */
strcpy (buffer, string);
}
else /* Success. */
{
*outptr = 0;
/* We could realloc the buffer now but I doubt that it makes
much sense given that it will get freed anyway soon
after. */
}
iconv_close (cd);
}
return buffer;
}
/* Convert string, which is in UTF8 to native encoding. Replace
* illegal encodings by some "\xnn" and quote all control
* characters. A character with value DELIM will always be quoted, it
* must be a vanilla ASCII character. */
char *
utf8_to_native (const char *string, size_t length, int delim)
static char *
do_utf8_to_native (const char *string, size_t length, int delim,
int with_iconv)
{
int nleft;
int i;
unsigned char encbuf[8];
int encidx;
const byte *s;
const unsigned char *s;
size_t n;
char *buffer = NULL;
char *p = NULL;
@ -224,19 +364,20 @@ utf8_to_native (const char *string, size_t length, int delim)
size_t slen;
int resync = 0;
/* 1. pass (p==NULL): count the extended utf-8 characters */
/* 2. pass (p!=NULL): create string */
/* First pass (p==NULL): count the extended utf-8 characters. */
/* Second pass (p!=NULL): create string. */
for (;;)
{
for (slen = length, nleft = encidx = 0, n = 0,
s = (const unsigned char *)string; slen;
s = (const unsigned char *)string;
slen;
s++, slen--)
{
if (resync)
{
if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
{
/* still invalid */
/* Still invalid. */
if (p)
{
sprintf (p, "\\x%02x", *s);
@ -250,45 +391,23 @@ utf8_to_native (const char *string, size_t length, int delim)
if (!nleft)
{
if (!(*s & 0x80))
{ /* plain ascii */
if (*s < 0x20 || *s == 0x7f || *s == delim ||
(delim && *s == '\\'))
{
/* Plain ascii. */
if ( delim != -1
&& (*s < 0x20 || *s == 0x7f || *s == delim
|| (delim && *s == '\\')))
{
n++;
if (p)
*p++ = '\\';
switch (*s)
{
case '\n':
n++;
if (p)
*p++ = 'n';
break;
case '\r':
n++;
if (p)
*p++ = 'r';
break;
case '\f':
n++;
if (p)
*p++ = 'f';
break;
case '\v':
n++;
if (p)
*p++ = 'v';
break;
case '\b':
n++;
if (p)
*p++ = 'b';
break;
case 0:
n++;
if (p)
*p++ = '0';
break;
case '\n': n++; if ( p ) *p++ = 'n'; break;
case '\r': n++; if ( p ) *p++ = 'r'; break;
case '\f': n++; if ( p ) *p++ = 'f'; break;
case '\v': n++; if ( p ) *p++ = 'v'; break;
case '\b': n++; if ( p ) *p++ = 'b'; break;
case 0: n++; if ( p ) *p++ = '0'; break;
default:
n += 3;
if (p)
@ -306,43 +425,43 @@ utf8_to_native (const char *string, size_t length, int delim)
n++;
}
}
else if ((*s & 0xe0) == 0xc0)
{ /* 110x xxxx */
else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
{
val = *s & 0x1f;
nleft = 1;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xf0) == 0xe0)
{ /* 1110 xxxx */
else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
{
val = *s & 0x0f;
nleft = 2;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xf8) == 0xf0)
{ /* 1111 0xxx */
else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
{
val = *s & 0x07;
nleft = 3;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xfc) == 0xf8)
{ /* 1111 10xx */
else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
{
val = *s & 0x03;
nleft = 4;
encidx = 0;
encbuf[encidx++] = *s;
}
else if ((*s & 0xfe) == 0xfc)
{ /* 1111 110x */
else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
{
val = *s & 0x01;
nleft = 5;
encidx = 0;
encbuf[encidx++] = *s;
}
else
{ /* invalid encoding: print as \xnn */
else /* Invalid encoding: print as \xNN. */
{
if (p)
{
sprintf (p, "\\x%02x", *s);
@ -352,8 +471,8 @@ utf8_to_native (const char *string, size_t length, int delim)
resync = 1;
}
}
else if (*s < 0x80 || *s >= 0xc0)
{ /* invalid */
else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
{
if (p)
{
for (i = 0; i < encidx; i++)
@ -374,8 +493,8 @@ utf8_to_native (const char *string, size_t length, int delim)
encbuf[encidx++] = *s;
val <<= 6;
val |= *s & 0x3f;
if (!--nleft)
{ /* ready */
if (!--nleft) /* Ready. */
{
if (no_translation)
{
if (p)
@ -386,43 +505,41 @@ utf8_to_native (const char *string, size_t length, int delim)
n += encidx;
encidx = 0;
}
else if (active_charset)
{ /* table lookup */
for (i = 0; i < 128; i++)
{
if (active_charset[i] == val)
break;
}
if (i < 128)
{ /* we can print this one */
if (p)
*p++ = i + 128;
n++;
}
else
{ /* we do not have a translation: print utf8 */
if (p)
{
for (i = 0; i < encidx; i++)
{
sprintf (p, "\\x%02x", encbuf[i]);
p += 4;
}
}
n += encidx * 4;
encidx = 0;
}
}
else
{ /* native set */
else if (with_iconv)
{
/* Our strategy for using iconv is a bit strange
but it better keeps compatibility with
previous versions in regard to how invalid
encodings are displayed. What we do is to
keep the utf-8 as is and have the real
translation step then at the end. Yes, I
know that this is ugly. However we are short
of the 1.4 release and for this branch we
should not mess too much around with iconv
things. One reason for this is that we don't
know enough about non-GNU iconv
implementation and want to minimize the risk
of breaking the code on too many platforms. */
if ( p )
{
for (i=0; i < encidx; i++ )
*p++ = encbuf[i];
}
n += encidx;
encidx = 0;
}
else /* Latin-1 case. */
{
if (val >= 0x80 && val < 256)
{
n++; /* we can simply print this character */
/* We can simply print this character */
n++;
if (p)
*p++ = val;
}
else
{ /* we do not have a translation: print utf8 */
{
/* We do not have a translation: print utf8. */
if (p)
{
for (i = 0; i < encidx; i++)
@ -440,13 +557,78 @@ utf8_to_native (const char *string, size_t length, int delim)
}
}
if (!buffer)
{ /* allocate the buffer after the first pass */
{
/* Allocate the buffer after the first pass. */
buffer = p = jnlib_xmalloc (n + 1);
}
else
else if (with_iconv)
{
/* Note: See above for comments. */
iconv_t cd;
const char *inptr;
char *outbuf, *outptr;
size_t inbytes, outbytes;
*p = 0; /* Terminate the buffer. */
cd = iconv_open (active_charset_name, "utf-8");
if (cd == (iconv_t)-1)
{
handle_iconv_error (active_charset_name, "utf-8", 1);
jnlib_free (buffer);
return utf8_to_native (string, length, delim);
}
/* Allocate a new buffer large enough to hold all possible
encodings. */
n = p - buffer + 1;
inbytes = n - 1;;
inptr = buffer;
outbytes = n * MB_LEN_MAX;
if (outbytes / MB_LEN_MAX != n)
BUG (); /* Actually an overflow. */
outbuf = outptr = jnlib_xmalloc (outbytes);
if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
&outptr, &outbytes) == (size_t)-1)
{
static int shown;
if (!shown)
log_info (_("conversion from `%s' to `%s' failed: %s\n"),
"utf-8", active_charset_name, strerror (errno));
shown = 1;
/* Didn't worked out. Try again but without iconv. */
jnlib_free (buffer);
buffer = NULL;
jnlib_free (outbuf);
outbuf = do_utf8_to_native (string, length, delim, 0);
}
else /* Success. */
{
*outptr = 0; /* Make sure it is a string. */
/* We could realloc the buffer now but I doubt that it
makes much sense given that it will get freed
anyway soon after. */
jnlib_free (buffer);
}
iconv_close (cd);
return outbuf;
}
else /* Not using iconv. */
{
*p = 0; /* make a string */
*p = 0; /* Make sure it is a string. */
return buffer;
}
}
}
/* Convert string, which is in UTF-8 to native encoding. Replace
illegal encodings by some "\xnn" and quote all control
characters. A character with value DELIM will always be quoted, it
must be a vanilla ASCII character. A DELIM value of -1 is special:
it disables all quoting of control characters. */
char *
utf8_to_native (const char *string, size_t length, int delim)
{
return do_utf8_to_native (string, length, delim, use_iconv);
}

134
po/de.po
View File

@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg2 1.9.18\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"POT-Creation-Date: 2006-09-18 14:18+0200\n"
"POT-Creation-Date: 2006-09-22 19:24+0200\n"
"PO-Revision-Date: 2006-06-20 20:04+0200\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: de\n"
@ -34,12 +34,12 @@ msgstr "Im Server Modus ausführen"
msgid "run in daemon mode (background)"
msgstr "Im Daemon Modus ausführen"
#: agent/gpg-agent.c:113 kbx/kbxutil.c:82 scd/scdaemon.c:107 sm/gpgsm.c:334
#: agent/gpg-agent.c:113 kbx/kbxutil.c:82 scd/scdaemon.c:107 sm/gpgsm.c:335
#: tools/gpgconf.c:63
msgid "verbose"
msgstr "ausführlich"
#: agent/gpg-agent.c:114 kbx/kbxutil.c:83 scd/scdaemon.c:108 sm/gpgsm.c:335
#: agent/gpg-agent.c:114 kbx/kbxutil.c:83 scd/scdaemon.c:108 sm/gpgsm.c:336
msgid "be somewhat more quiet"
msgstr "Etwas weniger Ausgaben erzeugen"
@ -63,7 +63,7 @@ msgstr "Im Vordergrund laufen lassen"
msgid "do not grab keyboard and mouse"
msgstr "Tastatur und Maus nicht \"grabben\""
#: agent/gpg-agent.c:124 scd/scdaemon.c:120 sm/gpgsm.c:337
#: agent/gpg-agent.c:124 scd/scdaemon.c:120 sm/gpgsm.c:338
msgid "use a log file for the server"
msgstr "Logausgaben in eine Datei umlenken"
@ -116,12 +116,12 @@ msgid "|FILE|write environment settings also to FILE"
msgstr "|DATEI|Schreibe die Umgebungsvariabeln auf DATEI"
#: agent/gpg-agent.c:236 agent/protect-tool.c:143 scd/scdaemon.c:188
#: sm/gpgsm.c:516 tools/gpgconf.c:86
#: sm/gpgsm.c:517 tools/gpgconf.c:86
msgid "Please report bugs to <"
msgstr "Fehlerberichte bitte an <"
#: agent/gpg-agent.c:236 agent/protect-tool.c:143 scd/scdaemon.c:188
#: sm/gpgsm.c:516 tools/gpgconf.c:86
#: sm/gpgsm.c:517 tools/gpgconf.c:86
msgid ">.\n"
msgstr ">.\n"
@ -147,30 +147,30 @@ msgstr ""
msgid "out of core while allocating %lu bytes"
msgstr ""
#: agent/gpg-agent.c:334 scd/scdaemon.c:262 sm/gpgsm.c:645
#: agent/gpg-agent.c:334 scd/scdaemon.c:262 sm/gpgsm.c:646
#, c-format
msgid "invalid debug-level `%s' given\n"
msgstr "ungültige Debugebene `%s' angegeben\n"
#: agent/gpg-agent.c:505 agent/protect-tool.c:1073 kbx/kbxutil.c:432
#: scd/scdaemon.c:354 sm/gpgsm.c:766
#: scd/scdaemon.c:354 sm/gpgsm.c:767
#, c-format
msgid "libgcrypt is too old (need %s, have %s)\n"
msgstr ""
"Die Bibliothek \"libgcrypt\" is zu alt (benötigt wird %s, vorhanden ist %s)\n"
#: agent/gpg-agent.c:599 scd/scdaemon.c:431 sm/gpgsm.c:868
#: agent/gpg-agent.c:599 scd/scdaemon.c:431 sm/gpgsm.c:869
#, c-format
msgid "NOTE: no default option file `%s'\n"
msgstr "Notiz: Voreingestellte Konfigurationsdatei `%s' fehlt\n"
#: agent/gpg-agent.c:604 agent/gpg-agent.c:1115 scd/scdaemon.c:436
#: sm/gpgsm.c:872
#: sm/gpgsm.c:873
#, c-format
msgid "option file `%s': %s\n"
msgstr "Konfigurationsdatei `%s': %s\n"
#: agent/gpg-agent.c:612 scd/scdaemon.c:444 sm/gpgsm.c:879
#: agent/gpg-agent.c:612 scd/scdaemon.c:444 sm/gpgsm.c:880
#, c-format
msgid "reading options from `%s'\n"
msgstr "Optionen werden aus `%s' gelesen\n"
@ -547,7 +547,7 @@ msgstr ""
"@Kommandos:\n"
" "
#: kbx/kbxutil.c:77 sm/gpgsm.c:277 tools/gpgconf.c:60
#: kbx/kbxutil.c:77 sm/gpgsm.c:278 tools/gpgconf.c:60
msgid ""
"@\n"
"Options:\n"
@ -557,7 +557,7 @@ msgstr ""
"Optionen:\n"
" "
#: kbx/kbxutil.c:84 sm/gpgsm.c:343 tools/gpgconf.c:65
#: kbx/kbxutil.c:84 sm/gpgsm.c:344 tools/gpgconf.c:65
msgid "do not make any changes"
msgstr "Keine Änderungen durchführen"
@ -593,7 +593,7 @@ msgstr ""
msgid "run in multi server mode (foreground)"
msgstr "Im Multiserver Modus ausführen"
#: scd/scdaemon.c:111 sm/gpgsm.c:355
#: scd/scdaemon.c:111 sm/gpgsm.c:356
msgid "read options from file"
msgstr "Konfigurationsoptionen aus Datei lesen"
@ -1195,151 +1195,151 @@ msgstr "Rufe das gpg-protect-tool auf"
msgid "change a passphrase"
msgstr "Das Mantra (Passphrase) ändern"
#: sm/gpgsm.c:279
#: sm/gpgsm.c:280
msgid "create ascii armored output"
msgstr "Ausgabe mit ASCII Hülle wird erzeugt"
#: sm/gpgsm.c:281
#: sm/gpgsm.c:282
msgid "create base-64 encoded output"
msgstr "Ausgabe im Basis-64 format erzeugen"
#: sm/gpgsm.c:283
#: sm/gpgsm.c:284
msgid "assume input is in PEM format"
msgstr "Eingabedaten sind im PEM Format"
#: sm/gpgsm.c:285
#: sm/gpgsm.c:286
msgid "assume input is in base-64 format"
msgstr "Eingabedaten sind im Basis-64 Format"
#: sm/gpgsm.c:287
#: sm/gpgsm.c:288
msgid "assume input is in binary format"
msgstr "Eingabedaten sind im Binärformat"
#: sm/gpgsm.c:289
#: sm/gpgsm.c:290
msgid "|NAME|encrypt for NAME"
msgstr "|NAME|Verschlüsseln für NAME"
#: sm/gpgsm.c:292
#: sm/gpgsm.c:293
msgid "use system's dirmngr if available"
msgstr "Benutze den System Dirmngr when verfügbar"
#: sm/gpgsm.c:293
#: sm/gpgsm.c:294
msgid "never consult a CRL"
msgstr "Niemals eine CRL konsultieren"
#: sm/gpgsm.c:300
#: sm/gpgsm.c:301
msgid "check validity using OCSP"
msgstr "Die Gültigkeit mittels OCSP prüfen"
#: sm/gpgsm.c:303
#: sm/gpgsm.c:304
msgid "|N|number of certificates to include"
msgstr "|N|Sende N Zertifikate mit"
#: sm/gpgsm.c:306
#: sm/gpgsm.c:307
msgid "|FILE|take policy information from FILE"
msgstr "|DATEI|Richtlinieninformationen DATEI entnehmen"
#: sm/gpgsm.c:309
#: sm/gpgsm.c:310
msgid "do not check certificate policies"
msgstr "Zertikikatrichtlinien nicht überprüfen"
#: sm/gpgsm.c:313
#: sm/gpgsm.c:314
msgid "fetch missing issuer certificates"
msgstr "Fehlende Zertifikate automatisch holen"
#: sm/gpgsm.c:317
#: sm/gpgsm.c:318
msgid "|NAME|use NAME as default recipient"
msgstr "|NAME|Benutze NAME als voreingestellten Empfänger"
#: sm/gpgsm.c:319
#: sm/gpgsm.c:320
msgid "use the default key as default recipient"
msgstr "Benuzte voreingestellten Schlüssel als Standardempfänger"
#: sm/gpgsm.c:325
#: sm/gpgsm.c:326
msgid "use this user-id to sign or decrypt"
msgstr "Benuzte diese Benutzer ID zum Signieren oder Entschlüsseln"
#: sm/gpgsm.c:328
#: sm/gpgsm.c:329
msgid "|N|set compress level N (0 disables)"
msgstr "|N|Benutze Komprimierungsstufe N"
#: sm/gpgsm.c:330
#: sm/gpgsm.c:331
msgid "use canonical text mode"
msgstr "Kanonischen Textmodus benutzen"
#: sm/gpgsm.c:333 tools/gpgconf.c:62
#: sm/gpgsm.c:334 tools/gpgconf.c:62
msgid "use as output file"
msgstr "als Ausgabedatei benutzen"
#: sm/gpgsm.c:336
#: sm/gpgsm.c:337
msgid "don't use the terminal at all"
msgstr "Das Terminal überhaupt nicht benutzen"
#: sm/gpgsm.c:340
#: sm/gpgsm.c:341
msgid "force v3 signatures"
msgstr "Version 3 Signaturen erzwingen"
#: sm/gpgsm.c:341
#: sm/gpgsm.c:342
msgid "always use a MDC for encryption"
msgstr "Immer das MDC Verfahren zum verschlüsseln mitbenutzen"
#: sm/gpgsm.c:346
#: sm/gpgsm.c:347
msgid "batch mode: never ask"
msgstr "Stapelverarbeitungs Modus: Nie nachfragen"
#: sm/gpgsm.c:347
#: sm/gpgsm.c:348
msgid "assume yes on most questions"
msgstr "\"Ja\" auf die meisten Anfragen annehmen"
#: sm/gpgsm.c:348
#: sm/gpgsm.c:349
msgid "assume no on most questions"
msgstr "\"Nein\" auf die meisten Anfragen annehmen"
#: sm/gpgsm.c:350
#: sm/gpgsm.c:351
msgid "add this keyring to the list of keyrings"
msgstr "Diesen Keyring in die Liste der Keyrings aufnehmen"
#: sm/gpgsm.c:351
#: sm/gpgsm.c:352
msgid "add this secret keyring to the list"
msgstr "Diese geheimen Keyring in die Liste aufnehmen"
#: sm/gpgsm.c:352
#: sm/gpgsm.c:353
msgid "|NAME|use NAME as default secret key"
msgstr "|NAME|Benutze NAME als voreingestellten Schlüssel"
#: sm/gpgsm.c:353
#: sm/gpgsm.c:354
msgid "|HOST|use this keyserver to lookup keys"
msgstr "|HOST|Benutze HOST als Schlüsselserver"
#: sm/gpgsm.c:354
#: sm/gpgsm.c:355
msgid "|NAME|set terminal charset to NAME"
msgstr "|NAME|Den Zeichensatz für das Terminal auf NAME setzen"
#: sm/gpgsm.c:358
#: sm/gpgsm.c:359
msgid "|LEVEL|set the debugging level to LEVEL"
msgstr "|NAME|Die Debugstufe auf NAME setzen"
#: sm/gpgsm.c:366
#: sm/gpgsm.c:367
msgid "|FD|write status info to this FD"
msgstr "|FD|Statusinformationen auf Dateidescriptor FD schreiben"
#: sm/gpgsm.c:373
#: sm/gpgsm.c:374
msgid "|FILE|load extension module FILE"
msgstr "|DATEI|Das Erweiterungsmodul DATEI laden"
#: sm/gpgsm.c:379
#: sm/gpgsm.c:380
msgid "|NAME|use cipher algorithm NAME"
msgstr "|NAME|Den Verschlüsselungsalgrithmus NAME benutzen"
#: sm/gpgsm.c:381
#: sm/gpgsm.c:382
msgid "|NAME|use message digest algorithm NAME"
msgstr "|NAME|Den Hashalgorithmus NAME benutzen"
#: sm/gpgsm.c:383
#: sm/gpgsm.c:384
msgid "|N|use compress algorithm N"
msgstr "|N|Den Kompressionsalgorithmus Nummer N benutzen"
#: sm/gpgsm.c:391
#: sm/gpgsm.c:392
msgid ""
"@\n"
"(See the man page for a complete listing of all commands and options)\n"
@ -1347,7 +1347,7 @@ msgstr ""
"@\n"
"(Die \"man\" Seite beschreibt alle Kommands und Optionen)\n"
#: sm/gpgsm.c:394
#: sm/gpgsm.c:395
msgid ""
"@\n"
"Examples:\n"
@ -1367,11 +1367,11 @@ msgstr ""
" --list-keys [Namen] Schlüssel anzeigenn\n"
" --fingerprint [Namen] \"Fingerabdrücke\" anzeigen\\n\n"
#: sm/gpgsm.c:519
#: sm/gpgsm.c:520
msgid "Usage: gpgsm [options] [files] (-h for help)"
msgstr "Gebrauch: gpgsm [Optionen] [Dateien] (-h für Hilfe)"
#: sm/gpgsm.c:522
#: sm/gpgsm.c:523
msgid ""
"Syntax: gpgsm [options] [files]\n"
"sign, check, encrypt or decrypt using the S/MIME protocol\n"
@ -1380,7 +1380,7 @@ msgstr ""
"Gebrauch: gpgsm [Optionen] [Dateien]\n"
"Signieren, prüfen, ver- und entschlüsseln mittels S/MIME protocol\n"
#: sm/gpgsm.c:529
#: sm/gpgsm.c:530
msgid ""
"\n"
"Supported algorithms:\n"
@ -1388,55 +1388,55 @@ msgstr ""
"\n"
"Unterstützte Algorithmen:\n"
#: sm/gpgsm.c:616
#: sm/gpgsm.c:617
msgid "usage: gpgsm [options] "
msgstr "Gebrauch: gpgsm [Optionen] "
#: sm/gpgsm.c:681
#: sm/gpgsm.c:682
msgid "conflicting commands\n"
msgstr "Widersprechende Kommandos\n"
#: sm/gpgsm.c:697
#: sm/gpgsm.c:698
#, c-format
msgid "can't encrypt to `%s': %s\n"
msgstr "Verschlüsseln für `%s' nicht möglich: %s\n"
#: sm/gpgsm.c:771
#: sm/gpgsm.c:772
#, c-format
msgid "libksba is too old (need %s, have %s)\n"
msgstr "Die Bibliothek Libksba is nicht aktuell (benötige %s, habe %s)\n"
#: sm/gpgsm.c:1234
#: sm/gpgsm.c:1235
msgid "WARNING: program may create a core file!\n"
msgstr "WARNUNG: Programm könnte eine core-dump-Datei schreiben!\n"
#: sm/gpgsm.c:1251
#: sm/gpgsm.c:1252
msgid "WARNING: running with faked system time: "
msgstr "WARNUNG: Ausführung mit gefälschter Systemzeit: "
#: sm/gpgsm.c:1277
#: sm/gpgsm.c:1278
msgid "selected cipher algorithm is invalid\n"
msgstr "Das ausgewählte Verschlüsselungsverfahren ist ungültig\n"
#: sm/gpgsm.c:1285
#: sm/gpgsm.c:1286
msgid "selected digest algorithm is invalid\n"
msgstr "Das ausgewählte Hashverfahren ist ungültig\n"
#: sm/gpgsm.c:1316
#: sm/gpgsm.c:1317
#, fuzzy, c-format
msgid "importing common certificates `%s'\n"
msgstr "Fehler beim Importieren des Zertifikats: %s\n"
#: sm/gpgsm.c:1334
#: sm/gpgsm.c:1335
#, c-format
msgid "can't sign using `%s': %s\n"
msgstr "Signieren mit `%s' nicht möglich: %s\n"
#: sm/gpgsm.c:1518
#: sm/gpgsm.c:1519
msgid "this command has not yet been implemented\n"
msgstr "Dieses Kommando wurde noch nicht implementiert\n"
#: sm/gpgsm.c:1754 sm/gpgsm.c:1791 sm/qualified.c:74
#: sm/gpgsm.c:1755 sm/gpgsm.c:1792 sm/qualified.c:74
#, c-format
msgid "can't open `%s': %s\n"
msgstr "Datei `%s' kann nicht geöffnet werden: %s\n"