Change purple_log_new to use GDateTime.

Tue, 11 Jul 2017 23:43:33 -0400

author
Elliott Sales de Andrade <qulogic@pidgin.im>
date
Tue, 11 Jul 2017 23:43:33 -0400
changeset 38620
b02941b9fa9a
parent 38619
2121337626ee
child 38621
1412d6b993e9

Change purple_log_new to use GDateTime.

finch/gntlog.c file | annotate | diff | comparison | revisions
libpurple/account.c file | annotate | diff | comparison | revisions
libpurple/conversation.c file | annotate | diff | comparison | revisions
libpurple/log.c file | annotate | diff | comparison | revisions
libpurple/log.h file | annotate | diff | comparison | revisions
libpurple/plugins/log_reader.c file | annotate | diff | comparison | revisions
pidgin/gtklog.c file | annotate | diff | comparison | revisions
pidgin/plugins/history.c file | annotate | diff | comparison | revisions
--- a/finch/gntlog.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/finch/gntlog.c	Tue Jul 11 23:43:33 2017 -0400
@@ -96,12 +96,14 @@
 	return ret;
 }
 
-static const char *log_get_date(PurpleLog *log)
+static gchar *log_get_date(PurpleLog *log)
 {
-	if (log->tm)
-		return purple_date_format_full(log->tm);
-	else
-		return purple_date_format_full(localtime(&log->time));
+	GDateTime *dt;
+	gchar *ret;
+	dt = g_date_time_to_local(log->time);
+	ret = g_date_time_format(dt, "%c");
+	g_date_time_unref(dt);
+	return ret;
 }
 
 static void search_cb(GntWidget *button, FinchLogViewer *lv)
@@ -132,11 +134,13 @@
 		char *read = purple_log_read((PurpleLog*)logs->data, NULL);
 		if (read && *read && purple_strcasestr(read, search_term)) {
 			PurpleLog *log = logs->data;
+			gchar *log_date = log_get_date(log);
 
 			gnt_tree_add_row_last(GNT_TREE(lv->tree),
 									log,
-									gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
+									gnt_tree_create_row(GNT_TREE(lv->tree), log_date),
 									NULL);
+			g_free(log_date);
 		}
 		g_free(read);
 	}
@@ -183,15 +187,17 @@
 		return;
 
 	if (log->type != PURPLE_LOG_SYSTEM) {
+		gchar *log_date = log_get_date(log);
 		char *title;
 		if (log->type == PURPLE_LOG_CHAT)
 			title = g_strdup_printf(_("Conversation in %s on %s"),
-									log->name, log_get_date(log));
+			                        log->name, log_date);
 		else
 			title = g_strdup_printf(_("Conversation with %s on %s"),
-									log->name, log_get_date(log));
+			                        log->name, log_date);
 
 		gnt_label_set_text(GNT_LABEL(viewer->label), title);
+		g_free(log_date);
 		g_free(title);
 	}
 
@@ -223,16 +229,18 @@
      /* Logs are made from trees in real life.
         This is a tree made from logs */
 {
-	const char *pmonth;
-	char *month = NULL;
+	gchar *pmonth;
+	gchar *month = NULL;
 	char prev_top_month[30] = "";
 	GList *logs = lv->logs;
 
 	while (logs != NULL) {
 		PurpleLog *log = logs->data;
+		GDateTime *dt;
+		gchar *log_date;
 
-		pmonth = purple_utf8_strftime(_("%B %Y"),
-		                           log->tm ? log->tm : localtime(&log->time));
+		dt = g_date_time_to_local(log->time);
+		pmonth = g_date_time_format(dt, _("%B %Y"));
 
 		if (!purple_strequal(pmonth, prev_top_month)) {
 			month = g_strdup(pmonth);
@@ -247,11 +255,15 @@
 		}
 
 		/* sub */
+		log_date = g_date_time_format(dt, "%c");
 		gnt_tree_add_row_last(GNT_TREE(lv->tree),
 								log,
-								gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
+								gnt_tree_create_row(GNT_TREE(lv->tree), log_date),
 								month);
 
+		g_free(log_date);
+		g_free(pmonth);
+		g_date_time_unref(dt);
 		logs = logs->next;
 	}
 }
--- a/libpurple/account.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/libpurple/account.c	Tue Jul 11 23:43:33 2017 -0400
@@ -2218,13 +2218,20 @@
 	if(!priv->system_log && create){
 		PurplePresence *presence;
 		int login_time;
+		GDateTime *dt;
 
 		presence = purple_account_get_presence(account);
 		login_time = purple_presence_get_login_time(presence);
-
-		priv->system_log	 = purple_log_new(PURPLE_LOG_SYSTEM,
-				purple_account_get_username(account), account, NULL,
-				(login_time != 0) ? login_time : time(NULL), NULL);
+		if (login_time != 0) {
+			dt = g_date_time_new_from_unix_local(login_time);
+		} else {
+			dt = g_date_time_new_now_local();
+		}
+
+		priv->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
+		                                  purple_account_get_username(account),
+		                                  account, NULL, dt);
+		g_date_time_unref(dt);
 	}
 
 	return priv->system_log;
--- a/libpurple/conversation.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/libpurple/conversation.c	Tue Jul 11 23:43:33 2017 -0400
@@ -197,12 +197,15 @@
 open_log(PurpleConversation *conv)
 {
 	PurpleConversationPrivate *priv = PURPLE_CONVERSATION_GET_PRIVATE(conv);
+	GDateTime *dt;
 
 	g_return_if_fail(priv != NULL);
 
+	dt = g_date_time_new_now_local();
 	priv->logs = g_list_append(NULL, purple_log_new(PURPLE_IS_CHAT_CONVERSATION(conv) ? PURPLE_LOG_CHAT :
 							   PURPLE_LOG_IM, priv->name, priv->account,
-							   conv, time(NULL), NULL));
+							   conv, dt));
+	g_date_time_unref(dt);
 }
 
 /* Functions that deal with PurpleMessage history */
