summary refs log tree commit diff stats
path: root/src/common/text.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/text.c')
-rw-r--r--src/common/text.c582
1 files changed, 227 insertions, 355 deletions
diff --git a/src/common/text.c b/src/common/text.c
index 329ef37b..cd9ea26e 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -51,6 +51,9 @@
 #include <canberra.h>
 #endif
 
+const gchar* unicode_fallback_string = "\357\277\275"; /* The Unicode replacement character 0xFFFD */
+const gchar* arbitrary_encoding_fallback_string = "?";
+
 struct pevt_stage1
 {
 	int len;
@@ -83,7 +86,7 @@ scrollback_get_filename (session *sess)
 		buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "scrollback" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S "%s.txt", get_xdir (), net, chan);
 	else
 		buf = NULL;
-	free (chan);
+	g_free (chan);
 
 	return buf;
 }
@@ -173,11 +176,11 @@ scrollback_shrink (session *sess)
 		p++;
 	}
 
-	fh = g_open (file, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, 0644);
+	fh = g_open (file, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY | OFLAGS, 0644);
 	g_free (file);
 	if (fh == -1)
 	{
-		free (buf);
+		g_free (buf);
 		return;
 	}
 
@@ -200,14 +203,13 @@ scrollback_shrink (session *sess)
 	}
 
 	close (fh);
-	free (buf);
+	g_free (buf);
 }
 
 static void
-scrollback_save (session *sess, char *text)
+scrollback_save (session *sess, char *text, time_t stamp)
 {
 	char *buf;
-	time_t stamp;
 	int len;
 
 	if (sess->type == SESS_SERVER && prefs.hex_gui_tab_server == 1)
@@ -229,13 +231,14 @@ scrollback_save (session *sess, char *text)
 		if ((buf = scrollback_get_filename (sess)) == NULL)
 			return;
 
-		sess->scrollfd = g_open (buf, O_CREAT | O_APPEND | O_WRONLY, 0644);
+		sess->scrollfd = g_open (buf, O_CREAT | O_APPEND | O_WRONLY | OFLAGS, 0644);
 		g_free (buf);
 		if (sess->scrollfd == -1)
 			return;
 	}
 
-	stamp = time (0);
+	if (!stamp)
+		stamp = time(0);
 	if (sizeof (stamp) == 4)	/* gcc will optimize one of these out */
 		buf = g_strdup_printf ("T %d ", (int) stamp);
 	else
