log_reader.c

来自「Linux下的多协议即时通讯程序源代码」· C语言 代码 · 共 2,177 行 · 第 1/4 页

C
2,177
字号
		if (name_guessed != NAME_GUESS_UNKNOWN) {			text = g_string_append(text, "<span style=\"color: #");			if (name_guessed == NAME_GUESS_ME)				text = g_string_append(text, "16569E");			else				text = g_string_append(text, "A82F2F");			text = g_string_append(text, ";\">");		}		time_unix = msn_logger_parse_timestamp(message, &tm);		timestamp = g_strdup_printf("<font size=\"2\">(%02u:%02u:%02u)</font> ",				tm->tm_hour, tm->tm_min, tm->tm_sec);		text = g_string_append(text, timestamp);		g_free(timestamp);		if (from_name) {			text = g_string_append(text, "<b>");			if (name_guessed == NAME_GUESS_ME) {				if (log->account->alias)					text = g_string_append(text, log->account->alias);				else					text = g_string_append(text, log->account->username);			}			else if (name_guessed == NAME_GUESS_THEM)				text = g_string_append(text, their_name);			else				text = g_string_append(text, from_name);			text = g_string_append(text, ":</b> ");		}		if (name_guessed != NAME_GUESS_UNKNOWN)			text = g_string_append(text, "</span>");		style     = xmlnode_get_attrib(text_node, "Style");		tmp = xmlnode_get_data(text_node);		if (style && *style) {			text = g_string_append(text, "<span style=\"");			text = g_string_append(text, style);			text = g_string_append(text, "\">");			text = g_string_append(text, tmp);			text = g_string_append(text, "</span>\n");		} else {			text = g_string_append(text, tmp);			text = g_string_append(text, "\n");		}		g_free(tmp);	}	data->text = text;	return text->str;}static int msn_logger_size (PurpleLog *log){	char *text;	size_t size;	g_return_val_if_fail(log != NULL, 0);	if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes"))		return 0;	text = msn_logger_read(log, NULL);	size = strlen(text);	g_free(text);	return size;}static void msn_logger_finalize(PurpleLog *log){	struct msn_logger_data *data;	g_return_if_fail(log != NULL);	data = log->logger_data;	if (data->last_log)		xmlnode_free(data->root);	if (data->text)		g_string_free(data->text, FALSE);}/***************************************************************************** * Trillian Logger                                                           * *****************************************************************************//* The trillian logger doesn't write logs, only reads them.  This is to include * Trillian logs in the log viewer transparently. */static PurpleLogLogger *trillian_logger;static void trillian_logger_finalize(PurpleLog *log);struct trillian_logger_data {	char *path; /* FIXME: Change this to use PurpleStringref like log.c:old_logger_list */	int offset;	int length;	char *their_nickname;};static GList *trillian_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account){	GList *list = NULL;	const char *logdir;	PurplePlugin *plugin;	PurplePluginProtocolInfo *prpl_info;	char *prpl_name;	const char *buddy_name;	char *filename;	char *path;	GError *error = NULL;	gchar *contents = NULL;	gsize length;	gchar *line;	gchar *c;	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/trillian/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);	buddy_name = purple_normalize(account, sn);	filename = g_strdup_printf("%s.log", buddy_name);	path = g_build_filename(		logdir, prpl_name, filename, NULL);	purple_debug(PURPLE_DEBUG_INFO, "Trillian log list",				"Reading %s\n", path);	/* FIXME: There's really no need to read the entire file at once.	 * See src/log.c:old_logger_list for a better approach.	 */	if (!g_file_get_contents(path, &contents, &length, &error)) {		if (error) {			g_error_free(error);			error = NULL;		}		g_free(path);		path = g_build_filename(			logdir, prpl_name, "Query", filename, NULL);		purple_debug(PURPLE_DEBUG_INFO, "Trillian log list",					"Reading %s\n", path);		if (!g_file_get_contents(path, &contents, &length, &error)) {			if (error)				g_error_free(error);		}	}	g_free(filename);	if (contents) {		struct trillian_logger_data *data = NULL;		int offset = 0;		int last_line_offset = 0;		line = contents;		c = contents;		while (*c) {			offset++;			if (*c != '\n') {				c++;				continue;			}			*c = '\0';			if (purple_str_has_prefix(line, "Session Close ")) {				if (data && !data->length) {					if (!(data->length = last_line_offset - data->offset)) {						/* This log had no data, so we remove it. */						GList *last = g_list_last(list);						purple_debug(PURPLE_DEBUG_INFO, "Trillian log list",							"Empty log. Offset %i\n", data->offset);						trillian_logger_finalize((PurpleLog *)last->data);						list = g_list_delete_link(list, last);					}				}			} else if (line[0] && line[1] && line [3] &&					   purple_str_has_prefix(&line[3], "sion Start ")) {				char *their_nickname = line;				char *timestamp;				if (data && !data->length)					data->length = last_line_offset - data->offset;				while (*their_nickname && (*their_nickname != ':'))					their_nickname++;				their_nickname++;				/* This code actually has nothing to do with				 * the timestamp YET. I'm simply using this				 * variable for now to NUL-terminate the				 * their_nickname string.				 */				timestamp = their_nickname;				while (*timestamp && *timestamp != ')')					timestamp++;				if (*timestamp == ')') {					char *month;					struct tm tm;					*timestamp = '\0';					if (line[0] && line[1] && line[2])						timestamp += 3;					/* Now we start dealing with the timestamp. */					/* Skip over the day name. */					while (*timestamp && (*timestamp != ' '))						timestamp++;					*timestamp = '\0';					timestamp++;					/* Parse out the month. */					month = timestamp;					while (*timestamp &&  (*timestamp != ' '))						timestamp++;					*timestamp = '\0';					timestamp++;					/* Parse the day, time, and year. */					if (sscanf(timestamp, "%u %u:%u:%u %u",							&tm.tm_mday, &tm.tm_hour,							&tm.tm_min, &tm.tm_sec,							&tm.tm_year) != 5) {						purple_debug(PURPLE_DEBUG_ERROR,							"Trillian log timestamp parse",							"Session Start parsing error\n");					} else {						PurpleLog *log;						tm.tm_year -= 1900;						/* Let the C library deal with						 * daylight savings time.						 */						tm.tm_isdst = -1;						/* Ugly hack, in case current locale						 * is not English. This code is taken						 * from log.c.						 */						if (strcmp(month, "Jan") == 0) {							tm.tm_mon= 0;						} else if (strcmp(month, "Feb") == 0) {							tm.tm_mon = 1;						} else if (strcmp(month, "Mar") == 0) {							tm.tm_mon = 2;						} else if (strcmp(month, "Apr") == 0) {							tm.tm_mon = 3;						} else if (strcmp(month, "May") == 0) {							tm.tm_mon = 4;						} else if (strcmp(month, "Jun") == 0) {							tm.tm_mon = 5;						} else if (strcmp(month, "Jul") == 0) {							tm.tm_mon = 6;						} else if (strcmp(month, "Aug") == 0) {							tm.tm_mon = 7;						} else if (strcmp(month, "Sep") == 0) {							tm.tm_mon = 8;						} else if (strcmp(month, "Oct") == 0) {							tm.tm_mon = 9;						} else if (strcmp(month, "Nov") == 0) {							tm.tm_mon = 10;						} else if (strcmp(month, "Dec") == 0) {							tm.tm_mon = 11;						}						data = g_new0(							struct trillian_logger_data, 1);						data->path = g_strdup(path);						data->offset = offset;						data->length = 0;						data->their_nickname =							g_strdup(their_nickname);						/* 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 = trillian_logger;						log->logger_data = data;						list = g_list_append(list, log);					}				}			}			c++;			line = c;			last_line_offset = offset;		}		g_free(contents);	}	g_free(path);	g_free(prpl_name);	return list;}static char * trillian_logger_read (PurpleLog *log, PurpleLogReadFlags *flags){	struct trillian_logger_data *data;	char *read;	FILE *file;	PurpleBuddy *buddy;	char *escaped;	GString *formatted;	char *c;	const char *line;	g_return_val_if_fail(log != NULL, g_strdup(""));	data = log->logger_data;	g_return_val_if_fail(data->path != NULL, g_strdup(""));	g_return_val_if_fail(data->length > 0, g_strdup(""));	g_return_val_if_fail(data->their_nickname != NULL, g_strdup(""));	purple_debug(PURPLE_DEBUG_INFO, "Trillian log read",				"Reading %s\n", data->path);	read = g_malloc(data->length + 2);	file = g_fopen(data->path, "rb");	fseek(file, data->offset, SEEK_SET);	fread(read, data->length, 1, file);	fclose(file);	if (read[data->length-1] == '\n') {		read[data->length] = '\0';	} else {		read[data->length] = '\n';		read[data->length+1] = '\0';	}	/* Load miscellaneous data. */	buddy = purple_find_buddy(log->account, log->name);	escaped = g_markup_escape_text(read, -1);	g_free(read);	read = escaped;	/* Apply formatting... */	formatted = g_string_sized_new(strlen(read));	c = read;	line = read;	while (c)	{		const char *link;		const char *footer = NULL;		GString *temp = NULL;		if ((c = strstr(c, "\n")))		{			*c = '\0';			c++;		}		/* Convert links.		 *		 * The format is (Link: URL)URL		 * So, I want to find each occurance of "(Link: " and replace that chunk with:		 * <a href="		 * Then, replace the next ")" with:		 * ">		 * Then, replace the next " " (or add this if the end-of-line is reached) with:		 * </a>		 * 		 * As implemented, this isn't perfect, but it should cover common cases.		 */		while (line && (link = strstr(line, "(Link: ")))		{			const char *tmp = link;			link += 7;			if (*link)			{				char *end_paren;				char *space;				if (!(end_paren = strstr(link, ")")))				{					/* Something is not as we expect.  Bail out. */					break;				}				if (!temp)					temp = g_string_sized_new(c ? (c - 1 - line) : strlen(line));				g_string_append_len(temp, line, (tmp - line));				/* Start an <a> tag. */				g_string_append(temp, "<a href=\"");				/* Append up to the ) */				g_string_append_len(temp, link, end_paren - link);				/* Finish the <a> tag. */				g_string_append(temp, "\">");				/* The \r is a bit of a hack to keep there from being a \r in				 * the link text, which may not matter. */				if ((space = strstr(end_paren, " ")) || (space = strstr(end_paren, "\r")))				{					g_string_append_len(temp, end_paren + 1, space - end_paren - 1);					/* Close the <a> tag. */					g_string_append(temp, "</a>");					space++;				}				else				{					/* There is no space before the end of the line. */					g_string_append(temp, end_paren + 1);					/* Close the <a> tag. */					g_string_append(temp, "</a>");				}				line = space;			}			else			{				/* Something is not as we expect.  Bail out. */				break;			}		}		if (temp)		{			if (line)				g_string_append(temp, line);			line = temp->str;		}		if (*line == '[') {			const char *timestamp;			if ((timestamp = strstr(line, "]"))) {				line++;				/* TODO: Parse the timestamp and convert it to Purple's format. */				g_string_append(formatted, "<font size=\"2\">(");				g_string_append_len(formatted, line, (timestamp - line));				g_string_append(formatted,")</font> ");				line = timestamp + 1;				if (line[0] && line[1])					line++;			}			if (purple_str_has_prefix(line, "*** ")) {				line += (sizeof("*** ") - 1);				g_string_append(formatted, "<b>");				footer = "</b>";				if (purple_str_has_prefix(line, "NOTE: This user is offline.")) {					line = _("User is offline.");				} else if (purple_str_has_prefix(line,						"NOTE: Your status is currently set to ")) {					line += (sizeof("NOTE: ") - 1);				} else if (purple_str_has_prefix(line, "Auto-response sent to ")) {					g_string_append(formatted, _("Auto-response sent:"));					while (*line && *line != ':')						line++;					if (*line)						line++;					g_string_append(formatted, "</b>");					footer = NULL;				} else if (strstr(line, " signed off ")) {					if (buddy != NULL && buddy->alias)						g_string_append_printf(formatted,							_("%s has signed off."), buddy->alias);					else						g_string_append_printf(formatted,							_("%s has signed off."), log->name);					line = "";				} else if (strstr(line, " signed on ")) {					if (buddy != NULL && buddy->alias)						g_string_append(formatted, buddy->alias);					else						g_string_append(formatted, log->name);					line = " logged in.";				} else if (purple_str_has_prefix(line,					"One or more messages may have been undeliverable.")) {					g_string_append(formatted,						"<span style=\"color: #ff0000;\">");					g_string_append(formatted,						_("One or more messages may have been "						  "undeliverable."));					line = "";					footer = "</span></b>";				} else if (purple_str_has_prefix(line,						"You have been disconnected.")) {					g_string_append(formatted,						"<span style=\"color: #ff0000;\">");					g_string_append(formatted,						_("You were disconnected from the server."));					line = "";					footer = "</span></b>";				} else if (purple_str_has_prefix(line,						"You are currently disconnected.")) {					g_string_append(formatted,						"<span style=\"color: #ff0000;\">");					line = _("You are currently disconnected. Messages "					         "will not be received unless you are "					         "logged in.");					footer = "</span></b>";				} else if (purple_str_has_prefix(line,						"Your previous message has not been sent.")) {					g_string_append(formatted,						"<span style=\"color: #ff0000;\">");					if (purple_str_has_prefix(line,						"Your previous message has not been sent.  "

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?