# HG changeset patch # User Etan Reisner # Date 1196812991 0 # Node ID e8e9a53b769448cc768a678f4508dc2455793617 # Parent 306ee626481d98d11fc5c1ebc9f6f6c6b8bc9e7b# Parent 3303c02a46f52baacb4409b2cb90b0146386cbe8 merge of '93a8de710501e9a772b3fb12ab3db6682a41b3d6' and 'ec67b1544528adb30f7d2edac30b22912b2da19b' diff -r 306ee626481d -r e8e9a53b7694 ChangeLog --- a/ChangeLog Sat Dec 01 06:46:25 2007 +0000 +++ b/ChangeLog Wed Dec 05 00:03:11 2007 +0000 @@ -1,9 +1,17 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.3.1 (??/??/????): +version 2.3.2 (??/??/????): + libpurple: + * Fixed various problems with loss of status messages when going + or returning from idle on MySpaceIM. + Finch: - * Color is used in the buddylist to indicate status. Look at the sample - gntrc file in the man-page for details. + * Color is used in the buddylist to indicate status, and the conversation + window to indicate various message attributes. Look at the sample gntrc + file in the man-page for details. + * The default keybinding for dump-screen is now M-D and uses a file + request dialog. M-d will properly delete-forward-word, and M-f has been + fixed to imitate readline's behavior. version 2.3.0 (11/24/2007): http://developer.pidgin.im/query?status=closed&milestone=2.3.0 diff -r 306ee626481d -r e8e9a53b7694 ChangeLog.API --- a/ChangeLog.API Sat Dec 01 06:46:25 2007 +0000 +++ b/ChangeLog.API Wed Dec 05 00:03:11 2007 +0000 @@ -1,6 +1,6 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.3.1 (??/??/????): +version 2.3.2 (??/??/????): Finch: libgnt: * Added gnt_tree_set_row_color to set the color for a row in a tree. @@ -8,6 +8,8 @@ * Added gnt_color_add_pair to define a new color. * Added gnt_colors_get_color to get an ncurses color value from a string. + * Added gnt_style_get_color to get a color pair from an entry in + ~/.gntrc version 2.3.0 (11/24/2007): libpurple: diff -r 306ee626481d -r e8e9a53b7694 Makefile.am --- a/Makefile.am Sat Dec 01 06:46:25 2007 +0000 +++ b/Makefile.am Wed Dec 05 00:03:11 2007 +0000 @@ -9,6 +9,7 @@ README.MTN \ README.mingw \ config.h.mingw \ + doxy2devhelp.xsl \ gaim.pc.in \ gaim-uninstalled.pc.in \ intltool-extract.in \ diff -r 306ee626481d -r e8e9a53b7694 configure.ac --- a/configure.ac Sat Dec 01 06:46:25 2007 +0000 +++ b/configure.ac Wed Dec 05 00:03:11 2007 +0000 @@ -328,7 +328,7 @@ enable_gtkui="$enableval", enable_gtkui="yes") AC_ARG_ENABLE(consoleui, [AC_HELP_STRING([--disable-consoleui], [compile without console user interface])], - enable_consoleui=$enableval, enable_consoleui=yes) + [enable_consoleui=$enableval force_finch=$enableval], [enable_consoleui=yes force_finch=no]) dnl ####################################################################### dnl # Check for GTK+ 2.0 and other things used by the GTK UI @@ -622,6 +622,14 @@ fi fi +if test "x$force_finch" = "xyes" -a "x$enable_consoleui" != "xyes"; then + AC_MSG_ERROR([ + +Finch will not be built. You need to install ncursesw (or ncurses) and its development headers. + +]) +fi + AC_SUBST(GNT_LIBS) AC_SUBST(GNT_CFLAGS) AM_CONDITIONAL(ENABLE_GNT, test "x$enable_consoleui" = "xyes") @@ -1651,16 +1659,24 @@ ]) mozilla_nspr="mozilla-nspr" mozilla_nss="mozilla-nss" - else - if `$PKG_CONFIG --exists nss`; then - PKG_CHECK_MODULES(NSS, nss, [ - have_nss="yes" - ], [ - AC_MSG_RESULT(no) - ]) - mozilla_nspr="nspr" - mozilla_nss="nss" - fi + elif `$PKG_CONFIG --exists nss`; then + PKG_CHECK_MODULES(NSS, nss, [ + have_nss="yes" + ], [ + AC_MSG_RESULT(no) + have_nss="no" + ]) + mozilla_nspr="nspr" + mozilla_nss="nss" + elif `$PKG_CONFIG --exists microb-engine-nss`; then + PKG_CHECK_MODULES(NSS, microb-engine-nss, [ + have_nss="yes" + ], [ + AC_MSG_RESULT(no) + have_nss="no" + ]) + mozilla_nspr="mozilla-nspr" + mozilla_nss="microb-engine-nss" fi if test "x$have_nss" = "xyes"; then diff -r 306ee626481d -r e8e9a53b7694 doc/finch.1.in --- a/doc/finch.1.in Sat Dec 01 06:46:25 2007 +0000 +++ b/doc/finch.1.in Wed Dec 05 00:03:11 2007 +0000 @@ -145,8 +145,19 @@ .br color-offline = red; black .br +color-message-sent = cyan; default +.br +color-message-received = red; default +.br +color-message-highlight = black; green +.br +color-message-action = yellow; default +.br +color-timestamp = blue; default +.br #See below for details on color .br + [general] .br shadow = 0 diff -r 306ee626481d -r e8e9a53b7694 doc/plugin-i18n.dox --- a/doc/plugin-i18n.dox Sat Dec 01 06:46:25 2007 +0000 +++ b/doc/plugin-i18n.dox Wed Dec 05 00:03:11 2007 +0000 @@ -1,13 +1,19 @@ /** @page plugin-i18n Third Party Plugin Translation Support @section Introduction + For the purpose of this document we're going to assume that your plugin: + + - Is set up to use autotools. It may be possible to add translation support + without autotools, but we have no idea how. We may not want to know, either ;) + - Has an autogen.sh. You may have also called this bootstrap.sh or similar. + - Resides in a source tree that has @c configure.ac and @c Makefile.am in the + top-level directory as well as a @c src directory in which the plugin's source + is located. A @c Makefile.am should also exist in the @c src directory. + For a plugin to have translation support there are a few steps that need to followed: - - The plugin must be setup to use autotools. It may be possible to add - translation support without autotools, but I have no idea how. - - In your autogen.sh, bootstrap.sh, or whatever you called it, add the - following after your other utility checks: + - In your autogen.sh, add the following after your other utility checks: @code (intltoolize --version) < /dev/null > /dev/null 2>&1 || { echo; @@ -16,12 +22,11 @@ exit; } @endcode - Then before your call aclocal add: + Then before your call to aclocal add: @code intltoolize --force --copy @endcode - - Now edit configure.ac, configure.in, or whatever you may have called it - and add the following: + - Now edit configure.ac and add the following: @code AC_PROG_INTLTOOL @@ -40,13 +45,13 @@ - Create/edit the file 'POTFILE.in' in your favorite editor. Each line should be the name of a file that could or does have strings marked for translating (we're getting to that step). These file names should be - relative to the top directory of your plugin. - - 'cd' back to the top directory of your plugin. + relative to the top directory of your plugin's source tree. + - 'cd' back to the top directory of your plugin's source tree. - Open 'Makefile.am' and add 'po' to your 'SUBDIRS' variable. - - While still in the top directory of your plugin execute + - While still in the top directory of your plugin's source tree, execute 'intltool-prepare'. This will setup anything extra that intltool needs. - - Fire off an 'autogen.sh' and when it's completed, verify that you have a - 'po/POTFILES', notice the lack of a .in. If you do, everything should be + - Fire off 'autogen.sh' and when it's completed, verify that you have a + 'po/POTFILES' (notice the lack of a .in). If you do, everything should be set on the autotools side. - Take a break, stretch your legs, smoke a cigarette, whatever, because we're done with the autotools part. @@ -60,8 +65,10 @@ #include @endcode Make sure that this include is after you include of your 'config.h', - otherwise you will break your build. - - This is where things get a bit goofy. libpurple is going to try and + otherwise you will break your build. Also note that if you wish to + maintain compatibility with older versions of GLib, you will need to + include additional preprocessor directives, which we won't cover here. + - This is where things get a bit goofy. libpurple is going to try to translate our strings using the libpurple gettext package. So we have to convert them before libpurple attempts to. - To do this, we're going to change the entries for name, summary, and diff -r 306ee626481d -r e8e9a53b7694 finch/gntblist.c --- a/finch/gntblist.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/gntblist.c Wed Dec 05 00:03:11 2007 +0000 @@ -1768,37 +1768,18 @@ draw_tooltip(ggblist); } -static int -get_color(char *key) -{ -#if GLIB_CHECK_VERSION(2,6,0) - int fg = 0, bg = 0; - gsize n; - char **vals; - vals = gnt_style_get_string_list(NULL, key, &n); - if (vals && n == 2) { - fg = gnt_colors_get_color(vals[0]); - bg = gnt_colors_get_color(vals[1]); - return gnt_color_add_pair(fg, bg); - } - return 0; -#else - return 0; -#endif -} - void finch_blist_init() { - color_available = get_color("color-available"); + color_available = gnt_style_get_color(NULL, "color-available"); if (!color_available) color_available = gnt_color_add_pair(COLOR_GREEN, -1); - color_away = get_color("color-away"); + color_away = gnt_style_get_color(NULL, "color-away"); if (!color_away) color_away = gnt_color_add_pair(COLOR_BLUE, -1); - color_idle = get_color("color-idle"); + color_idle = gnt_style_get_color(NULL, "color-idle"); if (!color_idle) color_idle = gnt_color_add_pair(COLOR_CYAN, -1); - color_offline = get_color("color-offline"); + color_offline = gnt_style_get_color(NULL, "color-offline"); if (!color_offline) color_offline = gnt_color_add_pair(COLOR_RED, -1); diff -r 306ee626481d -r e8e9a53b7694 finch/gntconv.c --- a/finch/gntconv.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/gntconv.c Wed Dec 05 00:03:11 2007 +0000 @@ -49,6 +49,7 @@ #include "gntmenu.h" #include "gntmenuitem.h" #include "gntmenuitemcheck.h" +#include "gntstyle.h" #include "gnttextview.h" #include "gnttree.h" #include "gntutils.h" @@ -64,6 +65,12 @@ const char *message, PurpleMessageFlags flags, time_t mtime); static void generate_send_to_menu(FinchConv *ggc); +static int color_message_receive; +static int color_message_send; +static int color_message_highlight; +static int color_message_action; +static int color_timestamp; + static PurpleBlistNode * get_conversation_blist_node(PurpleConversation *conv) { @@ -753,7 +760,9 @@ /* Unnecessary to print the timestamp for delayed message */ if (purple_prefs_get_bool("/finch/conversations/timestamps")) gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - purple_utf8_strftime("(%H:%M:%S) ", localtime(&mtime)), GNT_TEXT_FLAG_DIM); + purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)), gnt_color_pair(color_timestamp)); + + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), " ", GNT_TEXT_FLAG_NORMAL); if (flags & PURPLE_MESSAGE_AUTO_RESP) gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), @@ -763,23 +772,31 @@ !(flags & PURPLE_MESSAGE_NOTIFY)) { char * name = NULL; - - if (purple_message_meify((char*)message, -1)) - name = g_strdup_printf("*** %s ", who); - else - name = g_strdup_printf("%s: ", who); + GntTextFormatFlags msgflags = GNT_TEXT_FLAG_NORMAL; + gboolean me = FALSE; + if (purple_message_meify((char*)message, -1)) { + name = g_strdup_printf("*** %s", who); + msgflags = gnt_color_pair(color_message_action); + me = TRUE; + } else { + name = g_strdup_printf("%s", who); + if (flags & PURPLE_MESSAGE_SEND) + msgflags = gnt_color_pair(color_message_send); + else if (flags & PURPLE_MESSAGE_NICK) + msgflags = gnt_color_pair(color_message_highlight); + else + msgflags = gnt_color_pair(color_message_receive); + } gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), - name, GNT_TEXT_FLAG_BOLD); + name, msgflags); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), me ? " " : ": ", GNT_TEXT_FLAG_NORMAL); g_free(name); - } - else + } else fl = GNT_TEXT_FLAG_DIM; if (flags & PURPLE_MESSAGE_ERROR) fl |= GNT_TEXT_FLAG_BOLD; - if (flags & PURPLE_MESSAGE_NICK) - fl |= GNT_TEXT_FLAG_UNDERLINE; /* XXX: Remove this workaround when textview can parse messages. */ newline = purple_strdup_withhtml(message); @@ -1126,6 +1143,21 @@ void finch_conversation_init() { + color_message_send = gnt_style_get_color(NULL, "color-message-sent"); + if (!color_message_send) + color_message_send = gnt_color_add_pair(COLOR_CYAN, -1); + color_message_receive = gnt_style_get_color(NULL, "color-message-received"); + if (!color_message_receive) + color_message_receive = gnt_color_add_pair(COLOR_RED, -1); + color_message_highlight = gnt_style_get_color(NULL, "color-message-highlight"); + if (!color_message_highlight) + color_message_highlight = gnt_color_add_pair(COLOR_GREEN, -1); + color_timestamp = gnt_style_get_color(NULL, "color-timestamp"); + if (!color_timestamp) + color_timestamp = gnt_color_add_pair(COLOR_BLUE, -1); + color_message_action = gnt_style_get_color(NULL, "color-message-action"); + if (!color_message_action) + color_message_action = gnt_color_add_pair(COLOR_YELLOW, -1); purple_prefs_add_none(PREF_ROOT); purple_prefs_add_none(PREF_ROOT "/size"); purple_prefs_add_int(PREF_ROOT "/size/width", 70); diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/gntmain.c --- a/finch/libgnt/gntmain.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/gntmain.c Wed Dec 05 00:03:11 2007 +0000 @@ -679,8 +679,9 @@ g_free(cp); clean_pid(); wm->mode = GNT_KP_MODE_NORMAL; - clear(); + endwin(); setup_io(); + refresh(); refresh_screen(); } #endif diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/gntstyle.c --- a/finch/libgnt/gntstyle.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/gntstyle.c Wed Dec 05 00:03:11 2007 +0000 @@ -59,6 +59,25 @@ #endif } +int +gnt_style_get_color(char *group, char *key) +{ +#if GLIB_CHECK_VERSION(2,6,0) + int fg = 0, bg = 0; + gsize n; + char **vals; + vals = gnt_style_get_string_list(group, key, &n); + if (vals && n == 2) { + fg = gnt_colors_get_color(vals[0]); + bg = gnt_colors_get_color(vals[1]); + return gnt_color_add_pair(fg, bg); + } + return 0; +#else + return 0; +#endif +} + char **gnt_style_get_string_list(const char *group, const char *key, gsize *length) { #if GLIB_CHECK_VERSION(2,6,0) diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/gntstyle.h --- a/finch/libgnt/gntstyle.h Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/gntstyle.h Wed Dec 05 00:03:11 2007 +0000 @@ -74,11 +74,24 @@ * * @return NULL terminated string array. The array should be freed with g_strfreev(). * - * @since 2.3.1 (gnt), 2.3.1 (pidgin) + * @since 2.3.2 */ char **gnt_style_get_string_list(const char *group, const char *key, gsize *length); /** + * Get the value of a color pair in ~/.gntrc. + * + * @param group The name of the group in the keyfile. If @c NULL, the prgname + * will be used first, if available. Otherwise, "general" will be used. + * @param key The key + * + * @return The value of the color as an int, or 0 on error. + * + * @since 2.3.2 + */ +int gnt_style_get_color(char *group, char *key); + +/** * Parse a boolean preference. For example, if 'value' is "false" (ignoring case) * or "0", the return value will be @c FALSE, otherwise @c TRUE. * diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/gnttextview.c --- a/finch/libgnt/gnttextview.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/gnttextview.c Wed Dec 05 00:03:11 2007 +0000 @@ -650,8 +650,10 @@ fl |= (A_DIM | gnt_color_pair(GNT_COLOR_DISABLED)); else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) fl |= (A_DIM | gnt_color_pair(GNT_COLOR_HIGHLIGHT)); + else if ((flags & A_COLOR) == 0) + fl |= gnt_color_pair(GNT_COLOR_NORMAL); else - fl |= gnt_color_pair(GNT_COLOR_NORMAL); + fl |= (flags & A_COLOR); return fl; } diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/gntwm.c --- a/finch/libgnt/gntwm.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/gntwm.c Wed Dec 05 00:03:11 2007 +0000 @@ -692,6 +692,7 @@ {'\0', NULL} }; + gnt_widget_destroy(GNT_WIDGET(fs)); if ((file = g_fopen(path, "w+")) == NULL) { return; @@ -803,7 +804,6 @@ } fprintf(file, "\n"); fclose(file); - gnt_widget_destroy(GNT_WIDGET(fs)); } static void @@ -817,6 +817,11 @@ { GntWidget *window = gnt_file_sel_new(); GntFileSel *sel = GNT_FILE_SEL(window); + + g_object_set(G_OBJECT(window), "vertical", TRUE, NULL); + gnt_box_add_widget(GNT_BOX(window), gnt_label_new("Please enter the filename to save the screenshot.")); + gnt_box_set_title(GNT_BOX(window), "Save Screenshot..."); + gnt_file_sel_set_suggested_filename(sel, "dump.html"); g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(dump_file_save), NULL); g_signal_connect(G_OBJECT(sel->cancel), "activate", G_CALLBACK(dump_file_cancel), sel); diff -r 306ee626481d -r e8e9a53b7694 finch/libgnt/test/tv.c --- a/finch/libgnt/test/tv.c Sat Dec 01 06:46:25 2007 +0000 +++ b/finch/libgnt/test/tv.c Wed Dec 05 00:03:11 2007 +0000 @@ -112,8 +112,8 @@ gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 2nd line\n", GNT_TEXT_FLAG_NORMAL); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 3rd line\n", GNT_TEXT_FLAG_NORMAL); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD | gnt_color_pair(GNT_COLOR_HIGHLIGHT)); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 3rd line\n", GNT_TEXT_FLAG_NORMAL | gnt_color_pair(GNT_COLOR_HIGHLIGHT)); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 4th line\n", GNT_TEXT_FLAG_NORMAL); diff -r 306ee626481d -r e8e9a53b7694 libpurple/account.c --- a/libpurple/account.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/account.c Wed Dec 05 00:03:11 2007 +0000 @@ -741,7 +741,7 @@ current_error = g_new0(PurpleConnectionErrorInfo, 1); current_error->type = type; - current_error->description = description; + current_error->description = g_strdup(description); set_current_error(account, current_error); } diff -r 306ee626481d -r e8e9a53b7694 libpurple/blist.c --- a/libpurple/blist.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/blist.c Wed Dec 05 00:03:11 2007 +0000 @@ -1310,7 +1310,7 @@ g = (PurpleGroup *)((PurpleBlistNode *)c)->parent; } else { if (group) { - /* Add chat to blist if isn't already on it. Fixes #2752. */ + /* Add group to blist if isn't already on it. Fixes #2752. */ if (!purple_find_group(group->name)) { purple_blist_add_group(group, purple_blist_get_last_sibling(purplebuddylist->root)); diff -r 306ee626481d -r e8e9a53b7694 libpurple/connection.c --- a/libpurple/connection.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/connection.c Wed Dec 05 00:03:11 2007 +0000 @@ -38,6 +38,8 @@ #include "signals.h" #include "util.h" +#define KEEPALIVE_INTERVAL 30 + static GList *connections = NULL; static GList *connections_connecting = NULL; static PurpleConnectionUiOps *connection_ui_ops = NULL; @@ -73,7 +75,7 @@ if (on && !gc->keepalive) { purple_debug_info("connection", "Activating keepalive.\n"); - gc->keepalive = purple_timeout_add_seconds(30, send_keepalive, gc); + gc->keepalive = purple_timeout_add_seconds(KEEPALIVE_INTERVAL, send_keepalive, gc); } else if (!on && gc->keepalive > 0) { @@ -219,9 +221,6 @@ { PurpleAccount *account; GSList *buddies; -#if 0 - GList *wins; -#endif PurplePluginProtocolInfo *prpl_info = NULL; gboolean remove = FALSE; @@ -269,19 +268,6 @@ purple_signal_emit(purple_connections_get_handle(), "signed-off", gc); -#if 0 - /* see comment later in file on if 0'd same code */ - /* - * XXX This is a hack! Remove this and replace it with a better event - * notification system. - */ - for (wins = purple_get_windows(); wins != NULL; wins = wins->next) { - PurpleConvWindow *win = (PurpleConvWindow *)wins->data; - purple_conversation_update(purple_conv_window_get_conversation_at(win, 0), - PURPLE_CONV_ACCOUNT_OFFLINE); - } -#endif - purple_account_request_close_with_account(account); purple_request_close_with_handle(gc); purple_notify_close_with_handle(gc); diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Wed Dec 05 00:03:11 2007 +0000 @@ -62,6 +62,12 @@ #define DOCTYPE "\n" \ "" +enum sent_stream_start_types { + NOT_SENT = 0, + PARTIALLY_SENT = 1, + FULLY_SENT = 2 +}; + static void xep_iq_parse(xmlnode *packet, PurpleConnection *connection, PurpleBuddy *pb); @@ -100,6 +106,8 @@ bconv->rx_handler = 0; bconv->pb = pb; + bonjour_parser_setup(bconv); + return bconv; } @@ -289,7 +297,7 @@ /* If we're not ready to actually send, append it to the buffer */ if (bconv->tx_handler != 0 || bconv->connect_data != NULL - || !bconv->sent_stream_start + || bconv->sent_stream_start != FULLY_SENT || !bconv->recv_stream_start || purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { ret = -1; @@ -319,6 +327,7 @@ } if (ret < len) { + /* Don't interfere with the stream starting */ if (bconv->tx_handler == 0) bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, _send_data_write_cb, pb); @@ -409,20 +418,6 @@ } } -void bonjour_jabber_stream_started(PurpleBuddy *pb) { - BonjourBuddy *bb = pb->proto_data; - BonjourJabberConversation *bconv = bb->conversation; - - /* If the stream has been completely started, we can start doing stuff */ - if (bconv->sent_stream_start && bconv->recv_stream_start && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { - /* Watch for when we can write the buffered messages */ - bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, - _send_data_write_cb, pb); - /* We can probably write the data right now. */ - _send_data_write_cb(pb, bconv->socket, PURPLE_INPUT_WRITE); - } - -} struct _stream_start_data { char *msg; @@ -478,14 +473,13 @@ /* Stream started; process the send buffer if there is one */ purple_input_remove(bconv->tx_handler); - bconv->tx_handler= 0; - bconv->sent_stream_start = TRUE; + bconv->tx_handler = 0; + bconv->sent_stream_start = FULLY_SENT; bonjour_jabber_stream_started(pb); - } -static gboolean bonjour_jabber_stream_init(PurpleBuddy *pb, int client_socket) +static gboolean bonjour_jabber_send_stream_init(PurpleBuddy *pb, int client_socket) { int ret, len; char *stream_start; @@ -495,6 +489,8 @@ purple_buddy_get_name(pb)); len = strlen(stream_start); + bb->conversation->sent_stream_start = PARTIALLY_SENT; + /* Start the stream */ ret = send(client_socket, stream_start, len, 0); @@ -521,18 +517,55 @@ bb->conversation->tx_handler = purple_input_add(client_socket, PURPLE_INPUT_WRITE, _start_stream, pb); } else - bb->conversation->sent_stream_start = TRUE; + bb->conversation->sent_stream_start = FULLY_SENT; g_free(stream_start); - /* setup the parser fresh for each stream */ - bonjour_parser_setup(bb->conversation); + return TRUE; +} + +static gboolean +_async_bonjour_jabber_close_conversation(gpointer data) { + BonjourJabberConversation *bconv = data; + bonjour_jabber_close_conversation(bconv); + return FALSE; +} + +void bonjour_jabber_stream_started(PurpleBuddy *pb) { + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + if (bconv->sent_stream_start == NOT_SENT && !bonjour_jabber_send_stream_init(pb, bconv->socket)) { + const char *err = g_strerror(errno); + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); - bb->conversation->socket = client_socket; - bb->conversation->rx_handler = purple_input_add(client_socket, - PURPLE_INPUT_READ, _client_socket_handler, pb); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); - return TRUE; + close(bconv->socket); + /* This must be asynchronous because it destroys the parser and we + * may be in the middle of parsing. + */ + purple_timeout_add(0, _async_bonjour_jabber_close_conversation, bb->conversation); + bb->conversation = NULL; + return; + } + + /* If the stream has been completely started, we can start doing stuff */ + if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { + /* Watch for when we can write the buffered messages */ + bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + /* We can probably write the data right now. */ + _send_data_write_cb(pb, bconv->socket, PURPLE_INPUT_WRITE); + } + } static void @@ -576,14 +609,15 @@ bb = pb->proto_data; /* Check if the conversation has been previously started */ + /* This really shouldn't ever happen unless something weird is going on */ if (bb->conversation == NULL) { bb->conversation = bonjour_jabber_conv_new(pb); - if (!bonjour_jabber_stream_init(pb, client_socket)) { - close(client_socket); - return; - } + /* We wait for the stream start before doing anything else */ + bb->conversation->socket = client_socket; + bb->conversation->rx_handler = purple_input_add(client_socket, + PURPLE_INPUT_READ, _client_socket_handler, pb); } else { purple_debug_warning("bonjour", "Ignoring incoming connection because an existing connection exists.\n"); @@ -696,7 +730,7 @@ return; } - if (!bonjour_jabber_stream_init(pb, source)) { + if (!bonjour_jabber_send_stream_init(pb, source)) { const char *err = g_strerror(errno); PurpleConversation *conv; @@ -714,6 +748,11 @@ bb->conversation = NULL; return; } + + /* Start listening for the stream acknowledgement */ + bb->conversation->socket = source; + bb->conversation->rx_handler = purple_input_add(source, + PURPLE_INPUT_READ, _client_socket_handler, pb); } static PurpleBuddy * @@ -843,7 +882,7 @@ /* Close the socket and remove the watcher */ if (bconv->socket >= 0) { /* Send the end of the stream to the other end of the conversation */ - if (bconv->sent_stream_start) + if (bconv->sent_stream_start == FULLY_SENT) send(bconv->socket, STREAM_END, strlen(STREAM_END), 0); /* TODO: We're really supposed to wait for "" before closing the socket */ close(bconv->socket); diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/bonjour/jabber.h --- a/libpurple/protocols/bonjour/jabber.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Wed Dec 05 00:03:11 2007 +0000 @@ -47,7 +47,7 @@ guint rx_handler; guint tx_handler; PurpleCircBuffer *tx_buf; - gboolean sent_stream_start; + int sent_stream_start; /* 0 = Unsent, 1 = Partial, 2 = Complete */ gboolean recv_stream_start; PurpleProxyConnectData *connect_data; gpointer stream_data; diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/irc/irc.c Wed Dec 05 00:03:11 2007 +0000 @@ -184,9 +184,14 @@ /* XXX I don't like messing directly with these buddies */ gboolean irc_blist_timeout(struct irc_conn *irc) { - GString *string = g_string_sized_new(512); + GString *string; char *list, *buf; + if (irc->ison_outstanding) + return TRUE; + + string = g_string_sized_new(512); + g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_append, (gpointer)string); list = g_string_free(string, FALSE); @@ -200,6 +205,8 @@ irc_send(irc, buf); g_free(buf); + irc->ison_outstanding = TRUE; + return TRUE; } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/irc/irc.h --- a/libpurple/protocols/irc/irc.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/irc/irc.h Wed Dec 05 00:03:11 2007 +0000 @@ -56,6 +56,8 @@ guint timer; GHashTable *buddies; + gboolean ison_outstanding; + char *inbuf; int inbuflen; int inbufused; diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/irc/msgs.c --- a/libpurple/protocols/irc/msgs.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/irc/msgs.c Wed Dec 05 00:03:11 2007 +0000 @@ -707,6 +707,7 @@ g_strfreev(nicks); g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_status, (gpointer)irc); + irc->ison_outstanding = FALSE; } static void irc_buddy_status(char *name, struct irc_buddy *ib, struct irc_conn *irc) diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Wed Dec 05 00:03:11 2007 +0000 @@ -1777,7 +1777,7 @@ passport = msn_user_get_passport(session->user); url = session->passport_info.file; - purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL, + purple_notify_emails(gc, count, FALSE, NULL, NULL, &passport, &url, NULL, NULL); } } @@ -1850,7 +1850,7 @@ passport = msn_user_get_passport(session->user); url = session->passport_info.file; - purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL, + purple_notify_emails(gc, count, FALSE, NULL, NULL, &passport, &url, NULL, NULL); } } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/msn/oim.c --- a/libpurple/protocols/msn/oim.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/msn/oim.c Wed Dec 05 00:03:11 2007 +0000 @@ -488,10 +488,12 @@ char *unread = xmlnode_get_data(iu_node); const char *passport = msn_user_get_passport(session->user); const char *url = session->passport_info.file; + int count = atoi(unread); /* XXX/khc: pretty sure this is wrong */ - purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, - NULL, &passport, &url, NULL, NULL); + if (count > 0) + purple_notify_emails(session->account->gc, count, FALSE, NULL, + NULL, &passport, &url, NULL, NULL); g_free(unread); } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/msnp9/directconn.c --- a/libpurple/protocols/msnp9/directconn.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/msnp9/directconn.c Wed Dec 05 00:03:11 2007 +0000 @@ -81,6 +81,7 @@ create_listener(int port) { int fd; + int flags; const int on = 1; #if 0 @@ -156,7 +157,8 @@ return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } @@ -353,7 +355,7 @@ } static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnDirectConn* directconn; int fd; @@ -405,6 +407,15 @@ } } +static void +directconn_connect_cb(gpointer data, gint source, const gchar *error_message) +{ + if (error_message) + purple_debug_error("msn", "Error making direct connection: %s\n", error_message); + + connect_cb(data, source, PURPLE_INPUT_READ); +} + gboolean msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port) { @@ -424,14 +435,9 @@ #endif directconn->connect_data = purple_proxy_connect(NULL, session->account, - host, port, connect_cb, directconn); + host, port, directconn_connect_cb, directconn); - if (directconn->connect_data != NULL) - { - return TRUE; - } - else - return FALSE; + return (directconn->connect_data != NULL); } #if 0 diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/msnp9/servconn.c --- a/libpurple/protocols/msnp9/servconn.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/msnp9/servconn.c Wed Dec 05 00:03:11 2007 +0000 @@ -468,6 +468,7 @@ create_listener(int port) { int fd; + int flags; const int on = 1; #if 0 @@ -543,7 +544,8 @@ return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Wed Dec 05 00:03:11 2007 +0000 @@ -1047,15 +1047,18 @@ msim_set_status(PurpleAccount *account, PurpleStatus *status) { PurpleStatusType *type; + PurplePresence *pres; MsimSession *session; guint status_code; - gchar *statstring; + const gchar *message; + gchar *stripped; session = (MsimSession *)account->gc->proto_data; g_return_if_fail(MSIM_SESSION_VALID(session)); type = purple_status_get_type(status); + pres = purple_status_get_presence(status); switch (purple_status_type_get_primitive(type)) { case PURPLE_STATUS_AVAILABLE: @@ -1083,16 +1086,20 @@ break; } - statstring = (gchar *)purple_status_get_attr_string(status, "message"); - - if (!statstring) { - statstring = ""; - } + message = purple_status_get_attr_string(status, "message"); /* Status strings are plain text. */ - statstring = purple_markup_strip_html(statstring); - - msim_set_status_code(session, status_code, statstring); + if (message != NULL) + stripped = purple_markup_strip_html(message); + else + stripped = g_strdup(""); + + msim_set_status_code(session, status_code, stripped); + + /* If we should be idle, set that status. Time is irrelevant here. */ + if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN) + msim_set_idle(account->gc, 1); + } /** Go idle. */ @@ -1100,6 +1107,7 @@ msim_set_idle(PurpleConnection *gc, int time) { MsimSession *session; + PurpleStatus *status; g_return_if_fail(gc != NULL); @@ -1107,16 +1115,30 @@ g_return_if_fail(MSIM_SESSION_VALID(session)); + status = purple_account_get_active_status(session->account); + if (time == 0) { /* Going back from idle. In msim, idle is mutually exclusive * from the other states (you can only be away or idle, but not - * both, for example), so by going non-idle I go online. + * both, for example), so by going non-idle I go back to what + * libpurple says I should be. */ - /* TODO: find out how to keep old status string? */ - msim_set_status_code(session, MSIM_STATUS_CODE_ONLINE, g_strdup("")); + msim_set_status(session->account, status); } else { + const gchar *message; + gchar *stripped; + + /* Set the idle message to the status message from the real + * current status. + */ + message = purple_status_get_attr_string(status, "message"); + if (message != NULL) + stripped = purple_markup_strip_html(message); + else + stripped = g_strdup(""); + /* msim doesn't support idle time, so just go idle */ - msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, g_strdup("")); + msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped); } } @@ -1347,7 +1369,9 @@ msim_msg_dump("msim_check_inbox_cb: reply=%s\n", reply); body = msim_msg_get_dictionary(reply, "body"); - g_return_if_fail(body != NULL); + + if (body == NULL) + return; old_inbox_status = session->inbox_status; @@ -1411,6 +1435,11 @@ session = (MsimSession *)data; + if (!MSIM_SESSION_VALID(session)) { + purple_debug_info("msim", "msim_check_inbox: session invalid, stopping the mail check.\n"); + return FALSE; + } + purple_debug_info("msim", "msim_check_inbox: checking mail\n"); g_return_val_if_fail(msim_send(session, "persist", MSIM_TYPE_INTEGER, 1, @@ -1623,7 +1652,7 @@ /* Check mail if they want to. */ if (purple_account_get_check_mail(session->account)) { - purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK, + session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK, (GSourceFunc)msim_check_inbox, session); msim_check_inbox(session); } @@ -1894,7 +1923,7 @@ purple_debug_info("msim", "msim_status: found buddy %s\n", username); } - if (status_headline) { + if (status_headline && strcmp(status_headline, "") != 0) { /* The status headline is plaintext, but libpurple treats it as HTML, * so escape any HTML characters to their entity equivalents. */ status_headline_escaped = g_markup_escape_text(status_headline, strlen(status_headline)); @@ -1925,8 +1954,8 @@ break; case MSIM_STATUS_CODE_IDLE: - /* will be handled below */ - purple_status_code = -1; + /* Treat idle as an available status. */ + purple_status_code = PURPLE_STATUS_AVAILABLE; break; default: diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/myspace/session.c --- a/libpurple/protocols/myspace/session.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/myspace/session.c Wed Dec 05 00:03:11 2007 +0000 @@ -63,6 +63,7 @@ session->next_rid = 1; session->last_comm = time(NULL); session->inbox_status = 0; + session->inbox_handle = 0; return session; } @@ -90,6 +91,11 @@ msim_msg_free(session->server_info); } + /* Stop checking the inbox at the end of the session. */ + if (session->inbox_handle) { + purple_timeout_remove(session->inbox_handle); + } + g_free(session); } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/myspace/session.h --- a/libpurple/protocols/myspace/session.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/myspace/session.h Wed Dec 05 00:03:11 2007 +0000 @@ -45,6 +45,7 @@ guint next_rid; /**< Next request/response ID */ time_t last_comm; /**< Time received last communication */ guint inbox_status; /**< Bit field of inbox notifications */ + guint inbox_handle; /**< The handle for the mail check timer */ } MsimSession; /* Check if an MsimSession is valid */ diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/oscar/family_chatnav.c --- a/libpurple/protocols/oscar/family_chatnav.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/oscar/family_chatnav.c Wed Dec 05 00:03:11 2007 +0000 @@ -29,6 +29,49 @@ #include "oscar.h" +static int +error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) +{ + int ret = 0; + aim_snac_t *snac2; + guint16 error, chatnav_error; + GSList *tlvlist; + + if (!(snac2 = aim_remsnac(od, snac->id))) { + purple_debug_warning("oscar", "chatnav error: received response to unknown request (%08lx)\n", snac->id); + return 0; + } + + if (snac2->family != 0x000d) { + purple_debug_warning("oscar", "chatnav error: received response that maps to corrupt request (fam=%04x)\n", snac2->family); + return 0; + } + + /* + * We now know what the original SNAC subtype was. + */ + if (snac2->type == 0x0008) /* create room */ + { + error = byte_stream_get16(bs); + tlvlist = aim_tlvlist_read(bs); + chatnav_error = aim_tlv_get16(tlvlist, 0x0008, 1); + + purple_debug_warning("oscar", + "Could not join room, error=0x%04hx, chatnav_error=0x%04hx\n", + error, chatnav_error); + purple_notify_error(od->gc, NULL, _("Could not join chat room"), + chatnav_error == 0x0033 ? _("Invalid chat room name") : _("Unknown error")); + + ret = 1; + } + + if (snac2) + g_free(snac2->data); + g_free(snac2); + + return ret; +} + /* * Subtype 0x0002 * @@ -451,7 +494,9 @@ static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - if (snac->subtype == 0x0009) + if (snac->subtype == 0x0001) + return error(od, conn, mod, frame, snac, bs); + else if (snac->subtype == 0x0009) return parseinfo(od, conn, mod, frame, snac, bs); return 0; diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/oscar/family_feedbag.c --- a/libpurple/protocols/oscar/family_feedbag.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Wed Dec 05 00:03:11 2007 +0000 @@ -115,14 +115,10 @@ gboolean exists; struct aim_ssi_item *cur, *new; - new = (struct aim_ssi_item *)g_malloc(sizeof(struct aim_ssi_item)); + new = g_new(struct aim_ssi_item, 1); /* Set the name */ - if (name) { - new->name = (char *)g_malloc((strlen(name)+1)*sizeof(char)); - strcpy(new->name, name); - } else - new->name = NULL; + new->name = g_strdup(name); /* Set the group ID# and buddy ID# */ new->gid = gid; @@ -345,13 +341,9 @@ */ struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn) { - struct aim_ssi_item *cur; - if (!list || !sn) + if (!sn) return NULL; - for (cur=list; cur; cur=cur->next) - if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn))) - return cur; - return NULL; + return aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY); } /** @@ -510,7 +502,7 @@ for (cur1=od->ssi.official; cur1 && (n < 15); cur1=cur1->next) { if (!aim_ssi_itemlist_find(od->ssi.local, cur1->gid, cur1->bid)) { n++; - new = (struct aim_ssi_tmp *)g_malloc(sizeof(struct aim_ssi_tmp)); + new = g_new(struct aim_ssi_tmp, 1); new->action = SNAC_SUBTYPE_FEEDBAG_DEL; new->ack = 0xffff; new->name = NULL; @@ -530,7 +522,7 @@ for (cur1=od->ssi.local; cur1 && (n < 15); cur1=cur1->next) { if (!aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid)) { n++; - new = (struct aim_ssi_tmp *)g_malloc(sizeof(struct aim_ssi_tmp)); + new = g_new(struct aim_ssi_tmp, 1); new->action = SNAC_SUBTYPE_FEEDBAG_ADD; new->ack = 0xffff; new->name = NULL; @@ -551,7 +543,7 @@ cur2 = aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid); if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { n++; - new = (struct aim_ssi_tmp *)g_malloc(sizeof(struct aim_ssi_tmp)); + new = g_new(struct aim_ssi_tmp, 1); new->action = SNAC_SUBTYPE_FEEDBAG_MOD; new->ack = 0xffff; new->name = NULL; @@ -1028,8 +1020,7 @@ return -EINVAL; g_free(group->name); - group->name = (char *)g_malloc((strlen(newgn)+1)*sizeof(char)); - strcpy(group->name, newgn); + group->name = g_strdup(newgn); /* Sync our local list with the server list */ return aim_ssi_sync(od); @@ -1461,11 +1452,7 @@ if ((item = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) { item->type = type; g_free(item->name); - if (name) { - item->name = (char *)g_malloc((strlen(name)+1)*sizeof(char)); - strcpy(item->name, name); - } else - item->name = NULL; + item->name = g_strdup(name); aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } @@ -1473,11 +1460,7 @@ if ((item = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) { item->type = type; g_free(item->name); - if (name) { - item->name = (char *)g_malloc((strlen(name)+1)*sizeof(char)); - strcpy(item->name, name); - } else - item->name = NULL; + item->name = g_strdup(name); aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } @@ -1555,10 +1538,7 @@ /* Remove the item from the local list */ /* Make sure cur->item is still valid memory */ if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { - if (cur->item->name) { - cur->name = (char *)g_malloc((strlen(cur->item->name)+1)*sizeof(char)); - strcpy(cur->name, cur->item->name); - } + cur->name = g_strdup(cur->item->name); aim_ssi_itemlist_del(&od->ssi.local, cur->item); } cur->item = NULL; @@ -1569,11 +1549,7 @@ struct aim_ssi_item *cur1; if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { g_free(cur->item->name); - if (cur1->name) { - cur->item->name = (char *)g_malloc((strlen(cur1->name)+1)*sizeof(char)); - strcpy(cur->item->name, cur1->name); - } else - cur->item->name = NULL; + cur->item->name = g_strdup(cur1->name); aim_tlvlist_free(cur->item->data); cur->item->data = aim_tlvlist_copy(cur1->data); } @@ -1603,11 +1579,7 @@ struct aim_ssi_item *cur1; if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { g_free(cur1->name); - if (cur->item->name) { - cur1->name = (char *)g_malloc((strlen(cur->item->name)+1)*sizeof(char)); - strcpy(cur1->name, cur->item->name); - } else - cur1->name = NULL; + cur1->name = g_strdup(cur->item->name); aim_tlvlist_free(cur1->data); cur1->data = aim_tlvlist_copy(cur->item->data); } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/oscar/family_icbm.c --- a/libpurple/protocols/oscar/family_icbm.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Dec 05 00:03:11 2007 +0000 @@ -209,7 +209,6 @@ */ static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - aim_rxcallback_t userfunc; struct aim_icbmparameters params; params.maxchan = byte_stream_get16(bs); @@ -219,8 +218,11 @@ params.maxrecverwarn = byte_stream_get16(bs); params.minmsginterval = byte_stream_get32(bs); - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - return userfunc(od, conn, frame, ¶ms); + params.flags = 0x0000000b; + params.maxmsglen = 8000; + params.minmsginterval = 0; + + aim_im_setparams(od, ¶ms); return 0; } @@ -288,7 +290,7 @@ if (!args->msg || (args->msglen <= 0)) return -EINVAL; - if (args->msglen >= MAXMSGLEN) + if (args->msglen > MAXMSGLEN) return -E2BIG; } diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Wed Dec 05 00:03:11 2007 +0000 @@ -176,7 +176,6 @@ static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_locerr (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_icbm_param_info (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_memrequest (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_selfinfo (OscarData *, FlapConnection *, FlapFrame *, ...); @@ -1228,7 +1227,6 @@ oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ, purple_ssi_authrequest, 0); oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP, purple_ssi_authreply, 0); oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADDED, purple_ssi_gotadded, 0); - oscar_data_addhandler(od, SNAC_FAMILY_ICBM, 0x0005, purple_icbm_param_info, 0); oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_INCOMING, purple_parse_incoming_im, 0); oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0); oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0); @@ -1833,9 +1831,6 @@ signon = info->onlinesince; else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) signon = time(NULL) - info->sessionlen; - if (!aim_sncmp(purple_account_get_username(account), info->sn)) { - purple_connection_set_display_name(gc, info->sn); - } purple_prpl_got_user_login_time(account, info->sn, signon); /* Idle time stuff */ @@ -3437,6 +3432,8 @@ info = va_arg(ap, aim_userinfo_t *); va_end(ap); + purple_connection_set_display_name(od->gc, info->sn); + /* * What's with the + 0.5? * The 0.5 is basically poor-man's rounding. Normally @@ -3498,32 +3495,6 @@ return 1; } -static int purple_icbm_param_info(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - struct aim_icbmparameters *params; - va_list ap; - - va_start(ap, fr); - params = va_arg(ap, struct aim_icbmparameters *); - va_end(ap); - - /* XXX - evidently this crashes on solaris. i have no clue why - purple_debug_misc("oscar", "ICBM Parameters: maxchannel = %hu, default flags = 0x%08lx, max msg len = %hu, " - "max sender evil = %f, max receiver evil = %f, min msg interval = %u\n", - params->maxchan, params->flags, params->maxmsglen, - ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, - params->minmsginterval); - */ - - /* Maybe senderwarn and recverwarn should be user preferences... */ - params->flags = 0x0000000b; - params->maxmsglen = 8000; - params->minmsginterval = 0; - - aim_im_setparams(od, params); - - return 1; -} - static int purple_parse_locaterights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; @@ -5364,6 +5335,7 @@ if (chat_name != NULL) g_hash_table_insert(defaults, "room", g_strdup(chat_name)); + g_hash_table_insert(defaults, "exchange", g_strdup("4")); return defaults; } @@ -5380,26 +5352,29 @@ OscarData *od = (OscarData *)gc->proto_data; FlapConnection *conn; char *name, *exchange; + int exchange_int; name = g_hash_table_lookup(data, "room"); exchange = g_hash_table_lookup(data, "exchange"); - if ((name == NULL) || (*name == '\0')) { - purple_notify_error(gc, NULL, _("Invalid chat name specified."), NULL); - return; - } + g_return_if_fail(name != NULL && *name != '\0'); + g_return_if_fail(exchange != NULL); + + errno = 0; + exchange_int = strtol(exchange, NULL, 10); + g_return_if_fail(errno == 0); purple_debug_info("oscar", "Attempting to join chat room %s.\n", name); if ((conn = flap_connection_getbytype(od, SNAC_FAMILY_CHATNAV))) { purple_debug_info("oscar", "chatnav exists, creating room\n"); - aim_chatnav_createroom(od, conn, name, atoi(exchange)); + aim_chatnav_createroom(od, conn, name, exchange_int); } else { /* this gets tricky */ struct create_room *cr = g_new0(struct create_room, 1); purple_debug_info("oscar", "chatnav does not exist, opening chatnav\n"); - cr->exchange = atoi(exchange); + cr->exchange = exchange_int; cr->name = g_strdup(name); od->create_rooms = g_slist_prepend(od->create_rooms, cr); aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV); @@ -6725,7 +6700,7 @@ prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); option = purple_account_option_bool_new( - _("Always use ICQ proxy server for file transfers\n(slower, but does not reveal your IP address)"), "always_use_rv_proxy", + _("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy", OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY); prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.h Wed Dec 05 00:03:11 2007 +0000 @@ -94,11 +94,8 @@ * for WinAIM clients (up through the latest (4.0.1957)) to * send any more than 1kb. Amaze all your windows friends * with utterly oversized instant messages! - * - * TODO: the real limit is the total SNAC size at 8192. Fix this. - * */ -#define MAXMSGLEN 7987 +#define MAXMSGLEN 2544 /* * Maximum size of a Buddy Icon. diff -r 306ee626481d -r e8e9a53b7694 libpurple/protocols/qq/header_info.h --- a/libpurple/protocols/qq/header_info.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/protocols/qq/header_info.h Wed Dec 05 00:03:11 2007 +0000 @@ -33,7 +33,7 @@ #define QQ_PACKET_TAG 0x02 /* all QQ text packets starts with it */ #define QQ_PACKET_TAIL 0x03 /* all QQ text packets end with it */ -#define QQ_CLIENT 0x0E1B +#define QQ_CLIENT 0x0d55 /* list of known QQ commands */ enum { diff -r 306ee626481d -r e8e9a53b7694 libpurple/prpl.h --- a/libpurple/prpl.h Sat Dec 01 06:46:25 2007 +0000 +++ b/libpurple/prpl.h Wed Dec 05 00:03:11 2007 +0000 @@ -292,6 +292,13 @@ void (*chat_whisper)(PurpleConnection *, int id, const char *who, const char *message); int (*chat_send)(PurpleConnection *, int id, const char *message, PurpleMessageFlags flags); + + /** If implemented, this will be called regularly for this prpl's + * active connections. You'd want to do this if you need to repeatedly + * send some kind of keepalive packet to the server to avoid being + * disconnected. ("Regularly" is defined by + * KEEPALIVE_INTERVAL in libpurple/connection.c.) + */ void (*keepalive)(PurpleConnection *); /** new user registration */ diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkblist.c Wed Dec 05 00:03:11 2007 +0000 @@ -1398,7 +1398,7 @@ pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, node); pidgin_append_blist_node_extended_menu(menu, node); - if (!contact_expanded) + if (!contact_expanded && contact != NULL) pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact); if (node->parent && node->parent->child->next && @@ -3170,6 +3170,7 @@ GList *cur; struct proto_chat_entry *pce; char *name, *value; + PidginBlistNode *bnode = node->ui_data; chat = (PurpleChat *)node; prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account)); @@ -3182,6 +3183,11 @@ g_free(tmp); } + if (bnode && bnode->conv.conv) { + const char *topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(bnode->conv.conv)); + g_string_append_printf(str, _("\nTopic: %s"), topic ? topic : _("(no topic set)")); + } + if (prpl_info->chat_info != NULL) cur = prpl_info->chat_info(chat->account->gc); else @@ -3371,6 +3377,34 @@ return g_string_free(str, FALSE); } +static GHashTable *cached_emblems; + +static void _cleanup_cached_emblem(gpointer data, GObject *obj) { + g_hash_table_remove(cached_emblems, data); +} + +static GdkPixbuf * _pidgin_blist_get_cached_emblem(gchar *path) { + GdkPixbuf *pb = g_hash_table_lookup(cached_emblems, path); + + if (pb != NULL) { + /* The caller gets a reference */ + g_object_ref(pb); + g_free(path); + } else { + pb = gdk_pixbuf_new_from_file(path, NULL); + if (pb != NULL) { + /* We don't want to own a ref to the pixbuf, but we need to keep clean up. */ + /* I'm not sure if it would be better to just keep our ref and not let the emblem ever be destroyed */ + g_object_weak_ref(G_OBJECT(pb), _cleanup_cached_emblem, path); + g_hash_table_insert(cached_emblems, path, pb); + } else + g_free(path); + } + + return pb; +} + + GdkPixbuf * pidgin_blist_get_emblem(PurpleBlistNode *node) { @@ -3381,7 +3415,6 @@ PurplePluginProtocolInfo *prpl_info; const char *name = NULL; char *filename, *path; - GdkPixbuf *ret; PurplePresence *p; if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { @@ -3394,11 +3427,9 @@ gtkbuddynode = node->ui_data; p = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { - path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "mobile.png", NULL); - ret = gdk_pixbuf_new_from_file(path, NULL); - g_free(path); - return ret; + return _pidgin_blist_get_cached_emblem(path); } if (((struct _pidgin_blist_node*)(node->parent->ui_data))->contact_expanded) { @@ -3410,26 +3441,22 @@ return NULL; } + g_return_val_if_fail(buddy != NULL, NULL); + if (!purple_privacy_check(buddy->account, purple_buddy_get_name(buddy))) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "blocked.png", NULL); - ret = gdk_pixbuf_new_from_file(path, NULL); - g_free(path); - return ret; + return _pidgin_blist_get_cached_emblem(path); } p = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "mobile.png", NULL); - ret = gdk_pixbuf_new_from_file(path, NULL); - g_free(path); - return ret; + return _pidgin_blist_get_cached_emblem(path); } if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL); - ret = gdk_pixbuf_new_from_file(path, NULL); - g_free(path); - return ret; + return _pidgin_blist_get_cached_emblem(path); } prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account)); @@ -3446,12 +3473,10 @@ filename = g_strdup_printf("%s.png", name); path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", filename, NULL); - ret = gdk_pixbuf_new_from_file(path, NULL); - g_free(filename); - g_free(path); - - return ret; + + /* _pidgin_blist_get_cached_emblem() assumes ownership of path */ + return _pidgin_blist_get_cached_emblem(path); } @@ -5691,7 +5716,6 @@ static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded) { PurpleGroup *group; - GdkColor textcolor; gboolean selected; char group_count[12] = ""; char *mark, *esc; @@ -5699,7 +5723,6 @@ GtkTreeIter iter; group = (PurpleGroup*)gnode; - textcolor = gtkblist->treeview->style->fg[GTK_STATE_ACTIVE]; if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)), NULL, &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, @@ -5714,12 +5737,7 @@ } esc = g_markup_escape_text(group->name, -1); - if (selected) - mark = g_strdup_printf("%s%s", esc, group_count); - else - mark = g_strdup_printf("%s%s", - textcolor.red>>8, textcolor.green>>8, textcolor.blue>>8, - esc, group_count); + mark = g_strdup_printf("%s%s", esc ? esc : "", group_count); g_free(esc); return mark; @@ -6897,6 +6915,8 @@ { void *gtk_blist_handle = pidgin_blist_get_handle(); + cached_emblems = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + purple_signal_connect(purple_connections_get_handle(), "signed-on", gtk_blist_handle, PURPLE_CALLBACK(account_signon_cb), NULL); @@ -6948,6 +6968,8 @@ void pidgin_blist_uninit(void) { + g_hash_table_destroy(cached_emblems); + purple_signals_unregister_by_instance(pidgin_blist_get_handle()); purple_signals_disconnect_by_handle(pidgin_blist_get_handle()); } diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkconv.c Wed Dec 05 00:03:11 2007 +0000 @@ -4349,7 +4349,7 @@ pad_bottom = gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(gtkconv->entry)); pad_inside = gtk_text_view_get_pixels_inside_wrap(GTK_TEXT_VIEW(gtkconv->entry)); - height = (oneline.height + pad_top + pad_bottom) * lines; + height = (oneline.height + pad_top + pad_bottom) * (lines + 1); height += (oneline.height + pad_inside) * (wrapped_lines - lines); gtkconv->auto_resize = TRUE; @@ -6476,8 +6476,29 @@ markup = title; } } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { - const char *topic = gtk_entry_get_text(GTK_ENTRY(gtkconv->u.chat->topic_text)); - char *esc = topic ? g_markup_escape_text(topic, -1) : NULL; + const char *topic = gtkconv->u.chat->topic_text ? gtk_entry_get_text(GTK_ENTRY(gtkconv->u.chat->topic_text)) : NULL; + char *esc = NULL; +#if GTK_CHECK_VERSION(2,6,0) + esc = topic ? g_markup_escape_text(topic, -1) : NULL; +#else + /* GTK < 2.6 doesn't have auto ellipsization, so we do a crude + * trucation to prevent forcing the window to be as wide as the topic */ + int len = 0; + char *c, *tmp = g_strdup(topic); + c = tmp; + while(*c && len < 72) { + c = g_utf8_next_char(c); + len++; + } + if (len == 72) { + *c = '\0'; + c = g_strdup_printf("%s...", tmp); + g_free(tmp); + tmp = c; + } + esc = tmp ? g_markup_escape_text(tmp, -1) : NULL; + g_free(tmp); +#endif markup = g_strdup_printf("%s%s%s", purple_conversation_get_title(conv), esc && *esc ? "\n" : "", @@ -6511,7 +6532,7 @@ } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT) { atk_object_set_description(accessibility_obj, _("Unread Messages")); if (gtkconv->active_conv->type == PURPLE_CONV_TYPE_CHAT) - style = "color=\"#cc0000\""; + style = "tab-label-unreadchat"; else style = "tab-label-attention"; } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT) { @@ -7172,15 +7193,18 @@ if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0) when_away = TRUE; - while ((l = hidden_convwin->gtkconvs) != NULL) + for (l = hidden_convwin->gtkconvs; l; ) { gtkconv = l->data; + l = l->next; conv = gtkconv->active_conv; - if(when_away && !purple_status_is_available( + if (conv->type == PURPLE_CONV_TYPE_CHAT || + gtkconv->unseen_count == 0 || + (when_away && !purple_status_is_available( purple_account_get_active_status( - purple_conversation_get_account(conv)))) + purple_conversation_get_account(conv))))) continue; pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); @@ -7796,7 +7820,8 @@ } styles[] = { {"pidgin_tab_label_typing_default", "tab-label-typing", "#4e9a06"}, {"pidgin_tab_label_typed_default", "tab-label-typed", "#c4a000"}, - {"pidgin_tab_label_attention_default", "tab-label-attention", "#204a87"}, + {"pidgin_tab_label_attention_default", "tab-label-attention", "#006aff"}, + {"pidgin_tab_label_unreadchat_default", "tab-label-unreadchat", "#cc0000"}, {"pidgin_tab_label_event_default", "tab-label-event", "#888a85"}, {NULL, NULL, NULL} }; @@ -8652,7 +8677,7 @@ gtk_entry_get_text(entry)); } serv_alias_buddy(buddy); - } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { gtk_entry_set_text(GTK_ENTRY(gtkconv->u.chat->topic_text), gtk_entry_get_text(entry)); topic_callback(NULL, gtkconv); } @@ -8663,7 +8688,7 @@ infopane_entry_activate(PidginConversation *gtkconv) { GtkWidget *entry = NULL; - PurpleConversation *conv = gtkconv->active_conv; + PurpleConversation *conv = gtkconv->active_conv; const char *text = NULL; if (!GTK_WIDGET_VISIBLE(gtkconv->tab_label)) { @@ -8679,9 +8704,21 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { PurpleBuddy *buddy = purple_find_buddy(gtkconv->active_conv->account, gtkconv->active_conv->name); if (!buddy) + /* This buddy isn't in your buddy list, so we can't alias him */ return FALSE; + text = purple_buddy_get_contact_alias(buddy); } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + PurpleConnection *gc; + PurplePluginProtocolInfo *prpl_info = NULL; + + gc = purple_conversation_get_gc(conv); + if (gc != NULL) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + if (prpl_info && prpl_info->set_chat_topic == NULL) + /* This protocol doesn't support setting the chat room topic */ + return FALSE; + text = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(conv)); } @@ -8700,10 +8737,9 @@ g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(alias_cb), gtkconv); g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(alias_focus_cb), gtkconv); g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(alias_key_press_cb), gtkconv); - - - - gtk_entry_set_text(GTK_ENTRY(entry), text); + + if (text != NULL) + gtk_entry_set_text(GTK_ENTRY(entry), text); gtk_widget_show(entry); gtk_widget_hide(gtkconv->infopane); gtk_widget_grab_focus(entry); diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkimhtml.c Wed Dec 05 00:03:11 2007 +0000 @@ -844,19 +844,19 @@ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Smile!")); + mi = gtk_image_menu_item_new_with_mnemonic(_("S_mile!")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Insert")); + mi = gtk_image_menu_item_new_with_mnemonic(_("_Insert")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Font")); + mi = gtk_image_menu_item_new_with_mnemonic(_("_Font")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); @@ -4290,19 +4290,19 @@ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Font")); + mi = gtk_image_menu_item_new_with_mnemonic(_("_Font")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Insert")); + mi = gtk_image_menu_item_new_with_mnemonic(_("_Insert")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("_Smile!")); + mi = gtk_image_menu_item_new_with_mnemonic(_("S_mile!")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img); gtk_widget_show(mi); gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkimhtmltoolbar.c --- a/pidgin/gtkimhtmltoolbar.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Wed Dec 05 00:03:11 2007 +0000 @@ -1315,7 +1315,9 @@ purple_prefs_connect_callback(toolbar, PIDGIN_PREFS_ROOT "/conversations/toolbar/wide", imhtmltoolbar_view_pref_changed, toolbar); - purple_prefs_trigger_callback(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide"); + g_signal_connect_data(G_OBJECT(toolbar), "realize", + G_CALLBACK(purple_prefs_trigger_callback), PIDGIN_PREFS_ROOT "/conversations/toolbar/wide", + NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED); #if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE); diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkmain.c Wed Dec 05 00:03:11 2007 +0000 @@ -609,7 +609,7 @@ #ifndef _WIN32 "c:dhmnl::s:v", #else - "c:dhnl::v", + "c:dhmnl::v", #endif long_options, NULL)) != -1) { switch (opt) { diff -r 306ee626481d -r e8e9a53b7694 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Sat Dec 01 06:46:25 2007 +0000 +++ b/pidgin/gtkutils.c Wed Dec 05 00:03:11 2007 +0000 @@ -2451,7 +2451,13 @@ g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy", G_CALLBACK(icon_filesel_delete_cb), dialog); #endif /* FILECHOOSER */ - return dialog->icon_filesel; + +#ifdef _WIN32 + g_signal_connect(G_OBJECT(dialog->icon_filesel), "show", + G_CALLBACK(winpidgin_ensure_onscreen), dialog->icon_filesel); +#endif + + return dialog->icon_filesel; } diff -r 306ee626481d -r e8e9a53b7694 po/POTFILES.in --- a/po/POTFILES.in Sat Dec 01 06:46:25 2007 +0000 +++ b/po/POTFILES.in Wed Dec 05 00:03:11 2007 +0000 @@ -118,6 +118,7 @@ libpurple/protocols/myspace/zap.c libpurple/protocols/novell/nmuser.c libpurple/protocols/novell/novell.c +libpurple/protocols/oscar/family_chatnav.c libpurple/protocols/oscar/flap_connection.c libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libicq.c