@@ -298,13 +301,6 @@ scrollback_load (session *sess)
 		{
 			char *buf_tmp;
 
-			/* If nothing but funny trailing matter e.g. 0x0d or 0x0d0a, toss it */
-			if (n_bytes >= 1 && buf[0] == 0x0d)
-			{
-				g_free (buf);
-				continue;
-			}
-
 			n_bytes--;
 			buf_tmp = buf;
 			buf = g_strndup (buf_tmp, n_bytes);
@@ -319,9 +315,9 @@ scrollback_load (session *sess)
 			if (buf[0] == 'T')
 			{
 				if (sizeof (time_t) == 4)
-					stamp = strtoul (buf + 2, NULL, 10);
+					stamp = g_ascii_strtoull (buf + 2, NULL, 10);
 				else
-					stamp = strtoull (buf + 2, NULL, 10); /* in case time_t is 64 bits */
+					stamp = g_ascii_strtoull (buf + 2, NULL, 10); /* in case time_t is 64 bits */
 				text = strchr (buf + 3, ' ');
 				if (text && text[1])
 				{
@@ -383,7 +379,7 @@ log_close (session *sess)
 	{
 		currenttime = time (NULL);
 		write (sess->logfd, obuf,
-			 snprintf (obuf, sizeof (obuf) - 1, _("**** ENDING LOGGING AT %s\n"),
+			 g_snprintf (obuf, sizeof (obuf) - 1, _("**** ENDING LOGGING AT %s\n"),
 						  ctime (&currenttime)));
 		close (sess->logfd);
 		sess->logfd = -1;
@@ -393,9 +389,7 @@ log_close (session *sess)
 static void
 mkdir_p (char *filename)
 {
-	char *dirname;
-	
-	dirname = g_path_get_dirname (filename);
+	char *dirname = g_path_get_dirname (filename);
 
 	g_mkdir_with_parents (dirname, 0700);
 
@@ -408,7 +402,7 @@ log_create_filename (char *channame)
 	char *tmp, *ret;
 	int mbl;
 
-	ret = tmp = strdup (channame);
+	ret = tmp = g_strdup (channame);
 	while (*tmp)
 	{
 		mbl = g_utf8_skip[((unsigned char *)tmp)[0]];
@@ -507,34 +501,6 @@ log_insert_vars (char *buf, int bufsize, char *fmt, char *c, char *n, char *s)
 	}
 }
 
-static int
-logmask_is_fullpath ()
-{
-	/* Check if final path/filename is absolute or relative.
-	 * If one uses log mask variables, such as "%c/...", %c will be empty upon
-	 * connecting since there's no channel name yet, so we have to make sure
-	 * we won't try to write to the FS root. On Windows we can be sure it's
-	 * full path if the 2nd character is a colon since Windows doesn't allow
-	 * colons in filenames.
-	 */
-#ifdef WIN32
-	/* Treat it as full path if it
-	 * - starts with '\' which denotes the root directory of the current drive letter
-	 * - starts with a drive letter and followed by ':'
-	 */
-	if (prefs.hex_irc_logmask[0] == '\\' || (((prefs.hex_irc_logmask[0] >= 'A' && prefs.hex_irc_logmask[0] <= 'Z') || (prefs.hex_irc_logmask[0] >= 'a' && prefs.hex_irc_logmask[0] <= 'z')) && prefs.hex_irc_logmask[1] == ':'))
-#else
-	if (prefs.hex_irc_logmask[0] == '/')
-#endif
-	{
-		return 1;
-	}
-	else
-	{
-		return 0;
-	}
-}
-
 static char *
 log_create_pathname (char *servname, char *channame, char *netname)
 {
@@ -544,7 +510,7 @@ log_create_pathname (char *servname, char *channame, char *netname)
 
 	if (!netname)
 	{
-		netname = strdup ("NETWORK");
+		netname = g_strdup ("NETWORK");
 	}
 	else
 	{
@@ -554,7 +520,7 @@ log_create_pathname (char *servname, char *channame, char *netname)
 	/* first, everything is in UTF-8 */
 	if (!rfc_casecmp (channame, servname))
 	{
-		channame = strdup ("server");
+		channame = g_strdup ("server");
 	}
 	else
 	{
@@ -562,27 +528,29 @@ log_create_pathname (char *servname, char *channame, char *netname)
 	}
 
 	log_insert_vars (fname, sizeof (fname), prefs.hex_irc_logmask, channame, netname, servname);
-	free (channame);
-	free (netname);
+	g_free (channame);
+	g_free (netname);
 
 	/* insert time/date */
 	now = time (NULL);
 	strftime_utf8 (fnametime, sizeof (fnametime), fname, now);
 
-	/* create final path/filename */
-	if (logmask_is_fullpath ())
+	/* If one uses log mask variables, such as "%c/...", %c will be empty upon
+	 * connecting since there's no channel name yet, so we have to make sure
+	 * we won't try to write to the FS root. */
+	if (g_path_is_absolute (prefs.hex_irc_logmask))
 	{
-		snprintf (fname, sizeof (fname), "%s", fnametime);
+		g_snprintf (fname, sizeof (fname), "%s", fnametime);
 	}
 	else	/* relative path */
 	{
-		snprintf (fname, sizeof (fname), "%s" G_DIR_SEPARATOR_S "logs" G_DIR_SEPARATOR_S "%s", get_xdir (), fnametime);
+		g_snprintf (fname, sizeof (fname), "%s" G_DIR_SEPARATOR_S "logs" G_DIR_SEPARATOR_S "%s", get_xdir (), fnametime);
 	}
 
 	/* create all the subdirectories */
 	mkdir_p (fname);
 
-	return g_strdup(fname);
+	return g_strdup (fname);
 }
 
 static int
@@ -597,18 +565,14 @@ log_open_file (char *servname, char *channame, char *netname)
 	if (!file)
 		return -1;
 
-#ifdef WIN32
-	fd = g_open (file, O_CREAT | O_APPEND | O_WRONLY, S_IREAD|S_IWRITE);
-#else
-	fd = g_open (file, O_CREAT | O_APPEND | O_WRONLY, 0644);
-#endif
+	fd = g_open (file, O_CREAT | O_APPEND | O_WRONLY | OFLAGS, 0644);
 	g_free (file);
 
 	if (fd == -1)
 		return -1;
 	currenttime = time (NULL);
 	write (fd, buf,
-			 snprintf (buf, sizeof (buf), _("**** BEGIN LOGGING AT %s\n"),
+			 g_snprintf (buf, sizeof (buf), _("**** BEGIN LOGGING AT %s\n"),
 						  ctime (&currenttime)));
 
 	return fd;
@@ -625,14 +589,15 @@ log_open (session *sess)
 
 	if (!log_error && sess->logfd == -1)
 	{
-		char *message;
+		char *filename = log_create_pathname (sess->server->servername, sess->channel, server_get_network (sess->server, FALSE));
+		char *message = g_strdup_printf (_("* Can't open log file(s) for writing. Check the\npermissions on %s"), filename);
 
-		message = g_strdup_printf (_("* Can't open log file(s) for writing. Check the\npermissions on %s"),
-			log_create_pathname (sess->server->servername, sess->channel, server_get_network (sess->server, FALSE)));
+		g_free (filename);
 
 		fe_message (message, FE_MSG_WAIT | FE_MSG_ERROR);
 
 		g_free (message);
+
 		log_error = TRUE;
 	}
 }
@@ -659,34 +624,29 @@ log_open_or_close (session *sess)
 int
 get_stamp_str (char *fmt, time_t tim, char **ret)
 {
-	char *loc = NULL;
 	char dest[128];
-	gsize len;
+	gsize len_locale;
+	gsize len_utf8;
 
-	/* strftime wants the format string in LOCALE! */
-	if (!prefs.utf8_locale)
-	{
-		const gchar *charset;
+	/* strftime requires the format string to be in locale encoding. */
+	fmt = g_locale_from_utf8 (fmt, -1, NULL, NULL, NULL);
 
-		g_get_charset (&charset);
-		loc = g_convert_with_fallback (fmt, -1, charset, "UTF-8", "?", 0, 0, 0);
-		if (loc)
-			fmt = loc;
-	}
+	len_locale = strftime_validated (dest, sizeof (dest), fmt, localtime (&tim));
 
-	len = strftime_validated (dest, sizeof (dest), fmt, localtime (&tim));
-	if (len)
+	g_free (fmt);
+
+	if (len_locale == 0)
 	{
-		if (prefs.utf8_locale)
-			*ret = g_strdup (dest);
-		else
-			*ret = g_locale_to_utf8 (dest, len, 0, &len, 0);
+		return 0;
 	}
 
-	if (loc)
-		g_free (loc);
+	*ret = g_locale_to_utf8 (dest, len_locale, NULL, &len_utf8, NULL);
+	if (*ret == NULL)
+	{
+		return 0;
+	}
 
-	return len;
+	return len_utf8;
 }
 
 static void
@@ -709,22 +669,32 @@ log_write (session *sess, char *text, time_t ts)
 	}
 
 	if (sess->logfd == -1)
+	{
 		log_open (sess);
+	}
 
 	/* change to a different log file? */
-	file = log_create_pathname (sess->server->servername, sess->channel,
-										 server_get_network (sess->server, FALSE));
+	file = log_create_pathname (sess->server->servername, sess->channel, server_get_network (sess->server, FALSE));
 	if (file)
 	{
 		if (g_access (file, F_OK) != 0)
 		{
-			close (sess->logfd);
-			sess->logfd = log_open_file (sess->server->servername, sess->channel,
-												  server_get_network (sess->server, FALSE));
+			if (sess->logfd != -1)
+			{
+				close (sess->logfd);
+			}
+
+			sess->logfd = log_open_file (sess->server->servername, sess->channel, server_get_network (sess->server, FALSE));
 		}
+
 		g_free (file);
 	}
 
+	if (sess->logfd == -1)
+	{
+		return;
+	}
+
 	if (prefs.hex_stamp_log)
 	{
 		if (!ts) ts = time(0);
@@ -735,6 +705,7 @@ log_write (session *sess, char *text, time_t ts)
 			g_free (stamp);
 		}
 	}
+
 	temp = strip_color (text, -1, STRIP_ALL);
 	len = strlen (temp);
 	write (sess->logfd, temp, len);
@@ -744,156 +715,104 @@ log_write (session *sess, char *text, time_t ts)
 	g_free (temp);
 }
 
-/* converts a CP1252/ISO-8859-1(5) hybrid to UTF-8                           */
-/* Features: 1. It never fails, all 00-FF chars are converted to valid UTF-8 */
-/*           2. Uses CP1252 in the range 80-9f because ISO doesn't have any- */
-/*              thing useful in this range and it helps us receive from mIRC */
-/*           3. The five undefined chars in CP1252 80-9f are replaced with   */
-/*              ISO-8859-15 control codes.                                   */
-/*           4. Handles 0xa4 as a Euro symbol ala ISO-8859-15.               */
-/*           5. Uses ISO-8859-1 (which matches CP1252) for everything else.  */
-/*           6. This routine measured 3x faster than g_convert :)            */
-
-static unsigned char *
-iso_8859_1_to_utf8 (unsigned char *text, int len, gsize *bytes_written)
+/**
+ * Converts a given string using the given iconv converter. This is similar to g_convert_with_fallback, except that it is tolerant of sequences in
+ * the original input that are invalid even in from_encoding. g_convert_with_fallback fails for such text, whereas this function replaces such a
+ * sequence with the fallback string.
+ *
+ * If len is -1, strlen(text) is used to calculate the length. Do not pass -1 if text is supposed to contain \0 bytes, such as if from_encoding is a
+ * multi-byte encoding like UTF-16.
+ */
+gchar *
+text_convert_invalid (const gchar* text, gssize len, GIConv converter, const gchar *fallback, gsize *len_out)
 {
-	unsigned int idx;
-	unsigned char *res, *output;
-	static const unsigned short lowtable[] = /* 74 byte table for 80-a4 */
-	{
-	/* compressed utf-8 table: if the first byte's 0x20 bit is set, it
-	   indicates a 2-byte utf-8 sequence, otherwise prepend a 0xe2. */
-		0x82ac, /* 80 Euro. CP1252 from here on... */
-		0xe281, /* 81 NA */
-		0x809a, /* 82 */
-		0xe692, /* 83 */
-		0x809e, /* 84 */
-		0x80a6, /* 85 */
-		0x80a0, /* 86 */
-		0x80a1, /* 87 */
-		0xeb86, /* 88 */
-		0x80b0, /* 89 */
-		0xe5a0, /* 8a */
-		0x80b9, /* 8b */
-		0xe592, /* 8c */
-		0xe28d, /* 8d NA */
-		0xe5bd, /* 8e */
-		0xe28f, /* 8f NA */
-		0xe290, /* 90 NA */
-		0x8098, /* 91 */
-		0x8099, /* 92 */
-		0x809c, /* 93 */
-		0x809d, /* 94 */
-		0x80a2, /* 95 */
-		0x8093, /* 96 */
-		0x8094, /* 97 */
-		0xeb9c, /* 98 */
-		0x84a2, /* 99 */
-		0xe5a1, /* 9a */
-		0x80ba, /* 9b */
-		0xe593, /* 9c */
-		0xe29d, /* 9d NA */
-		0xe5be, /* 9e */
-		0xe5b8, /* 9f */
-		0xe2a0, /* a0 */
-		0xe2a1, /* a1 */
-		0xe2a2, /* a2 */
-		0xe2a3, /* a3 */
-		0x82ac  /* a4 ISO-8859-15 Euro. */
-	};
+	gchar *result_part;
+	gsize result_part_len;
+	const gchar *end;
+	gsize invalid_start_pos;
+	GString *result;
+	const gchar *current_start;
 
 	if (len == -1)
+	{
 		len = strlen (text);
+	}
 
-	/* worst case scenario: every byte turns into 3 bytes */
-	res = output = g_malloc ((len * 3) + 1);
-	if (!output)
-		return NULL;
+	end = text + len;
 
-	while (len)
+	/* Find the first position of an invalid sequence. */
+	result_part = g_convert_with_iconv (text, len, converter, &invalid_start_pos, &result_part_len, NULL);
+	if (result_part != NULL)
 	{
-		if (G_LIKELY (*text < 0x80))
+		/* All text converted successfully on the first try. Return it. */
+
+		if (len_out != NULL)
 		{
-			*output = *text;	/* ascii maps directly */
+			*len_out = result_part_len;
 		}
-		else if (*text <= 0xa4)	/* 80-a4 use a lookup table */
+
+		return result_part;
+	}
+
+	/* One or more invalid sequences exist that need to be replaced with the fallback. */
+
+	result = g_string_sized_new (len);
+	current_start = text;
+
+	for (;;)
+	{
+		g_assert (current_start + invalid_start_pos < end);
+
+		/* Convert everything before the position of the invalid sequence. It should be successful. */
+		result_part = g_convert_with_iconv (current_start, invalid_start_pos, converter, &invalid_start_pos, &result_part_len, NULL);
+		g_assert (result_part != NULL);
+		g_string_append_len (result, result_part, result_part_len);
+		g_free (result_part);
+
+		/* Append the fallback */
+		g_string_append (result, fallback);
+
+		/* Now try converting everything after the invalid sequence. */
+		current_start += invalid_start_pos + 1;
+
+		result_part = g_convert_with_iconv (current_start, end - current_start, converter, &invalid_start_pos, &result_part_len, NULL);
+		if (result_part != NULL)
 		{
-			idx = *text - 0x80;
-			if (lowtable[idx] & 0x2000)
-			{
-				*output++ = (lowtable[idx] >> 8) & 0xdf; /* 2 byte utf-8 */
-				*output = lowtable[idx] & 0xff;
-			}
-			else
+			/* The rest of the text converted successfully. Append it and return the whole converted text. */
+
+			g_string_append_len (result, result_part, result_part_len);
+			g_free (result_part);
+
+			if (len_out != NULL)
 			{
-				*output++ = 0xe2;	/* 3 byte utf-8 */
-				*output++ = (lowtable[idx] >> 8) & 0xff;
-				*output = lowtable[idx] & 0xff;
+				*len_out = result->len;
 			}
+
+			return g_string_free (result, FALSE);
 		}
-		else if (*text < 0xc0)
-		{
-			*output++ = 0xc2;
-			*output = *text;
-		}
-		else
-		{
-			*output++ = 0xc3;
-			*output = *text - 0x40;
-		}
-		output++;
-		text++;
-		len--;
-	}
-	*output = 0;	/* terminate */
-	*bytes_written = output - res;
 
-	return res;
+		/* The rest of the text didn't convert successfully. invalid_start_pos has the position of the next invalid sequence. */
+	}
 }
 
-char *
-text_validate (char **text, int *len)
+/**
+ * Replaces any invalid UTF-8 in the given text with the unicode replacement character.
+ */
+gchar *
+text_fixup_invalid_utf8 (const gchar* text, gssize len, gsize *len_out)
 {
-	char *utf;
-	gsize utf_len;
-
-	/* valid utf8? */
-	if (g_utf8_validate (*text, *len, 0))
-		return NULL;
-
-#ifdef WIN32
-	if (GetACP () == 1252) /* our routine is better than iconv's 1252 */
-#else
-	if (prefs.utf8_locale)
-#endif
-		/* fallback to iso-8859-1 */
-		utf = iso_8859_1_to_utf8 (*text, *len, &utf_len);
-	else
+	static GIConv utf8_fixup_converter = NULL;
+	if (utf8_fixup_converter == NULL)
 	{
-		/* fallback to locale */
-		utf = g_locale_to_utf8 (*text, *len, 0, &utf_len, NULL);
-		if (!utf)
-			utf = iso_8859_1_to_utf8 (*text, *len, &utf_len);
+		utf8_fixup_converter = g_iconv_open ("UTF-8", "UTF-8");
 	}
 
-	if (!utf) 
-	{
-		*text = g_strdup ("%INVALID%");
-		*len = 9;
-	} else
-	{
-		*text = utf;
-		*len = utf_len;
-	}
-
-	return utf;
+	return text_convert_invalid (text, len, utf8_fixup_converter, unicode_fallback_string, len_out);
 }
 
 void
 PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
 {
-	char *conv;
-
 	if (!sess)
 	{
 		if (!sess_list)
@@ -902,22 +821,19 @@ PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
 	}
 
 	/* make sure it's valid utf8 */
-	if (text[0] == 0)
+	if (text[0] == '\0')
 	{
-		text = "\n";
-		conv = NULL;
-	} else
+		text = g_strdup ("\n");
+	}
+	else
 	{
-		int len = -1;
-		conv = text_validate ((char **)&text, &len);
+		text = text_fixup_invalid_utf8 (text, -1, NULL);
 	}
 
 	log_write (sess, text, timestamp);
-	scrollback_save (sess, text);
+	scrollback_save (sess, text, timestamp);
 	fe_print_text (sess, text, timestamp, FALSE);
-
-	if (conv)
-		g_free (conv);
+	g_free (text);
 }
 
 void
@@ -1004,7 +920,7 @@ PrintTextTimeStampf (session *sess, time_t timestamp, const char *format, ...)
    Each XP_TE_* signal is hard coded to call text_emit which calls
    display_event which decodes the data
 
-   This means that this system *should be faster* than snprintf because
+   This means that this system *should be faster* than g_snprintf because
    it always 'knows' that format of the string (basically is preparses much
    of the work)
 
@@ -1211,26 +1127,26 @@ static char * const pevt_chanrmlimit_help[] = {
 };
 
 static char * const pevt_chandeop_help[] = {
-	N_("The nick of the person of did the deop'ing"),
+	N_("The nick of the person who did the deop'ing"),
 	N_("The nick of the person who has been deop'ed"),
 };
 static char * const pevt_chandehop_help[] = {
-	N_("The nick of the person of did the dehalfop'ing"),
+	N_("The nick of the person who did the dehalfop'ing"),
 	N_("The nick of the person who has been dehalfop'ed"),
 };
 
 static char * const pevt_chandevoice_help[] = {
-	N_("The nick of the person of did the devoice'ing"),
+	N_("The nick of the person who did the devoice'ing"),
 	N_("The nick of the person who has been devoice'ed"),
 };
 
 static char * const pevt_chanunban_help[] = {
-	N_("The nick of the person of did the unban'ing"),
+	N_("The nick of the person who did the unban'ing"),
 	N_("The ban mask"),
 };
 
 static char * const pevt_chanunquiet_help[] = {
-	N_("The nick of the person of did the unquiet'ing"),
+	N_("The nick of the person who did the unquiet'ing"),
 	N_("The quiet mask"),
 };
 
@@ -1569,14 +1485,13 @@ pevent_load_defaults ()
 
 	for (i = 0; i < NUM_XP; i++)
 	{
-		if (pntevts_text[i])
-			free (pntevts_text[i]);
+		g_free (pntevts_text[i]);
 
 		/* make-te.c sets this 128 flag (DON'T call gettext() flag) */
 		if (te[i].num_args & 128)
-			pntevts_text[i] = strdup (te[i].def);
+			pntevts_text[i] = g_strdup (te[i].def);
 		else
-			pntevts_text[i] = strdup (_(te[i].def));
+			pntevts_text[i] = g_strdup (_(te[i].def));
 	}
 }
 
