Marked all unused args on non-W32 platforms.
[gnupg.git] / common / gettime.c
1 /* gettime.c - Wrapper for time functions
2  *      Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <ctype.h>
24 #ifdef HAVE_LANGINFO_H
25 #include <langinfo.h>
26 #endif
27
28 #include "util.h"
29
30 static unsigned long timewarp;
31 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
32
33 /* Correction used to map to real Julian days. */
34 #define JD_DIFF 1721060L
35
36
37 /* Wrapper for the time(3).  We use this here so we can fake the time
38    for tests */
39 time_t 
40 gnupg_get_time () 
41 {
42   time_t current = time (NULL);
43   if (timemode == NORMAL)
44     return current;
45   else if (timemode == FROZEN)
46     return timewarp;
47   else if (timemode == FUTURE)
48     return current + timewarp;
49   else
50     return current - timewarp;
51 }
52
53
54 /* Return the current time (possibly faked) in ISO format. */
55 void
56 gnupg_get_isotime (gnupg_isotime_t timebuf)
57 {
58   time_t atime = gnupg_get_time ();
59     
60   if (atime < 0)
61     *timebuf = 0;
62   else 
63     {
64       struct tm *tp;
65 #ifdef HAVE_GMTIME_R
66       struct tm tmbuf;
67       
68       tp = gmtime_r (&atime, &tmbuf);
69 #else
70       tp = gmtime (&atime);
71 #endif
72       snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
73                 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
74                 tp->tm_hour, tp->tm_min, tp->tm_sec);
75     }
76 }
77
78
79 /* Set the time to NEWTIME so that gnupg_get_time returns a time
80    starting with this one.  With FREEZE set to 1 the returned time
81    will never change.  Just for completeness, a value of (time_t)-1
82    for NEWTIME gets you back to reality.  Note that this is obviously
83    not thread-safe but this is not required. */
84 void
85 gnupg_set_time (time_t newtime, int freeze)
86 {
87   time_t current = time (NULL);
88
89   if ( newtime == (time_t)-1 || current == newtime)
90     {
91       timemode = NORMAL;
92       timewarp = 0;
93     }
94   else if (freeze)
95     {
96       timemode = FROZEN;
97       timewarp = current;
98     }
99   else if (newtime > current)
100     {
101       timemode = FUTURE;
102       timewarp = newtime - current;
103     }
104   else
105     {
106       timemode = PAST;
107       timewarp = current - newtime;
108     }
109 }
110
111 /* Returns true when we are in timewarp mode */
112 int
113 gnupg_faked_time_p (void)
114 {
115   return timemode;
116 }
117
118
119 /* This function is used by gpg because OpenPGP defines the timestamp
120    as an unsigned 32 bit value. */
121 u32 
122 make_timestamp (void)
123 {
124   time_t t = gnupg_get_time ();
125
126   if (t == (time_t)-1)
127     log_fatal ("gnupg_get_time() failed\n");
128   return (u32)t;
129 }
130
131
132
133 /****************
134  * Scan a date string and return a timestamp.
135  * The only supported format is "yyyy-mm-dd"
136  * Returns 0 for an invalid date.
137  */
138 u32
139 scan_isodatestr( const char *string )
140 {
141     int year, month, day;
142     struct tm tmbuf;
143     time_t stamp;
144     int i;
145
146     if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
147         return 0;
148     for( i=0; i < 4; i++ )
149         if( !digitp (string+i) )
150             return 0;
151     if( !digitp (string+5) || !digitp(string+6) )
152         return 0;
153     if( !digitp(string+8) || !digitp(string+9) )
154         return 0;
155     year = atoi(string);
156     month = atoi(string+5);
157     day = atoi(string+8);
158     /* some basic checks */
159     if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
160         return 0;
161     memset( &tmbuf, 0, sizeof tmbuf );
162     tmbuf.tm_mday = day;
163     tmbuf.tm_mon = month-1;
164     tmbuf.tm_year = year - 1900;
165     tmbuf.tm_isdst = -1;
166     stamp = mktime( &tmbuf );
167     if( stamp == (time_t)-1 )
168         return 0;
169     return stamp;
170 }
171
172 /* Scan am ISO timestamp and return an Epoch based timestamp.  The only
173    supported format is "yyyymmddThhmmss" delimited by white space, nul, a
174    colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
175 time_t
176 isotime2epoch (const char *string)
177 {
178   const char *s;
179   int year, month, day, hour, minu, sec;
180   struct tm tmbuf;
181   int i;
182
183   if (!*string)
184     return (time_t)(-1);
185   for (s=string, i=0; i < 8; i++, s++)
186     if (!digitp (s))
187       return (time_t)(-1);
188   if (*s != 'T')
189       return (time_t)(-1);
190   for (s++, i=9; i < 15; i++, s++)
191     if (!digitp (s))
192       return (time_t)(-1);
193   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
194     return (time_t)(-1);  /* Wrong delimiter.  */
195
196   year  = atoi_4 (string);
197   month = atoi_2 (string + 4);
198   day   = atoi_2 (string + 6);
199   hour  = atoi_2 (string + 9);
200   minu  = atoi_2 (string + 11);
201   sec   = atoi_2 (string + 13);
202
203   /* Basic checks.  */
204   if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
205       || hour > 23 || minu > 59 || sec > 61 )
206     return (time_t)(-1);
207
208   memset (&tmbuf, 0, sizeof tmbuf);
209   tmbuf.tm_sec  = sec;
210   tmbuf.tm_min  = minu;
211   tmbuf.tm_hour = hour;
212   tmbuf.tm_mday = day;
213   tmbuf.tm_mon  = month-1;
214   tmbuf.tm_year = year - 1900;
215   tmbuf.tm_isdst = -1;
216   return timegm (&tmbuf);
217 }
218
219
220 /* Convert an Epoch time to an iso time stamp. */
221 void
222 epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
223 {
224   if (atime < 0)
225     *timebuf = 0;
226   else 
227     {
228       struct tm *tp;
229 #ifdef HAVE_GMTIME_R
230       struct tm tmbuf;
231       
232       tp = gmtime_r (&atime, &tmbuf);
233 #else
234       tp = gmtime (&atime);
235 #endif
236       snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
237                 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
238                 tp->tm_hour, tp->tm_min, tp->tm_sec);
239     }
240 }
241
242
243
244
245 u32
246 add_days_to_timestamp( u32 stamp, u16 days )
247 {
248     return stamp + days*86400L;
249 }
250
251
252 /****************
253  * Return a string with a time value in the form: x Y, n D, n H
254  */
255
256 const char *
257 strtimevalue( u32 value )
258 {
259     static char buffer[30];
260     unsigned int years, days, hours, minutes;
261
262     value /= 60;
263     minutes = value % 60;
264     value /= 60;
265     hours = value % 24;
266     value /= 24;
267     days = value % 365;
268     value /= 365;
269     years = value;
270
271     sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
272     if( years )
273         return buffer;
274     if( days )
275         return strchr( buffer, 'y' ) + 1;
276     return strchr( buffer, 'd' ) + 1;
277 }
278
279
280 /*
281  * Note: this function returns GMT
282  */
283 const char *
284 strtimestamp( u32 stamp )
285 {
286     static char buffer[11+5];
287     struct tm *tp;
288     time_t atime = stamp;
289     
290     if (atime < 0) {
291         strcpy (buffer, "????" "-??" "-??");
292     }
293     else {
294         tp = gmtime( &atime );
295         sprintf(buffer,"%04d-%02d-%02d",
296                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
297     }
298     return buffer;
299 }
300
301
302 /*
303  * Note: this function returns GMT
304  */
305 const char *
306 isotimestamp (u32 stamp)
307 {
308   static char buffer[25+5];
309   struct tm *tp;
310   time_t atime = stamp;
311   
312   if (atime < 0)
313     {
314       strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
315     }
316   else
317     {
318       tp = gmtime ( &atime );
319       sprintf (buffer,"%04d-%02d-%02d %02d:%02d:%02d",
320                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
321                tp->tm_hour, tp->tm_min, tp->tm_sec);
322     }
323   return buffer;
324 }
325
326
327 /****************
328  * Note: this function returns local time
329  */
330 const char *
331 asctimestamp( u32 stamp )
332 {
333     static char buffer[50];
334 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
335       static char fmt[50];
336 #endif
337     struct tm *tp;
338     time_t atime = stamp;
339
340     if (atime < 0) {
341         strcpy (buffer, "????" "-??" "-??");
342         return buffer;
343     }
344
345     tp = localtime( &atime );
346 #ifdef HAVE_STRFTIME
347 #if defined(HAVE_NL_LANGINFO)
348       mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
349       if( strstr( fmt, "%Z" ) == NULL )
350         strcat( fmt, " %Z");
351       /* NOTE: gcc -Wformat-noliteral will complain here.  I have
352          found no way to suppress this warning .*/
353       strftime (buffer, DIM(buffer)-1, fmt, tp);
354 #else
355       /* FIXME: we should check whether the locale appends a " %Z"
356        * These locales from glibc don't put the " %Z":
357        * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN
358        */
359       strftime( buffer, DIM(buffer)-1, "%c %Z", tp );
360 #endif
361     buffer[DIM(buffer)-1] = 0;
362 #else
363     mem2str( buffer, asctime(tp), DIM(buffer) );
364 #endif
365     return buffer;
366 }
367
368
369
370 static int
371 days_per_year (int y)
372 {
373   int s ;
374
375   s = !(y % 4);
376   if ( !(y % 100))
377     if ((y%400))
378       s = 0;
379   return s ? 366 : 365;
380 }
381
382 static int
383 days_per_month (int y, int m)
384 {
385   int s;
386     
387   switch(m)
388     {
389     case 1: case 3: case 5: case 7: case 8: case 10: case 12:
390       return 31 ;
391     case 2:
392       s = !(y % 4);
393       if (!(y % 100))
394         if ((y % 400))
395           s = 0;
396       return s? 29 : 28 ;
397     case 4: case 6: case 9: case 11:
398       return 30;
399     }
400   BUG();
401 }
402
403
404 /* Convert YEAR, MONTH and DAY into the Julian date.  We assume that
405    it is already noon.  We do not support dates before 1582-10-15. */
406 static unsigned long
407 date2jd (int year, int month, int day)
408 {
409   unsigned long jd;
410
411   jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
412   if (month < 3)
413     year-- ;
414   else
415     jd -= (4 * month + 23) / 10;
416
417   jd += year / 4 - ((year / 100 + 1) *3) / 4;
418
419   return jd ;
420 }
421
422 /* Convert a Julian date back to YEAR, MONTH and DAY.  Return day of
423    the year or 0 on error.  This function uses some more or less
424    arbitrary limits, most important is that days before 1582 are not
425    supported. */
426 static int
427 jd2date (unsigned long jd, int *year, int *month, int *day)
428 {
429   int y, m, d;
430   long delta;
431
432   if (!jd)
433     return 0 ;
434   if (jd < 1721425 || jd > 2843085)
435     return 0;
436
437   y = (jd - JD_DIFF) / 366;
438   d = m = 1;
439
440   while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
441     y++;
442
443   m = (delta / 31) + 1;
444   while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
445     if (++m > 12)
446       { 
447         m = 1;
448         y++;
449       }
450
451   d = delta + 1 ;
452   if (d > days_per_month (y, m))
453     { 
454       d = 1;
455       m++;
456     }
457   if (m > 12)
458     { 
459       m = 1;
460       y++;
461     }
462
463   if (year)
464     *year = y;
465   if (month)
466     *month = m;
467   if (day)
468     *day = d ;
469
470   return (jd - date2jd (y, 1, 1)) + 1;
471 }
472
473
474 /* Check that the 15 bytes in ATIME represent a valid ISO time.  Note
475    that this function does not expect a string but a plain 15 byte
476    isotime buffer. */
477 gpg_error_t
478 check_isotime (const gnupg_isotime_t atime)
479 {
480   int i;
481   const char *s;
482
483   if (!*atime)
484     return gpg_error (GPG_ERR_NO_VALUE);
485   
486   for (s=atime, i=0; i < 8; i++, s++)
487     if (!digitp (s))
488       return gpg_error (GPG_ERR_INV_TIME);
489   if (*s != 'T')
490       return gpg_error (GPG_ERR_INV_TIME);
491   for (s++, i=9; i < 15; i++, s++)
492     if (!digitp (s))
493       return gpg_error (GPG_ERR_INV_TIME);
494   return 0;
495 }
496
497
498
499 /* Add SECONDS to ATIME.  SECONDS may not be negative and is limited
500    to about the equivalent of 62 years which should be more then
501    enough for our purposes. */
502 gpg_error_t
503 add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
504 {
505   gpg_error_t err;
506   int year, month, day, hour, minute, sec, ndays;
507   unsigned long jd;
508
509   err = check_isotime (atime);
510   if (err)
511     return err;
512
513   if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
514     return gpg_error (GPG_ERR_INV_VALUE);
515
516   year  = atoi_4 (atime+0);
517   month = atoi_2 (atime+4);
518   day   = atoi_2 (atime+6);
519   hour  = atoi_2 (atime+9);
520   minute= atoi_2 (atime+11);
521   sec   = atoi_2 (atime+13);
522
523   if (year <= 1582) /* The julian date functions don't support this. */
524     return gpg_error (GPG_ERR_INV_VALUE); 
525
526   sec    += nseconds;
527   minute += sec/60;
528   sec    %= 60;
529   hour   += minute/60;
530   minute %= 60;
531   ndays  = hour/24;
532   hour   %= 24;
533   
534   jd = date2jd (year, month, day) + ndays;
535   jd2date (jd, &year, &month, &day);
536
537   if (year > 9999 || month > 12 || day > 31
538       || year < 0 || month < 1 || day < 1)
539     return gpg_error (GPG_ERR_INV_VALUE); 
540     
541   snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
542             year, month, day, hour, minute, sec);
543   return 0;
544 }
545
546
547 gpg_error_t
548 add_days_to_isotime (gnupg_isotime_t atime, int ndays)
549 {
550   gpg_error_t err;
551   int year, month, day, hour, minute, sec;
552   unsigned long jd;
553
554   err = check_isotime (atime);
555   if (err)
556     return err;
557
558   if (ndays < 0 || ndays >= 9999*366 )
559     return gpg_error (GPG_ERR_INV_VALUE);
560
561   year  = atoi_4 (atime+0);
562   month = atoi_2 (atime+4);
563   day   = atoi_2 (atime+6);
564   hour  = atoi_2 (atime+9);
565   minute= atoi_2 (atime+11);
566   sec   = atoi_2 (atime+13);
567
568   if (year <= 1582) /* The julian date functions don't support this. */
569     return gpg_error (GPG_ERR_INV_VALUE); 
570
571   jd = date2jd (year, month, day) + ndays;
572   jd2date (jd, &year, &month, &day);
573
574   if (year > 9999 || month > 12 || day > 31
575       || year < 0 || month < 1 || day < 1)
576     return gpg_error (GPG_ERR_INV_VALUE); 
577     
578   snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
579             year, month, day, hour, minute, sec);
580   return 0;
581 }