changeset 9923:248c3f88ce99

[gaim-migrate @ 10815] (14:24:22) datallah: LSchiere2: http://www.butfer.com/gaim-patches/log_filename_escaping.patch deals with creating logs for screennames that have characters that are not valid for filenames (14:25:34) datallah: i may write a conversion script for existing log files (particularly because it will cause all irc and yahoo chats not to be found) (14:25:49) datallah: oh.. not irc chats... only yahoo chats (14:26:10) LSchiere2: can yahoo chats be found now? (14:26:35) datallah: yeah... they all have a ':' in them which is not a valid filename character in win32 (14:26:51) LSchiere2: i see. so they can be found on unix but not on win32 (14:27:51) datallah: LSchiere2: yeah, as far as i know committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Tue, 31 Aug 2004 18:28:35 +0000
parents b03884f4eda6
children 872c4d8c1192
files ChangeLog src/log.c
diffstat 2 files changed, 126 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Aug 31 18:12:27 2004 +0000
+++ b/ChangeLog	Tue Aug 31 18:28:35 2004 +0000
@@ -9,6 +9,7 @@
 
 	Bug Fixes:
 	* Compile with gtk 2.5.x (Gary Kramlich)
+	* Escape invalid characters in log names (Daniel Atallah)
 
 version 0.82.1 (08/27/2004):
 	Bug Fixes:
--- a/src/log.c	Tue Aug 31 18:12:27 2004 +0000
+++ b/src/log.c	Tue Aug 31 18:28:35 2004 +0000
@@ -178,6 +178,118 @@
 	return size;
 }
 
+#if 0
+static char* unescape_filename(const char *escaped) {
+	const char *c = escaped;
+	GString *ret;
+
+	if (escaped == NULL)
+		return NULL;
+
+	ret = g_string_new("");
+
+	/**
+	 *  <>:"/\ |?*'&$ 
+	 *	The above chars are "taboo" for gaim log names and are URL escaped
+	 *  % is also escaped so we can convert back easily
+	 */
+
+	while (*c) {
+		if (*c == '%') {
+			if (*(c + 1) && *(c + 2)) {
+				char hex[2];
+				hex[0] = *(c + 1);
+				hex[1] = *(c + 2);
+				unsigned char *nonhex;
+				gaim_base16_decode(hex, &nonhex);
+				ret = g_string_append_c(ret, *nonhex);
+				g_free(nonhex);
+				c += 2;
+			}
+		} else {
+			ret = g_string_append_c(ret, *c);
+		}
+		c++;
+	}
+
+	return g_string_free(ret, FALSE);
+}
+#endif
+
+static char* escape_filename(const char *unescaped) {
+	const char *c = unescaped;
+	char *hex;
+	GString *ret;
+
+	if (unescaped == NULL)
+		return NULL;
+
+	ret = g_string_new("");
+
+	/**
+	 *  <>:"/\ |?*'&$ 
+	 *	The above chars are "taboo" for gaim log names and are URL escaped
+	 *  % is also escaped so we can convert back easily
+	 */
+
+	while (*c) {
+		switch (*c) {
+			case '<':
+			case '>':
+			case ':':
+			case '"':
+			case '/':
+			case '\\':
+			case ' ':
+			case '|':
+			case '?':
+			case '*':
+			case '\'':
+			case '&':
+			case '$':
+			case '%':
+				hex = g_strdup_printf ("%%%X", (int) *c);
+				ret = g_string_append(ret, hex);
+				g_free(hex);
+				break;
+			default:
+				ret = g_string_append_c(ret, *c);
+		}
+		c++;
+	}
+
+	return g_string_free(ret, FALSE);
+}
+
+static char* gaim_log_get_log_dir(GaimLogType type, const char *name, GaimAccount *account) {
+	char *acct_name = escape_filename(gaim_normalize(account,
+				gaim_account_get_username(account)));
+	char *target;
+	/* does this seem like a bad way to get this component of the path to anyone else? --Nathan */
+	const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO(
+			gaim_find_prpl(gaim_account_get_protocol_id(account))
+			)->list_icon(account, NULL);
+	
+	char *dir;
+
+	if (type == GAIM_LOG_CHAT) {
+		char *temp = g_strdup_printf("%s.chat", gaim_normalize(account, name));
+		target = escape_filename(temp);
+		g_free(temp);
+	} else if(type == GAIM_LOG_SYSTEM) {
+		target = g_strdup(".system");
+	} else {
+		target = escape_filename(gaim_normalize(account, name));
+	}
+
+
+	dir = g_build_filename(gaim_user_dir(), "logs", prpl, acct_name, target, NULL);
+	g_free(target);
+	g_free(acct_name);
+
+	return dir;
+}
+
 /****************************************************************************
  * LOGGER FUNCTIONS *********************************************************
  ****************************************************************************/
