summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/common/text.c11
-rw-r--r--src/common/util.c78
-rw-r--r--src/common/util.h2
-rw-r--r--src/fe-gtk/setup.c9
-rw-r--r--src/fe-text/fe-text.c2
5 files changed, 82 insertions, 20 deletions
diff --git a/src/common/text.c b/src/common/text.c
index 0b66c5fd..58d3b45c 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -542,7 +542,7 @@ log_create_pathname (char *servname, char *channame, char *netname)
 	/* insert time/date */
 	now = time (NULL);
 	tm = localtime (&now);
-	strftime (fnametime, sizeof (fnametime), fname, tm);
+	strftime_validated (fnametime, sizeof (fnametime), fname, tm);
 
 	/* create final path/filename */
 	if (logmask_is_fullpath ())
@@ -649,14 +649,7 @@ get_stamp_str (char *fmt, time_t tim, char **ret)
 			fmt = loc;
 	}
 
-	len = strftime (dest, sizeof (dest), fmt, localtime (&tim));
-#ifdef WIN32
-	if (!len)
-	{
-		/* use failsafe format until a correct one is specified */
-		len = strftime (dest, sizeof (dest), "[%H:%M:%S]", localtime (&tim));
-	}
-#endif
+	len = strftime_validated (dest, sizeof (dest), fmt, localtime (&tim));
 	if (len)
 	{
 		if (prefs.utf8_locale)
diff --git a/src/common/util.c b/src/common/util.c
index cb6181c4..6e912169 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -2287,3 +2288,80 @@ challengeauth_response (char *username, char *password, char *challenge)
 	return (char *) digest;
 }
 #endif
+
+/**
+* \brief Wrapper around strftime for Windows
+*
+* Prevents crashing when using an invalid format by escaping them.
+*
+* Behaves the same as strftime with the addition that
+* it returns 0 if the escaped format string is too large.
+*
+* Based upon work from znc-msvc project.
+*/
+size_t
+strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time)
+{
+#ifndef WIN32
+	return strftime (dest, destsize, format, time);
+#else
+	char safe_format[64];
+	const char *p = format;
+	int i = 0;
+
+	if (strlen (format) >= sizeof(safe_format))
+		return 0;
+
+	memset (safe_format, 0, sizeof(safe_format));
+
+	while (*p)
+	{
+		if (*p == '%')
+		{
+			int has_hash = (*(p + 1) == '#');
+			char c = *(p + (has_hash ? 2 : 1));
+
+			if (i >= sizeof (safe_format))
+				return 0;
+
+			switch (c)
+			{
+			case 'a': case 'A': case 'b': case 'B': case 'c': case 'd': case 'H': case 'I': case 'j': case 'm': case 'M':
+			case 'p': case 'S': case 'U': case 'w': case 'W': case 'x': case 'X': case 'y': case 'Y': case 'z': case 'Z':
+			case '%':
+				/* formatting code is fine */
+				break;
+			default:
+				/* replace bad formatting code with itself, escaped, e.g. "%V" --> "%%V" */
+				g_strlcat (safe_format, "%%", sizeof(safe_format));
+				i += 2;
+				p++;
+				break;
+			}
+
+			/* the current loop run will append % (and maybe #) and the next one will do the actual char. */
+			if (has_hash)
+			{
+				safe_format[i] = *p;
+				p++;
+				i++;
+			}
+			if (c == '%')
+			{
+				safe_format[i] = *p;
+				p++;
+				i++;
+			}
+		}
+
+		if (*p)
+		{
+			safe_format[i] = *p;
+			p++;
+			i++;
+		}
+	}
+
+	return strftime (dest, destsize, safe_format, time);
+#endif
+}
diff --git a/src/common/util.h b/src/common/util.h
index 6b8d359c..0c54411b 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -83,5 +83,5 @@ char *encode_sasl_pass_plain (char *user, char *pass);
 char *encode_sasl_pass_blowfish (char *user, char *pass, char *data);
 char *encode_sasl_pass_aes (char *user, char *pass, char *data);
 char *challengeauth_response (char *username, char *password, char *challenge);
-
+size_t strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time);
 #endif
diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c
index 2f52d5d9..a1a54ca4 100644
--- a/src/fe-gtk/setup.c
+++ b/src/fe-gtk/setup.c
@@ -2114,7 +2114,6 @@ setup_apply (struct hexchatprefs *pr)
 	PangoFontDescription *old_desc;
 	PangoFontDescription *new_desc;
 	char buffer[4 * FONTNAMELEN + 1];
-	time_t rawtime;
 #endif
 	int new_pix = FALSE;
 	int noapply = FALSE;
@@ -2192,14 +2191,6 @@ setup_apply (struct hexchatprefs *pr)
 	g_free (old_desc);
 	g_free (new_desc);
 	*/
-
-	/* workaround for strftime differences between POSIX and MSVC */
-	time (&rawtime);
-
-	if (!strftime (buffer, sizeof (buffer), prefs.hex_stamp_text_format, localtime (&rawtime)) || !strftime (buffer, sizeof (buffer), prefs.hex_stamp_log_format, localtime (&rawtime)))
-	{
-		fe_message (_("Invalid time stamp format! See the strftime MSDN article for details."), FE_MSG_ERROR);
-	}
 #endif
 
 	if (prefs.hex_irc_real_name[0] == 0)
diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c
index 6f197916..76f93d8d 100644
--- a/src/fe-text/fe-text.c
+++ b/src/fe-text/fe-text.c
@@ -121,7 +121,7 @@ fe_new_window (struct session *sess, int focus)
 static int
 get_stamp_str (time_t tim, char *dest, int size)
 {
-	return strftime (dest, size, prefs.hex_stamp_text_format, localtime (&tim));
+	return strftime_validated (dest, size, prefs.hex_stamp_text_format, localtime (&tim));
 }
 
 static int