@@ -1588,19 +1503,18 @@ pevent_make_pntevts ()
 
 	for (i = 0; i < NUM_XP; i++)
 	{
-		if (pntevts[i] != NULL)
-			free (pntevts[i]);
+		g_free (pntevts[i]);
 		if (pevt_build_string (pntevts_text[i], &(pntevts[i]), &m) != 0)
 		{
-			snprintf (out, sizeof (out),
+			g_snprintf (out, sizeof (out),
 						 _("Error parsing event %s.\nLoading default."), te[i].name);
 			fe_message (out, FE_MSG_WARN);
-			free (pntevts_text[i]);
+			g_free (pntevts_text[i]);
 			/* make-te.c sets this 128 flag (DON'T call gettext() flag) */
 			if (te[i].num_args & 128)
-				pntevts_text[i] = strdup (te[i].def);
+				pntevts_text[i] = g_strdup (te[i].def);
 			else
-				pntevts_text[i] = strdup (_(te[i].def));
+				pntevts_text[i] = g_strdup (_(te[i].def));
 			if (pevt_build_string (pntevts_text[i], &(pntevts[i]), &m) != 0)
 			{
 				fprintf (stderr,
@@ -1622,22 +1536,17 @@ pevent_make_pntevts ()
 static void
 pevent_trigger_load (int *i_penum, char **i_text, char **i_snd)
 {
-	int penum = *i_penum, len;
+	int penum = *i_penum;
 	char *text = *i_text, *snd = *i_snd;
 
 	if (penum != -1 && text != NULL)
 	{
-		len = strlen (text) + 1;
-		if (pntevts_text[penum])
-			free (pntevts_text[penum]);
-		pntevts_text[penum] = malloc (len);
-		memcpy (pntevts_text[penum], text, len);
+		g_free (pntevts_text[penum]);
+		pntevts_text[penum] = g_strdup (text);
 	}
 
-	if (text)
-		free (text);
-	if (snd)
-		free (snd);
+	g_free (text);
+	g_free (snd);
 	*i_text = NULL;
 	*i_snd = NULL;
 	*i_penum = 0;
@@ -1690,7 +1599,7 @@ pevent_load (char *filename)
 		close (fd);
 		return 1;
 	}
-	ibuf = malloc (st.st_size);
+	ibuf = g_malloc (st.st_size);
 	read (fd, ibuf, st.st_size);
 	close (fd);
 
@@ -1706,8 +1615,6 @@ pevent_load (char *filename)
 			continue;
 		*ofs = 0;
 		ofs++;
-		/*if (*ofs == 0)
-			continue;*/
 
 		if (strcmp (buf, "event_name") == 0)
 		{
@@ -1717,53 +1624,16 @@ pevent_load (char *filename)
 			continue;
 		} else if (strcmp (buf, "event_text") == 0)
 		{
-			if (text)
-				free (text);
-
-#if 0
-			/* This allows updating of old strings. We don't use new defaults
-				if the user has customized the strings (.e.g a text theme).
-				Hash of the old default is enough to identify and replace it.
-				This only works in English. */
-
-			switch (g_str_hash (ofs))
-			{
-			case 0x526743a4:
-		/* %C08,02 Hostmask                  PRIV NOTI CHAN CTCP INVI UNIG %O */
-				text = strdup (te[XP_TE_IGNOREHEADER].def);
-				break;
-
-			case 0xe91bc9c2:
-		/* %C08,02                                                         %O */
-				text = strdup (te[XP_TE_IGNOREFOOTER].def);
-				break;
-
-			case 0x1fbfdf22:
-		/* -%C10-%C11-%O$tDCC RECV: Cannot open $1 for writing - aborting. */
-				text = strdup (te[XP_TE_DCCFILEERR].def);
-				break;
-
-			default:
-				text = strdup (ofs);
-			}
-#else
-			text = strdup (ofs);
-#endif
-
-			continue;
-		}/* else if (strcmp (buf, "event_sound") == 0)
-		{
-			if (snd)
-				free (snd);
-			snd = strdup (ofs);
+			g_free (text);
+			text = g_strdup (ofs);
 			continue;
-		}*/
+		}
 
 		continue;
 	}
 
 	pevent_trigger_load (&penum, &text, &snd);
-	free (ibuf);
+	g_free (ibuf);
 	return 0;
 }
 
@@ -1777,13 +1647,13 @@ pevent_check_all_loaded ()
 		if (pntevts_text[i] == NULL)
 		{
 			/*printf ("%s\n", te[i].name);
-			snprintf(out, sizeof(out), "The data for event %s failed to load. Reverting to defaults.\nThis may be because a new version of HexChat is loading an old config file.\n\nCheck all print event texts are correct", evtnames[i]);
+			g_snprintf(out, sizeof(out), "The data for event %s failed to load. Reverting to defaults.\nThis may be because a new version of HexChat is loading an old config file.\n\nCheck all print event texts are correct", evtnames[i]);
 			   gtkutil_simpledialog(out); */
 			/* make-te.c sets this 128 flag (DON'T call gettext() flag) */
 			if (te[i].num_args & 128)
-				pntevts_text[i] = strdup (te[i].def);
+				pntevts_text[i] = g_strdup (te[i].def);
 			else
-				pntevts_text[i] = strdup (_(te[i].def));
+				pntevts_text[i] = g_strdup (_(te[i].def));
 		}
 	}
 }
