--- a/libpurple/plugins/log_reader.c Tue Oct 12 03:50:01 2021 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2736 +0,0 @@
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-#include <glib/gstdio.h>
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-/* Where is the Windows partition mounted? */
-#ifndef PURPLE_LOG_READER_WINDOWS_MOUNT_POINT
-#define PURPLE_LOG_READER_WINDOWS_MOUNT_POINT "/mnt/windows"
-/*****************************************************************************
- *****************************************************************************/
-/* 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;
-struct adium_logger_data {
- enum adium_log_type type;
-static GList *adium_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
- PurpleProtocol *protocol;
- g_return_val_if_fail(sn != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
- 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 || !*logdir)
- protocol = purple_account_get_protocol(account);
- protocol_name = g_ascii_strup(purple_protocol_get_list_icon(protocol, account, NULL), -1);
- temp = g_strdup_printf("%s.%s", protocol_name, purple_account_get_username(account));
- path = g_build_filename(logdir, temp, sn, NULL);
- dir = g_dir_open(path, 0, NULL);
- while ((file = g_dir_read_name(dir))) {
- if (!g_str_has_prefix(file, sn)) {
- if (g_str_has_suffix(file, ".html") ||
- g_str_has_suffix(file, ".AdiumHTMLLog")) {
- gint year, month, day, hour, minute, second;
- const char *date = file;
- date += strlen(sn) + 2;
- if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
- purple_debug_error("Adium log parse",
- "Filename timestamp parsing error\n");
- char *filename = g_build_filename(path, file, NULL);
- FILE *handle = g_fopen(filename, "rb");
- char contents[57]; /* XXX: This is really inflexible. */
- struct adium_logger_data *data;
- rd = fread(contents, 1, 56, handle) == 0;
- /* XXX: This is fairly inflexible. */
- while (*contents2 && *contents2 != '>')
- while (*contents2 && *contents2 != '>')
- if (sscanf(contents2, "%u.%u.%u",
- &hour, &minute, &second) != 3) {
- purple_debug_error("Adium log parse",
- "Contents timestamp parsing error\n");
- data = g_new0(struct adium_logger_data, 1);
- data->type = ADIUM_HTML;
- /* XXX: Look into this later... Should we figure out a timezone? */
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
- log->logger = adium_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
- } else if (g_str_has_suffix(file, ".adiumLog")) {
- gint year, month, day, hour, minute, second;
- const char *date = file;
- date += strlen(sn) + 2;
- if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
- purple_debug_error("Adium log parse",
- "Filename timestamp parsing error\n");
- char *filename = g_build_filename(path, file, NULL);
- FILE *handle = g_fopen(filename, "rb");
- char contents[14]; /* XXX: This is really inflexible. */
- struct adium_logger_data *data;
- rd = fread(contents, 1, 13, handle);
- while (*contents2 && *contents2 != '(')
- if (sscanf(contents2, "%u.%u.%u", &hour, &minute, &second) != 3) {
- purple_debug_error("Adium log parse",
- "Contents timestamp parsing error\n");
- data = g_new0(struct adium_logger_data, 1);
- data->type = ADIUM_TEXT;
- /* XXX: Look into this later... Should we figure out a timezone? */
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
- log->logger = adium_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
-static char *adium_logger_read (PurpleLog *log, PurpleLogReadFlags *flags)
- struct adium_logger_data *data;
- /* XXX: TODO: We probably want to set PURPLE_LOG_READ_NO_NEWLINE
- * XXX: TODO: for HTML logs. */
- 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_info("Adium log read", "Reading %s\n", data->path);
- if (!g_file_get_contents(data->path, &read, NULL, &error)) {
- purple_debug_error("Adium log read", "Error reading log: %s\n",
- (error && error->message) ? error->message : "Unknown error");
- if (data->type != ADIUM_HTML) {
- char *escaped = g_markup_escape_text(read, -1);
- /* This problem only seems to show up on Windows.
- * The BOM is displaying as a space at the beginning of the log.
- if (g_str_has_prefix(read, "\xef\xbb\xbf")) {
- /* FIXME: This feels so wrong... */
- char *temp = g_strdup(&(read[3]));
- /* TODO: Apply formatting.
- * Replace the above hack with something better, since we'll
- * be looping over the entire log file contents anyway.
-static int adium_logger_size (PurpleLog *log)
- struct adium_logger_data *data;
- g_return_val_if_fail(log != NULL, 0);
- data = log->logger_data;
- if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) {
- if (!data->path || g_stat(data->path, &st))
- text = adium_logger_read(log, NULL);
-static void adium_logger_finalize(PurpleLog *log)
- struct adium_logger_data *data;
- g_return_if_fail(log != NULL);
- data = log->logger_data;
-/*****************************************************************************
- * 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 {
- PurpleXmlNode *message;
- const char *session_id;
-/* 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."
-msn_logger_parse_timestamp(PurpleXmlNode *message)
- g_return_val_if_fail(message != NULL, NULL);
- datetime = purple_xmlnode_get_attrib(message, "DateTime");
- if (!(datetime && *datetime))
- purple_debug_error("MSN log timestamp parse",
- "Attribute missing: %s\n", "DateTime");
- stamp = purple_str_to_date_time(datetime, TRUE);
- date = purple_xmlnode_get_attrib(message, "Date");
- purple_debug_error("MSN log timestamp parse",
- "Attribute missing: %s\n", "Date");
- time = purple_xmlnode_get_attrib(message, "Time");
- purple_debug_error("MSN log timestamp parse",
- "Attribute missing: %s\n", "Time");
- if (sscanf(date, "%u/%u/%u", &month, &day, &year) != 3)
- purple_debug_error("MSN log timestamp parse",
- "%s parsing error\n", "Date");
- 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");
- } else if (hour == 12) {
- str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
- t = purple_str_to_date_time(str, TRUE);
- if (g_date_time_compare(stamp, t) > 0)
- diff = g_date_time_difference(stamp, t);
- diff = g_date_time_difference(t, stamp);
- if (diff > (14LL * G_TIME_SPAN_HOUR)) {
- /* Swap day & month variables, to see if it's a non-US date. */
- str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
- t = purple_str_to_date_time(str, TRUE);
- if (g_date_time_compare(stamp, t) > 0)
- diff = g_date_time_difference(stamp, t);
- diff = g_date_time_difference(t, stamp);
- if (diff > (14LL * G_TIME_SPAN_HOUR)) {
- /* We got a time, it's not impossible, but
- * the diff is too large. Display the UTC time. */
- /* We got a time, it's not impossible, but
- * the diff is too large. Display the UTC time. */
- /* If we got here, the time is legal with a reasonable offset.
- * Let's find out if it's in our TZ. */
- if (purple_str_to_date_time(str, FALSE) == stamp)
-static GList *msn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
- const char *savedfilename = NULL;
- gchar *contents = NULL;
- PurpleXmlNode *message;
- const char *old_session_id = "";
- struct msn_logger_data *data = NULL;
- g_return_val_if_fail(sn != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
- if (!purple_strequal(purple_account_get_protocol_id(account), "prpl-msn"))
- logdir = purple_prefs_get_string("/plugins/core/log_reader/msn/log_directory");
- /* By clearing the log directory path, this logger can be (effectively) disabled. */
- if (!logdir || !*logdir)
- buddy = purple_blist_find_buddy(account, sn);
- if ((username = g_strdup(purple_account_get_string(
- account, "log_reader_msn_log_folder", NULL)))) {
- /* As a special case, we allow the null string to kill the parsing
- * straight away. This would allow the user to deal with the case
- * when two account have the same username at different domains and
- * only one has logs stored.
- username = g_strdup(purple_normalize(account, purple_account_get_username(account)));
- savedfilename = purple_blist_node_get_string(PURPLE_BLIST_NODE(buddy),
- "log_reader_msn_log_filename");
- /* As a special case, we allow the null string to kill the parsing
- * straight away. This would allow the user to deal with the case
- * when two buddies have the same username at different domains and
- * only one has logs stored.
- logfile = g_strdup(savedfilename);
- logfile = g_strdup_printf("%s.xml", purple_normalize(account, sn));
- path = g_build_filename(logdir, username, "History", logfile, NULL);
- if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
- gboolean found = FALSE;
- /* We had a saved filename, but it doesn't exist.
- * Returning now is the right course of action because we don't
- * want to detect another file incorrectly.
- /* Perhaps we're using a new version of MSN with the weird numbered folders.
- * I don't know how the numbers are calculated, so I'm going to attempt to
- * find logs by pattern matching...
- at_sign = g_strrstr(username, "@");
- dir = g_dir_open(logdir, 0, NULL);
- while ((name = g_dir_read_name(dir))) {
- if (!g_str_has_prefix(c, username)) {
- if (!g_ascii_isdigit(*c))
- path = g_build_filename(logdir, name, NULL);
- /* The !c makes sure we got to the end of the while loop above. */
- if (!*c && g_file_test(path, G_FILE_TEST_IS_DIR)) {
- char *history_path = g_build_filename(
- path, "History", NULL);
- if (g_file_test(history_path, G_FILE_TEST_IS_DIR)) {
- purple_account_set_string(account,
- "log_reader_msn_log_folder", name);
- /* If we've reached this point, we've found a History folder. */
- username = g_strdup(purple_normalize(account, sn));
- at_sign = g_strrstr(username, "@");
- dir = g_dir_open(path, 0, NULL);
- while ((name = g_dir_read_name(dir))) {
- if (!g_str_has_prefix(c, username)) {
- if (!g_ascii_isdigit(*c))
- full_path = g_build_filename(path, name, NULL);
- if (purple_strequal(c, ".xml") &&
- g_file_test(full_path, G_FILE_TEST_EXISTS)) {
- logfile = g_strdup(name);
- logfile = NULL; /* No sense saving the obvious buddy@domain.com. */
- purple_debug_info("MSN log read", "Reading %s\n", path);
- if (!g_file_get_contents(path, &contents, &length, &error)) {
- purple_debug_error("MSN log read", "Error reading log\n");
- /* Reading the file was successful...
- * Save its name if it involves the crazy numbers. The idea here is that you could
- * then tweak the blist.xml file by hand if need be. This would be the case if two
- * buddies have the same username at different domains. One set of logs would get
- * detected for both buddies.
- if (buddy && logfile) {
- PurpleBlistNode *node = PURPLE_BLIST_NODE(buddy);
- purple_blist_node_set_string(node, "log_reader_msn_log_filename", logfile);
- root = purple_xmlnode_from_str(contents, length);
- for (message = purple_xmlnode_get_child(root, "Message"); message;
- message = purple_xmlnode_get_next_twin(message)) {
- const char *session_id;
- session_id = purple_xmlnode_get_attrib(message, "SessionID");
- purple_debug_error("MSN log parse",
- "Error parsing message: %s\n", "SessionID missing");
- if (!purple_strequal(session_id, old_session_id)) {
- * The session ID differs from the last message.
- * Thus, this is the start of a new conversation.
- data = g_new0(struct msn_logger_data, 1);
- data->message = message;
- data->session_id = session_id;
- data->last_log = FALSE;
- stamp = msn_logger_parse_timestamp(message);
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp);
- log->logger = msn_logger;
- log->logger_data = data;
- g_date_time_unref(stamp);
- list = g_list_prepend(list, log);
- old_session_id = session_id;
- return g_list_reverse(list);
-static char * msn_logger_read (PurpleLog *log, PurpleLogReadFlags *flags)
- struct msn_logger_data *data;
- PurpleXmlNode *message;
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
- g_return_val_if_fail(log != NULL, g_strdup(""));
- data = log->logger_data;
- /* The GTK code which displays the logs g_free()s whatever is
- * returned from this function. Thus, we can't reuse the str
- * part of the GString. The only solution is to free it and
- g_string_free(data->text, FALSE);
- text = g_string_new("");
- if (!data->root || !data->message || !data->session_id) {
- /* Something isn't allocated correctly. */
- purple_debug_error("MSN log parse",
- "Error parsing message: %s\n", "Internal variables inconsistent");
- for (message = data->message; message;
- message = purple_xmlnode_get_next_twin(message)) {
- const char *new_session_id;
- PurpleXmlNode *text_node;
- const char *from_name = NULL;
- const char *to_name = NULL;
- enum name_guesses name_guessed = NAME_GUESS_UNKNOWN;
- const char *their_name;
- new_session_id = purple_xmlnode_get_attrib(message, "SessionID");
- /* If this triggers, something is wrong with the XML. */
- purple_debug_error("MSN log parse",
- "Error parsing message: %s\n", "New SessionID missing");
- if (!purple_strequal(new_session_id, data->session_id)) {
- /* The session ID differs from the first message.
- * Thus, this is the start of a new conversation.
- text_node = purple_xmlnode_get_child(message, "Text");
- from = purple_xmlnode_get_child(message, "From");
- PurpleXmlNode *user = purple_xmlnode_get_child(from, "User");
- from_name = purple_xmlnode_get_attrib(user, "FriendlyName");
- /* This saves a check later. */
- to = purple_xmlnode_get_child(message, "To");
- PurpleXmlNode *user = purple_xmlnode_get_child(to, "User");
- to_name = purple_xmlnode_get_attrib(user, "FriendlyName");
- /* This saves a check later. */
- their_name = from_name;
- if (from_name && purple_prefs_get_bool("/plugins/core/log_reader/use_name_heuristics")) {
- const char *friendly_name = purple_connection_get_display_name(purple_account_get_connection(log->account));
- if (friendly_name != NULL) {
- int friendly_name_length = strlen(friendly_name);
- PurpleBuddy *buddy = purple_blist_find_buddy(log->account, log->name);
- gboolean from_name_matches;
- gboolean to_name_matches;
- their_name = purple_buddy_get_alias(buddy);
- alias = purple_account_get_private_alias(log->account);
- alias_length = strlen(alias);
- /* Try to guess which user is me.
- * The first step is to determine if either of the names matches either my
- * friendly name or alias. For this test, "match" is defined as:
- * ^(friendly_name|alias)([^a-zA-Z0-9].*)?$
- (g_str_has_prefix(from_name, friendly_name) &&
- !isalnum(*(from_name + friendly_name_length))) ||
- (g_str_has_prefix(from_name, alias) &&
- !isalnum(*(from_name + alias_length)));
- ((g_str_has_prefix(to_name, friendly_name) &&
- !isalnum(*(to_name + friendly_name_length))) ||
- (g_str_has_prefix(to_name, alias) &&
- !isalnum(*(to_name + alias_length))));
- if (from_name_matches) {
- if (!to_name_matches) {
- name_guessed = NAME_GUESS_ME;
- } else if (to_name_matches) {
- name_guessed = NAME_GUESS_THEM;
- const char *server_alias = NULL;
- char *alias = g_strdup(purple_buddy_get_alias(buddy));
- /* "Truncate" the string at the first non-alphanumeric
- * character. The idea is to relax the comparison.
- for (temp = alias; *temp ; temp++) {
- alias_length = strlen(alias);
- /* Try to guess which user is them.
- * The first step is to determine if either of the names
- * matches their alias. For this test, "match" is
- * defined as: ^alias([^a-zA-Z0-9].*)?$
- (g_str_has_prefix(from_name, alias) &&
- !isalnum(*(from_name + alias_length)));
- to_name_matches = to_name &&
- (g_str_has_prefix(to_name, alias) &&
- !isalnum(*(to_name + alias_length)));
- if (from_name_matches) {
- if (!to_name_matches) {
- name_guessed = NAME_GUESS_THEM;
- } else if (to_name_matches) {
- name_guessed = NAME_GUESS_ME;
- } else if ((server_alias = purple_buddy_get_server_alias(buddy))) {
- /* Try to guess which user is them.
- * The first step is to determine if either of
- * the names matches their friendly name. For
- * this test, "match" is defined as:
- * ^friendly_name([^a-zA-Z0-9].*)?$
- (g_str_has_prefix(from_name,
- friendly_name_length)));
- ((g_str_has_prefix(to_name, server_alias) &&
- friendly_name_length))));
- if (from_name_matches) {
- if (!to_name_matches) {
- name_guessed = NAME_GUESS_THEM;
- } else if (to_name_matches) {
- name_guessed = NAME_GUESS_ME;
- 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");
- text = g_string_append(text, "A82F2F");
- text = g_string_append(text, ";\">");
- if ((dt = msn_logger_parse_timestamp(message)) != NULL) {
- timestamp = g_date_time_format(
- "<font size=\"2\">(%H:%M:%s)</font> ");
- text = g_string_append(text, timestamp);
- text = g_string_append(text,
- "<font size=\"2\">(00:00:00)</font> ");
- text = g_string_append(text, "<b>");
- if (name_guessed == NAME_GUESS_ME) {
- if (purple_account_get_private_alias(log->account))
- text = g_string_append(text, purple_account_get_private_alias(log->account));
- text = g_string_append(text, purple_account_get_username(log->account));
- else if (name_guessed == NAME_GUESS_THEM)
- text = g_string_append(text, their_name);
- 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 = purple_xmlnode_get_attrib(text_node, "Style");
- tmp = purple_xmlnode_get_data(text_node);
- 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><br>");
- text = g_string_append(text, tmp);
- text = g_string_append(text, "<br>");
-static int msn_logger_size (PurpleLog *log)
- g_return_val_if_fail(log != NULL, 0);
- if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes"))
- text = msn_logger_read(log, NULL);
-static void msn_logger_finalize(PurpleLog *log)
- struct msn_logger_data *data;
- g_return_if_fail(log != NULL);
- data = log->logger_data;
- purple_xmlnode_free(data->root);
- g_string_free(data->text, FALSE);
-/*****************************************************************************
- *****************************************************************************/
-/* 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 */
-static GList *trillian_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
- PurpleProtocol *protocol;
- const char *buddy_name;
- gchar *contents = NULL;
- g_return_val_if_fail(sn != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
- 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 || !*logdir)
- protocol = purple_account_get_protocol(account);
- protocol_name = g_ascii_strup(purple_protocol_get_list_icon(protocol, account, NULL), -1);
- buddy_name = purple_normalize(account, sn);
- filename = g_strdup_printf("%s.log", buddy_name);
- path = g_build_filename(
- logdir, protocol_name, filename, NULL);
- 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)) {
- path = g_build_filename(
- logdir, protocol_name, "Query", filename, NULL);
- purple_debug_info("Trillian log list", "Reading %s\n", path);
- if (!g_file_get_contents(path, &contents, &length, &error)) {
- struct trillian_logger_data *data = NULL;
- int last_line_offset = 0;
- if (g_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_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[2] &&
- g_str_has_prefix(&line[3], "sion Start ")) {
- /* The conditional is to make sure we're not reading off
- * the end of the string. We don't want strlen(), as that'd
- * have to count the whole string needlessly.
- * The odd check here is because a Session Start at the
- * beginning of the file can be overwritten with a UTF-8
- * byte order mark. Yes, it's weird.
- char *their_nickname = line;
- if (data && !data->length)
- data->length = last_line_offset - data->offset;
- while (*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 != ')')
- if (*timestamp == ')') {
- gint year, month, day, hour, minute, second;
- if (line[0] && line[1] && line[2])
- /* Now we start dealing with the timestamp. */
- /* Skip over the day name. */
- while (*timestamp && (*timestamp != ' '))
- /* Parse out the month. */
- while (*timestamp && (*timestamp != ' '))
- /* Parse the day, time, and year. */
- if (sscanf(timestamp, "%u %u:%u:%u %u",
- purple_debug_error("Trillian log timestamp parse",
- "Session Start parsing error\n");
- month = purple_time_parse_month(month_str);
- struct trillian_logger_data, 1);
- data->path = g_strdup(path);
- g_strdup(their_nickname);
- /* XXX: Look into this later... Should we figure out a timezone? */
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM,
- sn, account, NULL, dt);
- log->logger = trillian_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
- last_line_offset = offset;
- return g_list_reverse(list);
-static char * trillian_logger_read (PurpleLog *log, PurpleLogReadFlags *flags)
- struct trillian_logger_data *data;
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
- 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_info("Trillian log read", "Reading %s\n", data->path);
- file = g_fopen(data->path, "rb");
- g_return_val_if_fail(file != NULL, g_strdup(""));
- read = g_malloc(data->length + 2);
- if (fseek(file, data->offset, SEEK_SET) != 0) {
- g_return_val_if_reached(g_strdup(""));
- data->length = fread(read, 1, data->length, file);
- if (read[data->length-1] == '\n') {
- read[data->length] = '\0';
- read[data->length] = '\n';
- read[data->length+1] = '\0';
- /* Load miscellaneous data. */
- buddy = purple_blist_find_buddy(log->account, log->name);
- escaped = g_markup_escape_text(read, -1);
- /* Apply formatting... */
- formatted = g_string_sized_new(strlen(read));
- const char *footer = NULL;
- /* There's always a trailing '\n' at the end of the file (see above), so
- * just quit out if we don't find another, because we're at the end.
- * The format is (Link: URL)URL
- * So, I want to find each occurrence of "(Link: " and replace that chunk with:
- * Then, replace the next ")" with:
- * Then, replace the next " " (or add this if the end-of-line is reached) with:
- * As implemented, this isn't perfect, but it should cover common cases.
- while (line && (link = strstr(line, "(Link: ")))
- const char *tmp = link;
- if (!(end_paren = strchr(link, ')')))
- /* Something is not as we expect. Bail out. */
- temp = g_string_sized_new(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 = strchr(end_paren, ' ')) || (space = strchr(end_paren, '\r')))
- g_string_append_len(temp, end_paren + 1, space - end_paren - 1);
- /* Close the <a> tag. */
- g_string_append(temp, "</a>");
- /* 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>");
- /* Something is not as we expect. Bail out. */
- g_string_append(temp, line);
- if (line && *line == '[') {
- if ((timestamp = strchr(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> ");
- if (line[0] && line[1])
- if (g_str_has_prefix(line, "*** ")) {
- line += (sizeof("*** ") - 1);
- g_string_append(formatted, "<b>");
- if (g_str_has_prefix(line, "NOTE: This user is offline.")) {
- line = _("User is offline.");
- } else if (g_str_has_prefix(
- "NOTE: Your status is currently set to ")) {
- line += (sizeof("NOTE: ") - 1);
- } else if (g_str_has_prefix(line, "Auto-response sent to ")) {
- g_string_append(formatted, _("Auto-response sent:"));
- while (*line && *line != ':')
- g_string_append(formatted, "</b>");
- } else if (strstr(line, " signed off ")) {
- const char *alias = NULL;
- alias = purple_buddy_get_alias(buddy);
- g_string_append_printf(formatted,
- _("%s has signed off."), alias);
- g_string_append_printf(formatted,
- _("%s has signed off."), log->name);
- } else if (strstr(line, " signed on ")) {
- const char *alias = NULL;
- alias = purple_buddy_get_alias(buddy);
- g_string_append(formatted, alias);
- g_string_append(formatted, log->name);
- } else if (g_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 "
- footer = "</span></b>";
- } else if (g_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."));
- footer = "</span></b>";
- } else if (g_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 "
- footer = "</span></b>";
- } else if (g_str_has_prefix(line, "Your previous message has "
- g_string_append(formatted,
- "<span style=\"color: #ff0000;\">");
- "Your previous message has not been sent. "
- "Reason: Maximum length exceeded.")) {
- g_string_append(formatted,
- _("Message could not be sent because "
- "the maximum length was exceeded."));
- g_string_append(formatted,
- _("Message could not be sent."));
- "Your previous message "
- "has not been sent. ") - 1);
- footer = "</span></b>";
- } else if (g_str_has_prefix(line, data->their_nickname)) {
- const char *alias = purple_buddy_get_alias(buddy);
- line += strlen(data->their_nickname) + 2;
- g_string_append_printf(formatted,
- "<span style=\"color: #A82F2F;\">"
- "<b>%s</b></span>: ", alias);
- const char *line2 = strchr(line, ':');
- acct_name = purple_account_get_private_alias(log->account);
- acct_name = purple_account_get_username(log->account);
- g_string_append_printf(formatted,
- "<span style=\"color: #16569E;\">"
- "<b>%s</b></span>:", acct_name);
- g_string_append(formatted, line);
- g_string_free(temp, TRUE);
- g_string_append(formatted, footer);
- g_string_append(formatted, "<br>");
- /* XXX: TODO: What can we do about removing \r characters?
- * XXX: TODO: and will that allow us to avoid this
- * XXX: TODO: g_strchomp(), or is that unrelated? */
- /* XXX: TODO: Avoid this g_strchomp() */
- return g_strchomp(g_string_free(formatted, FALSE));
-static int trillian_logger_size (PurpleLog *log)
- struct trillian_logger_data *data;
- g_return_val_if_fail(log != NULL, 0);
- data = log->logger_data;
- if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) {
- return data ? data->length : 0;
- text = trillian_logger_read(log, NULL);
-static void trillian_logger_finalize(PurpleLog *log)
- struct trillian_logger_data *data;
- g_return_if_fail(log != NULL);
- data = log->logger_data;
- g_free(data->their_nickname);
-/*****************************************************************************
- *****************************************************************************/
-/* The QIP logger doesn't write logs, only reads them. This is to include
- * QIP logs in the log viewer transparently.
-#define QIP_LOG_DELIMITER "--------------------------------------"
-#define QIP_LOG_IN_MESSAGE (QIP_LOG_DELIMITER "<-")
-#define QIP_LOG_OUT_MESSAGE (QIP_LOG_DELIMITER ">-")
-#define QIP_LOG_IN_MESSAGE_ESC (QIP_LOG_DELIMITER "<-")
-#define QIP_LOG_OUT_MESSAGE_ESC (QIP_LOG_DELIMITER ">-")
-#define QIP_LOG_TIMEOUT (G_TIME_SPAN_HOUR)
-static PurpleLogLogger *qip_logger;
-struct qip_logger_data {
- char *path; /* FIXME: Change this to use PurpleStringref like log.c:old_logger_list */
-static GList *qip_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
- PurpleProtocol *protocol;
- struct qip_logger_data *data = NULL;
- GDateTime *prev_dt = NULL;
- gint year, month, day, hour, minute, second;
- gboolean main_cycle = TRUE;
- g_return_val_if_fail(sn != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
- /* QIP only supports ICQ. */
- if (!purple_strequal(purple_account_get_protocol_id(account), "prpl-icq"))
- logdir = purple_prefs_get_string("/plugins/core/log_reader/qip/log_directory");
- /* By clearing the log directory path, this logger can be (effectively) disabled. */
- if (!logdir || !*logdir)
- protocol = purple_account_get_protocol(account);
- username = g_strdup(purple_normalize(account, purple_account_get_username(account)));
- filename = g_strdup_printf("%s.txt", purple_normalize(account, sn));
- path = g_build_filename(logdir, username, "History", filename, NULL);
- purple_debug_info("QIP logger", "Reading %s\n", path);
- if (!g_file_get_contents(path, &contents, NULL, &error)) {
- purple_debug_error("QIP logger",
- "Couldn't read file %s: %s \n", path,
- (error && error->message) ? error->message : "Unknown error");
- gboolean add_new_log = FALSE;
- if (g_str_has_prefix(c, QIP_LOG_IN_MESSAGE) ||
- g_str_has_prefix(c, QIP_LOG_OUT_MESSAGE)) {
- /* Find the last '(' character. */
- } else if ((tmp = strchr(c, '\n')) != NULL) {
- while (*tmp && *tmp != '(') --tmp;
- const char *timestamp = ++c;
- /* Parse the time, day, month and year */
- if (sscanf(timestamp, "%u:%u:%u %u/%u/%u",
- &hour, &minute, &second,
- &day, &month, &year) != 6) {
- purple_debug_error("QIP logger list",
- "Parsing timestamp error\n");
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- add_new_log = g_date_time_difference(dt, prev_dt) > QIP_LOG_TIMEOUT;
- if (add_new_log && prev_dt) {
- data = g_new0(struct qip_logger_data, 1);
- data->path = g_strdup(path);
- data->length = new_line - start_log;
- offset += data->length;
- purple_debug_info("QIP logger list",
- "Creating log: path = (%s); length = (%d); offset = (%d)\n",
- data->path, data->length, data->offset);
- /* XXX: Look into this later... Should we figure out a timezone? */
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM, sn, account,
- log->logger = qip_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
- g_date_time_unref(prev_dt);
- if ((c = strchr(c, '\n')))
- return g_list_reverse(list);
-static char *qip_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
- struct qip_logger_data *data;
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
- 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(""));
- file = g_fopen(data->path, "rb");
- g_return_val_if_fail(file != NULL, g_strdup(""));
- contents = g_malloc(data->length + 2);
- if (fseek(file, data->offset, SEEK_SET) != 0) {
- g_return_val_if_reached(g_strdup(""));
- data->length = fread(contents, 1, data->length, file);
- contents[data->length] = '\n';
- contents[data->length + 1] = '\0';
- /* Convert file contents from Cp1251 to UTF-8 codeset */
- if (!(utf8_string = g_convert(contents, -1, "UTF-8", "Cp1251", NULL, NULL, &error))) {
- purple_debug_error("QIP logger",
- "Couldn't convert file %s to UTF-8: %s\n", data->path,
- (error && error->message) ? error->message : "Unknown error");
- contents = g_markup_escape_text(utf8_string, -1);
- buddy = purple_blist_find_buddy(log->account, log->name);
- /* Apply formatting... */
- formatted = g_string_sized_new(data->length + 2);
- gboolean is_in_message = FALSE;
- if (g_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC) ||
- g_str_has_prefix(line, QIP_LOG_OUT_MESSAGE_ESC)) {
- is_in_message = g_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC);
- /* Find the last '(' character. */
- if ((tmp = strchr(c, '\n')) != NULL) {
- while (*tmp && *tmp != '(') --tmp;
- const char *timestamp = c;
- /* Parse the time, day, month and year */
- if (sscanf(timestamp, "%u:%u:%u",
- &hour, &min, &sec) != 3) {
- purple_debug_error("QIP logger read",
- "Parsing timestamp error\n");
- g_string_append(formatted, "<font size=\"2\">");
- /* TODO: Figure out if we can do anything more locale-independent. */
- g_string_append_printf(formatted,
- "(%u:%02u:%02u) %cM ", hour % 12,
- min, sec, (hour >= 12) ? 'P': 'A');
- g_string_append(formatted, "</font> ");
- const char *alias = NULL;
- (alias = purple_buddy_get_alias(buddy))) {
- g_string_append_printf(formatted,
- "<span style=\"color: #A82F2F;\">"
- "<b>%s</b></span>: ", alias);
- acct_name = purple_account_get_private_alias(log->account);
- acct_name = purple_account_get_username(log->account);
- g_string_append_printf(formatted,
- "<span style=\"color: #16569E;\">"
- "<b>%s</b></span>: ", acct_name);
- if ((c = strchr(c, '\n')))
- if (line[0] != '\n' && line[0] != '\r') {
- g_string_append(formatted, line);
- g_string_append(formatted, "<br>");
- /* XXX: TODO: Avoid this g_strchomp() */
- return g_strchomp(g_string_free(formatted, FALSE));
-static int qip_logger_size (PurpleLog *log)
- struct qip_logger_data *data;
- g_return_val_if_fail(log != NULL, 0);
- data = log->logger_data;
- if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) {
- return data ? data->length : 0;
- text = qip_logger_read(log, NULL);
-static void qip_logger_finalize(PurpleLog *log)
- struct qip_logger_data *data;
- g_return_if_fail(log != NULL);
- data = log->logger_data;
-/*************************************************************************
- *************************************************************************/
-/* The aMSN logger doesn't write logs, only reads them. This is to include
- * aMSN logs in the log viewer transparently.
-static PurpleLogLogger *amsn_logger;
-struct amsn_logger_data {
-#define AMSN_LOG_CONV_START "|\"LRED[Conversation started on "
-#define AMSN_LOG_CONV_END "|\"LRED[You have closed the window on "
-#define AMSN_LOG_CONV_EXTRA "01 Aug 2001 00:00:00]"
-static GList *amsn_logger_parse_file(char *filename, const char *sn, PurpleAccount *account)
- struct amsn_logger_data *data;
- purple_debug_info("aMSN logger", "Reading %s\n", filename);
- if (!g_file_get_contents(filename, &contents, NULL, &error)) {
- purple_debug_error("aMSN logger",
- "Couldn't read file %s: %s \n", filename,
- (error && error->message) ?
- error->message : "Unknown error");
- gboolean found_start = FALSE;
- gint year, month, day, hour, minute, second;
- if (g_str_has_prefix(c, AMSN_LOG_CONV_START)) {
- if (sscanf(c + strlen(AMSN_LOG_CONV_START),
- &day, (char*)&month_str, &year,
- &hour, &minute, &second) != 6) {
- purple_debug_error("aMSN logger",
- "Error parsing start date for %s\n",
- month = purple_time_parse_month(month_str);
- } else if (g_str_has_prefix(c, AMSN_LOG_CONV_END) && found_start) {
- data = g_new0(struct amsn_logger_data, 1);
- data->path = g_strdup(filename);
- data->length = c - start_log
- + strlen(AMSN_LOG_CONV_END)
- + strlen(AMSN_LOG_CONV_EXTRA);
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
- log->logger = amsn_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
- purple_debug_info("aMSN logger",
- sn, data->path, data->offset, data->length);
- /* I've seen the file end without the AMSN_LOG_CONV_END bit */
- data = g_new0(struct amsn_logger_data, 1);
- data->path = g_strdup(filename);
- data->length = c - start_log
- + strlen(AMSN_LOG_CONV_END)
- + strlen(AMSN_LOG_CONV_EXTRA);
- dt = g_date_time_new_local(year, month, day, hour, minute, second);
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
- log->logger = amsn_logger;
- log->logger_data = data;
- list = g_list_prepend(list, log);
- purple_debug_info("aMSN logger",
- sn, data->path, data->offset, data->length);
-/* `log_dir`/username@hotmail.com/logs/buddyname@hotmail.com.log */
-/* `log_dir`/username@hotmail.com/logs/Month Year/buddyname@hotmail.com.log */
-static GList *amsn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
- logdir = purple_prefs_get_string("/plugins/core/log_reader/amsn/log_directory");
- /* By clearing the log directory path, this logger can be (effectively) disabled. */
- if (!logdir || !*logdir)
- /* aMSN only works with MSN/WLM */
- if (!purple_strequal(purple_account_get_protocol_id(account), "prpl-msn"))
- username = g_strdup(purple_normalize(account, purple_account_get_username(account)));
- buddy_log = g_strdup_printf("%s.log", purple_normalize(account, sn));
- log_path = g_build_filename(logdir, username, "logs", NULL);
- /* First check in the top-level */
- filename = g_build_filename(log_path, buddy_log, NULL);
- if (g_file_test(filename, G_FILE_TEST_EXISTS))
- list = amsn_logger_parse_file(filename, sn, account);
- /* Check in previous months */
- dir = g_dir_open(log_path, 0, NULL);
- while ((name = g_dir_read_name(dir)) != NULL) {
- filename = g_build_filename(log_path, name, buddy_log, NULL);
- if (g_file_test(filename, G_FILE_TEST_EXISTS))
- list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
- /* New versions use 'friendlier' directory names */
- purple_util_chrreplace(username, '@', '_');
- purple_util_chrreplace(username, '.', '_');
- log_path = g_build_filename(logdir, username, "logs", NULL);
- /* First check in the top-level */
- filename = g_build_filename(log_path, buddy_log, NULL);
- if (g_file_test(filename, G_FILE_TEST_EXISTS))
- list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
- /* Check in previous months */
- dir = g_dir_open(log_path, 0, NULL);
- while ((name = g_dir_read_name(dir)) != NULL) {
- filename = g_build_filename(log_path, name, buddy_log, NULL);
- if (g_file_test(filename, G_FILE_TEST_EXISTS))
- list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
-/* Really it's |"L, but the string's been escaped */
-#define AMSN_LOG_FORMAT_TAG "|"L"
-static char *amsn_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
- struct amsn_logger_data *data;
- gboolean in_span = FALSE;
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
- 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(""));
- file = g_fopen(data->path, "rb");
- g_return_val_if_fail(file != NULL, g_strdup(""));
- contents = g_malloc(data->length + 2);
- if (fseek(file, data->offset, SEEK_SET) != 0) {
- g_return_val_if_reached(g_strdup(""));
- data->length = fread(contents, 1, data->length, file);
- contents[data->length] = '\n';
- contents[data->length + 1] = '\0';
- escaped = g_markup_escape_text(contents, -1);
- formatted = g_string_sized_new(data->length + 2);
- while (start && *start) {
- end = strchr(start, '\n');
- if (g_str_has_prefix(start, AMSN_LOG_FORMAT_TAG) && in_span) {
- /* New format for this line */
- g_string_append(formatted, "</span><br>");
- } else if (start != contents) {
- /* Continue format from previous line */
- g_string_append(formatted, "<br>");
- tag = strstr(start, AMSN_LOG_FORMAT_TAG);
- g_string_append_len(formatted, old_tag, tag - old_tag);
- tag += strlen(AMSN_LOG_FORMAT_TAG);
- g_string_append(formatted, "</span>");
- /* |"LCxxxxxx is a hex colour */
- strncpy(colour, tag + 1, 6);
- g_string_append_printf(formatted, "<span style=\"color: #%s;\">", colour);
- /* This doesn't appear to work? */
- /* g_string_append_printf(formatted, "<span style=\"color: #%6s;\">", tag + 1); */
- old_tag = tag + 7; /* C + xxxxxx */
- /* |"Lxxx is a 3-digit colour code */
- if (g_str_has_prefix(tag, "RED")) {
- g_string_append(formatted, "<span style=\"color: red;\">");
- } else if (g_str_has_prefix(tag, "GRA")) {
- g_string_append(formatted, "<span style=\"color: gray;\">");
- } else if (g_str_has_prefix(tag, "NOR")) {
- g_string_append(formatted, "<span style=\"color: black;\">");
- } else if (g_str_has_prefix(tag, "ITA")) {
- g_string_append(formatted, "<span style=\"color: blue;\">");
- } else if (g_str_has_prefix(tag, "GRE")) {
- g_string_append(formatted, "<span style=\"color: darkgreen;\">");
- purple_debug_info("aMSN logger", "Unknown colour format: %3s\n", tag);
- tag = strstr(tag, AMSN_LOG_FORMAT_TAG);
- g_string_append(formatted, old_tag);
- g_string_append(formatted, "</span>");
- return g_string_free(formatted, FALSE);
-static int amsn_logger_size(PurpleLog *log)
- struct amsn_logger_data *data;
- g_return_val_if_fail(log != NULL, 0);
- data = log->logger_data;
- if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) {
- return data ? data->length : 0;
- text = amsn_logger_read(log, NULL);
-static void amsn_logger_finalize(PurpleLog *log)
- struct amsn_logger_data *data;
- g_return_if_fail(log != NULL);
- data = log->logger_data;
-/*****************************************************************************
- *****************************************************************************/
-static void log_reader_init_prefs(void) {
- gboolean found = FALSE;
- purple_prefs_add_none("/plugins/core/log_reader");
- /* Add general preferences. */
- purple_prefs_add_bool("/plugins/core/log_reader/fast_sizes", FALSE);
- purple_prefs_add_bool("/plugins/core/log_reader/use_name_heuristics", TRUE);
- /* Add Adium log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/adium");
- /* Calculate default Adium log directory. */
- purple_prefs_add_string("/plugins/core/log_reader/adium/log_directory", "");
- path = g_build_filename(purple_home_dir(), "Library", "Application Support",
- "Adium 2.0", "Users", "Default", "Logs", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/adium/log_directory", path);
- /* Add Fire log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/fire");
- /* Calculate default Fire log directory. */
- purple_prefs_add_string("/plugins/core/log_reader/fire/log_directory", "");
- path = g_build_filename(purple_home_dir(), "Library", "Application Support",
- "Fire", "Sessions", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/fire/log_directory", path);
- /* Add Messenger Plus! log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/messenger_plus");
- /* Calculate default Messenger Plus! log directory. */
- folder = wpurple_get_special_folder(CSIDL_PERSONAL);
- path = g_build_filename(folder, "My Chat Logs", NULL);
- path = g_build_filename(PURPLE_LOG_READER_WINDOWS_MOUNT_POINT,
- "Documents and Settings", g_get_user_name(),
- "My Documents", "My Chat Logs", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/messenger_plus/log_directory", path ? path : "");
- /* Add MSN Messenger log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/msn");
- /* Calculate default MSN message history directory. */
- folder = wpurple_get_special_folder(CSIDL_PERSONAL);
- path = g_build_filename(folder, "My Received Files", NULL);
- path = g_build_filename(PURPLE_LOG_READER_WINDOWS_MOUNT_POINT,
- "Documents and Settings", g_get_user_name(),
- "My Documents", "My Received Files", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/msn/log_directory", path ? path : "");
- /* Add Trillian log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/trillian");
- /* XXX: While a major hack, this is the most reliable way I could
- * think of to determine the Trillian installation directory.
- reg_key = "Trillian.SkinZip\\shell\\Add\\command\\";
- if (wpurple_reg_val_exists(HKEY_CLASSES_ROOT, reg_key, NULL))
- folder = wpurple_read_reg_string(HKEY_CLASSES_ROOT, reg_key, NULL);
- /* Break apart buffer. */
- while (*temp && *temp != '"')
- while (*temp && *temp != ' ')
- if (g_str_has_suffix(value, "trillian.exe")) {
- value[strlen(value) - (sizeof("trillian.exe") - 1)] = '\0';
- path = g_build_filename(value, "users", "default", "talk.ini", NULL);
- char *folder = wpurple_get_special_folder(CSIDL_PROGRAM_FILES);
- path = g_build_filename(folder, "Trillian",
- "users", "default", "talk.ini", NULL);
- /* Read talk.ini file to find the log directory. */
- gchar *contents = NULL;
- if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
- purple_debug_info("Trillian talk.ini read",
- if (path && !g_file_get_contents(path, &contents, NULL, &error)) {
- purple_debug_error("Trillian talk.ini read",
- "Error reading talk.ini: %s\n",
- (error && error->message) ? error->message : "Unknown error");
- line = cursor = contents;
- /* XXX: This assumes the first Directory key is under [Logging]. */
- if (g_str_has_prefix(line, "Directory=")) {
- line += (sizeof("Directory=") - 1);
- purple_prefs_add_string(
- "/plugins/core/log_reader/trillian/log_directory",
- folder = wpurple_get_special_folder(CSIDL_PROGRAM_FILES);
- path = g_build_filename(folder, "Trillian", "users",
- "default", "logs", NULL);
- purple_prefs_add_string(
- "/plugins/core/log_reader/trillian/log_directory", path ? path : "");
-#else /* !defined(_WIN32) */
- /* TODO: At some point, this could attempt to parse talk.ini
- * TODO: from the default Trillian install directory on the
- * TODO: Windows mount point. */
- /* Calculate default Trillian log directory. */
- path = g_build_filename(PURPLE_LOG_READER_WINDOWS_MOUNT_POINT,
- "Program Files", "Trillian", "users",
- "default", "logs", NULL);
- purple_prefs_add_string(
- "/plugins/core/log_reader/trillian/log_directory", path);
- /* Add QIP log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/qip");
- /* Calculate default QIP log directory. */
- folder = wpurple_get_special_folder(CSIDL_PROGRAM_FILES);
- path = g_build_filename(folder, "QIP", "Users", NULL);
- path = g_build_filename(PURPLE_LOG_READER_WINDOWS_MOUNT_POINT,
- "Program Files", "QIP", "Users", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/qip/log_directory", path ? path : "");
- /* Add aMSN Messenger log directory preference. */
- purple_prefs_add_none("/plugins/core/log_reader/amsn");
- /* Calculate default aMSN log directory. */
- folder = wpurple_get_special_folder(CSIDL_PROFILE); /* Silly aMSN, not using CSIDL_APPDATA */
- path = g_build_filename(folder, "amsn", NULL);
- path = g_build_filename(purple_home_dir(), ".amsn", NULL);
- purple_prefs_add_string("/plugins/core/log_reader/amsn/log_directory", path ? path : "");
-static PurplePluginPrefFrame *
-get_plugin_pref_frame(PurplePlugin *plugin)
- PurplePluginPrefFrame *frame;
- PurplePluginPref *ppref;
- g_return_val_if_fail(plugin != NULL, FALSE);
- frame = purple_plugin_pref_frame_new();
- /* Add general preferences. */
- ppref = purple_plugin_pref_new_with_label(_("General Log Reading Configuration"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/fast_sizes", _("Fast size calculations"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/use_name_heuristics", _("Use name heuristics"));
- purple_plugin_pref_frame_add(frame, ppref);
- /* Add Log Directory preferences. */
- ppref = purple_plugin_pref_new_with_label(_("Log Directory"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/adium/log_directory", _("Adium"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/qip/log_directory", _("QIP"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/msn/log_directory", _("MSN Messenger"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/trillian/log_directory", _("Trillian"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(
- "/plugins/core/log_reader/amsn/log_directory", _("aMSN"));
- purple_plugin_pref_frame_add(frame, ppref);
-static GPluginPluginInfo *
-log_reader_query(GError **error)
- const gchar * const authors[] = {
- "Richard Laager <rlaager@pidgin.im>",
- return purple_plugin_info_new(
- "id", "core-log_reader",
- "name", N_("Log Reader"),
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("Includes other IM clients' logs in the log "
- "description", N_("When viewing logs, this plugin will include "
- "logs from other IM clients. Currently, this "
- "includes Adium, MSN Messenger, aMSN, and "
- "WARNING: This plugin is still alpha code and "
- "may crash frequently. Use it at your own "
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "pref-frame-cb", get_plugin_pref_frame,
-log_reader_load(GPluginPlugin *plugin, GError **error)
- g_return_val_if_fail(plugin != NULL, FALSE);
- log_reader_init_prefs();
- /* The names of IM clients are marked for translation at the request of
- translators who wanted to transliterate them. Many translators
- choose to leave them alone. Choose what's best for your language. */
- adium_logger = purple_log_logger_new("adium", _("Adium"), 6,
- purple_log_logger_add(adium_logger);
- /* The names of IM clients are marked for translation at the request of
- translators who wanted to transliterate them. Many translators
- choose to leave them alone. Choose what's best for your language. */
- qip_logger = purple_log_logger_new("qip", _("QIP"), 6,
- purple_log_logger_add(qip_logger);
- /* The names of IM clients are marked for translation at the request of
- translators who wanted to transliterate them. Many translators
- choose to leave them alone. Choose what's best for your language. */
- msn_logger = purple_log_logger_new("msn", _("MSN Messenger"), 6,
- purple_log_logger_add(msn_logger);
- /* The names of IM clients are marked for translation at the request of
- translators who wanted to transliterate them. Many translators
- choose to leave them alone. Choose what's best for your language. */
- trillian_logger = purple_log_logger_new("trillian", _("Trillian"), 6,
- trillian_logger_finalize,
- purple_log_logger_add(trillian_logger);
- /* The names of IM clients are marked for translation at the request of
- translators who wanted to transliterate them. Many translators
- choose to leave them alone. Choose what's best for your language. */
- amsn_logger = purple_log_logger_new("amsn", _("aMSN"), 6,
- purple_log_logger_add(amsn_logger);
-log_reader_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
- g_return_val_if_fail(plugin != NULL, FALSE);
- purple_log_logger_remove(adium_logger);
- purple_log_logger_free(adium_logger);
- purple_log_logger_remove(msn_logger);
- purple_log_logger_free(msn_logger);
- purple_log_logger_remove(trillian_logger);
- purple_log_logger_free(trillian_logger);
- trillian_logger = NULL;
- purple_log_logger_remove(qip_logger);
- purple_log_logger_free(qip_logger);
- purple_log_logger_remove(amsn_logger);
- purple_log_logger_free(amsn_logger);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(log_reader)
--- a/libpurple/plugins/meson.build Tue Oct 12 03:50:01 2021 -0500
+++ b/libpurple/plugins/meson.build Tue Oct 12 04:38:45 2021 -0500
@@ -21,11 +21,6 @@
install : true, install_dir : PURPLE_PLUGINDIR)
-log_reader = library('log_reader', 'log_reader.c',
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
psychic = library('psychic', 'psychic.c',
dependencies : [libpurple_dep],
--- a/po/POTFILES.in Tue Oct 12 03:50:01 2021 -0500
+++ b/po/POTFILES.in Tue Oct 12 04:38:45 2021 -0500
@@ -67,7 +67,6 @@
libpurple/plugins/keyrings/kwallet/purplekwallet.cpp
libpurple/plugins/keyrings/secretservice.c
libpurple/plugins/keyrings/wincred.c
-libpurple/plugins/log_reader.c
libpurple/plugins/notification-sound/notification-sound.c
libpurple/plugins/psychic.c
libpurple/plugins/purple-toast.c