# HG changeset patch # User Paul Aurich # Date 1237607431 0 # Node ID 2d781c58a8a231cab46a35b91acfcee8c0583c07 # Parent cde07a2e45313c0c82d881d790a23cae4609c7df# Parent b23211876f478a1c92e9c7b89e4d5792ac8eec0e propagate from branch 'im.pidgin.pidgin' (head d70375c084af2336e7fc6646fb778120b05de9a8) to branch 'im.pidgin.cpw.darkrain42.xmpp.iq-handlers' (head a0e14a71dc7095483850d6879d12a1ece864ef6a) diff -r cde07a2e4531 -r 2d781c58a8a2 COPYRIGHT --- a/COPYRIGHT Sat Mar 14 15:50:56 2009 +0000 +++ b/COPYRIGHT Sat Mar 21 03:50:31 2009 +0000 @@ -8,6 +8,7 @@ Dave Ahlswede Manuel Amador Matt Amato +Josef Andrysek Geoffrey Antos Daniel Atallah Paul Aurich diff -r cde07a2e4531 -r 2d781c58a8a2 ChangeLog --- a/ChangeLog Sat Mar 14 15:50:56 2009 +0000 +++ b/ChangeLog Sat Mar 21 03:50:31 2009 +0000 @@ -6,8 +6,9 @@ project. With some minor additions and clean ups from Paul Aurich. XMPP: - * Add support for in-band bytestreams (XEP-0047). - * Add support for attention (XEP-0224). + * Add support for in-band bytestreams for file transfers (XEP-0047). + * Add support for sending attentions (equivalent to "buzz" and "nudge") + using the command /buzz (XEP-0224). Pidgin: * Added -f command line option to tell Pidgin to ignore NetworkManager @@ -18,6 +19,9 @@ * Pressing the Enter key in the message entry box of the New Status dialog and various other dialogs now causes the cursor to move to the next line. + * Created a unified Buddy Pounce notification window for all pounces + where "Pop up a notification" is selected, which avoids having a + new dialog box every time a pounce is triggered. (Jorge VillaseƱor) version 2.5.5 (03/01/2009): libpurple: diff -r cde07a2e4531 -r 2d781c58a8a2 ChangeLog.API --- a/ChangeLog.API Sat Mar 14 15:50:56 2009 +0000 +++ b/ChangeLog.API Sat Mar 21 03:50:31 2009 +0000 @@ -26,6 +26,14 @@ * purple_request_field_set_ui_data * purple_strequal * xmlnode_from_file + * xmlnode_set_attrib_full + + Changed: + * xmlnode_remove_attrib now removes all attributes with the + same name. Previously, it would remove the first one found, + which was completely non-deterministic. If you want to remove + the attribute with no namespace, then use NULL with + xmlnode_remove_with_namespace. Deprecated: * purple_buddy_get_local_alias @@ -40,6 +48,8 @@ * purple_status_set_attr_string * purple_presence_add_status * purple_presence_add_list + * xmlnode_set_attrib_with_namespace + * xmlnode_set_attrib_with_prefix pidgin: Added: @@ -52,6 +62,7 @@ * pidgin_blist_get_theme * pidgin_sound_is_customized * pidgin_utils_init, pidgin_utils_uninit + * pidgin_notify_pounce_add perl: Changed: diff -r cde07a2e4531 -r 2d781c58a8a2 finch/gntlog.c --- a/finch/gntlog.c Sat Mar 14 15:50:56 2009 +0000 +++ b/finch/gntlog.c Sat Mar 21 03:50:31 2009 +0000 @@ -66,7 +66,7 @@ g_str_hash(purple_account_get_username(viewer->account)); } - return (guint)viewer; + return g_direct_hash(viewer); } static gboolean log_viewer_equal(gconstpointer y, gconstpointer z) diff -r cde07a2e4531 -r 2d781c58a8a2 finch/gntplugin.c --- a/finch/gntplugin.c Sat Mar 14 15:50:56 2009 +0000 +++ b/finch/gntplugin.c Sat Mar 21 03:50:31 2009 +0000 @@ -484,10 +484,10 @@ char *value = NULL; switch(type) { case PURPLE_PREF_BOOLEAN: - value = g_strdup_printf("%d", (int)list->next->data); + value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data)); break; case PURPLE_PREF_INT: - value = g_strdup_printf("%d", (int)list->next->data); + value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data)); break; case PURPLE_PREF_STRING: value = g_strdup(list->next->data); diff -r cde07a2e4531 -r 2d781c58a8a2 finch/gntroomlist.c --- a/finch/gntroomlist.c Sat Mar 14 15:50:56 2009 +0000 +++ b/finch/gntroomlist.c Sat Mar 21 03:50:31 2009 +0000 @@ -190,7 +190,7 @@ label = g_strdup(iter->data ? "True" : "False"); break; case PURPLE_ROOMLIST_FIELD_INT: - label = g_strdup_printf("%d", (int)iter->data); + label = g_strdup_printf("%d", GPOINTER_TO_INT(iter->data)); break; case PURPLE_ROOMLIST_FIELD_STRING: label = g_strdup(iter->data); diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/account.h --- a/libpurple/account.h Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/account.h Sat Mar 21 03:50:31 2009 +0000 @@ -42,6 +42,7 @@ #include "connection.h" #include "log.h" +#include "privacy.h" #include "proxy.h" #include "prpl.h" #include "status.h" @@ -141,7 +142,7 @@ */ GSList *permit; /**< Permit list. */ GSList *deny; /**< Deny list. */ - int perm_deny; /**< The permit/deny setting. */ + PurplePrivacyType perm_deny; /**< The permit/deny setting. */ GList *status_types; /**< Status types. */ diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/blist.h --- a/libpurple/blist.h Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/blist.h Sat Mar 21 03:50:31 2009 +0000 @@ -595,7 +595,7 @@ * @param contact The optional contact to place the buddy in. * @param group The group to add the new buddy to. * @param node The insertion point. Pass in NULL to add the node as - * the last child in the given group. + * the first child in the given group. */ void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node); diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/circbuffer.c --- a/libpurple/circbuffer.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/circbuffer.c Sat Mar 21 03:50:31 2009 +0000 @@ -68,7 +68,8 @@ /* If the fill pointer is wrapped to before the remove * pointer, we need to shift the data */ - if (in_offset < out_offset) { + if (in_offset < out_offset + || (in_offset == out_offset && buf->bufused > 0)) { int shift_n = MIN(buf->buflen - start_buflen, in_offset); memcpy(buf->buffer + start_buflen, buf->buffer, diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/dnssrv.c --- a/libpurple/dnssrv.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/dnssrv.c Sat Mar 21 03:50:31 2009 +0000 @@ -175,9 +175,11 @@ end: size = g_list_length(ret); + /* TODO: Check return value */ write(out, &size, sizeof(int)); while (ret != NULL) { + /* TODO: Check return value */ write(out, ret->data, sizeof(PurpleSrvResponse)); g_free(ret->data); ret = g_list_remove(ret, ret->data); diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/protocols/bonjour/parser.c --- a/libpurple/protocols/bonjour/parser.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/protocols/bonjour/parser.c Sat Mar 21 03:50:31 2009 +0000 @@ -91,14 +91,12 @@ xmlnode_set_namespace(node, (const char*) namespace); for(i=0; i < nb_attributes * 5; i+=5) { + const char *name = (const char *)attributes[i]; + const char *prefix = (const char *)attributes[i+1]; + const char *attrib_ns = (const char *)attributes[i+2]; char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; char *attrib = g_malloc(attrib_len + 1); - char *attrib_ns = NULL; - - if (attributes[i+2]) { - attrib_ns = g_strdup((char*)attributes[i+2]); - } memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; @@ -106,9 +104,8 @@ txt = attrib; attrib = purple_unescape_html(txt); g_free(txt); - xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib); + xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib); g_free(attrib); - g_free(attrib_ns); } bconv->current = node; diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/protocols/jabber/parser.c --- a/libpurple/protocols/jabber/parser.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/protocols/jabber/parser.c Sat Mar 21 03:50:31 2009 +0000 @@ -86,6 +86,8 @@ } } for(i=0; i < nb_attributes * 5; i+=5) { + const char *name = (const char *)attributes[i]; + const char *prefix = (const char *)attributes[i+1]; const char *attrib_ns = (const char *)attributes[i+2]; char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; @@ -97,7 +99,7 @@ txt = attrib; attrib = purple_unescape_html(txt); g_free(txt); - xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib); + xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib); g_free(attrib); } diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Sat Mar 21 03:50:31 2009 +0000 @@ -1092,6 +1092,7 @@ "jabber_si_xfer_ibb_send_data: error reading from file\n"); purple_xfer_cancel_local(xfer); } + g_free(data); } static void diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/util.c --- a/libpurple/util.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/util.c Sat Mar 21 03:50:31 2009 +0000 @@ -2850,6 +2850,12 @@ return "icon"; } +/* + * TODO: Consider using something faster than SHA-1, such as MD5, MD4 + * or CRC32. Are there security implications to that? Would + * probably be a good idea to benchmark some algorithms with + * 3KB-10KB chunks of data (typical buddy icon sizes). + */ char * purple_util_get_image_checksum(gconstpointer image_data, size_t image_len) { @@ -4038,6 +4044,13 @@ &gfud->website.page, &gfud->website.user, &gfud->website.passwd); if (purple_strcasestr(url, "https://") != NULL) { + if (!purple_ssl_is_supported()) { + purple_util_fetch_url_error(gfud, + _("Unable to connect to %s: Server requires TLS/SSL, but no TLS/SSL support was found."), + gfud->website.address); + return NULL; + } + gfud->is_ssl = TRUE; gfud->ssl_connection = purple_ssl_connect(NULL, gfud->website.address, gfud->website.port, diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/xmlnode.c --- a/libpurple/xmlnode.c Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/xmlnode.c Sat Mar 21 03:50:31 2009 +0000 @@ -27,6 +27,7 @@ * libxode uses memory pools that we simply have no need for, I decided to * write my own stuff. Also, re-writing this lets me be as lightweight * as I want to be. Thank you libxode for giving me a good starting point */ +#define _PURPLE_XMLNODE_C_ #include "debug.h" #include "internal.h" @@ -126,21 +127,28 @@ g_return_if_fail(node != NULL); g_return_if_fail(attr != NULL); - for(attr_node = node->child; attr_node; attr_node = attr_node->next) - { + attr_node = node->child; + while (attr_node) { if(attr_node->type == XMLNODE_TYPE_ATTRIB && purple_strequal(attr_node->name, attr)) { - if(sibling == NULL) { - node->child = attr_node->next; - } else { - sibling->next = attr_node->next; - } if (node->lastchild == attr_node) { node->lastchild = sibling; } - xmlnode_free(attr_node); - return; + if (sibling == NULL) { + node->child = attr_node->next; + xmlnode_free(attr_node); + attr_node = node->child; + } else { + sibling->next = attr_node->next; + sibling = attr_node->next; + xmlnode_free(attr_node); + attr_node = sibling; + } + } + else + { + attr_node = attr_node->next; } sibling = attr_node; } @@ -178,24 +186,25 @@ void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value) { - xmlnode *attrib_node; - - g_return_if_fail(node != NULL); - g_return_if_fail(attr != NULL); - g_return_if_fail(value != NULL); - xmlnode_remove_attrib(node, attr); - - attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); - - attrib_node->data = g_strdup(value); - - xmlnode_insert_child(node, attrib_node); + xmlnode_set_attrib_full(node, attr, NULL, NULL, value); } void xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value) { + xmlnode_set_attrib_full(node, attr, xmlns, NULL, value); +} + +void +xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value) +{ + xmlnode_set_attrib_full(node, attr, NULL, prefix, value); +} + +void +xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns, const char *prefix, const char *value) +{ xmlnode *attrib_node; g_return_if_fail(node != NULL); @@ -207,22 +216,6 @@ attrib_node->data = g_strdup(value); attrib_node->xmlns = g_strdup(xmlns); - - xmlnode_insert_child(node, attrib_node); -} - -void -xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value) -{ - xmlnode *attrib_node; - - g_return_if_fail(node != NULL); - g_return_if_fail(attr != NULL); - g_return_if_fail(value != NULL); - - attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); - - attrib_node->data = g_strdup(value); attrib_node->prefix = g_strdup(prefix); xmlnode_insert_child(node, attrib_node); @@ -585,7 +578,8 @@ } for(i=0; i < nb_attributes * 5; i+=5) { - const char *prefix = (const char *)attributes[i + 1]; + const char *name = (const char *)attributes[i]; + const char *prefix = (const char *)attributes[i+1]; char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; char *attrib = g_malloc(attrib_len + 1); @@ -594,11 +588,7 @@ txt = attrib; attrib = purple_unescape_html(txt); g_free(txt); - if (prefix && *prefix) { - xmlnode_set_attrib_with_prefix(node, (const char*) attributes[i], prefix, attrib); - } else { - xmlnode_set_attrib(node, (const char*) attributes[i], attrib); - } + xmlnode_set_attrib_full(node, name, NULL, prefix, attrib); g_free(attrib); } diff -r cde07a2e4531 -r 2d781c58a8a2 libpurple/xmlnode.h --- a/libpurple/xmlnode.h Sat Mar 14 15:50:56 2009 +0000 +++ b/libpurple/xmlnode.h Sat Mar 21 03:50:31 2009 +0000 @@ -157,6 +157,7 @@ */ void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value); +#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_XMLNODE_C_) /** * Sets a prefixed attribute for a node * @@ -164,6 +165,8 @@ * @param attr The name of the attribute to set * @param prefix The prefix of the attribute to ste * @param value The value of the attribute + * + * @deprecated Use xmlnode_set_attrib_full instead. */ void xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value); @@ -174,8 +177,25 @@ * @param attr The name of the attribute to set * @param xmlns The namespace of the attribute to ste * @param value The value of the attribute + * + * @deprecated Use xmlnode_set_attrib_full instead. */ void xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value); +#endif /* PURPLE_DISABLE_DEPRECATED */ + +/** + * Sets a namespaced attribute for a node + * + * @param node The node to set an attribute for. + * @param attr The name of the attribute to set + * @param xmlns The namespace of the attribute to ste + * @param prefix The prefix of the attribute to ste + * @param value The value of the attribute + * + * @since 2.6.0 + */ +void xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns, + const char *prefix, const char *value); /** * Gets an attribute from a node. diff -r cde07a2e4531 -r 2d781c58a8a2 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Sat Mar 14 15:50:56 2009 +0000 +++ b/pidgin/gtkdialogs.c Sat Mar 21 03:50:31 2009 +0000 @@ -189,7 +189,7 @@ {N_("Italian"), "it", "Claudio Satriano", "satriano@na.infn.it"}, {N_("Japanese"), "ja", "Takashi Aihana", "aihana@gnome.gr.jp"}, {N_("Georgian"), "ka", N_("Ubuntu Georgian Translators"), "alexander.didebulidze@stusta.mhn.de"}, - {"Khmer", "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"}, + {N_("Khmer"), "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"}, {N_("Kannada"), "kn", N_("Kannada Translation team"), "translation@sampada.info"}, {N_("Korean"), "ko", "Sushizang", "sushizang@empal.com"}, {N_("Kurdish"), "ku", "Erdal Ronahi", "erdal.ronahi@gmail.com"}, diff -r cde07a2e4531 -r 2d781c58a8a2 pidgin/gtknotify.c --- a/pidgin/gtknotify.c Sat Mar 14 15:50:56 2009 +0000 +++ b/pidgin/gtknotify.c Sat Mar 21 03:50:31 2009 +0000 @@ -28,6 +28,7 @@ #include +#include "account.h" #include "connection.h" #include "debug.h" #include "prefs.h" @@ -37,6 +38,7 @@ #include "gtkblist.h" #include "gtkimhtml.h" #include "gtknotify.h" +#include "gtkpounce.h" #include "gtkutils.h" typedef struct @@ -57,6 +59,13 @@ typedef struct { PurpleAccount *account; + PurplePounce *pounce; +} PidginNotifyPounceData; + + +typedef struct +{ + PurpleAccount *account; GtkListStore *model; GtkWidget *treeview; GtkWidget *window; @@ -80,21 +89,44 @@ COLUMNS_PIDGIN_MAIL }; -typedef struct _PidginMailDialog PidginMailDialog; +enum +{ + PIDGIN_POUNCE_ICON, + PIDGIN_POUNCE_ALIAS, + PIDGIN_POUNCE_EVENT, + PIDGIN_POUNCE_TEXT, + PIDGIN_POUNCE_DATE, + PIDGIN_POUNCE_DATA, + PIDGIN_POUNCE_COLUMNS +}; -struct _PidginMailDialog +typedef struct _PidginNotifyDialog PidginNotifyDialog; +typedef PidginNotifyDialog PidginMailDialog; + +struct _PidginNotifyDialog { GtkWidget *dialog; GtkWidget *treeview; GtkTreeStore *treemodel; GtkLabel *label; GtkWidget *open_button; + GtkWidget *dismiss_button; + GtkWidget *edit_button; int total_count; gboolean in_use; }; -static PidginMailDialog *mail_dialog = NULL; +typedef enum +{ + PIDGIN_NOTIFY_MAIL, + PIDGIN_NOTIFY_POUNCE, + PIDGIN_NOTIFY_TYPES +} PidginNotifyType; +static PidginNotifyDialog *mail_dialog = NULL; +static PidginNotifyDialog *pounce_dialog = NULL; + +static GtkWidget *pidgin_get_notification_dialog(PidginNotifyType type); static void *pidgin_notify_emails(PurpleConnection *gc, size_t count, gboolean detailed, const char **subjects, const char **froms, const char **tos, @@ -109,6 +141,159 @@ } static void +pounce_response_close(PidginNotifyDialog *dialog) +{ + GtkTreeIter iter; + PidginNotifyPounceData *pounce_data; + + while (gtk_tree_model_get_iter_first( + GTK_TREE_MODEL(pounce_dialog->treemodel), &iter)) { + gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + gtk_tree_store_remove(dialog->treemodel, &iter); + + g_free(pounce_data); + } + + gtk_widget_destroy(pounce_dialog->dialog); + g_free(pounce_dialog); + pounce_dialog = NULL; +} + +static void +delete_foreach(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + PidginNotifyPounceData *pounce_data; + + gtk_tree_model_get(model, iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + if (pounce_data != NULL) + g_free(pounce_data); +} + +static void +append_to_list(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + GList **list = data; + *list = g_list_prepend(*list, gtk_tree_path_copy(path)); +} +static void +pounce_response_dismiss() +{ + GtkTreeSelection *selection; + GList *list = NULL; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview)); + gtk_tree_selection_selected_foreach(selection, delete_foreach, pounce_dialog); + gtk_tree_selection_selected_foreach(selection, append_to_list, &list); + + while (list) { + GtkTreeIter iter; + if (gtk_tree_model_get_iter(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + list->data)) { + gtk_tree_store_remove(GTK_TREE_STORE(pounce_dialog->treemodel), &iter); + } + gtk_tree_path_free(list->data); + list = g_list_delete_link(list, list); + } +} + +static void +pounce_response_edit_cb(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + PidginNotifyPounceData *pounce_data; + PidginNotifyDialog *dialog = (PidginNotifyDialog*)data; + PurplePounce *pounce; + GList *list; + + list = purple_pounces_get_all(); + + gtk_tree_model_get(GTK_TREE_MODEL(dialog->treemodel), iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + for (; list != NULL; list = list->next) { + pounce = list->data; + if (pounce == pounce_data->pounce) { + pidgin_pounce_editor_show(pounce_data->account, NULL, pounce_data->pounce); + return; + } + } + + purple_debug_warning("gtknotify", "Pounce was destroyed.\n"); +} + +static void +pounce_response_cb(GtkDialog *dlg, gint id, PidginNotifyDialog *dialog) +{ + GtkTreeSelection *selection = NULL; + + switch (id) { + case GTK_RESPONSE_CLOSE: + case GTK_RESPONSE_DELETE_EVENT: + pounce_response_close(dialog); + break; + case GTK_RESPONSE_NO: + pounce_response_dismiss(); + break; + case GTK_RESPONSE_APPLY: + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); + gtk_tree_selection_selected_foreach(selection, pounce_response_edit_cb, + dialog); + break; + } +} + +static void +pounce_row_selected_cb(GtkTreeView *tv, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer data) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + gboolean selected; + GList *list; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview)); + + selected = gtk_tree_selection_get_selected(selection, + NULL, &iter); + + if (selected) { + PurplePounce *pounce; + PidginNotifyPounceData *pounce_data; + + list = purple_pounces_get_all(); + + gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter, + PIDGIN_POUNCE_DATA, &pounce_data, + -1); + + gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE); + + for (; list != NULL; list = list->next) { + pounce = list->data; + if (pounce == pounce_data->pounce) { + gtk_widget_set_sensitive(pounce_dialog->edit_button, TRUE); + break; + } + } + + gtk_widget_set_sensitive(pounce_dialog->dismiss_button, TRUE); + } else { + gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE); + gtk_widget_set_sensitive(pounce_dialog->dismiss_button, FALSE); + } + + +} + +static void email_response_cb(GtkDialog *dlg, gint id, PidginMailDialog *dialog) { PidginNotifyMailData *data = NULL; @@ -342,89 +527,7 @@ static GtkWidget * pidgin_get_mail_dialog(void) { - if (mail_dialog == NULL) { - GtkWidget *dialog = NULL; - GtkWidget *label; - GtkWidget *sw; - GtkCellRenderer *rend; - GtkTreeViewColumn *column; - GtkWidget *button = NULL; - GtkWidget *vbox = NULL; - - dialog = gtk_dialog_new_with_buttons(_("New Mail"), NULL, 0, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed"); - g_signal_connect(G_OBJECT(dialog), "focus-in-event", - G_CALLBACK(mail_window_focus_cb), NULL); - - gtk_dialog_add_button(GTK_DIALOG(dialog), - _("Open All Messages"), GTK_RESPONSE_ACCEPT); - - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES); - - /* make "Open All Messages" the default response */ - gtk_dialog_set_default_response(GTK_DIALOG(dialog), - GTK_RESPONSE_ACCEPT); - - /* Setup the dialog */ - gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE); - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); - - /* Vertical box */ - vbox = GTK_DIALOG(dialog)->vbox; - - /* Golden ratio it up! */ - gtk_widget_set_size_request(dialog, 550, 400); - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - - mail_dialog = g_new0(PidginMailDialog, 1); - mail_dialog->dialog = dialog; - mail_dialog->open_button = button; - - mail_dialog->treemodel = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL, - GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); - mail_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mail_dialog->treemodel)); - g_object_unref(G_OBJECT(mail_dialog->treemodel)); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(mail_dialog->treeview), PIDGIN_MAIL_TEXT); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(mail_dialog->treeview), - pidgin_tree_view_search_equal_func, NULL, NULL); - - g_signal_connect(G_OBJECT(dialog), "response", - G_CALLBACK(email_response_cb), mail_dialog); - g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(mail_dialog->treeview))), - "changed", G_CALLBACK(selection_changed_cb), mail_dialog); - g_signal_connect(G_OBJECT(mail_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL); - - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mail_dialog->treeview), FALSE); - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mail_dialog->treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), mail_dialog->treeview); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(column, TRUE); - rend = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(column, rend, FALSE); - gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL); - rend = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, rend, TRUE); - gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(mail_dialog->treeview), column); - - label = gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(label), _("You have mail!")); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - } - - return mail_dialog->dialog; + return pidgin_get_notification_dialog(PIDGIN_NOTIFY_MAIL); } /* count == 0 means this is a detailed mail notification. @@ -1001,8 +1104,10 @@ { PidginNotifyMailData *data = (PidginNotifyMailData *)ui_handle; - g_free(data->url); - g_free(data); + if (data) { + g_free(data->url); + g_free(data); + } } else if (type == PURPLE_NOTIFY_SEARCHRESULTS) { @@ -1234,6 +1339,228 @@ return NULL; } +static GtkWidget * +pidgin_get_dialog(PidginNotifyType type, GtkTreeStore *treemodel) +{ + GtkWidget *dialog = NULL; + GtkWidget *label = NULL; + GtkWidget *sw; + GtkCellRenderer *rend; + GtkTreeViewColumn *column; + GtkWidget *button = NULL; + GtkWidget *vbox = NULL; + GtkTreeSelection *sel; + PidginNotifyDialog *spec_dialog = NULL; + + g_return_val_if_fail(type < PIDGIN_NOTIFY_TYPES, NULL); + + dialog = gtk_dialog_new_with_buttons(NULL, NULL, 0, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE); + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); + + /* Vertical box */ + vbox = GTK_DIALOG(dialog)->vbox; + + /* Golden ratio it up! */ + gtk_widget_set_size_request(dialog, 550, 400); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + spec_dialog = g_new0(PidginNotifyDialog, 1); + spec_dialog->dialog = dialog; + spec_dialog->open_button = button; + + spec_dialog->treemodel = treemodel; + spec_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(spec_dialog->treemodel)); + g_object_unref(G_OBJECT(spec_dialog->treemodel)); + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE); + gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview); + + if (type == PIDGIN_NOTIFY_MAIL) { + gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail")); + gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed"); + g_signal_connect(G_OBJECT(dialog), "focus-in-event", + G_CALLBACK(mail_window_focus_cb), NULL); + + gtk_dialog_add_button(GTK_DIALOG(dialog), + _("Open All Messages"), GTK_RESPONSE_ACCEPT); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spec_dialog->treeview), FALSE); + + gtk_tree_view_set_search_column(GTK_TREE_VIEW(spec_dialog->treeview), PIDGIN_MAIL_TEXT); + gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(spec_dialog->treeview), + pidgin_tree_view_search_equal_func, NULL, NULL); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(email_response_cb), spec_dialog); + g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview))), + "changed", G_CALLBACK(selection_changed_cb), spec_dialog); + g_signal_connect(G_OBJECT(spec_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + + gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, TRUE); + gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(label), _("You have mail!")); + + } else if (type == PIDGIN_NOTIFY_POUNCE) { + gtk_window_set_title(GTK_WINDOW(dialog), _("New Pounces")); + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + _("Dismiss"), GTK_RESPONSE_NO); + gtk_widget_set_sensitive(button, FALSE); + spec_dialog->dismiss_button = button; + + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + PIDGIN_STOCK_EDIT, GTK_RESPONSE_APPLY); + gtk_widget_set_sensitive(button, FALSE); + spec_dialog->edit_button = button; + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(pounce_response_cb), spec_dialog); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Buddy")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + + gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_POUNCE_ICON, NULL); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_ALIAS); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Event")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_EVENT); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Message")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_TEXT); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Date")); + gtk_tree_view_column_set_resizable(column, TRUE); + rend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, rend, FALSE); + gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_DATE); + gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column); + + label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(label), _("You have pounced!")); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview)); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(sel), "changed", + G_CALLBACK(pounce_row_selected_cb), NULL); + } + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2); + + if (type == PIDGIN_NOTIFY_MAIL) + mail_dialog = spec_dialog; + else if (type == PIDGIN_NOTIFY_POUNCE) { + pounce_dialog = spec_dialog; + } + + return spec_dialog->dialog; + +} + +void +pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce, + const char *alias, const char *event, const char *message, const char *date) +{ + GtkWidget *dialog; + GdkPixbuf *icon; + GtkTreeIter iter; + PidginNotifyPounceData *pounce_data; + + dialog = pidgin_get_notification_dialog(PIDGIN_NOTIFY_POUNCE); + + icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + + pounce_data = g_new(PidginNotifyPounceData, 1); + + pounce_data->account = account; + pounce_data->pounce = pounce; + + gtk_tree_store_append(pounce_dialog->treemodel, &iter, NULL); + + gtk_tree_store_set(pounce_dialog->treemodel, &iter, + PIDGIN_POUNCE_ICON, icon, + PIDGIN_POUNCE_ALIAS, alias, + PIDGIN_POUNCE_EVENT, event, + PIDGIN_POUNCE_TEXT, (message != NULL)? message : _("No message"), + PIDGIN_POUNCE_DATE, date, + PIDGIN_POUNCE_DATA, pounce_data, + -1); + + if (icon) + g_object_unref(icon); + + gtk_widget_show_all(dialog); + + return; +} + +static GtkWidget * +pidgin_get_notification_dialog(PidginNotifyType type) +{ + GtkTreeStore *model = NULL; + + if (type == PIDGIN_NOTIFY_MAIL) { + if (mail_dialog != NULL) + return mail_dialog->dialog; + + model = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL, + GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + + } else if (type == PIDGIN_NOTIFY_POUNCE) { + + if (pounce_dialog != NULL) + return pounce_dialog->dialog; + + model = gtk_tree_store_new(PIDGIN_POUNCE_COLUMNS, + GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_POINTER); + } + + return pidgin_get_dialog(type, model); +} + static PurpleNotifyUiOps ops = { pidgin_notify_message, diff -r cde07a2e4531 -r 2d781c58a8a2 pidgin/gtknotify.h --- a/pidgin/gtknotify.h Sat Mar 14 15:50:56 2009 +0000 +++ b/pidgin/gtknotify.h Sat Mar 21 03:50:31 2009 +0000 @@ -27,6 +27,18 @@ #define _PIDGINNOTIFY_H_ #include "notify.h" +#include "pounce.h" + +/** + * Adds a buddy pounce to the buddy pounce dialog + * + * @param alias The buddy alias + * @param event Event description + * @param message Pounce message + * @param date Pounce date + */ +void pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce, + const char *alias, const char *event, const char *message, const char *date); /** * Returns the UI operations structure for GTK+ notification functions. diff -r cde07a2e4531 -r 2d781c58a8a2 pidgin/gtkpounce.c --- a/pidgin/gtkpounce.c Sat Mar 14 15:50:56 2009 +0000 +++ b/pidgin/gtkpounce.c Sat Mar 21 03:50:31 2009 +0000 @@ -30,7 +30,6 @@ #include "account.h" #include "conversation.h" #include "debug.h" -#include "notify.h" #include "prpl.h" #include "request.h" #include "server.h" @@ -41,6 +40,7 @@ #include "gtkdialogs.h" #include "gtkimhtml.h" #include "gtkpounce.h" +#include "gtknotify.h" #include "pidginstock.h" #include "gtkutils.h" @@ -1275,7 +1275,6 @@ /* Handle double-clicking */ g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(pounce_double_click_cb), dialog); - gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); @@ -1458,27 +1457,27 @@ */ tmp = g_strdup_printf( (events & PURPLE_POUNCE_TYPING) ? - _("%s has started typing to you (%s)") : + _("Started typing") : (events & PURPLE_POUNCE_TYPED) ? - _("%s has paused while typing to you (%s)") : + _("Paused while typing") : (events & PURPLE_POUNCE_SIGNON) ? - _("%s has signed on (%s)") : + _("Signed on") : (events & PURPLE_POUNCE_IDLE_RETURN) ? - _("%s has returned from being idle (%s)") : + _("Returned from being idle") : (events & PURPLE_POUNCE_AWAY_RETURN) ? - _("%s has returned from being away (%s)") : + _("Returned from being away") : (events & PURPLE_POUNCE_TYPING_STOPPED) ? - _("%s has stopped typing to you (%s)") : + _("Stopped typing") : (events & PURPLE_POUNCE_SIGNOFF) ? - _("%s has signed off (%s)") : + _("Signed off") : (events & PURPLE_POUNCE_IDLE) ? - _("%s has become idle (%s)") : + _("Became idle") : (events & PURPLE_POUNCE_AWAY) ? - _("%s has gone away. (%s)") : + _("Went away") : (events & PURPLE_POUNCE_MESSAGE_RECEIVED) ? - _("%s has sent you a message. (%s)") : - _("Unknown pounce event. Please report this!"), - alias, purple_account_get_protocol_name(account)); + _("Sent a message") : + _("Unknown.... Please report this!") + ); /* * Ok here is where I change the second argument, title, from @@ -1488,16 +1487,9 @@ if ((name_shown = purple_account_get_alias(account)) == NULL) name_shown = purple_account_get_username(account); - if (reason == NULL) - { - purple_notify_info(NULL, name_shown, tmp, purple_date_format_full(NULL)); - } - else - { - char *tmp2 = g_strdup_printf("%s\n\n%s", reason, purple_date_format_full(NULL)); - purple_notify_info(NULL, name_shown, tmp, tmp2); - g_free(tmp2); - } + pidgin_notify_pounce_add(account, pounce, alias, tmp, reason, + purple_date_format_full(NULL)); + g_free(tmp); } diff -r cde07a2e4531 -r 2d781c58a8a2 pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Sat Mar 14 15:50:56 2009 +0000 +++ b/pidgin/gtkprefs.c Sat Mar 21 03:50:31 2009 +0000 @@ -2385,14 +2385,12 @@ /* Auto-away stuff */ vbox = pidgin_make_frame(ret, _("Auto-away")); - button = pidgin_prefs_checkbox(_("Change status when _idle"), - "/purple/away/away_when_idle", vbox); - select = pidgin_prefs_labeled_spin_button(vbox, _("_Minutes before becoming idle:"), "/purple/away/mins_before_away", 1, 24 * 60, sg); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(pidgin_toggle_sensitive), select); + + button = pidgin_prefs_checkbox(_("Change status when _idle"), + "/purple/away/away_when_idle", vbox); /* TODO: Show something useful if we don't have any saved statuses. */ menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away)); @@ -2404,7 +2402,6 @@ if (!purple_prefs_get_bool("/purple/away/away_when_idle")) { gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(select), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE); }