@@ -1808,9 +1678,10 @@ load_text_events ()
 #define ARG_FLAG(argn) (1 << (argn))
 
 void
-format_event (session *sess, int index, char **args, char *o, int sizeofo, unsigned int stripcolor_args)
+format_event (session *sess, int index, char **args, char *o, gsize sizeofo, unsigned int stripcolor_args)
 {
-	int len, oi, ii, numargs;
+	int len, ii, numargs;
+	gsize oi;
 	char *i, *ar, d, a, done_all = FALSE;
 
 	i = pntevts[index];
@@ -1868,19 +1739,10 @@ format_event (session *sess, int index, char **args, char *o, int sizeofo, unsig
 			done_all = TRUE;
 			continue;
 		case 3:
-/*			if (sess->type == SESS_DIALOG)
-			{
-				if (prefs.dialog_indent_nicks)
-					o[oi++] = '\t';
-				else
-					o[oi++] = ' ';
-			} else
-			{*/
-				if (prefs.hex_text_indent)
-					o[oi++] = '\t';
-				else
-					o[oi++] = ' ';
-			/*}*/
+			if (prefs.hex_text_indent)
+				o[oi++] = '\t';
+			else
+				o[oi++] = ' ';
 			break;
 		}
 	}
@@ -1908,7 +1770,7 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 	int oi, ii, max = -1, len, x;
 
 	len = strlen (input);
