4145f52db542ac45ba8f6b71fad2edd3fb0d612a
[claws.git] / src / plugins / rssyl / date.c
1 /**
2  * @file common.c common routines for Liferea
3  * 
4  * Copyright (C) 2003-2005  Lars Lindner <lars.lindner@gmx.net>
5  * Copyright (C) 2004,2005  Nathan J. Conrad <t98502@users.sourceforge.net>
6  * Copyright (C) 2004       Karl Soderstrom <ks@xanadunet.net>
7  *
8  * parts of the RFC822 timezone decoding were taken from the gmime 
9  * source written by 
10  *
11  * Authors: Michael Zucchi <notzed@helixcode.com>
12  *          Jeffrey Stedfast <fejj@helixcode.com>
13  *
14  * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program 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, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34
35 /* this is needed for strptime() */
36 #if !defined (__FreeBSD__)
37 #define _XOPEN_SOURCE 600 /* glibc2 needs this */
38 #else
39 #define _XOPEN_SOURCE
40 #endif
41
42 #ifdef USE_PTHREAD
43 #include <pthread.h>
44 #endif
45
46 #include <time.h>
47 #include <glib.h>
48 #include <locale.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52
53 #include "procheader.h"
54
55 /* converts a ISO 8601 time string to a time_t value */
56 time_t parseISO8601Date(gchar *date) {
57         struct tm       tm;
58         time_t          t, t2, offset = 0;
59         gboolean        success = FALSE;
60 #ifdef G_OS_WIN32
61         gchar *tmp = g_strdup(date);
62         gint result, year, month, day, hour, minute, second;
63 #else
64         gchar *pos;
65 #endif  
66         g_assert(date != NULL);
67         
68         memset(&tm, 0, sizeof(struct tm));
69         
70 #ifdef G_OS_WIN32
71         g_strstrip(tmp);
72         result = sscanf((const char *)date, "%d-%d-%dT%d:%d:%d", 
73                         &year, &month, &day, &hour, &minute, &second);
74         if (result < 6)
75                 second = 0;
76         if (result < 5)
77                 minute = 0;
78         if (result < 4)
79                 hour = 0;
80         if (result >= 3) {
81                 tm.tm_sec = second;
82                 tm.tm_min = minute;
83                 tm.tm_hour = hour;
84                 tm.tm_mday = day;
85                 tm.tm_mon = month - 1;
86                 tm.tm_year = year - 1900;
87                 tm.tm_wday = 0;
88                 tm.tm_yday = 0;
89                 tm.tm_isdst = -1;
90                 success = TRUE;
91         }
92 #else
93         /* we expect at least something like "2003-08-07T15:28:19" and
94            don't require the second fractions and the timezone info
95
96            the most specific format:   YYYY-MM-DDThh:mm:ss.sTZD
97          */
98          
99         /* full specified variant */
100         if(NULL != (pos = strptime((const char *)date, "%t%Y-%m-%dT%H:%M%t", &tm))) {
101                 /* Parse seconds */
102                 if (*pos == ':')
103                         pos++;
104                 if (isdigit(pos[0]) && !isdigit(pos[1])) {
105                         tm.tm_sec = pos[0] - '0';
106                         pos++;
107                 } else if (isdigit(pos[0]) && isdigit(pos[1])) {
108                         tm.tm_sec = 10*(pos[0]-'0') + pos[1] - '0';
109                         pos +=2;
110                 }
111                 /* Parse timezone */
112                 if (*pos == 'Z')
113                         offset = 0;
114                 else if ((*pos == '+' || *pos == '-') && isdigit(pos[1]) && isdigit(pos[2]) && strlen(pos) >= 3) {
115                         offset = (10*(pos[1] - '0') + (pos[2] - '0')) * 60 * 60;
116                         
117                         if (pos[3] == ':' && isdigit(pos[4]) && isdigit(pos[5]))
118                                 offset +=  (10*(pos[4] - '0') + (pos[5] - '0')) * 60;
119                         else if (isdigit(pos[3]) && isdigit(pos[4]))
120                                 offset +=  (10*(pos[3] - '0') + (pos[4] - '0')) * 60;
121                         
122                         offset *= (pos[0] == '+') ? 1 : -1;
123
124                 }
125                 success = TRUE;
126         /* only date */
127         } else if(NULL != strptime((const char *)date, "%t%Y-%m-%d", &tm))
128                 success = TRUE;
129         /* there were others combinations too... */
130 #endif
131         if(TRUE == success) {
132                 if((time_t)(-1) != (t = mktime(&tm))) {
133                         struct tm buft;
134                         /* Correct for the local timezone*/
135                         t = t - offset;
136                         t2 = mktime(gmtime_r(&t, &buft));
137                         t = t - (t2 - t);
138                         
139                         return t;
140                 } else {
141                         g_warning("internal error! time conversion error! mktime failed!\n");
142                 }
143         } else {
144                 g_warning("Invalid ISO8601 date format! Ignoring <dc:date> information!\n");
145         }
146         
147         return 0;
148 }
149
150 gchar *dayofweek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
151 gchar *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
152
153 gchar *createRFC822Date(const time_t *time) {
154         struct tm *tm;
155         struct tm buft;
156 #ifdef G_OS_WIN32
157         if (*time < 0) {
158                 time_t t = 1;
159                 tm = gmtime_r(&t, &buft);
160         } else 
161 #endif
162         {
163                 tm = gmtime_r(time, &buft); /* No need to free because it is statically allocated */
164         }
165         return g_strdup_printf("%s, %2d %s %4d %02d:%02d:%02d GMT", dayofweek[tm->tm_wday], tm->tm_mday,
166                                            months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
167 }