[tracker/localtime-for-master: 2/5] libtracker-common: Add TrackerDateTime to store time with UTC offset
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/localtime-for-master: 2/5] libtracker-common: Add TrackerDateTime to store time with UTC offset
- Date: Fri, 19 Feb 2010 13:12:32 +0000 (UTC)
commit 9a26a4c535eaef90d978ce0a94cd653a216e8e86
Author: Jürg Billeter <j bitron ch>
Date: Wed Feb 17 13:28:46 2010 +0100
libtracker-common: Add TrackerDateTime to store time with UTC offset
src/libtracker-common/Makefile.am | 2 +
src/libtracker-common/libtracker-common.vapi | 4 +-
src/libtracker-common/tracker-common.h | 1 +
src/libtracker-common/tracker-date-time.c | 627 +++++++++++++++++++++
src/libtracker-common/tracker-date-time.h | 57 ++
src/libtracker-common/tracker-type-utils.c | 460 ---------------
src/libtracker-common/tracker-type-utils.h | 6 -
src/libtracker-data/tracker-data-update.c | 2 +-
src/libtracker-data/tracker-sparql-query.vala | 2 +-
src/libtracker-db/tracker-db-manager.c | 2 +-
src/libtracker-extract/tracker-exif.c | 2 +-
src/libtracker-extract/tracker-iptc.c | 2 +-
src/plugins/evolution/tracker-evolution-plugin.c | 3 +-
src/tracker-extract/tracker-extract-mp3.c | 2 +-
src/tracker-extract/tracker-extract-pdf.c | 2 +-
src/tracker-extract/tracker-extract-png.c | 1 +
src/tracker-extract/tracker-extract-ps.c | 1 +
src/tracker-miner-fs/tracker-miner-files.c | 1 +
src/tracker-miner-fs/tracker-volume-cleanup.c | 1 +
tests/libtracker-common/tracker-type-utils-test.c | 11 +-
20 files changed, 708 insertions(+), 481 deletions(-)
---
diff --git a/src/libtracker-common/Makefile.am b/src/libtracker-common/Makefile.am
index abebfe0..d8469dd 100644
--- a/src/libtracker-common/Makefile.am
+++ b/src/libtracker-common/Makefile.am
@@ -60,6 +60,7 @@ libtracker_common_la_SOURCES = \
$(storage_sources) \
tracker-config-file.c \
tracker-class.c \
+ tracker-date-time.c \
tracker-dbus.c \
tracker-file-utils.c \
tracker-ioprio.c \
@@ -87,6 +88,7 @@ libtracker_commoninclude_HEADERS = \
tracker-class.h \
tracker-config-file.h \
tracker-common.h \
+ tracker-date-time.h \
tracker-file-utils.h \
tracker-keyfile-object.h \
tracker-language.h \
diff --git a/src/libtracker-common/libtracker-common.vapi b/src/libtracker-common/libtracker-common.vapi
index 9be6d09..ff69dd6 100644
--- a/src/libtracker-common/libtracker-common.vapi
+++ b/src/libtracker-common/libtracker-common.vapi
@@ -64,7 +64,7 @@ namespace Tracker {
public weak Property[] get_properties ();
}
- [CCode (cheader_filename = "libtracker-common/tracker-type-utils.h")]
- public int string_to_date (string date_string);
+ [CCode (cheader_filename = "libtracker-common/tracker-date-time.h")]
+ public int string_to_date (string date_string, out int offset);
}
diff --git a/src/libtracker-common/tracker-common.h b/src/libtracker-common/tracker-common.h
index 5e17683..1dc915a 100644
--- a/src/libtracker-common/tracker-common.h
+++ b/src/libtracker-common/tracker-common.h
@@ -43,6 +43,7 @@ G_BEGIN_DECLS
/* Installed headers */
#include "tracker-class.h"
#include "tracker-config-file.h"
+#include "tracker-date-time.h"
#include "tracker-file-utils.h"
#include "tracker-keyfile-object.h"
#include "tracker-language.h"
diff --git a/src/libtracker-common/tracker-date-time.c b/src/libtracker-common/tracker-date-time.c
new file mode 100644
index 0000000..3e52171
--- /dev/null
+++ b/src/libtracker-common/tracker-date-time.c
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2006, Mr Jamie McCracken (jamiemcc gnome org)
+ * Copyright (C) 2008-2010, Nokia (urho konttori nokia com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#define _XOPEN_SOURCE
+#include <time.h>
+
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "tracker-date-time.h"
+#include "tracker-type-utils.h"
+
+#define DATE_FORMAT_ISO8601 "%Y-%m-%dT%H:%M:%S%z"
+
+static const char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char imonths[] = {
+ '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', '0', '1', '2'
+};
+
+static gboolean
+is_int (const gchar *str)
+{
+ gint i, len;
+
+ if (!str || str[0] == '\0') {
+ return FALSE;
+ }
+
+ len = strlen (str);
+
+ for (i = 0; i < len; i++) {
+ if (!g_ascii_isdigit(str[i])) {
+ return FALSE;
+ }
+ }
+
+ return TRUE ;
+}
+
+static gint
+parse_month (const gchar *month)
+{
+ gint i;
+
+ for (i = 0; i < 12; i++) {
+ if (!strncmp (month, months[i], 3)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/* Determine date format and convert to ISO 8601 format */
+/* FIXME We should handle all the fractions here (see ISO 8601), as well as YYYY:DDD etc */
+gchar *
+tracker_date_format (const gchar *date_string)
+{
+ gchar buf[30];
+ gint len;
+
+ if (!date_string) {
+ return NULL;
+ }
+
+ len = strlen (date_string);
+
+ /* We cannot format a date without at least a four digit
+ * year.
+ */
+ if (len < 4) {
+ return NULL;
+ }
+
+ /* Check for year only dates (EG ID3 music tags might have
+ * Audio.ReleaseDate as 4 digit year)
+ */
+ if (len == 4) {
+ if (is_int (date_string)) {
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = '0';
+ buf[6] = '1';
+ buf[7] = '-';
+ buf[8] = '0';
+ buf[9] = '1';
+ buf[10] = 'T';
+ buf[11] = '0';
+ buf[12] = '0';
+ buf[13] = ':';
+ buf[14] = '0';
+ buf[15] = '0';
+ buf[16] = ':';
+ buf[17] = '0';
+ buf[18] = '0';
+ buf[19] = 'Z';
+ buf[20] = '\0';
+
+ return g_strdup (buf);
+ } else {
+ return NULL;
+ }
+ } else if (len == 10) {
+ /* Check for date part only YYYY-MM-DD*/
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[5];
+ buf[6] = date_string[6];
+ buf[7] = '-';
+ buf[8] = date_string[8];
+ buf[9] = date_string[9];
+ buf[10] = 'T';
+ buf[11] = '0';
+ buf[12] = '0';
+ buf[13] = ':';
+ buf[14] = '0';
+ buf[15] = '0';
+ buf[16] = ':';
+ buf[17] = '0';
+ buf[18] = '0';
+ buf[19] = '\0';
+
+ return g_strdup (buf);
+ } else if (len == 14) {
+ /* Check for pdf format EG 20050315113224-08'00' or
+ * 20050216111533Z
+ */
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[4];
+ buf[6] = date_string[5];
+ buf[7] = '-';
+ buf[8] = date_string[6];
+ buf[9] = date_string[7];
+ buf[10] = 'T';
+ buf[11] = date_string[8];
+ buf[12] = date_string[9];
+ buf[13] = ':';
+ buf[14] = date_string[10];
+ buf[15] = date_string[11];
+ buf[16] = ':';
+ buf[17] = date_string[12];
+ buf[18] = date_string[13];
+ buf[19] = '\0';
+
+ return g_strdup (buf);
+ } else if (len == 15 && date_string[14] == 'Z') {
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[4];
+ buf[6] = date_string[5];
+ buf[7] = '-';
+ buf[8] = date_string[6];
+ buf[9] = date_string[7];
+ buf[10] = 'T';
+ buf[11] = date_string[8];
+ buf[12] = date_string[9];
+ buf[13] = ':';
+ buf[14] = date_string[10];
+ buf[15] = date_string[11];
+ buf[16] = ':';
+ buf[17] = date_string[12];
+ buf[18] = date_string[13];
+ buf[19] = 'Z';
+ buf[20] = '\0';
+
+ return g_strdup (buf);
+ } else if (len == 21 && (date_string[14] == '-' || date_string[14] == '+' )) {
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[4];
+ buf[6] = date_string[5];
+ buf[7] = '-';
+ buf[8] = date_string[6];
+ buf[9] = date_string[7];
+ buf[10] = 'T';
+ buf[11] = date_string[8];
+ buf[12] = date_string[9];
+ buf[13] = ':';
+ buf[14] = date_string[10];
+ buf[15] = date_string[11];
+ buf[16] = ':';
+ buf[17] = date_string[12];
+ buf[18] = date_string[13];
+ buf[19] = date_string[14];
+ buf[20] = date_string[15];
+ buf[21] = date_string[16];
+ buf[22] = ':';
+ buf[23] = date_string[18];
+ buf[24] = date_string[19];
+ buf[25] = '\0';
+
+ return g_strdup (buf);
+ } else if ((len == 24) && (date_string[3] == ' ')) {
+ /* Check for msoffice date format "Mon Feb 9 10:10:00 2004" */
+ gint num_month;
+ gchar mon1;
+ gchar day1;
+
+ num_month = parse_month (date_string + 4);
+
+ mon1 = imonths[num_month];
+
+ if (date_string[8] == ' ') {
+ day1 = '0';
+ } else {
+ day1 = date_string[8];
+ }
+
+ buf[0] = date_string[20];
+ buf[1] = date_string[21];
+ buf[2] = date_string[22];
+ buf[3] = date_string[23];
+ buf[4] = '-';
+
+ if (num_month < 10) {
+ buf[5] = '0';
+ buf[6] = mon1;
+ } else {
+ buf[5] = '1';
+ buf[6] = mon1;
+ }
+
+ buf[7] = '-';
+ buf[8] = day1;
+ buf[9] = date_string[9];
+ buf[10] = 'T';
+ buf[11] = date_string[11];
+ buf[12] = date_string[12];
+ buf[13] = ':';
+ buf[14] = date_string[14];
+ buf[15] = date_string[15];
+ buf[16] = ':';
+ buf[17] = date_string[17];
+ buf[18] = date_string[18];
+ buf[19] = '\0';
+
+ return g_strdup (buf);
+ } else if ((len == 19) && (date_string[4] == ':') && (date_string[7] == ':')) {
+ /* Check for Exif date format "2005:04:29 14:56:54" */
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[5];
+ buf[6] = date_string[6];
+ buf[7] = '-';
+ buf[8] = date_string[8];
+ buf[9] = date_string[9];
+ buf[10] = 'T';
+ buf[11] = date_string[11];
+ buf[12] = date_string[12];
+ buf[13] = ':';
+ buf[14] = date_string[14];
+ buf[15] = date_string[15];
+ buf[16] = ':';
+ buf[17] = date_string[17];
+ buf[18] = date_string[18];
+ buf[19] = '\0';
+
+ return g_strdup (buf);
+ } else if ((len == 28) && (date_string[4] == '-') && (date_string[10] == 'T')
+ && (date_string[19] == '.') ) {
+ /* The fraction of seconds ISO 8601 "YYYY-MM-DDThh:mm:ss.ff+zz:zz" */
+ buf[0] = date_string[0];
+ buf[1] = date_string[1];
+ buf[2] = date_string[2];
+ buf[3] = date_string[3];
+ buf[4] = '-';
+ buf[5] = date_string[5];
+ buf[6] = date_string[6];
+ buf[7] = '-';
+ buf[8] = date_string[8];
+ buf[9] = date_string[9];
+ buf[10] = 'T';
+ buf[11] = date_string[11];
+ buf[12] = date_string[12];
+ buf[13] = ':';
+ buf[14] = date_string[14];
+ buf[15] = date_string[15];
+ buf[16] = ':';
+ buf[17] = date_string[17];
+ buf[18] = date_string[18];
+ buf[19] = date_string[22];
+ buf[20] = date_string[23];
+ buf[21] = date_string[24];
+ buf[22] = ':';
+ buf[23] = date_string[26];
+ buf[24] = date_string[27];
+ buf[25] = '\0';
+
+ return g_strdup (buf);
+ }
+
+ return g_strdup (date_string);
+}
+
+gchar *
+tracker_date_format_to_iso8601 (const gchar *date_string,
+ const gchar *format)
+{
+ gchar *result;
+ struct tm date_tm = { 0 };
+
+ g_return_val_if_fail (date_string != NULL, NULL);
+ g_return_val_if_fail (format != NULL, NULL);
+
+ if (strptime (date_string, format, &date_tm) == 0) {
+ return NULL;
+ }
+
+ result = g_malloc (sizeof (char)*25);
+
+ strftime (result, 25, DATE_FORMAT_ISO8601 , &date_tm);
+
+ return result;
+}
+
+gchar *
+tracker_date_to_time_string (const gchar *date_string)
+{
+ gchar *str;
+
+ str = tracker_date_format (date_string);
+
+ if (str) {
+ time_t t;
+
+ t = tracker_string_to_date (str, NULL);
+
+ g_free (str);
+
+ if (t != -1) {
+ return tracker_gint_to_string (t);
+ }
+ }
+
+ return NULL;
+}
+
+time_t
+tracker_string_to_date (const gchar *date_string,
+ gint *offset_p)
+{
+ static GRegex *regex = NULL;
+
+ GMatchInfo *match_info;
+ gchar *match;
+ struct tm tm;
+ time_t t;
+ gint offset;
+
+ g_return_val_if_fail (date_string, -1);
+
+ /* We should have a valid iso 8601 date in format
+ * YYYY-MM-DDThh:mm:ss with optional TZ
+ */
+
+ if (!regex) {
+ GError *e = NULL;
+ regex = g_regex_new ("^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])T([0-9][0-9]):([0-9][0-9]):([0-9][0-9])(\\.[0-9]+)?(Z|((\\+|-)[0-9][0-9]):?([0-9][0-9]))?$", 0, 0, &e);
+ if (e) {
+ g_error ("%s", e->message);
+ }
+ }
+
+ if (!g_regex_match (regex, date_string, 0, &match_info)) {
+ g_match_info_free (match_info);
+ return -1;
+ }
+
+ memset (&tm, 0, sizeof (struct tm));
+
+ /* year */
+ match = g_match_info_fetch (match_info, 1);
+ tm.tm_year = atoi (match) - 1900;
+ g_free (match);
+
+ /* month */
+ match = g_match_info_fetch (match_info, 2);
+ tm.tm_mon = atoi (match) - 1;
+ g_free (match);
+
+ /* day of month */
+ match = g_match_info_fetch (match_info, 3);
+ tm.tm_mday = atoi (match);
+ g_free (match);
+
+ /* hour */
+ match = g_match_info_fetch (match_info, 4);
+ tm.tm_hour = atoi (match);
+ g_free (match);
+
+ /* minute */
+ match = g_match_info_fetch (match_info, 5);
+ tm.tm_min = atoi (match);
+ g_free (match);
+
+ /* second */
+ match = g_match_info_fetch (match_info, 6);
+ tm.tm_sec = atoi (match);
+ g_free (match);
+
+ match = g_match_info_fetch (match_info, 8);
+ if (match) {
+ /* timezoned */
+ g_free (match);
+
+ /* mktime() always assumes that "tm" is in locale time but we
+ * want to keep control on time, so we go to UTC
+ */
+ t = mktime (&tm);
+ t -= timezone;
+
+ offset = 0;
+
+ match = g_match_info_fetch (match_info, 9);
+ if (match) {
+ /* non-UTC timezone */
+ offset = atoi (match) * 3600;
+ g_free (match);
+
+ match = g_match_info_fetch (match_info, 10);
+ offset += atoi (match) * 60;
+ g_free (match);
+
+ if (offset <= -24 * 3600 || offset >= 24 * 3600) {
+ g_warning ("UTC offset too large: %d seconds", offset);
+ }
+
+ t -= offset;
+ }
+ } else {
+ /* local time */
+ tm.tm_isdst = -1;
+ t = mktime (&tm);
+
+ offset = -timezone + (tm.tm_isdst > 0 ? 3600 : 0);
+ }
+
+ g_match_info_free (match_info);
+
+ if (offset_p) {
+ *offset_p = offset;
+ }
+
+ return t;
+}
+
+gchar *
+tracker_date_to_string (time_t date_time)
+{
+ gchar buffer[30];
+ struct tm utc_time;
+ size_t count;
+
+ memset (buffer, '\0', sizeof (buffer));
+ memset (&utc_time, 0, sizeof (struct tm));
+
+ gmtime_r (&date_time, &utc_time);
+
+ /* Output is ISO 8160 format : "YYYY-MM-DDThh:mm:ssZ" */
+ count = strftime (buffer, sizeof (buffer), "%FT%TZ", &utc_time);
+
+ return count > 0 ? g_strdup (buffer) : NULL;
+}
+
+static void
+date_time_value_init (GValue *value)
+{
+ value->data[0].v_int64 = 0;
+ value->data[1].v_int = 0;
+}
+
+static void
+date_time_value_copy (const GValue *src_value,
+ GValue *dest_value)
+{
+ dest_value->data[0].v_int64 = src_value->data[0].v_int64;
+ dest_value->data[1].v_int = src_value->data[1].v_int;
+}
+
+GType
+tracker_date_time_get_type (void)
+{
+ static GType tracker_date_time_type_id = 0;
+ if (G_UNLIKELY (tracker_date_time_type_id == 0)) {
+ static const GTypeValueTable value_table = {
+ date_time_value_init,
+ NULL,
+ date_time_value_copy
+ };
+ static const GTypeInfo type_info = {
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &value_table
+ };
+ static const GTypeFundamentalInfo fundamental_info = {
+ 0
+ };
+ tracker_date_time_type_id = g_type_register_fundamental (
+ g_type_fundamental_next (),
+ "TrackerDateTime",
+ &type_info,
+ &fundamental_info,
+ 0);
+ }
+ return tracker_date_time_type_id;
+}
+
+void
+tracker_date_time_set (GValue *value,
+ gint64 time,
+ gint offset)
+{
+ g_return_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME));
+ g_return_if_fail (offset > -24 * 3600 && offset < 24 * 3600);
+
+ value->data[0].v_int64 = time;
+ value->data[1].v_int = offset;
+}
+
+void
+tracker_date_time_set_from_string (GValue *value,
+ const gchar *date_time_string)
+{
+ g_return_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME));
+ g_return_if_fail (date_time_string != NULL);
+
+ gint64 time;
+ gint offset;
+
+ time = tracker_string_to_date (date_time_string, &offset);
+ tracker_date_time_set (value, time, offset);
+}
+
+gint64
+tracker_date_time_get_time (const GValue *value)
+{
+ g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
+
+ /* UTC timestamp */
+ return value->data[0].v_int64;
+}
+
+gint
+tracker_date_time_get_offset (const GValue *value)
+{
+ g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
+
+ /* UTC offset */
+ return value->data[1].v_int;
+}
+
+gint
+tracker_date_time_get_local_date (const GValue *value)
+{
+ g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
+
+ gint64 local_timestamp;
+
+ /* return number of days since epoch */
+ local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value);
+ return local_timestamp / 3600 / 24;
+}
+
+gint
+tracker_date_time_get_local_time (const GValue *value)
+{
+ g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0);
+
+ gint64 local_timestamp;
+
+ /* return local time of day */
+ local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value);
+ return local_timestamp % (24 * 3600);
+}
diff --git a/src/libtracker-common/tracker-date-time.h b/src/libtracker-common/tracker-date-time.h
new file mode 100644
index 0000000..f3d6022
--- /dev/null
+++ b/src/libtracker-common/tracker-date-time.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2006, Mr Jamie McCracken (jamiemcc gnome org)
+ * Copyright (C) 2008-2010, Nokia (urho konttori nokia com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __LIBTRACKER_COMMON_DATE_TIME_H__
+#define __LIBTRACKER_COMMON_DATE_TIME_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#if !defined (__LIBTRACKER_COMMON_INSIDE__) && !defined (TRACKER_COMPILATION)
+#error "only <libtracker-common/tracker-common.h> must be included directly."
+#endif
+
+#define TRACKER_TYPE_DATE_TIME (tracker_date_time_get_type ())
+
+GType tracker_date_time_get_type (void);
+
+void tracker_date_time_set (GValue *value,
+ gint64 time,
+ gint offset);
+void tracker_date_time_set_from_string (GValue *value,
+ const gchar *date_time_string);
+gint64 tracker_date_time_get_time (const GValue *value);
+gint tracker_date_time_get_offset (const GValue *value);
+gint tracker_date_time_get_local_date (const GValue *value);
+gint tracker_date_time_get_local_time (const GValue *value);
+
+gchar * tracker_date_format (const gchar *date_string);
+gchar * tracker_date_format_to_iso8601 (const gchar *date_string,
+ const gchar *format);
+gchar * tracker_date_to_time_string (const gchar *date_string);
+time_t tracker_string_to_date (const gchar *date_string,
+ gint *offset);
+gchar * tracker_date_to_string (time_t date_time);
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_COMMON_DATE_TIME_H__ */
diff --git a/src/libtracker-common/tracker-type-utils.c b/src/libtracker-common/tracker-type-utils.c
index f5bf266..88e9dfd 100644
--- a/src/libtracker-common/tracker-type-utils.c
+++ b/src/libtracker-common/tracker-type-utils.c
@@ -33,466 +33,6 @@
#include "tracker-utils.h"
#include "tracker-type-utils.h"
-#define DATE_FORMAT_ISO8601 "%Y-%m-%dT%H:%M:%S%z"
-
-static const char *months[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-static const char imonths[] = {
- '1', '2', '3', '4', '5',
- '6', '7', '8', '9', '0', '1', '2'
-};
-
-static gboolean
-is_int (const gchar *str)
-{
- gint i, len;
-
- if (!str || str[0] == '\0') {
- return FALSE;
- }
-
- len = strlen (str);
-
- for (i = 0; i < len; i++) {
- if (!g_ascii_isdigit(str[i])) {
- return FALSE;
- }
- }
-
- return TRUE ;
-}
-
-static gint
-parse_month (const gchar *month)
-{
- gint i;
-
- for (i = 0; i < 12; i++) {
- if (!strncmp (month, months[i], 3)) {
- return i;
- }
- }
-
- return -1;
-}
-
-/* Determine date format and convert to ISO 8601 format */
-/* FIXME We should handle all the fractions here (see ISO 8601), as well as YYYY:DDD etc */
-gchar *
-tracker_date_format (const gchar *date_string)
-{
- gchar buf[30];
- gint len;
-
- if (!date_string) {
- return NULL;
- }
-
- len = strlen (date_string);
-
- /* We cannot format a date without at least a four digit
- * year.
- */
- if (len < 4) {
- return NULL;
- }
-
- /* Check for year only dates (EG ID3 music tags might have
- * Audio.ReleaseDate as 4 digit year)
- */
- if (len == 4) {
- if (is_int (date_string)) {
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = '0';
- buf[6] = '1';
- buf[7] = '-';
- buf[8] = '0';
- buf[9] = '1';
- buf[10] = 'T';
- buf[11] = '0';
- buf[12] = '0';
- buf[13] = ':';
- buf[14] = '0';
- buf[15] = '0';
- buf[16] = ':';
- buf[17] = '0';
- buf[18] = '0';
- buf[19] = 'Z';
- buf[20] = '\0';
-
- return g_strdup (buf);
- } else {
- return NULL;
- }
- } else if (len == 10) {
- /* Check for date part only YYYY-MM-DD*/
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[5];
- buf[6] = date_string[6];
- buf[7] = '-';
- buf[8] = date_string[8];
- buf[9] = date_string[9];
- buf[10] = 'T';
- buf[11] = '0';
- buf[12] = '0';
- buf[13] = ':';
- buf[14] = '0';
- buf[15] = '0';
- buf[16] = ':';
- buf[17] = '0';
- buf[18] = '0';
- buf[19] = '\0';
-
- return g_strdup (buf);
- } else if (len == 14) {
- /* Check for pdf format EG 20050315113224-08'00' or
- * 20050216111533Z
- */
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[4];
- buf[6] = date_string[5];
- buf[7] = '-';
- buf[8] = date_string[6];
- buf[9] = date_string[7];
- buf[10] = 'T';
- buf[11] = date_string[8];
- buf[12] = date_string[9];
- buf[13] = ':';
- buf[14] = date_string[10];
- buf[15] = date_string[11];
- buf[16] = ':';
- buf[17] = date_string[12];
- buf[18] = date_string[13];
- buf[19] = '\0';
-
- return g_strdup (buf);
- } else if (len == 15 && date_string[14] == 'Z') {
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[4];
- buf[6] = date_string[5];
- buf[7] = '-';
- buf[8] = date_string[6];
- buf[9] = date_string[7];
- buf[10] = 'T';
- buf[11] = date_string[8];
- buf[12] = date_string[9];
- buf[13] = ':';
- buf[14] = date_string[10];
- buf[15] = date_string[11];
- buf[16] = ':';
- buf[17] = date_string[12];
- buf[18] = date_string[13];
- buf[19] = 'Z';
- buf[20] = '\0';
-
- return g_strdup (buf);
- } else if (len == 21 && (date_string[14] == '-' || date_string[14] == '+' )) {
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[4];
- buf[6] = date_string[5];
- buf[7] = '-';
- buf[8] = date_string[6];
- buf[9] = date_string[7];
- buf[10] = 'T';
- buf[11] = date_string[8];
- buf[12] = date_string[9];
- buf[13] = ':';
- buf[14] = date_string[10];
- buf[15] = date_string[11];
- buf[16] = ':';
- buf[17] = date_string[12];
- buf[18] = date_string[13];
- buf[19] = date_string[14];
- buf[20] = date_string[15];
- buf[21] = date_string[16];
- buf[22] = ':';
- buf[23] = date_string[18];
- buf[24] = date_string[19];
- buf[25] = '\0';
-
- return g_strdup (buf);
- } else if ((len == 24) && (date_string[3] == ' ')) {
- /* Check for msoffice date format "Mon Feb 9 10:10:00 2004" */
- gint num_month;
- gchar mon1;
- gchar day1;
-
- num_month = parse_month (date_string + 4);
-
- mon1 = imonths[num_month];
-
- if (date_string[8] == ' ') {
- day1 = '0';
- } else {
- day1 = date_string[8];
- }
-
- buf[0] = date_string[20];
- buf[1] = date_string[21];
- buf[2] = date_string[22];
- buf[3] = date_string[23];
- buf[4] = '-';
-
- if (num_month < 10) {
- buf[5] = '0';
- buf[6] = mon1;
- } else {
- buf[5] = '1';
- buf[6] = mon1;
- }
-
- buf[7] = '-';
- buf[8] = day1;
- buf[9] = date_string[9];
- buf[10] = 'T';
- buf[11] = date_string[11];
- buf[12] = date_string[12];
- buf[13] = ':';
- buf[14] = date_string[14];
- buf[15] = date_string[15];
- buf[16] = ':';
- buf[17] = date_string[17];
- buf[18] = date_string[18];
- buf[19] = '\0';
-
- return g_strdup (buf);
- } else if ((len == 19) && (date_string[4] == ':') && (date_string[7] == ':')) {
- /* Check for Exif date format "2005:04:29 14:56:54" */
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[5];
- buf[6] = date_string[6];
- buf[7] = '-';
- buf[8] = date_string[8];
- buf[9] = date_string[9];
- buf[10] = 'T';
- buf[11] = date_string[11];
- buf[12] = date_string[12];
- buf[13] = ':';
- buf[14] = date_string[14];
- buf[15] = date_string[15];
- buf[16] = ':';
- buf[17] = date_string[17];
- buf[18] = date_string[18];
- buf[19] = '\0';
-
- return g_strdup (buf);
- } else if ((len == 28) && (date_string[4] == '-') && (date_string[10] == 'T')
- && (date_string[19] == '.') ) {
- /* The fraction of seconds ISO 8601 "YYYY-MM-DDThh:mm:ss.ff+zz:zz" */
- buf[0] = date_string[0];
- buf[1] = date_string[1];
- buf[2] = date_string[2];
- buf[3] = date_string[3];
- buf[4] = '-';
- buf[5] = date_string[5];
- buf[6] = date_string[6];
- buf[7] = '-';
- buf[8] = date_string[8];
- buf[9] = date_string[9];
- buf[10] = 'T';
- buf[11] = date_string[11];
- buf[12] = date_string[12];
- buf[13] = ':';
- buf[14] = date_string[14];
- buf[15] = date_string[15];
- buf[16] = ':';
- buf[17] = date_string[17];
- buf[18] = date_string[18];
- buf[19] = date_string[22];
- buf[20] = date_string[23];
- buf[21] = date_string[24];
- buf[22] = ':';
- buf[23] = date_string[26];
- buf[24] = date_string[27];
- buf[25] = '\0';
-
- return g_strdup (buf);
- }
-
- return g_strdup (date_string);
-}
-
-gchar *
-tracker_date_format_to_iso8601 (const gchar *date_string,
- const gchar *format)
-{
- gchar *result;
- struct tm date_tm = { 0 };
-
- g_return_val_if_fail (date_string != NULL, NULL);
- g_return_val_if_fail (format != NULL, NULL);
-
- if (strptime (date_string, format, &date_tm) == 0) {
- return NULL;
- }
-
- result = g_malloc (sizeof (char)*25);
-
- strftime (result, 25, DATE_FORMAT_ISO8601 , &date_tm);
-
- return result;
-}
-
-gchar *
-tracker_date_to_time_string (const gchar *date_string)
-{
- gchar *str;
-
- str = tracker_date_format (date_string);
-
- if (str) {
- time_t t;
-
- t = tracker_string_to_date (str);
-
- g_free (str);
-
- if (t != -1) {
- return tracker_gint_to_string (t);
- }
- }
-
- return NULL;
-}
-
-time_t
-tracker_string_to_date (const gchar *date_string)
-{
- static GRegex *regex = NULL;
-
- GMatchInfo *match_info;
- gchar *match;
- struct tm tm;
- time_t t;
-
- g_return_val_if_fail (date_string, -1);
-
- /* We should have a valid iso 8601 date in format
- * YYYY-MM-DDThh:mm:ss with optional TZ
- */
-
- if (!regex) {
- GError *e = NULL;
- regex = g_regex_new ("^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])T([0-9][0-9]):([0-9][0-9]):([0-9][0-9])(\\.[0-9]+)?(Z|((\\+|-)[0-9][0-9]):?([0-9][0-9]))?$", 0, 0, &e);
- if (e) {
- g_error ("%s", e->message);
- }
- }
-
- if (!g_regex_match (regex, date_string, 0, &match_info)) {
- g_match_info_free (match_info);
- return -1;
- }
-
- memset (&tm, 0, sizeof (struct tm));
-
- /* year */
- match = g_match_info_fetch (match_info, 1);
- tm.tm_year = atoi (match) - 1900;
- g_free (match);
-
- /* month */
- match = g_match_info_fetch (match_info, 2);
- tm.tm_mon = atoi (match) - 1;
- g_free (match);
-
- /* day of month */
- match = g_match_info_fetch (match_info, 3);
- tm.tm_mday = atoi (match);
- g_free (match);
-
- /* hour */
- match = g_match_info_fetch (match_info, 4);
- tm.tm_hour = atoi (match);
- g_free (match);
-
- /* minute */
- match = g_match_info_fetch (match_info, 5);
- tm.tm_min = atoi (match);
- g_free (match);
-
- /* second */
- match = g_match_info_fetch (match_info, 6);
- tm.tm_sec = atoi (match);
- g_free (match);
-
- match = g_match_info_fetch (match_info, 8);
- if (match) {
- /* timezoned */
- g_free (match);
-
- /* mktime() always assumes that "tm" is in locale time but we
- * want to keep control on time, so we go to UTC
- */
- t = mktime (&tm);
- t -= timezone;
-
- match = g_match_info_fetch (match_info, 9);
- if (match) {
- /* non-UTC timezone */
- t -= atoi (match) * 3600;
- g_free (match);
-
- match = g_match_info_fetch (match_info, 10);
- t -= atoi (match) * 60;
- g_free (match);
- }
- } else {
- /* local time */
- tm.tm_isdst = -1;
- t = mktime (&tm);
- }
-
- g_match_info_free (match_info);
-
- return t;
-}
-
-gchar *
-tracker_date_to_string (time_t date_time)
-{
- gchar buffer[30];
- struct tm utc_time;
- size_t count;
-
- memset (buffer, '\0', sizeof (buffer));
- memset (&utc_time, 0, sizeof (struct tm));
-
- gmtime_r (&date_time, &utc_time);
-
- /* Output is ISO 8160 format : "YYYY-MM-DDThh:mm:ssZ" */
- count = strftime (buffer, sizeof (buffer), "%FT%TZ", &utc_time);
-
- return count > 0 ? g_strdup (buffer) : NULL;
-}
-
gchar *
tracker_glong_to_string (glong i)
{
diff --git a/src/libtracker-common/tracker-type-utils.h b/src/libtracker-common/tracker-type-utils.h
index 4d5ae19..1a8fa34 100644
--- a/src/libtracker-common/tracker-type-utils.h
+++ b/src/libtracker-common/tracker-type-utils.h
@@ -29,12 +29,6 @@ G_BEGIN_DECLS
#error "only <libtracker-common/tracker-common.h> must be included directly."
#endif
-gchar * tracker_date_format (const gchar *date_string);
-gchar * tracker_date_format_to_iso8601 (const gchar *date_string,
- const gchar *format);
-gchar * tracker_date_to_time_string (const gchar *date_string);
-time_t tracker_string_to_date (const gchar *date_string);
-gchar * tracker_date_to_string (time_t date_time);
gchar * tracker_glong_to_string (glong i);
gchar * tracker_gint_to_string (gint i);
gchar * tracker_guint_to_string (guint i);
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 7c53be0..db8d6e5 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -25,7 +25,7 @@
#include <time.h>
#include <libtracker-common/tracker-common.h>
-#include <libtracker-common/tracker-type-utils.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-file-utils.h>
#include <libtracker-common/tracker-ontology.h>
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index 7cb1f01..a9fa3c3 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -567,7 +567,7 @@ public class Tracker.SparqlQuery : Object {
throw new SparqlError.TYPE ("`%s' is not a valid boolean".printf (binding.literal));
}
} else if (binding.data_type == PropertyType.DATETIME) {
- stmt.bind_int (i, string_to_date (binding.literal));
+ stmt.bind_int (i, string_to_date (binding.literal, null));
} else if (binding.data_type == PropertyType.INTEGER) {
stmt.bind_int (i, binding.literal.to_int ());
} else {
diff --git a/src/libtracker-db/tracker-db-manager.c b/src/libtracker-db/tracker-db-manager.c
index a1bae21..cc78a10 100644
--- a/src/libtracker-db/tracker-db-manager.c
+++ b/src/libtracker-db/tracker-db-manager.c
@@ -33,10 +33,10 @@
#include <glib/gstdio.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-file-utils.h>
#include <libtracker-common/tracker-ontology.h>
#include <libtracker-common/tracker-property.h>
-#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-common/tracker-utils.h>
#include "tracker-db-journal.h"
diff --git a/src/libtracker-extract/tracker-exif.c b/src/libtracker-extract/tracker-exif.c
index 5506ac8..6337c9b 100644
--- a/src/libtracker-extract/tracker-exif.c
+++ b/src/libtracker-extract/tracker-exif.c
@@ -26,7 +26,7 @@
#include <ctype.h>
#include <glib.h>
-#include <libtracker-common/tracker-type-utils.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-utils.h>
#include "tracker-exif.h"
diff --git a/src/libtracker-extract/tracker-iptc.c b/src/libtracker-extract/tracker-iptc.c
index 83a29be..783685b 100644
--- a/src/libtracker-extract/tracker-iptc.c
+++ b/src/libtracker-extract/tracker-iptc.c
@@ -23,7 +23,7 @@
#include <glib.h>
-#include <libtracker-common/tracker-type-utils.h>
+#include <libtracker-common/tracker-date-time.h>
#include "tracker-iptc.h"
diff --git a/src/plugins/evolution/tracker-evolution-plugin.c b/src/plugins/evolution/tracker-evolution-plugin.c
index c465eca..79d2c8f 100644
--- a/src/plugins/evolution/tracker-evolution-plugin.c
+++ b/src/plugins/evolution/tracker-evolution-plugin.c
@@ -74,6 +74,7 @@
#include <libtracker-client/tracker.h>
#include <libtracker-client/tracker-sparql-builder.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-ontology.h>
#include <libtracker-common/tracker-utils.h>
#include <libtracker-common/tracker-type-utils.h>
@@ -1724,7 +1725,7 @@ on_register_client_qry (GPtrArray *results,
} else {
for (i = 0; i < results->len; i++) {
const gchar **str = g_ptr_array_index (results, i);
- info->last_checkout = (guint64) tracker_string_to_date (str[0]);
+ info->last_checkout = (guint64) tracker_string_to_date (str[0], NULL);
break;
}
}
diff --git a/src/tracker-extract/tracker-extract-mp3.c b/src/tracker-extract/tracker-extract-mp3.c
index fe9470d..f1f16a2 100644
--- a/src/tracker-extract/tracker-extract-mp3.c
+++ b/src/tracker-extract/tracker-extract-mp3.c
@@ -43,10 +43,10 @@
#include <enca.h>
#endif
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-file-utils.h>
#include <libtracker-common/tracker-ontology.h>
#include <libtracker-common/tracker-utils.h>
-#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-extract/tracker-extract.h>
#include <libtracker-extract/tracker-utils.h>
diff --git a/src/tracker-extract/tracker-extract-pdf.c b/src/tracker-extract/tracker-extract-pdf.c
index 41eb6d7..7dd825a 100644
--- a/src/tracker-extract/tracker-extract-pdf.c
+++ b/src/tracker-extract/tracker-extract-pdf.c
@@ -25,8 +25,8 @@
#include <glib.h>
#include <poppler.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-ontology.h>
-#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-common/tracker-utils.h>
#include <libtracker-common/tracker-type-utils.h>
diff --git a/src/tracker-extract/tracker-extract-png.c b/src/tracker-extract/tracker-extract-png.c
index 6cdcec7..36c9347 100644
--- a/src/tracker-extract/tracker-extract-png.c
+++ b/src/tracker-extract/tracker-extract-png.c
@@ -36,6 +36,7 @@
#include <glib.h>
#include <glib/gstdio.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-ontology.h>
#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-common/tracker-file-utils.h>
diff --git a/src/tracker-extract/tracker-extract-ps.c b/src/tracker-extract/tracker-extract-ps.c
index 543de10..728c5e2 100644
--- a/src/tracker-extract/tracker-extract-ps.c
+++ b/src/tracker-extract/tracker-extract-ps.c
@@ -33,6 +33,7 @@
#include <glib.h>
#include <glib/gstdio.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-file-utils.h>
#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-common/tracker-os-dependant.h>
diff --git a/src/tracker-miner-fs/tracker-miner-files.c b/src/tracker-miner-fs/tracker-miner-files.c
index 91049be..5db9689 100644
--- a/src/tracker-miner-fs/tracker-miner-files.c
+++ b/src/tracker-miner-fs/tracker-miner-files.c
@@ -28,6 +28,7 @@
#include <glib/gi18n.h>
#include <glib/gstdio.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-ontology.h>
#include <libtracker-common/tracker-power.h>
#include <libtracker-common/tracker-storage.h>
diff --git a/src/tracker-miner-fs/tracker-volume-cleanup.c b/src/tracker-miner-fs/tracker-volume-cleanup.c
index 6c8356b..5a1c691 100644
--- a/src/tracker-miner-fs/tracker-volume-cleanup.c
+++ b/src/tracker-miner-fs/tracker-volume-cleanup.c
@@ -23,6 +23,7 @@
#include <gio/gio.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-utils.h>
#include <libtracker-common/tracker-type-utils.h>
#include <libtracker-db/tracker-db-manager.h>
diff --git a/tests/libtracker-common/tracker-type-utils-test.c b/tests/libtracker-common/tracker-type-utils-test.c
index 1034b3a..10fc7ba 100644
--- a/tests/libtracker-common/tracker-type-utils-test.c
+++ b/tests/libtracker-common/tracker-type-utils-test.c
@@ -22,6 +22,7 @@
#include <glib-object.h>
+#include <libtracker-common/tracker-date-time.h>
#include <libtracker-common/tracker-type-utils.h>
#include <tracker-test-helpers.h>
@@ -85,7 +86,7 @@ test_string_to_date (void)
expected = g_date_new_dmy (16, G_DATE_JUNE, 2008);
- result_time_t = tracker_string_to_date (input);
+ result_time_t = tracker_string_to_date (input, NULL);
result = g_date_new ();
g_date_set_time_t (result, result_time_t);
@@ -100,18 +101,18 @@ test_string_to_date (void)
g_assert_cmpint (g_date_get_month (expected), ==, g_date_get_month (result));
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) {
- result_time_t = tracker_string_to_date (NULL);
+ result_time_t = tracker_string_to_date (NULL, NULL);
}
g_test_trap_assert_failed ();
- result_time_t = tracker_string_to_date ("");
+ result_time_t = tracker_string_to_date ("", NULL);
g_assert_cmpint (result_time_t, ==, -1);
- result_time_t = tracker_string_to_date ("i am not a date");
+ result_time_t = tracker_string_to_date ("i am not a date", NULL);
g_assert_cmpint (result_time_t, ==, -1);
/* Fails! Check the code
- result_time_t = tracker_string_to_date ("2008-06-32T04:23:10+0000");
+ result_time_t = tracker_string_to_date ("2008-06-32T04:23:10+0000", NULL);
g_assert_cmpint (result_time_t, ==, -1);
*/
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]