diff options
Diffstat (limited to 'libtdenetwork/libgpgme-copy/gpgme/conversion.c')
-rw-r--r-- | libtdenetwork/libgpgme-copy/gpgme/conversion.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/libtdenetwork/libgpgme-copy/gpgme/conversion.c b/libtdenetwork/libgpgme-copy/gpgme/conversion.c new file mode 100644 index 000000000..01e5cae7e --- /dev/null +++ b/libtdenetwork/libgpgme-copy/gpgme/conversion.c @@ -0,0 +1,414 @@ +/* conversion.c - String conversion helper functions. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> + +#include "gpgme.h" +#include "util.h" + + +#define atoi_1(p) (*(p) - '0' ) +#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) +#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) + + + +/* Convert two hexadecimal digits from STR to the value they + represent. Returns -1 if one of the characters is not a + hexadecimal digit. */ +int +_gpgme_hextobyte (const char *str) +{ + int val = 0; + int i; + +#define NROFHEXDIGITS 2 + for (i = 0; i < NROFHEXDIGITS; i++) + { + if (*str >= '0' && *str <= '9') + val += *str - '0'; + else if (*str >= 'A' && *str <= 'F') + val += 10 + *str - 'A'; + else if (*str >= 'a' && *str <= 'f') + val += 10 + *str - 'a'; + else + return -1; + if (i < NROFHEXDIGITS - 1) + val *= 16; + str++; + } + return val; +} + + +/* Decode the C formatted string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. */ +gpgme_error_t +_gpgme_decode_c_string (const char *src, char **destp, size_t len) +{ + char *dest; + + /* Set up the destination buffer. */ + if (len) + { + if (len < strlen (src) + 1) + return gpg_error (GPG_ERR_INTERNAL); + + dest = *destp; + } + else + { + /* The converted string will never be larger than the original + string. */ + dest = malloc (strlen (src) + 1); + if (!dest) + return gpg_error_from_errno (errno); + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src != '\\') + { + *(dest++) = *(src++); + continue; + } + + switch (src[1]) + { +#define DECODE_ONE(match,result) \ + case match: \ + src += 2; \ + *(dest++) = result; \ + break; + + DECODE_ONE ('\'', '\''); + DECODE_ONE ('\"', '\"'); + DECODE_ONE ('\?', '\?'); + DECODE_ONE ('\\', '\\'); + DECODE_ONE ('a', '\a'); + DECODE_ONE ('b', '\b'); + DECODE_ONE ('f', '\f'); + DECODE_ONE ('n', '\n'); + DECODE_ONE ('r', '\r'); + DECODE_ONE ('t', '\t'); + DECODE_ONE ('v', '\v'); + + case 'x': + { + int val = _gpgme_hextobyte (&src[2]); + + if (val == -1) + { + /* Should not happen. */ + *(dest++) = *(src++); + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + } + else + { + if (!val) + { + /* A binary zero is not representable in a C + string. */ + *(dest++) = '\\'; + *(dest++) = '0'; + } + else + *((unsigned char *) dest++) = val; + src += 4; + } + } + break; + + default: + { + /* Should not happen. */ + *(dest++) = *(src++); + *(dest++) = *(src++); + } + } + } + *(dest++) = 0; + + return 0; +} + + +/* Decode the percent escaped string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. If BINARY is 1, then '\0' + characters are allowed in the output. */ +gpgme_error_t +_gpgme_decode_percent_string (const char *src, char **destp, size_t len, + int binary) +{ + char *dest; + + /* Set up the destination buffer. */ + if (len) + { + if (len < strlen (src) + 1) + return gpg_error (GPG_ERR_INTERNAL); + + dest = *destp; + } + else + { + /* The converted string will never be larger than the original + string. */ + dest = malloc (strlen (src) + 1); + if (!dest) + return gpg_error_from_errno (errno); + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src != '%') + { + *(dest++) = *(src++); + continue; + } + else + { + int val = _gpgme_hextobyte (&src[1]); + + if (val == -1) + { + /* Should not happen. */ + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + } + else + { + if (!val && !binary) + { + /* A binary zero is not representable in a C + string. */ + *(dest++) = '\\'; + *(dest++) = '0'; + } + else + *((unsigned char *) dest++) = val; + src += 3; + } + } + } + *(dest++) = 0; + + return 0; +} + + +/* Parse the string TIMESTAMP into a time_t. The string may either be + seconds since Epoch or in the ISO 8601 format like + "20390815T143012". Returns 0 for an empty string or seconds since + Epoch. Leading spaces are skipped. If ENDP is not NULL, it will + point to the next non-parsed character in TIMESTRING. */ +time_t +_gpgme_parse_timestamp (const char *timestamp, char **endp) +{ + /* Need to skip leading spaces, because that is what strtoul does + but not our ISO 8601 checking code. */ + while (*timestamp && *timestamp== ' ') + timestamp++; + if (!*timestamp) + return 0; + + if (strlen (timestamp) >= 15 && timestamp[8] == 'T') + { + struct tm buf; + int year; + + year = atoi_4 (timestamp); + if (year < 1900) + return (time_t)(-1); + + /* Fixme: We would better use a configure test to see whether + mktime can handle dates beyond 2038. */ + if (sizeof (time_t) <= 4 && year >= 2038) + return (time_t)2145914603; /* 2037-12-31 23:23:23 */ + + memset (&buf, 0, sizeof buf); + buf.tm_year = year - 1900; + buf.tm_mon = atoi_2 (timestamp+4) - 1; + buf.tm_mday = atoi_2 (timestamp+6); + buf.tm_hour = atoi_2 (timestamp+9); + buf.tm_min = atoi_2 (timestamp+11); + buf.tm_sec = atoi_2 (timestamp+13); + + if (endp) + *endp = (char*)(timestamp + 15); +#ifdef HAVE_TIMEGM + return timegm (&buf); +#else + { + time_t tim; + + putenv ("TZ=UTC"); + tim = mktime (&buf); +#ifdef __GNUC__ +#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway. +#endif + return tim; + } +#endif /* !HAVE_TIMEGM */ + } + else + return (time_t)strtoul (timestamp, endp, 10); +} + + + + +static struct +{ + char *name; + gpgme_error_t err; +} gnupg_errors[] = + { + { "EOF", GPG_ERR_EOF }, + { "No_Error", GPG_ERR_NO_ERROR }, + { "General_Error", GPG_ERR_GENERAL }, + { "Out_Of_Core", GPG_ERR_ENOMEM }, + { "Invalid_Value", GPG_ERR_INV_VALUE }, + { "IO_Error", GPG_ERR_GENERAL }, + { "Resource_Limit", GPG_ERR_RESOURCE_LIMIT }, + { "Internal_Error", GPG_ERR_INTERNAL }, + { "Bad_Certificate", GPG_ERR_BAD_CERT }, + { "Bad_Certificate_Chain", GPG_ERR_BAD_CERT_CHAIN}, + { "Missing_Certificate", GPG_ERR_MISSING_CERT }, + { "No_Data", GPG_ERR_NO_DATA }, + { "Bad_Signature", GPG_ERR_BAD_SIGNATURE }, + { "Not_Implemented", GPG_ERR_NOT_IMPLEMENTED }, + { "Conflict", GPG_ERR_CONFLICT }, + { "Bug", GPG_ERR_BUG }, + { "Read_Error", GPG_ERR_GENERAL }, + { "Write_Error", GPG_ERR_GENERAL }, + { "Invalid_Line", GPG_ERR_GENERAL }, + { "Incomplete_Line", GPG_ERR_INCOMPLETE_LINE }, + { "Invalid_Response", GPG_ERR_INV_RESPONSE }, + { "Agent_Error", GPG_ERR_AGENT }, + { "No_Public_Key", GPG_ERR_NO_PUBKEY }, + { "No_Secret_Key", GPG_ERR_NO_SECKEY }, + { "File_Open_Error", GPG_ERR_GENERAL }, + { "File_Create_Error", GPG_ERR_GENERAL }, + { "File_Error", GPG_ERR_GENERAL }, + { "Not_Supported", GPG_ERR_NOT_SUPPORTED }, + { "Invalid_Data", GPG_ERR_INV_DATA }, + { "Assuan_Server_Fault", GPG_ERR_ASSUAN_SERVER_FAULT }, + { "Assuan_Error", GPG_ERR_ASSUAN }, + { "Invalid_Session_Key", GPG_ERR_INV_SESSION_KEY }, + { "Invalid_Sexp", GPG_ERR_INV_SEXP }, + { "Unsupported_Algorithm", GPG_ERR_UNSUPPORTED_ALGORITHM }, + { "No_PIN_Entry", GPG_ERR_NO_PIN_ENTRY }, + { "PIN_Entry_Error", GPG_ERR_NO_PIN_ENTRY }, + { "Bad_PIN", GPG_ERR_BAD_PIN }, + { "Bad_Passphrase", GPG_ERR_BAD_PASSPHRASE }, + { "Invalid_Name", GPG_ERR_INV_NAME }, + { "Bad_Public_Key", GPG_ERR_BAD_PUBKEY }, + { "Bad_Secret_Key", GPG_ERR_BAD_SECKEY }, + { "Bad_Data", GPG_ERR_BAD_DATA }, + { "Invalid_Parameter", GPG_ERR_INV_PARAMETER }, + { "Tribute_to_D_A", GPG_ERR_TRIBUTE_TO_D_A }, + { "No_Dirmngr", GPG_ERR_NO_DIRMNGR }, + { "Dirmngr_Error", GPG_ERR_DIRMNGR }, + { "Certificate_Revoked", GPG_ERR_CERT_REVOKED }, + { "No_CRL_Known", GPG_ERR_NO_CRL_KNOWN }, + { "CRL_Too_Old", GPG_ERR_CRL_TOO_OLD }, + { "Line_Too_Long", GPG_ERR_LINE_TOO_LONG }, + { "Not_Trusted", GPG_ERR_NOT_TRUSTED }, + { "Canceled", GPG_ERR_CANCELED }, + { "Bad_CA_Certificate", GPG_ERR_BAD_CA_CERT }, + { "Certificate_Expired", GPG_ERR_CERT_EXPIRED }, + { "Certificate_Too_Young", GPG_ERR_CERT_TOO_YOUNG }, + { "Unsupported_Certificate", GPG_ERR_UNSUPPORTED_CERT }, + { "Unknown_Sexp", GPG_ERR_UNKNOWN_SEXP }, + { "Unsupported_Protection", GPG_ERR_UNSUPPORTED_PROTECTION }, + { "Corrupted_Protection", GPG_ERR_CORRUPTED_PROTECTION }, + { "Ambiguous_Name", GPG_ERR_AMBIGUOUS_NAME }, + { "Card_Error", GPG_ERR_CARD }, + { "Card_Reset", GPG_ERR_CARD_RESET }, + { "Card_Removed", GPG_ERR_CARD_REMOVED }, + { "Invalid_Card", GPG_ERR_INV_CARD }, + { "Card_Not_Present", GPG_ERR_CARD_NOT_PRESENT }, + { "No_PKCS15_App", GPG_ERR_NO_PKCS15_APP }, + { "Not_Confirmed", GPG_ERR_NOT_CONFIRMED }, + { "Configuration_Error", GPG_ERR_CONFIGURATION }, + { "No_Policy_Match", GPG_ERR_NO_POLICY_MATCH }, + { "Invalid_Index", GPG_ERR_INV_INDEX }, + { "Invalid_Id", GPG_ERR_INV_ID }, + { "No_Scdaemon", GPG_ERR_NO_SCDAEMON }, + { "Scdaemon_Error", GPG_ERR_SCDAEMON }, + { "Unsupported_Protocol", GPG_ERR_UNSUPPORTED_PROTOCOL }, + { "Bad_PIN_Method", GPG_ERR_BAD_PIN_METHOD }, + { "Card_Not_Initialized", GPG_ERR_CARD_NOT_INITIALIZED }, + { "Unsupported_Operation", GPG_ERR_UNSUPPORTED_OPERATION }, + { "Wrong_Key_Usage", GPG_ERR_WRONG_KEY_USAGE } + }; + + +gpgme_error_t +_gpgme_map_gnupg_error (char *err) +{ + unsigned int i; + + /* Future version of GnuPG might return the error code directly, so + we first test for a a numerical value and use that verbatim. + Note that this numerical value might be followed by an + underschore and the textual representation of the error code. */ + if (*err >= '0' && *err <= '9') + return strtoul (err, NULL, 10); + + /* Well, this is a token, use the mapping table to get the error. + The drawback is that we won't receive an error source and have to + use GPG as source. */ + for (i = 0; i < DIM (gnupg_errors); i++) + if (!strcmp (gnupg_errors[i].name, err)) + return gpg_err_make (GPG_ERR_SOURCE_GPG, gnupg_errors[i].err); + + return gpg_err_make (GPG_ERR_SOURCE_GPG, GPG_ERR_GENERAL); +} |