Fri, 12 Oct 2007 02:06:38 +0000
propagate from branch 'im.pidgin.sadrul.currentmedia' (head aed170143d4317466eb52019a328c54e01784e61)
to branch 'next.minor' (head 1c90c7de868806272bde7e95f1792ee28bb531c2)
| libpurple/protocols/jabber/google.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/jabber/jabber.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/msn/msn.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/msn/notification.c | file | annotate | diff | comparison | revisions | |
| pidgin/gtkblist.c | file | annotate | diff | comparison | revisions | |
| po/sr@Latn.po | file | annotate | diff | comparison | revisions |
--- a/COPYRIGHT Wed Sep 26 06:56:02 2007 +0000 +++ b/COPYRIGHT Fri Oct 12 02:06:38 2007 +0000 @@ -267,6 +267,7 @@ Ruediger Oertel Gudmundur Bjarni Olafsson Bartosz Oler +Stefan Ott Shawn Outman Nathan Owens (pianocomp81) John Oyler
--- a/ChangeLog Wed Sep 26 06:56:02 2007 +0000 +++ b/ChangeLog Fri Oct 12 02:06:38 2007 +0000 @@ -1,15 +1,13 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -Version 2.2.1: - http://developer.pidgin.im/query?status=closed&milestone=2.2.1 - +version 2.2.2: + http://developer.pidgin.im/query?status=closed&milestone=2.2.2 + NOTE: Due to 2.2.1 being a security fix release, some bugs + marked fixed in 2.2.1 may not have been fixed until + this release (2.2.2). + libpurple: - * A few build issues on Solaris were fixed. - * Cancelling the password prompt for an account will no longer leave - it in an ambiguous state. (It will be disabled.) - * Fixed an erroneous size display for MSN file transfers. (galt) * Real usernames are now shown in the system log. - * Gmail notifications are better tracked Pidgin: * If you alias a buddy to an alias that is already present within @@ -30,17 +28,36 @@ resumes, the history will be retained. A preference has been added to toggle this behavior. * The "Smiley" menu has been moved to the top-level of the toolbar. - * Fixed keyboard tab reordering to move tabs one step instead of two. * Pidgin's display is now saved with the command line for session restoration. (David Mohr) + * ICQ Birthday notifications are shown as buddy list emblems. + +version 2.2.1 (09/29/2007): + http://developer.pidgin.im/query?status=closed&milestone=2.2.1 + NOTE: Due to the backporting that happened for the actual + release, it is possible bugs marked as fixed in 2.2.1 + will not be fixed until 2.2.2. + + libpurple: + * A few build issues on Solaris were fixed. + * Cancelling the password prompt for an account will no longer leave + it in an ambiguous state. (It will be disabled.) + * Fixed an erroneous size display for MSN file transfers. (galt) + * Fixed multiple memory leaks, particularly in XMPP and MySpace + protocols + * Fixed remembering proxy preferences and status scores + * Gmail notifications are better tracked + + Pidgin: + * Fixed keyboard tab reordering to move tabs one step instead of two. * You should no longer lose proxy settings when Pidgin is restarted. - * ICQ Birthday notifications are shown as buddy list emblems + * Fixed detection of X11 when compiling Finch: * Pressing 'Insert' in the buddylist will bring up the 'Add Buddy' dialog. -Version 2.2.0 (09/13/2007): +version 2.2.0 (09/13/2007): http://developer.pidgin.im/query?status=closed&milestone=2.2.0 Libpurple:
--- a/NEWS Wed Sep 26 06:56:02 2007 +0000 +++ b/NEWS Fri Oct 12 02:06:38 2007 +0000 @@ -1,5 +1,24 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +2.2.1 (9/28/2007): + Richard: We have some new code in the pipeline, but it's not quite + ready for a general release. Instead, this is basically a bug fix + release. + + Luke: Unfortunately the necessity of this bug fix release means + some of the tickets that have been closed as part of the 2.2.1 + milestone are not actually fixed yet. We have grabbed as many + of the changes as we could while avoiding those that are as + yet unstable though, and this should still be a marked + improvement over 2.2.0. We have spent a lot of time since the + last release looking at the tickets that have been submitted + and many of them have been closed. + + Stu: I haven't NEWS'd in a while. I haven't actually done much for + too long also, maybe I'll find some time soon. This release is + basically what 2.2.0 should have been - it actually compiles this + time. + 2.2.0 (9/13/2007): Sean: 2.2.0 contains the results of several major Google Summer of Code branches bringing some new, extraordinary features. We
--- a/configure.ac Wed Sep 26 06:56:02 2007 +0000 +++ b/configure.ac Fri Oct 12 02:06:38 2007 +0000 @@ -46,8 +46,8 @@ m4_define([purple_lt_current], [2]) m4_define([purple_major_version], [2]) m4_define([purple_minor_version], [2]) -m4_define([purple_micro_version], [1]) -m4_define([purple_version_suffix], [devel]) +m4_define([purple_micro_version], [2]) +m4_define([purple_version_suffix], []) m4_define([purple_version], [purple_major_version.purple_minor_version.purple_micro_version]) m4_define([purple_display_version], purple_version[]m4_ifdef([purple_version_suffix],[purple_version_suffix])) @@ -55,8 +55,8 @@ m4_define([gnt_lt_current], [2]) m4_define([gnt_major_version], [2]) m4_define([gnt_minor_version], [2]) -m4_define([gnt_micro_version], [1]) -m4_define([gnt_version_suffix], [devel]) +m4_define([gnt_micro_version], [2]) +m4_define([gnt_version_suffix], []) m4_define([gnt_version], [gnt_major_version.gnt_minor_version.gnt_micro_version]) m4_define([gnt_display_version], gnt_version[]m4_ifdef([gnt_version_suffix],[gnt_version_suffix])) @@ -136,7 +136,7 @@ ;; esac -ALL_LINGUAS="af am ar az be@latin bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr gl gu he hi hu id it ja ka kn ko ku lt mk my_MM nb ne nl nn pa pl pt_BR pt ps ro ru sk sl sq sr sr@Latn sv ta te th tr uk vi xh zh_CN zh_HK zh_TW" +ALL_LINGUAS="af am ar az be@latin bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr gl gu he hi hu id it ja ka kn ko ku lo lt mk my_MM nb ne nl nn pa pl pt_BR pt ps ro ru sk sl sq sr sr@latin sv ta te th tr uk vi xh zh_CN zh_HK zh_TW" AM_GLIB_GNU_GETTEXT dnl If we don't have msgfmt, then po/ is going to fail -- ensure that @@ -1460,7 +1460,7 @@ [enable_nss="$enableval"], [enable_nss="yes"]) -msg_ssl="None (MSN and Google Talk will not work without SSL!)" +msg_ssl="None. MSN, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!" dnl # dnl # Check for GnuTLS if it's specified.
--- a/doc/account-signals.dox Wed Sep 26 06:56:02 2007 +0000 +++ b/doc/account-signals.dox Fri Oct 12 02:06:38 2007 +0000 @@ -100,5 +100,38 @@ @param old The alias before change. @endsignaldef + @signaldef account-authorization-requested + @signalproto +void (*account_authorization_requested)(PurpleAccount *account, const char *user); + @endsignalproto + @signaldesc + Emitted when a user requests authorization. + @param account The account. + @param user The name of the user requesting authorization. + @return Less than zero to deny the request without prompting, greater + than zero if the request should be granted. If zero is returned, + then the user will be prompted with the request. + @endsignaldef + + @signaldef account-authorization-denied + @signalproto +void (*account_authorization_denied)(PurpleAccount *account, const char *user); + @endsignalproto + @signaldesc + Emitted when the authorization request for a buddy is denied. + @param account The account. + @param user The name of the user requesting authorization. + @endsignaldef + + @signaldef account-authorization-granted + @signalproto +void (*account_authorization_granted)(PurpleAccount *account, const char *user); + @endsignalproto + @signaldesc + Emitted when the authorization request for a buddy is granted. + @param account The account. + @param user The name of the user requesting authorization. + @endsignaldef + */ // vim: syntax=c tw=75 et
--- a/finch/gntblist.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntblist.c Fri Oct 12 02:06:38 2007 +0000 @@ -2202,12 +2202,12 @@ group = purple_request_field_group_new(NULL); purple_request_fields_add_group(fields, group); - field = purple_request_field_string_new("screenname", _("_Name"), NULL, FALSE); + field = purple_request_field_string_new("screenname", _("Name"), NULL, FALSE); purple_request_field_set_type_hint(field, "screenname"); purple_request_field_set_required(field, TRUE); purple_request_field_group_add_field(group, field); - field = purple_request_field_account_new("account", _("_Account"), NULL); + field = purple_request_field_account_new("account", _("Account"), NULL); purple_request_field_set_type_hint(field, "account"); purple_request_field_set_visible(field, (purple_connections_get_all() != NULL && @@ -2227,6 +2227,69 @@ } static void +join_chat_select_cb(gpointer data, PurpleRequestFields *fields) +{ + PurpleAccount *account; + const char *name; + PurpleConnection *gc; + PurpleChat *chat; + GHashTable *hash = NULL; + + account = purple_request_fields_get_account(fields, "account"); + name = purple_request_fields_get_string(fields, "chat"); + + if (!purple_account_is_connected(account)) + return; + + gc = purple_account_get_connection(account); + purple_conversation_new(PURPLE_CONV_TYPE_CHAT, account, name); + chat = purple_blist_find_chat(account, name); + if (chat == NULL) { + if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) + hash = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, name); + } else { + hash = chat->components; + } + serv_join_chat(gc, hash); + if (chat == NULL && hash != NULL) + g_hash_table_destroy(hash); +} + +static void +join_chat_select(GntMenuItem *item, gpointer n) +{ + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + + fields = purple_request_fields_new(); + + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); + + field = purple_request_field_string_new("chat", _("Channel"), NULL, FALSE); + purple_request_field_set_required(field, TRUE); + purple_request_field_group_add_field(group, field); + + field = purple_request_field_account_new("account", _("Account"), NULL); + purple_request_field_set_type_hint(field, "account"); + purple_request_field_set_visible(field, + (purple_connections_get_all() != NULL && + purple_connections_get_all()->next != NULL)); + purple_request_field_set_required(field, TRUE); + purple_request_field_group_add_field(group, field); + + purple_request_fields(purple_get_blist(), _("Join a Chat"), + NULL, + _("Please enter the name of the chat you want to join."), + fields, + _("Join"), G_CALLBACK(join_chat_select_cb), + _("Cancel"), NULL, + NULL, NULL, NULL, + NULL); +} + +static void menu_add_buddy_cb(GntMenuItem *item, gpointer null) { purple_blist_request_add_buddy(NULL, NULL, NULL, NULL); @@ -2265,21 +2328,29 @@ gnt_menuitem_set_submenu(item, GNT_MENU(sub)); item = gnt_menuitem_new(_("Send IM...")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "send-im"); gnt_menu_add_item(GNT_MENU(sub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), send_im_select, NULL); + item = gnt_menuitem_new(_("Join Chat...")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "join-chat"); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENU_ITEM(item), join_chat_select, NULL); + item = gnt_menuitem_new(_("Show")); gnt_menu_add_item(GNT_MENU(sub), item); subsub = gnt_menu_new(GNT_MENU_POPUP); gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); item = gnt_menuitem_check_new(_("Empty groups")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "show-empty-groups"); gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), purple_prefs_get_bool(PREF_ROOT "/emptygroups")); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/emptygroups"); item = gnt_menuitem_check_new(_("Offline buddies")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "show-offline-buddies"); gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), purple_prefs_get_bool(PREF_ROOT "/showoffline")); gnt_menu_add_item(GNT_MENU(subsub), item); @@ -2291,14 +2362,17 @@ gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); item = gnt_menuitem_new(_("By Status")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-status"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "status"); item = gnt_menuitem_new(_("Alphabetically")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-alpha"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "text"); item = gnt_menuitem_new(_("By Log Size")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-log"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log"); @@ -2309,14 +2383,17 @@ gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); item = gnt_menuitem_new("Buddy"); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-buddy"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_buddy_cb, NULL); item = gnt_menuitem_new("Chat"); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-chat"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_chat_cb, NULL); item = gnt_menuitem_new("Group"); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-group"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_group_cb, NULL);
--- a/finch/gntconv.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntconv.c Fri Oct 12 02:06:38 2007 +0000 @@ -959,7 +959,7 @@ { FinchConv *fc = FINCH_CONV(conv); if (fc && fc->window) - return gnt_window_present(fc->window); + gnt_window_present(fc->window); } static gboolean
--- a/finch/gntdebug.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntdebug.c Fri Oct 12 02:06:38 2007 +0000 @@ -28,12 +28,14 @@ #include <gntbutton.h> #include <gntcheckbox.h> #include <gntentry.h> +#include <gntfilesel.h> #include <gntlabel.h> #include <gntline.h> #include <gnttextview.h> #include "gntdebug.h" #include "finch.h" +#include "notify.h" #include "util.h" #include <stdio.h> @@ -220,9 +222,43 @@ (GDestroyNotify)g_source_remove); } +static void +file_save(GntFileSel *fs, const char *path, const char *file, GntTextView *tv) +{ + FILE *fp; + + if ((fp = g_fopen(path, "w+")) == NULL) { + purple_notify_error(NULL, NULL, _("Unable to open file."), NULL); + return; + } + + fprintf(fp, "Finch Debug Log : %s\n", purple_date_format_full(NULL)); + fprintf(fp, tv->string->str); + fclose(fp); + gnt_widget_destroy(GNT_WIDGET(fs)); +} + +static void +file_cancel(GntWidget *w, GntFileSel *fs) +{ + gnt_widget_destroy(GNT_WIDGET(fs)); +} + +static void +save_debug_win(GntWidget *w, GntTextView *tv) +{ + GntWidget *window = gnt_file_sel_new(); + GntFileSel *sel = GNT_FILE_SEL(window); + gnt_file_sel_set_current_location(sel, purple_home_dir()); + gnt_file_sel_set_suggested_filename(sel, "debug.txt"); + g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(file_save), tv); + g_signal_connect(G_OBJECT(sel->cancel), "activate", G_CALLBACK(file_cancel), sel); + gnt_widget_show(window); +} + void finch_debug_window_show() { - GntWidget *wid, *box; + GntWidget *wid, *box, *label; debug.paused = FALSE; if (debug.window) { @@ -258,8 +294,15 @@ GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); gnt_box_add_widget(GNT_BOX(box), wid); + wid = gnt_button_new(_("Save")); + g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(save_debug_win), debug.tview); + GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); + gnt_box_add_widget(GNT_BOX(box), wid); + debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter")); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Filter: "))); + label = gnt_label_new(_("Filter:")); + GNT_WIDGET_UNSET_FLAGS(label, GNT_WIDGET_GROW_X); + gnt_box_add_widget(GNT_BOX(box), label); gnt_box_add_widget(GNT_BOX(box), debug.search); g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL);
--- a/finch/gntplugin.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntplugin.c Fri Oct 12 02:06:38 2007 +0000 @@ -32,6 +32,7 @@ #include "finch.h" +#include "debug.h" #include "notify.h" #include "request.h" @@ -127,8 +128,8 @@ /* XXX: Use formatting and stuff */ gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot)); text = g_strdup_printf(_("Name: %s\nVersion: %s\nDescription: %s\nAuthor: %s\nWebsite: %s\nFilename: %s\n"), - SAFE(plugin->info->name), SAFE(plugin->info->version), SAFE(plugin->info->description), - SAFE(plugin->info->author), SAFE(plugin->info->homepage), SAFE(plugin->path)); + SAFE(_(plugin->info->name)), SAFE(_(plugin->info->version)), SAFE(_(plugin->info->description)), + SAFE(_(plugin->info->author)), SAFE(_(plugin->info->homepage)), SAFE(plugin->path)); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(plugins.aboot), text, GNT_TEXT_FLAG_NORMAL); gnt_text_view_scroll(GNT_TEXT_VIEW(plugins.aboot), 0); @@ -237,6 +238,93 @@ } } +static void +install_selected_file_cb(gpointer handle, const char *filename) +{ + /* Try to init the selected file. + * If it succeeds, try to make a copy of the file in $USERDIR/plugins/. + * If the copy succeeds, unload and destroy the plugin in the original + * location and init+load the new one. + * Select the plugin in the plugin list. + */ + char *path; + PurplePlugin *plugin; + + g_return_if_fail(plugins.window); + + plugin = purple_plugin_probe(filename); + if (!plugin) { + purple_notify_error(handle, _("Error loading plugin"), + _("The selected file is not a valid plugin."), + _("Please open the debug window and try again to see the exact error message.")); + return; + } + if (g_list_find(gnt_tree_get_rows(GNT_TREE(plugins.tree)), plugin)) { + purple_plugin_load(plugin); + gnt_tree_set_choice(GNT_TREE(plugins.tree), plugin, purple_plugin_is_loaded(plugin)); + gnt_tree_set_selected(GNT_TREE(plugins.tree), plugin); + return; + } + + path = g_build_filename(purple_user_dir(), "plugins", NULL); + if (purple_build_dir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0) { + char *content = NULL; + gsize length = 0; + + if (g_file_get_contents(filename, &content, &length, NULL)) { + char *file = g_path_get_basename(filename); + g_free(path); + path = g_build_filename(purple_user_dir(), "plugins", file, NULL); + if (purple_util_write_data_to_file_absolute(path, content, length)) { + purple_plugin_destroy(plugin); + plugin = purple_plugin_probe(path); + if (!plugin) { + purple_debug_warning("gntplugin", "This is really strange. %s can be loaded, but %s can't!\n", + filename, path); + g_unlink(path); + plugin = purple_plugin_probe(filename); + } + } else { + } + } + g_free(content); + } + g_free(path); + + purple_plugin_load(plugin); + + if (plugin->info->type == PURPLE_PLUGIN_LOADER) { + GList *cur; + for (cur = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts; cur != NULL; + cur = cur->next) + purple_plugins_probe(cur->data); + return; + } + + if (plugin->info->type != PURPLE_PLUGIN_STANDARD || + (plugin->info->flags & PURPLE_PLUGIN_FLAG_INVISIBLE) || + plugin->error) + return; + + gnt_tree_add_choice(GNT_TREE(plugins.tree), plugin, + gnt_tree_create_row(GNT_TREE(plugins.tree), plugin->info->name), NULL, NULL); + gnt_tree_set_choice(GNT_TREE(plugins.tree), plugin, purple_plugin_is_loaded(plugin)); + gnt_tree_set_row_flags(GNT_TREE(plugins.tree), plugin, GNT_TEXT_FLAG_BOLD); + gnt_tree_set_selected(GNT_TREE(plugins.tree), plugin); +} + +static void +install_plugin_cb(GntWidget *w, gpointer null) +{ + static int handle; + + purple_request_close_with_handle(&handle); + purple_request_file(&handle, _("Select plugin to install"), NULL, + FALSE, G_CALLBACK(install_selected_file_cb), NULL, + NULL, NULL, NULL, &handle); + g_signal_connect_swapped(G_OBJECT(w), "destroy", G_CALLBACK(purple_request_close_with_handle), &handle); +} + void finch_plugins_show_all() { GntWidget *window, *tree, *box, *aboot, *button; @@ -272,6 +360,7 @@ gnt_box_add_widget(GNT_BOX(box), gnt_vline_new()); plugins.aboot = aboot = gnt_text_view_new(); + gnt_text_view_set_flag(GNT_TEXT_VIEW(aboot), GNT_TEXT_VIEW_TOP_ALIGN); gnt_widget_set_size(aboot, 40, 20); gnt_box_add_widget(GNT_BOX(box), aboot); @@ -307,6 +396,10 @@ box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); + button = gnt_button_new(_("Install Plugin...")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(install_plugin_cb), NULL); + button = gnt_button_new(_("Close")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect_swapped(G_OBJECT(button), "activate",
--- a/finch/gntpounce.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntpounce.c Fri Oct 12 02:06:38 2007 +0000 @@ -964,10 +964,15 @@ PURPLE_CALLBACK(signed_on_off_cb), NULL); } +static void +dummy_pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data) +{ +} + /* XXX: There's no such thing in pidgin. Perhaps there should be? */ void finch_pounces_uninit() { - purple_pounces_register_handler(FINCH_UI, NULL, NULL, NULL); + purple_pounces_register_handler(FINCH_UI, dummy_pounce_cb, NULL, NULL); purple_signals_disconnect_by_handle(finch_pounces_get_handle()); }
--- a/finch/gntrequest.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/gntrequest.c Fri Oct 12 02:06:38 2007 +0000 @@ -76,6 +76,8 @@ static void setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data) { + if (default_cb == NULL) + return; g_object_set_data(G_OBJECT(window), "default-callback", default_cb); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data); }
--- a/finch/libgnt/gntbindable.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntbindable.h Fri Oct 12 02:06:38 2007 +0000 @@ -105,73 +105,75 @@ /*GntBindableAction *gnt_bindable_action_parse(const char *name);*/ /** - * - * @param action + * Free a bindable action. + * + * @param action The bindable action. */ void gnt_bindable_action_free(GntBindableAction *action); /** - * - * @param param + * Free a GntBindableActionParam. + * + * @param param The GntBindableActionParam to free. */ void gnt_bindable_action_param_free(GntBindableActionParam *param); /** - * - * @param klass - * @param name - * @param callback - * @param trigger + * Register a bindable action for a class. + * + * @param klass The class the binding is for. + * @param name The name of the binding. + * @param callback The callback for the binding. + * @param trigger The default trigger for the binding, or @c NULL, followed by a NULL-terminated + * list of default parameters. */ void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, GntBindableActionCallback callback, const char *trigger, ...); /** - * - * @param klass - * @param name - * @param trigger + * Register a key-binding to an existing action. + * + * @param klass The class the binding is for. + * @param name The name of the binding. + * @param trigger A new trigger for the binding, followed by a @c NULL-terminated list of parameters for the callback. */ void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, const char *trigger, ...); /** - * - * @param bindable - * @param keys + * Perform an action from a keybinding. * - * @return + * @param bindable The bindable object. + * @param keys The key to trigger the action. + * + * @return @c TRUE if the action was performed successfully, @c FALSE otherwise. */ gboolean gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys); /** - * - * @param bindable - * @param name + * Perform an action on a bindable object. * - * @return + * @param bindable The bindable object. + * @param name The action to perform, followed by a @c NULL-terminated list of parameters. + * + * @return @c TRUE if the action was performed successfully, @c FALSE otherwise. */ gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...); /** -* Returns a GntTree populated with "key" -> "binding" for the widget. -*/ -/** -* -* @param widget -* -* @return -*/ + * Returns a GntTree populated with "key" -> "binding" for the widget. + * + * @param widget The object to list the bindings for. + * + * @return The GntTree. + */ GntBindable * gnt_bindable_bindings_view(GntBindable *bind); /** - * - * Builds a window that list the key bindings for a GntBindable object. From this window a user can select a listing to rebind a new key for the given action. - * - */ -/** + * Builds a window that list the key bindings for a GntBindable object. + * From this window a user can select a listing to rebind a new key for the given action. * - * @param bindable + * @param bindable The object to list the bindings for. * - * @return + * @return @c TRUE */ gboolean gnt_bindable_build_help_window(GntBindable *bindable);
--- a/finch/libgnt/gntbutton.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntbutton.h Fri Oct 12 02:06:38 2007 +0000 @@ -73,17 +73,16 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for Gntbutton */ GType gnt_button_get_gtype(void); /** - * - * @param text + * Create a new button. * - * @return + * @param text The text for the button. + * + * @return The newly created button. */ GntWidget * gnt_button_new(const char *text);
--- a/finch/libgnt/gntcheckbox.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntcheckbox.h Fri Oct 12 02:06:38 2007 +0000 @@ -68,32 +68,33 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for GntCheckBox */ GType gnt_check_box_get_gtype(void); /** - * - * @param text + * Create a new checkbox. * - * @return + * @param text The text for the checkbox. + * + * @return The newly created checkbox. */ GntWidget * gnt_check_box_new(const char *text); /** - * - * @param box - * @param set + * Set whether the checkbox should be checked or not. + * + * @param box The checkbox. + * @param set @c TRUE if the checkbox should be selected, @c FALSE otherwise. */ void gnt_check_box_set_checked(GntCheckBox *box, gboolean set); /** - * - * @param box + * Return the checked state of the checkbox. * - * @return + * @param box The checkbox. + * + * @return @c TRUE if the checkbox is selected, @c FALSE otherwise. */ gboolean gnt_check_box_get_checked(GntCheckBox *box);
--- a/finch/libgnt/gntclipboard.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntclipboard.c Fri Oct 12 02:06:38 2007 +0000 @@ -48,7 +48,7 @@ *****************************************************************************/ void -gnt_clipboard_set_string(GntClipboard *clipboard, gchar *string) +gnt_clipboard_set_string(GntClipboard *clipboard, const gchar *string) { g_free(clipboard->string); clipboard->string = g_strdup(string);
--- a/finch/libgnt/gntclipboard.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntclipboard.h Fri Oct 12 02:06:38 2007 +0000 @@ -60,26 +60,27 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for GntClipboard. */ GType gnt_clipboard_get_gtype(void); /** - * - * @param clip + * Get the current text from the clipboard. * - * @return + * @param clip The clipboard. + * + * @return A copy of the string in the clipboard. The caller should free the + * returned value. */ gchar * gnt_clipboard_get_string(GntClipboard *clip); /** - * - * @param clip - * @param string + * Set the text in the clipboard. + * + * @param clip The clipboard. + * @param string New string for the clipboard. */ -void gnt_clipboard_set_string(GntClipboard *clip, gchar *string); +void gnt_clipboard_set_string(GntClipboard *clip, const gchar *string); G_END_DECLS
--- a/finch/libgnt/gntcolors.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntcolors.h Fri Oct 12 02:06:38 2007 +0000 @@ -29,6 +29,9 @@ #include <glib.h> +/** + * Different classes of colors. + */ typedef enum { GNT_COLOR_NORMAL = 1, @@ -58,27 +61,28 @@ GNT_TOTAL_COLORS }; -/* populate some default colors */ /** - * + * Initialize the colors. */ void gnt_init_colors(void); /** - * + * Uninitialize the colors. */ void gnt_uninit_colors(void); #if GLIB_CHECK_VERSION(2,6,0) /** - * - * @param kfile + * Parse color information from a file. + * + * @param kfile The file containing color information. */ void gnt_colors_parse(GKeyFile *kfile); /** - * - * @param kfile + * Parse color-pair information from a file. + * + * @param kfile The file containing the color-pair information. */ void gnt_color_pairs_parse(GKeyFile *kfile);
--- a/finch/libgnt/gntcombobox.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntcombobox.h Fri Oct 12 02:06:38 2007 +0000 @@ -69,15 +69,11 @@ G_BEGIN_DECLS /** - * - * Get the GType for GntComboBox - * - * @return + * @return Get the GType for GntComboBox */ GType gnt_combo_box_get_gtype(void); /** - * * Create a new GntComboBox * * @return A new GntComboBox @@ -85,7 +81,6 @@ GntWidget * gnt_combo_box_new(void); /** - * * Add an entry * * @param box The GntComboBox @@ -95,7 +90,6 @@ void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text); /** - * * Remove an entry * * @param box The GntComboBox @@ -104,7 +98,6 @@ void gnt_combo_box_remove(GntComboBox *box, gpointer key); /** - * * Remove all entries * * @param box The GntComboBox @@ -112,7 +105,6 @@ void gnt_combo_box_remove_all(GntComboBox *box); /** - * * Get the data that is currently selected * * @param box The GntComboBox @@ -122,7 +114,6 @@ gpointer gnt_combo_box_get_selected_data(GntComboBox *box); /** - * * Set the current selection to a specific entry * * @param box The GntComboBox
--- a/finch/libgnt/gntentry.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntentry.h Fri Oct 12 02:06:38 2007 +0000 @@ -100,95 +100,115 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for GntEntry. */ GType gnt_entry_get_gtype(void); /** - * - * @param text + * Create a new GntEntry. * - * @return + * @param text The text in the new entry box. + * + * @return The newly created entry box. */ GntWidget * gnt_entry_new(const char *text); /** - * - * @param entry - * @param max + * Set the maximum length of the text in the entry box. + * + * @param entry The entry box. + * @param max The maximum length for text. A value of 0 means infinite length. */ void gnt_entry_set_max(GntEntry *entry, int max); /** - * - * @param entry - * @param text + * Set the text in an entry box. + * + * @param entry The entry box. + * @param text The text to set in the box. */ void gnt_entry_set_text(GntEntry *entry, const char *text); /** - * - * @param entry - * @param flag + * Set flags an entry box. + * + * @param entry The entry box. + * @param flag The flags to set for the entry box. */ void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag); +/** + * Get the text in an entry box. + * + * @param entry The entry box. + * + * @return The current text in the entry box. + */ const char *gnt_entry_get_text(GntEntry *entry); /** - * - * @param entry + * Clear the text in the entry box. + * + * @param entry The entry box. */ void gnt_entry_clear(GntEntry *entry); /** - * - * @param entry - * @param set + * Set whether the text in the entry box should be masked for display. + * + * @param entry The entry box. + * @param set @c TRUE if the text should be masked, @c FALSE otherwise. */ void gnt_entry_set_masked(GntEntry *entry, gboolean set); /** - * - * @param entry - * @param text + * Add a text to the history list for the text. The history length for the + * entry box needs to be set first by gnt_entry_set_history_length. + * + * @param entry The entry box. + * @param text A new entry for the history list. */ void gnt_entry_add_to_history(GntEntry *entry, const char *text); /** - * - * @param entry - * @param num + * Set the length of history for the entry box. + * + * @param entry The entry box. + * @param num The maximum length of the history. */ void gnt_entry_set_history_length(GntEntry *entry, int num); /** - * - * @param entry - * @param word + * Set whether the suggestions are for the entire entry box, or for each + * individual word in the entry box. + * + * @param entry The entry box. + * @param word @c TRUE if the suggestions are for individual words, @c FALSE otherwise. */ void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word); /** - * - * @param entry - * @param always + * Set whether to always display the suggestions list, or only when the + * tab-completion key is pressed (the TAB key, by default). + * + * @param entry The entry box. + * @param always @c TRUE if the suggestion list should always be displayed. */ void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always); /** - * - * @param entry - * @param text + * Add an item to the suggestion list. + * + * @param entry The entry box. + * @param text An item to add to the suggestion list. */ void gnt_entry_add_suggest(GntEntry *entry, const char *text); /** - * - * @param entry - * @param text + * Remove an entry from the suggestion list. + * + * @param entry The entry box. + * @param text The item to remove from the suggestion list. */ void gnt_entry_remove_suggest(GntEntry *entry, const char *text);
--- a/finch/libgnt/gntmain.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntmain.c Fri Oct 12 02:06:38 2007 +0000 @@ -223,6 +223,7 @@ char keys[256]; int rd; char *k; + char *cvrt = NULL; if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD) return FALSE; @@ -243,15 +244,16 @@ raise(SIGABRT); } - gnt_wm_set_event_stack(wm, TRUE); rd += HOLDING_ESCAPE; - keys[rd] = 0; - if (mouse_enabled && detect_mouse_action(keys)) - goto end; - if (HOLDING_ESCAPE) keys[0] = '\033'; - k = keys; + keys[rd] = 0; + gnt_wm_set_event_stack(wm, TRUE); + + cvrt = g_locale_to_utf8(keys, rd, (gsize*)&rd, NULL, NULL); + k = cvrt ? cvrt : keys; + if (mouse_enabled && detect_mouse_action(k)) + goto end; #if 0 /* I am not sure what's happening here. If this actually does something, @@ -290,6 +292,7 @@ } end: gnt_wm_set_event_stack(wm, FALSE); + g_free(cvrt); return TRUE; }
--- a/finch/libgnt/gntmenu.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntmenu.c Fri Oct 12 02:06:38 2007 +0000 @@ -459,3 +459,34 @@ menu->list = g_list_append(menu->list, item); } +GntMenuItem *gnt_menu_get_item(GntMenu *menu, const char *id) +{ + GntMenuItem *item = NULL; + GList *iter = menu->list; + + if (!id || !*id) + return NULL; + + for (; iter; iter = iter->next) { + GntMenu *sub; + item = iter->data; + sub = gnt_menuitem_get_submenu(item); + if (sub) { + item = gnt_menu_get_item(sub, id); + if (item) + break; + } else { + const char *itid = gnt_menuitem_get_id(item); + if (itid && strcmp(itid, id) == 0) + break; + /* XXX: Perhaps look at the menu-label as well? */ + } + item = NULL; + } + + if (item) + menuitem_activate(menu, item); + + return item; +} +
--- a/finch/libgnt/gntmenu.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntmenu.h Fri Oct 12 02:06:38 2007 +0000 @@ -86,27 +86,37 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return The GType for GntMenu. */ GType gnt_menu_get_gtype(void); /** - * - * @param type + * Create a new menu. * - * @return + * @param type The type of the menu, whether it's a toplevel menu or a popup menu. + * + * @return The newly created menu. */ GntWidget * gnt_menu_new(GntMenuType type); /** - * - * @param menu - * @param item + * Add an item to the menu. + * + * @param menu The menu. + * @param item The item to add to the menu. */ void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item); +/** + * Get the GntMenuItem with the given ID. + * + * @param menu The menu. + * @param id The ID for an item. + * + * @return The menuitem with the given ID, or @c NULL. + */ +GntMenuItem *gnt_menu_get_item(GntMenu *menu, const char *id); + G_END_DECLS #endif /* GNT_MENU_H */
--- a/finch/libgnt/gntmenuitem.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntmenuitem.c Fri Oct 12 02:06:38 2007 +0000 @@ -33,6 +33,7 @@ item->text = NULL; if (item->submenu) gnt_widget_destroy(GNT_WIDGET(item->submenu)); + g_free(item->priv.id); parent_class->dispose(obj); } @@ -104,6 +105,11 @@ item->submenu = menu; } +GntMenu *gnt_menuitem_get_submenu(GntMenuItem *item) +{ + return item->submenu; +} + void gnt_menuitem_set_trigger(GntMenuItem *item, char trigger) { item->priv.trigger = trigger; @@ -114,3 +120,14 @@ return item->priv.trigger; } +void gnt_menuitem_set_id(GntMenuItem *item, const char *id) +{ + g_free(item->priv.id); + item->priv.id = g_strdup(id); +} + +const char * gnt_menuitem_get_id(GntMenuItem *item) +{ + return item->priv.id; +} +
--- a/finch/libgnt/gntmenuitem.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntmenuitem.h Fri Oct 12 02:06:38 2007 +0000 @@ -53,6 +53,7 @@ int x; int y; char trigger; + char *id; }; typedef void (*GntMenuItemCallback)(GntMenuItem *item, gpointer data); @@ -86,36 +87,46 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for GntMenuItem. */ GType gnt_menuitem_get_gtype(void); /** - * - * @param text + * Create a new menuitem. * - * @return + * @param text Label for the menuitem. + * + * @return The newly created menuitem. */ GntMenuItem * gnt_menuitem_new(const char *text); /** - * - * @param item - * @param callback - * @param data + * Set a callback function for a menuitem. + * + * @param item The menuitem. + * @param callback The callback function. + * @param data Data to send to the callback function. */ void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data); /** - * - * @param item - * @param menu + * Set a submenu for a menuitem. A menuitem with a submenu cannot have a callback. + * + * @param item The menuitem. + * @param menu The submenu. */ void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu); /** + * Get the submenu for a menuitem. + * + * @param item The menuitem. + * + * @return The submenu, or @c NULL. + */ +GntMenu *gnt_menuitem_get_submenu(GntMenuItem *item); + +/** * Set a trigger key for the item. * * @param item The menuitem @@ -134,6 +145,23 @@ */ char gnt_menuitem_get_trigger(GntMenuItem *item); +/** + * Set an ID for the menuitem. + * + * @param item The menuitem. + * @param id The ID for the menuitem. + */ +void gnt_menuitem_set_id(GntMenuItem *item, const char *id); + +/** + * Get the ID of the menuitem. + * + * @param item The menuitem. + * + * @return The ID for the menuitem. + */ +const char * gnt_menuitem_get_id(GntMenuItem *item); + G_END_DECLS #endif /* GNT_MENUITEM_H */
--- a/finch/libgnt/gntstyle.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntstyle.c Fri Oct 12 02:06:38 2007 +0000 @@ -26,7 +26,6 @@ #include <glib.h> #include <ctype.h> -#include <glib/gprintf.h> #include <stdlib.h> #include <string.h> @@ -228,6 +227,65 @@ #endif } +gboolean gnt_style_read_menu_accels(const char *name, GHashTable *table) +{ +#if GLIB_CHECK_VERSION(2,6,0) + char *kname; + GError *error = NULL; + gboolean ret = FALSE; + + kname = g_strdup_printf("%s::menu", name); + + if (g_key_file_has_group(gkfile, kname)) + { + gsize len = 0; + char **keys; + + keys = g_key_file_get_keys(gkfile, kname, &len, &error); + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + g_free(kname); + return ret; + } + + while (len--) + { + char *key, *menuid; + + key = g_strdup(keys[len]); + menuid = g_key_file_get_string(gkfile, kname, keys[len], &error); + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + error = NULL; + } + else + { + const char *keycode = parse_key(key); + if (keycode == NULL) { + g_printerr("GntStyle: Invalid key-binding %s\n", key); + } else { + ret = TRUE; + g_hash_table_replace(table, g_strdup(keycode), menuid); + menuid = NULL; + } + } + g_free(key); + g_free(menuid); + } + g_strfreev(keys); + } + + g_free(kname); + return ret; +#endif + return FALSE; +} + void gnt_styles_get_keyremaps(GType type, GHashTable *hash) { #if GLIB_CHECK_VERSION(2,6,0)
--- a/finch/libgnt/gntstyle.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntstyle.h Fri Oct 12 02:06:38 2007 +0000 @@ -89,6 +89,16 @@ */ void gnt_style_read_actions(GType type, GntBindableClass *klass); +/* + * Read menu-accels from ~/.gntrc + * + * @param name The name of the window. + * @param table The hastable to store the accel information. + * + * @return @c TRUE if some accels were read, @c FALSE otherwise. + */ +gboolean gnt_style_read_menu_accels(const char *name, GHashTable *table); + void gnt_style_read_workspaces(GntWM *wm); /**
--- a/finch/libgnt/gnttree.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gnttree.c Fri Oct 12 02:06:38 2007 +0000 @@ -1265,8 +1265,10 @@ { GntTreeRow *pr = NULL; + row->tree = tree; + row->key = key; + row->data = NULL; g_hash_table_replace(tree->hash, key, row); - row->tree = tree; if (bigbro == NULL && tree->priv->compare) { @@ -1327,9 +1329,6 @@ } } - row->key = key; - row->data = NULL; - redraw_tree(tree); return row;
--- a/finch/libgnt/gntwindow.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntwindow.c Fri Oct 12 02:06:38 2007 +0000 @@ -25,6 +25,11 @@ #include <string.h> +struct _GntWindowPriv +{ + GHashTable *accels; /* key => menuitem-id */ +}; + enum { SIG_WORKSPACE_HIDE, @@ -55,6 +60,10 @@ GntWindow *window = GNT_WINDOW(widget); if (window->menu) gnt_widget_destroy(GNT_WIDGET(window->menu)); + if (window->priv) { + g_hash_table_destroy(window->priv->accels); + g_free(window->priv); + } org_destroy(widget); } @@ -98,8 +107,11 @@ gnt_window_init(GTypeInstance *instance, gpointer class) { GntWidget *widget = GNT_WIDGET(instance); + GntWindow *win = GNT_WINDOW(widget); GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + win->priv = g_new0(GntWindowPriv, 1); + win->priv->accels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); GNTDEBUG; } @@ -170,8 +182,23 @@ void gnt_window_set_menu(GntWindow *window, GntMenu *menu) { /* If a menu already existed, then destroy that first. */ + const char *name = gnt_widget_get_name(GNT_WIDGET(window)); if (window->menu) gnt_widget_destroy(GNT_WIDGET(window->menu)); window->menu = menu; + if (name && window->priv) { + if (!gnt_style_read_menu_accels(name, window->priv->accels)) { + g_hash_table_destroy(window->priv->accels); + g_free(window->priv); + window->priv = NULL; + } + } } +const char * gnt_window_get_accel_item(GntWindow *window, const char *key) +{ + if (window->priv) + return g_hash_table_lookup(window->priv->accels, key); + return NULL; +} +
--- a/finch/libgnt/gntwindow.h Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntwindow.h Fri Oct 12 02:06:38 2007 +0000 @@ -52,6 +52,7 @@ { GntBox parent; GntMenu *menu; + GntWindowPriv *priv; }; struct _GntWindowClass @@ -99,6 +100,8 @@ */ void gnt_window_set_menu(GntWindow *window, GntMenu *menu); +const char * gnt_window_get_accel_item(GntWindow *window, const char *key); + void gnt_window_workspace_hiding(GntWindow *); void gnt_window_workspace_showing(GntWindow *);
--- a/finch/libgnt/gntwm.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/gntwm.c Fri Oct 12 02:06:38 2007 +0000 @@ -27,8 +27,8 @@ #include "config.h" +#include <glib.h> #include <ctype.h> -#include <glib/gprintf.h> #include <gmodule.h> #include <stdlib.h> #include <string.h> @@ -1853,8 +1853,19 @@ ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys); else if (wm->_list.window) ret = gnt_widget_key_pressed(wm->_list.window, keys); - else if (wm->cws->ordered) - ret = gnt_widget_key_pressed(GNT_WIDGET(wm->cws->ordered->data), keys); + else if (wm->cws->ordered) { + GntWidget *win = wm->cws->ordered->data; + if (GNT_IS_WINDOW(win)) { + GntMenu *menu = GNT_WINDOW(win)->menu; + if (menu) { + const char *id = gnt_window_get_accel_item(GNT_WINDOW(win), keys); + if (id) + ret = (gnt_menu_get_item(menu, id) != NULL); + } + } + if (!ret) + ret = gnt_widget_key_pressed(win, keys); + } return ret; }
--- a/finch/libgnt/pygnt/gntmodule.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/pygnt/gntmodule.c Fri Oct 12 02:06:38 2007 +0000 @@ -1,7 +1,74 @@ #include <pygobject.h> +#include "gnt.h" void gnt_register_classes (PyObject *d); extern PyMethodDef gnt_functions[]; + +static void +gnt_add_string_constants(PyObject *module) +{ +#define define_key(x) if (GNT_KEY_##x && *(GNT_KEY_##x)) PyModule_AddStringConstant(module, "KEY_" #x, GNT_KEY_##x) + + define_key(POPUP); + + define_key(LEFT); + define_key(RIGHT); + define_key(UP); + define_key(DOWN); + + define_key(CTRL_UP); + define_key(CTRL_DOWN); + define_key(CTRL_RIGHT); + define_key(CTRL_LEFT); + + define_key(PGUP); + define_key(PGDOWN); + define_key(HOME); + define_key(END); + + define_key(ENTER); + + define_key(BACKSPACE); + define_key(DEL); + define_key(INS); + define_key(BACK_TAB); + + define_key(CTRL_A); + define_key(CTRL_B); + define_key(CTRL_D); + define_key(CTRL_E); + define_key(CTRL_F); + define_key(CTRL_G); + define_key(CTRL_H); + define_key(CTRL_I); + define_key(CTRL_J); + define_key(CTRL_K); + define_key(CTRL_L); + define_key(CTRL_M); + define_key(CTRL_N); + define_key(CTRL_O); + define_key(CTRL_P); + define_key(CTRL_R); + define_key(CTRL_T); + define_key(CTRL_U); + define_key(CTRL_V); + define_key(CTRL_W); + define_key(CTRL_X); + define_key(CTRL_Y); + + define_key(F1); + define_key(F2); + define_key(F3); + define_key(F4); + define_key(F5); + define_key(F6); + define_key(F7); + define_key(F8); + define_key(F9); + define_key(F10); + define_key(F11); + define_key(F12); +} DL_EXPORT(void) initgnt(void) @@ -19,5 +86,8 @@ if (PyErr_Occurred ()) { Py_FatalError ("can't initialise module sad"); } + + gnt_init(); + gnt_add_string_constants(m); }
--- a/finch/libgnt/pygnt/gnttree.override Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/libgnt/pygnt/gnttree.override Fri Oct 12 02:06:38 2007 +0000 @@ -62,13 +62,14 @@ { static char *kwlist[] = {"key", "row", "parent", "bigbro", NULL}; PyObject *py_list; - gpointer key, parent, bigbro; + gpointer key, parent, bigbro = NULL; int len, i; GList *list = NULL; GntTreeRow *row; + gboolean insert_last = FALSE; if (!PyArg_ParseTuple(args, - "OOOO:GntTree.add_row_after", + "OOO|O:GntTree.add_row_after", &key, &py_list, &parent, @@ -92,13 +93,20 @@ parent = NULL; if (bigbro == Py_None) bigbro = NULL; + else if (bigbro == NULL) + insert_last = TRUE; + + Py_INCREF((PyObject*)key); list = g_list_reverse(list); row = gnt_tree_create_row_from_list(GNT_TREE(self->obj), list); - gnt_tree_add_row_after(GNT_TREE(self->obj), - key, - row, - parent, bigbro); + if (insert_last) + gnt_tree_add_row_last(GNT_TREE(self->obj), + key, row, parent); + else + gnt_tree_add_row_after(GNT_TREE(self->obj), + key, row, + parent, bigbro); g_list_free(list); Py_INCREF(Py_None); @@ -179,4 +187,27 @@ Py_INCREF(Py_None); return Py_None; } +%% +override gnt_tree_set_compare_func +static PyObject * +_wrap_gnt_tree_set_compare_func(PyGObject *self, PyObject *args) +{ + static char *kwlist[] = {"compare_func", NULL}; + PyGObject *compare; + if (!PyArg_ParseTuple(args, "O:GntTree.set_compare_func", &compare)) { + return NULL; + } + + if (!PyCallable_Check(compare)) { + PyErr_SetString(PyExc_TypeError, "the callback must be callable ... doh!"); + return NULL; + } + + Py_INCREF(compare); + gnt_tree_set_compare_func(GNT_TREE(self->obj), (GCompareFunc)compare->obj); + + Py_INCREF(Py_None); + return Py_None; +} +
--- a/finch/plugins/lastlog.c Wed Sep 26 06:56:02 2007 +0000 +++ b/finch/plugins/lastlog.c Fri Oct 12 02:06:38 2007 +0000 @@ -96,6 +96,7 @@ { cmd = purple_cmd_register("lastlog", "s", PURPLE_CMD_P_DEFAULT, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL, + /* Translator Note: The "backlog" is the conversation buffer/history. */ lastlog_cb, _("lastlog: Searches for a substring in the backlog."), NULL); return TRUE; }
--- a/libpurple/Makefile.am Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/Makefile.am Fri Oct 12 02:06:38 2007 +0000 @@ -114,6 +114,7 @@ privacy.h \ proxy.h \ prpl.h \ + purple.h \ request.h \ roomlist.h \ savedstatuses.h \
--- a/libpurple/account.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/account.c Fri Oct 12 02:06:38 2007 +0000 @@ -63,7 +63,10 @@ PurpleAccountRequestType type; PurpleAccount *account; void *ui_handle; - + char *user; + gpointer userdata; + PurpleAccountRequestAuthorizationCb auth_cb; + PurpleAccountRequestAuthorizationCb deny_cb; } PurpleAccountRequestInfo; static PurpleAccountUiOps *account_ui_ops = NULL; @@ -1157,6 +1160,28 @@ } } +static void +request_auth_cb(void *data) +{ + PurpleAccountRequestInfo *info = data; + info->auth_cb(info->userdata); + purple_signal_emit(purple_accounts_get_handle(), + "account-authorization-granted", info->account, info->user); + g_free(info->user); + g_free(info); +} + +static void +request_deny_cb(void *data) +{ + PurpleAccountRequestInfo *info = data; + info->deny_cb(info->userdata); + purple_signal_emit(purple_accounts_get_handle(), + "account-authorization-denied", info->account, info->user); + g_free(info->user); + g_free(info); +} + void * purple_account_request_authorization(PurpleAccount *account, const char *remote_user, const char *id, const char *alias, const char *message, gboolean on_list, @@ -1164,18 +1189,35 @@ { PurpleAccountUiOps *ui_ops; PurpleAccountRequestInfo *info; + int plugin_return; g_return_val_if_fail(account != NULL, NULL); g_return_val_if_fail(remote_user != NULL, NULL); ui_ops = purple_accounts_get_ui_ops(); + plugin_return = GPOINTER_TO_INT( + purple_signal_emit_return_1(purple_accounts_get_handle(), + "account-authorization-requested", account, remote_user)); + + if (plugin_return > 0) { + auth_cb(user_data); + return NULL; + } else if (plugin_return < 0) { + deny_cb(user_data); + return NULL; + } + if (ui_ops != NULL && ui_ops->request_authorize != NULL) { info = g_new0(PurpleAccountRequestInfo, 1); info->type = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION; info->account = account; + info->auth_cb = auth_cb; + info->deny_cb = deny_cb; + info->userdata = user_data; + info->user = g_strdup(remote_user); info->ui_handle = ui_ops->request_authorize(account, remote_user, id, alias, message, - on_list, auth_cb, deny_cb, user_data); + on_list, request_auth_cb, request_deny_cb, info); handles = g_list_append(handles, info); return info->ui_handle; @@ -2452,6 +2494,25 @@ PURPLE_SUBTYPE_ACCOUNT), purple_value_new(PURPLE_TYPE_STRING)); + purple_signal_register(handle, "account-authorization-requested", + purple_marshal_INT__POINTER_POINTER, + purple_value_new(PURPLE_TYPE_INT), 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, + PURPLE_SUBTYPE_ACCOUNT), + purple_value_new(PURPLE_TYPE_STRING)); + + purple_signal_register(handle, "account-authorization-denied", + purple_marshal_VOID__POINTER_POINTER, NULL, 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, + PURPLE_SUBTYPE_ACCOUNT), + purple_value_new(PURPLE_TYPE_STRING)); + + purple_signal_register(handle, "account-authorization-granted", + purple_marshal_VOID__POINTER_POINTER, NULL, 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, + PURPLE_SUBTYPE_ACCOUNT), + purple_value_new(PURPLE_TYPE_STRING)); + load_accounts(); }
--- a/libpurple/blist.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/blist.h Fri Oct 12 02:06:38 2007 +0000 @@ -41,6 +41,8 @@ typedef struct _PurpleContact PurpleContact; typedef struct _PurpleBuddy PurpleBuddy; +typedef gboolean (*PurpleFilterBlistFunc)(PurpleBlistNode *node); + /**************************************************************************/ /* Enumerations */ /**************************************************************************/ @@ -66,9 +68,12 @@ typedef enum { PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 << 0, /**< node should not be saved with the buddy list */ + PURPLE_BLIST_NODE_HAS_CONVERSATION = 1 << 1, /**< node (buddy or chat) has an open conversation */ } PurpleBlistNodeFlags; +#define PURPLE_BLIST_NODE_SET_FLAG(node, f) (((PurpleBlistNode *)node)->flags |= (f)) +#define PURPLE_BLIST_NODE_UNSET_FLAG(node, f) (((PurpleBlistNode *)node)->flags &= ~(f)) #define PURPLE_BLIST_NODE_HAS_FLAG(b, f) (((PurpleBlistNode*)(b))->flags & (f)) #define PURPLE_BLIST_NODE_SHOULD_SAVE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_NO_SAVE))
--- a/libpurple/certificate.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/certificate.c Fri Oct 12 02:06:38 2007 +0000 @@ -540,7 +540,7 @@ /* Determine whether the name matches */ if (purple_certificate_check_subject_name(crt, vrq->subject_name)) { - cn_match = _(""); + cn_match = ""; } else { cn_match = _("(DOES NOT MATCH)"); } @@ -1460,15 +1460,14 @@ tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,tls_peers_name); - /* TODO: This should probably just prompt the user instead of throwing - an angry fit */ if (!tls_peers) { purple_debug_error("certificate/x509/tls_cached", - "Couldn't find local peers cache %s\nReturning INVALID to callback\n", + "Couldn't find local peers cache %s\nPrompting the user\n", tls_peers_name); - purple_certificate_verify_complete(vrq, - PURPLE_CERTIFICATE_INVALID); + + /* vrq now becomes the problem of unknown_peer */ + x509_tls_cached_unknown_peer(vrq); return; }
--- a/libpurple/conversation.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/conversation.c Fri Oct 12 02:06:38 2007 +0000 @@ -225,6 +225,7 @@ msg->flags = flags; msg->what = g_strdup(message); msg->when = when; + msg->conv = conv; conv->message_history = g_list_prepend(conv->message_history, msg); }
--- a/libpurple/conversation.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/conversation.h Fri Oct 12 02:06:38 2007 +0000 @@ -293,6 +293,7 @@ char *what; PurpleMessageFlags flags; time_t when; + PurpleConversation *conv; }; /**
--- a/libpurple/plugin.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/plugin.c Fri Oct 12 02:06:38 2007 +0000 @@ -1275,13 +1275,9 @@ if (basename) basename = purple_plugin_get_basename(filename); - if ((plugin = purple_plugins_find_with_filename(filename)) != NULL) - { - purple_debug_info("plugins", "Loading saved plugin %s\n", - plugin->path); - purple_plugin_load(plugin); - } - else if (basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) + if (((plugin = purple_plugins_find_with_filename(filename)) != NULL) || + (basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) || + ((plugin = purple_plugin_probe(filename)) != NULL)) { purple_debug_info("plugins", "Loading saved plugin %s\n", plugin->path);
--- a/libpurple/plugins/signals-test.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/plugins/signals-test.c Fri Oct 12 02:06:38 2007 +0000 @@ -76,6 +76,28 @@ old, purple_account_get_alias(account)); } +static int +account_authorization_requested_cb(PurpleAccount *account, const char *user, gpointer data) +{ + purple_debug_misc("signals test", "account-authorization-requested (%s, %s)\n", + purple_account_get_username(account), user); + return 0; +} + +static void +account_authorization_granted_cb(PurpleAccount *account, const char *user, gpointer data) +{ + purple_debug_misc("signals test", "account-authorization-granted (%s, %s)\n", + purple_account_get_username(account), user); +} + +static void +account_authorization_denied_cb(PurpleAccount *account, const char *user, gpointer data) +{ + purple_debug_misc("signals test", "account-authorization-denied (%s, %s)\n", + purple_account_get_username(account), user); +} + /************************************************************************** * Buddy Icons signal callbacks **************************************************************************/ @@ -568,6 +590,12 @@ plugin, PURPLE_CALLBACK(account_status_changed), NULL); purple_signal_connect(accounts_handle, "account-alias-changed", plugin, PURPLE_CALLBACK(account_alias_changed), NULL); + purple_signal_connect(accounts_handle, "account-authorization-requested", + plugin, PURPLE_CALLBACK(account_authorization_requested_cb), NULL); + purple_signal_connect(accounts_handle, "account-authorization-denied", + plugin, PURPLE_CALLBACK(account_authorization_denied_cb), NULL); + purple_signal_connect(accounts_handle, "account-authorization-granted", + plugin, PURPLE_CALLBACK(account_authorization_granted_cb), NULL); /* Buddy List subsystem signals */ purple_signal_connect(blist_handle, "buddy-status-changed",
--- a/libpurple/plugins/ssl/ssl-gnutls.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Fri Oct 12 02:06:38 2007 +0000 @@ -111,7 +111,7 @@ PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc); ssize_t ret; - purple_debug_info("gnutls", "Handshaking with %s\n", gsc->host); + /*purple_debug_info("gnutls", "Handshaking with %s\n", gsc->host);*/ ret = gnutls_handshake(gnutls_data->session); if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) @@ -163,9 +163,9 @@ g_list_free(peers); { - const gnutls_datum_t *cert_list; + const gnutls_datum *cert_list; unsigned int cert_list_size = 0; - gnutls_session_t session=gnutls_data->session; + gnutls_session session=gnutls_data->session; int i; cert_list = @@ -182,7 +182,7 @@ gchar tbuf[256]; gsize tsz=sizeof(tbuf); gchar * tasc = NULL; - gnutls_x509_crt_t cert; + gnutls_x509_crt cert; gnutls_x509_crt_init(&cert); gnutls_x509_crt_import (cert, &cert_list[i], @@ -271,6 +271,8 @@ gnutls_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc); + purple_debug_info("gnutls", "Starting handshake with %s\n", gsc->host); + /* Orborde asks: Why are we configuring a callback, then immediately calling it? @@ -363,7 +365,7 @@ /* Forward declarations are fun! */ static PurpleCertificate * -x509_import_from_datum(const gnutls_datum_t dt, gnutls_x509_crt_fmt_t mode); +x509_import_from_datum(const gnutls_datum dt, gnutls_x509_crt_fmt mode); static GList * ssl_gnutls_get_peer_certificates(PurpleSslConnection * gsc) @@ -374,7 +376,7 @@ GList * peer_certs = NULL; /* List of raw certificates as given by GnuTLS */ - const gnutls_datum_t *cert_list; + const gnutls_datum *cert_list; unsigned int cert_list_size = 0; unsigned int i; @@ -412,7 +414,7 @@ /** Refcounted GnuTLS certificate data instance */ typedef struct { gint refcount; - gnutls_x509_crt_t crt; + gnutls_x509_crt crt; } x509_crtdata_t; /** Helper functions for reference counting */ @@ -434,9 +436,6 @@ /* If the refcount reaches zero, kill the structure */ if (cd->refcount <= 0) { - purple_debug_info("gnutls/x509", - "Freeing unused cert data at %p\n", - cd); /* Kill the internal data */ gnutls_x509_crt_deinit( cd->crt ); /* And kill the struct */ @@ -447,7 +446,7 @@ /** Helper macro to retrieve the GnuTLS crt_t from a PurpleCertificate */ #define X509_GET_GNUTLS_DATA(pcrt) ( ((x509_crtdata_t *) (pcrt->data))->crt) -/** Transforms a gnutls_datum_t containing an X.509 certificate into a Certificate instance under the x509_gnutls scheme +/** Transforms a gnutls_datum containing an X.509 certificate into a Certificate instance under the x509_gnutls scheme * * @param dt Datum to transform * @param mode GnuTLS certificate format specifier (GNUTLS_X509_FMT_PEM for @@ -457,7 +456,7 @@ * @return A newly allocated Certificate structure of the x509_gnutls scheme */ static PurpleCertificate * -x509_import_from_datum(const gnutls_datum_t dt, gnutls_x509_crt_fmt_t mode) +x509_import_from_datum(const gnutls_datum dt, gnutls_x509_crt_fmt mode) { /* Internal certificate data structure */ x509_crtdata_t *certdat; @@ -492,7 +491,7 @@ PurpleCertificate *crt; /* Certificate being constructed */ gchar *buf; /* Used to load the raw file data */ gsize buf_sz; /* Size of the above */ - gnutls_datum_t dt; /* Struct to pass down to GnuTLS */ + gnutls_datum dt; /* Struct to pass down to GnuTLS */ purple_debug_info("gnutls", "Attempting to load X.509 certificate from %s\n", @@ -533,7 +532,7 @@ static gboolean x509_export_certificate(const gchar *filename, PurpleCertificate *crt) { - gnutls_x509_crt_t crt_dat; /* GnuTLS cert struct */ + gnutls_x509_crt crt_dat; /* GnuTLS cert struct */ int ret; gchar * out_buf; /* Data to output */ size_t out_size; /* Output size */ @@ -640,8 +639,8 @@ x509_certificate_signed_by(PurpleCertificate * crt, PurpleCertificate * issuer) { - gnutls_x509_crt_t crt_dat; - gnutls_x509_crt_t issuer_dat; + gnutls_x509_crt crt_dat; + gnutls_x509_crt issuer_dat; unsigned int verify; /* used to store result from GnuTLS verifier */ int ret; @@ -674,10 +673,10 @@ purple_debug_info("gnutls/x509", "Certificate for %s claims to be " "issued by %s, but the certificate " - "for %s does not match. A strcmp " - "says %d\n", - crt_id, crt_issuer_id, issuer_id, - strcmp(crt_issuer_id, issuer_id)); + "for %s does not match.\n", + crt_id ? crt_id : "(null)", + crt_issuer_id ? crt_issuer_id : "(null)", + issuer_id ? issuer_id : "(null)"); g_free(crt_id); g_free(issuer_id); g_free(crt_issuer_id); @@ -727,7 +726,7 @@ { size_t hashlen = 20; /* SHA1 hashes are 20 bytes */ size_t tmpsz = hashlen; /* Throw-away variable for GnuTLS to stomp on*/ - gnutls_x509_crt_t crt_dat; + gnutls_x509_crt crt_dat; GByteArray *hash; /**< Final hash container */ guchar hashbuf[hashlen]; /**< Temporary buffer to contain hash */ @@ -754,7 +753,7 @@ static gchar * x509_cert_dn (PurpleCertificate *crt) { - gnutls_x509_crt_t cert_dat; + gnutls_x509_crt cert_dat; gchar *dn = NULL; size_t dn_size; @@ -770,7 +769,10 @@ gnutls_x509_crt_get_dn(cert_dat, dn, &dn_size); /* Now allocate and get the Distinguished Name */ - dn = g_new0(gchar, dn_size); + /* Old versions of GnuTLS have an off-by-one error in reporting + the size of the needed buffer in some functions, so allocate + an extra byte */ + dn = g_new0(gchar, ++dn_size); if (0 != gnutls_x509_crt_get_dn(cert_dat, dn, &dn_size)) { purple_debug_error("gnutls/x509", "Failed to get Distinguished Name\n"); @@ -784,7 +786,7 @@ static gchar * x509_issuer_dn (PurpleCertificate *crt) { - gnutls_x509_crt_t cert_dat; + gnutls_x509_crt cert_dat; gchar *dn = NULL; size_t dn_size; @@ -800,7 +802,10 @@ gnutls_x509_crt_get_issuer_dn(cert_dat, dn, &dn_size); /* Now allocate and get the Distinguished Name */ - dn = g_new0(gchar, dn_size); + /* Old versions of GnuTLS have an off-by-one error in reporting + the size of the needed buffer in some functions, so allocate + an extra byte */ + dn = g_new0(gchar, ++dn_size); if (0 != gnutls_x509_crt_get_issuer_dn(cert_dat, dn, &dn_size)) { purple_debug_error("gnutls/x509", "Failed to get issuer's Distinguished " @@ -815,7 +820,7 @@ static gchar * x509_common_name (PurpleCertificate *crt) { - gnutls_x509_crt_t cert_dat; + gnutls_x509_crt cert_dat; gchar *cn = NULL; size_t cn_size; int ret; @@ -836,7 +841,10 @@ cn, &cn_size); /* Now allocate and get the Common Name */ - cn = g_new0(gchar, cn_size); + /* Old versions of GnuTLS have an off-by-one error in reporting + the size of the needed buffer in some functions, so allocate + an extra byte */ + cn = g_new0(gchar, ++cn_size); ret = gnutls_x509_crt_get_dn_by_oid(cert_dat, GNUTLS_OID_X520_COMMON_NAME, 0, /* First CN found, please */ @@ -855,7 +863,7 @@ static gboolean x509_check_name (PurpleCertificate *crt, const gchar *name) { - gnutls_x509_crt_t crt_dat; + gnutls_x509_crt crt_dat; g_return_val_if_fail(crt, FALSE); g_return_val_if_fail(crt->scheme == &x509_gnutls, FALSE); @@ -873,7 +881,7 @@ static gboolean x509_times (PurpleCertificate *crt, time_t *activation, time_t *expiration) { - gnutls_x509_crt_t crt_dat; + gnutls_x509_crt crt_dat; /* GnuTLS time functions return this on error */ const time_t errval = (time_t) (-1);
--- a/libpurple/protocols/irc/msgs.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/irc/msgs.c Fri Oct 12 02:06:38 2007 +0000 @@ -751,7 +751,10 @@ } purple_conversation_set_data(convo, IRC_NAMES_FLAG, GINT_TO_POINTER(FALSE)); - purple_conversation_present(convo); + /* Until purple_conversation_present does something that + * one would expect in Pidgin, this call produces buggy + * behavior both for the /join and auto-join cases. */ + /* purple_conversation_present(convo); */ return; }
--- a/libpurple/protocols/jabber/google.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/jabber/google.c Fri Oct 12 02:06:38 2007 +0000 @@ -64,7 +64,8 @@ message = xmlnode_get_child(child, "mail-thread-info"); if (count == 0 || !message) { - purple_notify_emails(js->gc, count, FALSE, NULL, NULL, (const char**) default_tos, NULL, NULL, NULL); + if (count > 0) + purple_notify_emails(js->gc, count, FALSE, NULL, NULL, (const char**) default_tos, NULL, NULL, NULL); g_free(default_tos[0]); return; }
--- a/libpurple/protocols/jabber/jutil.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/jabber/jutil.h Fri Oct 12 02:06:38 2007 +0000 @@ -22,8 +22,6 @@ #ifndef _PURPLE_JABBER_JUTIL_H_ #define _PURPLE_JABBER_JUTIL_H_ -#include "account.h" - typedef struct _JabberID { char *node; char *domain;
--- a/libpurple/protocols/msn/contact.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/msn/contact.c Fri Oct 12 02:06:38 2007 +0000 @@ -31,8 +31,8 @@ const char *MsnSoapPartnerScenarioText[] = { - "Initial", - "ContactSave", + "Initial", + "ContactSave", "MessengerPendingList", "ContactMsgrAPI", "BlockUnblock" @@ -72,32 +72,23 @@ msn_callback_state_new(void) { return g_new0(MsnCallbackState, 1); -} +} void msn_callback_state_free(MsnCallbackState *state) { if (state == NULL) return; - - if (state->who != NULL) - g_free(state->who); - - if (state->uid != NULL) - g_free(state->uid); - if (state->old_group_name != NULL) - g_free(state->old_group_name); - - if (state->new_group_name != NULL) - g_free(state->new_group_name); - - if (state->guid != NULL) - g_free(state->guid); + g_free(state->who); + g_free(state->uid); + g_free(state->old_group_name); + g_free(state->new_group_name); + g_free(state->guid); g_free(state); } - + void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who) { @@ -107,27 +98,23 @@ if (who != NULL) new_str = g_strdup(who); - - if (state->who != NULL) - g_free(state->who); - + + g_free(state->who); state->who = new_str; } void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid) { - gchar *new_str = NULL; + gchar *new_str = NULL; - g_return_if_fail(state != NULL); + g_return_if_fail(state != NULL); - if (uid != NULL) - new_str = g_strdup(uid); + if (uid != NULL) + new_str = g_strdup(uid); - if (state->uid != NULL) - g_free(state->uid); - - state->uid = new_str; + g_free(state->uid); + state->uid = new_str; } void @@ -140,9 +127,7 @@ if (old_group_name != NULL) new_str = g_strdup(old_group_name); - if (state->old_group_name != NULL) - g_free(state->old_group_name); - + g_free(state->old_group_name); state->old_group_name = new_str; } @@ -156,9 +141,7 @@ if (new_group_name != NULL) new_str = g_strdup(new_group_name); - if (state->new_group_name != NULL) - g_free(state->new_group_name); - + g_free(state->new_group_name); state->new_group_name = new_str; } @@ -171,10 +154,8 @@ if (guid != NULL) new_str = g_strdup(guid); - - if (state->guid != NULL) - g_free(state->guid); - + + g_free(state->guid); state->guid = new_str; } @@ -183,7 +164,7 @@ msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id) { g_return_if_fail(state != NULL); - + state->list_id = list_id; } @@ -191,10 +172,10 @@ msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action) { g_return_if_fail(state != NULL); - + state->action |= action; } - + /*contact SOAP server login error*/ static void msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) @@ -227,9 +208,10 @@ /*get MSN member role utility*/ static MsnListId -msn_get_memberrole(char * role) +msn_get_memberrole(char *role) { - + g_return_val_if_fail(role != NULL, 0); + if (!strcmp(role,"Allow")) { return MSN_LIST_AL; } else if (!strcmp(role,"Block")) { @@ -243,9 +225,11 @@ } /*get User Type*/ -static int -msn_get_user_type(char * type) +static int +msn_get_user_type(char *type) { + g_return_val_if_fail(type != NULL, 0); + if (!strcmp(type,"Regular")) { return MSN_USER_TYPE_PASSPORT; } @@ -327,9 +311,7 @@ xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; xmlnode *node, *body, *response, *result, *services; xmlnode *service, *memberships, *info, *handle, *handletype; - xmlnode *LastChangeNode; xmlnode *membershipnode, *members, *member, *passportNode; - char *LastChangeStr; session = contact->session; node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); @@ -341,8 +323,12 @@ purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len); - purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n",node,node->name,node->child->name,node->lastchild->name); - body = xmlnode_get_child(node,"Body"); + purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node, + node->name ? node->name : "(null)", + (node->child && node->child->name) ? node->child->name : "(null)", + (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); + + body = xmlnode_get_child(node, "Body"); if (body == NULL) { purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n"); @@ -357,20 +343,20 @@ if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { gchar * faultstring = xmlnode_get_data(faultstringnode); - purple_debug_info("MSNCL","Faultstring: %s\n", faultstring); + purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)"); g_free(faultstring); } if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name); if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { - purple_debug_info("MSNCL","errorcode @ %p, name: %s\n",errorcode, errorcode->name); + purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name); if (errorcode->child != NULL) { gchar *errorcodestring = xmlnode_get_data(errorcode); - purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring); + purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); - if ( !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { xmlnode_free(node); g_free(errorcodestring); msn_create_address_book(contact); @@ -418,7 +404,7 @@ for (service = xmlnode_get_child(services, "Service"); service; service = xmlnode_get_next_twin(service)) { purple_debug_info("MSNCL","Service @ %p\n",service); - + if ( (info = xmlnode_get_child(service,"Info")) == NULL ) { purple_debug_error("MSNCL","Error getting 'Info' child node\n"); continue; @@ -434,7 +420,6 @@ if ( (typedata = xmlnode_get_data(handletype)) == NULL) { purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n"); - g_free(typedata); continue; } @@ -447,11 +432,13 @@ } if ( !g_strcasecmp(typedata, "Messenger") ) { + char *LastChangeStr = NULL; + xmlnode *LastChangeNode; /*Last Change Node*/ - LastChangeNode = xmlnode_get_child(service, "LastChange"); - LastChangeStr = xmlnode_get_data(LastChangeNode); - purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr); + if ((LastChangeNode = xmlnode_get_child(service, "LastChange"))) + LastChangeStr = xmlnode_get_data(LastChangeNode); + purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)"); purple_account_set_string(session->account, "CLLastChange", LastChangeStr); g_free(LastChangeStr); @@ -466,35 +453,44 @@ for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; membershipnode = xmlnode_get_next_twin(membershipnode)){ xmlnode *roleNode; - char *role; + char *role = NULL; + list = 0; - roleNode = xmlnode_get_child(membershipnode,"MemberRole"); - role = xmlnode_get_data(roleNode); - list = msn_get_memberrole(role); + if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) { + role = xmlnode_get_data(roleNode); + list = msn_get_memberrole(role); + } list_op = 1 << list; - purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n",role,list_op); - + purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op); + g_free(role); - - members = xmlnode_get_child(membershipnode,"Members"); + + members = xmlnode_get_child(membershipnode, "Members"); for (member = xmlnode_get_child(members, "Member"); member; member = xmlnode_get_next_twin(member)){ MsnUser *user = NULL; - xmlnode *typeNode, *membershipIdNode=NULL; + xmlnode *typeNode, *membershipIdNode = NULL; gchar *type, *membershipId = NULL; + const char *member_type = xmlnode_get_attrib(member, "type"); + + if (!member_type) { + purple_debug_error("msn", "No Member Type specified for Member.\n"); + continue; + } - purple_debug_info("MSNCL","Member type: %s\n", xmlnode_get_attrib(member,"type")); - - if( !g_strcasecmp(xmlnode_get_attrib(member,"type"), "PassportMember") ) { - passportNode = xmlnode_get_child(member,"PassportName"); - passport = xmlnode_get_data(passportNode); - typeNode = xmlnode_get_child(member,"Type"); - type = xmlnode_get_data(typeNode); - purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n",passport,type); + if(!g_strcasecmp(member_type, "PassportMember") ) { + passport = type = NULL; + if ((passportNode = xmlnode_get_child(member, "PassportName"))) + passport = xmlnode_get_data(passportNode); + if ((typeNode = xmlnode_get_child(member, "Type"))) + type = xmlnode_get_data(typeNode); + purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)"); + /* Why do we even bother parsing it just to free it??? */ g_free(type); user = msn_userlist_find_add_user(session->userlist,passport,NULL); + g_free(passport); membershipIdNode = xmlnode_get_child(member,"MembershipId"); if (membershipIdNode != NULL) { @@ -504,23 +500,23 @@ g_free(membershipId); } } - + msn_got_lst_user(session, user, list_op, NULL); - - g_free(passport); } - - if (!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PhoneMember")) { + else if (!g_strcasecmp(member_type, "PhoneMember")) { + purple_debug_info("msn", "Recieved Phone Member; ignoring.\n"); } - - if (!g_strcasecmp(xmlnode_get_attrib(member,"type"),"EmailMember")) { + else if (!g_strcasecmp(member_type, "EmailMember")) { xmlnode *emailNode; + passport = NULL; - emailNode = xmlnode_get_child(member,"Email"); - passport = xmlnode_get_data(emailNode); - purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport, list_op); + if ((emailNode = xmlnode_get_child(member, "Email"))) + passport = xmlnode_get_data(emailNode); + purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op); + user = msn_userlist_find_add_user(session->userlist, passport, NULL); - + g_free(passport); + membershipIdNode = xmlnode_get_child(member,"MembershipId"); if (membershipIdNode != NULL) { membershipId = xmlnode_get_data(membershipIdNode); @@ -529,9 +525,10 @@ g_free(membershipId); } } - + msn_got_lst_user(session, user, list_op, NULL); - g_free(passport); + } else { + purple_debug_info("msn", "Unknown Member type: %s\n", member_type); } } } @@ -600,8 +597,8 @@ msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time) { MsnSoapReq *soap_request; - gchar *body = NULL; - gchar * update_str; + gchar *body; + gchar *update_str = NULL; const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; purple_debug_misc("MSNCL","Getting Contact List.\n"); @@ -609,11 +606,9 @@ if ( update_time != NULL ) { purple_debug_info("MSNCL","Last update time: %s\n",update_time); update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time); - } else { - update_str = g_strdup(""); } - body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str); + body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : ""); g_free(update_str); soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, @@ -639,13 +634,12 @@ for(group = xmlnode_get_child(node, "Group"); group; group = xmlnode_get_next_twin(group)){ xmlnode *groupId, *groupInfo, *groupname; - char *group_id, *group_name; + char *group_id = NULL, *group_name = NULL; - groupId = xmlnode_get_child(group,"groupId"); - group_id = xmlnode_get_data(groupId); - groupInfo = xmlnode_get_child(group,"groupInfo"); - groupname = xmlnode_get_child(groupInfo,"name"); - group_name = xmlnode_get_data(groupname); + if ((groupId = xmlnode_get_child(group, "groupId"))) + group_id = xmlnode_get_data(groupId); + if ((groupInfo = xmlnode_get_child(group, "groupInfo")) && (groupname = xmlnode_get_child(groupInfo, "name"))) + group_name = xmlnode_get_data(groupname); msn_group_new(session->userlist, group_id, group_name); @@ -655,7 +649,7 @@ continue; } - purple_debug_info("MsnAB","group_id: %s, name: %s\n",group_id,group_name); + purple_debug_info("MsnAB","group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)"); if ((purple_find_group(group_name)) == NULL){ PurpleGroup *g = purple_group_new(group_name); purple_blist_add_group(g, NULL); @@ -670,34 +664,40 @@ { MsnSession *session = contact->session; xmlnode *contactNode; + char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL; for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; - contactNode = xmlnode_get_next_twin(contactNode)){ - xmlnode *contactId,*contactInfo,*contactType,*passportName,*displayName,*guid; - xmlnode *groupIds; + contactNode = xmlnode_get_next_twin(contactNode)) { + xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds; MsnUser *user; MsnUserType usertype; - char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL; + + if (!(contactId = xmlnode_get_child(contactNode,"contactId")) + || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo")) + || !(contactType = xmlnode_get_child(contactInfo, "contactType"))) + continue; - contactId= xmlnode_get_child(contactNode,"contactId"); + g_free(passport); + g_free(Name); + g_free(uid); + g_free(type); + passport = Name = uid = type = NULL; + uid = xmlnode_get_data(contactId); - - contactInfo = xmlnode_get_child(contactNode,"contactInfo"); - contactType = xmlnode_get_child(contactInfo,"contactType"); type = xmlnode_get_data(contactType); /*setup the Display Name*/ - if (!strcmp(type, "Me")){ - char *friendly; - friendly = xmlnode_get_data(xmlnode_get_child(contactInfo, "displayName")); - purple_connection_set_display_name(session->account->gc, purple_url_decode(friendly)); + if (type && !strcmp(type, "Me")){ + char *friendly = NULL; + if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) + friendly = xmlnode_get_data(displayName); + purple_connection_set_display_name(session->account->gc, friendly ? purple_url_decode(friendly) : NULL); g_free(friendly); - g_free(uid); - g_free(type); continue; /* Not adding own account as buddy to buddylist */ } + usertype = msn_get_user_type(type); - passportName = xmlnode_get_child(contactInfo,"passportName"); + passportName = xmlnode_get_child(contactInfo, "passportName"); if (passportName == NULL) { xmlnode *emailsNode, *contactEmailNode, *emailNode; xmlnode *messengerEnabledNode; @@ -705,103 +705,93 @@ /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/ /*Yahoo User?*/ - emailsNode = xmlnode_get_child(contactInfo,"emails"); + emailsNode = xmlnode_get_child(contactInfo, "emails"); if (emailsNode == NULL) { /*TODO: need to support the Mobile type*/ - g_free(uid); - g_free(type); continue; } - for(contactEmailNode = xmlnode_get_child(emailsNode,"ContactEmail");contactEmailNode; + for(contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode; contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){ - messengerEnabledNode = xmlnode_get_child(contactEmailNode,"isMessengerEnabled"); - if(messengerEnabledNode == NULL){ - g_free(uid); - g_free(type); + if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) { + /* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */ break; } + msnEnabled = xmlnode_get_data(messengerEnabledNode); - if(!strcmp(msnEnabled,"true")){ - /*Messenger enabled, Get the Passport*/ - emailNode = xmlnode_get_child(contactEmailNode,"email"); + + if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) { + g_free(passport); passport = xmlnode_get_data(emailNode); - purple_debug_info("MsnAB","Yahoo User %s\n",passport); + } + + if(msnEnabled && !strcmp(msnEnabled, "true")) { + /*Messenger enabled, Get the Passport*/ + purple_debug_info("MsnAB", "Yahoo User %s\n", passport ? passport : "(null)"); usertype = MSN_USER_TYPE_YAHOO; - g_free(uid); - g_free(type); - g_free(passport); g_free(msnEnabled); break; - }else{ + } else { /*TODO maybe we can just ignore it in Purple?*/ - emailNode = xmlnode_get_child(contactEmailNode,"email"); - passport = xmlnode_get_data(emailNode); - purple_debug_info("MSNAB","Other type user\n"); + purple_debug_info("MSNAB", "Other type user\n"); } + g_free(msnEnabled); } } else { passport = xmlnode_get_data(passportName); } - if (passport == NULL) { - g_free(uid); - g_free(type); + if (passport == NULL) continue; - } - displayName = xmlnode_get_child(contactInfo,"displayName"); - if (displayName == NULL) { + if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) + Name = xmlnode_get_data(displayName); + else Name = g_strdup(passport); - } else { - Name = xmlnode_get_data(displayName); - } purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n", - passport,uid,Name); + passport, uid ? uid : "(null)", Name ? Name : "(null)"); - user = msn_userlist_find_add_user(session->userlist, passport,Name); - msn_user_set_uid(user,uid); + user = msn_userlist_find_add_user(session->userlist, passport, Name); + msn_user_set_uid(user, uid); msn_user_set_type(user, usertype); - g_free(Name); - g_free(passport); - g_free(uid); - g_free(type); - purple_debug_misc("MsnAB","parse guid...\n"); - groupIds = xmlnode_get_child(contactInfo,"groupIds"); + groupIds = xmlnode_get_child(contactInfo, "groupIds"); if (groupIds) { - for (guid = xmlnode_get_child(groupIds, "guid");guid; + for (guid = xmlnode_get_child(groupIds, "guid"); guid; guid = xmlnode_get_next_twin(guid)){ - char *group_id; - group_id = xmlnode_get_data(guid); - msn_user_add_group_id(user,group_id); - purple_debug_misc("MsnAB","guid:%s\n",group_id); + char *group_id = xmlnode_get_data(guid); + msn_user_add_group_id(user, group_id); + purple_debug_misc("MsnAB", "guid:%s\n", group_id ? group_id : "(null)"); g_free(group_id); } } else { + purple_debug_info("msn", "User not in any groups, adding to default group.\n"); /*not in any group,Then set default group*/ msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID); } msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL); } + + g_free(passport); + g_free(Name); + g_free(uid); + g_free(type); } static gboolean msn_parse_addressbook(MsnContact * contact) { - MsnSession * session; + MsnSession *session; xmlnode * node,*body,*response,*result; xmlnode *groups; - xmlnode *contacts; + xmlnode *contacts; xmlnode *abNode; xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; session = contact->session; - - node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); if ( node == NULL ) { purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len); @@ -810,17 +800,21 @@ purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len); - purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name); - + purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n", node, + node->name ? node->name : "(null)", + (node->child && node->child->name) ? node->child->name : "(null)", + (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); + body = xmlnode_get_child(node,"Body"); purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name); - + + /* TODO: This appears to be used in a number of places and should be de-duplicated */ if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n"); if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { gchar *faultstring = xmlnode_get_data(faultstringnode); - purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring); + purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)"); g_free(faultstring); } if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { @@ -831,9 +825,9 @@ purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name); errorcodestring = xmlnode_get_data(errorcode); - purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring); + purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); - if ( !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { g_free(errorcodestring); xmlnode_free(node); return TRUE; @@ -895,20 +889,20 @@ abNode =xmlnode_get_child(result,"ab"); if(abNode != NULL){ - xmlnode *LastChangeNode, *DynamicItemLastChangedNode; - char *lastchange, *dynamicChange; + xmlnode *node2; + char *tmp = NULL; - LastChangeNode = xmlnode_get_child(abNode,"lastChange"); - lastchange = xmlnode_get_data(LastChangeNode); - purple_debug_info("MsnAB"," lastchanged Time:{%s}\n",lastchange); - purple_account_set_string(session->account, "ablastChange", lastchange); + if ((node2 = xmlnode_get_child(abNode, "lastChange"))) + tmp = xmlnode_get_data(node2); + purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); + purple_account_set_string(session->account, "ablastChange", tmp); - DynamicItemLastChangedNode = xmlnode_get_child(abNode,"DynamicItemLastChanged"); - dynamicChange = xmlnode_get_data(DynamicItemLastChangedNode); - purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n",dynamicChange); - purple_account_set_string(session->account, "DynamicItemLastChanged", lastchange); - g_free(dynamicChange); - g_free(lastchange); + g_free(tmp); tmp = NULL; + if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged"))) + tmp = xmlnode_get_data(node2); + purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)"); + purple_account_set_string(session->account, "DynamicItemLastChanged", tmp); + g_free(tmp); } xmlnode_free(node); @@ -969,27 +963,19 @@ msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange) { MsnSoapReq *soap_request; - char *body = NULL; - char *ab_update_str,*update_str; + char *body; + char *update_str = NULL; purple_debug_misc("MSN AddressBook","Getting Address Book\n"); /*build SOAP and POST it*/ - if ( LastChanged != NULL ) { - ab_update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML,LastChanged); - } else { - ab_update_str = g_strdup(""); - } - if ( dynamicItemLastChange != NULL ) { - update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, - dynamicItemLastChange); - } else { - update_str = g_strdup(ab_update_str); - } - g_free(ab_update_str); - + if (dynamicItemLastChange != NULL) + update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange); + else if (LastChanged != NULL) + update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); - body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str); + + body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : ""); g_free(update_str); soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, @@ -1063,7 +1049,8 @@ MsnSoapReq *soap_request; gchar *body = NULL; gchar *contact_xml = NULL; - gchar *soap_action; + + g_return_if_fail(passport != NULL); /* gchar *escaped_displayname; @@ -1084,11 +1071,10 @@ g_free(contact_xml); /*build SOAP and POST it*/ - soap_action = g_strdup(MSN_CONTACT_ADD_SOAP_ACTION); soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, - soap_action, + MSN_CONTACT_ADD_SOAP_ACTION, body, state, msn_add_contact_read_cb, @@ -1096,7 +1082,6 @@ msn_contact_connect_init); msn_soap_post(contact->soapconn,soap_request); - g_free(soap_action); g_free(body); } @@ -1165,7 +1150,7 @@ MsnSoapReq *soap_request; MsnUserList *userlist; MsnUser *user; - gchar *body = NULL, *soap_action, *contact_xml; + gchar *body = NULL, *contact_xml; g_return_if_fail(passport != NULL); g_return_if_fail(groupId != NULL); @@ -1214,11 +1199,10 @@ g_free(contact_xml); /*build SOAP and POST it*/ - soap_action = g_strdup(MSN_ADD_CONTACT_GROUP_SOAP_ACTION); soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, - soap_action, + MSN_ADD_CONTACT_GROUP_SOAP_ACTION, body, state, msn_add_contact_to_group_read_cb, @@ -1226,7 +1210,6 @@ msn_contact_connect_init); msn_soap_post(contact->soapconn,soap_request); - g_free(soap_action); g_free(body); } @@ -1340,7 +1323,7 @@ MsnUserList * userlist; MsnUser *user; MsnCallbackState *state; - gchar *body = NULL, *soap_action, *contact_id_xml; + gchar *body = NULL, *contact_id_xml; const gchar *groupId; g_return_if_fail(passport != NULL); @@ -1375,25 +1358,22 @@ msn_callback_state_set_who(state, passport); msn_callback_state_set_guid(state, groupId); msn_callback_state_set_old_group_name(state, group_name); - + contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId); g_free(contact_id_xml); - + /*build SOAP and POST it*/ - soap_action = g_strdup(MSN_CONTACT_DEL_GROUP_SOAP_ACTION); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, - soap_action, + MSN_CONTACT_DEL_GROUP_SOAP_ACTION, body, state, msn_del_contact_from_group_read_cb, msn_del_contact_from_group_written_cb, msn_contact_connect_init); msn_soap_post(contact->soapconn,soap_request); - - g_free(soap_action); + g_free(body); } @@ -1422,14 +1402,17 @@ msn_update_contact(MsnContact *contact, const char* nickname) { MsnSoapReq *soap_request; - gchar *body = NULL, *escaped_nickname; + gchar *body, *escaped_nickname; + + /* I'm not sure this is right, but if it isn't, the rest of this function will need to be fixed */ + g_return_if_fail(nickname != NULL); purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname); - + escaped_nickname = g_markup_escape_text(nickname, -1); body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname); - + g_free(escaped_nickname); /*build SOAP and POST it*/ soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
--- a/libpurple/protocols/msn/notification.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Fri Oct 12 02:06:38 2007 +0000 @@ -101,7 +101,8 @@ MsnCmdProc *cmdproc; MsnSession *session; PurpleAccount *account; - char **a, **c, *vers; + GString *vers; + const char *ver_str; int i; g_return_if_fail(servconn != NULL); @@ -110,31 +111,24 @@ session = servconn->session; account = session->account; - /* Allocate an array for CVR0, NULL, and all the versions */ -// a = c = g_new0(char *, session->protocol_ver - WLM_MIN_PROTOCOL + 3); - a = c = g_new0(char *, WLM_MAX_PROTOCOL - WLM_MIN_PROTOCOL + 3); + vers = g_string_new(""); -// for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) +/* for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) */ for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) - *c++ = g_strdup_printf("MSNP%d", i); + g_string_append_printf(vers, " MSNP%d", i); - *c++ = g_strdup("CVR0"); - - vers = g_strjoinv(" ", a); + g_string_append(vers, " CVR0"); if (session->login_step == MSN_LOGIN_STEP_START) - { msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE); - } else - { msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2); - } - msn_cmdproc_send(cmdproc, "VER", "%s", vers); + /* Skip the initial space */ + ver_str = (vers->str + 1); + msn_cmdproc_send(cmdproc, "VER", "%s", ver_str); - g_strfreev(a); - g_free(vers); + g_string_free(vers, TRUE); } gboolean @@ -189,7 +183,7 @@ const char *group_name; group_name = msn_userlist_find_group_name(session->userlist,group_id); reason = g_strdup_printf(_("%s is not a valid group."), - group_name); + group_name ? group_name : ""); } } else @@ -590,57 +584,59 @@ { xmlnode *d_node,*c_node; char **tokens; - char *email,*domain; - char *list_op_str,*type_str; + const char *email,*domain; + char fmt_str[3]; + + g_return_if_fail(passport != NULL); purple_debug_info("MSNP14","Passport: %s, type: %d\n", passport, type); tokens = g_strsplit(passport, "@", 2); email = tokens[0]; domain = tokens[1]; + if (email == NULL || domain == NULL) { + purple_debug_error("msn", "Invalid passport (%s) specified to add to contact xml.\n", passport); + g_strfreev(tokens); + g_return_if_reached(); + } + /*find a domain Node*/ for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node)) { - const char * attr = NULL; - purple_debug_info("MSNP14","d_node: %s\n",d_node->name); - attr = xmlnode_get_attrib(d_node,"n"); - if(attr == NULL){ + const char *attr = xmlnode_get_attrib(d_node,"n"); + if (attr == NULL) continue; - } - if(!strcmp(attr,domain)){ + if (!strcmp(attr,domain)) break; - } } + if(d_node == NULL) { /*domain not found, create a new domain Node*/ - purple_debug_info("MSNP14","get No d_node\n"); + purple_debug_info("msn", "Didn't find existing domain node, adding one.\n"); d_node = xmlnode_new("d"); - xmlnode_set_attrib(d_node,"n",domain); - xmlnode_insert_child(mlNode,d_node); + xmlnode_set_attrib(d_node, "n", domain); + xmlnode_insert_child(mlNode, d_node); } /*create contact node*/ c_node = xmlnode_new("c"); - xmlnode_set_attrib(c_node,"n",email); + xmlnode_set_attrib(c_node, "n", email); - list_op_str = g_strdup_printf("%d",list_op); - purple_debug_info("MSNP14","list_op: %d\n",list_op); - xmlnode_set_attrib(c_node,"l",list_op_str); - g_free(list_op_str); + purple_debug_info("MSNP14", "list_op: %d\n", list_op); + g_snprintf(fmt_str, sizeof(fmt_str), "%d", list_op); + xmlnode_set_attrib(c_node, "l", fmt_str); - if (type != MSN_USER_TYPE_UNKNOWN) { - type_str = g_strdup_printf("%d", type); - } else { - if (msn_user_is_yahoo(session->account, passport)) - type_str = g_strdup_printf("%d", MSN_USER_TYPE_YAHOO); - else - type_str = g_strdup_printf("%d", MSN_USER_TYPE_PASSPORT); - } + if (type != MSN_USER_TYPE_UNKNOWN) + g_snprintf(fmt_str, sizeof(fmt_str), "%d", type); + else if (msn_user_is_yahoo(session->account, passport)) + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_YAHOO); + else + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_PASSPORT); + /*mobile*/ //type_str = g_strdup_printf("4"); - xmlnode_set_attrib(c_node,"t",type_str); - g_free(type_str); + xmlnode_set_attrib(c_node, "t", fmt_str); xmlnode_insert_child(d_node, c_node);
--- a/libpurple/protocols/msn/switchboard.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Fri Oct 12 02:06:38 2007 +0000 @@ -958,25 +958,14 @@ nudge_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { MsnSwitchBoard *swboard; - char *username, *str; PurpleAccount *account; - PurpleBuddy *buddy; const char *user; - str = NULL; - swboard = cmdproc->data; account = cmdproc->session->account; user = msg->remote_user; - if ((buddy = purple_find_buddy(account, user)) != NULL) - username = g_markup_escape_text(purple_buddy_get_alias(buddy), -1); - else - username = g_markup_escape_text(user, -1); - - serv_got_attention(account->gc, buddy->name, MSN_NUDGE); - g_free(username); - g_free(str); + serv_got_attention(account->gc, user, MSN_NUDGE); } /**************************************************************************
--- a/libpurple/protocols/msn/userlist.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Fri Oct 12 02:06:38 2007 +0000 @@ -41,16 +41,20 @@ msn_accept_add_cb(gpointer data) { MsnPermitAdd *pa = data; - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; - MsnUser *user = msn_userlist_find_add_user(userlist, pa->who, pa->who); - + purple_debug_misc("MSN Userlist", "Accepted the new buddy: %s\n", pa->who); - msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); + if (PURPLE_CONNECTION_IS_VALID(pa->gc)) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; + MsnUser *user = msn_userlist_find_add_user(userlist, pa->who, pa->who); - if (msn_userlist_user_is_in_list(user, MSN_LIST_FL)) { - msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL); + + msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_FL)) + msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL); } g_free(pa->who); @@ -63,14 +67,14 @@ { MsnPermitAdd *pa = data; - purple_debug_misc("MSN Userlist", "Deniedthe new buddy: %s\n", pa->who); + purple_debug_misc("MSN Userlist", "Denied the new buddy: %s\n", pa->who); - if (g_list_find(purple_connections_get_all(), pa->gc) != NULL) + if (PURPLE_CONNECTION_IS_VALID(pa->gc)) { MsnSession *session = pa->gc->proto_data; MsnUserList *userlist = session->userlist; MsnCallbackState *state = msn_callback_state_new(); - + msn_callback_state_set_action(state, MSN_DENIED_BUDDY); msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_BL); @@ -85,16 +89,18 @@ static void got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly) { + PurpleAccount *acct; MsnPermitAdd *pa; pa = g_new0(MsnPermitAdd, 1); pa->who = g_strdup(passport); pa->friendly = g_strdup(friendly); pa->gc = gc; - - purple_account_request_authorization(purple_connection_get_account(gc), passport, NULL, friendly, NULL, - purple_find_buddy(purple_connection_get_account(gc), passport) != NULL, - msn_accept_add_cb, msn_cancel_add_cb, pa); + + acct = purple_connection_get_account(gc); + purple_account_request_authorization(acct, passport, NULL, friendly, NULL, + purple_find_buddy(acct, passport) != NULL, + msn_accept_add_cb, msn_cancel_add_cb, pa); }
--- a/libpurple/protocols/myspace/markup.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/myspace/markup.c Fri Oct 12 02:06:38 2007 +0000 @@ -258,8 +258,8 @@ } - *begin = gs_begin->str; - *end = gs_end->str; + *begin = g_string_free(gs_begin, FALSE); + *end = g_string_free(gs_end, FALSE); } /** Convert a msim markup color to a color suitable for libpurple. @@ -444,7 +444,8 @@ *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE); *end = g_strdup("</f>"); } else if (!purple_utf8_strcasecmp(root->name, "a")) { - const gchar *href, *link_text; + const gchar *href; + gchar *link_text; href = xmlnode_get_attrib(root, "href"); @@ -476,6 +477,7 @@ /* Sorry, kid. MySpace doesn't support you within <a> tags. */ xmlnode_free(root->child); + g_free(link_text); root->child = NULL; *end = g_strdup(""); @@ -568,10 +570,7 @@ case XMLNODE_TYPE_DATA: /* Literal text. */ - inner = g_new0(char, node->data_sz + 1); - strncpy(inner, node->data, node->data_sz); - inner[node->data_sz] = 0; - + inner = g_strndup(node->data, node->data_sz); purple_debug_info("msim", " ** node data=%s\n", inner ? inner : "(NULL)"); break; @@ -584,6 +583,8 @@ if (inner) { g_string_append(final, inner); + g_free(inner); + inner = NULL; } } @@ -593,10 +594,13 @@ * Comment out this line below to see. */ g_string_append(final, end); + g_free(begin); + g_free(end); + purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n", (final && final->str) ? final->str : "(NULL)"); - return final->str; + return g_string_free(final, FALSE); } /** Convert XML to something based on MSIM_XMLNODE_CONVERT. */
--- a/libpurple/protocols/myspace/message.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/myspace/message.c Fri Oct 12 02:06:38 2007 +0000 @@ -80,7 +80,7 @@ purple_debug_info("msim", "msim_escape: msg=%s, ret=%s\n", msg, gs->str); #endif - return gs->str; + return g_string_free(gs, FALSE); } /** @@ -120,7 +120,7 @@ purple_debug_info("msim", "msim_unescape: msg=%s, ret=%s\n", msg, gs->str); #endif - return gs->str; + return g_string_free(gs, FALSE); } /** Create a new MsimMessage. @@ -691,7 +691,7 @@ ++i; } - string = gs->str; + string = g_string_free(gs, FALSE); break; default: @@ -798,7 +798,7 @@ g_string_append(gs, "|"); } - return gs->str; + return g_string_free(gs, FALSE); default: purple_debug_info("msim", "field %s, unknown type %d\n", @@ -1337,9 +1337,7 @@ gs = (GString *)elem->data; /* Duplicate data, so caller can g_free() it. */ - *binary_data = g_new0(char, gs->len); - memcpy(*binary_data, gs->str, gs->len); - + *binary_data = g_memdup(gs->str, gs->len); *binary_length = gs->len; return TRUE;
--- a/libpurple/protocols/myspace/myspace.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Fri Oct 12 02:06:38 2007 +0000 @@ -43,7 +43,7 @@ static int msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes); static gboolean msim_login_challenge(MsimSession *session, MsimMessage *msg); -static const gchar *msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], const gchar *email, const gchar *password, guint *response_len); +static gchar *msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], const gchar *email, const gchar *password, guint *response_len); static gboolean msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg); static gboolean msim_incoming_bm(MsimSession *session, MsimMessage *msg); @@ -289,7 +289,7 @@ (int)strlen(acct->password)); /* Notify an error message also, because this is important! */ - purple_notify_error(acct, g_strdup(_("MySpaceIM Error")), str, NULL); + purple_notify_error(acct, _("MySpaceIM Error"), str, NULL); gc->wants_to_die = TRUE; purple_connection_error(gc, str); @@ -332,10 +332,11 @@ msim_login_challenge(MsimSession *session, MsimMessage *msg) { PurpleAccount *account; - const gchar *response; + gchar *response; guint response_len; gchar *nc; gsize nc_len; + gboolean ret; g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); g_return_val_if_fail(msg != NULL, FALSE); @@ -363,11 +364,11 @@ g_free(nc); - return msim_send(session, + ret = msim_send(session, "login2", MSIM_TYPE_INTEGER, MSIM_AUTH_ALGORITHM, /* This is actually user's email address. */ "username", MSIM_TYPE_STRING, g_strdup(account->username), - /* GString and gchar * response will be freed in msim_msg_free() in msim_send(). */ + /* GString will be freed in msim_msg_free() in msim_send(). */ "response", MSIM_TYPE_BINARY, g_string_new_len(response, response_len), "clientver", MSIM_TYPE_INTEGER, MSIM_CLIENT_VERSION, "langid", MSIM_TYPE_INTEGER, MSIM_LANGUAGE_ID_ENGLISH, @@ -376,6 +377,10 @@ "status", MSIM_TYPE_INTEGER, 100, "id", MSIM_TYPE_INTEGER, 1, NULL); + + g_free(response); + + return ret; } /** @@ -389,7 +394,7 @@ * @return Binary login challenge response, ready to send to the server. * Must be g_free()'d when finished. NULL if error. */ -static const gchar * +static gchar * msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE], const gchar *email, const gchar *password, guint *response_len) { @@ -487,8 +492,13 @@ purple_cipher_context_encrypt(rc4, (const guchar *)data, data_len, data_out, &data_out_len); purple_cipher_context_destroy(rc4); - - g_assert(data_out_len == data_len); + g_free(data); + + if (data_out_len != data_len) { + purple_debug_info("msim", "msim_compute_login_response: " + "data length mismatch: %d != %d\n", + data_out_len, data_len); + } #ifdef MSIM_DEBUG_LOGIN_CHALLENGE purple_debug_info("msim", "response=<%s>\n", data_out); @@ -496,7 +506,7 @@ *response_len = data_out_len; - return (const gchar *)data_out; + return (gchar *)data_out; } /** @@ -626,6 +636,7 @@ g_return_val_if_fail(username != NULL, FALSE); if (!cv) { /* No client version to record, don't worry about it. */ + g_free(username); return FALSE; } @@ -815,6 +826,7 @@ serv_got_typing_stopped(session->gc, username); g_free(username); + g_free(text); return TRUE; } @@ -963,7 +975,6 @@ purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username); purple_notify_user_info_destroy(user_info); - /* TODO: do not free username, since it will be used by user_info? */ if (temporary_user) { g_free(user->client_info); @@ -977,7 +988,7 @@ g_free(user->image_url); g_free(user); } - + g_free(username); } /** Retrieve a user's profile. @@ -1156,7 +1167,7 @@ /* TODO: more elegant solution than below. attach whole message? */ /* Special elements name beginning with '_', we'll use internally within the * program (did not come directly from the wire). */ - msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); + msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */ /* TODO: attach more useful information, like ImageURL */ @@ -1297,7 +1308,6 @@ msim_check_inbox_cb(MsimSession *session, MsimMessage *reply, gpointer data) { MsimMessage *body; - GString *notification; guint old_inbox_status; guint i, n; const gchar *froms[5], *tos[5], *urls[5], *subjects[5]; @@ -1331,8 +1341,6 @@ body = msim_msg_get_dictionary(reply, "body"); g_return_if_fail(body != NULL); - notification = g_string_new(""); - old_inbox_status = session->inbox_status; n = 0; @@ -1795,8 +1803,7 @@ } purple_connection_error(session->gc, full_errmsg); } else { - purple_notify_error(session->account, g_strdup(_("MySpaceIM Error")), - full_errmsg, NULL); + purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL); } g_free(full_errmsg); @@ -2667,6 +2674,7 @@ /* TODO: other fields, store in 'user' */ msim_msg_free(contact_info); + g_free(username); } /** Add first ContactID in contact_info to buddy's list. Used to add @@ -3009,7 +3017,7 @@ msg = msim_msg_new(NULL); /* Create a new, empty message. */ /* Append some new elements. */ - msg = msim_msg_append(msg, "bx", MSIM_TYPE_BINARY, g_string_new_len(g_strdup("XXX"), 3)); + msg = msim_msg_append(msg, "bx", MSIM_TYPE_BINARY, g_string_new_len("XXX", 3)); msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v1")); msg = msim_msg_append(msg, "k1", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(42)); msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v43"));
--- a/libpurple/protocols/myspace/user.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/myspace/user.c Fri Oct 12 02:06:38 2007 +0000 @@ -30,10 +30,10 @@ static gchar * msim_format_now_playing(gchar *band, gchar *song) { - if ((band && strlen(band)) || (song && strlen(song))) { + if ((band && *band) || (song && *song)) { return g_strdup_printf("%s - %s", - (band && strlen(band)) ? band : "Unknown Artist", - (song && strlen(song)) ? song : "Unknown Song"); + (band && *band) ? band : "Unknown Artist", + (song && *song) ? song : "Unknown Song"); } else { return NULL; } @@ -99,58 +99,63 @@ if (full) { /* TODO: link to username, if available */ - purple_notify_user_info_add_pair(user_info, _("Profile"), - g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>", - uid, uid)); + char *profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>", + uid, uid); + purple_notify_user_info_add_pair(user_info, _("Profile"), profile); + g_free(profile); } /* a/s/l...the vitals */ if (user->age) { - purple_notify_user_info_add_pair(user_info, _("Age"), - g_strdup_printf("%d", user->age)); + char age[16]; + g_snprintf(age, sizeof(age), "%d", user->age); + purple_notify_user_info_add_pair(user_info, _("Age"), age); } - if (user->gender && strlen(user->gender)) { + if (user->gender && *user->gender) { purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender); } - if (user->location && strlen(user->location)) { + if (user->location && *user->location) { purple_notify_user_info_add_pair(user_info, _("Location"), user->location); } /* Other information */ - if (user->headline && strlen(user->headline)) { + if (user->headline && *user->headline) { purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline); } str = msim_format_now_playing(user->band_name, user->song_name); - if (str && strlen(str)) { + if (str && *str) { purple_notify_user_info_add_pair(user_info, _("Song"), str); } + g_free(str); /* Note: total friends only available if looked up by uid, not username. */ if (user->total_friends) { - purple_notify_user_info_add_pair(user_info, _("Total Friends"), - g_strdup_printf("%d", user->total_friends)); + char friends[16]; + g_snprintf(friends, sizeof(friends), "%d", user->total_friends); + purple_notify_user_info_add_pair(user_info, _("Total Friends"), friends); } if (full) { /* Client information */ + char *client = NULL; str = user->client_info; cv = user->client_cv; if (str && cv != 0) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup_printf("%s (build %d)", str, cv)); + client = g_strdup_printf("%s (build %d)", str, cv); } else if (str) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup(str)); + client = g_strdup(str); } else if (cv) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup_printf("Build %d", cv)); + client = g_strdup_printf("Build %d", cv); } + if (client && *client) + purple_notify_user_info_add_pair(user_info, _("Client Version"), client); + g_free(client); } }
--- a/libpurple/protocols/myspace/zap.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/myspace/zap.c Fri Oct 12 02:06:38 2007 +0000 @@ -41,15 +41,52 @@ types = g_list_append(types, attn); /* TODO: icons for each zap */ + + /* Lots of comments for translators: */ + + /* Zap means "to strike suddenly and forcefully as if with a + * projectile or weapon." This term often has an electrical + * connotation, for example, "he was zapped by electricity when + * he put a fork in the toaster." */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s...")); + + /* Whack means "to hit or strike someone with a sharp blow" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s...")); + + /* Torch means "to set on fire." Don't worry, this doesn't + * make a whole lot of sense in English, either. Feel free + * to translate it literally. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s...")); + + /* Smooch means "to kiss someone, often enthusiastically" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s...")); + + /* A hug is a display of affection; wrapping your arms around someone */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s...")); + + /* Slap means "to hit someone with an open/flat hand" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s...")); + + /* Goose means "to pinch someone on their butt" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s...")); + + /* A high-five is when two people's hands slap each other + * in the air above their heads. It is done to celebrate + * something, often a victory, or to congratulate someone. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s...")); + + /* We're not entirely sure what the MySpace people mean by + * this... but we think it's the equivalent of "prank." Or, for + * someone to perform a mischievous trick or practical joke. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s...")); + + /* Raspberry is a slang term for the vibrating sound made + * when you stick your tongue out of your mouth with your + * lips closed and blow. It is typically done when + * gloating or bragging. Nowadays it's a pretty silly + * gesture, so it does not carry a harsh negative + * connotation. It is generally used in a playful tone + * with friends. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s...")); }
--- a/libpurple/protocols/oscar/family_auth.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/oscar/family_auth.c Fri Oct 12 02:06:38 2007 +0000 @@ -438,10 +438,6 @@ * login request instead of the normal SNAC one. * * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/. - * - * XXX This may cause problems if the client relies on callbacks only - * being called from the context of aim_rxdispatch()... - * */ static int goddamnicq(OscarData *od, FlapConnection *conn, const char *sn)
--- a/libpurple/protocols/oscar/odc.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/oscar/odc.c Fri Oct 12 02:06:38 2007 +0000 @@ -27,6 +27,8 @@ #include "imgstore.h" #include "util.h" +#define DIRECTIM_MAX_FILESIZE 52428800 + /** * Free any ODC related data and print a message to the conversation * window based on conn->disconnect_reason. @@ -587,6 +589,27 @@ if (frame->payload.len > 0) { + if (frame->payload.len > DIRECTIM_MAX_FILESIZE) + { + gchar *tmp, *size1, *size2; + PurpleAccount *account; + PurpleConversation *conv; + + size1 = purple_str_size_to_units(frame->payload.len); + size2 = purple_str_size_to_units(DIRECTIM_MAX_FILESIZE); + tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM. Try using file transfer instead.\n"), conn->sn, size1, size2); + g_free(size1); + g_free(size2); + + account = purple_connection_get_account(conn->od->gc); + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + + peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL); + return; + } + /* We have payload data! Switch to the ODC watcher to read it. */ frame->payload.data = g_new(guint8, frame->payload.len); frame->payload.offset = 0;
--- a/libpurple/protocols/oscar/oscar.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Fri Oct 12 02:06:38 2007 +0000 @@ -1873,6 +1873,10 @@ saved_b16 = purple_buddy_icons_get_checksum_for_user(b); if (!b16 || !saved_b16 || strcmp(b16, saved_b16)) { + /* Invalidate the old icon for this user */ + purple_buddy_icons_set_for_user(account, info->sn, NULL, 0, NULL); + + /* Fetch the new icon (if we're not already doing so) */ if (g_slist_find_custom(od->requesticon, info->sn, (GCompareFunc)aim_sncmp) == NULL) { @@ -2180,12 +2184,14 @@ { PurpleConnection *gc; OscarData *od; + PurpleAccount *account; PurpleBuddy *buddy; PurpleGroup *group; gc = data->gc; od = gc->proto_data; - buddy = purple_find_buddy(purple_connection_get_account(gc), data->name); + account = purple_connection_get_account(gc); + buddy = purple_find_buddy(account, data->name); if (buddy != NULL) group = purple_buddy_get_group(buddy); else @@ -2197,7 +2203,19 @@ buddy->name, group->name); aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); if (!aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY)) + { aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); + + /* Mobile users should always be online */ + if (buddy->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_MOBILE, NULL); + } + } } } @@ -4617,12 +4635,16 @@ void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { - OscarData *od = (OscarData *)gc->proto_data; + OscarData *od; + PurpleAccount *account; + + od = (OscarData *)gc->proto_data; + account = purple_connection_get_account(gc); if (!aim_snvalid(buddy->name)) { gchar *buf; buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid. Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name); - if (!purple_conv_present_error(buddy->name, purple_connection_get_account(gc), buf)) + if (!purple_conv_present_error(buddy->name, account, buf)) purple_notify_error(gc, NULL, _("Unable To Add"), buf); g_free(buf); @@ -4636,6 +4658,16 @@ purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", buddy->name, group->name); aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); + + /* Mobile users should always be online */ + if (buddy->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_MOBILE, NULL); + } } /* XXX - Should this be done from AIM accounts, as well? */ @@ -4951,6 +4983,17 @@ g_free(comment); } } + + /* Mobile users should always be online */ + if (b->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_MOBILE, NULL); + } + g_free(gname_utf8); g_free(alias_utf8); } @@ -5141,6 +5184,17 @@ purple_debug_info("oscar", "ssi: adding buddy %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans")); purple_blist_add_buddy(b, NULL, g, NULL); + + /* Mobile users should always be online */ + if (b->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_MOBILE, NULL); + } + } g_free(gname_utf8);
--- a/libpurple/protocols/yahoo/yahoo.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Fri Oct 12 02:06:38 2007 +0000 @@ -862,10 +862,13 @@ /* If a Doodle session doesn't exist between this user */ if(wb == NULL) { + doodle_session *ds; wb = purple_whiteboard_create(gc->account, im->from, DOODLE_STATE_REQUESTED); - - yahoo_doodle_command_send_request(gc, im->from); - yahoo_doodle_command_send_ready(gc, im->from); + ds = wb->proto_data; + ds->imv_key = g_strdup(imv); + + yahoo_doodle_command_send_request(gc, im->from, imv); + yahoo_doodle_command_send_ready(gc, im->from, imv); } } }
--- a/libpurple/protocols/yahoo/yahoo_doodle.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_doodle.c Fri Oct 12 02:06:38 2007 +0000 @@ -118,19 +118,19 @@ /* Insert this 'session' in the list. At this point, it's only a * requested session. */ - purple_whiteboard_create(account, to, DOODLE_STATE_REQUESTING); + wb = purple_whiteboard_create(account, to, DOODLE_STATE_REQUESTING); } /* NOTE Perhaps some careful handling of remote assumed established * sessions */ - yahoo_doodle_command_send_ready(gc, to); - yahoo_doodle_command_send_request(gc, to); + yahoo_doodle_command_send_ready(gc, to, DOODLE_IMV_KEY); + yahoo_doodle_command_send_request(gc, to, DOODLE_IMV_KEY); } -static void yahoo_doodle_command_got_request(PurpleConnection *gc, const char *from) +static void yahoo_doodle_command_got_request(PurpleConnection *gc, const char *from, const char *imv_key) { PurpleAccount *account; PurpleWhiteboard *wb; @@ -147,6 +147,7 @@ /* If a session with the remote user doesn't exist */ if(wb == NULL) { + doodle_session *ds; /* Ask user if they wish to accept the request for a doodle session */ /* TODO Ask local user to start Doodle session with remote user */ /* NOTE This if/else statement won't work right--must use dialog @@ -160,9 +161,11 @@ dialog_message, NULL, NULL, NULL); */ - purple_whiteboard_create(account, from, DOODLE_STATE_REQUESTED); + wb = purple_whiteboard_create(account, from, DOODLE_STATE_REQUESTED); + ds = wb->proto_data; + ds->imv_key = g_strdup(imv_key); - yahoo_doodle_command_send_ready(gc, from); + yahoo_doodle_command_send_ready(gc, from, imv_key); } /* TODO Might be required to clear the canvas of an existing doodle @@ -170,7 +173,7 @@ */ } -static void yahoo_doodle_command_got_ready(PurpleConnection *gc, const char *from) +static void yahoo_doodle_command_got_ready(PurpleConnection *gc, const char *from, const char *imv_key) { PurpleAccount *account; PurpleWhiteboard *wb; @@ -189,11 +192,15 @@ if(wb->state == DOODLE_STATE_REQUESTING) { + doodle_session *ds = wb->proto_data; purple_whiteboard_start(wb); wb->state = DOODLE_STATE_ESTABLISHED; - yahoo_doodle_command_send_confirm(gc, from); + yahoo_doodle_command_send_confirm(gc, from, imv_key); + /* Let's steal the imv_key and reuse it */ + g_free(ds->imv_key); + ds->imv_key = g_strdup(imv_key); } else if(wb->state == DOODLE_STATE_ESTABLISHED) { @@ -208,7 +215,7 @@ else if(wb->state == DOODLE_STATE_REQUESTED) { /* purple_whiteboard_start(wb); */ - yahoo_doodle_command_send_ready(gc, from); + yahoo_doodle_command_send_ready(gc, from, imv_key); } } @@ -296,14 +303,14 @@ static void -yahoo_doodle_command_got_extra(PurpleConnection *gc, const char *from, const char *message) +yahoo_doodle_command_got_extra(PurpleConnection *gc, const char *from, const char *message, const char *imv_key) { purple_debug_info("yahoo", "doodle: Got Extra (%s)\n", from); /* I do not like these 'extra' features, so I'll only handle them in one * way, which is returning them with the command/packet to turn them off */ - yahoo_doodle_command_send_extra(gc, from, DOODLE_EXTRA_NONE); + yahoo_doodle_command_send_extra(gc, from, DOODLE_EXTRA_NONE, imv_key); } static void yahoo_doodle_command_got_confirm(PurpleConnection *gc, const char *from) @@ -399,34 +406,34 @@ yahoo_packet_send_and_free(pkt, yd); } -void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to) +void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to, const char *imv_key) { - yahoo_doodle_command_send_generic("Ready", gc, to, "1", DOODLE_CMD_READY, NULL, "1"); + yahoo_doodle_command_send_generic("Ready", gc, to, "1", DOODLE_CMD_READY, imv_key, "1"); } -void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to) +void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to, const char *imv_key) { - yahoo_doodle_command_send_generic("Request", gc, to, "", DOODLE_CMD_REQUEST, NULL, "0"); + yahoo_doodle_command_send_generic("Request", gc, to, "", DOODLE_CMD_REQUEST, imv_key, "0"); } -void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message) +void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message, const char *imv_key) { - yahoo_doodle_command_send_generic("Draw", gc, to, message, DOODLE_CMD_DRAW, NULL, "1"); + yahoo_doodle_command_send_generic("Draw", gc, to, message, DOODLE_CMD_DRAW, imv_key, "1"); } -void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to) +void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to, const char *imv_key) { - yahoo_doodle_command_send_generic("Clear", gc, to, " ", DOODLE_CMD_CLEAR, NULL, "1"); + yahoo_doodle_command_send_generic("Clear", gc, to, " ", DOODLE_CMD_CLEAR, imv_key, "1"); } -void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message) +void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message, const char *imv_key) { - yahoo_doodle_command_send_generic("Extra", gc, to, message, DOODLE_CMD_EXTRA, NULL, "1"); + yahoo_doodle_command_send_generic("Extra", gc, to, message, DOODLE_CMD_EXTRA, imv_key, "1"); } -void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to) +void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to, const char *imv_key) { - yahoo_doodle_command_send_generic("Confirm", gc, to, "1", DOODLE_CMD_CONFIRM, NULL, "1"); + yahoo_doodle_command_send_generic("Confirm", gc, to, "1", DOODLE_CMD_CONFIRM, imv_key, "1"); } void yahoo_doodle_command_send_shutdown(PurpleConnection *gc, const char *to) @@ -450,12 +457,14 @@ void yahoo_doodle_end(PurpleWhiteboard *wb) { PurpleConnection *gc = purple_account_get_connection(wb->account); + doodle_session *ds = wb->proto_data; /* g_debug_debug("yahoo", "doodle: yahoo_doodle_end()\n"); */ if (gc && wb->state != DOODLE_STATE_CANCELED) yahoo_doodle_command_send_shutdown(gc, wb->who); + g_free(ds->imv_key); g_free(wb->proto_data); } @@ -492,13 +501,14 @@ g_return_if_fail(draw_list != NULL); message = yahoo_doodle_build_draw_string(ds, draw_list); - yahoo_doodle_command_send_draw(wb->account->gc, wb->who, message); + yahoo_doodle_command_send_draw(wb->account->gc, wb->who, message, ds->imv_key); g_free(message); } void yahoo_doodle_clear(PurpleWhiteboard *wb) { - yahoo_doodle_command_send_clear(wb->account->gc, wb->who); + doodle_session *ds = wb->proto_data; + yahoo_doodle_command_send_clear(wb->account->gc, wb->who, ds->imv_key); } @@ -551,14 +561,14 @@ void yahoo_doodle_get_brush(const PurpleWhiteboard *wb, int *size, int *color) { - doodle_session *ds = (doodle_session *)wb->proto_data; + doodle_session *ds = wb->proto_data; *size = ds->brush_size; *color = ds->brush_color; } void yahoo_doodle_set_brush(PurpleWhiteboard *wb, int size, int color) { - doodle_session *ds = (doodle_session *)wb->proto_data; + doodle_session *ds = wb->proto_data; ds->brush_size = size; ds->brush_color = color; @@ -567,7 +577,7 @@ } void yahoo_doodle_process(PurpleConnection *gc, const char *me, const char *from, - const char *command, const char *message) + const char *command, const char *message, const char *imv_key) { if(!command) return; @@ -576,11 +586,11 @@ switch(atoi(command)) { case DOODLE_CMD_REQUEST: - yahoo_doodle_command_got_request(gc, from); + yahoo_doodle_command_got_request(gc, from, imv_key); break; case DOODLE_CMD_READY: - yahoo_doodle_command_got_ready(gc, from); + yahoo_doodle_command_got_ready(gc, from, imv_key); break; case DOODLE_CMD_CLEAR: @@ -592,7 +602,7 @@ break; case DOODLE_CMD_EXTRA: - yahoo_doodle_command_got_extra(gc, from, message); + yahoo_doodle_command_got_extra(gc, from, message, imv_key); break; case DOODLE_CMD_CONFIRM:
--- a/libpurple/protocols/yahoo/yahoo_doodle.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_doodle.h Fri Oct 12 02:06:38 2007 +0000 @@ -31,7 +31,7 @@ #include "whiteboard.h" #include "cmds.h" -#define DOODLE_IMV_KEY "doodle;103" +#define DOODLE_IMV_KEY "doodle;106" /****************************************************************************** * Defines @@ -94,6 +94,7 @@ { int brush_size; /* Size of drawing brush */ int brush_color; /* Color of drawing brush */ + gchar *imv_key; } doodle_session; /****************************************************************************** @@ -104,17 +105,17 @@ char **error, void *data); void yahoo_doodle_process(PurpleConnection *gc, const char *me, const char *from, - const char *command, const char *message); + const char *command, const char *message, const char *imv_key); void yahoo_doodle_initiate(PurpleConnection *gc, const char *to); void yahoo_doodle_command_got_shutdown(PurpleConnection *gc, const char *from); -void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to); -void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to); -void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message); -void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to); -void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message); -void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to); +void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to, const char *imv_key); +void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to, const char *imv_key); +void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message, const char *imv_key); +void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to, const char *imv_key); +void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message, const char *imv_key); +void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to, const char *imv_key); void yahoo_doodle_command_send_shutdown(PurpleConnection *gc, const char *to); void yahoo_doodle_start(PurpleWhiteboard *wb);
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Fri Oct 12 02:06:38 2007 +0000 @@ -452,26 +452,29 @@ { struct yahoo_pair *pair = l->data; - if(pair->key == 5) /* Get who the packet is for */ + switch(pair->key) { + case 5: /* Get who the packet is for */ me = pair->value; - - if(pair->key == 4) /* Get who the packet is from */ + break; + case 4: /* Get who the packet is from */ from = pair->value; - - if(pair->key == 49) /* Get the type of service */ + break; + case 49: /* Get the type of service */ service = pair->value; - - if(pair->key == 14) /* Get the 'message' of the packet */ + break; + case 14: /* Get the 'message' of the packet */ message = pair->value; - - if(pair->key == 13) /* Get the command associated with this packet */ + break; + case 13: /* Get the command associated with this packet */ command = pair->value; - - if(pair->key == 63) /* IMVironment name and version */ + break; + case 63: /* IMVironment name and version */ imv = pair->value; - - if(pair->key == 64) /* Not sure, but it does vary with initialization of Doodle */ + break; + case 64: /* Not sure, but it does vary with initialization of Doodle */ unknown = pair->value; /* So, I'll keep it (for a little while atleast) */ + break; + } l = l->next; } @@ -481,7 +484,7 @@ { /* Check for a Doodle packet and handle it accordingly */ if(strstr(imv, "doodle;") != NULL) - yahoo_doodle_process(gc, me, from, command, message); + yahoo_doodle_process(gc, me, from, command, message, imv); /* If an IMVIRONMENT packet comes without a specific imviroment name */ if(!strcmp(imv, ";0")) @@ -513,24 +516,35 @@ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - if (pair->key == 4) + switch (pair->key) { + case 4: from = pair->value; - if (pair->key == 5) + break; + case 5: to = pair->value; - if (pair->key == 14) + break; + case 14: msg = pair->value; - if (pair->key == 20) + break; + case 20: url = pair->value; - if (pair->key == 38) + break; + case 38: expires = strtol(pair->value, NULL, 10); - if (pair->key == 27) + break; + case 27: filename = pair->value; - if (pair->key == 28) + break; + case 28: filesize = atol(pair->value); - if (pair->key == 49) + break; + case 49: service = pair->value; - if (pair->key == 63) + break; + case 63: imv = pair->value; + break; + } } /*
--- a/libpurple/purple-remote Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/purple-remote Fri Oct 12 02:06:38 2007 +0000 @@ -9,7 +9,12 @@ xml.dom.minidom.Element.all = xml.dom.minidom.Element.getElementsByTagName -obj = dbus.SessionBus().get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject") +obj = None +try: + obj = dbus.SessionBus().get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject") +except: + pass + purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface") class CheckedObject: @@ -212,7 +217,10 @@ if len(sys.argv) == 1: show_help() - +elif (obj == None): + print "No existing libpurple instance detected." + sys.exit(1); + for arg in sys.argv[1:]: output = execute(arg)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/purple.h Fri Oct 12 02:06:38 2007 +0000 @@ -0,0 +1,92 @@ +/** + * @file purple.h Header files and defines + * This file contains all the necessary preprocessor directives to include + * libpurple's headers and other preprocessor directives required for plugins + * or UIs to build. Inlcuding this file eliminates the need to directly + * include any other libpurple files. It will still be necessary for plugins + * to define @c PURPLE_PLUGINS before including this header. + * + * @ingroup core libpurple + */ + +/* purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + */ +#ifndef _PURPLE_H +#define _PURPLE_H + +#ifndef G_GNUC_NULL_TERMINATED +# if __GNUC__ >= 4 +# define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) +# else +# define G_GNUC_NULL_TERMINATED +# endif +#endif + +#include <account.h> +#include <accountopt.h> +#include <blist.h> +#include <buddyicon.h> +#include <certificate.h> +#include <cipher.h> +#include <circbuffer.h> +#include <cmds.h> +#include <connection.h> +#include <conversation.h> +#include <core.h> +#include <debug.h> +#include <desktopitem.h> +#include <dnsquery.h> +#include <dnssrv.h> +#include <eventloop.h> +#include <ft.h> +#include <idle.h> +#include <imgstore.h> +#include <log.h> +#include <mime.h> +#include <nat-pmp.h> +#include <network.h> +#include <ntlm.h> +#include <notify.h> +#include <plugin.h> +#include <pluginpref.h> +#include <pounce.h> +#include <prefs.h> +#include <privacy.h> +#include <proxy.h> +#include <prpl.h> +#include <request.h> +#include <roomlist.h> +#include <savedstatuses.h> +#include <server.h> +#include <signals.h> +#include <status.h> +#include <stringref.h> +#include <stun.h> +#include <sound.h> +#include <sslconn.h> +#include <upnp.h> +#include <util.h> +#include <value.h> +#include <version.h> +#include <xmlnode.h> +#include <whiteboard.h> + +#endif
--- a/libpurple/request.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/request.c Fri Oct 12 02:06:38 2007 +0000 @@ -377,6 +377,13 @@ g_hash_table_destroy(field->u.list.item_data); g_hash_table_destroy(field->u.list.selected_table); } + else if (field->type == PURPLE_REQUEST_FIELD_BLIST) + { + if (field->u.blist.default_nodes) + g_list_free(field->u.blist.default_nodes); + if (field->u.blist.selecteds) + g_list_free(field->u.blist.selecteds); + } g_free(field); } @@ -1133,6 +1140,85 @@ /* -- */ +PurpleRequestField *purple_request_field_blist_nodes_new(const char *id, + const char *text, PurpleRequestBlistFlags flags, GList *selected) +{ + PurpleRequestField *field; + + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(text != NULL, NULL); + + field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_BLIST); + + field->u.blist.flags = flags; + field->u.blist.default_nodes = selected; + purple_request_field_blist_set_selection_list(field, selected); + + return field; +} + +PurpleFilterBlistFunc +purple_request_field_blist_set_filter(PurpleRequestField *field, PurpleFilterBlistFunc filter) +{ + PurpleFilterBlistFunc old; + g_return_val_if_fail(field != NULL, NULL); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST, NULL); + old = field->u.blist.filter; + field->u.blist.filter = filter; + return old; +} + +PurpleFilterBlistFunc +purple_request_field_blist_get_filter(const PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, NULL); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST, NULL); + return field->u.blist.filter; +} + +GList *purple_request_field_blist_get_selection_list(const PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, NULL); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST, NULL); + return field->u.blist.selecteds; +} + +gboolean purple_request_field_blist_add(PurpleRequestField *field, PurpleBlistNode *node) +{ + g_return_val_if_fail(field != NULL, FALSE); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST, FALSE); + if (!g_list_find(field->u.blist.selecteds, node)) { + field->u.blist.selecteds = g_list_append(field->u.blist.selecteds, node); + return TRUE; + } else { + return FALSE; + } +} + +gboolean purple_request_field_blist_remove(PurpleRequestField *field, PurpleBlistNode *node) +{ + GList *search; + g_return_val_if_fail(field != NULL, FALSE); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST, FALSE); + if ((search = g_list_find(field->u.blist.selecteds, node)) != NULL) { + field->u.blist.selecteds = g_list_delete_link(field->u.blist.selecteds, search); + return TRUE; + } else { + return FALSE; + } +} + +void purple_request_field_blist_set_selection_list(PurpleRequestField *field, GList *selecteds) +{ + g_return_if_fail(field != NULL); + g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_BLIST); + if (field->u.blist.selecteds) + g_list_free(field->u.blist.selecteds); + field->u.blist.selecteds = selecteds; +} + +/* -- */ + void * purple_request_input(void *handle, const char *title, const char *primary, const char *secondary, const char *default_value,
--- a/libpurple/request.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/request.h Fri Oct 12 02:06:38 2007 +0000 @@ -61,7 +61,8 @@ PURPLE_REQUEST_FIELD_LIST, PURPLE_REQUEST_FIELD_LABEL, PURPLE_REQUEST_FIELD_IMAGE, - PURPLE_REQUEST_FIELD_ACCOUNT + PURPLE_REQUEST_FIELD_ACCOUNT, + PURPLE_REQUEST_FIELD_BLIST, } PurpleRequestFieldType; @@ -94,6 +95,17 @@ } PurpleRequestFieldGroup; /** + * Flags that can be used for Buddylist Fields. + */ +typedef enum +{ + PURPLE_REQUEST_BLIST_FLAG_BUDDY = 0x01, /**< Include buddies in the list. */ + PURPLE_REQUEST_BLIST_FLAG_CHAT = 0x02, /**< Include chats in the list. */ + PURPLE_REQUEST_BLIST_FLAG_GROUP = 0x04, /**< Include groups in the list. */ + PURPLE_REQUEST_BLIST_FLAG_ALLOW_OFFLINE = 0x08, /**< Include offline buddies in the list. */ +} PurpleRequestBlistFlags; + +/** * A request field. */ typedef struct @@ -172,6 +184,14 @@ gsize size; } image; + struct + { + GList *default_nodes; + PurpleRequestBlistFlags flags; + GList *selecteds; + PurpleFilterBlistFunc filter; + } blist; + } u; void *ui_data; @@ -1151,6 +1171,84 @@ /*@}*/ /**************************************************************************/ +/** @name Buddylist Field API */ +/**************************************************************************/ +/*@{*/ + +/** + * Creates a buddylist field. + * + * @param id The field ID. + * @param text The label for the field. + * @param flag Flags dictating what kind of blist nodes should be + * included in the request field. + * @param selected A list of PurpleBlistNode's to select by default, or @c NULL. + * + * @return The new field. + */ +PurpleRequestField *purple_request_field_blist_nodes_new(const char *id, const char *text, + PurpleRequestBlistFlags flag, GList *selected); + +/** + * Set a filter for the request field. + * + * @param field The request field. + * @param filter The filter function. + * + * @return The old filter function, or @c NULL if there was none. + */ +PurpleFilterBlistFunc purple_request_field_blist_set_filter(PurpleRequestField *field, PurpleFilterBlistFunc filter); + +/** + * Get the filter function for the request field. + * + * @param field The request field. + * + * @return The filter function, or @c NULL if there isn't any. + */ +PurpleFilterBlistFunc purple_request_field_blist_get_filter(const PurpleRequestField *field); + +/** + * Add a PurpleBlistNode to the selected list. + * + * @param field The request field. + * @param node The buddylist node to add to the list. + * + * @return @c TRUE if the node is added to the list, @c FALSE if it was already in the list. + */ +gboolean purple_request_field_blist_add(PurpleRequestField *field, PurpleBlistNode *node); + +/** + * Remove a PurpleBlistNode from the selected list. + * + * @param field The request field. + * @param node The buddylist node to remove from the list. + * + * @return @c TRUE if the node is removed from the list, @c FALSE if the node is not in the list. + */ +gboolean purple_request_field_blist_remove(PurpleRequestField *field, PurpleBlistNode *node); + +/** + * Set the list of selected nodes in the request field. + * + * @param field The request field. + * @param selecteds The list of selected PurpleBlistNode's. Note that the request field + * becomes the owner of the list, and so the caller should not modify it. + */ +void purple_request_field_blist_set_selection_list(PurpleRequestField *field, GList *selecteds); + +/** + * Get a list of the selected buddylist nodes. + * + * @param field The request field. + * + * @return A GList of PurpleBlistNode's. + */ +GList *purple_request_field_blist_get_selection_list(const PurpleRequestField *field); + +/*@}*/ + +/**************************************************************************/ /** @name Request API */ /**************************************************************************/ /*@{*/
--- a/libpurple/signals.c Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/signals.c Fri Oct 12 02:06:38 2007 +0000 @@ -794,6 +794,19 @@ *return_val = GINT_TO_POINTER(ret_val); } +void +purple_marshal_INT__POINTER_POINTER(PurpleCallback cb, va_list args, void *data, + void **return_val) +{ + gint ret_val; + void *arg1 = va_arg(args, void *); + void *arg2 = va_arg(args, void *); + + ret_val = ((gint (*)(void *, void *, void *))cb)(arg1, arg2, data); + + if (return_val != NULL) + *return_val = GINT_TO_POINTER(ret_val); +} void purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER(
--- a/libpurple/signals.h Wed Sep 26 06:56:02 2007 +0000 +++ b/libpurple/signals.h Fri Oct 12 02:06:38 2007 +0000 @@ -307,6 +307,8 @@ PurpleCallback cb, va_list args, void *data, void **return_val); void purple_marshal_INT__INT_INT( PurpleCallback cb, va_list args, void *data, void **return_val); +void purple_marshal_INT__POINTER_POINTER( + PurpleCallback cb, va_list args, void *data, void **return_val); void purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER( PurpleCallback cb, va_list args, void *data, void **return_val);
--- a/pidgin/Makefile.am Wed Sep 26 06:56:02 2007 +0000 +++ b/pidgin/Makefile.am Fri Oct 12 02:06:38 2007 +0000 @@ -29,6 +29,7 @@ win32/nsis/langmacros.nsh \ win32/nsis/translations/afrikaans.nsh \ win32/nsis/translations/albanian.nsh \ + win32/nsis/translations/arabic.nsh \ win32/nsis/translations/basque.nsh \ win32/nsis/translations/bulgarian.nsh \ win32/nsis/translations/catalan.nsh \
--- a/pidgin/eggtrayicon.c Wed Sep 26 06:56:02 2007 +0000 +++ b/pidgin/eggtrayicon.c Fri Oct 12 02:06:38 2007 +0000 @@ -23,7 +23,6 @@ #include "eggtrayicon.h" -#include <gdk/gdkx.h> #include <X11/Xatom.h> #define _(x) x
--- a/pidgin/gtkconv.c Wed Sep 26 06:56:02 2007 +0000 +++ b/pidgin/gtkconv.c Fri Oct 12 02:06:38 2007 +0000 @@ -6835,7 +6835,9 @@ event = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event); +#if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE); +#endif gtk_widget_add_events(event, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(event), "button-press-event", @@ -7379,6 +7381,17 @@ pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC); } +/* Message history stuff */ + +/* Compare two PurpleConvMessage's, according to time in ascending order. */ +static int +message_compare(gconstpointer p1, gconstpointer p2) +{ + const PurpleConvMessage *m1 = p1, *m2 = p2; + return (m1->when > m2->when); +} + +/* Adds some message history to the gtkconv. This happens in a idle-callback. */ static gboolean add_message_history_to_gtkconv(gpointer data) { @@ -7386,49 +7399,106 @@ int count = 0; int timer = gtkconv->attach.timer; time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time")); + gboolean im = (gtkconv->active_conv->type == PURPLE_CONV_TYPE_IM); gtkconv->attach.timer = 0; while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ PurpleConvMessage *msg = gtkconv->attach.current->data; - if (when && when < msg->when) {