47
32
#include <sys/stat.h>
49
34
#include <string.h>
52
36
#include <stdlib.h>
55
39
#include "common.h"
61
43
static gchar *lifereaUserPath = NULL;
63
/* Conversion function which should be applied to all read XML strings,
64
to ensure proper UTF8. This is because we use libxml2 in recovery
65
mode which can produce invalid UTF-8.
67
The valid or a corrected string is returned. The original XML
68
string is modified . */
69
gchar * common_utf8_fix(gchar *string) {
70
const gchar *invalid_offset;
75
if(!g_utf8_validate(string, -1, &invalid_offset)) {
76
/* if we have an invalid string we try to shorten
77
it until it is valid UTF-8 */
78
debug0(DEBUG_PARSING, "parser delivered invalid UTF-8!");
79
debug1(DEBUG_PARSING, " >>>%s<<<", string);
80
debug1(DEBUG_PARSING, "first invalid char is: >>>%s<<<" , invalid_offset);
81
debug0(DEBUG_PARSING, "removing invalid bytes");
84
memmove((void *)invalid_offset, invalid_offset + 1, strlen(invalid_offset + 1) + 1);
85
} while(!g_utf8_validate(string, -1, &invalid_offset));
87
debug0(DEBUG_PARSING, "result is:");
88
debug1(DEBUG_PARSING, " >>>%s<<<", string);
94
long common_parse_long(gchar *str, long def) {
46
common_parse_long (const gchar *str, long def)
99
if(0 == (sscanf(str,"%ld",&num)))
52
if (0 == (sscanf (str,"%ld", &num)))
105
#define TIMESTRLEN 256
107
gchar * common_format_date(time_t date, const gchar *date_format) {
112
return g_strdup ("");
115
localtime_r (&date, &date_tm);
117
result = g_new0(gchar, TIMESTRLEN);
118
e_utf8_strftime_fix_am_pm(result, TIMESTRLEN, date_format, &date_tm);
122
/* This function is originally from the Evolution 2.6.2 code (e-cell-date.c) */
123
gchar * common_format_nice_date(time_t date) {
124
time_t nowdate = time(NULL);
126
struct tm then, now, yesterday;
128
gboolean done = FALSE;
131
return g_strdup ("");
134
buf = g_new0(gchar, TIMESTRLEN + 1);
136
localtime_r (&date, &then);
137
localtime_r (&nowdate, &now);
139
/* if (nowdate - date < 60 * 60 * 8 && nowdate > date) {
140
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("%l:%M %p"), &then);
145
if (then.tm_mday == now.tm_mday &&
146
then.tm_mon == now.tm_mon &&
147
then.tm_year == now.tm_year) {
148
/* translation hint: date format for today, reorder format codes as necessary */
149
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("Today %l:%M %p"), &then);
154
yesdate = nowdate - 60 * 60 * 24;
155
localtime_r (&yesdate, &yesterday);
156
if (then.tm_mday == yesterday.tm_mday &&
157
then.tm_mon == yesterday.tm_mon &&
158
then.tm_year == yesterday.tm_year) {
159
/* translation hint: date format for yesterday, reorder format codes as necessary */
160
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("Yesterday %l:%M %p"), &then);
166
for (i = 2; i < 7; i++) {
167
yesdate = nowdate - 60 * 60 * 24 * i;
168
localtime_r (&yesdate, &yesterday);
169
if (then.tm_mday == yesterday.tm_mday &&
170
then.tm_mon == yesterday.tm_mon &&
171
then.tm_year == yesterday.tm_year) {
172
/* translation hint: date format for dates older than 2 days but not older than a week, reorder format codes as necessary */
173
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("%a %l:%M %p"), &then);
180
if (then.tm_year == now.tm_year) {
181
/* translation hint: date format for dates older than a week but from this year, reorder format codes as necessary */
182
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("%b %d %l:%M %p"), &then);
184
/* translation hint: date format for dates from the last years, reorder format codes as necessary */
185
e_utf8_strftime_fix_am_pm (buf, TIMESTRLEN, _("%b %d %Y"), &then);
190
while ((temp = strstr (temp, " "))) {
191
memmove (temp, temp + 1, strlen (temp));
193
temp = g_strstrip (buf);
197
/* converts a ISO 8601 time string to a time_t value */
198
time_t parseISO8601Date(gchar *date) {
200
time_t t, t2, offset = 0;
201
gboolean success = FALSE;
204
g_assert(date != NULL);
206
memset(&tm, 0, sizeof(struct tm));
208
/* we expect at least something like "2003-08-07T15:28:19" and
209
don't require the second fractions and the timezone info
211
the most specific format: YYYY-MM-DDThh:mm:ss.sTZD
214
/* full specified variant */
215
if(NULL != (pos = strptime((const char *)date, "%t%Y-%m-%dT%H:%M%t", &tm))) {
219
if (isdigit(pos[0]) && !isdigit(pos[1])) {
220
tm.tm_sec = pos[0] - '0';
222
} else if (isdigit(pos[0]) && isdigit(pos[1])) {
223
tm.tm_sec = 10*(pos[0]-'0') + pos[1] - '0';
226
/* Parse second fractions */
228
while (*pos == '.' || isdigit(pos[0]))
234
else if ((*pos == '+' || *pos == '-') && isdigit(pos[1]) && isdigit(pos[2]) && strlen(pos) >= 3) {
235
offset = (10*(pos[1] - '0') + (pos[2] - '0')) * 60 * 60;
237
if (pos[3] == ':' && isdigit(pos[4]) && isdigit(pos[5]))
238
offset += (10*(pos[4] - '0') + (pos[5] - '0')) * 60;
239
else if (isdigit(pos[3]) && isdigit(pos[4]))
240
offset += (10*(pos[3] - '0') + (pos[4] - '0')) * 60;
242
offset *= (pos[0] == '+') ? 1 : -1;
247
} else if(NULL != strptime((const char *)date, "%t%Y-%m-%d", &tm))
249
/* there were others combinations too... */
251
if(TRUE == success) {
252
if((time_t)(-1) != (t = mktime(&tm))) {
253
/* Correct for the local timezone*/
257
gmtime_r(&t, &tmp_tm);
258
t2 = mktime(&tmp_tm);
263
debug0(DEBUG_PARSING, "internal error! time conversion error! mktime failed!");
266
debug0(DEBUG_PARSING, "Invalid ISO8601 date format! Ignoring <dc:date> information!");
272
static const gchar *dayofweek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
273
static const gchar *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
275
gchar *createRFC822Date(const time_t *time) {
278
tm = gmtime(time); /* No need to free because it is statically allocated */
279
return g_strdup_printf("%s, %2d %s %4d %02d:%02d:%02d GMT", dayofweek[tm->tm_wday], tm->tm_mday,
280
months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
283
/* in theory, we'd need only the RFC822 timezones here
284
in practice, feeds also use other timezones... */
350
/** @returns timezone offset in seconds */
351
static time_t common_parse_rfc822_tz(char *token) {
353
const char *inptr = token;
354
int num_timezones = sizeof(tz_offsets) / sizeof((tz_offsets)[0]);
356
if (*inptr == '+' || *inptr == '-') {
357
offset = atoi (inptr);
364
for (t = 0; t < num_timezones; t++)
365
if (!strncmp (inptr, tz_offsets[t].name, strlen (tz_offsets[t].name))) {
366
offset = tz_offsets[t].offset;
371
return 60 * ((offset / 100) * 60 + (offset % 100));
375
/* converts a RFC822 time string to a time_t value */
376
time_t parseRFC822Date(gchar *date) {
381
gboolean success = FALSE;
383
memset(&tm, 0, sizeof(struct tm));
385
/* we expect at least something like "03 Dec 12 01:38:34"
386
and don't require a day of week or the timezone
388
the most specific format we expect: "Fri, 03 Dec 12 01:38:34 CET"
390
/* skip day of week */
391
if(NULL != (pos = g_utf8_strchr(date, -1, ',')))
394
/* we expect English month names, so we set the locale */
395
oldlocale = g_strdup(setlocale(LC_TIME, NULL));
396
setlocale(LC_TIME, "C");
398
/* standard format with seconds and 4 digit year */
399
if(NULL != (pos = strptime((const char *)date, " %d %b %Y %T", &tm)))
401
/* non-standard format without seconds and 4 digit year */
402
else if(NULL != (pos = strptime((const char *)date, " %d %b %Y %H:%M", &tm)))
404
/* non-standard format with seconds and 2 digit year */
405
else if(NULL != (pos = strptime((const char *)date, " %d %b %y %T", &tm)))
407
/* non-standard format without seconds 2 digit year */
408
else if(NULL != (pos = strptime((const char *)date, " %d %b %y %H:%M", &tm)))
411
while(pos && *pos != '\0' && isspace((int)*pos)) /* skip whitespaces before timezone */
415
setlocale(LC_TIME, oldlocale); /* and reset it again */
420
if((time_t)(-1) != (t = mktime(&tm))) {
421
/* GMT time, with no daylight savings time
422
correction. (Usually, there is no daylight savings
423
time since the input is GMT.) */
424
t = t - common_parse_rfc822_tz(pos);
425
t2 = mktime(gmtime(&t));
429
debug0(DEBUG_PARSING, "internal error! time conversion error! mktime failed!");
437
59
common_check_dir (gchar *path)
469
const gchar * common_get_cache_path(void) {
472
common_init_cache_path();
92
common_get_cache_path (void)
95
common_init_cache_path ();
474
97
return lifereaUserPath;
477
gchar * common_create_cache_filename(const gchar *folder, const gchar *filename, const gchar *extension) {
101
common_create_cache_filename (const gchar *folder, const gchar *filename, const gchar *extension)
480
result = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s%s%s%s%s", common_get_cache_path(),
481
(folder != NULL) ? folder : "",
482
(folder != NULL) ? G_DIR_SEPARATOR_S : "",
484
(extension != NULL)? "." : "",
485
(extension != NULL)? extension : "");
105
result = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s%s%s%s%s", common_get_cache_path (),
106
folder ? folder : "",
107
folder ? G_DIR_SEPARATOR_S : "",
109
extension ? "." : "",
110
extension ? extension : "");
490
xmlChar * common_uri_escape(const xmlChar *url) {
116
common_uri_escape (const xmlChar *url)
118
xmlChar *result, *tmp;
120
g_assert (NULL != url);
493
122
/* xmlURIEscape returns NULL if spaces are in the URL,
494
123
so we need to replace them first (see SF #2965158) */
495
result = common_strreplace (g_strdup (url), " ", "+");
497
result = xmlURIEscape(result);
124
tmp = common_strreplace (g_strdup (url), " ", "+");
125
result = xmlURIEscape (tmp);
499
128
/* workaround if escaping somehow fails... */
501
result = g_strdup(url);
130
result = g_strdup (url);
506
xmlChar * common_uri_unescape(const xmlChar *url) {
508
return xmlURIUnescapeString(url, -1, NULL);
136
common_uri_unescape (const xmlChar *url)
138
return xmlURIUnescapeString (url, -1, NULL);
142
common_uri_sanitize (const xmlChar *uri)
144
xmlChar *tmp, *result;
146
/* We must escape all dangerous characters (e.g. & and spaces)
147
in the URL. As we do not know if the URL is already escaped we
148
simply unescape and reescape it. */
149
tmp = common_uri_unescape (uri);
150
result = common_uri_escape (tmp);
511
156
/* to correctly escape and expand URLs */
512
xmlChar * common_build_url(const gchar *url, const gchar *baseURL) {
158
common_build_url (const gchar *url, const gchar *baseURL)
513
160
xmlChar *escapedURL, *absURL, *escapedBaseURL;
515
escapedURL = common_uri_escape(url);
162
escapedURL = common_uri_escape (url);
517
if(NULL != baseURL) {
518
escapedBaseURL = common_uri_escape(baseURL);
519
absURL = xmlBuildURI(escapedURL, escapedBaseURL);
165
escapedBaseURL = common_uri_escape (baseURL);
166
absURL = xmlBuildURI (escapedURL, escapedBaseURL);
168
xmlFree (escapedURL);
523
170
absURL = escapedURL;
525
xmlFree(escapedBaseURL);
172
xmlFree (escapedBaseURL);
527
174
absURL = escapedURL;