Line data Source code
1 : /* gettime.c - Wrapper for time functions
2 : * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * This file is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * This file is distributed in the hope that it will be useful,
22 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 : * GNU General Public License for more details.
25 : *
26 : * You should have received a copy of the GNU General Public License
27 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 : */
29 :
30 : #include <config.h>
31 : #include <stdlib.h>
32 : #include <time.h>
33 : #include <ctype.h>
34 : #ifdef HAVE_LANGINFO_H
35 : #include <langinfo.h>
36 : #endif
37 :
38 : #include "util.h"
39 : #include "i18n.h"
40 : #include "gettime.h"
41 :
42 : #ifdef HAVE_UNSIGNED_TIME_T
43 : # define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
44 : #else
45 : /* Error or 32 bit time_t and value after 2038-01-19. */
46 : # define IS_INVALID_TIME_T(a) ((a) < 0)
47 : #endif
48 :
49 :
50 : static unsigned long timewarp;
51 : static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
52 :
53 : /* Correction used to map to real Julian days. */
54 : #define JD_DIFF 1721060L
55 :
56 :
57 : /* Wrapper for the time(3). We use this here so we can fake the time
58 : for tests */
59 : time_t
60 13080 : gnupg_get_time ()
61 : {
62 13080 : time_t current = time (NULL);
63 13080 : if (timemode == NORMAL)
64 13074 : return current;
65 6 : else if (timemode == FROZEN)
66 0 : return timewarp;
67 6 : else if (timemode == FUTURE)
68 0 : return current + timewarp;
69 : else
70 6 : return current - timewarp;
71 : }
72 :
73 :
74 : /* Wrapper around gmtime_r.
75 :
76 : On systems without gmtime_r this implementation works within gnupg
77 : because we use only one thread a time. FIXME: An independent
78 : library may use gmtime in one of its own thread (or via
79 : npth_enter/npth_leave) - in this case we run into a problem. The
80 : solution would be to use a mutex here. */
81 : struct tm *
82 14 : gnupg_gmtime (const time_t *timep, struct tm *result)
83 : {
84 : #ifdef HAVE_GMTIME_R
85 14 : return gmtime_r (timep, result);
86 : #else
87 : struct tm *tp;
88 :
89 : tp = gmtime (timep);
90 : if (tp)
91 : memcpy (result, tp, sizeof *result);
92 : return tp;
93 : #endif
94 : }
95 :
96 :
97 : /* Return the current time (possibly faked) in ISO format. */
98 : void
99 14 : gnupg_get_isotime (gnupg_isotime_t timebuf)
100 : {
101 14 : time_t atime = gnupg_get_time ();
102 :
103 14 : if (atime == (time_t)(-1))
104 0 : *timebuf = 0;
105 : else
106 : {
107 : struct tm *tp;
108 : struct tm tmbuf;
109 :
110 14 : tp = gnupg_gmtime (&atime, &tmbuf);
111 14 : if (!tp)
112 0 : *timebuf = 0;
113 : else
114 42 : snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
115 28 : 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
116 : tp->tm_hour, tp->tm_min, tp->tm_sec);
117 : }
118 14 : }
119 :
120 :
121 : /* Set the time to NEWTIME so that gnupg_get_time returns a time
122 : starting with this one. With FREEZE set to 1 the returned time
123 : will never change. Just for completeness, a value of (time_t)-1
124 : for NEWTIME gets you back to reality. Note that this is obviously
125 : not thread-safe but this is not required. */
126 : void
127 3 : gnupg_set_time (time_t newtime, int freeze)
128 : {
129 3 : time_t current = time (NULL);
130 :
131 3 : if ( newtime == (time_t)-1 || current == newtime)
132 : {
133 0 : timemode = NORMAL;
134 0 : timewarp = 0;
135 : }
136 3 : else if (freeze)
137 : {
138 0 : timemode = FROZEN;
139 0 : timewarp = current;
140 : }
141 3 : else if (newtime > current)
142 : {
143 0 : timemode = FUTURE;
144 0 : timewarp = newtime - current;
145 : }
146 : else
147 : {
148 3 : timemode = PAST;
149 3 : timewarp = current - newtime;
150 : }
151 3 : }
152 :
153 : /* Returns true when we are in timewarp mode */
154 : int
155 1279 : gnupg_faked_time_p (void)
156 : {
157 1279 : return timemode;
158 : }
159 :
160 :
161 : /* This function is used by gpg because OpenPGP defines the timestamp
162 : as an unsigned 32 bit value. */
163 : u32
164 12719 : make_timestamp (void)
165 : {
166 12719 : time_t t = gnupg_get_time ();
167 :
168 12719 : if (t == (time_t)-1)
169 0 : log_fatal ("gnupg_get_time() failed\n");
170 12719 : return (u32)t;
171 : }
172 :
173 :
174 :
175 : /****************
176 : * Scan a date string and return a timestamp.
177 : * The only supported format is "yyyy-mm-dd"
178 : * Returns 0 for an invalid date.
179 : */
180 : u32
181 117 : scan_isodatestr( const char *string )
182 : {
183 : int year, month, day;
184 : struct tm tmbuf;
185 : time_t stamp;
186 : int i;
187 :
188 117 : if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
189 117 : return 0;
190 0 : for( i=0; i < 4; i++ )
191 0 : if( !digitp (string+i) )
192 0 : return 0;
193 0 : if( !digitp (string+5) || !digitp(string+6) )
194 0 : return 0;
195 0 : if( !digitp(string+8) || !digitp(string+9) )
196 0 : return 0;
197 0 : year = atoi(string);
198 0 : month = atoi(string+5);
199 0 : day = atoi(string+8);
200 : /* some basic checks */
201 0 : if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
202 0 : return 0;
203 0 : memset( &tmbuf, 0, sizeof tmbuf );
204 0 : tmbuf.tm_mday = day;
205 0 : tmbuf.tm_mon = month-1;
206 0 : tmbuf.tm_year = year - 1900;
207 0 : tmbuf.tm_isdst = -1;
208 0 : stamp = mktime( &tmbuf );
209 0 : if( stamp == (time_t)-1 )
210 0 : return 0;
211 0 : return stamp;
212 : }
213 :
214 :
215 : int
216 179 : isotime_p (const char *string)
217 : {
218 : const char *s;
219 : int i;
220 :
221 179 : if (!*string)
222 2 : return 0;
223 661 : for (s=string, i=0; i < 8; i++, s++)
224 628 : if (!digitp (s))
225 144 : return 0;
226 33 : if (*s != 'T')
227 5 : return 0;
228 194 : for (s++, i=9; i < 15; i++, s++)
229 168 : if (!digitp (s))
230 2 : return 0;
231 26 : if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
232 2 : return 0; /* Wrong delimiter. */
233 :
234 24 : return 1;
235 : }
236 :
237 :
238 : /* Scan a string and return true if the string represents the human
239 : readable format of an ISO time. This format is:
240 : yyyy-mm-dd[ hh[:mm[:ss]]]
241 : Scanning stops at the second space or at a comma. If DATE_ONLY is
242 : true the time part is not expected and the scanning stops at the
243 : first space or at a comma. */
244 : int
245 57 : isotime_human_p (const char *string, int date_only)
246 : {
247 : const char *s;
248 : int i;
249 :
250 57 : if (!*string)
251 2 : return 0;
252 269 : for (s=string, i=0; i < 4; i++, s++)
253 217 : if (!digitp (s))
254 3 : return 0;
255 52 : if (*s != '-')
256 6 : return 0;
257 46 : s++;
258 46 : if (!digitp (s) || !digitp (s+1) || s[2] != '-')
259 4 : return 0;
260 42 : i = atoi_2 (s);
261 42 : if (i < 1 || i > 12)
262 5 : return 0;
263 37 : s += 3;
264 37 : if (!digitp (s) || !digitp (s+1))
265 3 : return 0;
266 34 : i = atoi_2 (s);
267 34 : if (i < 1 || i > 31)
268 4 : return 0;
269 30 : s += 2;
270 30 : if (!*s || *s == ',')
271 11 : return 1; /* Okay; only date given. */
272 19 : if (!spacep (s))
273 4 : return 0;
274 15 : if (date_only)
275 3 : return 1; /* Okay; only date was requested. */
276 12 : s++;
277 12 : if (spacep (s))
278 1 : return 1; /* Okay, second space stops scanning. */
279 11 : if (!digitp (s) || !digitp (s+1))
280 0 : return 0;
281 11 : i = atoi_2 (s);
282 11 : if (i < 0 || i > 23)
283 1 : return 0;
284 10 : s += 2;
285 10 : if (!*s || *s == ',')
286 3 : return 1; /* Okay; only date and hour given. */
287 7 : if (*s != ':')
288 0 : return 0;
289 7 : s++;
290 7 : if (!digitp (s) || !digitp (s+1))
291 2 : return 0;
292 5 : i = atoi_2 (s);
293 5 : if (i < 0 || i > 59)
294 0 : return 0;
295 5 : s += 2;
296 5 : if (!*s || *s == ',')
297 1 : return 1; /* Okay; only date, hour and minute given. */
298 4 : if (*s != ':')
299 0 : return 0;
300 4 : s++;
301 4 : if (!digitp (s) || !digitp (s+1))
302 0 : return 0;
303 4 : i = atoi_2 (s);
304 4 : if (i < 0 || i > 60)
305 0 : return 0;
306 4 : s += 2;
307 4 : if (!*s || *s == ',' || spacep (s))
308 3 : return 1; /* Okay; date, hour and minute and second given. */
309 :
310 1 : return 0; /* Unexpected delimiter. */
311 : }
312 :
313 : /* Convert a standard isotime or a human readable variant into an
314 : isotime structure. The allowed formats are those described by
315 : isotime_p and isotime_human_p. The function returns 0 on failure
316 : or the length of the scanned string on success. */
317 : size_t
318 43 : string2isotime (gnupg_isotime_t atime, const char *string)
319 : {
320 : gnupg_isotime_t dummyatime;
321 :
322 43 : if (!atime)
323 0 : atime = dummyatime;
324 :
325 43 : atime[0] = 0;
326 43 : if (isotime_p (string))
327 : {
328 12 : memcpy (atime, string, 15);
329 12 : atime[15] = 0;
330 12 : return 15;
331 : }
332 31 : if (!isotime_human_p (string, 0))
333 21 : return 0;
334 10 : atime[0] = string[0];
335 10 : atime[1] = string[1];
336 10 : atime[2] = string[2];
337 10 : atime[3] = string[3];
338 10 : atime[4] = string[5];
339 10 : atime[5] = string[6];
340 10 : atime[6] = string[8];
341 10 : atime[7] = string[9];
342 10 : atime[8] = 'T';
343 10 : memset (atime+9, '0', 6);
344 10 : atime[15] = 0;
345 10 : if (!spacep (string+10))
346 2 : return 10;
347 8 : if (spacep (string+11))
348 1 : return 11; /* As per def, second space stops scanning. */
349 7 : atime[9] = string[11];
350 7 : atime[10] = string[12];
351 7 : if (string[13] != ':')
352 3 : return 13;
353 4 : atime[11] = string[14];
354 4 : atime[12] = string[15];
355 4 : if (string[16] != ':')
356 1 : return 16;
357 3 : atime[13] = string[17];
358 3 : atime[14] = string[18];
359 3 : return 19;
360 : }
361 :
362 :
363 : /* Scan an ISO timestamp and return an Epoch based timestamp. The only
364 : supported format is "yyyymmddThhmmss" delimited by white space, nul, a
365 : colon or a comma. Returns (time_t)(-1) for an invalid string. */
366 : time_t
367 136 : isotime2epoch (const char *string)
368 : {
369 : int year, month, day, hour, minu, sec;
370 : struct tm tmbuf;
371 :
372 136 : if (!isotime_p (string))
373 124 : return (time_t)(-1);
374 :
375 12 : year = atoi_4 (string);
376 12 : month = atoi_2 (string + 4);
377 12 : day = atoi_2 (string + 6);
378 12 : hour = atoi_2 (string + 9);
379 12 : minu = atoi_2 (string + 11);
380 12 : sec = atoi_2 (string + 13);
381 :
382 : /* Basic checks. */
383 12 : if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
384 10 : || hour > 23 || minu > 59 || sec > 61 )
385 2 : return (time_t)(-1);
386 :
387 10 : memset (&tmbuf, 0, sizeof tmbuf);
388 10 : tmbuf.tm_sec = sec;
389 10 : tmbuf.tm_min = minu;
390 10 : tmbuf.tm_hour = hour;
391 10 : tmbuf.tm_mday = day;
392 10 : tmbuf.tm_mon = month-1;
393 10 : tmbuf.tm_year = year - 1900;
394 10 : tmbuf.tm_isdst = -1;
395 10 : return timegm (&tmbuf);
396 : }
397 :
398 :
399 : /* Convert an Epoch time to an iso time stamp. */
400 : void
401 10 : epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
402 : {
403 10 : if (atime == (time_t)(-1))
404 0 : *timebuf = 0;
405 : else
406 : {
407 : struct tm *tp;
408 : #ifdef HAVE_GMTIME_R
409 : struct tm tmbuf;
410 :
411 10 : tp = gmtime_r (&atime, &tmbuf);
412 : #else
413 : tp = gmtime (&atime);
414 : #endif
415 30 : snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
416 20 : 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
417 : tp->tm_hour, tp->tm_min, tp->tm_sec);
418 : }
419 10 : }
420 :
421 :
422 : /* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
423 : Returns 0 on success. */
424 : int
425 26 : isodate_human_to_tm (const char *string, struct tm *t)
426 : {
427 : int year, month, day;
428 :
429 26 : if (!isotime_human_p (string, 1))
430 14 : return -1;
431 :
432 12 : year = atoi_4 (string);
433 12 : month = atoi_2 (string + 5);
434 12 : day = atoi_2 (string + 8);
435 :
436 : /* Basic checks. */
437 12 : if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
438 2 : return -1;
439 :
440 10 : memset (t, 0, sizeof *t);
441 10 : t->tm_sec = 0;
442 10 : t->tm_min = 0;
443 10 : t->tm_hour = 0;
444 10 : t->tm_mday = day;
445 10 : t->tm_mon = month-1;
446 10 : t->tm_year = year - 1900;
447 10 : t->tm_isdst = -1;
448 10 : return 0;
449 : }
450 :
451 :
452 : /* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
453 : If you change it, then update the other one too. */
454 : #ifdef HAVE_W32_SYSTEM
455 : static time_t
456 : _win32_timegm (struct tm *tm)
457 : {
458 : /* This one is thread safe. */
459 : SYSTEMTIME st;
460 : FILETIME ft;
461 : unsigned long long cnsecs;
462 :
463 : st.wYear = tm->tm_year + 1900;
464 : st.wMonth = tm->tm_mon + 1;
465 : st.wDay = tm->tm_mday;
466 : st.wHour = tm->tm_hour;
467 : st.wMinute = tm->tm_min;
468 : st.wSecond = tm->tm_sec;
469 : st.wMilliseconds = 0; /* Not available. */
470 : st.wDayOfWeek = 0; /* Ignored. */
471 :
472 : /* System time is UTC thus the conversion is pretty easy. */
473 : if (!SystemTimeToFileTime (&st, &ft))
474 : {
475 : gpg_err_set_errno (EINVAL);
476 : return (time_t)(-1);
477 : }
478 :
479 : cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
480 : | ft.dwLowDateTime);
481 : cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
482 : return (time_t)(cnsecs / 10000000ULL);
483 : }
484 : #endif
485 :
486 :
487 : /* Parse the string TIMESTAMP into a time_t. The string may either be
488 : seconds since Epoch or in the ISO 8601 format like
489 : "20390815T143012". Returns 0 for an empty string or seconds since
490 : Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
491 : point to the next non-parsed character in TIMESTRING.
492 :
493 : This function is a copy of
494 : gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
495 : then update the other one too. */
496 : time_t
497 0 : parse_timestamp (const char *timestamp, char **endp)
498 : {
499 : /* Need to skip leading spaces, because that is what strtoul does
500 : but not our ISO 8601 checking code. */
501 0 : while (*timestamp && *timestamp== ' ')
502 0 : timestamp++;
503 0 : if (!*timestamp)
504 0 : return 0;
505 :
506 0 : if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
507 : {
508 : struct tm buf;
509 : int year;
510 :
511 0 : year = atoi_4 (timestamp);
512 0 : if (year < 1900)
513 0 : return (time_t)(-1);
514 :
515 0 : if (endp)
516 0 : *endp = (char*)(timestamp + 15);
517 :
518 : /* Fixme: We would better use a configure test to see whether
519 : mktime can handle dates beyond 2038. */
520 : if (sizeof (time_t) <= 4 && year >= 2038)
521 : return (time_t)2145914603; /* 2037-12-31 23:23:23 */
522 :
523 0 : memset (&buf, 0, sizeof buf);
524 0 : buf.tm_year = year - 1900;
525 0 : buf.tm_mon = atoi_2 (timestamp+4) - 1;
526 0 : buf.tm_mday = atoi_2 (timestamp+6);
527 0 : buf.tm_hour = atoi_2 (timestamp+9);
528 0 : buf.tm_min = atoi_2 (timestamp+11);
529 0 : buf.tm_sec = atoi_2 (timestamp+13);
530 :
531 : #ifdef HAVE_W32_SYSTEM
532 : return _win32_timegm (&buf);
533 : #else
534 : #ifdef HAVE_TIMEGM
535 0 : return timegm (&buf);
536 : #else
537 : {
538 : time_t tim;
539 :
540 : putenv ("TZ=UTC");
541 : tim = mktime (&buf);
542 : #ifdef __GNUC__
543 : #warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
544 : #endif
545 : return tim;
546 : }
547 : #endif /* !HAVE_TIMEGM */
548 : #endif /* !HAVE_W32_SYSTEM */
549 : }
550 : else
551 0 : return (time_t)strtoul (timestamp, endp, 10);
552 : }
553 :
554 :
555 :
556 : u32
557 0 : add_days_to_timestamp( u32 stamp, u16 days )
558 : {
559 0 : return stamp + days*86400L;
560 : }
561 :
562 :
563 : /****************
564 : * Return a string with a time value in the form: x Y, n D, n H
565 : */
566 :
567 : const char *
568 0 : strtimevalue( u32 value )
569 : {
570 : static char buffer[30];
571 : unsigned int years, days, hours, minutes;
572 :
573 0 : value /= 60;
574 0 : minutes = value % 60;
575 0 : value /= 60;
576 0 : hours = value % 24;
577 0 : value /= 24;
578 0 : days = value % 365;
579 0 : value /= 365;
580 0 : years = value;
581 :
582 0 : sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
583 0 : if( years )
584 0 : return buffer;
585 0 : if( days )
586 0 : return strchr( buffer, 'y' ) + 1;
587 0 : return strchr( buffer, 'd' ) + 1;
588 : }
589 :
590 :
591 :
592 : /* Return a malloced string with the time elapsed between NOW and
593 : SINCE. May return NULL on error. */
594 : char *
595 0 : elapsed_time_string (time_t since, time_t now)
596 : {
597 : char *result;
598 : double diff;
599 : unsigned long value;
600 : unsigned int days, hours, minutes, seconds;
601 :
602 0 : if (!now)
603 0 : now = gnupg_get_time ();
604 :
605 0 : diff = difftime (now, since);
606 0 : if (diff < 0)
607 0 : return xtrystrdup ("time-warp");
608 :
609 0 : seconds = (unsigned long)diff % 60;
610 0 : value = (unsigned long)(diff / 60);
611 0 : minutes = value % 60;
612 0 : value /= 60;
613 0 : hours = value % 24;
614 0 : value /= 24;
615 0 : days = value % 365;
616 :
617 0 : if (days)
618 0 : result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds);
619 0 : else if (hours)
620 0 : result = xtryasprintf ("%uh%um%us", hours, minutes, seconds);
621 0 : else if (minutes)
622 0 : result = xtryasprintf ("%um%us", minutes, seconds);
623 : else
624 0 : result = xtryasprintf ("%us", seconds);
625 :
626 0 : return result;
627 : }
628 :
629 :
630 : /*
631 : * Note: this function returns GMT
632 : */
633 : const char *
634 639 : strtimestamp (u32 stamp)
635 : {
636 : static char buffer[11+5];
637 : struct tm *tp;
638 639 : time_t atime = stamp;
639 :
640 639 : if (IS_INVALID_TIME_T (atime))
641 : {
642 0 : strcpy (buffer, "????" "-??" "-??");
643 : }
644 : else
645 : {
646 639 : tp = gmtime( &atime );
647 1917 : snprintf (buffer, sizeof buffer, "%04d-%02d-%02d",
648 1278 : 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
649 : }
650 639 : return buffer;
651 : }
652 :
653 :
654 : /*
655 : * Note: this function returns GMT
656 : */
657 : const char *
658 0 : isotimestamp (u32 stamp)
659 : {
660 : static char buffer[25+5];
661 : struct tm *tp;
662 0 : time_t atime = stamp;
663 :
664 0 : if (IS_INVALID_TIME_T (atime))
665 : {
666 0 : strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
667 : }
668 : else
669 : {
670 0 : tp = gmtime ( &atime );
671 0 : snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
672 0 : 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
673 : tp->tm_hour, tp->tm_min, tp->tm_sec);
674 : }
675 0 : return buffer;
676 : }
677 :
678 :
679 : /****************
680 : * Note: this function returns local time
681 : */
682 : const char *
683 147 : asctimestamp (u32 stamp)
684 : {
685 : static char buffer[50];
686 : #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
687 : static char fmt[50];
688 : #endif
689 : struct tm *tp;
690 147 : time_t atime = stamp;
691 :
692 147 : if (IS_INVALID_TIME_T (atime))
693 : {
694 0 : strcpy (buffer, "????" "-??" "-??");
695 0 : return buffer;
696 : }
697 :
698 147 : tp = localtime( &atime );
699 : #ifdef HAVE_STRFTIME
700 : # if defined(HAVE_NL_LANGINFO)
701 147 : mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
702 147 : if (!strstr( fmt, "%Z" ))
703 147 : strcat( fmt, " %Z");
704 : /* NOTE: gcc -Wformat-noliteral will complain here. I have found no
705 : way to suppress this warning. */
706 147 : strftime (buffer, DIM(buffer)-1, fmt, tp);
707 : # elif defined(HAVE_W32CE_SYSTEM)
708 : /* tzset is not available but %Z nevertheless prints a default
709 : nonsense timezone ("WILDABBR"). Thus we don't print the time
710 : zone at all. */
711 : strftime (buffer, DIM(buffer)-1, "%c", tp);
712 : # else
713 : /* FIXME: we should check whether the locale appends a " %Z" These
714 : * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
715 : * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN. */
716 : strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
717 : # endif
718 147 : buffer[DIM(buffer)-1] = 0;
719 : #else
720 : mem2str( buffer, asctime(tp), DIM(buffer) );
721 : #endif
722 147 : return buffer;
723 : }
724 :
725 :
726 :
727 : static int
728 0 : days_per_year (int y)
729 : {
730 : int s ;
731 :
732 0 : s = !(y % 4);
733 0 : if ( !(y % 100))
734 0 : if ((y%400))
735 0 : s = 0;
736 0 : return s ? 366 : 365;
737 : }
738 :
739 : static int
740 0 : days_per_month (int y, int m)
741 : {
742 : int s;
743 :
744 0 : switch(m)
745 : {
746 : case 1: case 3: case 5: case 7: case 8: case 10: case 12:
747 0 : return 31 ;
748 : case 2:
749 0 : s = !(y % 4);
750 0 : if (!(y % 100))
751 0 : if ((y % 400))
752 0 : s = 0;
753 0 : return s? 29 : 28 ;
754 : case 4: case 6: case 9: case 11:
755 0 : return 30;
756 : }
757 0 : BUG();
758 : }
759 :
760 :
761 : /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
762 : it is already noon. We do not support dates before 1582-10-15. */
763 : static unsigned long
764 0 : date2jd (int year, int month, int day)
765 : {
766 : unsigned long jd;
767 :
768 0 : jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
769 0 : if (month < 3)
770 0 : year-- ;
771 : else
772 0 : jd -= (4 * month + 23) / 10;
773 :
774 0 : jd += year / 4 - ((year / 100 + 1) *3) / 4;
775 :
776 0 : return jd ;
777 : }
778 :
779 : /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
780 : the year or 0 on error. This function uses some more or less
781 : arbitrary limits, most important is that days before 1582 are not
782 : supported. */
783 : static int
784 0 : jd2date (unsigned long jd, int *year, int *month, int *day)
785 : {
786 : int y, m, d;
787 : long delta;
788 :
789 0 : if (!jd)
790 0 : return 0 ;
791 0 : if (jd < 1721425 || jd > 2843085)
792 0 : return 0;
793 :
794 0 : y = (jd - JD_DIFF) / 366;
795 0 : d = m = 1;
796 :
797 0 : while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
798 0 : y++;
799 :
800 0 : m = (delta / 31) + 1;
801 0 : while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
802 0 : if (++m > 12)
803 : {
804 0 : m = 1;
805 0 : y++;
806 : }
807 :
808 0 : d = delta + 1 ;
809 0 : if (d > days_per_month (y, m))
810 : {
811 0 : d = 1;
812 0 : m++;
813 : }
814 0 : if (m > 12)
815 : {
816 0 : m = 1;
817 0 : y++;
818 : }
819 :
820 0 : if (year)
821 0 : *year = y;
822 0 : if (month)
823 0 : *month = m;
824 0 : if (day)
825 0 : *day = d ;
826 :
827 0 : return (jd - date2jd (y, 1, 1)) + 1;
828 : }
829 :
830 :
831 : /* Check that the 15 bytes in ATIME represent a valid ISO time. Note
832 : that this function does not expect a string but a plain 15 byte
833 : isotime buffer. */
834 : gpg_error_t
835 0 : check_isotime (const gnupg_isotime_t atime)
836 : {
837 : int i;
838 : const char *s;
839 :
840 0 : if (!*atime)
841 0 : return gpg_error (GPG_ERR_NO_VALUE);
842 :
843 0 : for (s=atime, i=0; i < 8; i++, s++)
844 0 : if (!digitp (s))
845 0 : return gpg_error (GPG_ERR_INV_TIME);
846 0 : if (*s != 'T')
847 0 : return gpg_error (GPG_ERR_INV_TIME);
848 0 : for (s++, i=9; i < 15; i++, s++)
849 0 : if (!digitp (s))
850 0 : return gpg_error (GPG_ERR_INV_TIME);
851 0 : return 0;
852 : }
853 :
854 :
855 : /* Dump the ISO time T to the log stream without a LF. */
856 : void
857 3 : dump_isotime (const gnupg_isotime_t t)
858 : {
859 3 : if (!t || !*t)
860 0 : log_printf ("%s", _("[none]"));
861 : else
862 3 : log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
863 : t, t+4, t+6, t+9, t+11, t+13);
864 3 : }
865 :
866 :
867 : /* Copy one ISO date to another, this is inline so that we can do a
868 : minimal sanity check. A null date (empty string) is allowed. */
869 : void
870 0 : gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
871 : {
872 0 : if (*s)
873 : {
874 0 : if ((strlen (s) != 15 || s[8] != 'T'))
875 0 : BUG();
876 0 : memcpy (d, s, 15);
877 0 : d[15] = 0;
878 : }
879 : else
880 0 : *d = 0;
881 0 : }
882 :
883 :
884 : /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
885 : to about the equivalent of 62 years which should be more then
886 : enough for our purposes. */
887 : gpg_error_t
888 0 : add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
889 : {
890 : gpg_error_t err;
891 : int year, month, day, hour, minute, sec, ndays;
892 : unsigned long jd;
893 :
894 0 : err = check_isotime (atime);
895 0 : if (err)
896 0 : return err;
897 :
898 0 : if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
899 0 : return gpg_error (GPG_ERR_INV_VALUE);
900 :
901 0 : year = atoi_4 (atime+0);
902 0 : month = atoi_2 (atime+4);
903 0 : day = atoi_2 (atime+6);
904 0 : hour = atoi_2 (atime+9);
905 0 : minute= atoi_2 (atime+11);
906 0 : sec = atoi_2 (atime+13);
907 :
908 0 : if (year <= 1582) /* The julian date functions don't support this. */
909 0 : return gpg_error (GPG_ERR_INV_VALUE);
910 :
911 0 : sec += nseconds;
912 0 : minute += sec/60;
913 0 : sec %= 60;
914 0 : hour += minute/60;
915 0 : minute %= 60;
916 0 : ndays = hour/24;
917 0 : hour %= 24;
918 :
919 0 : jd = date2jd (year, month, day) + ndays;
920 0 : jd2date (jd, &year, &month, &day);
921 :
922 0 : if (year > 9999 || month > 12 || day > 31
923 0 : || year < 0 || month < 1 || day < 1)
924 0 : return gpg_error (GPG_ERR_INV_VALUE);
925 :
926 0 : snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
927 : year, month, day, hour, minute, sec);
928 0 : return 0;
929 : }
930 :
931 :
932 : gpg_error_t
933 0 : add_days_to_isotime (gnupg_isotime_t atime, int ndays)
934 : {
935 : gpg_error_t err;
936 : int year, month, day, hour, minute, sec;
937 : unsigned long jd;
938 :
939 0 : err = check_isotime (atime);
940 0 : if (err)
941 0 : return err;
942 :
943 0 : if (ndays < 0 || ndays >= 9999*366 )
944 0 : return gpg_error (GPG_ERR_INV_VALUE);
945 :
946 0 : year = atoi_4 (atime+0);
947 0 : month = atoi_2 (atime+4);
948 0 : day = atoi_2 (atime+6);
949 0 : hour = atoi_2 (atime+9);
950 0 : minute= atoi_2 (atime+11);
951 0 : sec = atoi_2 (atime+13);
952 :
953 0 : if (year <= 1582) /* The julian date functions don't support this. */
954 0 : return gpg_error (GPG_ERR_INV_VALUE);
955 :
956 0 : jd = date2jd (year, month, day) + ndays;
957 0 : jd2date (jd, &year, &month, &day);
958 :
959 0 : if (year > 9999 || month > 12 || day > 31
960 0 : || year < 0 || month < 1 || day < 1)
961 0 : return gpg_error (GPG_ERR_INV_VALUE);
962 :
963 0 : snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
964 : year, month, day, hour, minute, sec);
965 0 : return 0;
966 : }
|