--- a/libpurple/log.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/libpurple/log.c	Tue Jul 11 23:43:33 2017 -0400
@@ -75,7 +75,7 @@
  **************************************************************************/
 
 PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
-                      PurpleConversation *conv, time_t time, const struct tm *tm)
+                      PurpleConversation *conv, GDateTime *time)
 {
 	PurpleLog *log;
 
@@ -87,33 +87,13 @@
 	log->name = g_strdup(purple_normalize(account, name));
 	log->account = account;
 	log->conv = conv;
-	log->time = time;
+	if (time)
+		log->time = g_date_time_ref(time);
+	else
+		log->time = NULL;
 	log->logger = purple_log_logger_get();
 	log->logger_data = NULL;
 
-	if (tm == NULL)
-		log->tm = NULL;
-	else
-	{
-		/* There's no need to zero this as we immediately do a direct copy. */
-		log->tm = g_slice_new(struct tm);
-
-		*(log->tm) = *tm;
-
-#ifdef HAVE_STRUCT_TM_TM_ZONE
-		/* XXX: This is so wrong... */
-		if (log->tm->tm_zone != NULL)
-		{
-			char *tmp = g_locale_from_utf8(log->tm->tm_zone, -1, NULL, NULL, NULL);
-			if (tmp != NULL)
-				log->tm->tm_zone = tmp;
-			else
-				/* Just shove the UTF-8 bytes in and hope... */
-				log->tm->tm_zone = g_strdup(log->tm->tm_zone);
-		}
-#endif
-	}
-
 	if (log->logger && log->logger->create)
 		log->logger->create(log);
 	return log;
@@ -125,15 +105,7 @@
 	if (log->logger && log->logger->finalize)
 		log->logger->finalize(log);
 	g_free(log->name);
-
-	if (log->tm != NULL)
-	{
-#ifdef HAVE_STRUCT_TM_TM_ZONE
-		/* XXX: This is so wrong... */
-		g_free((char *)log->tm->tm_zone);
-#endif
-		g_slice_free(struct tm, log->tm);
-	}
+	g_date_time_unref(log->time);
 
 	PURPLE_DBUS_UNREGISTER_POINTER(log);
 	g_slice_free(PurpleLog, log);
@@ -266,8 +238,6 @@
 	int score;
 	GSList *n;
 	struct _purple_logsize_user *lu;
-	time_t now;
-	time(&now);
 
 	lu = g_new(struct _purple_logsize_user, 1);
 	lu->name = g_strdup(purple_normalize(account, name));
@@ -278,6 +248,7 @@
 		g_free(lu->name);
 		g_free(lu);
 	} else {
+		GDateTime *now = g_date_time_new_now_utc();
 		double score_double = 0.0;
 		for (n = loggers; n; n = n->next) {
 			PurpleLogLogger *logger = n->data;
@@ -294,12 +265,13 @@
 					/* Activity score counts bytes in the log, exponentially
 					   decayed with a half-life of 14 days. */
 					score_double += purple_log_get_size(log) *
-						pow(0.5, difftime(now, log->time)/1209600.0);
+						pow(0.5, g_date_time_difference(now, log->time)/(14LL*G_TIME_SPAN_DAY));
 					purple_log_free(log);
 					logs = g_list_delete_link(logs, logs);
 				}
 			}
 		}
+		g_date_time_unref(now);
 
 		score = (gint) ceil(score_double);
 		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(score));
@@ -508,7 +480,7 @@
 	const PurpleLog *a = y;
 	const PurpleLog *b = z;
 
-	return b->time - a->time;
+	return g_date_time_compare(b->time, a->time); // TODO: swap?
 }
 
 GList *purple_log_get_logs(PurpleLogType type, const char *name, PurpleAccount *account)
@@ -910,9 +882,9 @@
 	{
 		/* This log is new */
 		char *dir;
-		struct tm *tm;
+		GDateTime *dt;
 		const char *tz;
-		const char *date;
+		gchar *date;
 		char *filename;
 		char *path;
 
@@ -922,14 +894,16 @@
 
 		purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
 
-		tm = localtime(&log->time);
-		tz = purple_escape_filename(purple_utf8_strftime("%Z", tm));
-		date = purple_utf8_strftime("%Y-%m-%d.%H%M%S%z", tm);
+		dt = g_date_time_to_local(log->time);
+		tz = purple_escape_filename(g_date_time_get_timezone_abbreviation(dt));
+		date = g_date_time_format(dt, "%Y-%m-%d.%H%M%S%z");
+		g_date_time_unref(dt);
 
 		filename = g_strdup_printf("%s%s%s", date, tz, ext ? ext : "");
 
 		path = g_build_filename(dir, filename, NULL);
 		g_free(dir);
+		g_free(date);
 		g_free(filename);
 
 		log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
@@ -979,39 +953,16 @@
 		{
 			PurpleLog *log;
 			PurpleLogCommonLoggerData *data;
-			struct tm tm;
-#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE)
-			long tz_off;
-			const char *rest, *end;
-			time_t stamp = purple_str_to_time(purple_unescape_filename(filename), FALSE, &tm, &tz_off, &rest);
-
-			/* As zero is a valid offset, PURPLE_NO_TZ_OFF means no offset was
-			 * provided. See util.h. Yes, it's kinda ugly. */
-			if (tz_off != PURPLE_NO_TZ_OFF)
-				tm.tm_gmtoff = tz_off - tm.tm_gmtoff;
+			GDateTime *stamp = purple_str_to_date_time(purple_unescape_filename(filename), FALSE);
 
-			if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL)
-			{
-				log = purple_log_new(type, name, account, NULL, stamp, NULL);
-			}
-			else
-			{
-				char *tmp = g_strndup(rest, end - rest);
-				tm.tm_zone = tmp;
-				log = purple_log_new(type, name, account, NULL, stamp, &tm);
-				g_free(tmp);
-			}
-#else
-			time_t stamp = purple_str_to_time(filename, FALSE, &tm, NULL, NULL);
-
-			log = purple_log_new(type, name, account, NULL, stamp, (stamp != 0) ?  &tm : NULL);
-#endif
-
+			log = purple_log_new(type, name, account, NULL, stamp);
 			log->logger = logger;
 			log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
 
 			data->path = g_build_filename(path, filename, NULL);
 			list = g_list_prepend(list, log);
+
+			g_date_time_unref(stamp);
 		}
 	}
 	g_dir_close(dir);
