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