log_reader.c
来自「Linux下的多协议即时通讯程序源代码」· C语言 代码 · 共 2,177 行 · 第 1/4 页
C
2,177 行
#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <stdio.h>#ifndef PURPLE_PLUGINS# define PURPLE_PLUGINS#endif#include "internal.h"#include "debug.h"#include "log.h"#include "plugin.h"#include "pluginpref.h"#include "prefs.h"#include "stringref.h"#include "util.h"#include "version.h"#include "xmlnode.h"/* This must be the last Purple header included. */#ifdef _WIN32#include "win32dep.h"#endif/* Where is the Windows partition mounted? */#ifndef PURPLE_LOG_READER_WINDOWS_MOUNT_POINT#define PURPLE_LOG_READER_WINDOWS_MOUNT_POINT "/mnt/windows"#endifenum name_guesses { NAME_GUESS_UNKNOWN, NAME_GUESS_ME, NAME_GUESS_THEM};/***************************************************************************** * Adium Logger * *****************************************************************************//* The adium logger doesn't write logs, only reads them. This is to include * Adium logs in the log viewer transparently. */static PurpleLogLogger *adium_logger;enum adium_log_type { ADIUM_HTML, ADIUM_TEXT,};struct adium_logger_data { char *path; enum adium_log_type type;};static GList *adium_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account){ GList *list = NULL; const char *logdir; PurplePlugin *plugin; PurplePluginProtocolInfo *prpl_info; char *prpl_name; char *temp; char *path; GDir *dir; g_return_val_if_fail(sn != NULL, list); g_return_val_if_fail(account != NULL, list); logdir = purple_prefs_get_string("/plugins/core/log_reader/adium/log_directory"); /* By clearing the log directory path, this logger can be (effectively) disabled. */ if (!*logdir) return list; plugin = purple_find_prpl(purple_account_get_protocol_id(account)); if (!plugin) return NULL; prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); if (!prpl_info->list_icon) return NULL; prpl_name = g_ascii_strup(prpl_info->list_icon(account, NULL), -1); temp = g_strdup_printf("%s.%s", prpl_name, account->username); path = g_build_filename(logdir, temp, sn, NULL); g_free(temp); dir = g_dir_open(path, 0, NULL); if (dir) { const gchar *file; while ((file = g_dir_read_name(dir))) { if (!purple_str_has_prefix(file, sn)) continue; if (purple_str_has_suffix(file, ".html") || purple_str_has_suffix(file, ".AdiumHTMLLog")) { struct tm tm; const char *date = file; date += strlen(sn) + 2; if (sscanf(date, "%u|%u|%u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) { purple_debug(PURPLE_DEBUG_ERROR, "Adium log parse", "Filename timestamp parsing error\n"); } else { char *filename = g_build_filename(path, file, NULL); FILE *handle = g_fopen(filename, "rb"); char *contents; char *contents2; struct adium_logger_data *data; PurpleLog *log; if (!handle) { g_free(filename); continue; } /* XXX: This is really inflexible. */ contents = g_malloc(57); fread(contents, 56, 1, handle); fclose(handle); contents[56] = '\0'; /* XXX: This is fairly inflexible. */ contents2 = contents; while (*contents2 && *contents2 != '>') contents2++; if (*contents2) contents2++; while (*contents2 && *contents2 != '>') contents2++; if (*contents2) contents2++; if (sscanf(contents2, "%u.%u.%u", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) { purple_debug(PURPLE_DEBUG_ERROR, "Adium log parse", "Contents timestamp parsing error\n"); g_free(contents); g_free(filename); continue; } g_free(contents); data = g_new0(struct adium_logger_data, 1); 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); log->logger = adium_logger; log->logger_data = data; list = g_list_append(list, log); } } else if (purple_str_has_suffix(file, ".adiumLog")) { struct tm tm; const char *date = file; date += strlen(sn) + 2; if (sscanf(date, "%u|%u|%u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) { purple_debug(PURPLE_DEBUG_ERROR, "Adium log parse", "Filename timestamp parsing error\n"); } else { char *filename = g_build_filename(path, file, NULL); FILE *handle = g_fopen(filename, "rb"); char *contents; char *contents2; struct adium_logger_data *data; PurpleLog *log; if (!handle) { g_free(filename); continue; } /* XXX: This is really inflexible. */ contents = g_malloc(14); fread(contents, 13, 1, handle); fclose(handle); contents[13] = '\0'; contents2 = contents; while (*contents2 && *contents2 != '(') contents2++; if (*contents2) contents2++; if (sscanf(contents2, "%u.%u.%u", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) { purple_debug(PURPLE_DEBUG_ERROR, "Adium log parse", "Contents timestamp parsing error\n"); g_free(contents); g_free(filename); continue; } g_free(contents); 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); log->logger = adium_logger; log->logger_data = data; list = g_list_append(list, log); } } } g_dir_close(dir); } g_free(prpl_name); g_free(path); return list;}static char *adium_logger_read (PurpleLog *log, PurpleLogReadFlags *flags){ struct adium_logger_data *data; GError *error = NULL; gchar *read = NULL; gsize length; g_return_val_if_fail(log != NULL, g_strdup("")); data = log->logger_data; g_return_val_if_fail(data->path != NULL, g_strdup("")); purple_debug(PURPLE_DEBUG_INFO, "Adium log read", "Reading %s\n", data->path); if (!g_file_get_contents(data->path, &read, &length, &error)) { purple_debug(PURPLE_DEBUG_ERROR, "Adium log read", "Error reading log\n"); if (error) g_error_free(error); return g_strdup(""); } if (data->type != ADIUM_HTML) { char *escaped = g_markup_escape_text(read, -1); g_free(read); read = escaped; }#ifdef WIN32 /* This problem only seems to show up on Windows. * The BOM is displaying as a space at the beginning of the log. */ if (purple_str_has_prefix(read, "\xef\xbb\xbf")) { /* FIXME: This feels so wrong... */ char *temp = g_strdup(&(read[3])); g_free(read); read = temp; }#endif /* TODO: Apply formatting. * Replace the above hack with something better, since we'll * be looping over the entire log file contents anyway. */ return read;}static int adium_logger_size (PurpleLog *log){ struct adium_logger_data *data; char *text; size_t size; g_return_val_if_fail(log != NULL, 0); data = log->logger_data; if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) { struct stat st; if (!data->path || stat(data->path, &st)) st.st_size = 0; return st.st_size; } text = adium_logger_read(log, NULL); size = strlen(text); g_free(text); return size;}static void adium_logger_finalize(PurpleLog *log){ struct adium_logger_data *data; g_return_if_fail(log != NULL); data = log->logger_data; g_free(data->path);}/***************************************************************************** * Fire Logger * *****************************************************************************/#if 0/* The fire logger doesn't write logs, only reads them. This is to include * Fire logs in the log viewer transparently. */static PurpleLogLogger *fire_logger;struct fire_logger_data {};static GList *fire_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account){ /* TODO: Do something here. */ return NULL;}static char * fire_logger_read (PurpleLog *log, PurpleLogReadFlags *flags){ struct fire_logger_data *data; g_return_val_if_fail(log != NULL, g_strdup("")); data = log->logger_data; /* TODO: Do something here. */ return g_strdup("");}static int fire_logger_size (PurpleLog *log){ g_return_val_if_fail(log != NULL, 0); if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) return 0; /* TODO: Do something here. */ return 0;}static void fire_logger_finalize(PurpleLog *log){ g_return_if_fail(log != NULL); /* TODO: Do something here. */}#endif/***************************************************************************** * Messenger Plus! Logger * *****************************************************************************/#if 0/* The messenger_plus logger doesn't write logs, only reads them. This is to include * Messenger Plus! logs in the log viewer transparently. */static PurpleLogLogger *messenger_plus_logger;struct messenger_plus_logger_data {};static GList *messenger_plus_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account){ /* TODO: Do something here. */ return NULL;}static char * messenger_plus_logger_read (PurpleLog *log, PurpleLogReadFlags *flags){ struct messenger_plus_logger_data *data = log->logger_data; g_return_val_if_fail(log != NULL, g_strdup("")); data = log->logger_data; /* TODO: Do something here. */ return g_strdup("");}static int messenger_plus_logger_size (PurpleLog *log){ g_return_val_if_fail(log != NULL, 0); if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) return 0; /* TODO: Do something here. */ return 0;}static void messenger_plus_logger_finalize(PurpleLog *log){ g_return_if_fail(log != NULL); /* TODO: Do something here. */}#endif/***************************************************************************** * MSN Messenger Logger * *****************************************************************************//* The msn logger doesn't write logs, only reads them. This is to include * MSN Messenger message histories in the log viewer transparently. */static PurpleLogLogger *msn_logger;struct msn_logger_data { xmlnode *root; xmlnode *message; const char *session_id; int last_log; GString *text;};/* 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(xmlnode *message, struct tm **tm_out){ const char *datetime; static struct tm tm2; time_t stamp; const char *date; const char *time; int month; int day; int year; int hour; int min; 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 datetime = xmlnode_get_attrib(message, "DateTime"); if (!(datetime && *datetime)) { purple_debug_error("MSN log timestamp parse", "Attribute missing: %s\n", "DateTime"); return (time_t)0; } 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 date = 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; } time = xmlnode_get_attrib(message, "Time"); if (!(time && *time)) { purple_debug_error("MSN log timestamp parse", "Attribute missing: %s\n", "Time"); *tm_out = &tm2; return stamp; } if (sscanf(date, "%u/%u/%u", &month, &day, &year) != 3) { purple_debug_error("MSN log timestamp parse", "%s parsing error\n", "Date"); *tm_out = &tm2; return stamp; } else { if (month > 12) { int tmp = day; day = month; month = tmp; } } if (sscanf(time, "%u:%u:%u %c", &hour, &min, &sec, &am_pm) != 4) { purple_debug_error("MSN log timestamp parse", "%s parsing error\n", "Time"); *tm_out = &tm2; return stamp; } if (am_pm == 'P') { hour += 12;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?