@@ -1303,7 +1254,8 @@
 
 	if(!data) {
 		const char *proto = purple_protocol_class_list_icon(protocol, log->account, NULL);
-		const char *date;
+		GDateTime *dt;
+		gchar *date;
 		purple_log_common_writer(log, ".html");
 
 		data = log->logger_data;
@@ -1312,7 +1264,9 @@
 		if(!data->file)
 			return 0;
 
-		date = purple_date_format_full(localtime(&log->time));
+		dt = g_date_time_to_local(log->time);
+		date = g_date_time_format(dt, "%c");
+		g_date_time_unref(dt);
 
 		written += fprintf(data->file, "<html><head>");
 		written += fprintf(data->file, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
@@ -1327,6 +1281,7 @@
 		written += fprintf(data->file, "%s", header);
 		written += fprintf(data->file, "</title></head><body>");
 		written += fprintf(data->file, "<h3>%s</h3>\n", header);
+		g_free(date);
 		g_free(header);
 	}
 
@@ -1462,6 +1417,8 @@
 		 * that you open a convo with someone, but don't say anything.
 		 */
 		const char *proto = purple_protocol_class_list_icon(protocol, log->account, NULL);
+		GDateTime *dt;
+		gchar *date;
 		purple_log_common_writer(log, ".txt");
 
 		data = log->logger_data;
@@ -1470,14 +1427,18 @@
 		if(!data || !data->file)
 			return 0;
 
+		dt = g_date_time_to_local(log->time);
+		date = g_date_time_format(dt, "%c");
 		if (log->type == PURPLE_LOG_SYSTEM)
 			written += fprintf(data->file, "System log for account %s (%s) connected at %s\n",
 				purple_account_get_username(log->account), proto,
-				purple_date_format_full(localtime(&log->time)));
+				date);
 		else
 			written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n",
-				log->name, purple_date_format_full(localtime(&log->time)),
+				log->name, date,
 				purple_account_get_username(log->account), proto);
+		g_free(date);
+		g_date_time_unref(dt);
 	}
 
 	/* if we can't write to the file, give up before we hurt ourselves */
@@ -1594,13 +1555,13 @@
 	int file_fd, index_fd;
 	char *index_tmp;
 	char buf[BUF_LONG];
-	struct tm tm;
-	char month[4];
+	gint year, month, day, hour, minute, second;
+	char month_str[4];
 	struct old_logger_data *data = NULL;
 	int logfound = 0;
 	int lastoff = 0;
 	int newlen;
-	time_t lasttime = 0;
+	GDateTime *lasttime = NULL;
 
 	PurpleLog *log = NULL;
 	GList *list = NULL;
@@ -1657,9 +1618,9 @@
 					unsigned long idx_time;
 					if (sscanf(buf, "%d\t%d\t%lu", &lastoff, &newlen, &idx_time) == 3)
 					{
-						log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+						log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, NULL);
 						log->logger = old_logger;
-						log->time = (time_t)idx_time;
+						log->time = g_date_time_new_from_unix_local(idx_time);
 
 						/* IMPORTANT: Always set all members of struct old_logger_data */
 						data = g_slice_new(struct old_logger_data);
@@ -1734,9 +1695,9 @@
 					newlen--;
 
 				if (newlen != 0) {
-					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, NULL);
 					log->logger = old_logger;
-					log->time = lasttime;
+					log->time = g_date_time_ref(lasttime);
 
 					/* IMPORTANT: Always set all members of struct old_logger_data */
 					data = g_slice_new(struct old_logger_data);
@@ -1757,49 +1718,48 @@
 			lastoff = offset;
 
 			g_snprintf(convostart, length, "%s", temp);
-			memset(&tm, 0, sizeof(tm));
-			if (sscanf(convostart, "%*s %3s %d %d:%d:%d %d", month,
-				&tm.tm_mday, &tm.tm_hour, &tm.tm_min,
-				&tm.tm_sec, &tm.tm_year) != 6)
+			year = month = day = hour = minute = second = 0;
+			if (sscanf(convostart, "%*s %3s %d %d:%d:%d %d", month_str,
+				&day, &hour, &minute, &second, &year) != 6)
 			{
 				purple_debug_warning("log", "invalid date format\n");
 			}
 			/* Ugly hack, in case current locale is not English */
