# HG changeset patch # User Luke Schierer # Date 1093976915 0 # Node ID 248c3f88ce99465953a02d7e46af0ecdb30bf0ef # Parent b03884f4eda6f63037aa712ed77f4043bd7878cb [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 diff -r b03884f4eda6 -r 248c3f88ce99 ChangeLog --- 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: diff -r b03884f4eda6 -r 248c3f88ce99 src/log.c --- 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;