-	i = malloc (len + 1);
+	i = g_malloc (len + 1);
 	memcpy (i, input, len + 1);
 	check_special_chars (i, TRUE);
 
@@ -1933,14 +1795,14 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 		}
 		if (oi > 0)
 		{
-			s = (struct pevt_stage1 *) malloc (sizeof (struct pevt_stage1));
+			s = g_new (struct pevt_stage1, 1);
 			if (base == NULL)
 				base = s;
 			if (last != NULL)
 				last->next = s;
 			last = s;
 			s->next = NULL;
-			s->data = malloc (oi + sizeof (int) + 1);
+			s->data = g_malloc (oi + sizeof (int) + 1);
 			s->len = oi + sizeof (int) + 1;
 			clen += oi + sizeof (int) + 1;
 			s->data[0] = 0;
@@ -1951,12 +1813,12 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 		if (ii == len)
 		{
 			fe_message ("String ends with a $", FE_MSG_WARN);
-			return 1;
+			goto err;
 		}
 		d = i[ii++];
 		if (d == 'a')
-		{								  /* Hex value */
-			x = 0;
+		{
+			/* Hex value */
 			if (ii == len)
 				goto a_len_error;
 			d = i[ii++];
@@ -1977,24 +1839,24 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 			o[oi++] = x;
 			continue;
 
-		 a_len_error:
+		a_len_error:
 			fe_message ("String ends in $a", FE_MSG_WARN);
-			return 1;
-		 a_range_error:
+			goto err;
+		a_range_error:
 			fe_message ("$a value is greater than 255", FE_MSG_WARN);
-			return 1;
+			goto err;
 		}
 		if (d == 't')
 		{
 			/* Tab - if tabnicks is set then write '\t' else ' ' */
-			s = (struct pevt_stage1 *) malloc (sizeof (struct pevt_stage1));
+			s = g_new (struct pevt_stage1, 1);
 			if (base == NULL)
 				base = s;
 			if (last != NULL)
 				last->next = s;
 			last = s;
 			s->next = NULL;
-			s->data = malloc (1);
+			s->data = g_malloc (1);
 			s->len = 1;
 			clen += 1;
 			s->data[0] = 3;
@@ -2003,21 +1865,21 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 		}
 		if (d < '1' || d > '9')
 		{
-			snprintf (o, sizeof (o), "Error, invalid argument $%c\n", d);
+			g_snprintf (o, sizeof (o), "Error, invalid argument $%c\n", d);
 			fe_message (o, FE_MSG_WARN);
-			return 1;
+			goto err;
 		}
 		d -= '0';
 		if (max < d)
 			max = d;
-		s = (struct pevt_stage1 *) malloc (sizeof (struct pevt_stage1));
+		s = g_new (struct pevt_stage1, 1);
 		if (base == NULL)
 			base = s;
 		if (last != NULL)
 			last->next = s;
 		last = s;
 		s->next = NULL;
-		s->data = malloc (2);
+		s->data = g_malloc (2);
 		s->len = 2;
 		clen += 2;
 		s->data[0] = 1;
@@ -2025,14 +1887,14 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 	}
 	if (oi > 0)
 	{
-		s = (struct pevt_stage1 *) malloc (sizeof (struct pevt_stage1));
+		s = g_new (struct pevt_stage1, 1);
 		if (base == NULL)
 			base = s;
 		if (last != NULL)
 			last->next = s;
 		last = s;
 		s->next = NULL;
-		s->data = malloc (oi + sizeof (int) + 1);
+		s->data = g_malloc (oi + sizeof (int) + 1);
 		s->len = oi + sizeof (int) + 1;
 		clen += oi + sizeof (int) + 1;
 		s->data[0] = 0;
@@ -2040,39 +1902,54 @@ pevt_build_string (const char *input, char **output, int *max_arg)
 		memcpy (&(s->data[1 + sizeof (int)]), o, oi);
 		oi = 0;
 	}
-	s = (struct pevt_stage1 *) malloc (sizeof (struct pevt_stage1));
+	s = g_new (struct pevt_stage1, 1);
 	if (base == NULL)
 		base = s;
 	if (last != NULL)
 		last->next = s;
-	last = s;
 	s->next = NULL;
-	s->data = malloc (1);
+	s->data = g_malloc (1);
 	s->len = 1;
 	clen += 1;
 	s->data[0] = 2;
 
 	oi = 0;
 	s = base;
-	obuf = malloc (clen);
+	obuf = g_malloc (clen);
+
 	while (s)
 	{
 		next = s->next;
 		memcpy (&obuf[oi], s->data, s->len);
 		oi += s->len;
-		free (s->data);
-		free (s);
+		g_free (s->data);
+		g_free (s);
 		s = next;
 	}
 
-	free (i);
+	g_free (i);
 
 	if (max_arg)
 		*max_arg = max;
 	if (output)
 		*output = obuf;
+	else
+		g_free (obuf);
 
 	return 0;
+
+err:
+	while (s)
+	{
+		next = s->next;
+		g_free (s->data);
+		g_free (s);
+		s = next;
+	}
+
+	g_free(i);
+
+	return 1;
 }
 
 