-			if (purple_strequal(month, "Jan")) {
-				tm.tm_mon= 0;
-			} else if (purple_strequal(month, "Feb")) {
-				tm.tm_mon = 1;
-			} else if (purple_strequal(month, "Mar")) {
-				tm.tm_mon = 2;
-			} else if (purple_strequal(month, "Apr")) {
-				tm.tm_mon = 3;
-			} else if (purple_strequal(month, "May")) {
-				tm.tm_mon = 4;
-			} else if (purple_strequal(month, "Jun")) {
-				tm.tm_mon = 5;
-			} else if (purple_strequal(month, "Jul")) {
-				tm.tm_mon = 6;
-			} else if (purple_strequal(month, "Aug")) {
-				tm.tm_mon = 7;
-			} else if (purple_strequal(month, "Sep")) {
-				tm.tm_mon = 8;
-			} else if (purple_strequal(month, "Oct")) {
-				tm.tm_mon = 9;
-			} else if (purple_strequal(month, "Nov")) {
-				tm.tm_mon = 10;
-			} else if (purple_strequal(month, "Dec")) {
-				tm.tm_mon = 11;
+			if (purple_strequal(month_str, "Jan")) {
+				month = 1;
+			} else if (purple_strequal(month_str, "Feb")) {
+				month = 2;
+			} else if (purple_strequal(month_str, "Mar")) {
+				month = 3;
+			} else if (purple_strequal(month_str, "Apr")) {
+				month = 4;
+			} else if (purple_strequal(month_str, "May")) {
+				month = 5;
+			} else if (purple_strequal(month_str, "Jun")) {
+				month = 6;
+			} else if (purple_strequal(month_str, "Jul")) {
+				month = 7;
+			} else if (purple_strequal(month_str, "Aug")) {
+				month = 8;
+			} else if (purple_strequal(month_str, "Sep")) {
+				month = 9;
+			} else if (purple_strequal(month_str, "Oct")) {
+				month = 10;
+			} else if (purple_strequal(month_str, "Nov")) {
+				month = 11;
+			} else if (purple_strequal(month_str, "Dec")) {
+				month = 12;
 			}
-			tm.tm_year -= 1900;
-			lasttime = mktime(&tm);
+			lasttime = g_date_time_new_local(year, month, day,
+			                                 hour, minute, second);
 		}
 	}
 
 	if (logfound) {
 		if ((newlen = ftell(file) - lastoff) != 0) {
-			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, NULL);
 			log->logger = old_logger;
-			log->time = lasttime;
+			log->time = g_date_time_ref(lasttime);
 
 			/* IMPORTANT: Always set all members of struct old_logger_data */
 			data = g_slice_new(struct old_logger_data);
--- a/libpurple/log.h	Tue Jul 11 05:27:50 2017 -0400
+++ b/libpurple/log.h	Tue Jul 11 23:43:33 2017 -0400
@@ -139,10 +139,6 @@
  *               timezone
  * @logger:      The logging mechanism this log is to use
  * @logger_data: Data used by the log logger
- * @tm:          The time this conversation started, saved with original
- *               timezone data, if available and if struct tm has the BSD
- *               timezone fields, else %NULL. Do NOT modify anything in this
- *               struct.
  *
  * A log.  Not the wooden type.
  */
@@ -151,11 +147,10 @@
 	char *name;
 	PurpleAccount *account;
 	PurpleConversation *conv;
-	time_t time;
+	GDateTime *time;
 
 	PurpleLogLogger *logger;
 	void *logger_data;
-	struct tm *tm;
 
 	/* IMPORTANT: Some code in log.c allocates these without zeroing them.
 	 * IMPORTANT: Update that code if you add members here. */
@@ -225,15 +220,13 @@
  * @account:     The account the conversation is occurring on
  * @conv:        The conversation being logged
  * @time:        The time this conversation started
- * @tm:          The time this conversation started, with timezone data,
- *                    if available and if struct tm has the BSD timezone fields.
  *
  * Creates a new log
  *
  * Returns:            The new log
  */
 PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
-                      PurpleConversation *conv, time_t time, const struct tm *tm);
+                      PurpleConversation *conv, GDateTime *time);
 
 /**
  * purple_log_free:
--- a/libpurple/plugins/log_reader.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/libpurple/plugins/log_reader.c	Tue Jul 11 23:43:33 2017 -0400
@@ -95,12 +95,12 @@
 			if (!purple_str_has_prefix(file, sn))
 				continue;
 			if (purple_str_has_suffix(file, ".html") || purple_str_has_suffix(file, ".AdiumHTMLLog")) {
-				struct tm tm;
+				GDateTime *dt;
+				gint year, month, day, hour, minute, second;
 				const char *date = file;
 
 				date += strlen(sn) + 2;
-				if (sscanf(date, "%u|%u|%u",
-						&tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) {
+				if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
 
 					purple_debug_error("Adium log parse",
 					                   "Filename timestamp parsing error\n");
@@ -134,7 +134,7 @@
 						contents2++;
 
 					if (sscanf(contents2, "%u.%u.%u",
-							&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) {
+							&hour, &minute, &second) != 3) {
 
 						purple_debug_error("Adium log parse",
 						                   "Contents timestamp parsing error\n");
@@ -146,23 +146,24 @@
 					data->path = filename;
 					data->type = ADIUM_HTML;
 
-					tm.tm_year -= 1900;
-					tm.tm_mon  -= 1;
-
-					/* XXX: Look into this later... Should we pass in a struct tm? */
-					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
+					/* XXX: Look into this later... Should we figure out a timezone? */
+					dt = g_date_time_new_local(year, month, day, hour, minute, second);
+
+					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
 					log->logger = adium_logger;
 					log->logger_data = data;
 
