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