* Finch is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * 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 02111-1301 USA static GHashTable *log_viewers = NULL; static void populate_log_tree(FinchLogViewer *lv); static FinchLogViewer *syslog_viewer = NULL; static guint log_viewer_hash(gconstpointer data) const struct log_viewer_hash *viewer = data; if (viewer->contact != NULL) return g_direct_hash(viewer->contact); return g_str_hash(viewer->username) + g_str_hash(purple_account_get_username(viewer->account)); return g_direct_hash(viewer); static gboolean log_viewer_equal(gconstpointer y, gconstpointer z) const struct log_viewer_hash *a, *b; if (a->contact != NULL) { return (a->contact == b->contact); if (a->username && b->username) { normal = g_strdup(purple_normalize(a->account, a->username)); ret = (a->account == b->account) && purple_strequal(normal, purple_normalize(b->account, b->username)); static gchar *log_get_date(PurpleLog *log) dt = g_date_time_to_local(log->time); ret = g_date_time_format(dt, "%c"); static void search_cb(GntWidget *button, FinchLogViewer *lv) const char *search_term = gnt_entry_get_text(GNT_ENTRY(lv->entry)); gnt_tree_remove_all(GNT_TREE(lv->tree)); if (lv->search != NULL && purple_strequal(lv->search, search_term)) { lv->search = g_strdup(search_term); gnt_tree_remove_all(GNT_TREE(lv->tree)); gnt_text_view_clear(GNT_TEXT_VIEW(lv->text)); for (logs = lv->logs; logs != NULL; logs = logs->next) { char *read = purple_log_read((PurpleLog*)logs->data, NULL); if (read && *read && purple_strcasestr(read, search_term)) { PurpleLog *log = logs->data; gchar *log_date = log_get_date(log); gnt_tree_add_row_last(GNT_TREE(lv->tree), gnt_tree_create_row(GNT_TREE(lv->tree), log_date), destroy_cb(GntWidget *w, struct log_viewer_hash *ht) FinchLogViewer *lv = syslog_viewer; lv = g_hash_table_lookup(log_viewers, ht); g_hash_table_remove(log_viewers, ht); purple_request_close_with_handle(lv); g_list_free_full(lv->logs, (GDestroyNotify)purple_log_free); static void log_select_cb(GntWidget *w, gpointer old, gpointer new, FinchLogViewer *viewer) GntTree *tree = GNT_TREE(w); PurpleLogReadFlags flags; char *read = NULL, *strip, *newline; if (!viewer->search && !gnt_tree_get_parent_key(tree, new)) if (log->type != PURPLE_LOG_SYSTEM) { gchar *log_date = log_get_date(log); if (log->type == PURPLE_LOG_CHAT) title = g_strdup_printf(_("Conversation in %s on %s"), title = g_strdup_printf(_("Conversation with %s on %s"), gnt_label_set_text(GNT_LABEL(viewer->label), title); read = purple_log_read(log, &flags); if (flags != PURPLE_LOG_READ_NO_NEWLINE) { newline = purple_strdup_withhtml(read); strip = purple_markup_strip_html(newline); strip = purple_markup_strip_html(read); purple_signal_emit(finch_log_get_handle(), "log-displaying", viewer, log); gnt_text_view_clear(GNT_TEXT_VIEW(viewer->text)); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(viewer->text), strip, GNT_TEXT_FLAG_NORMAL); /* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet. * I want the tree to be divided into groups like "Today," "Yesterday," "Last week," * "August," "2002," etc. based on how many conversation took place in each subdivision. * For now, I'll just make it a flat list. static void populate_log_tree(FinchLogViewer *lv) /* Logs are made from trees in real life. This is a tree made from logs */ char prev_top_month[30] = ""; PurpleLog *log = logs->data; dt = g_date_time_to_local(log->time); pmonth = g_date_time_format(dt, _("%B %Y")); if (!purple_strequal(pmonth, prev_top_month)) { month = g_strdup(pmonth); gnt_tree_add_row_last(GNT_TREE(lv->tree), gnt_tree_create_row(GNT_TREE(lv->tree), month), gnt_tree_set_expanded(GNT_TREE(lv->tree), month, FALSE); g_strlcpy(prev_top_month, month, sizeof(prev_top_month)); log_date = g_date_time_format(dt, "%c"); gnt_tree_add_row_last(GNT_TREE(lv->tree), gnt_tree_create_row(GNT_TREE(lv->tree), log_date), display_log_viewer(struct log_viewer_hash *ht, GList *logs, const char *title, /* No logs were found. */ const char *log_preferences = NULL; if (!purple_prefs_get_bool("/purple/logging/log_system")) log_preferences = _("System events will only be logged if the \"Log all status changes to system log\" preference is enabled."); if (ht->type == PURPLE_LOG_IM) { if (!purple_prefs_get_bool("/purple/logging/log_ims")) log_preferences = _("Instant messages will only be logged if the \"Log all instant messages\" preference is enabled."); } else if (ht->type == PURPLE_LOG_CHAT) { if (!purple_prefs_get_bool("/purple/logging/log_chats")) log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled."); purple_notify_info(NULL, title, _("No logs were found"), log_preferences, NULL); lv = g_new0(FinchLogViewer, 1); g_hash_table_insert(log_viewers, ht, lv); lv->window = gnt_vwindow_new(FALSE); gnt_box_set_title(GNT_BOX(lv->window), title); gnt_box_set_toplevel(GNT_BOX(lv->window), TRUE); gnt_box_set_pad(GNT_BOX(lv->window), 0); g_signal_connect(G_OBJECT(lv->window), "destroy", G_CALLBACK(destroy_cb), ht); vbox = gnt_vbox_new(FALSE); gnt_box_add_widget(GNT_BOX(lv->window), vbox); text = g_strdup_printf("%s", title); lv->label = gnt_label_new_with_format(text, GNT_TEXT_FLAG_BOLD); gnt_box_add_widget(GNT_BOX(vbox), lv->label); hbox = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(vbox), hbox); lv->tree = gnt_tree_new(); gnt_widget_set_size(lv->tree, 30, 0); g_signal_connect (G_OBJECT(lv->tree), "selection-changed", G_CALLBACK (log_select_cb), gnt_box_add_widget(GNT_BOX(hbox), lv->tree); lv->text = gnt_text_view_new(); gnt_box_add_widget(GNT_BOX(hbox), lv->text); gnt_text_view_set_flag(GNT_TEXT_VIEW(lv->text), GNT_TEXT_VIEW_TOP_ALIGN); hbox = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(vbox), hbox); /* Log size ************/ char *sz_txt = g_format_size(log_size); text = g_strdup_printf("%s %s", _("Total log size:"), sz_txt); size_label = gnt_label_new(text); gnt_box_add_widget(GNT_BOX(hbox), size_label); /* Search box **********/ gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Scroll/Search: "))); lv->entry = gnt_entry_new(""); gnt_box_add_widget(GNT_BOX(hbox), lv->entry); g_signal_connect(GNT_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv); gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(lv->text), lv->entry); gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(lv->text), lv->entry); gnt_widget_show(lv->window); our_logging_blows(PurpleLogSet *set, PurpleLogSet *setagain, GList **list) /* The iteration happens on the first list. So we use the shorter list in front */ if (set->type != PURPLE_LOG_IM) *list = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, set->name, set->account), *list); void finch_log_show(PurpleLogType type, const char *username, PurpleAccount *account) struct log_viewer_hash *ht; FinchLogViewer *lv = NULL; const char *name = username; if (type != PURPLE_LOG_IM) { g_return_if_fail(account != NULL); g_return_if_fail(username != NULL); ht = g_new0(struct log_viewer_hash, 1); ht->username = g_strdup(username); if (log_viewers == NULL) { log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { gnt_window_present(lv->window); if (type == PURPLE_LOG_CHAT) { chat = purple_blist_find_chat(account, username); name = purple_chat_get_name(chat); title = g_strdup_printf(_("Conversations in %s"), name); buddy = purple_blist_find_buddy(account, username); name = purple_buddy_get_contact_alias(buddy); title = g_strdup_printf(_("Conversations with %s"), name); title = g_strdup(_("All Conversations")); logs = purple_log_get_logs(type, username, account); size = purple_log_get_total_size(type, username, account); /* This will happen only for IMs */ GHashTable *table = purple_log_get_log_sets(); g_hash_table_foreach(table, (GHFunc)our_logging_blows, &logs); g_hash_table_destroy(table); logs = g_list_sort(logs, purple_log_compare); display_log_viewer(ht, logs, title, size); void finch_log_show_contact(PurpleContact *contact) struct log_viewer_hash *ht; FinchLogViewer *lv = NULL; g_return_if_fail(contact != NULL); ht = g_new0(struct log_viewer_hash, 1); ht->type = PURPLE_LOG_IM; if (log_viewers == NULL) { log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { gnt_window_present(lv->window); for (child = purple_blist_node_get_first_child((PurpleBlistNode*)contact); child; child = purple_blist_node_get_sibling_next(child)) { if (!PURPLE_IS_BUDDY(child)) name = purple_buddy_get_name((PurpleBuddy *)child); account = purple_buddy_get_account((PurpleBuddy *)child); logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, name, total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, name, account); logs = g_list_sort(logs, purple_log_compare); name = purple_contact_get_alias(contact); name = purple_buddy_get_contact_alias(purple_contact_get_priority_buddy(contact)); /* This will happen if the contact doesn't have an alias, * and none of the contact's buddies are online. * There is probably a better way to deal with this. */ child = purple_blist_node_get_first_child((PurpleBlistNode*)contact); if (PURPLE_IS_BUDDY(child)) { name = purple_buddy_get_contact_alias((PurpleBuddy *)child); title = g_strdup_printf(_("Conversations with %s"), name); display_log_viewer(ht, logs, title, total_log_size); if (syslog_viewer != NULL) { gnt_window_present(syslog_viewer->window); for(accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) { PurpleAccount *account = (PurpleAccount *)accounts->data; if(purple_protocols_find(purple_account_get_protocol_id(account)) == NULL) logs = g_list_concat(purple_log_get_system_logs(account), logs); logs = g_list_sort(logs, purple_log_compare); syslog_viewer = display_log_viewer(NULL, logs, _("System Log"), 0); /**************************************************************************** * GNT LOG SUBSYSTEM ******************************************************* ****************************************************************************/ finch_log_get_handle(void) void finch_log_init(void) void *handle = finch_log_get_handle(); purple_signal_register(handle, "log-displaying", purple_marshal_VOID__POINTER_POINTER, G_TYPE_POINTER, /* (FinchLogViewer *) */ purple_signals_unregister_by_instance(finch_log_get_handle());