+					g_date_time_unref(dt);
+
 					list = g_list_prepend(list, log);
 				}
 			} else if (purple_str_has_suffix(file, ".adiumLog")) {
-				struct tm tm;
+				GDateTime *dt;
+				gint year, month, day, hour, minute, second;
 				const char *date = file;
 
 				date += strlen(sn) + 2;
-				if (sscanf(date, "%u|%u|%u",
-						&tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) {
+				if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
 
 					purple_debug_error("Adium log parse",
 					                   "Filename timestamp parsing error\n");
@@ -190,8 +191,7 @@
 					if (*contents2)
 						contents2++;
 
-					if (sscanf(contents2, "%u.%u.%u",
-							&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) {
+					if (sscanf(contents2, "%u.%u.%u", &hour, &minute, &second) != 3) {
 
 						purple_debug_error("Adium log parse",
 						                   "Contents timestamp parsing error\n");
@@ -199,18 +199,19 @@
 						continue;
 					}
 
-					tm.tm_year -= 1900;
-					tm.tm_mon  -= 1;
-
 					data = g_new0(struct adium_logger_data, 1);
 					data->path = filename;
 					data->type = ADIUM_TEXT;
 
-					/* XXX: Look into this later... Should we pass in a struct tm? */
-					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
+					/* XXX: Look into this later... Should we figure out a timezone? */
+					dt = g_date_time_new_local(year, month, day, hour, minute, second);
+
+					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
 					log->logger = adium_logger;
 					log->logger_data = data;
 
+					g_date_time_unref(dt);
+
 					list = g_list_prepend(list, log);
 				}
 			}
@@ -337,11 +338,11 @@
 /* This function is really confusing.  It makes baby rlaager cry...
    In other news: "You lost a lot of blood but we found most of it."
  */
-static time_t msn_logger_parse_timestamp(PurpleXmlNode *message, struct tm **tm_out)
+static GDateTime *
+msn_logger_parse_timestamp(PurpleXmlNode *message)
 {
 	const char *datetime;
-	static struct tm tm2;
-	time_t stamp;
+	GDateTime *stamp;
 	const char *date;
 	const char *time;
 	int month;
@@ -352,47 +353,26 @@
 	int sec;
 	char am_pm;
 	char *str;
-	static struct tm tm;
-	time_t t;
-	time_t diff;
-
-#ifndef G_DISABLE_CHECKS
-	if (message != NULL)
-	{
-		*tm_out = NULL;
-
-		/* Trigger the usual warning. */
-		g_return_val_if_fail(message != NULL, (time_t)0);
-	}
-#endif
+	GDateTime *t;
+	GTimeSpan diff;
+
+	g_return_val_if_fail(message != NULL, NULL);
 
 	datetime = purple_xmlnode_get_attrib(message, "DateTime");
 	if (!(datetime && *datetime))
 	{
 		purple_debug_error("MSN log timestamp parse",
 		                   "Attribute missing: %s\n", "DateTime");
-		return (time_t)0;
+		return NULL;
 	}
 
-	stamp = purple_str_to_time(datetime, TRUE, &tm2, NULL, NULL);
-#ifdef HAVE_TM_GMTOFF
-	tm2.tm_gmtoff = 0;
-#endif
-#ifdef HAVE_STRUCT_TM_TM_ZONE
-	/* This is used in the place of a timezone abbreviation if the
-	 * offset is way off.  The user should never really see it, but
-	 * it's here just in case.  The parens are to make it clear it's
-	 * not a real timezone. */
-	tm2.tm_zone = _("(UTC)");
-#endif
-
+	stamp = purple_str_to_date_time(datetime, TRUE);
 
 	date = purple_xmlnode_get_attrib(message, "Date");
 	if (!(date && *date))
 	{
 		purple_debug_error("MSN log timestamp parse",
 		                   "Attribute missing: %s\n", "Date");
-		*tm_out = &tm2;
 		return stamp;
 	}
 
@@ -401,7 +381,6 @@
 	{
 		purple_debug_error("MSN log timestamp parse",
 		                   "Attribute missing: %s\n", "Time");
-		*tm_out = &tm2;
 		return stamp;
 	}
 
@@ -409,7 +388,6 @@
 	{
 		purple_debug_error("MSN log timestamp parse",
 		                   "%s parsing error\n", "Date");
-		*tm_out = &tm2;
 		return stamp;
 	}
 	else
@@ -426,7 +404,6 @@
 	{
 		purple_debug_error("MSN log timestamp parse",
 		                   "%s parsing error\n", "Time");
-		*tm_out = &tm2;
 		return stamp;
 	}
 
@@ -438,34 +415,30 @@
         }
 
 	str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
-	t = purple_str_to_time(str, TRUE, &tm, NULL, NULL);
-
-
-	if (stamp > t)
-		diff = stamp - t;
+	t = purple_str_to_date_time(str, TRUE);
+
+	if (g_date_time_compare(stamp, t) > 0)
+		diff = g_date_time_difference(stamp, t);
 	else
-		diff = t - stamp;
-
-	if (diff > (14 * 60 * 60))
-	{
+		diff = g_date_time_difference(t, stamp);
+
+	if (diff > (14LL * G_TIME_SPAN_HOUR)) {
 		if (day <= 12)
 		{
 			/* Swap day & month variables, to see if it's a non-US date. */
 			g_free(str);
 			str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
-			t = purple_str_to_time(str, TRUE, &tm, NULL, NULL);
-
-			if (stamp > t)
-				diff = stamp - t;
+			t = purple_str_to_date_time(str, TRUE);
+
+			if (g_date_time_compare(stamp, t) > 0)
+				diff = g_date_time_difference(stamp, t);
 			else
-				diff = t - stamp;
-
-			if (diff > (14 * 60 * 60))
-			{
+				diff = g_date_time_difference(t, stamp);
+
+			if (diff > (14LL * G_TIME_SPAN_HOUR)) {
 				/* We got a time, it's not impossible, but
 				 * the diff is too large.  Display the UTC time. */
 				g_free(str);
-				*tm_out = &tm2;
 				return stamp;
 			}
 			else
@@ -479,26 +452,19 @@
 			/* We got a time, it's not impossible, but
 			 * the diff is too large.  Display the UTC time. */
 			g_free(str);
-			*tm_out = &tm2;
 			return stamp;
 		}
 	}
 
 	/* If we got here, the time is legal with a reasonable offset.
 	 * Let's find out if it's in our TZ. */
-	if (purple_str_to_time(str, FALSE, &tm, NULL, NULL) == stamp)
+	if (purple_str_to_date_time(str, FALSE) == stamp)
 	{
 		g_free(str);
-		*tm_out = &tm;
 		return stamp;
 	}
 	g_free(str);
 
-	/* The time isn't in our TZ, but it's reasonable. */
-#ifdef HAVE_STRUCT_TM_TM_ZONE
-	tm.tm_zone = "   ";
-#endif
-	*tm_out = &tm;
 	return stamp;
 }
 
@@ -737,8 +703,7 @@
 			 * The session ID differs from the last message.
 			 * Thus, this is the start of a new conversation.
 			 */
-			struct tm *tm;
-			time_t stamp;
+			GDateTime *stamp;
 			PurpleLog *log;
 
 			data = g_new0(struct msn_logger_data, 1);
@@ -748,12 +713,14 @@
 			data->text = NULL;
 			data->last_log = FALSE;
 
-			stamp = msn_logger_parse_timestamp(message, &tm);
-
-			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp, tm);
+			stamp = msn_logger_parse_timestamp(message);
+
+			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp);
 			log->logger = msn_logger;
 			log->logger_data = data;
 
+			g_date_time_unref(stamp);
+
 			list = g_list_prepend(list, log);
 		}
 		old_session_id = session_id;
@@ -808,7 +775,7 @@
 		PurpleXmlNode *to;
 		enum name_guesses name_guessed = NAME_GUESS_UNKNOWN;
 		const char *their_name;
-		struct tm *tm = NULL;
+		GDateTime *dt = NULL;
 		char *timestamp;
 		char *tmp;
 		const char *style;
@@ -987,12 +954,13 @@
 			text = g_string_append(text, ";\">");
 		}
 