@@ -2107,7 +1984,7 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
 
 	if (prefs.hex_text_color_nicks && (index == XP_TE_CHANACTION || index == XP_TE_CHANMSG))
 	{
-		snprintf (tbuf, sizeof (tbuf), "\003%d%s", text_color_of (a), a);
+		g_snprintf (tbuf, sizeof (tbuf), "\003%d%s", text_color_of (a), a);
 		a = tbuf;
 		stripcolor_args &= ~ARG_FLAG(1);	/* don't strip color from this argument */
 	}
@@ -2239,9 +2116,9 @@ pevent_save (char *fn)
 
 	for (i = 0; i < NUM_XP; i++)
 	{
-		write (fd, buf, snprintf (buf, sizeof (buf),
+		write (fd, buf, g_snprintf (buf, sizeof (buf),
 										  "event_name=%s\n", te[i].name));
-		write (fd, buf, snprintf (buf, sizeof (buf),
+		write (fd, buf, g_snprintf (buf, sizeof (buf),
 										  "event_text=%s\n\n", pntevts_text[i]));
 	}
 
@@ -2257,7 +2134,7 @@ char *sound_files[NUM_XP];
 void
 sound_beep (session *sess)
 {
-	if (!prefs.hex_gui_focus_omitalerts || !fe_gui_info (sess, 0) == 1)
+	if (!prefs.hex_gui_focus_omitalerts || fe_gui_info (sess, 0) != 1)
 	{
 		if (sound_files[XP_TE_BEEP] && sound_files[XP_TE_BEEP][0])
 			/* user defined beep _file_ */
@@ -2283,12 +2160,8 @@ sound_play (const char *file, gboolean quiet)
 		return;
 	}
 
-#ifdef WIN32
 	/* check for fullpath */
-	if (file[0] == '\\' || (((file[0] >= 'A' && file[0] <= 'Z') || (file[0] >= 'a' && file[0] <= 'z')) && file[1] == ':'))
-#else
-	if (file[0] == '/')
-#endif
+	if (g_path_is_absolute (file))
 	{
 		wavfile = g_strdup (file);
 	}
@@ -2363,9 +2236,8 @@ sound_load_event (char *evt, char *file)
 
 	if (file[0] && pevent_find (evt, &i) != -1)
 	{
-		if (sound_files[i])
-			free (sound_files[i]);
-		sound_files[i] = strdup (file);
+		g_free (sound_files[i]);
+		sound_files[i] = g_strdup (file);
 	}
 }
 
@@ -2417,9 +2289,9 @@ sound_save ()
 	{
 		if (sound_files[i] && sound_files[i][0])
 		{
-			write (fd, buf, snprintf (buf, sizeof (buf),
+			write (fd, buf, g_snprintf (buf, sizeof (buf),
 											  "event=%s\n", te[i].name));
-			write (fd, buf, snprintf (buf, sizeof (buf),
+			write (fd, buf, g_snprintf (buf, sizeof (buf),
 											  "sound=%s\n\n", sound_files[i]));
 		}
 	}