008-11-03 Marcus Brinkmann <marcus@g10code.com>
[gpgme.git] / src / conversion.c
1 /* conversion.c - String conversion helper functions.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
4  
5    This file is part of GPGME.
6
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11    
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 /* Solaris 8 needs sys/types.h before time.h.  */
29 #include <sys/types.h>
30 #include <time.h>
31 #include <errno.h>
32
33 #include "gpgme.h"
34 #include "util.h"
35 #include "debug.h"
36
37 #define atoi_1(p)   (*(p) - '0' )
38 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
39 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
40
41
42 \f
43 /* Convert two hexadecimal digits from STR to the value they
44    represent.  Returns -1 if one of the characters is not a
45    hexadecimal digit.  */
46 int
47 _gpgme_hextobyte (const char *str)
48 {
49   int val = 0;
50   int i;
51
52 #define NROFHEXDIGITS 2
53   for (i = 0; i < NROFHEXDIGITS; i++)
54     {
55       if (*str >= '0' && *str <= '9')
56         val += *str - '0';
57       else if (*str >= 'A' && *str <= 'F')
58         val += 10 + *str - 'A';
59       else if (*str >= 'a' && *str <= 'f')
60         val += 10 + *str - 'a';
61       else
62         return -1;
63       if (i < NROFHEXDIGITS - 1)
64         val *= 16;
65       str++;
66     }
67   return val;
68 }
69
70
71 /* Decode the C formatted string SRC and store the result in the
72    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
73    large enough buffer is allocated with malloc and *DESTP is set to
74    the result.  Currently, LEN is only used to specify if allocation
75    is desired or not, the caller is expected to make sure that *DESTP
76    is large enough if LEN is not zero.  */
77 gpgme_error_t
78 _gpgme_decode_c_string (const char *src, char **destp, size_t len)
79 {
80   char *dest;
81
82   /* Set up the destination buffer.  */
83   if (len)
84     {
85       if (len < strlen (src) + 1)
86         return gpg_error (GPG_ERR_INTERNAL);
87
88       dest = *destp;
89     }
90   else
91     {
92       /* The converted string will never be larger than the original
93          string.  */
94       dest = malloc (strlen (src) + 1);
95       if (!dest)
96         return gpg_error_from_errno (errno);
97
98       *destp = dest;
99     }
100
101   /* Convert the string.  */
102   while (*src)
103     {
104       if (*src != '\\')
105         {
106           *(dest++) = *(src++);
107           continue;
108         }
109
110       switch (src[1])
111         {
112 #define DECODE_ONE(match,result)        \
113         case match:                     \
114           src += 2;                     \
115           *(dest++) = result;           \
116           break;
117
118           DECODE_ONE ('\'', '\'');
119           DECODE_ONE ('\"', '\"');
120           DECODE_ONE ('\?', '\?');
121           DECODE_ONE ('\\', '\\');
122           DECODE_ONE ('a', '\a');
123           DECODE_ONE ('b', '\b');
124           DECODE_ONE ('f', '\f');
125           DECODE_ONE ('n', '\n');
126           DECODE_ONE ('r', '\r');
127           DECODE_ONE ('t', '\t');
128           DECODE_ONE ('v', '\v');
129
130         case 'x':
131           {
132             int val = _gpgme_hextobyte (&src[2]);
133
134             if (val == -1)
135               {
136                 /* Should not happen.  */
137                 *(dest++) = *(src++);
138                 *(dest++) = *(src++);
139                 if (*src)
140                   *(dest++) = *(src++);
141                 if (*src)
142                   *(dest++) = *(src++);
143               }
144             else
145               {
146                 if (!val)
147                   {
148                     /* A binary zero is not representable in a C
149                        string.  */
150                     *(dest++) = '\\';
151                     *(dest++) = '0'; 
152                   }
153                 else 
154                   *((unsigned char *) dest++) = val;
155                 src += 4;
156               }
157           }
158           break;
159
160         default:
161           {
162             /* Should not happen.  */
163             *(dest++) = *(src++);
164             *(dest++) = *(src++);
165           }
166         } 
167     }
168   *(dest++) = 0;
169
170   return 0;
171 }
172
173
174 /* Decode the percent escaped string SRC and store the result in the
175    buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
176    large enough buffer is allocated with malloc and *DESTP is set to
177    the result.  Currently, LEN is only used to specify if allocation
178    is desired or not, the caller is expected to make sure that *DESTP
179    is large enough if LEN is not zero.  If BINARY is 1, then '\0'
180    characters are allowed in the output.  */
181 gpgme_error_t
182 _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
183                               int binary)
184 {
185   char *dest;
186
187   /* Set up the destination buffer.  */
188   if (len)
189     {
190       if (len < strlen (src) + 1)
191         return gpg_error (GPG_ERR_INTERNAL);
192
193       dest = *destp;
194     }
195   else
196     {
197       /* The converted string will never be larger than the original
198          string.  */
199       dest = malloc (strlen (src) + 1);
200       if (!dest)
201         return gpg_error_from_errno (errno);
202
203       *destp = dest;
204     }
205
206   /* Convert the string.  */
207   while (*src)
208     {
209       if (*src != '%')
210         {
211           *(dest++) = *(src++);
212           continue;
213         }
214       else
215         {
216           int val = _gpgme_hextobyte (&src[1]);
217           
218           if (val == -1)
219             {
220               /* Should not happen.  */
221               *(dest++) = *(src++);
222               if (*src)
223                 *(dest++) = *(src++);
224               if (*src)
225                 *(dest++) = *(src++);
226             }
227           else
228             {
229               if (!val && !binary)
230                 {
231                   /* A binary zero is not representable in a C
232                      string.  */
233                   *(dest++) = '\\';
234                   *(dest++) = '0'; 
235                 }
236               else 
237                 *((unsigned char *) dest++) = val;
238               src += 3;
239             }
240         }
241     }
242   *(dest++) = 0;
243
244   return 0;
245 }
246
247
248 /* Parse the string TIMESTAMP into a time_t.  The string may either be
249    seconds since Epoch or in the ISO 8601 format like
250    "20390815T143012".  Returns 0 for an empty string or seconds since
251    Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
252    point to the next non-parsed character in TIMESTRING. */
253 time_t
254 _gpgme_parse_timestamp (const char *timestamp, char **endp)
255 {
256   /* Need to skip leading spaces, because that is what strtoul does
257      but not our ISO 8601 checking code. */
258   while (*timestamp && *timestamp== ' ')
259     timestamp++;
260   if (!*timestamp)
261     return 0;
262
263   if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
264     {
265       struct tm buf;
266       int year;
267
268       year = atoi_4 (timestamp);
269       if (year < 1900)
270         return (time_t)(-1);
271
272       /* Fixme: We would better use a configure test to see whether
273          mktime can handle dates beyond 2038. */
274       if (sizeof (time_t) <= 4 && year >= 2038)
275         return (time_t)2145914603; /* 2037-12-31 23:23:23 */
276
277       memset (&buf, 0, sizeof buf);
278       buf.tm_year = year - 1900;
279       buf.tm_mon = atoi_2 (timestamp+4) - 1; 
280       buf.tm_mday = atoi_2 (timestamp+6);
281       buf.tm_hour = atoi_2 (timestamp+9);
282       buf.tm_min = atoi_2 (timestamp+11);
283       buf.tm_sec = atoi_2 (timestamp+13);
284
285       if (endp)
286         *endp = (char*)(timestamp + 15);
287 #ifdef HAVE_TIMEGM
288       return timegm (&buf);
289 #else
290       {
291         time_t tim;
292         
293         putenv ("TZ=UTC");
294         tim = mktime (&buf);
295 #ifdef __GNUC__
296 #warning fixme: we must somehow reset TZ here.  It is not threadsafe anyway.
297 #endif
298         return tim;
299       }
300 #endif /* !HAVE_TIMEGM */
301     }
302   else
303     return (time_t)strtoul (timestamp, endp, 10);
304 }
305
306
307
308 \f
309 static struct
310 {
311   char *name;
312   gpgme_error_t err;
313 } gnupg_errors[] =
314   {
315     { "EOF", GPG_ERR_EOF },
316     { "No_Error", GPG_ERR_NO_ERROR },
317     { "General_Error", GPG_ERR_GENERAL },
318     { "Out_Of_Core", GPG_ERR_ENOMEM },
319     { "Invalid_Value", GPG_ERR_INV_VALUE },
320     { "IO_Error", GPG_ERR_GENERAL },
321     { "Resource_Limit", GPG_ERR_RESOURCE_LIMIT },
322     { "Internal_Error", GPG_ERR_INTERNAL },
323     { "Bad_Certificate", GPG_ERR_BAD_CERT },
324     { "Bad_Certificate_Chain", GPG_ERR_BAD_CERT_CHAIN},
325     { "Missing_Certificate", GPG_ERR_MISSING_CERT },
326     { "No_Data", GPG_ERR_NO_DATA },
327     { "Bad_Signature", GPG_ERR_BAD_SIGNATURE },
328     { "Not_Implemented", GPG_ERR_NOT_IMPLEMENTED },
329     { "Conflict", GPG_ERR_CONFLICT },
330     { "Bug", GPG_ERR_BUG },
331     { "Read_Error", GPG_ERR_GENERAL },
332     { "Write_Error", GPG_ERR_GENERAL },
333     { "Invalid_Line", GPG_ERR_GENERAL },
334     { "Incomplete_Line", GPG_ERR_INCOMPLETE_LINE },
335     { "Invalid_Response", GPG_ERR_INV_RESPONSE },
336     { "Agent_Error", GPG_ERR_AGENT },
337     { "No_Public_Key", GPG_ERR_NO_PUBKEY },
338     { "No_Secret_Key", GPG_ERR_NO_SECKEY },
339     { "File_Open_Error", GPG_ERR_GENERAL },
340     { "File_Create_Error", GPG_ERR_GENERAL },
341     { "File_Error", GPG_ERR_GENERAL },
342     { "Not_Supported", GPG_ERR_NOT_SUPPORTED },
343     { "Invalid_Data", GPG_ERR_INV_DATA },
344     { "Assuan_Server_Fault", GPG_ERR_ASSUAN_SERVER_FAULT },
345     { "Assuan_Error", GPG_ERR_ASSUAN },
346     { "Invalid_Session_Key", GPG_ERR_INV_SESSION_KEY },
347     { "Invalid_Sexp", GPG_ERR_INV_SEXP },
348     { "Unsupported_Algorithm", GPG_ERR_UNSUPPORTED_ALGORITHM },
349     { "No_PIN_Entry", GPG_ERR_NO_PIN_ENTRY },
350     { "PIN_Entry_Error", GPG_ERR_NO_PIN_ENTRY },
351     { "Bad_PIN", GPG_ERR_BAD_PIN },
352     { "Bad_Passphrase", GPG_ERR_BAD_PASSPHRASE },
353     { "Invalid_Name", GPG_ERR_INV_NAME },
354     { "Bad_Public_Key", GPG_ERR_BAD_PUBKEY },
355     { "Bad_Secret_Key", GPG_ERR_BAD_SECKEY },
356     { "Bad_Data", GPG_ERR_BAD_DATA },
357     { "Invalid_Parameter", GPG_ERR_INV_PARAMETER },
358     { "Tribute_to_D_A", GPG_ERR_TRIBUTE_TO_D_A },
359     { "No_Dirmngr", GPG_ERR_NO_DIRMNGR },
360     { "Dirmngr_Error", GPG_ERR_DIRMNGR },
361     { "Certificate_Revoked", GPG_ERR_CERT_REVOKED },
362     { "No_CRL_Known", GPG_ERR_NO_CRL_KNOWN },
363     { "CRL_Too_Old", GPG_ERR_CRL_TOO_OLD },
364     { "Line_Too_Long", GPG_ERR_LINE_TOO_LONG },
365     { "Not_Trusted", GPG_ERR_NOT_TRUSTED },
366     { "Canceled", GPG_ERR_CANCELED },
367     { "Bad_CA_Certificate", GPG_ERR_BAD_CA_CERT },
368     { "Certificate_Expired", GPG_ERR_CERT_EXPIRED },
369     { "Certificate_Too_Young", GPG_ERR_CERT_TOO_YOUNG },
370     { "Unsupported_Certificate", GPG_ERR_UNSUPPORTED_CERT },
371     { "Unknown_Sexp", GPG_ERR_UNKNOWN_SEXP },
372     { "Unsupported_Protection", GPG_ERR_UNSUPPORTED_PROTECTION },
373     { "Corrupted_Protection", GPG_ERR_CORRUPTED_PROTECTION },
374     { "Ambiguous_Name", GPG_ERR_AMBIGUOUS_NAME },
375     { "Card_Error", GPG_ERR_CARD },
376     { "Card_Reset", GPG_ERR_CARD_RESET },
377     { "Card_Removed", GPG_ERR_CARD_REMOVED },
378     { "Invalid_Card", GPG_ERR_INV_CARD },
379     { "Card_Not_Present", GPG_ERR_CARD_NOT_PRESENT },
380     { "No_PKCS15_App", GPG_ERR_NO_PKCS15_APP },
381     { "Not_Confirmed", GPG_ERR_NOT_CONFIRMED },
382     { "Configuration_Error", GPG_ERR_CONFIGURATION },
383     { "No_Policy_Match", GPG_ERR_NO_POLICY_MATCH },
384     { "Invalid_Index", GPG_ERR_INV_INDEX },
385     { "Invalid_Id", GPG_ERR_INV_ID },
386     { "No_Scdaemon", GPG_ERR_NO_SCDAEMON },
387     { "Scdaemon_Error", GPG_ERR_SCDAEMON },
388     { "Unsupported_Protocol", GPG_ERR_UNSUPPORTED_PROTOCOL },
389     { "Bad_PIN_Method", GPG_ERR_BAD_PIN_METHOD },
390     { "Card_Not_Initialized", GPG_ERR_CARD_NOT_INITIALIZED },
391     { "Unsupported_Operation", GPG_ERR_UNSUPPORTED_OPERATION },
392     { "Wrong_Key_Usage", GPG_ERR_WRONG_KEY_USAGE }
393   };
394     
395
396 gpgme_error_t
397 _gpgme_map_gnupg_error (char *errstr)
398 {
399   unsigned int i;
400   gpgme_error_t err = gpg_err_make (GPG_ERR_SOURCE_GPG, GPG_ERR_GENERAL);
401
402   /* Future version of GnuPG might return the error code directly, so
403      we first test for a a numerical value and use that verbatim.
404      Note that this numerical value might be followed by an
405      underschore and the textual representation of the error code. */
406   if (*errstr >= '0' && *errstr <= '9')
407     return strtoul (errstr, NULL, 10);
408
409   /* Well, this is a token, use the mapping table to get the error.
410      The drawback is that we won't receive an error source and have to
411      use GPG as source. */
412   for (i = 0; i < DIM (gnupg_errors); i++)
413     if (!strcmp (gnupg_errors[i].name, errstr))
414       err = gpg_err_make (GPG_ERR_SOURCE_GPG, gnupg_errors[i].err);
415
416   TRACE3 (DEBUG_CTX, "_gpgme_map_gnupg_error", 0,
417           "mapped %s to %s <%s>", errstr, gpgme_strerror (err),
418           gpgme_strsource (err));
419   return err;
420 }