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 + -
显示快捷键?