-		if (msn_logger_parse_timestamp(message, &tm)) {
-			timestamp = g_strdup_printf(
-				"<font size=\"2\">(%02u:%02u:%02u)</font> ",
-				tm->tm_hour, tm->tm_min, tm->tm_sec);
+		if ((dt = msn_logger_parse_timestamp(message)) != NULL) {
+			timestamp = g_date_time_format(
+				dt,
+				"<font size=\"2\">(%H:%M:%s)</font> ");
 			text = g_string_append(text, timestamp);
 			g_free(timestamp);
+			g_date_time_unref(dt);
 		} else {
 			text = g_string_append(text,
 				"<font size=\"2\">(00:00:00)</font> ");
@@ -1208,8 +1176,9 @@
 					timestamp++;
 
 				if (*timestamp == ')') {
-					char *month;
-					struct tm tm;
+					char *month_str;
+					gint year, month, day, hour, minute, second;
+					GDateTime *dt;
 
 					*timestamp = '\0';
 					if (line[0] && line[1] && line[2])
@@ -1224,7 +1193,7 @@
 					timestamp++;
 
 					/* Parse out the month. */
-					month = timestamp;
+					month_str = timestamp;
 					while (*timestamp &&  (*timestamp != ' '))
 						timestamp++;
 					*timestamp = '\0';
@@ -1232,22 +1201,16 @@
 
 					/* Parse the day, time, and year. */
 					if (sscanf(timestamp, "%u %u:%u:%u %u",
-							&tm.tm_mday, &tm.tm_hour,
-							&tm.tm_min, &tm.tm_sec,
-							&tm.tm_year) != 5) {
+							&day, &hour,
+							&minute, &second,
+							&year) != 5) {
 
 						purple_debug_error("Trillian log timestamp parse",
 						                   "Session Start parsing error\n");
 					} else {
 						PurpleLog *log;
 
-						tm.tm_year -= 1900;
-
-						/* Let the C library deal with
-						 * daylight savings time.
-						 */
-						tm.tm_isdst = -1;
-						tm.tm_mon = get_month(month);
+						month = get_month(month_str);
 
 						data = g_new0(
 							struct trillian_logger_data, 1);
@@ -1257,12 +1220,16 @@
 						data->their_nickname =
 							g_strdup(their_nickname);
 
-						/* XXX: Look into this later... Should we pass in a struct tm? */
+						/* XXX: Look into this later... Should we figure out a timezone? */
+						dt = g_date_time_new_local(year, month, day, hour, minute, second);
+
 						log = purple_log_new(PURPLE_LOG_IM,
-							sn, account, NULL, mktime(&tm), NULL);
+							sn, account, NULL, dt);
 						log->logger = trillian_logger;
 						log->logger_data = data;
 
+						g_date_time_unref(dt);
+
 						list = g_list_prepend(list, log);
 					}
 				}
@@ -1634,7 +1601,7 @@
 #define QIP_LOG_OUT_MESSAGE (QIP_LOG_DELIMITER ">-")
 #define QIP_LOG_IN_MESSAGE_ESC (QIP_LOG_DELIMITER "&lt;-")
 #define QIP_LOG_OUT_MESSAGE_ESC (QIP_LOG_DELIMITER "&gt;-")
-#define QIP_LOG_TIMEOUT (60*60)
+#define QIP_LOG_TIMEOUT (G_TIME_SPAN_HOUR)
 
 static PurpleLogLogger *qip_logger;
 
