Mercurial > pidgin
changeset 15539:16845e318249
merge of 'da0538e2883464dc803b72262e19be90b9612288'
and 'e99f3a76f0c205fa22237b3bc8c73947a5d69493'
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sun, 04 Feb 2007 08:25:43 +0000 |
parents | b258250b72c9 (current diff) d41c1006e670 (diff) |
children | d74985add99f 5ec72809228b |
files | |
diffstat | 5 files changed, 374 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/gaim.spec.in Sun Feb 04 08:10:50 2007 +0000 +++ b/gaim.spec.in Sun Feb 04 08:25:43 2007 +0000 @@ -6,7 +6,7 @@ # When not doing betas comment this out # NOTE: %defines in spec files are evaluated in comments so the correct # way to comment it out is to replace the % with # -%define beta 6 +#define beta 7 %if 0%{?beta} %define gaimver %(echo "@VERSION@"|sed -e 's/dev//; s/beta.*//')
--- a/libpurple/log.c Sun Feb 04 08:10:50 2007 +0000 +++ b/libpurple/log.c Sun Feb 04 08:25:43 2007 +0000 @@ -248,6 +248,31 @@ return size; } +gboolean gaim_log_is_deletable(GaimLog *log) +{ + g_return_val_if_fail(log != NULL, FALSE); + g_return_val_if_fail(log->logger != NULL, FALSE); + + if (log->logger->delete == NULL) + return FALSE; + + if (log->logger->is_deletable != NULL) + return log->logger->is_deletable(log); + + return TRUE; +} + +gboolean gaim_log_delete(GaimLog *log) +{ + g_return_val_if_fail(log != NULL, FALSE); + g_return_val_if_fail(log->logger != NULL, FALSE); + + if (log->logger->delete != NULL) + return log->logger->delete(log); + + return FALSE; +} + char * gaim_log_get_log_dir(GaimLogType type, const char *name, GaimAccount *account) { @@ -318,7 +343,9 @@ int(*size)(GaimLog*), int(*total_size)(GaimLogType type, const char *name, GaimAccount *account), GList*(*list_syslog)(GaimAccount *account), - void(*get_log_sets)(GaimLogSetCallback cb, GHashTable *sets)) + void(*get_log_sets)(GaimLogSetCallback cb, GHashTable *sets), + gboolean(*delete)(GaimLog *log), + gboolean(*is_deletable)(GaimLog *log)) { #endif GaimLogLogger *logger; @@ -352,8 +379,12 @@ logger->list_syslog = va_arg(args, void *); if (functions >= 9) logger->get_log_sets = va_arg(args, void *); + if (functions >= 10) + logger->delete = va_arg(args, void *); + if (functions >= 11) + logger->is_deletable = va_arg(args, void *); - if (functions > 9) + if (functions >= 12) gaim_debug_info("log", "Dropping new functions for logger: %s (%s)\n", name, id); va_end(args); @@ -559,7 +590,7 @@ gaim_prefs_add_string("/core/logging/format", "txt"); - html_logger = gaim_log_logger_new("html", _("HTML"), 8, + html_logger = gaim_log_logger_new("html", _("HTML"), 11, NULL, html_logger_write, html_logger_finalize, @@ -567,10 +598,13 @@ html_logger_read, gaim_log_common_sizer, html_logger_total_size, - html_logger_list_syslog); + html_logger_list_syslog, + NULL, + gaim_log_common_deleter, + gaim_log_common_is_deletable); gaim_log_logger_add(html_logger); - txt_logger = gaim_log_logger_new("txt", _("Plain text"), 8, + txt_logger = gaim_log_logger_new("txt", _("Plain text"), 11, NULL, txt_logger_write, txt_logger_finalize, @@ -578,7 +612,10 @@ txt_logger_read, gaim_log_common_sizer, txt_logger_total_size, - txt_logger_list_syslog); + txt_logger_list_syslog, + NULL, + gaim_log_common_deleter, + gaim_log_common_is_deletable); gaim_log_logger_add(txt_logger); old_logger = gaim_log_logger_new("old", _("Old flat format"), 9, @@ -601,7 +638,7 @@ #else #error Unknown size of time_t #endif - gaim_value_new(GAIM_TYPE_POINTER), 2, + gaim_value_new(GAIM_TYPE_STRING), 2, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_LOG), #if SIZEOF_TIME_T == 4 @@ -817,6 +854,8 @@ struct stat st; GaimLogCommonLoggerData *data = log->logger_data; + g_return_val_if_fail(data != NULL, 0); + if (!data->path || g_stat(data->path, &st)) st.st_size = 0; @@ -943,6 +982,95 @@ g_dir_close(log_dir); } +gboolean gaim_log_common_deleter(GaimLog *log) +{ + GaimLogCommonLoggerData *data; + int ret; + + g_return_val_if_fail(log != NULL, FALSE); + + data = log->logger_data; + if (data == NULL) + return FALSE; + + if (data->path == NULL) + return FALSE; + + ret = g_unlink(data->path); + if (ret == 0) + return TRUE; + else if (ret == -1) + { + gaim_debug_error("log", "Failed to delete: %s - %s\n", data->path, strerror(errno)); + } + else + { + /* I'm not sure that g_unlink() will ever return + * something other than 0 or -1. -- rlaager */ + gaim_debug_error("log", "Failed to delete: %s\n", data->path); + } + + return FALSE; +} + +gboolean gaim_log_common_is_deletable(GaimLog *log) +{ + GaimLogCommonLoggerData *data; + gchar *dirname; + + g_return_val_if_fail(log != NULL, FALSE); + + data = log->logger_data; + if (data == NULL) + return FALSE; + + if (data->path == NULL) + return FALSE; + +#ifndef _WIN32 + dirname = g_path_get_dirname(data->path); + if (g_access(dirname, W_OK) == 0) + { + g_free(dirname); + return TRUE; + } + gaim_debug_info("log", "access(%s) failed: %s\n", dirname, strerror(errno)); + g_free(dirname); +#else + /* Unless and until someone writes equivalent win32 code, + * we'll assume the file is deletable. */ + return TRUE; +#endif + + return FALSE; +} + +static char *process_txt_log(char *txt, char *to_free) +{ + char *tmp; + + /* The to_free argument allows us to save a + * g_strdup() in some cases. */ + + if (to_free == NULL) + to_free = txt; + + /* g_markup_escape_text requires valid UTF-8 */ + if (!g_utf8_validate(txt, -1, NULL)) + { + tmp = gaim_utf8_salvage(txt); + g_free(to_free); + to_free = txt = tmp; + } + + tmp = g_markup_escape_text(txt, -1); + g_free(to_free); + txt = gaim_markup_linkify(tmp); + g_free(tmp); + + return txt; +} + #if 0 /* Maybe some other time. */ /**************** ** XML LOGGER ** @@ -1314,16 +1442,11 @@ return g_strdup(_("<font color=\"red\"><b>Unable to find log path!</b></font>")); if (g_file_get_contents(data->path, &read, NULL, NULL)) { minus_header = strchr(read, '\n'); - if (!minus_header) - minus_header = g_strdup(read); + + if (minus_header) + return process_txt_log(minus_header + 1, read); else - minus_header = g_strdup(minus_header + 1); - g_free(read); - minus_header2 = g_markup_escape_text(minus_header, -1); - g_free(minus_header); - read = gaim_markup_linkify(minus_header2); - g_free(minus_header2); - return read; + return process_txt_log(read, NULL); } return g_strdup_printf(_("<font color=\"red\"><b>Could not read file: %s</b></font>"), data->path); } @@ -1628,15 +1751,13 @@ fclose(file); read[data->length] = '\0'; *flags = 0; - if(strstr(read, "<BR>")) + if (strstr(read, "<BR>")) + { *flags |= GAIM_LOG_READ_NO_NEWLINE; - else { - tmp = g_markup_escape_text(read, -1); - g_free(read); - read = gaim_markup_linkify(tmp); - g_free(tmp); + return read; } - return read; + + return process_txt_log(read, NULL); } static int old_logger_size (GaimLog *log)
--- a/libpurple/log.h Sun Feb 04 08:10:50 2007 +0000 +++ b/libpurple/log.h Sun Feb 04 08:25:43 2007 +0000 @@ -80,15 +80,15 @@ GList *(*list)(GaimLogType type, const char *name, GaimAccount *account); /** Given one of the logs returned by the logger's list function, - * this returns the contents of the log in GtkIMHtml markup */ + * this returns the contents of the log in GtkIMHtml markup */ char *(*read)(GaimLog *log, GaimLogReadFlags *flags); /** Given one of the logs returned by the logger's list function, - * this returns the size of the log in bytes */ + * this returns the size of the log in bytes */ int (*size)(GaimLog *log); /** Returns the total size of all the logs. If this is undefined a default - * implementation is used */ + * implementation is used */ int (*total_size)(GaimLogType type, const char *name, GaimAccount *account); /** This function returns a sorted GList of available system GaimLogs */ @@ -103,6 +103,12 @@ * Loggers which implement this function must create a GaimLogSet, * then call @a cb with @a sets and the newly created GaimLogSet. */ void (*get_log_sets)(GaimLogSetCallback cb, GHashTable *sets); + + /* Attempts to delete the specified log, indicating success or failure */ + gboolean (*delete)(GaimLog *log); + + /* Tests whether a log is deletable */ + gboolean (*is_deletable)(GaimLog *log); }; /** @@ -281,6 +287,26 @@ int gaim_log_get_total_size(GaimLogType type, const char *name, GaimAccount *account); /** + * Tests whether a log is deletable + * + * A return value of @c FALSE indicates that gaim_log_delete() will fail on this + * log, unless something changes between the two calls. A return value of @c TRUE, + * however, does not guarantee the log can be deleted. + * + * @param log The log + * @return A boolean indicating if the log is deletable + */ +gboolean gaim_log_is_deletable(GaimLog *log); + +/** + * Deletes a log + * + * @param log The log + * @return A boolean indicating success or failure + */ +gboolean gaim_log_delete(GaimLog *log); + +/** * Returns the default logger directory Gaim uses for a given account * and username. This would be where Gaim stores logs created by * the built-in text or HTML loggers. @@ -332,6 +358,11 @@ * set to a GaimLogCommonLoggerData struct containing the log * file handle and log path. * + * This function is intended to be used as a "common" + * implementation of a logger's @c write function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. + * * @param log The log to write to. * @param ext The file extension to give to this log file. */ @@ -339,8 +370,12 @@ /** * Returns a sorted GList of GaimLogs of the requested type. + * * This function should only be used with logs that are written - * with gaim_log_common_writer(). + * with gaim_log_common_writer(). It's intended to be used as + * a "common" implementation of a logger's @c list function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. * * @param type The type of the logs being listed. * @param name The name of the log. @@ -356,10 +391,13 @@ /** * Returns the total size of all the logs for a given user, with - * a given extension. This is the "common" implemention of a - * logger's total_size function. + * a given extension. + * * This function should only be used with logs that are written - * with gaim_log_common_writer(). + * with gaim_log_common_writer(). It's intended to be used as + * a "common" implementation of a logger's @c total_size function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. * * @param type The type of the logs being sized. * @param name The name of the logs to size @@ -375,14 +413,49 @@ /** * Returns the size of a given GaimLog. + * * This function should only be used with logs that are written - * with gaim_log_common_writer(). + * with gaim_log_common_writer(). It's intended to be used as + * a "common" implementation of a logger's @c size function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. * * @param log The GaimLog to size. * * @return An integer indicating the size of the log in bytes. */ int gaim_log_common_sizer(GaimLog *log); + +/** + * Deletes a log + * + * This function should only be used with logs that are written + * with gaim_log_common_writer(). It's intended to be used as + * a "common" implementation of a logger's @c delete function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. + * + * @param log The GaimLog to delete. + * + * @return A boolean indicating success or failure. + */ +gboolean gaim_log_common_deleter(GaimLog *log); + +/** + * Checks to see if a log is deletable + * + * This function should only be used with logs that are written + * with gaim_log_common_writer(). It's intended to be used as + * a "common" implementation of a logger's @c is_deletable function. + * It should only be passed to gaim_log_logger_new() and never + * called directly. + * + * @param log The GaimLog to check. + * + * @return A boolean indicating if the log is deletable. + */ +gboolean gaim_log_common_is_deletable(GaimLog *log); + /*@}*/ /******************************************/ @@ -398,8 +471,9 @@ * @param functions The number of functions being passed. The following * functions are currently available (in order): @c create, * @c write, @c finalize, @c list, @c read, @c size, - * @c total_size, @c list_syslog, @c get_log_sets. For - * details on these functions, see GaimLogLogger. + * @c total_size, @c list_syslog, @c get_log_sets, + * @c delete, @c is_deletable. + * For details on these functions, see GaimLogLogger. * Functions may not be skipped. For example, passing * @c create and @c write is acceptable (for a total of * two functions). Passing @c create and @c finalize,
--- a/pidgin/gtkconv.c Sun Feb 04 08:10:50 2007 +0000 +++ b/pidgin/gtkconv.c Sun Feb 04 08:25:43 2007 +0000 @@ -6807,7 +6807,7 @@ #else #error Unkown size of time_t #endif - gaim_value_new(GAIM_TYPE_POINTER), 3, + gaim_value_new(GAIM_TYPE_STRING), 3, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONVERSATION), #if SIZEOF_TIME_T == 4
--- a/pidgin/gtklog.c Sun Feb 04 08:10:50 2007 +0000 +++ b/pidgin/gtklog.c Sun Feb 04 08:25:43 2007 +0000 @@ -26,13 +26,16 @@ #include "pidgin.h" #include "account.h" +#include "debug.h" +#include "log.h" +#include "notify.h" +#include "request.h" +#include "util.h" + #include "gtkblist.h" #include "gtkimhtml.h" #include "gtklog.h" #include "gtkutils.h" -#include "log.h" -#include "notify.h" -#include "util.h" static GHashTable *log_viewers = NULL; static void populate_log_tree(PidginLogViewer *lv); @@ -184,6 +187,8 @@ } else syslog_viewer = NULL; + gaim_request_close_with_handle(lv); + g_list_foreach(lv->logs, (GFunc)gaim_log_free, NULL); g_list_free(lv->logs); @@ -200,6 +205,139 @@ gtk_tree_view_expand_row(tv, path, FALSE); } +static void delete_log_cb(GaimLog *log) +{ + if (!gaim_log_delete(log)) + { + gaim_notify_error(NULL, NULL, "Log Deletion Failed", + "Check permissions and try again."); + } +} + +static void log_delete_log_cb(GtkWidget *menuitem, gpointer *data) +{ + PidginLogViewer *lv = data[0]; + GaimLog *log = data[1]; + const char *time = log_get_date(log); + const char *name; + char *tmp; + + if (log->type == GAIM_LOG_IM) + { + GaimBuddy *buddy = gaim_find_buddy(log->account, log->name); + if (buddy != NULL) + name = gaim_buddy_get_contact_alias(buddy); + else + name = log->name; + + tmp = g_strdup_printf(_("Are you sure you want to permanently delete the log of the " + "conversation with %s which started at %s?"), name, time); + } + else if (log->type == GAIM_LOG_CHAT) + { + GaimChat *chat = gaim_blist_find_chat(log->account, log->name); + if (chat != NULL) + name = gaim_chat_get_name(chat); + else + name = log->name; + + tmp = g_strdup_printf(_("Are you sure you want to permanently delete the log of the " + "conversation in %s which started at %s?"), name, time); + } + else if (log->type == GAIM_LOG_SYSTEM) + { + tmp = g_strdup_printf(_("Are you sure you want to permanently delete the system log " + "which started at %s?"), time); + } + else + g_return_if_reached(); + + gaim_request_action(lv, NULL, "Delete Log?", tmp, + 0, log, 2, _("Delete"), delete_log_cb, _("Cancel"), NULL); + g_free(tmp); +} + +static void log_show_popup_menu(GtkWidget *treeview, GdkEventButton *event, gpointer *data) +{ + GtkWidget *menu = gtk_menu_new(); + GtkWidget *menuitem = gtk_menu_item_new_with_label("Delete Log..."); + + if (!gaim_log_is_deletable((GaimLog *)data[1])) + gtk_widget_set_sensitive(menuitem, FALSE); + + g_signal_connect(menuitem, "activate", G_CALLBACK(log_delete_log_cb), data); + g_object_set_data_full(menuitem, "log-viewer-data", data, g_free); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + gtk_widget_show_all(menu); + + gtk_menu_popup(GTK_MENU(menu), NULL, (GtkMenuPositionFunc)data[2], NULL, NULL, + (event != NULL) ? event->button : 0, + gdk_event_get_time((GdkEvent *)event)); +} + +static gboolean log_button_press_cb(GtkWidget *treeview, GdkEventButton *event, PidginLogViewer *lv) +{ + if (event->type == GDK_BUTTON_PRESS && event->button == 3) + { + GtkTreePath *path; + GtkTreeIter iter; + GValue val; + GaimLog *log; + gpointer *data; + + if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL)) + return FALSE; + gtk_tree_model_get_iter(GTK_TREE_MODEL(lv->treestore), &iter, path); + val.g_type = 0; + gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), &iter, 1, &val); + + log = g_value_get_pointer(&val); + + if (log == NULL) + return FALSE; + + data = g_new(gpointer, 3); + data[0] = lv; + data[1] = log; + data[2] = NULL; + + log_show_popup_menu(treeview, event, data); + return TRUE; + } + + return FALSE; +} + +static gboolean log_popup_menu_cb(GtkWidget *treeview, PidginLogViewer *lv) +{ + GtkTreeSelection *sel; + GtkTreeIter iter; + GValue val; + GaimLog *log; + gpointer *data; + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(lv)); + if (!gtk_tree_selection_get_selected(sel, NULL, &iter)) + return FALSE; + + val.g_type = 0; + gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), + &iter, NODE_COLUMN, &val); + + log = g_value_get_pointer(&val); + + if (log == NULL) + return FALSE; + + data = g_new(gpointer, 3); + data[0] = lv; + data[1] = log; + data[2] = pidgin_treeview_popup_menu_position_func; + + log_show_popup_menu(treeview, NULL, data); + return TRUE; +} + static gboolean search_find_cb(gpointer data) { PidginLogViewer *viewer = data; @@ -416,6 +554,9 @@ lv); pidgin_set_accessible_label(lv->treeview, lv->label); + g_signal_connect(lv->treeview, "button-press-event", G_CALLBACK(log_button_press_cb), lv); + g_signal_connect(lv->treeview, "popup-menu", G_CALLBACK(log_popup_menu_cb), lv); + /* Log size ************/ if(log_size) { char *sz_txt = gaim_str_size_to_units(log_size);