* http.c (connect_server): Fix fd leak when connecting to a round-robin
[gnupg.git] / util / miscutil.c
1 /* miscutil.c -  miscellaneous utilities
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <ctype.h>
28 #ifdef HAVE_LANGINFO_H
29 #include <langinfo.h>
30 #endif
31 #include "types.h"
32 #include "util.h"
33 #include "i18n.h"
34
35 /****************
36  * I know that the OpenPGP protocol has a Y2106 problem ;-)
37  */
38 u32
39 make_timestamp()
40 {
41     return time(NULL);
42 }
43
44 /****************
45  * Scan a date string and return a timestamp.
46  * The only supported format is "yyyy-mm-dd"
47  * Returns 0 for an invalid date.
48  */
49 u32
50 scan_isodatestr( const char *string )
51 {
52     int year, month, day;
53     struct tm tmbuf;
54     time_t stamp;
55     int i;
56
57     if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
58         return 0;
59     for( i=0; i < 4; i++ )
60         if( !digitp(string+i) )
61             return 0;
62     if( !digitp(string+5) || !digitp(string+6) )
63         return 0;
64     if( !digitp(string+8) || !digitp(string+9) )
65         return 0;
66     year = atoi(string);
67     month = atoi(string+5);
68     day = atoi(string+8);
69     /* some basic checks */
70     if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
71         return 0;
72     memset( &tmbuf, 0, sizeof tmbuf );
73     tmbuf.tm_mday = day;
74     tmbuf.tm_mon = month-1;
75     tmbuf.tm_year = year - 1900;
76     tmbuf.tm_isdst = -1;
77     stamp = mktime( &tmbuf );
78     if( stamp == (time_t)-1 )
79         return 0;
80     return stamp;
81 }
82
83
84 u32
85 add_days_to_timestamp( u32 stamp, u16 days )
86 {
87     return stamp + days*86400L;
88 }
89
90
91 /****************
92  * Return a string with a time value in the form: x Y, n D, n H
93  */
94
95 const char *
96 strtimevalue( u32 value )
97 {
98     static char buffer[30];
99     unsigned int years, days, hours, minutes;
100
101     value /= 60;
102     minutes = value % 60;
103     value /= 60;
104     hours = value % 24;
105     value /= 24;
106     days = value % 365;
107     value /= 365;
108     years = value;
109
110     sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
111     if( years )
112         return buffer;
113     if( days )
114         return strchr( buffer, 'y' ) + 1;
115     return strchr( buffer, 'd' ) + 1;
116 }
117
118
119 /****************
120  * Note: this function returns GMT
121  */
122 const char *
123 strtimestamp( u32 stamp )
124 {
125     static char buffer[11+5];
126     struct tm *tp;
127     time_t atime = stamp;
128     
129     if (atime < 0) {
130         strcpy (buffer, "????" "-??" "-??");
131     }
132     else {
133         tp = gmtime( &atime );
134         sprintf(buffer,"%04d-%02d-%02d",
135                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
136     }
137     return buffer;
138 }
139
140 /****************
141  * Note: this function returns local time
142  */
143 const char *
144 asctimestamp( u32 stamp )
145 {
146     static char buffer[50];
147 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
148       static char fmt[50];
149 #endif
150     struct tm *tp;
151     time_t atime = stamp;
152
153     if (atime < 0) {
154         strcpy (buffer, "????" "-??" "-??");
155         return buffer;
156     }
157
158     tp = localtime( &atime );
159 #ifdef HAVE_STRFTIME
160 #if defined(HAVE_NL_LANGINFO)
161       mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
162       if( strstr( fmt, "%Z" ) == NULL )
163         strcat( fmt, " %Z");
164       strftime( buffer, DIM(buffer)-1, fmt, tp );
165 #else
166       /* fixme: we should check whether the locale appends a " %Z"
167        * These locales from glibc don't put the " %Z":
168        * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN
169        */
170       strftime( buffer, DIM(buffer)-1, "%c %Z", tp );
171 #endif
172     buffer[DIM(buffer)-1] = 0;
173 #else
174     mem2str( buffer, asctime(tp), DIM(buffer) );
175 #endif
176     return buffer;
177 }
178
179
180 /****************
181  * Print a string to FP, but filter all control characters out.
182  */
183 void
184 print_string2( FILE *fp, const byte *p, size_t n, int delim, int delim2 )
185 {
186     for( ; n; n--, p++ )
187         if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0)
188             || *p == delim || *p == delim2
189             || ((delim || delim2) && *p=='\\'))
190           {
191             putc('\\', fp);
192             if( *p == '\n' )
193                 putc('n', fp);
194             else if( *p == '\r' )
195                 putc('r', fp);
196             else if( *p == '\f' )
197                 putc('f', fp);
198             else if( *p == '\v' )
199                 putc('v', fp);
200             else if( *p == '\b' )
201                 putc('b', fp);
202             else if( !*p )
203                 putc('0', fp);
204             else
205                 fprintf(fp, "x%02x", *p );
206           }
207         else
208           putc(*p, fp);
209 }
210
211 void
212 print_string( FILE *fp, const byte *p, size_t n, int delim )
213 {
214   print_string2(fp,p,n,delim,0);
215 }
216
217 /****************
218  * Print an UTF8 string to FP and filter all control characters out.
219  */
220 void
221 print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim )
222 {
223     size_t i;
224     char *buf;
225
226     /* we can handle plain ascii simpler, so check for it first */
227     for(i=0; i < n; i++ ) {
228         if( p[i] & 0x80 )
229             break;
230     }
231     if( i < n ) {
232         buf = utf8_to_native ( p, n, delim );
233         /*(utf8 conversion already does the control character quoting)*/
234         fputs( buf, fp );
235         m_free( buf );
236     }
237     else
238         print_string( fp, p, n, delim );
239 }
240
241 void
242 print_utf8_string( FILE *fp, const byte *p, size_t n )
243 {
244     print_utf8_string2 (fp, p, n, 0);
245 }
246
247 /****************
248  * This function returns a string which is suitable for printing
249  * Caller must release it with m_free()
250  */
251 char *
252 make_printable_string( const byte *p, size_t n, int delim )
253 {
254     size_t save_n, buflen;
255     const byte *save_p;
256     char *buffer, *d;
257
258     /* first count length */
259     for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) {
260         if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
261             (delim && *p=='\\')) {
262             if( *p=='\n' || *p=='\r' || *p=='\f'
263                 || *p=='\v' || *p=='\b' || !*p )
264                 buflen += 2;
265             else
266                 buflen += 4;
267         }
268         else
269             buflen++;
270     }
271     p = save_p;
272     n = save_n;
273     /* and now make the string */
274     d = buffer = m_alloc( buflen );
275     for( ; n; n--, p++ ) {
276         if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
277             (delim && *p=='\\')) {
278             *d++ = '\\';
279             if( *p == '\n' )
280                 *d++ = 'n';
281             else if( *p == '\r' )
282                 *d++ = 'r';
283             else if( *p == '\f' )
284                 *d++ = 'f';
285             else if( *p == '\v' )
286                 *d++ = 'v';
287             else if( *p == '\b' )
288                 *d++ = 'b';
289             else if( !*p )
290                 *d++ = '0';
291             else {
292                 sprintf(d, "x%02x", *p );
293                 d += 2;
294             }
295         }
296         else
297             *d++ = *p;
298     }
299     *d = 0;
300     return buffer;
301 }
302
303 int
304 answer_is_yes_no_default( const char *s, int def_answer )
305 {
306     /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
307     const char *long_yes = _("yes");
308     const char *short_yes = _("yY");
309     /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
310     const char *long_no = _("no");
311     const char *short_no = _("nN");
312
313     /* Note: we have to use the local dependent strcasecmp here */
314     if( match_multistr(long_yes,s) )
315         return 1;
316     if( *s && strchr( short_yes, *s ) && !s[1] )
317         return 1;
318     /* test for no strings to catch ambiguities for the next test */
319     if( match_multistr(long_no,s) )
320         return 0;
321     if( *s && strchr( short_no, *s ) && !s[1] )
322         return 0;
323     /* test for the english version (for those who are used to type yes) */
324     if( !ascii_strcasecmp(s, "yes" ) )
325         return 1;
326     if( *s && strchr( "yY", *s ) && !s[1] )
327         return 1;
328     return def_answer;
329 }
330
331 int
332 answer_is_yes( const char *s )
333 {
334   return answer_is_yes_no_default(s,0);
335 }
336
337 /****************
338  * Return 1 for yes, -1 for quit, or 0 for no
339  */
340 int
341 answer_is_yes_no_quit( const char *s )
342 {
343     /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
344     const char *long_yes = _("yes");
345     /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
346     const char *long_no = _("no");
347     /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
348     const char *long_quit = _("quit");
349     const char *short_yes = _("yY");
350     const char *short_no = _("nN");
351     const char *short_quit = _("qQ");
352
353     if( match_multistr(long_no,s) )
354         return 0;
355     if( match_multistr(long_yes,s) )
356         return 1;
357     if( match_multistr(long_quit,s) )
358         return -1;
359     if( *s && strchr( short_no, *s ) && !s[1] )
360         return 0;
361     if( *s && strchr( short_yes, *s ) && !s[1] )
362         return 1;
363     if( *s && strchr( short_quit, *s ) && !s[1] )
364         return -1;
365     /* but not here */
366     if( !ascii_strcasecmp(s, "yes" ) )
367         return 1;
368     if( !ascii_strcasecmp(s, "quit" ) )
369         return -1;
370     if( *s && strchr( "yY", *s ) && !s[1] )
371         return 1;
372     if( *s && strchr( "qQ", *s ) && !s[1] )
373         return -1;
374     return 0;
375 }
376
377 /*
378    Return 1 for okay, 0 for for cancel or DEF_ANSWER for default. 
379  */
380 int
381 answer_is_okay_cancel (const char *s, int def_answer)
382 {
383   /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
384   const char *long_okay = _("okay|okay");
385   /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
386   const char *long_cancel = _("cancel|cancel");
387   const char *short_okay = _("oO");
388   const char *short_cancel = _("cC");
389   
390   /* Note: We have to use the locale dependent strcasecmp */
391   if ( match_multistr(long_okay,s) )
392     return 1;
393   if ( match_multistr(long_cancel,s) )
394     return 0;
395   if ( *s && strchr( short_okay, *s ) && !s[1] )
396     return 1;
397   if ( *s && strchr( short_cancel, *s ) && !s[1] )
398     return 0;
399   /* Always test for the English values (not locale here) */
400   if ( !ascii_strcasecmp(s, "okay" ) )
401     return 1;
402   if ( !ascii_strcasecmp(s, "ok" ) )
403     return 1;
404   if ( !ascii_strcasecmp(s, "cancel" ) )
405     return 0;
406   if ( *s && strchr( "oO", *s ) && !s[1] )
407     return 1;
408   if ( *s && strchr( "cC", *s ) && !s[1] )
409     return 0;
410   return def_answer;
411 }
412
413 /* Try match against each substring of multistr, delimited by | */
414 int
415 match_multistr(const char *multistr,const char *match)
416 {
417   do
418     {
419       size_t seglen=strcspn(multistr,"|");
420       if(!seglen)
421         break;
422       /* Using the localized strncasecmp */
423       if(strncasecmp(multistr,match,seglen)==0)
424         return 1;
425       multistr+=seglen;
426       if(*multistr=='|')
427         multistr++;
428     }
429   while(*multistr);
430
431   return 0;
432 }
433
434 int
435 hextobyte( const char *s )
436 {
437     int c;
438
439     if( *s >= '0' && *s <= '9' )
440         c = 16 * (*s - '0');
441     else if( *s >= 'A' && *s <= 'F' )
442         c = 16 * (10 + *s - 'A');
443     else if( *s >= 'a' && *s <= 'f' )
444         c = 16 * (10 + *s - 'a');
445     else
446         return -1;
447     s++;
448     if( *s >= '0' && *s <= '9' )
449         c += *s - '0';
450     else if( *s >= 'A' && *s <= 'F' )
451         c += 10 + *s - 'A';
452     else if( *s >= 'a' && *s <= 'f' )
453         c += 10 + *s - 'a';
454     else
455         return -1;
456     return c;
457 }