@@ -1655,9 +1622,9 @@
 	char *path;
 	char *contents;
 	struct qip_logger_data *data = NULL;
-	struct tm prev_tm;
-	struct tm tm;
-	gboolean prev_tm_init = FALSE;
+	GDateTime *prev_dt = NULL;
+	GDateTime *dt = NULL;
+	gint year, month, day, hour, minute, second;
 	gboolean main_cycle = TRUE;
 	char *c;
 	char *start_log;
@@ -1668,8 +1635,6 @@
 	g_return_val_if_fail(sn != NULL, NULL);
 	g_return_val_if_fail(account != NULL, NULL);
 
-	memset(&tm, 0, sizeof(tm));
-
 	/* QIP only supports ICQ. */
 	if (!purple_strequal(purple_account_get_protocol_id(account), "prpl-icq"))
 		return NULL;
@@ -1740,24 +1705,18 @@
 
 					/*  Parse the time, day, month and year  */
 					if (sscanf(timestamp, "%u:%u:%u %u/%u/%u",
-						&tm.tm_hour, &tm.tm_min, &tm.tm_sec,
-						&tm.tm_mday, &tm.tm_mon, &tm.tm_year) != 6) {
+						&hour, &minute, &second,
+						&day, &month, &year) != 6) {
 
 						purple_debug_error("QIP logger list",
 							"Parsing timestamp error\n");
 					} else {
-						tm.tm_mon -= 1;
-						tm.tm_year -= 1900;
-
-						/* Let the C library deal with
-						 * daylight savings time. */
-						tm.tm_isdst = -1;
-
-						if (!prev_tm_init) {
-							prev_tm = tm;
-							prev_tm_init = TRUE;
+						g_date_time_unref(dt);
+						dt = g_date_time_new_local(year, month, day, hour, minute, second);
+						if (!prev_dt) {
+							prev_dt = dt;
 						} else {
-							add_new_log = difftime(mktime(&tm), mktime(&prev_tm)) > QIP_LOG_TIMEOUT;
+							add_new_log = g_date_time_difference(dt, prev_dt) > QIP_LOG_TIMEOUT;
 						}
 					}
 				}
@@ -1769,7 +1728,7 @@
 		}
 
 		/* adding  log */
-		if (add_new_log && prev_tm_init) {
+		if (add_new_log && prev_dt) {
 			PurpleLog *log;
 
 			/* filling data */
@@ -1782,16 +1741,18 @@
 				"Creating log: path = (%s); length = (%d); offset = (%d)\n",
 				data->path, data->length, data->offset);
 
-			/* XXX: Look into this later... Should we pass in a struct tm? */
+			/* XXX: Look into this later... Should we figure out a timezone? */
+			dt = g_date_time_new_local(year, month, day, hour, minute, second);
 			log = purple_log_new(PURPLE_LOG_IM, sn, account,
-				NULL, mktime(&prev_tm), NULL);
+				NULL, prev_dt);
 
 			log->logger = qip_logger;
 			log->logger_data = data;
 
 			list = g_list_prepend(list, log);
 
-			prev_tm = tm;
+			g_date_time_unref(prev_dt);
+			prev_dt = dt;
 			start_log = new_line;
 		}
 
@@ -2042,26 +2003,21 @@
 		gboolean found_start = FALSE;
 		char *start_log = c;
 		int offset = 0;