@@ -336,38 +448,20 @@
 };
 
 static void log_writer_common(GaimLog *log, GaimMessageFlags type,
-							  const char *prpl, time_t time,
-							  const char *ext)
+		time_t time, const char *ext)
 {
 	char date[64];
 	struct generic_logger_data *data = log->logger_data;
 
 	if(!data) {
 		/* This log is new */
-		char *ud = gaim_user_dir();
-		char *acct_name = g_strdup(gaim_normalize(log->account,
-					gaim_account_get_username(log->account)));
-		char *target;
-		char *dir;
-		char *filename, *path;
-
-		if (log->type == GAIM_LOG_CHAT) {
-			target = g_strdup_printf("%s.chat", gaim_normalize(log->account,
-						log->name));
-		} else if(log->type == GAIM_LOG_SYSTEM) {
-			target = g_strdup(".system");
-		} else {
-			target = g_strdup(gaim_normalize(log->account, log->name));
-		}
+		char *dir, *filename, *path;
+		
+		dir = gaim_log_get_log_dir(log->type, log->name, log->account);
+		gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
 
 		strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S", localtime(&log->time));
 
-		dir = g_build_filename(ud, "logs",
-				       prpl, acct_name, target, NULL);
-		gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
-		g_free(target);
-		g_free(acct_name);
-
 		filename = g_strdup_printf("%s%s", date, ext ? ext : "");
 
 		path = g_build_filename(dir, filename, NULL);
@@ -392,26 +486,12 @@
 	GDir *dir;
 	GList *list = NULL;
 	const char *filename;
-	char *me;
-	const char *prpl;
 	char *path;
 
 	if(!account)
 		return NULL;
 
-	if (type == GAIM_LOG_CHAT)
-		me = g_strdup_printf("%s.chat", gaim_normalize(account, gaim_account_get_username(account)));
-	else
-		me = g_strdup(gaim_normalize(account, gaim_account_get_username(account)));
-
-	/* does this seem like a bad way to get this component of the path to anyone else? --Nathan */
-	prpl = GAIM_PLUGIN_PROTOCOL_INFO
-		(gaim_find_prpl(gaim_account_get_protocol_id(account)))->list_icon(account, NULL);
-	if(type == GAIM_LOG_SYSTEM)
-		path = g_build_filename(gaim_user_dir(),"logs", prpl, me, name, NULL);
-	else
-		path = g_build_filename(gaim_user_dir(),"logs", prpl, me, gaim_normalize(account, name), NULL);
-	g_free(me);
+	path = gaim_log_get_log_dir(type, name, account);
 
 	if (!(dir = g_dir_open(path, 0, NULL))) {
 		g_free(path);
@@ -472,25 +552,11 @@
 		 * creating a new file there would result in empty files in the case
 		 * that you open a convo with someone, but don't say anything.
 		 */
-		char *ud = gaim_user_dir();
-		char *guy = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account)));
-		const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
-			(gaim_find_prpl(gaim_account_get_protocol(log->account)))->list_icon(log->account, NULL);
-		char *dir;
+		char *dir = gaim_log_get_log_dir(log->type, log->name, log->account);
 		FILE *file;
-
-		if (log->type == GAIM_LOG_CHAT) {
-			char *chat = g_strdup_printf("%s.chat", guy);
-			g_free(guy);
-			guy = chat;
-		}
-
 		strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.xml", localtime(&log->time));
 
-		dir = g_build_filename(ud, "logs",
-				       prpl, guy, gaim_normalize(log->account, log->name), NULL);
 		gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
-		g_free(guy);
 
 		char *filename = g_build_filename(dir, date, NULL);
 		g_free(dir);
@@ -510,6 +576,10 @@
 			date, log->name, prpl);
 	}
 
+	/* if we can't write to the file, give up before we hurt ourselves */
+	if(!data->file)
+		return;
+
 	strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
 	gaim_markup_html_to_xhtml(message, &xhtml, NULL);
 	if (from)
@@ -569,7 +639,7 @@
 	if(!data) {
 		const char *prpl =
 			GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
-		log_writer_common(log, type, prpl, time, ".html");
+		log_writer_common(log, type, time, ".html");
 
 		data = log->logger_data;
 
@@ -707,7 +777,7 @@
 		 */
 		const char *prpl =
 			GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
-		log_writer_common(log, type, prpl, time, ".txt");
+		log_writer_common(log, type, time, ".txt");
 
 		data = log->logger_data;