-		struct tm tm;
+		gint year, month, day, hour, minute, second;
+		GDateTime *dt;
 		while (c && *c) {
 			if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
-				char month[4];
+				char month_str[4];
 				if (sscanf(c + strlen(AMSN_LOG_CONV_START),
 				           "%u %3s %u %u:%u:%u",
-				           &tm.tm_mday, (char*)&month, &tm.tm_year,
-				           &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+				           &day, (char*)&month_str, &year,
+				           &hour, &minute, &second) != 6) {
 					found_start = FALSE;
 					purple_debug_error("aMSN logger",
 					                   "Error parsing start date for %s\n",
 					                   filename);
 				} else {
-					tm.tm_year -= 1900;
-
-					/* Let the C library deal with
-					 * daylight savings time.
-					 */
-					tm.tm_isdst = -1;
-					tm.tm_mon = get_month(month);
+					month = get_month(month_str);
 
 					found_start = TRUE;
 					offset = c - contents;
@@ -2074,11 +2030,13 @@
 				data->length = c - start_log
 					             + strlen(AMSN_LOG_CONV_END)
 					             + strlen(AMSN_LOG_CONV_EXTRA);
-				log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
+				dt = g_date_time_new_local(year, month, day, hour, minute, second);
+				log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
 				log->logger = amsn_logger;
 				log->logger_data = data;
 				list = g_list_prepend(list, log);
 				found_start = FALSE;
+				g_date_time_unref(dt);
 
 				purple_debug_info("aMSN logger",
 				                  "Found log for %s:"
@@ -2100,10 +2058,12 @@
 			data->length = c - start_log
 				             + strlen(AMSN_LOG_CONV_END)
 				             + strlen(AMSN_LOG_CONV_EXTRA);
-			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
+			dt = g_date_time_new_local(year, month, day, hour, minute, second);
+			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
 			log->logger = amsn_logger;
 			log->logger_data = data;
 			list = g_list_prepend(list, log);
+			g_date_time_unref(dt);
 
 			purple_debug_info("aMSN logger",
 			                  "Found log for %s:"
@@ -2522,7 +2482,7 @@
 			g_free(path);
 			path = NULL;
 		}
-		
+
 		if (path && !g_file_get_contents(path, &contents, NULL, &error)) {
 			purple_debug_error("Trillian talk.ini read",
 					   "Error reading talk.ini: %s\n",
--- a/pidgin/gtklog.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/pidgin/gtklog.c	Tue Jul 11 23:43:33 2017 -0400
@@ -108,12 +108,14 @@
 	gtk_tree_path_free(path);
 }
 
-static const char *log_get_date(PurpleLog *log)
+static gchar *log_get_date(PurpleLog *log)
 {
-	if (log->tm)
-		return purple_date_format_full(log->tm);
-	else
-		return purple_date_format_full(localtime(&log->time));
+	GDateTime *dt;
+	gchar *ret;
+	dt = g_date_time_to_local(log->time);
+	ret = g_date_time_format(dt, "%c");
+	g_date_time_unref(dt);
+	return ret;
 }
 
 static void search_cb(GtkWidget *button, PidginLogViewer *lv)
@@ -152,11 +154,13 @@
 		if (read && *read && purple_strcasestr(read, search_term)) {
 			GtkTreeIter iter;
 			PurpleLog *log = logs->data;
+			gchar *log_date = log_get_date(log);
 
 			gtk_tree_store_append (lv->treestore, &iter, NULL);
 			gtk_tree_store_set(lv->treestore, &iter,
-					   0, log_get_date(log),
+					   0, log_date,
 					   1, log, -1);
+			g_free(log_date);
 		}
 		g_free(read);
 	}
@@ -270,7 +274,7 @@
 {
 	PidginLogViewer *lv = data[0];
 	PurpleLog *log = data[1];
-	const char *time = log_get_date(log);
+	gchar *time = log_get_date(log);
 	const char *name;
 	char *tmp;
 	gpointer *data2;
@@ -302,8 +306,10 @@
 		tmp = g_strdup_printf(_("Are you sure you want to permanently delete the system log "
 		                        "which started at %s?"), time);
 	}
-	else
+	else {
+		g_free(time);
 		g_return_if_reached();
+	}
 
 	/* The only way to free data in all cases is to tie it to the menuitem with
 	 * g_object_set_data_full().  But, since we need to get some data down to
@@ -319,6 +325,7 @@
 						data2, 2,
 						_("Delete"), delete_log_cb,
 						_("Cancel"), delete_log_cleanup_cb);
+	g_free(time);
 	g_free(tmp);
 }
 
@@ -444,15 +451,17 @@
 	pidgin_set_cursor(viewer->window, GDK_WATCH);
 
 	if (log->type != PURPLE_LOG_SYSTEM) {
+		gchar *log_date = log_get_date(log);
 		char *title;
 		if (log->type == PURPLE_LOG_CHAT)
 			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"),
-									log->name, log_get_date(log));
+									log->name, log_date);
 		else
 			title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"),
-									log->name, log_get_date(log));
+									log->name, log_date);
 
 		gtk_label_set_markup(viewer->label, title);
+		g_free(log_date);
 		g_free(title);
 	}
 
@@ -492,19 +501,20 @@
      /* Logs are made from trees in real life.
         This is a tree made from logs */
 {
-	const char *month;
+	gchar *month;
 	char prev_top_month[30] = "";
 	GtkTreeIter toplevel, child;
 	GList *logs = lv->logs;
 
 	while (logs != NULL) {
 		PurpleLog *log = logs->data;
+		GDateTime *dt;
+		gchar *log_date;
 
-		month = purple_utf8_strftime(_("%B %Y"),
-		                           log->tm ? log->tm : localtime(&log->time));
+		dt = g_date_time_to_local(log->time);
+		month = g_date_time_format(dt, _("%B %Y"));
 
-		if (!purple_strequal(month, prev_top_month))
-		{
+		if (!purple_strequal(month, prev_top_month)) {
 			/* top level */
 			gtk_tree_store_append(lv->treestore, &toplevel, NULL);
 			gtk_tree_store_set(lv->treestore, &toplevel, 0, month, 1, NULL, -1);
@@ -513,12 +523,16 @@
 		}
 
 		/* sub */
+		log_date = g_date_time_format(dt, "%c");
 		gtk_tree_store_append(lv->treestore, &child, &toplevel);
 		gtk_tree_store_set(lv->treestore, &child,
-						   0, log_get_date(log),
+						   0, log_date,
 						   1, log,
 						   -1);
 
+		g_free(log_date);
+		g_free(month);
+		g_date_time_unref(dt);
 		logs = logs->next;
 	}
 }
--- a/pidgin/plugins/history.c	Tue Jul 11 05:27:50 2017 -0400
+++ b/pidgin/plugins/history.c	Tue Jul 11 23:43:33 2017 -0400
@@ -48,7 +48,8 @@
 	char *protocol;
 #endif
 	char *escaped_alias;
-	const char *header_date;
+	GDateTime *dt;
+	gchar *header_date;
 
 	gtkconv = PIDGIN_CONVERSATION(c);
 	g_return_if_fail(gtkconv != NULL);
@@ -141,13 +142,13 @@
 
 	escaped_alias = g_markup_escape_text(alias, -1);
 
-	if (((PurpleLog *)logs->data)->tm)
-		header_date = purple_date_format_full(((PurpleLog *)logs->data)->tm);
-	else
-		header_date = purple_date_format_full(localtime(&((PurpleLog *)logs->data)->time));
+	dt = g_date_time_to_local(((PurpleLog *)logs->data)->time);
+	header_date = g_date_time_format(dt, "%c");
+	g_date_time_unref(dt);
 
 	header = g_strdup_printf(_("<b>Conversation with %s on %s:</b><br>"), escaped_alias, header_date);
 	pidgin_webview_append_html(PIDGIN_WEBVIEW(gtkconv->webview), header);
+	g_free(header_date);
 	g_free(header);
 	g_free(escaped_alias);
 

mercurial