Mercurial > pidgin
changeset 25097:60d3ba8c9047
propagate from branch 'im.pidgin.pidgin' (head 1d533cebad7c0dbda8ec8ebee1334d27dcae5f9c)
to branch 'im.pidgin.soc.2008.themes' (head 6108b8f480f1589e219641d557022940902871cf)
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Mon, 30 Jun 2008 23:12:54 +0000 |
parents | 47b709962aab (diff) fbf72bbd1084 (current diff) |
children | 331a7a69d955 |
files | finch/libgnt/gntkeys.c libpurple/Makefile.am libpurple/protocols/qq/qq_proxy.c libpurple/protocols/qq/qq_proxy.h libpurple/protocols/qq/recv_core.c libpurple/protocols/qq/recv_core.h libpurple/protocols/qq/send_core.c libpurple/protocols/qq/send_core.h libpurple/protocols/qq/sendqueue.c libpurple/protocols/qq/sendqueue.h libpurple/protocols/qq/udp_proxy_s5.c libpurple/protocols/qq/udp_proxy_s5.h libpurple/util.c |
diffstat | 222 files changed, 7699 insertions(+), 5748 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Mon Jun 30 03:50:35 2008 +0000 +++ b/COPYRIGHT Mon Jun 30 23:12:54 2008 +0000 @@ -178,6 +178,7 @@ hjheins Hil Casey Ho +Andrew Hoffman Iain Holmes Joshua Honeycutt Nigel Horne @@ -388,6 +389,7 @@ Richard Stellingwerff Charlie Stockman David Stoddard +Adam Strzelecki Andreas Stührk Oleg Sukhodolsky Sun Microsystems
--- a/ChangeLog Mon Jun 30 03:50:35 2008 +0000 +++ b/ChangeLog Mon Jun 30 23:12:54 2008 +0000 @@ -5,19 +5,36 @@ * Ability to create custom smileys (currently only the MSN protocol utilizes the feature). (Thanks to Mauro Sérgio Ferreira Brasil, Marcus Lundblad, Jorge Villaseñor and other contributors) - * Yahoo! Japan now uses UTF-8, matching the behavior of official clients - and restoring compatibility with the web messenger (Yusuke Odate) + * Add a configure option, --with-system-ssl-certs to allow packagers + to specify a system-wide SSL CA certificates directory. When set, + we don't install our SSL CA certs, so it's important that the + libpurple package depend on the CA certificates. Pidgin: - * Custom buddy icons can now be added and removed to buddy list + * Custom buddy icons can now be added to and removed from buddy list entries via the buddy list entry right-click menu. * Resize large incoming custom smileys to a maximum of 96px on either side. + * Offer to add new buddies into the same contact as existing buddies + in the same group if the alias given is the same. General: * Group and Chat buddy list entries can now be given custom buddy icons. + Finch: + * Added "Invite..." menu to chats. + * Added "View All Logs" menu in the buddylist to display a list of all IM + logs. + * Added '/msgcolor' command to change colors of different classes of + messages in a conversation. See '/help msgcolor' for details. + +version 2.4.3 (??/??/2008): + libpurple: + * Yahoo! Japan now uses UTF-8, matching the behavior of official clients + and restoring compatibility with the web messenger (Yusuke Odate) + * Setting your buddy icon once again works for Yahoo! accounts. + version 2.4.2 (05/17/2008): libpurple: * In MySpaceIM, messages from spambots are discarded (Justin Williams)
--- a/ChangeLog.API Mon Jun 30 03:50:35 2008 +0000 +++ b/ChangeLog.API Mon Jun 30 23:12:54 2008 +0000 @@ -36,7 +36,7 @@ * GTK_IMHTML_CUSTOM_SMILEY flag for GtkIMHtml. * GTK+ Custom Smiley API. -version 2.4.2: +version 2.4.2 (05/17/2008): perl: Added: * Purple::Prefs::get_children_names.
--- a/configure.ac Mon Jun 30 03:50:35 2008 +0000 +++ b/configure.ac Mon Jun 30 23:12:54 2008 +0000 @@ -1207,8 +1207,8 @@ dnl # Check for D-Bus libraries dnl ####################################################################### -AC_ARG_ENABLE(dbus, [AC_HELP_STRING([--enable-dbus], [enable D-Bus support])], , enable_dbus=yes) -AC_ARG_ENABLE(nm, [AC_HELP_STRING([--enable-nm], [enable NetworkManager support (requires D-Bus)])], enable_nm=$enableval, enable_nm=yes) +AC_ARG_ENABLE(dbus, [AC_HELP_STRING([--disable-dbus], [disable D-Bus support])], , enable_dbus=yes) +AC_ARG_ENABLE(nm, [AC_HELP_STRING([--disable-nm], [disable NetworkManager support (requires D-Bus)])], enable_nm=$enableval, enable_nm=yes) if test "x$enable_dbus" = "xyes" ; then AC_CHECK_PROG(enable_dbus, dbus-binding-tool, yes, no) @@ -1561,6 +1561,18 @@ dnl # Thanks go to Evolution for the checks. dnl ####################################################################### +AC_ARG_WITH(with-system-ssl-certs, [AC_HELP_STRING([--with-system-ssl-certs=<dir>], [directory containing system-wide SSL CA certificates])]) + +SSL_CERTIFICATES_DIR="" +if ! test -z "$with_system_ssl_certs" ; then + if ! test -d "$with_system_ssl_certs" ; then + AC_MSG_ERROR([$with_system_ssl_certs does not exist, if this is the correct location please make sure that it exists.]) + fi + SSL_CERTIFICATES_DIR="$with_system_ssl_certs" +fi +AC_SUBST(SSL_CERTIFICATES_DIR) +AM_CONDITIONAL(INSTALL_SSL_CERTIFICATES, test "x$SSL_CERTIFICATES_DIR" = "x") + dnl These two are inverses of each other <-- stolen from evolution! AC_ARG_ENABLE(gnutls, @@ -2211,9 +2223,11 @@ AC_CHECK_HEADERS(termios.h) # sys/sysctl.h on OpenBSD 4.2 requires sys/param.h +# sys/sysctl.h on FreeBSD requires sys/types.h AC_CHECK_HEADERS(sys/param.h) AC_CHECK_HEADERS(sys/sysctl.h, [], [], [[ + #include <sys/types.h> #ifdef HAVE_PARAM_H # include <sys/param.h> #endif @@ -2409,6 +2423,9 @@ fi echo Build with NetworkManager..... : $enable_nm echo SSL Library/Libraries......... : $msg_ssl +if test "x$SSL_CERTIFICATES_DIR" != "x" ; then + eval eval echo SSL CA certificates directory. : $SSL_CERTIFICATES_DIR +fi echo Build with Cyrus SASL support. : $enable_cyrus_sasl echo Use kerberos 4 with zephyr.... : $kerberos echo Use external libzephyr........ : $zephyr
--- a/doc/gtkrc-2.0 Mon Jun 30 03:50:35 2008 +0000 +++ b/doc/gtkrc-2.0 Mon Jun 30 23:12:54 2008 +0000 @@ -45,7 +45,7 @@ # Change the color of the typing notification GtkIMHtml::typing-notification-color = "#ff0000" # Disable the typing notification - GtkIMHtml::typing-notification-enable = 1 + GtkIMHtml::typing-notification-enable = 0 # The following settings will change the behaviour in all GTK+ applications # Change the cursor color
--- a/finch/gntblist.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/gntblist.c Mon Jun 30 23:12:54 2008 +0000 @@ -2722,6 +2722,7 @@ PurpleConnection *gc; PurpleChat *chat; GHashTable *hash = NULL; + PurpleConversation *conv; account = purple_request_fields_get_account(fields, "account"); name = purple_request_fields_get_string(fields, "chat"); @@ -2730,7 +2731,16 @@ return; gc = purple_account_get_connection(account); - purple_conversation_new(PURPLE_CONV_TYPE_CHAT, account, name); + /* Create a new conversation now. This will give focus to the new window. + * But it's necessary to pretend that we left the chat, because otherwise + * a new conversation window will pop up when we finally join the chat. */ + if (!(conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, name, account))) { + conv = purple_conversation_new(PURPLE_CONV_TYPE_CHAT, account, name); + purple_conv_chat_left(PURPLE_CONV_CHAT(conv)); + } else { + purple_conversation_present(conv); + } + chat = purple_blist_find_chat(account, name); if (chat == NULL) { PurplePluginProtocolInfo *info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc)); @@ -2841,6 +2851,12 @@ } static void +view_all_logs_cb(GntMenuItem *item, gpointer n) +{ + finch_log_show(PURPLE_LOG_IM, NULL, NULL); +} + +static void menu_add_buddy_cb(GntMenuItem *item, gpointer null) { purple_blist_request_add_buddy(NULL, NULL, NULL, NULL); @@ -2905,6 +2921,11 @@ gnt_menu_add_item(GNT_MENU(sub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), view_log_cb, NULL); + item = gnt_menuitem_new(_("View All Logs")); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), "view-all-logs"); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENU_ITEM(item), view_all_logs_cb, NULL); + item = gnt_menuitem_new(_("Show")); gnt_menu_add_item(GNT_MENU(sub), item); subsub = gnt_menu_new(GNT_MENU_POPUP); @@ -3012,9 +3033,6 @@ gnt_widget_set_position(ggblist->window, purple_prefs_get_int(PREF_ROOT "/position/x"), purple_prefs_get_int(PREF_ROOT "/position/y")); - gnt_tree_set_col_width(GNT_TREE(ggblist->tree), 0, - purple_prefs_get_int(PREF_ROOT "/size/width") - 1); - gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->tree); ggblist->status = gnt_combo_box_new();
--- a/finch/gntblist.h Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/gntblist.h Mon Jun 30 23:12:54 2008 +0000 @@ -34,6 +34,10 @@ **********************************************************************/ /*@{*/ +/** + * Buddylist manager for finch. This decides the visility, ordering and hierarchy + * of the buddylist nodes. This also manages the creation of tooltips. + */ typedef struct { const char *id; /**< An identifier for the manager. */
--- a/finch/gntconv.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/gntconv.c Mon Jun 30 23:12:54 2008 +0000 @@ -38,10 +38,11 @@ #include "gntdebug.h" #include "gntlog.h" #include "gntplugin.h" +#include "gntpounce.h" #include "gntprefs.h" +#include "gntrequest.h" #include "gntsound.h" #include "gntstatus.h" -#include "gntpounce.h" #include "gnt.h" #include "gntbox.h" @@ -140,7 +141,7 @@ entry_key_pressed(GntWidget *w, FinchConv *ggconv) { const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry)); - if (*text == '/') + if (*text == '/' && *(text + 1) != '/') { PurpleConversation *conv = ggconv->active_conv; PurpleCmdStatus status; @@ -190,7 +191,7 @@ } else { - char *escape = g_markup_escape_text(text, -1); + char *escape = g_markup_escape_text((*text == '/' ? text + 1 : text), -1); char *apos = purple_strreplace(escape, "'", "'"); g_free(escape); escape = apos; @@ -557,6 +558,47 @@ } static void +invite_select_cb(FinchConv *fc, PurpleRequestFields *fields) +{ + PurpleConversation *conv = fc->active_conv; + const char *buddy = purple_request_fields_get_string(fields, "screenname"); + const char *message = purple_request_fields_get_string(fields, "message"); + serv_chat_invite(purple_conversation_get_gc(conv), + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), + message, buddy); + +} + +static void +invite_cb(GntMenuItem *item, gpointer ggconv) +{ + 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("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_string_new("message", _("Invite message"), NULL, FALSE); + purple_request_field_group_add_field(group, field); + purple_request_fields(finch_conv_get_handle(), _("Invite"), + NULL, + _("Please enter the name of the user " + "you wish to invite,\nalong with an optional invite message."), + fields, + _("OK"), G_CALLBACK(invite_select_cb), + _("Cancel"), NULL, + NULL, NULL, NULL, + ggconv); +} + +static void gg_create_menu(FinchConv *ggc) { GntWidget *menu, *sub; @@ -606,6 +648,10 @@ } generate_send_to_menu(ggc); + } else if (purple_conversation_get_type(ggc->active_conv) == PURPLE_CONV_TYPE_CHAT) { + item = gnt_menuitem_new(_("Invite...")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, invite_cb, ggc); } item = gnt_menuitem_new(_("View Log...")); @@ -1195,6 +1241,47 @@ } static PurpleCmdRet +cmd_message_color(PurpleConversation *conv, const char *cmd, char **args, char **error, gpointer data) +{ + int *msgclass = NULL; + int fg, bg; + + if (strcmp(args[0], "receive") == 0) + msgclass = &color_message_receive; + else if (strcmp(args[0], "send") == 0) + msgclass = &color_message_send; + else if (strcmp(args[0], "highlight") == 0) + msgclass = &color_message_highlight; + else if (strcmp(args[0], "action") == 0) + msgclass = &color_message_action; + else if (strcmp(args[0], "timestamp") == 0) + msgclass = &color_timestamp; + else { + if (error) + *error = g_strdup_printf(_("%s is not a valid message class. See '/help msgcolor' for valid message classes."), args[0]); + return PURPLE_CMD_STATUS_FAILED; + } + + fg = gnt_colors_get_color(args[1]); + if (fg == -EINVAL) { + if (error) + *error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[1]); + return PURPLE_CMD_STATUS_FAILED; + } + + bg = gnt_colors_get_color(args[2]); + if (bg == -EINVAL) { + if (error) + *error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[2]); + return PURPLE_CMD_STATUS_FAILED; + } + + init_pair(*msgclass, fg, bg); + + return PURPLE_CMD_STATUS_OK; +} + +static PurpleCmdRet users_command_cb(PurpleConversation *conv, const char *cmd, char **args, char **error, gpointer data) { FinchConv *fc = FINCH_GET_DATA(conv); @@ -1278,6 +1365,16 @@ PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL, cmd_show_window, _("statuses: Show the savedstatuses window."), finch_savedstatus_show_all); + /* Allow customizing the message colors using a command during run-time */ + purple_cmd_register("msgcolor", "www", PURPLE_CMD_P_DEFAULT, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL, + cmd_message_color, _("msgcolor <class> <foreground> <background>: " + "Set the color for different classes of messages in the conversation window.<br>" + " <class>: receive, send, highlight, action, timestamp<br>" + " <foreground/background>: black, red, green, blue, white, gray, darkgray, magenta, cyan, default<br><br>" + "EXAMPLE:<br> msgcolor send cyan default"), + NULL); + purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), PURPLE_CALLBACK(update_buddy_typing), NULL); purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(),
--- a/finch/gntft.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/gntft.c Mon Jun 30 23:12:54 2008 +0000 @@ -117,7 +117,9 @@ total_pct = 100 * total_bytes_xferred / total_file_size; } - title = g_strdup_printf(_("File Transfers - %d%% of %d files"), + title = g_strdup_printf(ngettext("File Transfers - %d%% of %d file", + "File Transfers - %d%% of %d files", + num_active_xfers), total_pct, num_active_xfers); gnt_screen_rename_widget((xfer_dialog->window), title); g_free(title);
--- a/finch/gntlog.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/gntlog.c Mon Jun 30 23:12:54 2008 +0000 @@ -61,8 +61,12 @@ if (viewer->contact != NULL) return g_direct_hash(viewer->contact); - return g_str_hash(viewer->screenname) + - g_str_hash(purple_account_get_username(viewer->account)); + if (viewer->account) { + return g_str_hash(viewer->screenname) + + g_str_hash(purple_account_get_username(viewer->account)); + } + + return (guint)viewer; } static gboolean log_viewer_equal(gconstpointer y, gconstpointer z) @@ -84,10 +88,14 @@ return FALSE; } - normal = g_strdup(purple_normalize(a->account, a->screenname)); - ret = (a->account == b->account) && - !strcmp(normal, purple_normalize(b->account, b->screenname)); - g_free(normal); + if (a->screenname && b->screenname) { + normal = g_strdup(purple_normalize(a->account, a->screenname)); + ret = (a->account == b->account) && + !strcmp(normal, purple_normalize(b->account, b->screenname)); + g_free(normal); + } else { + ret = (a == b); + } return ret; } @@ -348,14 +356,28 @@ return lv; } -void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account) { +static void +our_logging_blows(PurpleLogSet *set, PurpleLogSet *setagain, GList **list) +{ + /* The iteration happens on the first list. So we use the shorter list in front */ + if (set->type != PURPLE_LOG_IM) + return; + *list = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, set->name, set->account), *list); +} + +void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account) +{ struct log_viewer_hash_t *ht; FinchLogViewer *lv = NULL; const char *name = screenname; char *title; + GList *logs = NULL; + int size = 0; - g_return_if_fail(account != NULL); - g_return_if_fail(screenname != NULL); + if (type != PURPLE_LOG_IM) { + g_return_if_fail(account != NULL); + g_return_if_fail(screenname != NULL); + } ht = g_new0(struct log_viewer_hash_t, 1); @@ -383,20 +405,35 @@ } else { PurpleBuddy *buddy; - buddy = purple_find_buddy(account, screenname); - if (buddy != NULL) - name = purple_buddy_get_contact_alias(buddy); - - title = g_strdup_printf(_("Conversations with %s"), name); + if (screenname) { + buddy = purple_find_buddy(account, screenname); + if (buddy != NULL) + name = purple_buddy_get_contact_alias(buddy); + title = g_strdup_printf(_("Conversations with %s"), name); + } else { + title = g_strdup(_("All Conversations")); + } } - display_log_viewer(ht, purple_log_get_logs(type, screenname, account), - title, purple_log_get_total_size(type, screenname, account)); + if (screenname) { + logs = purple_log_get_logs(type, screenname, account); + size = purple_log_get_total_size(type, screenname, account); + } else { + /* This will happen only for IMs */ + GHashTable *table = purple_log_get_log_sets(); + g_hash_table_foreach(table, (GHFunc)our_logging_blows, &logs); + g_hash_table_destroy(table); + logs = g_list_sort(logs, purple_log_compare); + size = 0; + } + + display_log_viewer(ht, logs, title, size); g_free(title); } -void finch_log_show_contact(PurpleContact *contact) { +void finch_log_show_contact(PurpleContact *contact) +{ struct log_viewer_hash_t *ht; PurpleBlistNode *child; FinchLogViewer *lv = NULL;
--- a/finch/libgnt/gntbutton.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntbutton.c Mon Jun 30 23:12:54 2008 +0000 @@ -77,18 +77,6 @@ } static gboolean -gnt_button_key_pressed(GntWidget *widget, const char *key) -{ - if (strcmp(key, GNT_KEY_ENTER) == 0 || - strcmp(key, SAFE(cursor_down)) == 0) - { - gnt_widget_activate(widget); - return TRUE; - } - return FALSE; -} - -static gboolean gnt_button_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) { if (event == GNT_LEFT_MOUSE_DOWN) { @@ -106,23 +94,33 @@ g_free(button->priv); } +static gboolean +button_activate(GntBindable *bind, GList *null) +{ + gnt_widget_activate(GNT_WIDGET(bind)); + return TRUE; +} + static void gnt_button_class_init(GntWidgetClass *klass) { char *style; + GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); parent_class = GNT_WIDGET_CLASS(klass); parent_class->draw = gnt_button_draw; parent_class->map = gnt_button_map; parent_class->size_request = gnt_button_size_request; - parent_class->key_pressed = gnt_button_key_pressed; parent_class->clicked = gnt_button_clicked; parent_class->destroy = gnt_button_destroy; style = gnt_style_get_from_name(NULL, "small-button"); small_button = gnt_style_parse_bool(style); g_free(style); - GNTDEBUG; + + gnt_bindable_class_register_action(bindable, "activate", button_activate, + GNT_KEY_ENTER, NULL); + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass)); } static void
--- a/finch/libgnt/gntcolors.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntcolors.c Mon Jun 30 23:12:54 2008 +0000 @@ -29,6 +29,7 @@ #include <glib.h> +#include <errno.h> #include <stdlib.h> #include <string.h> @@ -168,7 +169,7 @@ color = -1; else { g_warning("Invalid color name: %s\n", key); - color = -1; + color = -EINVAL; } return color; }
--- a/finch/libgnt/gntcolors.h Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntcolors.h Mon Jun 30 23:12:54 2008 +0000 @@ -91,7 +91,7 @@ * * @param kfile The string value * - * @return A color + * @return A color. For an unknown color name, returns -EINVAL. * * @since 2.4.0 */
--- a/finch/libgnt/gntentry.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntentry.c Mon Jun 30 23:12:54 2008 +0000 @@ -580,11 +580,13 @@ while (text && text < end && g_unichar_isspace(g_utf8_get_char(text))) text = g_utf8_find_next_char(text, end); - ch = g_utf8_get_char(text); - while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { - gunichar cur = g_utf8_get_char(text); - if (!SAME(ch, cur)) - break; + if (text) { + ch = g_utf8_get_char(text); + while ((text = g_utf8_find_next_char(text, end)) != NULL && text <= end) { + gunichar cur = g_utf8_get_char(text); + if (!SAME(ch, cur)) + break; + } } return (text ? text : end); }
--- a/finch/libgnt/gntkeys.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntkeys.c Mon Jun 30 23:12:54 2008 +0000 @@ -80,6 +80,9 @@ INSERT_KEY("down", GNT_KEY_DOWN); INSERT_KEY("tab", "\t"); + INSERT_KEY("escape", "\033"); + INSERT_KEY("space", " "); + INSERT_KEY("return", GNT_KEY_ENTER); INSERT_KEY("menu", GNT_KEY_POPUP); INSERT_KEY("f1", GNT_KEY_F1); @@ -119,6 +122,9 @@ code[ind] = (c ? 1 : 'a') + ch; INSERT_COMB(str, code); } + if (c == 0) { + INSERT_COMB("tab", "\033\t"); + } } } c = 0;
--- a/finch/libgnt/gntmenu.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gntmenu.c Mon Jun 30 23:12:54 2008 +0000 @@ -283,6 +283,8 @@ do sub = sub->submenu; while (sub->submenu); if (gnt_widget_key_pressed(GNT_WIDGET(sub), text)) return TRUE; + if (menu->type != GNT_MENU_TOPLEVEL) + return FALSE; } if ((text[0] == 27 && text[1] == 0) || @@ -332,10 +334,12 @@ return TRUE; } } + if (gnt_bindable_perform_action_key(GNT_BINDABLE(widget), text)) + return TRUE; return org_key_pressed(widget, text); } - return FALSE; + return gnt_bindable_perform_action_key(GNT_BINDABLE(widget), text); } static void @@ -434,7 +438,7 @@ { GntWidget *widget = GNT_WIDGET(instance); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW | GNT_WIDGET_NO_BORDER | - GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_TRANSIENT); + GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_TRANSIENT | GNT_WIDGET_DISABLE_ACTIONS); GNTDEBUG; }
--- a/finch/libgnt/gnttree.c Mon Jun 30 03:50:35 2008 +0000 +++ b/finch/libgnt/gnttree.c Mon Jun 30 23:12:54 2008 +0000 @@ -110,13 +110,14 @@ gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)) width -= 2; + width -= 1; /* Exclude the scrollbar from the calculation */ for (i = 0, total = 0; i < tree->ncol ; i++) { if (tree->columns[i].flags & GNT_TREE_COLUMN_INVISIBLE) continue; if (tree->columns[i].flags & GNT_TREE_COLUMN_FIXED_SIZE) - width -= WIDTH(i) + 1; + width -= WIDTH(i) + (tree->priv->lastvisible != i); else - total += WIDTH(i) + 1; + total += WIDTH(i) + (tree->priv->lastvisible != i); } if (total == 0)
--- a/libpurple/Makefile.am Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/Makefile.am Mon Jun 30 23:12:54 2008 +0000 @@ -271,3 +271,9 @@ $(DBUS_CFLAGS) \ $(LIBXML_CFLAGS) \ $(NETWORKMANAGER_CFLAGS) + +# INSTALL_SSL_CERTIFICATES is true when SSL_CERTIFICATES_DIR is empty. +# We want to use SSL_CERTIFICATES_DIR when it's not empty. +if ! INSTALL_SSL_CERTIFICATES +AM_CPPFLAGS += -DSSL_CERTIFICATES_DIR=\"$(SSL_CERTIFICATES_DIR)\" +endif
--- a/libpurple/blist.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/blist.h Mon Jun 30 23:12:54 2008 +0000 @@ -31,13 +31,20 @@ #include <glib.h> +/** @copydoc _PurpleBuddyList */ typedef struct _PurpleBuddyList PurpleBuddyList; +/** @copydoc _PurpleBlistUiOps */ typedef struct _PurpleBlistUiOps PurpleBlistUiOps; +/** @copydoc _PurpleBlistNode */ typedef struct _PurpleBlistNode PurpleBlistNode; +/** @copydoc _PurpleChat */ typedef struct _PurpleChat PurpleChat; +/** @copydoc _PurpleGroup */ typedef struct _PurpleGroup PurpleGroup; +/** @copydoc _PurpleContact */ typedef struct _PurpleContact PurpleContact; +/** @copydoc _PurpleBuddy */ typedef struct _PurpleBuddy PurpleBuddy; /**************************************************************************/
--- a/libpurple/certificate.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/certificate.c Mon Jun 30 23:12:54 2008 +0000 @@ -745,8 +745,12 @@ x509_ca_paths = g_list_append(NULL, g_build_filename(DATADIR, "ca-certs", NULL)); #else +# ifdef SSL_CERTIFICATES_DIR + x509_ca_paths = g_list_append(NULL, SSL_CERTIFICATES_DIR); +# else x509_ca_paths = g_list_append(NULL, g_build_filename(DATADIR, "purple", "ca-certs", NULL)); +# endif #endif } @@ -787,8 +791,7 @@ for (cur = lst; cur; cur = cur->next) { x509_ca_element *el = cur->data; - /* TODO: Unsafe? */ - if ( !strcmp(dn, el->dn) ) { + if (el->dn && !strcmp(dn, el->dn)) { return el; } }
--- a/libpurple/cmds.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/cmds.h Mon Jun 30 23:12:54 2008 +0000 @@ -30,6 +30,7 @@ /**************************************************************************/ /*@{*/ +/** The possible results of running a command with purple_cmd_do_command(). */ typedef enum _PurpleCmdStatus { PURPLE_CMD_STATUS_OK, PURPLE_CMD_STATUS_FAILED, @@ -39,16 +40,31 @@ PURPLE_CMD_STATUS_WRONG_TYPE, } PurpleCmdStatus; +/** Commands registered with the core return one of these values when run. + * Normally, a command will want to return one of the first two; in some + * unusual cases, you might want to have several functions called for a + * particular command; in this case, they should return + * #PURPLE_CMD_RET_CONTINUE to cause the core to fall through to other + * commands with the same name. + */ typedef enum _PurpleCmdRet { - PURPLE_CMD_RET_OK, /**< Everything's okay. Don't look for another command to call. */ + PURPLE_CMD_RET_OK, /**< Everything's okay; Don't look for another command to call. */ PURPLE_CMD_RET_FAILED, /**< The command failed, but stop looking.*/ PURPLE_CMD_RET_CONTINUE, /**< Continue, looking for other commands with the same name to call. */ } PurpleCmdRet; #define PURPLE_CMD_FUNC(func) ((PurpleCmdFunc)func) +/** A function implementing a command, as passed to purple_cmd_register(). + * + * @todo document the arguments to these functions. + * */ typedef PurpleCmdRet (*PurpleCmdFunc)(PurpleConversation *, const gchar *cmd, gchar **args, gchar **error, void *data); +/** A unique integer representing a command registered with + * purple_cmd_register(), which can subsequently be passed to + * purple_cmd_unregister() to unregister that command. + */ typedef guint PurpleCmdId; typedef enum _PurpleCmdPriority { @@ -171,7 +187,7 @@ * include both the default formatting and any extra manual formatting. * @param errormsg If the command failed errormsg is filled in with the appropriate error * message. It must be freed by the caller with g_free(). - * @return A #PurpleCmdStatus indicated if the command succeeded or failed. + * @return A #PurpleCmdStatus indicating if the command succeeded or failed. */ PurpleCmdStatus purple_cmd_do_command(PurpleConversation *conv, const gchar *cmdline, const gchar *markup, gchar **errormsg);
--- a/libpurple/connection.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/connection.h Mon Jun 30 23:12:54 2008 +0000 @@ -27,6 +27,7 @@ #ifndef _PURPLE_CONNECTION_H_ #define _PURPLE_CONNECTION_H_ +/** @copydoc _PurpleConnection */ typedef struct _PurpleConnection PurpleConnection; /** @@ -121,7 +122,7 @@ */ PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR = 15, - /** Some other error occured which fits into none of the other + /** Some other error occurred which fits into none of the other * categories. */ /* purple_connection_error_reason() in connection.c uses the fact that @@ -223,6 +224,8 @@ void (*_purple_reserved3)(void); } PurpleConnectionUiOps; + +/* Represents an active connection on an account. */ struct _PurpleConnection { PurplePlugin *prpl; /**< The protocol plugin. */
--- a/libpurple/conversation.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/conversation.c Mon Jun 30 23:12:54 2008 +0000 @@ -98,7 +98,7 @@ char *displayed = NULL, *sent = NULL; int err = 0; - if (strlen(message) == 0) + if (*message == '\0') return; account = purple_conversation_get_account(conv);
--- a/libpurple/conversation.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/conversation.h Mon Jun 30 23:12:54 2008 +0000 @@ -32,11 +32,17 @@ /**************************************************************************/ +/** @copydoc _PurpleConversationUiOps */ typedef struct _PurpleConversationUiOps PurpleConversationUiOps; +/** @copydoc _PurpleConversation */ typedef struct _PurpleConversation PurpleConversation; +/** @copydoc _PurpleConvIm */ typedef struct _PurpleConvIm PurpleConvIm; +/** @copydoc _PurpleConvChat */ typedef struct _PurpleConvChat PurpleConvChat; +/** @copydoc _PurpleConvChatBuddy */ typedef struct _PurpleConvChatBuddy PurpleConvChatBuddy; +/** @copydoc _PurpleConvMessage */ typedef struct _PurpleConvMessage PurpleConvMessage; /**
--- a/libpurple/core.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/core.h Mon Jun 30 23:12:54 2008 +0000 @@ -1,4 +1,5 @@ /** + * @file core.h Startup and shutdown of libpurple * @defgroup core libpurple * @see @ref core-signals */ @@ -28,12 +29,36 @@ typedef struct PurpleCore PurpleCore; +/** Callbacks that fire at different points of the initialization and teardown + * of libpurple, along with a hook to return descriptive information about the + * UI. + */ typedef struct { + /** Called just after the preferences subsystem is initialized; the UI + * could use this callback to add some preferences it needs to be in + * place when other subsystems are initialized. + */ void (*ui_prefs_init)(void); - void (*debug_ui_init)(void); /* Unfortunate necessity. */ + /** Called just after the debug subsystem is initialized, but before + * just about every other component's initialization. The UI should + * use this hook to call purple_debug_set_ui_ops() so that debugging + * information for other components can be logged during their + * initialization. + */ + void (*debug_ui_init)(void); + /** Called after all of libpurple has been initialized. The UI should + * use this hook to set all other necessary UiOps structures. + * + * @see @ref ui-ops + */ void (*ui_init)(void); + /** Called after most of libpurple has been uninitialized. */ void (*quit)(void); + + /** Called by purple_core_get_ui_info(); should return the information + * documented there. + */ GHashTable* (*get_ui_info)(void); void (*_purple_reserved1)(void); @@ -64,17 +89,23 @@ void purple_core_quit(void); /** + * <p> * Calls purple_core_quit(). This can be used as the function * passed to purple_timeout_add() when you want to shutdown Purple * in a specified amount of time. When shutting down Purple * from a plugin, you must use this instead of purple_core_quit(); * for an immediate exit, use a timeout value of 0: - * purple_timeout_add(0, purple_core_quitcb, NULL); + * </p> + * + * <code>purple_timeout_add(0, purple_core_quitcb, NULL);</code> + * + * <p> * This is ensures that code from your plugin is not being * executed when purple_core_quit() is called. If the plugin * called purple_core_quit() directly, you would get a core dump * after purple_core_quit() executes and control returns to your * plugin because purple_core_quit() frees all plugins. + * </p> */ gboolean purple_core_quit_cb(gpointer unused); @@ -86,7 +117,8 @@ const char *purple_core_get_version(void); /** - * Returns the ID of the UI that is using the core. + * Returns the ID of the UI that is using the core, as passed to + * purple_core_init(). * * @return The ID of the UI that is currently using the core. */ @@ -95,7 +127,7 @@ /** * Returns a handle to the purple core. * - * This is used for such things as signals. + * This is used to connect to @ref core-signals "core signals". */ PurpleCore *purple_get_core(void); @@ -114,10 +146,10 @@ PurpleCoreUiOps *purple_core_get_ui_ops(void); /** - * Migrates from .gaim to .purple. + * Migrates from <tt>.gaim</tt> to <tt>.purple</tt>. * - * UIs MUST NOT call this if they have been told to use a custom - * user directory. + * UIs <strong>must not</strong> call this if they have been told to use a + * custom user directory. * * @return A boolean indicating success or migration failure. On failure, * the application must display an error to the user and then exit. @@ -125,20 +157,33 @@ gboolean purple_core_migrate(void); /** - * Ensures that only one instance is running. + * Ensures that only one instance is running. If libpurple is built with D-Bus + * support, this checks if another process owns the libpurple bus name and if + * so whether that process is using the same configuration directory as this + * process. * - * @return A boolean such that @c TRUE indicates that this is the first instance, - * whereas @c FALSE indicates that there is another instance running. + * @return @c TRUE if this is the first instance of libpurple running; + * @c FALSE if there is another instance running. * * @since 2.1.0 */ gboolean purple_core_ensure_single_instance(void); /** - * Returns a hashtable containing various information about the UI + * Returns a hash table containing various information about the UI. The + * following well-known entries may be in the table (along with any others the + * UI might choose to include): + * + * <dl> + * <dt><tt>name</tt></dt> + * <dd>the user-readable name for the UI.</dd> + * + * <dt><tt>version</tt></dt> + * <dd>a user-readable description of the current version of the UI.</dd> + * </dl> * * @return A GHashTable with strings for keys and values. This - * hash table must not be freed. + * hash table must not be freed and should not be modified. * * @since 2.1.0 *
--- a/libpurple/idle.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/idle.c Mon Jun 30 23:12:54 2008 +0000 @@ -252,7 +252,7 @@ PurpleAccount *account; account = purple_connection_get_account(gc); - idled_accts = g_list_remove(idled_accts, account); + set_account_unidle(account); } static void
--- a/libpurple/internal.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/internal.h Mon Jun 30 23:12:54 2008 +0000 @@ -140,6 +140,14 @@ # define G_MAXUINT32 ((guint32) 0xffffffff) #endif +#ifndef G_MAXSIZE +# if GLIB_SIZEOF_LONG == 8 +# define G_MAXSIZE ((gsize) 0xffffffffffffffff) +# else +# define G_MAXSIZE ((gsize) 0xffffffff) +# endif +#endif + #if GLIB_CHECK_VERSION(2,6,0) # include <glib/gstdio.h> #endif
--- a/libpurple/log.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/log.c Mon Jun 30 23:12:54 2008 +0000 @@ -1067,7 +1067,7 @@ set->normalized_name = g_strdup(purple_normalize(account, name)); /* Chat for .chat or .system at the end of the name to determine the type. */ - if (len > 7) { + if (len >= 7) { gchar *tmp = &name[len - 7]; if (!strcmp(tmp, ".system")) { set->type = PURPLE_LOG_SYSTEM; @@ -1083,7 +1083,7 @@ } /* Determine if this (account, name) combination exists as a buddy. */ - if (account != NULL) + if (account != NULL && name != NULL && *name != '\0') set->buddy = (purple_find_buddy(account, name) != NULL); else set->buddy = FALSE;
--- a/libpurple/nat-pmp.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/nat-pmp.c Mon Jun 30 23:12:54 2008 +0000 @@ -35,6 +35,10 @@ #include "signals.h" #include "network.h" +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + #ifdef HAVE_SYS_SYSCTL_H #include <sys/sysctl.h> #endif
--- a/libpurple/plugins/perl/perl-handlers.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/plugins/perl/perl-handlers.c Mon Jun 30 23:12:54 2008 +0000 @@ -383,6 +383,9 @@ case PURPLE_TYPE_BOXED: *((void **)copy_args[i]) = (void *)SvIV(sv_args[i]); break; + case PURPLE_TYPE_SUBTYPE: + *((void **)copy_args[i]) = purple_perl_ref_object(sv_args[i]); + break; default: break;
--- a/libpurple/plugins/ssl/ssl-gnutls.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Mon Jun 30 23:12:54 2008 +0000 @@ -54,8 +54,8 @@ If there are strange bugs, perhaps look here (yes, I am a hypocrite) */ gnutls_global_set_mem_functions( - (gnutls_alloc_function) g_malloc0, /* malloc */ - (gnutls_alloc_function) g_malloc0, /* secure malloc */ + (gnutls_alloc_function) g_malloc, /* malloc */ + (gnutls_alloc_function) g_malloc, /* secure malloc */ NULL, /* mem_is_secure */ (gnutls_realloc_function) g_realloc, /* realloc */ (gnutls_free_function) g_free /* free */
--- a/libpurple/privacy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/privacy.c Mon Jun 30 23:12:54 2008 +0000 @@ -241,6 +241,7 @@ gboolean restore) { GSList *list; + PurplePrivacyType type = account->perm_deny; switch (account->perm_deny) { case PURPLE_PRIVACY_ALLOW_ALL: @@ -254,10 +255,12 @@ case PURPLE_PRIVACY_DENY_ALL: if (!restore) { /* Empty the allow-list. */ + const char *norm = purple_normalize(account, who); for (list = account->permit; list != NULL;) { - char *who = list->data; + char *person = list->data; list = list->next; - purple_privacy_permit_remove(account, who, local); + if (strcmp(norm, person) != 0) + purple_privacy_permit_remove(account, person, local); } } purple_privacy_permit_add(account, who, local); @@ -273,6 +276,10 @@ default: g_return_if_reached(); } + + /* Notify the server if the privacy setting was changed */ + if (type != account->perm_deny && purple_account_is_connected(account)) + serv_set_permit_deny(purple_account_get_connection(account)); } /* @@ -286,15 +293,18 @@ gboolean restore) { GSList *list; + PurplePrivacyType type = account->perm_deny; switch (account->perm_deny) { case PURPLE_PRIVACY_ALLOW_ALL: if (!restore) { /* Empty the deny-list. */ + const char *norm = purple_normalize(account, who); for (list = account->deny; list != NULL; ) { char *person = list->data; list = list->next; - purple_privacy_deny_remove(account, person, local); + if (strcmp(norm, person) != 0) + purple_privacy_deny_remove(account, person, local); } } purple_privacy_deny_add(account, who, local); @@ -318,6 +328,10 @@ default: g_return_if_reached(); } + + /* Notify the server if the privacy setting was changed */ + if (type != account->perm_deny && purple_account_is_connected(account)) + serv_set_permit_deny(purple_account_get_connection(account)); } gboolean
--- a/libpurple/protocols/gg/gg.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/gg/gg.c Mon Jun 30 23:12:54 2008 +0000 @@ -343,7 +343,8 @@ { PurpleConnection *gc = (PurpleConnection *)action->context; - purple_request_file(action, "Load buddylist from file...", NULL, FALSE, + purple_request_file(action, _("Load buddylist from file..."), NULL, + FALSE, G_CALLBACK(ggp_callback_buddylist_load_ok), NULL, purple_connection_get_account(gc), NULL, NULL, gc); @@ -926,8 +927,10 @@ /* ----- INTERNAL CALLBACKS --------------------------------------------- */ /* ---------------------------------------------------------------------- */ -/* just a prototype */ +/* Prototypes */ static void ggp_set_status(PurpleAccount *account, PurpleStatus *status); +static int ggp_to_gg_status(PurpleStatus *status, char **msg); + /** * Handle change of the status of the buddy. @@ -1488,23 +1491,12 @@ break; case GG_EVENT_CONN_SUCCESS: { - PurpleAccount *account; - PurplePresence *presence; - PurpleStatus *status; - purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS\n"); purple_input_remove(gc->inpa); gc->inpa = purple_input_add(info->session->fd, PURPLE_INPUT_READ, ggp_callback_recv, gc); - /* gg_change_status(info->session, GG_STATUS_AVAIL); */ - - account = purple_connection_get_account(gc); - presence = purple_account_get_presence(account); - status = purple_presence_get_active_status(presence); - - ggp_set_status(account, status); purple_connection_set_state(gc, PURPLE_CONNECTED); ggp_buddylist_send(gc); } @@ -1692,6 +1684,8 @@ static void ggp_login(PurpleAccount *account) { PurpleConnection *gc; + PurplePresence *presence; + PurpleStatus *status; struct gg_login_params *glp; GGPInfo *info; @@ -1714,8 +1708,11 @@ glp->uin = ggp_get_uin(account); glp->password = (char *)purple_account_get_password(account); + presence = purple_account_get_presence(account); + status = purple_presence_get_active_status(presence); + glp->async = 1; - glp->status = GG_STATUS_AVAIL; + glp->status = ggp_to_gg_status(status, &glp->status_descr); glp->tls = 0; info->session = gg_login(glp); @@ -1826,22 +1823,15 @@ /* }}} */ /* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ -static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) +static int ggp_to_gg_status(PurpleStatus *status, char **msg) { - PurpleConnection *gc; - GGPInfo *info; - const char *status_id, *msg; + const char *status_id = purple_status_get_id(status); int new_status, new_status_descr; + const char *new_msg; - if (!purple_status_is_active(status)) - return; + g_return_val_if_fail(msg == NULL, 0); - gc = purple_account_get_connection(account); - info = gc->proto_data; - - status_id = purple_status_get_id(status); - - purple_debug_info("gg", "ggp_set_status: Requested status = %s\n", + purple_debug_info("gg", "ggp_to_gg_status: Requested status = %s\n", status_id); if (strcmp(status_id, "available") == 0) { @@ -1860,22 +1850,45 @@ new_status = GG_STATUS_AVAIL; new_status_descr = GG_STATUS_AVAIL_DESCR; purple_debug_info("gg", - "ggp_set_status: uknown status requested (status_id=%s)\n", + "ggp_set_status: unknown status requested (status_id=%s)\n", status_id); } - msg = purple_status_get_attr_string(status, "message"); + new_msg = purple_status_get_attr_string(status, "message"); + + if(new_msg) { + char *tmp = purple_markup_strip_html(new_msg); + *msg = charset_convert(tmp, "UTF-8", "CP1250"); + g_free(tmp); + + return new_status_descr; + } else { + *msg = NULL; + return new_status; + } +} +/* }}} */ - if (msg == NULL) { +/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ +static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) +{ + PurpleConnection *gc; + GGPInfo *info; + int new_status; + char *new_msg = NULL; + + if (!purple_status_is_active(status)) + return; + + gc = purple_account_get_connection(account); + info = gc->proto_data; + + new_status = ggp_to_gg_status(status, &new_msg); + + if (new_msg == NULL) { gg_change_status(info->session, new_status); } else { - gchar *tmp, *new_msg; - - tmp = charset_convert(msg, "UTF-8", "CP1250"); - new_msg = purple_markup_strip_html(tmp); - g_free(tmp); - - gg_change_status_descr(info->session, new_status_descr, new_msg); + gg_change_status_descr(info->session, new_status, new_msg); g_free(new_msg); }
--- a/libpurple/protocols/gg/search.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/gg/search.h Mon Jun 30 23:12:54 2008 +0000 @@ -130,7 +130,7 @@ * @param gc PurpleConnection. * @param form Filled in GGPSearchForm. * - * @return Sequence number of a search or 0 if an error occured. + * @return Sequence number of a search or 0 if an error occurred. */ guint32 ggp_search_start(PurpleConnection *gc, GGPSearchForm *form);
--- a/libpurple/protocols/irc/msgs.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon Jun 30 23:12:54 2008 +0000 @@ -122,7 +122,11 @@ void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args) { - purple_debug(PURPLE_DEBUG_INFO, "irc", "Unrecognized message: %s\n", args[0]); + char *clean; + /* This, too, should be escaped somehow (smarter) */ + clean = purple_utf8_salvage(args[0]); + purple_debug(PURPLE_DEBUG_INFO, "irc", "Unrecognized message: %s\n", clean); + g_free(clean); } void irc_msg_features(struct irc_conn *irc, const char *name, const char *from, char **args) @@ -211,7 +215,9 @@ /* This is an extended syntax, not in RFC 1459 */ int t1 = atoi(args[4]); time_t t2 = time(NULL); - msg = g_strdup_printf(_("Ban on %s by %s, set %ld seconds ago"), + msg = g_strdup_printf(ngettext("Ban on %s by %s, set %ld second ago", + "Ban on %s by %s, set %ld seconds ago", + t2 - t1), args[2], args[3], t2 - t1); } else { msg = g_strdup_printf(_("Ban on %s"), args[2]);
--- a/libpurple/protocols/irc/parse.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/irc/parse.c Mon Jun 30 23:12:54 2008 +0000 @@ -232,7 +232,7 @@ if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) { g_strfreev(encodings); - return g_strdup(string); + return NULL; } utf8 = g_convert(string, strlen(string), encodings[0], "UTF-8", NULL, NULL, &err); @@ -597,7 +597,7 @@ case 'n': case 'c': tmp = irc_send_convert(irc, tok); - g_string_append(string, tmp); + g_string_append(string, tmp ? tmp : tok); g_free(tmp); break; default: @@ -710,5 +710,10 @@ static void irc_parse_error_cb(struct irc_conn *irc, char *input) { - purple_debug(PURPLE_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", input); + char *clean; + /* This really should be escaped somehow that you can tell what + * the junk was -- but as it is, it can crash glib. */ + clean = purple_utf8_salvage(input); + purple_debug(PURPLE_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", clean); + g_free(clean); }
--- a/libpurple/protocols/jabber/auth.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/auth.c Mon Jun 30 23:12:54 2008 +0000 @@ -589,75 +589,6 @@ } } -/*! - * @brief Given the server challenge (message) and the key (password), calculate the HMAC-MD5 digest - * - * This is the crammd5 response. Inspired by cyrus-sasl's _sasl_hmac_md5() - */ -static void -auth_hmac_md5(const char *challenge, size_t challenge_len, const char *key, size_t key_len, guchar *digest) -{ - PurpleCipher *cipher; - PurpleCipherContext *context; - int i; - /* inner padding - key XORd with ipad */ - unsigned char k_ipad[65]; - /* outer padding - key XORd with opad */ - unsigned char k_opad[65]; - - cipher = purple_ciphers_find_cipher("md5"); - - /* if key is longer than 64 bytes reset it to key=MD5(key) */ - if (strlen(key) > 64) { - guchar keydigest[16]; - - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, (const guchar *)key, strlen(key)); - purple_cipher_context_digest(context, 16, keydigest, NULL); - purple_cipher_context_destroy(context); - - key = (char *)keydigest; - key_len = 16; - } - - /* - * the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected - */ - - /* start out by storing key in pads */ - memset(k_ipad, '\0', sizeof k_ipad); - memset(k_opad, '\0', sizeof k_opad); - memcpy(k_ipad, (void *)key, key_len); - memcpy(k_opad, (void *)key, key_len); - - /* XOR key with ipad and opad values */ - for (i=0; i<64; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - /* perform inner MD5 */ - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, k_ipad, 64); /* start with inner pad */ - purple_cipher_context_append(context, (const guchar *)challenge, challenge_len); /* then text of datagram */ - purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 1st pass */ - purple_cipher_context_destroy(context); - - /* perform outer MD5 */ - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, k_opad, 64); /* start with outer pad */ - purple_cipher_context_append(context, digest, 16); /* then results of 1st hash */ - purple_cipher_context_digest(context, 16, digest, NULL); /* finish up 2nd pass */ - purple_cipher_context_destroy(context); -} - static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data) { JabberIq *iq; @@ -703,14 +634,19 @@ jabber_iq_set_callback(iq, auth_old_result_cb, NULL); jabber_iq_send(iq); - } else if(js->stream_id && xmlnode_get_child(query, "crammd5")) { + } else if(js->stream_id && (x = xmlnode_get_child(query, "crammd5"))) { const char *challenge; - guchar digest[16]; - char h[17], *p; - int i; + gchar digest[33]; + PurpleCipherContext *hmac; - challenge = xmlnode_get_attrib(xmlnode_get_child(query, "crammd5"), "challenge"); - auth_hmac_md5(challenge, strlen(challenge), pw, strlen(pw), digest); + /* Calculate the MHAC-MD5 digest */ + challenge = xmlnode_get_attrib(x, "challenge"); + hmac = purple_cipher_context_new_by_name("hmac", NULL); + purple_cipher_context_set_option(hmac, "hash", "md5"); + purple_cipher_context_set_key(hmac, (guchar *)pw); + purple_cipher_context_append(hmac, (guchar *)challenge, strlen(challenge)); + purple_cipher_context_digest_to_str(hmac, 33, digest, NULL); + purple_cipher_context_destroy(hmac); /* Create the response query */ iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth"); @@ -723,11 +659,7 @@ x = xmlnode_new_child(query, "crammd5"); - /* Translate the digest to a hexadecimal notation */ - p = h; - for(i=0; i<16; i++, p+=2) - snprintf(p, 3, "%02x", digest[i]); - xmlnode_insert_data(x, h, -1); + xmlnode_insert_data(x, digest, 32); jabber_iq_set_callback(iq, auth_old_result_cb, NULL); jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/buddy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.c Mon Jun 30 23:12:54 2008 +0000 @@ -824,10 +824,14 @@ } if(jbr) { char *purdy = NULL; + const char *status_name = jabber_buddy_state_get_name(jbr->state); if(jbr->status) purdy = purple_strdup_withhtml(jbr->status); - tmp = g_strdup_printf("%s%s%s", jabber_buddy_state_get_name(jbr->state), - (purdy ? ": " : ""), + if(status_name && purdy && !strcmp(status_name, purdy)) + status_name = NULL; + + tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""), + ((status_name && purdy) ? ": " : ""), (purdy ? purdy : "")); purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp); g_free(tmp); @@ -964,6 +968,8 @@ for(resources = jbi->jb->resources; resources; resources = resources->next) { char *purdy = NULL; + const char *status_name = NULL; + jbr = resources->data; if(jbr->client.name) { @@ -987,10 +993,14 @@ } } + status_name = jabber_buddy_state_get_name(jbr->state); if(jbr->status) purdy = purple_strdup_withhtml(jbr->status); - tmp = g_strdup_printf("%s%s%s", jabber_buddy_state_get_name(jbr->state), - (purdy ? ": " : ""), + if(status_name && purdy && !strcmp(status_name, purdy)) + status_name = NULL; + + tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""), + ((status_name && purdy) ? ": " : ""), (purdy ? purdy : "")); purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp); g_free(tmp); @@ -1783,22 +1793,6 @@ } } -void jabber_buddy_get_info_chat(PurpleConnection *gc, int id, - const char *resource) -{ - JabberStream *js = gc->proto_data; - JabberChat *chat = jabber_chat_find_by_id(js, id); - char *full_jid; - - if(!chat) - return; - - full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource); - jabber_buddy_get_info_for_jid(js, full_jid); - g_free(full_jid); -} - - static void jabber_buddy_set_invisibility(JabberStream *js, const char *who, gboolean invisible) {
--- a/libpurple/protocols/jabber/buddy.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.h Mon Jun 30 23:12:54 2008 +0000 @@ -96,8 +96,6 @@ void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource); const char *jabber_buddy_get_status_msg(JabberBuddy *jb); void jabber_buddy_get_info(PurpleConnection *gc, const char *who); -void jabber_buddy_get_info_chat(PurpleConnection *gc, int id, - const char *resource); GList *jabber_blist_node_menu(PurpleBlistNode *node);
--- a/libpurple/protocols/jabber/chat.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/chat.c Mon Jun 30 23:12:54 2008 +0000 @@ -308,7 +308,7 @@ jabber_chat_part(chat, NULL); - chat->conv = NULL; + chat->left = TRUE; } void jabber_chat_destroy(JabberChat *chat) @@ -342,12 +342,18 @@ { JabberStream *js = gc->proto_data; JabberChat *chat; + JabberChatMember *jcm; chat = jabber_chat_find_by_id(js, id); if(!chat) return NULL; + jcm = g_hash_table_lookup(chat->members, who); + if (jcm != NULL && jcm->jid) + return g_strdup(jcm->jid); + + return g_strdup_printf("%s@%s/%s", chat->room, chat->server, who); }
--- a/libpurple/protocols/jabber/chat.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/chat.h Mon Jun 30 23:12:54 2008 +0000 @@ -49,6 +49,7 @@ PurpleRequestType config_dialog_type; void *config_dialog_handle; GHashTable *members; + gboolean left; } JabberChat; GList *jabber_chat_info(PurpleConnection *gc);
--- a/libpurple/protocols/jabber/jabber.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon Jun 30 23:12:54 2008 +0000 @@ -273,70 +273,10 @@ purple_circ_buffer_mark_read(js->write_buffer, ret); } -void jabber_send_raw(JabberStream *js, const char *data, int len) +static gboolean do_jabber_send_raw(JabberStream *js, const char *data, int len) { int ret; - - /* because printing a tab to debug every minute gets old */ - if(strcmp(data, "\t")) - purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s\n", - js->gsc ? " (ssl)" : "", data); - - /* If we've got a security layer, we need to encode the data, - * splitting it on the maximum buffer length negotiated */ - - purple_signal_emit(my_protocol, "jabber-sending-text", js->gc, &data); - if (data == NULL) - return; - -#ifdef HAVE_CYRUS_SASL - if (js->sasl_maxbuf>0) { - int pos; - - if (!js->gsc && js->fd<0) - return; - pos = 0; - if (len == -1) - len = strlen(data); - while (pos < len) { - int towrite; - const char *out; - unsigned olen; - - if ((len - pos) < js->sasl_maxbuf) - towrite = len - pos; - else - towrite = js->sasl_maxbuf; - - sasl_encode(js->sasl, &data[pos], towrite, &out, &olen); - pos += towrite; - - if (js->writeh == 0) - ret = jabber_do_send(js, out, olen); - else { - ret = -1; - errno = EAGAIN; - } - - if (ret < 0 && errno != EAGAIN) - purple_connection_error_reason (js->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Write error")); - else if (ret < olen) { - if (ret < 0) - ret = 0; - if (js->writeh == 0) - js->writeh = purple_input_add( - js->gsc ? js->gsc->fd : js->fd, - PURPLE_INPUT_WRITE, - jabber_send_cb, js); - purple_circ_buffer_append(js->write_buffer, - out + ret, olen - ret); - } - } - return; - } -#endif + gboolean success = TRUE; if (len == -1) len = strlen(data); @@ -348,11 +288,12 @@ errno = EAGAIN; } - if (ret < 0 && errno != EAGAIN) + if (ret < 0 && errno != EAGAIN) { purple_connection_error_reason (js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Write error")); - else if (ret < len) { + success = FALSE; + } else if (ret < len) { if (ret < 0) ret = 0; if (js->writeh == 0) @@ -362,7 +303,53 @@ purple_circ_buffer_append(js->write_buffer, data + ret, len - ret); } - return; + + return success; +} + +void jabber_send_raw(JabberStream *js, const char *data, int len) +{ + + /* because printing a tab to debug every minute gets old */ + if(strcmp(data, "\t")) + purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s\n", + js->gsc ? " (ssl)" : "", data); + + /* If we've got a security layer, we need to encode the data, + * splitting it on the maximum buffer length negotiated */ + + purple_signal_emit(my_protocol, "jabber-sending-text", js->gc, &data); + if (data == NULL) + return; + +#ifdef HAVE_CYRUS_SASL + if (js->sasl_maxbuf>0) { + int pos = 0; + + if (!js->gsc && js->fd<0) + return; + + if (len == -1) + len = strlen(data); + + while (pos < len) { + int towrite; + const char *out; + unsigned olen; + + towrite = MIN((len - pos), js->sasl_maxbuf); + + sasl_encode(js->sasl, &data[pos], towrite, &out, &olen); + pos += towrite; + + if (!do_jabber_send_raw(js, out, olen)) + break; + } + return; + } +#endif + + do_jabber_send_raw(js, data, len); } int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) @@ -388,9 +375,9 @@ g_free(txt); } -static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer timeout) +static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused) { - purple_timeout_remove(GPOINTER_TO_INT(timeout)); + purple_timeout_remove(js->keepalive_timeout); js->keepalive_timeout = -1; } @@ -414,7 +401,7 @@ xmlnode_set_namespace(ping, "urn:xmpp:ping"); js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc); - jabber_iq_set_callback(iq, jabber_pong_cb, GINT_TO_POINTER(js->keepalive_timeout)); + jabber_iq_set_callback(iq, jabber_pong_cb, NULL); jabber_iq_send(iq); } } @@ -443,12 +430,17 @@ jabber_stream_init(js); } - if(errno == EAGAIN) + if(len < 0 && errno == EAGAIN) return; - else + else { + if (len == 0) + purple_debug_info("jabber", "Server closed the connection.\n"); + else + purple_debug_info("jabber", "Disconnected: %s\n", g_strerror(errno)); purple_connection_error_reason (js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Read Error")); + } } static void @@ -483,9 +475,13 @@ jabber_parser_process(js, buf, len); if(js->reinit) jabber_stream_init(js); - } else if(errno == EAGAIN) { + } else if(len < 0 && errno == EAGAIN) { return; } else { + if (len == 0) + purple_debug_info("jabber", "Server closed the connection.\n"); + else + purple_debug_info("jabber", "Disconnected: %s\n", g_strerror(errno)); purple_connection_error_reason (js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Read Error")); @@ -627,7 +623,7 @@ js->write_buffer = purple_circ_buffer_new(512); js->old_length = 0; js->keepalive_timeout = -1; - js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain); + js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); if(!js->user) { purple_connection_error_reason (gc, @@ -1504,8 +1500,7 @@ if (full) { PurpleStatus *status; - PurpleValue *value; - + if(jb->subscription & JABBER_SUB_FROM) { if(jb->subscription & JABBER_SUB_TO) sub = _("Both"); @@ -1521,17 +1516,17 @@ else sub = _("None"); } - + purple_notify_user_info_add_pair(user_info, _("Subscription"), sub); - + status = purple_presence_get_active_status(presence); - value = purple_status_get_attr_value(status, "mood"); - if (value && purple_value_get_type(value) == PURPLE_TYPE_STRING && (mood = purple_value_get_string(value))) { - - value = purple_status_get_attr_value(status, "moodtext"); - if(value && purple_value_get_type(value) == PURPLE_TYPE_STRING) { - char *moodplustext = g_strdup_printf("%s (%s)",mood,purple_value_get_string(value)); - + mood = purple_status_get_attr_string(status, "mood"); + if(mood != NULL) { + const char *moodtext; + moodtext = purple_status_get_attr_string(status, "moodtext"); + if(moodtext != NULL) { + char *moodplustext = g_strdup_printf("%s (%s)", mood, moodtext); + purple_notify_user_info_add_pair(user_info, _("Mood"), moodplustext); g_free(moodplustext); } else
--- a/libpurple/protocols/jabber/libxmpp.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon Jun 30 23:12:54 2008 +0000 @@ -89,7 +89,7 @@ jabber_message_send_chat, /* chat_send */ jabber_keepalive, /* keepalive */ jabber_register_account, /* register_user */ - jabber_buddy_get_info_chat, /* get_cb_info */ + NULL, /* get_cb_info */ NULL, /* get_cb_away */ jabber_roster_alias_change, /* alias_buddy */ jabber_roster_group_change, /* group_buddy */
--- a/libpurple/protocols/jabber/pep.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/pep.h Mon Jun 30 23:12:54 2008 +0000 @@ -57,7 +57,7 @@ * @parameter id The item id of the requested item (may be NULL) * @parameter cb The callback to be used when this item is received * - * The items element passed to the callback will be NULL if any error occured (like a permission error, node doesn't exist etc.) + * The items element passed to the callback will be NULL if any error occurred (like a permission error, node doesn't exist etc.) */ void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb);
--- a/libpurple/protocols/jabber/presence.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/presence.c Mon Jun 30 23:12:54 2008 +0000 @@ -49,7 +49,7 @@ xmlnode *presence = user_data; char *chat_full_jid; - if(!chat->conv) + if(!chat->conv || chat->left) return; chat_full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, @@ -581,13 +581,13 @@ if(state == JABBER_BUDDY_STATE_ERROR) { char *title, *msg = jabber_parse_error(js, packet, NULL); - if(chat->conv) { + if (!chat->conv) { + title = g_strdup_printf(_("Error joining chat %s"), from); + purple_serv_got_join_chat_failed(js->gc, chat->components); + } else { title = g_strdup_printf(_("Error in chat %s"), from); if (g_hash_table_size(chat->members) == 0) serv_got_chat_left(js->gc, chat->id); - } else { - title = g_strdup_printf(_("Error joining chat %s"), from); - purple_serv_got_join_chat_failed(js->gc, chat->components); } purple_notify_error(js->gc, title, title, msg); g_free(title); @@ -609,8 +609,9 @@ /* If we haven't joined the chat yet, we don't care that someone * left, or it was us leaving after we closed the chat */ - if(!chat->conv) { - if(jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) + if (!chat->conv || chat->left) { + if (chat->left && + jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) jabber_chat_destroy(chat); jabber_id_free(jid); g_free(status);
--- a/libpurple/protocols/jabber/si.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/si.c Mon Jun 30 23:12:54 2008 +0000 @@ -63,6 +63,7 @@ char *rxqueue; size_t rxlen; gsize rxmaxlen; + int local_streamhost_fd; } JabberSIXfer; static PurpleXfer* @@ -347,7 +348,11 @@ g_free(jsx->rxqueue); jsx->rxqueue = NULL; - purple_xfer_start(xfer, source, NULL, -1); + /* Before actually starting sending the file, we need to wait until the + * recipient sends the IQ result with <streamhost-used/> + */ + purple_debug_info("jabber", "SOCKS5 connection negotiation completed. " + "Waiting for IQ result to start file transfer.\n"); } static void @@ -608,6 +613,7 @@ PurpleInputCondition cond) { PurpleXfer *xfer = data; + JabberSIXfer *jsx = xfer->data; int acceptfd; purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_connected_cb\n"); @@ -617,12 +623,13 @@ return; else if(acceptfd == -1) { purple_debug_warning("jabber", "accept: %s\n", g_strerror(errno)); - /* TODO: This should cancel the ft */ + /* Don't cancel the ft - allow it to fall to the next streamhost.*/ return; } purple_input_remove(xfer->watcher); close(source); + jsx->local_streamhost_fd = -1; xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ, jabber_si_xfer_bytestreams_send_read_cb, xfer); @@ -633,19 +640,30 @@ gpointer data) { PurpleXfer *xfer = data; - JabberSIXfer *jsx = xfer->data; + JabberSIXfer *jsx; xmlnode *query, *streamhost_used; const char *from, *type, *jid; GList *matched; /* TODO: This need to send errors if we don't see what we're looking for */ + /* Make sure that the xfer is actually still valid and we're not just receiving an old iq response */ + if (!g_list_find(js->file_transfers, xfer)) { + purple_debug_error("jabber", "Got bytestreams response for no longer existing xfer (%p)\n", xfer); + return; + } + /* In the case of a direct file transfer, this is expected to return */ - if(!jsx) + if(!xfer->data) return; - if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) + jsx = xfer->data; + + if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { + if (type && !strcmp(type, "error")) + purple_xfer_cancel_remote(xfer); return; + } if(!(from = xmlnode_get_attrib(packet, "from"))) return; @@ -659,22 +677,33 @@ if(!(jid = xmlnode_get_attrib(streamhost_used, "jid"))) return; - purple_debug_info("jabber", "jabber_si_connect_proxy_cb() will be looking at jsx %p: jsx->streamhosts is %p and jid is %p", + purple_debug_info("jabber", "jabber_si_connect_proxy_cb() will be looking at jsx %p: jsx->streamhosts is %p and jid is %s\n", jsx, jsx->streamhosts, jid); if(!(matched = g_list_find_custom(jsx->streamhosts, jid, jabber_si_compare_jid))) { gchar *my_jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource); - if (!strcmp(jid, my_jid)) + if (!strcmp(jid, my_jid)) { purple_debug_info("jabber", "Got local SOCKS5 streamhost-used.\n"); - else + purple_xfer_start(xfer, xfer->fd, NULL, -1); + } else { purple_debug_info("jabber", "streamhost-used does not match any proxy that was offered to target\n"); + purple_xfer_cancel_local(xfer); + } g_free(my_jid); return; } - /* TODO: Clean up the local SOCKS5 proxy - it isn't going to be used.*/ + /* Clean up the local streamhost - it isn't going to be used.*/ + if (xfer->watcher > 0) { + purple_input_remove(xfer->watcher); + xfer->watcher = 0; + } + if (jsx->local_streamhost_fd >= 0) { + close(jsx->local_streamhost_fd); + jsx->local_streamhost_fd = -1; + } jsx->streamhosts = g_list_remove_link(jsx->streamhosts, matched); g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL); @@ -692,14 +721,17 @@ JabberSIXfer *jsx; JabberIq *iq; xmlnode *query, *streamhost; - char *jid, port[6]; - const char *local_ip, *public_ip, *ft_proxies; + const char *ft_proxies; + char port[6]; GList *tmp; JabberBytestreamsStreamhost *sh, *sh2; + int streamhost_count = 0; jsx = xfer->data; jsx->listen_data = NULL; + /* I'm not sure under which conditions this can happen + * (it seems like it shouldn't be possible */ if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) { purple_xfer_unref(xfer); return; @@ -707,11 +739,6 @@ purple_xfer_unref(xfer); - if (sock < 0) { - purple_xfer_cancel_local(xfer); - return; - } - iq = jabber_iq_new_query(jsx->js, JABBER_IQ_SET, "http://jabber.org/protocol/bytestreams"); xmlnode_set_attrib(iq->node, "to", xfer->who); @@ -719,41 +746,45 @@ xmlnode_set_attrib(query, "sid", jsx->stream_id); - jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, + /* If we successfully started listening locally */ + if (sock >= 0) { + gchar *jid; + const char *local_ip, *public_ip; + + jsx->local_streamhost_fd = sock; + + jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource); - xfer->local_port = purple_network_get_port_from_fd(sock); - g_snprintf(port, sizeof(port), "%hu", xfer->local_port); - - /* TODO: Should there be an option to not use the local host as a ft proxy? - * (to prevent revealing IP address, etc.) */ + xfer->local_port = purple_network_get_port_from_fd(sock); + g_snprintf(port, sizeof(port), "%hu", xfer->local_port); - /* Include the localhost's IP (for in-network transfers) */ - local_ip = purple_network_get_local_system_ip(jsx->js->fd); - if (strcmp(local_ip, "0.0.0.0") != 0) - { - streamhost = xmlnode_new_child(query, "streamhost"); - xmlnode_set_attrib(streamhost, "jid", jid); - xmlnode_set_attrib(streamhost, "host", local_ip); - xmlnode_set_attrib(streamhost, "port", port); + /* Include the localhost's IP (for in-network transfers) */ + local_ip = purple_network_get_local_system_ip(jsx->js->fd); + if (strcmp(local_ip, "0.0.0.0") != 0) { + streamhost_count++; + streamhost = xmlnode_new_child(query, "streamhost"); + xmlnode_set_attrib(streamhost, "jid", jid); + xmlnode_set_attrib(streamhost, "host", local_ip); + xmlnode_set_attrib(streamhost, "port", port); + } + + /* Include the public IP (assuming that there is a port mapped somehow) */ + public_ip = purple_network_get_my_ip(jsx->js->fd); + if (strcmp(public_ip, local_ip) != 0 && strcmp(public_ip, "0.0.0.0") != 0) { + streamhost_count++; + streamhost = xmlnode_new_child(query, "streamhost"); + xmlnode_set_attrib(streamhost, "jid", jid); + xmlnode_set_attrib(streamhost, "host", public_ip); + xmlnode_set_attrib(streamhost, "port", port); + } + + g_free(jid); + + /* The listener for the local proxy */ + xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, + jabber_si_xfer_bytestreams_send_connected_cb, xfer); } - /* Include the public IP (assuming that there is a port mapped somehow) */ - /* TODO: Check that it isn't the same as above and is a valid IP */ - public_ip = purple_network_get_my_ip(jsx->js->fd); - if (strcmp(public_ip, local_ip) != 0) - { - streamhost = xmlnode_new_child(query, "streamhost"); - xmlnode_set_attrib(streamhost, "jid", jid); - xmlnode_set_attrib(streamhost, "host", public_ip); - xmlnode_set_attrib(streamhost, "port", port); - } - - g_free(jid); - - /* The listener for the local proxy */ - xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, - jabber_si_xfer_bytestreams_send_connected_cb, xfer); - /* insert proxies here */ ft_proxies = purple_account_get_string(xfer->account, "ft_proxies", NULL); if (ft_proxies) { @@ -778,11 +809,12 @@ g_snprintf(port, sizeof(port), "%hu", portnum); - purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p", + purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p\n", jsx, jsx->streamhosts, i, ft_proxy_list[i]); if(g_list_find_custom(jsx->streamhosts, ft_proxy_list[i], jabber_si_compare_jid) != NULL) continue; + streamhost_count++; streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", ft_proxy_list[i]); xmlnode_set_attrib(streamhost, "host", ft_proxy_list[i]); @@ -812,6 +844,7 @@ if(g_list_find_custom(jsx->streamhosts, sh->jid, jabber_si_compare_jid) != NULL) continue; + streamhost_count++; streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", sh->jid); xmlnode_set_attrib(streamhost, "host", sh->host); @@ -827,6 +860,14 @@ jsx->streamhosts = g_list_prepend(jsx->streamhosts, sh2); } + /* We have no way of transferring, cancel the transfer */ + if (streamhost_count == 0) { + jabber_iq_free(iq); + /* We should probably notify the target, but this really shouldn't ever happen */ + purple_xfer_cancel_local(xfer); + return; + } + jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer); jabber_iq_send(iq); @@ -841,13 +882,14 @@ purple_xfer_ref(xfer); jsx = xfer->data; + + /* TODO: Should there be an option to not use the local host as a ft proxy? + * (to prevent revealing IP address, etc.) */ jsx->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM, jabber_si_xfer_bytestreams_listen_cb, xfer); if (jsx->listen_data == NULL) { - purple_xfer_unref(xfer); - /* XXX: couldn't open a port, we're fscked */ - purple_xfer_cancel_local(xfer); - return; + /* We couldn't open a local port. Perhaps we can use a proxy. */ + jabber_si_xfer_bytestreams_listen_cb(-1, xfer); } } @@ -956,7 +998,8 @@ purple_network_listen_cancel(jsx->listen_data); if (jsx->iq_id != NULL) jabber_iq_remove_callback_by_id(js, jsx->iq_id); - + if (jsx->local_streamhost_fd >= 0) + close(jsx->local_streamhost_fd); if (jsx->connect_timeout > 0) purple_timeout_remove(jsx->connect_timeout); @@ -1164,6 +1207,7 @@ { xfer->data = jsx = g_new0(JabberSIXfer, 1); jsx->js = js; + jsx->local_streamhost_fd = -1; purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init); purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send); @@ -1183,9 +1227,6 @@ js = gc->proto_data; - if(!purple_find_buddy(gc->account, who) || !jabber_buddy_find(js, who, FALSE)) - return; - xfer = jabber_si_new_xfer(gc, who); if (file) @@ -1237,6 +1278,7 @@ return; jsx = g_new0(JabberSIXfer, 1); + jsx->local_streamhost_fd = -1; for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) { const char *var = xmlnode_get_attrib(field, "var");
--- a/libpurple/protocols/jabber/xdata.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/jabber/xdata.c Mon Jun 30 23:12:54 2008 +0000 @@ -201,7 +201,7 @@ xmlnode *fn, *x; PurpleRequestFields *fields; PurpleRequestFieldGroup *group; - PurpleRequestField *field; + PurpleRequestField *field = NULL; char *title = NULL; char *instructions = NULL; @@ -232,10 +232,6 @@ if(!label) label = var; - if((valuenode = xmlnode_get_child(fn, "value"))) - value = xmlnode_get_data(valuenode); - - if(!strcmp(type, "text-private")) { if((valuenode = xmlnode_get_child(fn, "value"))) value = xmlnode_get_data(valuenode); @@ -333,14 +329,16 @@ g_hash_table_replace(data->fields, g_strdup(var), GINT_TO_POINTER(JABBER_X_DATA_BOOLEAN)); g_free(value); - } else if(!strcmp(type, "fixed") && value) { + } else if(!strcmp(type, "fixed")) { if((valuenode = xmlnode_get_child(fn, "value"))) value = xmlnode_get_data(valuenode); - field = purple_request_field_label_new("", value); - purple_request_field_group_add_field(group, field); + if(value != NULL) { + field = purple_request_field_label_new("", value); + purple_request_field_group_add_field(group, field); - g_free(value); + g_free(value); + } } else if(!strcmp(type, "hidden")) { if((valuenode = xmlnode_get_child(fn, "value"))) value = xmlnode_get_data(valuenode);
--- a/libpurple/protocols/msn/contact.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/contact.c Mon Jun 30 23:12:54 2008 +0000 @@ -1,5 +1,5 @@ /** - * @file contact.c + * @file contact.c * get MSN contacts via SOAP request * created by MaYuan<mayuan2006@gmail.com> * @@ -80,7 +80,7 @@ state->session = session; return state; -} +} void msn_callback_state_free(MsnCallbackState *state) @@ -217,7 +217,7 @@ g_return_if_fail(contact->session != NULL); g_return_if_fail(contact->session->user != NULL); g_return_if_fail(contact->session->user->passport != NULL); - + purple_debug_info("msnab","Creating an Address Book.\n"); body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport); @@ -247,7 +247,7 @@ user->membership_id[list] = atoi(member_id); } - msn_got_lst_user(session, user, 1 << list, NULL); + msn_got_lst_user(session, user, 1 << list, NULL); g_free(passport); g_free(type); @@ -269,7 +269,7 @@ char *lastchange_str = xmlnode_get_data(lastchange); xmlnode *membership; - purple_debug_info("msncl","last change: %s\n", lastchange_str); + purple_debug_info("msncl","last change: %s\n", lastchange_str); purple_account_set_string(session->account, "CLLastChange", lastchange_str); @@ -480,7 +480,7 @@ if (phone_type && !strcmp(phone_type, "ContactPhoneMobile")) { xmlnode *number; - + if ((number = xmlnode_get_child(contact_phone, "number"))) { xmlnode *messenger_enabled; char *is_messenger_enabled = NULL; @@ -489,8 +489,8 @@ mobile_number = xmlnode_get_data(number); if (mobile_number && - (messenger_enabled = xmlnode_get_child(contact_phone, "isMessengerEnabled")) - && (is_messenger_enabled = xmlnode_get_data(messenger_enabled)) + (messenger_enabled = xmlnode_get_child(contact_phone, "isMessengerEnabled")) + && (is_messenger_enabled = xmlnode_get_data(messenger_enabled)) && !strcmp(is_messenger_enabled, "true")) mobile = TRUE; @@ -679,7 +679,7 @@ gchar *errorcode = xmlnode_get_data(faultnode); purple_debug_info("MSNAB", "Error Code: %s\n", errorcode); - + if (g_str_equal(errorcode, "ABDoesNotExist")) { g_free(errorcode); return TRUE; @@ -823,7 +823,7 @@ if (resp != NULL) { MsnUserList *userlist = session->userlist; MsnUser *user; - + purple_debug_info("MSNCL","Contact added successfully\n"); // the code this block is replacing didn't send ADL for yahoo contacts, @@ -921,7 +921,7 @@ } void -msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, +msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, const char *passport, const char *groupId) { MsnUserList *userlist; @@ -934,11 +934,11 @@ g_return_if_fail(contact != NULL); g_return_if_fail(contact->session != NULL); g_return_if_fail(contact->session->userlist != NULL); - + userlist = contact->session->userlist; if (!strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) { - + user = msn_userlist_find_add_user(userlist, passport, passport); if (state->action & MSN_ADD_BUDDY) { @@ -956,13 +956,13 @@ return; } - purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, + purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, msn_userlist_find_group_name(userlist, groupId)); user = msn_userlist_find_user(userlist, passport); if (user == NULL) { purple_debug_warning("MSNCL", "Unable to retrieve user %s from the userlist!\n", passport); - msn_callback_state_free(state); + msn_callback_state_free(state); return; /* guess this never happened! */ } @@ -1007,7 +1007,7 @@ /*delete a Contact*/ void msn_delete_contact(MsnContact *contact, const char *contactId) -{ +{ gchar *body = NULL; gchar *contact_id_xml = NULL ; MsnCallbackState *state; @@ -1045,7 +1045,7 @@ purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); } } - + msn_callback_state_free(state); } @@ -1057,15 +1057,15 @@ MsnCallbackState *state; gchar *body, *contact_id_xml; const gchar *groupId; - + g_return_if_fail(passport != NULL); g_return_if_fail(group_name != NULL); g_return_if_fail(contact != NULL); g_return_if_fail(contact->session != NULL); g_return_if_fail(contact->session->userlist != NULL); - + userlist = contact->session->userlist; - + groupId = msn_userlist_find_group_id(userlist, group_name); if (groupId != NULL) { purple_debug_info("MSNCL", "Deleting user %s from group %s\n", passport, group_name); @@ -1073,9 +1073,9 @@ purple_debug_warning("MSNCL", "Unable to retrieve group id from group %s !\n", group_name); return; } - + user = msn_userlist_find_user(userlist, passport); - + if (user == NULL) { purple_debug_warning("MSNCL", "Unable to retrieve user from passport %s!\n", passport); return; @@ -1099,7 +1099,7 @@ xmlnode_from_str(body, -1)), MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_del_contact_from_group_read_cb, state); - + g_free(contact_id_xml); g_free(body); } @@ -1198,7 +1198,7 @@ } else { /* list == MSN_LIST_AL || list == MSN_LIST_BL */ partner_scenario = MSN_PS_BLOCK_UNBLOCK; - + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport); } @@ -1226,13 +1226,13 @@ g_return_if_fail(state != NULL); g_return_if_fail(state->session != NULL); g_return_if_fail(state->session->contact != NULL); - + if (resp != NULL) { purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); if (state->list_id == MSN_LIST_RL) { MsnUser *user = msn_userlist_find_user(state->session->userlist, state->who); - + if (user != NULL) { msn_user_set_op(user, MSN_LIST_RL_OP); } @@ -1274,9 +1274,9 @@ member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, state->who); - body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, + body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], - MsnMemberRole[list], + MsnMemberRole[list], member); msn_soap_message_send(contact->session, @@ -1323,9 +1323,9 @@ msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { MsnCallbackState *state = data; - + purple_debug_info("MSNCL", "Group request successful.\n"); - + g_return_if_fail(state->session != NULL); g_return_if_fail(state->session->userlist != NULL); g_return_if_fail(state->session->contact != NULL); @@ -1338,13 +1338,13 @@ if (state) { MsnSession *session = state->session; MsnUserList *userlist = session->userlist; - + if (state->action & MSN_RENAME_GROUP) { msn_userlist_rename_group_id(session->userlist, state->guid, state->new_group_name); } - + if (state->action & MSN_ADD_GROUP) { /* the response is taken from http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions @@ -1364,7 +1364,7 @@ state->who, state->new_group_name); } else if (state->action & MSN_MOVE_BUDDY) { - msn_add_contact_to_group(session->contact, state, state->who, guid); + msn_add_contact_to_group(session->contact, state, state->who, guid); g_free(guid); return; } @@ -1374,16 +1374,16 @@ state->new_group_name); } } - + if (state->action & MSN_DEL_GROUP) { GList *l; - + msn_userlist_remove_group_id(session->userlist, state->guid); for (l = userlist->users; l != NULL; l = l->next) { msn_user_remove_group_id( (MsnUser *)l->data, state->guid); } } - + msn_callback_state_free(state); } } @@ -1396,7 +1396,7 @@ g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - + purple_debug_info("MSNCL","Adding group %s to contact list.\n", group_name); if (state == NULL) { @@ -1429,13 +1429,13 @@ const gchar *guid; g_return_if_fail(session != NULL); - + g_return_if_fail(group_name != NULL); purple_debug_info("MSNCL","Deleting group %s from contact list\n", group_name); - + guid = msn_userlist_find_group_id(session->userlist, group_name); - - /* if group uid we need to del is NULL, + + /* if group uid we need to del is NULL, * we need to delete nothing */ if (guid == NULL) { @@ -1451,7 +1451,7 @@ state = msn_callback_state_new(session); msn_callback_state_set_action(state, MSN_DEL_GROUP); msn_callback_state_set_guid(state, guid); - + body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid); msn_soap_message_send(session, @@ -1470,14 +1470,14 @@ gchar *body = NULL; const gchar * guid; MsnCallbackState *state; - + g_return_if_fail(session != NULL); g_return_if_fail(session->userlist != NULL); g_return_if_fail(old_group_name != NULL); g_return_if_fail(new_group_name != NULL); - + purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name); - + guid = msn_userlist_find_group_id(session->userlist, old_group_name); if (guid == NULL) return; @@ -1492,10 +1492,10 @@ } msn_callback_state_set_action(state, MSN_RENAME_GROUP); - + body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE, guid, new_group_name); - + msn_soap_message_send(session, msn_soap_message_new(MSN_GROUP_RENAME_SOAP_ACTION, xmlnode_from_str(body, -1)),
--- a/libpurple/protocols/msn/contact.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/contact.h Mon Jun 30 23:12:54 2008 +0000 @@ -349,7 +349,7 @@ #define MSN_GROUP_RENAME_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupUpdate" #define MSN_GROUP_RENAME_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groups><Group><groupId>%s</groupId><groupInfo><name>%s</name></groupInfo><propertiesChanged>GroupName </propertiesChanged></Group></groups></ABGroupUpdate></soap:Body></soap:Envelope>" -typedef enum +typedef enum { MSN_ADD_BUDDY = 0x01, MSN_MOVE_BUDDY = 0x02, @@ -383,7 +383,7 @@ MsnSession *session; }; -typedef enum +typedef enum { MSN_PS_INITIAL, MSN_PS_SAVE_CONTACT, @@ -404,34 +404,34 @@ void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid); void msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name); -void msn_callback_state_set_new_group_name(MsnCallbackState *state, +void msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name); void msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid); void msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id); -void msn_callback_state_set_action(MsnCallbackState *state, +void msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action); void msn_contact_connect(MsnContact *contact); -void msn_get_contact_list(MsnContact * contact, +void msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update); -void msn_get_address_book(MsnContact *contact, +void msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char * update, const char * gupdate); /* contact SOAP operations */ void msn_update_contact(MsnContact *contact, const char* nickname); -void msn_add_contact(MsnContact *contact, MsnCallbackState *state, +void msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport); void msn_delete_contact(MsnContact *contact, const char *contactId); -void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, +void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, const char *passport, const char *groupId); -void msn_del_contact_from_group(MsnContact *contact, const char *passport, +void msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name); /* group operations */ -void msn_add_group(MsnSession *session, MsnCallbackState *state, +void msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name); void msn_del_group(MsnSession *session, const gchar *group_name); void msn_contact_rename_group(MsnSession *session, const char *old_group_name,
--- a/libpurple/protocols/msn/dialog.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/dialog.c Mon Jun 30 23:12:54 2008 +0000 @@ -135,7 +135,7 @@ passport); } - purple_request_action(gc, NULL, msg, reason, PURPLE_DEFAULT_ACTION_NONE, + purple_request_action(gc, NULL, msg, reason, PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), data->who, NULL, data, 2, _("Yes"), G_CALLBACK(msn_add_cb),
--- a/libpurple/protocols/msn/error.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/error.c Mon Jun 30 23:12:54 2008 +0000 @@ -259,7 +259,7 @@ { char buf[MSN_BUF_LEN]; gboolean debug; - + g_snprintf(buf, sizeof(buf), _("MSN Error: %s\n"), msn_error_get_text(type, &debug)); if (debug)
--- a/libpurple/protocols/msn/msn.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/msn.c Mon Jun 30 23:12:54 2008 +0000 @@ -1594,10 +1594,10 @@ MsnSession *session; session = gc->proto_data; - + g_return_if_fail(session != NULL); g_return_if_fail(session->userlist != NULL); - + if (msn_userlist_find_group_with_name(session->userlist, old_name) != NULL) { msn_contact_rename_group(session, old_name, group->name); @@ -1677,7 +1677,7 @@ purple_debug_info("MSN", "This group can't be removed, returning.\n"); return ; } - + msn_del_group(session, group->name); }
--- a/libpurple/protocols/msn/msnutils.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/msnutils.c Mon Jun 30 23:12:54 2008 +0000 @@ -169,7 +169,7 @@ gchar *base64, *retval; g_return_val_if_fail(str != NULL, NULL); - + base64 = purple_base64_encode((guchar *)str, strlen(str)); retval = g_strdup_printf("=?utf-8?B?%s?=", base64); g_free(base64); @@ -509,7 +509,7 @@ *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges */ #define BUFSIZE 256 -void +void msn_handle_chl(char *input, char *output) { PurpleCipher *cipher; @@ -538,7 +538,7 @@ /* Split it into four integers */ md5Parts = (unsigned int *)md5Hash; - for(i=0; i<4; i++){ + for(i=0; i<4; i++){ /* adjust endianess */ md5Parts[i] = GUINT_TO_LE(md5Parts[i]); @@ -578,7 +578,7 @@ /* adjust endianness */ for(i=0; i<4; i++) - newHashParts[i] = GUINT_TO_LE(newHashParts[i]); + newHashParts[i] = GUINT_TO_LE(newHashParts[i]); /* make a string of the parts */ newHash = (unsigned char *)newHashParts;
--- a/libpurple/protocols/msn/notification.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Jun 30 23:12:54 2008 +0000 @@ -34,15 +34,6 @@ static MsnTable *cbs_table; -/**************************************************************************** - * Local Function Prototype - ****************************************************************************/ - -static void msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len); -static void -msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport, - MsnListOp list_op, MsnUserType type); - /************************************************************************** * Main **************************************************************************/ @@ -336,7 +327,7 @@ } /* - * Windows Live Messenger 8.0 + * Windows Live Messenger 8.0 * Notice :CVR String discriminate! * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx * to see the Local ID @@ -430,7 +421,7 @@ char *payload; gsize payload_len; int type; - + cmdproc = session->notification->cmdproc; g_return_if_fail(msg != NULL); payload = msn_message_gen_payload(msg, &payload_len); @@ -649,7 +640,7 @@ { MsnTransaction *trans; purple_debug_info("MSN Notification","Sending ADL with payload: %s\n", payload); - trans = msn_transaction_new(cmdproc, "ADL","%" G_GSIZE_FORMAT, payload_len); + trans = msn_transaction_new(cmdproc, "ADL", "%i", payload_len); msn_transaction_set_payload(trans, payload, payload_len); msn_cmdproc_send_trans(cmdproc, trans); } @@ -709,8 +700,8 @@ } display_name = purple_connection_get_display_name(session->account->gc); - if (display_name - && strcmp(display_name, + if (display_name + && strcmp(display_name, purple_account_get_username(session->account))) { msn_act_id(session->account->gc, display_name); } @@ -755,15 +746,15 @@ purple_debug_misc("MSN Notification", "Parsing received ADL XML data\n"); g_return_if_fail(payload != NULL); - + root = xmlnode_from_str(payload, (gssize) len); - + if (root == NULL) { purple_debug_info("MSN Notification", "Invalid XML!\n"); return; } for (domain_node = xmlnode_get_child(root, "d"); domain_node; domain_node = xmlnode_get_next_twin(domain_node)) { - const gchar * domain = NULL; + const gchar * domain = NULL; xmlnode *contact_node = NULL; domain = xmlnode_get_attrib(domain_node, "n"); @@ -1024,13 +1015,13 @@ MsnSlpLink *slplink; MsnUser *user; + /* Tell libpurple that the user has signed off */ user = msn_userlist_find_user(cmdproc->session->userlist, cmd->params[0]); - user->status = "offline"; msn_user_update(user); + /* If we have an open MsnSlpLink with the user then close it */ slplink = msn_session_find_slplink(cmdproc->session, cmd->params[0]); - if (slplink != NULL) msn_slplink_destroy(slplink); @@ -1300,7 +1291,7 @@ type = cmd->params[1]; if (!strcmp(type, "MFN")) { friendlyname = purple_url_decode(cmd->params[2]); - + msn_update_contact(session->contact, friendlyname); purple_connection_set_display_name( @@ -1649,12 +1640,12 @@ purple_debug_error("MSN","Unable to parse GCF payload into a XML tree"); return; } - + buf = xmlnode_to_formatted_str(root, &xmllen); /* get the payload content */ purple_debug_info("MSNP14","GCF command payload:\n%.*s\n", xmllen, buf); - + g_free(buf); xmlnode_free(root); } @@ -1698,7 +1689,7 @@ passport = cmd->params[0]; user = msn_userlist_find_user(session->userlist, passport); - + psm_str = msn_get_psm(cmd->payload,len); msn_user_set_statusline(user, psm_str); g_free(psm_str); @@ -2005,7 +1996,7 @@ { case 1: minutes = atoi(g_hash_table_lookup(table, "Arg1")); - g_snprintf(buf, sizeof(buf), dngettext(PACKAGE, + g_snprintf(buf, sizeof(buf), dngettext(PACKAGE, "The MSN server will shut down for maintenance " "in %d minute. You will automatically be " "signed out at that time. Please finish any " @@ -2032,7 +2023,7 @@ void msn_notification_add_buddy_to_list(MsnNotification *notification, MsnListId list_id, - const char *who) + const char *who) { MsnCmdProc *cmdproc; MsnListOp list_op = 1 << list_id; @@ -2045,12 +2036,12 @@ adl_node = xmlnode_new("ml"); adl_node->child = NULL; - msn_add_contact_xml(notification->session, adl_node, who, list_op, + msn_add_contact_xml(notification->session, adl_node, who, list_op, MSN_USER_TYPE_PASSPORT); payload = xmlnode_to_str(adl_node,&payload_len); xmlnode_free(adl_node); - + msn_notification_post_adl(notification->servconn->cmdproc, payload,payload_len); g_free(payload); @@ -2155,11 +2146,11 @@ /*initial OIM notification*/ msn_table_add_msg_type(cbs_table, "text/x-msmsgsinitialmdatanotification", - initial_mdata_msg); + initial_mdata_msg); /*OIM notification when user online*/ msn_table_add_msg_type(cbs_table, "text/x-msmsgsoimnotification", - initial_mdata_msg); + initial_mdata_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgsinitialemailnotification", initial_email_msg);
--- a/libpurple/protocols/msn/notification.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/notification.h Mon Jun 30 23:12:54 2008 +0000 @@ -30,7 +30,7 @@ #define MSNP13_WLM_PRODUCT_ID "PROD01065C%ZFN6F" #define MSNP10_PRODUCT_KEY "VT6PX?UQTM4WM%YR" -#define MSNP10_PRODUCT_ID "PROD0038W!61ZTF9" +#define MSNP10_PRODUCT_ID "PROD0038W!61ZTF9" typedef struct _MsnNotification MsnNotification; @@ -41,6 +41,11 @@ struct _MsnNotification { MsnSession *session; + + /** + * This is a convenience pointer that always points to + * servconn->cmdproc + */ MsnCmdProc *cmdproc; MsnServConn *servconn; @@ -71,7 +76,7 @@ * Closes a notification. * * It's first closed, and then disconnected. - * + * * @param notification The notification object to close. */ void msn_notification_close(MsnNotification *notification);
--- a/libpurple/protocols/msn/object.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/object.c Mon Jun 30 23:12:54 2008 +0000 @@ -172,7 +172,7 @@ base64 = purple_base64_encode(digest, sizeof(digest)); msn_object_set_sha1c(msnobj, base64); g_free(base64); - + return msnobj; }
--- a/libpurple/protocols/msn/oim.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/oim.c Mon Jun 30 23:12:54 2008 +0000 @@ -1,5 +1,5 @@ /** - * @file oim.c + * @file oim.c * get and send MSN offline Instant Message via SOAP request * Author * MaYuan<mayuan2006@gmail.com> @@ -91,7 +91,7 @@ const char* to_member, const char *msg) { MsnOimSendReq *request; - + request = g_new0(MsnOimSendReq, 1); request->from_member = g_strdup(from_member); request->friendname = g_strdup(friendname); @@ -109,7 +109,7 @@ g_free(req->friendname); g_free(req->to_member); g_free(req->oim_msg); - + g_free(req); } @@ -121,10 +121,10 @@ msn_oim_msg_to_str(MsnOim *oim, const char *body) { char *oim_body,*oim_base64; - - purple_debug_info("MSN OIM","encode OIM Message...\n"); + + purple_debug_info("MSN OIM","encode OIM Message...\n"); oim_base64 = purple_base64_encode((const guchar *)body, strlen(body)); - purple_debug_info("MSN OIM","encoded base64 body:{%s}\n",oim_base64); + purple_debug_info("MSN OIM","encoded base64 body:{%s}\n",oim_base64); oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE, oim->run_id,oim->send_seq,oim_base64); g_free(oim_base64); @@ -213,7 +213,7 @@ } /*post send single message request to oim server*/ -void +void msn_oim_send_msg(MsnOim *oim) { MsnOimSendReq *oim_request; @@ -333,7 +333,7 @@ gboolean offset_positive = TRUE; int tzhrs; int tzmins; - + for (t.tm_mon = 0; months[t.tm_mon] != NULL && strcmp(months[t.tm_mon], month_str) != 0; t.tm_mon++); @@ -462,7 +462,7 @@ } } -/* parse the oim XML data +/* parse the oim XML data * and post it to the soap server to get the Offline Message * */ void
--- a/libpurple/protocols/msn/oim.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/oim.h Mon Jun 30 23:12:54 2008 +0000 @@ -1,7 +1,7 @@ /** * @file oim.h Header file for oim.c * Author - * MaYuan<mayuan2006@gmail.com> + * MaYuan<mayuan2006@gmail.com> * purple * * Purple is the legal property of its developers, whose names are too numerous @@ -127,4 +127,3 @@ void msn_oim_send_msg(MsnOim *oim); #endif/* _MSN_OIM_H_*/ -/*endof oim.h*/
--- a/libpurple/protocols/msn/servconn.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/servconn.c Mon Jun 30 23:12:54 2008 +0000 @@ -396,15 +396,15 @@ if (len <= 0) { switch (errno) { - case 0: + case 0: case EBADF: case EAGAIN: return; - + default: purple_debug_error("msn", "servconn read error," "len: %d, errno: %d, error: %s\n", len, errno, g_strerror(errno)); - msn_servconn_got_error(servconn, + msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ); return; }
--- a/libpurple/protocols/msn/session.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/session.h Mon Jun 30 23:12:54 2008 +0000 @@ -104,7 +104,6 @@ int servconns_count; /**< The count of server connections. */ GList *switches; /**< The list of all the switchboards. */ - GList *directconns; /**< The list of all the directconnections. */ GList *slplinks; /**< The list of all the slplinks. */ /*psm info*/
--- a/libpurple/protocols/msn/slp.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/slp.c Mon Jun 30 23:12:54 2008 +0000 @@ -947,15 +947,15 @@ msn_release_buddy_icon_request_timeout(gpointer data) { MsnUserList *userlist = (MsnUserList *)data; - + /* Free one window slot */ - userlist->buddy_icon_window++; - + userlist->buddy_icon_window++; + /* Clear the tag for our former request timer */ userlist->buddy_icon_request_timer = 0; - + msn_release_buddy_icon_request(userlist); - + return FALSE; } @@ -1062,7 +1062,7 @@ } /* Wait BUDDY_ICON_DELAY ms before freeing our window slot and requesting the next icon. */ - userlist->buddy_icon_request_timer = purple_timeout_add(BUDDY_ICON_DELAY, + userlist->buddy_icon_request_timer = purple_timeout_add(BUDDY_ICON_DELAY, msn_release_buddy_icon_request_timeout, userlist); }
--- a/libpurple/protocols/msn/slplink.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/slplink.c Mon Jun 30 23:12:54 2008 +0000 @@ -58,7 +58,7 @@ * Main **************************************************************************/ -MsnSlpLink * +static MsnSlpLink * msn_slplink_new(MsnSession *session, const char *username) { MsnSlpLink *slplink; @@ -593,7 +593,7 @@ } else if (slpmsg->size) { - if ((offset + len) > slpmsg->size) + if (G_MAXSIZE - len < offset || (offset + len) > slpmsg->size) { purple_debug_error("msn", "Oversized slpmsg - msgsize=%lld offset=%" G_GSIZE_FORMAT " len=%" G_GSIZE_FORMAT "\n",
--- a/libpurple/protocols/msn/slplink.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/slplink.h Mon Jun 30 23:12:54 2008 +0000 @@ -59,11 +59,21 @@ GQueue *slp_msg_queue; }; -MsnSlpLink *msn_slplink_new(MsnSession *session, const char *username); void msn_slplink_destroy(MsnSlpLink *slplink); + +/** + * @return An MsnSlpLink for the given user, or NULL if there is no + * existing MsnSlpLink. + */ MsnSlpLink *msn_session_find_slplink(MsnSession *session, const char *who); + +/** + * @return An MsnSlpLink for the given user. One will be created if + * it does not already exist. + */ MsnSlpLink *msn_session_get_slplink(MsnSession *session, const char *username); + MsnSlpSession *msn_slplink_find_slp_session(MsnSlpLink *slplink, long session_id); void msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall);
--- a/libpurple/protocols/msn/soap.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/soap.c Mon Jun 30 23:12:54 2008 +0000 @@ -1,5 +1,5 @@ /** - * @file soap.c + * @file soap.c * SOAP connection related process * Author * MaYuan<mayuan2006@gmail.com> @@ -107,7 +107,7 @@ /*ssl soap error callback*/ static void msn_soap_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) -{ +{ MsnSoapConn * soapconn = data; g_return_if_fail(data != NULL); @@ -159,7 +159,7 @@ if (*handler > 0) { purple_input_remove(*handler); *handler = 0; - } + } #ifdef MSN_SOAP_DEBUG else { purple_debug_misc("MSN SOAP", "Handler inactive, not removing\n"); @@ -250,7 +250,7 @@ { gssize len, requested_len; char temp_buf[MSN_SOAP_READ_BUFF_SIZE]; - + if ( soapconn->need_to_read == 0 || soapconn->need_to_read > MSN_SOAP_READ_BUFF_SIZE) { requested_len = MSN_SOAP_READ_BUFF_SIZE; } @@ -264,7 +264,7 @@ len = read(soapconn->fd, temp_buf, requested_len); } - + if ( len <= 0 ) { switch (errno) { @@ -298,7 +298,7 @@ soapconn->read_len + len + 1); exit(EXIT_FAILURE); } - + } #if defined(MSN_SOAP_DEBUG) @@ -312,7 +312,7 @@ } /*read the whole SOAP server response*/ -static void +static void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnSoapConn *soapconn = data; @@ -331,10 +331,10 @@ session = soapconn->session; g_return_if_fail(session != NULL); - + /*read the request header*/ len = msn_soap_read(soapconn); - + if ( len < 0 ) return; @@ -342,7 +342,7 @@ return; } - if ( (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) + if ( (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) || ( strstr(soapconn->read_buf, "HTTP/1.1 301") != NULL ) ) { /* Redirect. */ @@ -382,14 +382,14 @@ g_free(soapconn->login_host); soapconn->login_host = g_strdup(location); - + msn_soap_close_handler( &(soapconn->input_handler) ); msn_soap_close(soapconn); if (purple_ssl_connect(session->account, soapconn->login_host, PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, msn_soap_error_cb, soapconn) == NULL) { - + purple_debug_error("MSN SOAP", "Unable to connect to %s !\n", soapconn->login_host); // dispatch next request msn_soap_post(soapconn, NULL); @@ -429,7 +429,7 @@ g_free(soapconn->login_host); soapconn->login_host = g_strdup(location); - + msn_soap_close_handler( &(soapconn->input_handler) ); msn_soap_close(soapconn); @@ -489,7 +489,7 @@ } } } - + } else if (strstr(soapconn->read_buf, "HTTP/1.1 503 Service Unavailable")) { @@ -539,11 +539,11 @@ #if defined(MSN_SOAP_DEBUG) && !defined(_WIN32) node = xmlnode_from_str(soapconn->body, soapconn->body_len); - + if (node != NULL) { formattedxml = xmlnode_to_formatted_str(node, NULL); http_headers = g_strndup(soapconn->read_buf, soapconn->body - soapconn->read_buf); - + purple_debug_info("MSN SOAP","Data with XML payload received from the SOAP server:\n%s%s\n", http_headers, formattedxml); g_free(http_headers); g_free(formattedxml); @@ -572,22 +572,22 @@ if ( soapconn->read_cb != NULL ) { soapconn_is_valid = soapconn->read_cb(soapconn); } - + if (!soapconn_is_valid) { return; } /* dispatch next request in queue */ msn_soap_post(soapconn, NULL); - } + } return; } -void +void msn_soap_free_read_buf(MsnSoapConn *soapconn) { g_return_if_fail(soapconn != NULL); - + if (soapconn->read_buf) { g_free(soapconn->read_buf); } @@ -626,7 +626,7 @@ } total_len = strlen(soapconn->write_buf); - /* + /* * write the content to SSL server, */ len = purple_ssl_write(soapconn->gsc, @@ -690,7 +690,7 @@ soapconn->write_buf = write_buf; soapconn->written_len = 0; soapconn->written_cb = written_cb; - + msn_soap_free_read_buf(soapconn); /*clear the read buffer first*/ @@ -748,7 +748,7 @@ { g_return_if_fail(soapconn != NULL); g_return_if_fail(soapconn->soap_queue != NULL); - + if (soapconn->step == MSN_SOAP_CONNECTED || soapconn->step == MSN_SOAP_CONNECTED_IDLE) { @@ -868,7 +868,7 @@ else purple_debug_info("MSN SOAP","Failed to parse SOAP request being sent:\n%s\n", request_str); #endif - + /*free read buffer*/ // msn_soap_free_read_buf(soapconn); /*post it to server*/
--- a/libpurple/protocols/msn/soap.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/soap.h Mon Jun 30 23:12:54 2008 +0000 @@ -66,7 +66,7 @@ char *soap_action; char *body; - + gpointer data_cb; MsnSoapReadCbFunction read_cb; MsnSoapWrittenCbFunction written_cb;
--- a/libpurple/protocols/msn/soap2.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/soap2.c Mon Jun 30 23:12:54 2008 +0000 @@ -82,6 +82,7 @@ static void msn_soap_request_destroy(MsnSoapRequest *req); static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect); +static void msn_soap_process(MsnSoapConnection *conn); static gboolean msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data) @@ -264,45 +265,53 @@ msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) { MsnSoapConnection *conn = data; - int count = 0, cnt; - char buf[8192]; - char *linebreak; - char *cursor; - gboolean handled = FALSE; + int count = 0, cnt, perrno; + /* This buffer needs to be larger than any packets received from + login.live.com or Adium will fail to receive the packet + (something weird with the login.live.com server). With NSS it works + fine, so I believe it's some bug with OS X */ + char buf[16 * 1024]; if (conn->message == NULL) { conn->message = msn_soap_message_new(NULL, NULL); } + if (conn->buf == NULL) { + conn->buf = g_string_new_len(buf, 0); + } + while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { purple_debug_info("soap", "read %d bytes\n", cnt); count += cnt; - if (conn->buf == NULL) { - conn->buf = g_string_new_len(buf, cnt); - } else { - g_string_append_len(conn->buf, buf, cnt); - } + g_string_append_len(conn->buf, buf, cnt); } - if (cnt < 0) { - if (errno != EAGAIN) { - purple_debug_info("soap", "read: %s\n", g_strerror(errno)); + /* && count is necessary for Adium, on OS X the last read always + return an error, so we want to proceed anyway. See #5212 for + discussion on this and the above buffer size issues */ + if(cnt < 0 && errno == EAGAIN && count == 0) + return; + + // msn_soap_process could alter errno + perrno = errno; + msn_soap_process(conn); + + if (cnt < 0 && perrno != EAGAIN) { + purple_debug_info("soap", "read: %s\n", g_strerror(perrno)); + // It's possible msn_soap_process closed the ssl connection + if (conn->ssl) { purple_ssl_close(conn->ssl); conn->ssl = NULL; msn_soap_connection_handle_next(conn); - return; - } else if (count == 0) { - return; } } +} - if (cnt == 0 && count == 0) { - purple_debug_info("soap", "msn_soap_read_cb() called, but no data available?\n"); - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - msn_soap_connection_handle_next(conn); - return; - } +static void +msn_soap_process(MsnSoapConnection *conn) { + gboolean handled = FALSE; + char *cursor; + char *linebreak; purple_debug_info("soap", "current %s\n", conn->buf->str);
--- a/libpurple/protocols/msn/state.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/state.c Mon Jun 30 23:12:54 2008 +0000 @@ -150,7 +150,7 @@ { xmlnode *payloadNode, *currentmediaNode; char *currentmedia; - + purple_debug_info("msn","msn get CurrentMedia\n"); payloadNode = xmlnode_from_str(xml_str, len); if (!payloadNode){ @@ -176,7 +176,7 @@ { xmlnode *payloadNode, *psmNode; char *psm; - + purple_debug_info("MSNP14","msn get PSM\n"); payloadNode = xmlnode_from_str(xml_str, len); if (!payloadNode){ @@ -217,7 +217,7 @@ return ret; } -/* set the MSN's PSM info,Currently Read from the status Line +/* set the MSN's PSM info,Currently Read from the status Line * Thanks for Cris Code */ void
--- a/libpurple/protocols/msn/transaction.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/transaction.h Mon Jun 30 23:12:54 2008 +0000 @@ -62,7 +62,7 @@ }; MsnTransaction *msn_transaction_new(MsnCmdProc *cmdproc, const char *command, - const char *format, ...) G_GNUC_PRINTF(3, 4); + const char *format, ...) G_GNUC_PRINTF(3, 4); void msn_transaction_destroy(MsnTransaction *trans); char *msn_transaction_to_string(MsnTransaction *trans);
--- a/libpurple/protocols/msn/user.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/user.c Mon Jun 30 23:12:54 2008 +0000 @@ -122,7 +122,7 @@ NULL); } else { purple_prpl_got_user_status_deactive(account, user->passport, "tune"); - } + } } if (user->idle) @@ -239,7 +239,7 @@ msn_user_unset_op(MsnUser *user, int list_op) { g_return_if_fail(user != NULL); - + user->list_op &= ~list_op; }
--- a/libpurple/protocols/msn/user.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/user.h Mon Jun 30 23:12:54 2008 +0000 @@ -57,9 +57,6 @@ */ struct _MsnUser { -#if 0 - MsnSession *session; /**< The MSN session. */ -#endif MsnUserList *userlist; char *passport; /**< The passport account. */ @@ -69,7 +66,7 @@ char * uid; /*< User Id */ const char *status; /**< The state of the user. */ - char *statusline; /**< The state of the user. */ + char *statusline; /**< The state of the user. */ CurrentMedia media; /**< Current media of the user. */ gboolean idle; /**< The idle state of the user. */ @@ -135,7 +132,7 @@ /** * Sets the new statusline of user. - * + * * @param user The user. * @param state The statusline string. */ @@ -143,7 +140,7 @@ /** * Sets the current media of user. - * + * * @param user The user. * @param cmedia Current media. */
--- a/libpurple/protocols/msn/userlist.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/userlist.c Mon Jun 30 23:12:54 2008 +0000 @@ -48,7 +48,7 @@ { MsnSession *session = pa->gc->proto_data; MsnUserList *userlist = session->userlist; - + msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL); @@ -127,7 +127,7 @@ if (user == NULL) return FALSE; - + list_op = 1 << list_id; if (user->list_op & list_op) @@ -237,7 +237,7 @@ if (convo) { PurpleBuddy *buddy; char *msg; - + buddy = purple_find_buddy(account, passport); msg = g_strdup_printf( _("%s has added you to his or her buddy list."), @@ -246,7 +246,7 @@ PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(msg); } - + if (!(user->list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) { /* @@ -341,7 +341,7 @@ passport = msn_user_get_passport(user); store = msn_user_get_store_name(user); - + msn_user_set_op(user, list_op); if (list_op & MSN_LIST_FL_OP) @@ -407,7 +407,7 @@ userlist->session = session; userlist->buddy_icon_requests = g_queue_new(); - + /* buddy_icon_window is the number of allowed simultaneous buddy icon requests. * XXX With smarter rate limiting code, we could allow more at once... 5 was the limit set when * we weren't retrieiving any more than 5 per MSN session. */ @@ -644,12 +644,12 @@ msn_userlist_rem_buddy(MsnUserList *userlist, const char *who) { MsnUser *user = NULL; - + g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); g_return_if_fail(userlist->session->contact != NULL); g_return_if_fail(who != NULL); - + user = msn_userlist_find_user(userlist, who); msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_FL); @@ -669,9 +669,9 @@ MsnListOp list_op = 1 << list_id; user = msn_userlist_find_user(userlist, who); - + g_return_if_fail(user != NULL); - + if ( !msn_userlist_user_is_in_list(user, list_id)) { list = lists[list_id]; purple_debug_info("MSN Userlist", "User %s is not in list %s, not removing.\n", who, list); @@ -690,14 +690,14 @@ MsnUser *user; MsnCallbackState *state = NULL; const char *group_id = NULL, *new_group_name; - + new_group_name = group_name == NULL ? MSN_INDIVIDUALS_GROUP_NAME : group_name; - + g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); - + purple_debug_info("MSN Userlist", "Add user: %s to group: %s\n", who, new_group_name); state = msn_callback_state_new(userlist->session); @@ -709,9 +709,9 @@ /* only notify the user about problems adding to the friends list * maybe we should do something else for other lists, but it probably * won't cause too many problems if we just ignore it */ - + char *str = g_strdup_printf(_("Unable to add \"%s\"."), who); - + purple_notify_error(NULL, NULL, str, _("The username specified is invalid.")); g_free(str); @@ -725,7 +725,7 @@ { /* Whoa, we must add that group first. */ purple_debug_info("MSN Userlist", "Adding user %s to a new group, creating group %s first\n", who, new_group_name); - + msn_callback_state_set_action(state, MSN_ADD_BUDDY); msn_add_group(userlist->session, state, new_group_name); @@ -733,9 +733,9 @@ } else { msn_callback_state_set_guid(state, group_id); } - + /* XXX: adding user here may not be correct (should add them in the - * ACK to the ADL command), but for now we need to make sure they exist + * ACK to the ADL command), but for now we need to make sure they exist * early enough that the ILN command doesn't screw us up */ user = msn_userlist_find_add_user(userlist, who, who); @@ -751,7 +751,7 @@ return; } } - + purple_debug_info("MSN Userlist", "Adding user: %s to group id: %s\n", who, group_id); msn_callback_state_set_action(state, MSN_ADD_BUDDY); @@ -762,7 +762,7 @@ } void -msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, +msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, MsnListId list_id) { MsnUser *user = NULL; @@ -770,9 +770,9 @@ MsnListOp list_op = 1 << list_id; g_return_if_fail(userlist != NULL); - + user = msn_userlist_find_add_user(userlist, who, who); - + /* First we're going to check if it's already there. */ if (msn_userlist_user_is_in_list(user, list_id)) { @@ -780,16 +780,16 @@ purple_debug_info("MSN Userlist", "User '%s' is already in list: %s\n", who, list); return; } - + //store_name = (user != NULL) ? get_store_name(user) : who; - + //purple_debug_info("MSN Userlist", "store_name = %s\n", store_name); - + /* XXX: see XXX above, this should really be done when we get the response from the server */ - + msn_user_set_op(user, list_op); - + msn_notification_add_buddy_to_list(userlist->session->notification, list_id, who); } @@ -799,7 +799,7 @@ { MsnUser *user; gchar * group_id; - + g_return_val_if_fail(userlist != NULL, FALSE); g_return_val_if_fail(group_name != NULL, FALSE); g_return_val_if_fail(who != NULL, FALSE); @@ -815,7 +815,7 @@ purple_debug_error("MSN Userlist", "User %s not found!", who); return FALSE; } - + msn_user_add_group_id(user, group_id); return TRUE; @@ -832,7 +832,7 @@ g_return_val_if_fail(userlist != NULL, FALSE); g_return_val_if_fail(group_name != NULL, FALSE); g_return_val_if_fail(who != NULL, FALSE); - + purple_debug_info("MSN Userlist","Removing buddy with passport %s from group %s\n", who, group_name); if ( (group_id = msn_userlist_find_group_id(userlist, group_name)) == NULL) { @@ -856,7 +856,7 @@ { const char *new_group_id; MsnCallbackState *state; - + g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); g_return_if_fail(userlist->session->contact != NULL); @@ -870,11 +870,11 @@ new_group_id = msn_userlist_find_group_id(userlist, new_group_name); if (new_group_id == NULL) - { + { msn_add_group(userlist->session, state, new_group_name); return; } - + /* add the contact to the new group, and remove it from the old one in * the callback */ @@ -928,6 +928,6 @@ (char *)l->data,NULL); msn_user_set_op(user, MSN_LIST_BL_OP); } - + }
--- a/libpurple/protocols/msn/userlist.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msn/userlist.h Mon Jun 30 23:12:54 2008 +0000 @@ -45,11 +45,8 @@ { MsnSession *session; - /* MsnUsers *users; */ - /* MsnGroups *groups; */ - - GList *users; - GList *groups; + GList *users; /* Contains MsnUsers */ + GList *groups; /* Contains MsnGroups */ GQueue *buddy_icon_requests; int buddy_icon_window; @@ -94,7 +91,7 @@ void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id); void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who); -void msn_userlist_add_buddy(MsnUserList *userlist, +void msn_userlist_add_buddy(MsnUserList *userlist, const char *who, const char *group_name); void msn_userlist_move_buddy(MsnUserList *userlist, const char *who, const char *old_group_name, @@ -106,7 +103,7 @@ const char *who, const char *group_name); -void msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, +void msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, MsnListId list_id); void msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who, MsnListId list_id);
--- a/libpurple/protocols/msnp9/slplink.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/msnp9/slplink.c Mon Jun 30 23:12:54 2008 +0000 @@ -597,7 +597,7 @@ } else if (slpmsg->size) { - if ((offset + len) > slpmsg->size) + if (G_MAXSIZE - len < offset || (offset + len) > slpmsg->size) { purple_debug_error("msn", "Oversized slpmsg\n"); g_return_if_reached();
--- a/libpurple/protocols/myspace/myspace.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/myspace/myspace.c Mon Jun 30 23:12:54 2008 +0000 @@ -1328,7 +1328,10 @@ delta = time(NULL) - session->last_comm; /* purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); */ if (delta >= MSIM_KEEPALIVE_INTERVAL) { - errmsg = g_strdup_printf(_("Connection to server lost (no data received within %d seconds)"), (int)delta); + errmsg = g_strdup_printf(ngettext("Connection to server lost (no data received within %d second)", + "Connection to server lost (no data received within %d seconds)", + (int)delta), + (int)delta); purple_debug_info("msim", "msim_check_alive: %s > interval of %d, presumed dead\n", errmsg, MSIM_KEEPALIVE_INTERVAL); @@ -2404,7 +2407,7 @@ const char *username; /* If the account does not exist, we can't look up the user. */ - if (!account) + if (!account || !account->gc) return str; id = atol(str); @@ -2946,7 +2949,10 @@ switch (GPOINTER_TO_UINT(user_data)) { case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS: - msg = g_strdup_printf(_("%d buddies were added or updated from the server (including buddies already on the server-side list)"), buddy_count); + msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)", + "%d buddies were added or updated from the server (including buddies already on the server-side list)", + buddy_count), + buddy_count); purple_notify_info(session->account, _("Add contacts from server"), msg, NULL); g_free(msg); break;
--- a/libpurple/protocols/myspace/user.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/myspace/user.c Mon Jun 30 23:12:54 2008 +0000 @@ -635,7 +635,7 @@ if (!body) { purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username); purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, - "An error occured while trying to set the username.\n" + "An error occurred while trying to set the username.\n" "Please try again, or visit http://editprofile.myspace.com/index.cfm?" "fuseaction=profile.username to set your username."); return; @@ -778,7 +778,7 @@ uid = msim_msg_get_integer(userinfo, "uid"); lid = msim_msg_get_integer(userinfo, "lid"); body = msim_msg_get_dictionary(userinfo, "body"); - errmsg = g_strdup("An error occured while trying to set the username.\n" + errmsg = g_strdup("An error occurred while trying to set the username.\n" "Please try again, or visit http://editprofile.myspace.com/index.cfm?" "fuseaction=profile.username to set your username.");
--- a/libpurple/protocols/oscar/family_admin.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_admin.c Mon Jun 30 23:12:54 2008 +0000 @@ -47,8 +47,8 @@ byte_stream_put16(&bs, info); byte_stream_put16(&bs, 0x0000); - snacid = aim_cachesnac(od, 0x0007, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0007, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -127,8 +127,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -154,8 +154,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -177,8 +177,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -194,11 +194,11 @@ void aim_admin_reqconfirm(OscarData *od, FlapConnection *conn) { - aim_genericreq_n(od, conn, 0x0007, 0x0006); + aim_genericreq_n(od, conn, SNAC_FAMILY_ADMIN, 0x0006); } /** - * Subtype 0x0007 - Account confirmation request acknowledgement. + * Subtype SNAC_FAMILY_ADMIN - Account confirmation request acknowledgement. */ static int accountconfirm(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) @@ -227,7 +227,7 @@ if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) { infochange(od, conn, mod, frame, snac, bs); return 1; - } else if (snac->subtype == 0x0007) + } else if (snac->subtype == SNAC_FAMILY_ADMIN) return accountconfirm(od, conn, mod, frame, snac, bs); return 0; @@ -235,7 +235,7 @@ int admin_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0007; + mod->family = SNAC_FAMILY_ADMIN; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_advert.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_advert.c Mon Jun 30 23:12:54 2008 +0000 @@ -28,7 +28,7 @@ void aim_ads_requestads(OscarData *od, FlapConnection *conn) { - aim_genericreq_n(od, conn, 0x0005, 0x0002); + aim_genericreq_n(od, conn, SNAC_FAMILY_ADVERT, 0x0002); } static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs) @@ -39,7 +39,7 @@ int adverts_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0005; + mod->family = SNAC_FAMILY_ADVERT; mod->version = 0x0001; mod->toolid = 0x0001; mod->toolversion = 0x0001;
--- a/libpurple/protocols/oscar/family_alert.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_alert.c Mon Jun 30 23:12:54 2008 +0000 @@ -72,8 +72,8 @@ byte_stream_put16(&bs, 0xb0ee); byte_stream_put16(&bs, 0x0631); - snacid = aim_cachesnac(od, 0x0018, 0x0006, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0018, 0x0006, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0006, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -188,8 +188,8 @@ byte_stream_put32(&bs, 0x04000000); byte_stream_put32(&bs, 0x00000000); - snacid = aim_cachesnac(od, 0x0018, 0x0016, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0018, 0x0006, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0016, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -225,7 +225,7 @@ int email_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0018; + mod->family = SNAC_FAMILY_ALERT; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_auth.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_auth.c Mon Jun 30 23:12:54 2008 +0000 @@ -81,12 +81,9 @@ static int aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest) { - PurpleCipher *cipher; PurpleCipherContext *context; - cipher = purple_ciphers_find_cipher("md5"); - - context = purple_cipher_context_new(cipher, NULL); + context = purple_cipher_context_new_by_name("md5", NULL); purple_cipher_context_append(context, (const guchar *)key, strlen(key)); purple_cipher_context_append(context, (const guchar *)password, password_len); purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING)); @@ -200,9 +197,13 @@ * usually happens for AOL accounts. We are told that we * should truncate it if the 0x0017/0x0007 SNAC contains * a TLV of type 0x0026 with data 0x0000. + * @param allow_multiple_logins Allow multiple logins? If TRUE, the AIM + * server will prompt the user when multiple logins occur. If + * FALSE, existing connections (on other clients) will be + * disconnected automatically as we connect. */ int -aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key) +aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins) { FlapFrame *frame; GSList *tlvlist = NULL; @@ -221,8 +222,8 @@ frame = flap_frame_new(od, 0x02, 1152); - snacid = aim_cachesnac(od, 0x0017, 0x0002, 0x0000, NULL, 0); - aim_putsnac(&frame->data, 0x0017, 0x0002, 0x0000, snacid); + snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, 0x0000, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); @@ -256,7 +257,7 @@ * If set, old-fashioned buddy lists will not work. You will need * to use SSI. */ - aim_tlvlist_add_8(&tlvlist, 0x004a, 0x01); + aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x02)); aim_tlvlist_write(&frame->data, &tlvlist); @@ -403,7 +404,7 @@ od->authinfo = info; - if ((userfunc = aim_callhandler(od, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) + if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003))) ret = userfunc(od, conn, frame, info); aim_tlvlist_free(tlvlist); @@ -449,7 +450,7 @@ FlapFrame frame; aim_rxcallback_t userfunc; - if ((userfunc = aim_callhandler(od, 0x0017, 0x0007))) + if ((userfunc = aim_callhandler(od, SNAC_FAMILY_AUTH, 0x0007))) userfunc(od, conn, &frame, ""); return 0; @@ -483,8 +484,8 @@ frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8); - snacid = aim_cachesnac(od, 0x0017, 0x0006, 0x0000, NULL, 0); - aim_putsnac(&frame->data, 0x0017, 0x0006, 0x0000, snacid); + snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, 0x0000, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); @@ -628,7 +629,7 @@ int auth_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0017; + mod->family = SNAC_FAMILY_AUTH; mod->version = 0x0000; mod->flags = 0; strncpy(mod->name, "auth", sizeof(mod->name));
--- a/libpurple/protocols/oscar/family_bart.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_bart.c Mon Jun 30 23:12:54 2008 +0000 @@ -43,7 +43,7 @@ ByteStream bs; aim_snacid_t snacid; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !icon || !iconlen) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !icon || !iconlen) return -EINVAL; byte_stream_new(&bs, 2 + 2 + iconlen); @@ -55,8 +55,8 @@ byte_stream_put16(&bs, iconlen); byte_stream_putraw(&bs, icon, iconlen); - snacid = aim_cachesnac(od, 0x0010, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0010, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -102,7 +102,7 @@ ByteStream bs; aim_snacid_t snacid; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen) return -EINVAL; byte_stream_new(&bs, 1+strlen(sn) + 4 + 1+iconcsumlen); @@ -120,8 +120,8 @@ byte_stream_put8(&bs, iconcsumlen); byte_stream_putraw(&bs, iconcsum, iconcsumlen); - snacid = aim_cachesnac(od, 0x0010, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0010, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0004, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -174,7 +174,7 @@ int bart_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0010; + mod->family = SNAC_FAMILY_BART; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_bos.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_bos.c Mon Jun 30 23:12:54 2008 +0000 @@ -32,7 +32,7 @@ void aim_bos_reqrights(OscarData *od, FlapConnection *conn) { - aim_genericreq_n_snacid(od, conn, 0x0009, 0x0002); + aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_BOS, 0x0002); } /* Subtype 0x0003 - BOS Rights. */ @@ -81,7 +81,7 @@ void aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask) { - aim_genericreq_l(od, conn, 0x0009, 0x0004, &mask); + aim_genericreq_l(od, conn, SNAC_FAMILY_BOS, 0x0004, &mask); } /* @@ -153,8 +153,8 @@ } g_free(localcpy); - snacid = aim_cachesnac(od, 0x0009, subtype, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0009, subtype, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BOS, subtype, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BOS, subtype, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -173,7 +173,7 @@ int bos_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0009; + mod->family = SNAC_FAMILY_BOS; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_buddy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_buddy.c Mon Jun 30 23:12:54 2008 +0000 @@ -108,8 +108,8 @@ byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, 0x0003, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, sn, strlen(sn)+1); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -159,8 +159,8 @@ tmpptr = strtok(NULL, "&"); } - snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0003, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -190,8 +190,8 @@ byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - snacid = aim_cachesnac(od, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, 0x0003, 0x0005, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, sn, strlen(sn)+1); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -243,7 +243,7 @@ int buddylist_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0003; + mod->family = SNAC_FAMILY_BUDDY; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_chat.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_chat.c Mon Jun 30 23:12:54 2008 +0000 @@ -364,7 +364,7 @@ byte_stream_new(&bs, 1142); - snacid = aim_cachesnac(od, 0x000e, 0x0005, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_CHAT, 0x0005, 0x0000, NULL, 0); /* * Cookie @@ -432,7 +432,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x000e, 0x0005, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -594,7 +594,7 @@ int chat_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000e; + mod->family = SNAC_FAMILY_CHAT; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_chatnav.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_chatnav.c Mon Jun 30 23:12:54 2008 +0000 @@ -42,7 +42,7 @@ return 0; } - if (snac2->family != 0x000d) { + if (snac2->family != SNAC_FAMILY_CHATNAV) { purple_debug_warning("oscar", "chatnav error: received response that maps to corrupt request (fam=%04x)\n", snac2->family); return 0; } @@ -80,7 +80,7 @@ */ void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn) { - aim_genericreq_n_snacid(od, conn, 0x000d, 0x0002); + aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_CHATNAV, 0x0002); } /* @@ -97,7 +97,7 @@ byte_stream_new(&bs, 1142); - snacid = aim_cachesnac(od, 0x000d, 0x0008, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, NULL, 0); /* exchange */ byte_stream_put16(&bs, exchange); @@ -137,7 +137,7 @@ aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x000d, 0x0008, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -460,7 +460,7 @@ return 0; } - if (snac2->family != 0x000d) { + if (snac2->family != SNAC_FAMILY_CHATNAV) { purple_debug_misc("oscar", "faim: chatnav_parse_info: received response that maps to corrupt request! (fam=%04x)\n", snac2->family); return 0; } @@ -506,7 +506,7 @@ int chatnav_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000d; + mod->family = SNAC_FAMILY_CHATNAV; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_icbm.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Mon Jun 30 23:12:54 2008 +0000 @@ -164,7 +164,7 @@ ByteStream bs; aim_snacid_t snacid; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (!params) @@ -182,8 +182,8 @@ byte_stream_put16(&bs, params->maxrecverwarn); byte_stream_put32(&bs, params->minmsginterval); - snacid = aim_cachesnac(od, 0x0004, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0004, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -198,10 +198,10 @@ { FlapConnection *conn; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; - aim_genericreq_n_snacid(od, conn, 0x0004, 0x0004); + aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_ICBM, 0x0004); return 0; } @@ -237,7 +237,7 @@ * Possible flags: * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse * AIM_IMFLAGS_ACK -- Requests that the server send an ack - * when the message is received (of type 0x0004/0x000c) + * when the message is received (of type SNAC_FAMILY_ICBM/0x000c) * AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are * online (probably ICQ only). * @@ -280,7 +280,7 @@ int msgtlvlen; static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 }; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (!args) @@ -410,9 +410,9 @@ } /* XXX - should be optional */ - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); - - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &data); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); + + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &data); byte_stream_destroy(&data); /* clean out SNACs over 60sec old */ @@ -462,7 +462,7 @@ GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (!sn || !msg || !roomname) @@ -472,7 +472,7 @@ byte_stream_new(&bs, 1142+strlen(sn)+strlen(roomname)+strlen(msg)); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, sn, strlen(sn)+1); /* XXX should be uncached by an unwritten 'invite accept' handler */ priv = g_malloc(sizeof(struct aim_invite_priv)); @@ -519,7 +519,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -539,7 +539,7 @@ aim_snacid_t snacid; guchar cookie[8]; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) @@ -549,7 +549,7 @@ byte_stream_new(&bs, 8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -589,7 +589,7 @@ byte_stream_put16(&bs, 0x0003); byte_stream_put16(&bs, 0x0000); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -620,7 +620,7 @@ const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */ int servdatalen; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (!args || !args->destsn || !args->rtfmsg) @@ -632,7 +632,7 @@ byte_stream_new(&bs, 128+servdatalen); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, args->destsn); @@ -682,7 +682,7 @@ byte_stream_putle32(&bs, strlen(rtfcap)+1); byte_stream_putraw(&bs, (const guint8 *)rtfcap, strlen(rtfcap)+1); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -704,13 +704,13 @@ ByteStream hdrbs; od = peer_conn->od; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 118+strlen(peer_conn->sn)); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn); @@ -735,7 +735,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -753,13 +753,13 @@ aim_snacid_t snacid; od = peer_conn->od; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 11+strlen(peer_conn->sn) + 4+2+8+16); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn); @@ -770,7 +770,7 @@ byte_stream_putraw(&bs, peer_conn->cookie, 8); byte_stream_putcaps(&bs, peer_conn->type); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -791,13 +791,13 @@ GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 246+strlen(sn)); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -825,7 +825,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -844,13 +844,13 @@ ByteStream hdrbs; guint8 ip_comp[4]; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 246+strlen(sn)); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -888,7 +888,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -906,13 +906,13 @@ GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 1014); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -971,7 +971,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -990,13 +990,13 @@ ByteStream hdrbs; guint8 ip_comp[4]; - conn = flap_connection_findbygroup(od, 0x0004); + conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (conn == NULL) return; byte_stream_new(&bs, 1014); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -1064,7 +1064,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -1085,14 +1085,14 @@ aim_snacid_t snacid; guchar cookie[8]; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)) || !sn) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)) || !sn) return -EINVAL; aim_icbm_makecookie(cookie); byte_stream_new(&bs, 8+2+1+strlen(sn) + 4+0x5e + 4); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); /* ICBM header */ aim_im_puticbm(&bs, cookie, 0x0002, sn); @@ -1160,7 +1160,7 @@ byte_stream_put16(&bs, 0x0003); byte_stream_put16(&bs, 0x0000); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1196,7 +1196,7 @@ byte_stream_new(&bs, 8+3+strlen(sn)+12+strlen(message)+1+4); - snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); aim_icbm_makecookie(cookie); @@ -1229,7 +1229,7 @@ byte_stream_put16(&bs, 0x0006); byte_stream_put16(&bs, 0x0000); - flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -2268,13 +2268,13 @@ byte_stream_new(&bs, strlen(sn)+3); - snacid = aim_cachesnac(od, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0008, 0x0000, sn, strlen(sn)+1); byte_stream_put16(&bs, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - flap_connection_send_snac(od, conn, 0x0004, 0x0008, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0008, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -2321,12 +2321,12 @@ aim_snacid_t snacid; GSList *tlvlist = NULL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; byte_stream_new(&bs, 8+2+1+strlen(sn)+6); - snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0); byte_stream_putraw(&bs, cookie, 8); @@ -2338,7 +2338,7 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -2660,7 +2660,7 @@ if (!od || !(conn = flap_connection_findbygroup(od, 0x0002))) return -EINVAL; - aim_genericreq_n(od, conn, 0x0004, 0x0010); + aim_genericreq_n(od, conn, SNAC_FAMILY_ICBM, 0x0010); return 0; } @@ -2686,7 +2686,7 @@ byte_stream_new(&bs, 11+strlen(sn)+2); - snacid = aim_cachesnac(od, 0x0004, 0x0014, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0014, 0x0000, NULL, 0); /* * 8 days of light @@ -2713,7 +2713,7 @@ */ byte_stream_put16(&bs, type2); - flap_connection_send_snac(od, conn, 0x0004, 0x0014, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -2773,7 +2773,7 @@ int msg_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0004; + mod->family = SNAC_FAMILY_ICBM; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_icq.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_icq.c Mon Jun 30 23:12:54 2008 +0000 @@ -33,14 +33,14 @@ aim_snacid_t snacid; int bslen; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 4 + 2 + 2; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -51,7 +51,7 @@ byte_stream_putle16(&bs, 0x003c); /* I command thee. */ byte_stream_putle16(&bs, snacid); /* eh. */ - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -65,14 +65,14 @@ aim_snacid_t snacid; int bslen; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 4 + 2 + 2; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -83,7 +83,7 @@ byte_stream_putle16(&bs, 0x003e); /* I command thee. */ byte_stream_putle16(&bs, snacid); /* eh. */ - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -99,14 +99,14 @@ aim_snacid_t snacid; int bslen; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -126,7 +126,7 @@ byte_stream_putle8(&bs, 0x00); byte_stream_putle8(&bs, !auth_required); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -151,7 +151,7 @@ if (!passwd) return -EINVAL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; passwdlen = strlen(passwd); @@ -161,7 +161,7 @@ byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -176,7 +176,7 @@ byte_stream_putstr(&bs, passwd); byte_stream_putle8(&bs, '\0'); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -194,14 +194,14 @@ if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 4 + 2 + 2 + 2 + 4; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -214,7 +214,7 @@ byte_stream_putle16(&bs, 0x04b2); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -239,14 +239,14 @@ if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 4 + 2 + 2 + 2 + 4; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -259,7 +259,7 @@ byte_stream_putle16(&bs, 0x04ba); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -283,14 +283,14 @@ if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 4 + 2 + 2 + 2 + 4; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -303,7 +303,7 @@ byte_stream_putle16(&bs, 0x051f); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -321,14 +321,14 @@ if (!xml || !strlen(xml)) return -EINVAL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; bslen = 2 + 10 + 2 + strlen(xml) + 1; byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -342,7 +342,7 @@ byte_stream_putle16(&bs, strlen(xml) + 1); byte_stream_putraw(&bs, (guint8 *)xml, strlen(xml) + 1); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -380,7 +380,7 @@ struct tm *tm; gchar *stripped; - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) return -EINVAL; if (!name || !msg || !alias) @@ -411,7 +411,7 @@ byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -436,7 +436,7 @@ byte_stream_putstr(&bs, xml); byte_stream_put8(&bs, 0x00); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -460,7 +460,7 @@ purple_debug_misc("oscar", "aim_icq_getstatusnote: requesting status note for %s.\n", uin); - if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) { purple_debug_misc("oscar", "aim_icq_getstatusnote: no connection.\n"); return -EINVAL; @@ -469,7 +469,7 @@ bslen = 2 + 4 + 2 + 2 + 2 + 2 + 58 + strlen(uin); byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); byte_stream_put16(&bs, 0x0001); byte_stream_put16(&bs, bslen); @@ -497,7 +497,7 @@ byte_stream_put16(&bs, strlen(uin)); byte_stream_putstr(&bs, uin); - flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x000, snacid, &bs); byte_stream_destroy(&bs); @@ -541,7 +541,7 @@ } /** - * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet. + * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet. */ static int icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) @@ -940,7 +940,7 @@ int icq_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0015; + mod->family = SNAC_FAMILY_ICQ; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x047c;
--- a/libpurple/protocols/oscar/family_invite.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_invite.c Mon Jun 30 23:12:54 2008 +0000 @@ -41,7 +41,7 @@ int invite_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0006; + mod->family = SNAC_FAMILY_INVITE; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_locate.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Mon Jun 30 23:12:54 2008 +0000 @@ -171,7 +171,7 @@ {0x09, 0x46, 0xf0, 0x03, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {OSCAR_CAPABILITY_GENERICUNKNOWN, + {OSCAR_CAPABILITY_ICHAT_SCREENSHARE, {0x09, 0x46, 0xf0, 0x04, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, @@ -943,7 +943,7 @@ return 0; } - if ((snac2->family != 0x0002) && (snac2->type != 0x0015)) { + if ((snac2->family != SNAC_FAMILY_LOCATE) && (snac2->type != 0x0015)) { purple_debug_misc("oscar", "faim: locate.c, error(): received response from invalid request! %d\n", snac2->family); return 0; } @@ -1094,12 +1094,12 @@ byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x0002, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1124,12 +1124,12 @@ byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x0002, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1157,13 +1157,13 @@ byte_stream_new(&bs, 2+1+strlen(sn)); - snacid = aim_cachesnac(od, 0x0002, 0x0005, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, NULL, 0); byte_stream_put16(&bs, infotype); byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - flap_connection_send_snac(od, conn, 0x0002, 0x0005, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1274,12 +1274,12 @@ byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - snacid = aim_cachesnac(od, 0x0002, 0x0009, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x0002, 0x0009, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1302,12 +1302,12 @@ byte_stream_new(&bs, 1+strlen(sn)); - snacid = aim_cachesnac(od, 0x0002, 0x000b, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0); byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - flap_connection_send_snac(od, conn, 0x0002, 0x000b, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1347,12 +1347,12 @@ byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0); aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, 0x0002, 0x000f, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs); byte_stream_destroy(&bs); return 0; @@ -1385,8 +1385,8 @@ byte_stream_put8(&bs, strlen(sn)); byte_stream_putstr(&bs, sn); - snacid = aim_cachesnac(od, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, 0x0002, 0x0015, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, sn, strlen(sn)+1); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs); byte_stream_destroy(&bs);
--- a/libpurple/protocols/oscar/family_odir.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_odir.c Mon Jun 30 23:12:54 2008 +0000 @@ -45,7 +45,7 @@ aim_snacid_t snacid; GSList *tlvlist = NULL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region || !email) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region || !email) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ @@ -58,8 +58,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -94,7 +94,7 @@ aim_snacid_t snacid; GSList *tlvlist = NULL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ @@ -126,8 +126,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -149,7 +149,7 @@ aim_snacid_t snacid; GSList *tlvlist = NULL; - if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region) + if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ @@ -163,8 +163,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -252,7 +252,7 @@ int odir_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000f; + mod->family = SNAC_FAMILY_ODIR; mod->version = 0x0001; mod->toolid = 0x0010; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_oservice.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_oservice.c Mon Jun 30 23:12:54 2008 +0000 @@ -54,8 +54,8 @@ } } - snacid = aim_cachesnac(od, 0x0001, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -108,7 +108,7 @@ if(!conn) return; - aim_genericreq_s(od, conn, 0x0001, 0x0004, &serviceid); + aim_genericreq_s(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, &serviceid); } /* @@ -146,8 +146,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi)); - flap_connection_send_snac(od, conn, 0x0001, 0x0004, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, &csi, sizeof(csi)); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -210,7 +210,7 @@ void aim_srv_reqrates(OscarData *od, FlapConnection *conn) { - aim_genericreq_n_snacid(od, conn, 0x0001, 0x0006); + aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_OSERVICE, 0x0006); } /* @@ -389,8 +389,8 @@ byte_stream_put16(&bs, rateclass->classid); } - snacid = aim_cachesnac(od, 0x0001, 0x0008, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x0008, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -412,8 +412,8 @@ byte_stream_put16(&bs, rateclass->classid); } - snacid = aim_cachesnac(od, 0x0001, 0x0009, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x0009, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -503,8 +503,8 @@ for (cur = conn->groups; cur != NULL; cur = cur->next) byte_stream_put16(&bs, GPOINTER_TO_UINT(cur->data)); - snacid = aim_cachesnac(od, 0x0001, 0x000c, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x000c, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -526,7 +526,7 @@ void aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn) { - aim_genericreq_n_snacid(od, conn, 0x0001, 0x000e); + aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_OSERVICE, 0x000e); } /* Subtype 0x000f - Self User Info */ @@ -589,7 +589,7 @@ if(!conn) return; - aim_genericreq_l(od, conn, 0x0001, 0x0011, &idletime); + aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0011, &idletime); } /* @@ -698,7 +698,7 @@ void aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32 flags) { - aim_genericreq_l(od, conn, 0x0001, 0x0014, &flags); + aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0014, &flags); } /* @@ -713,7 +713,7 @@ void aim_srv_nop(OscarData *od, FlapConnection *conn) { - aim_genericreq_n(od, conn, 0x0001, 0x0016); + aim_genericreq_n(od, conn, SNAC_FAMILY_OSERVICE, 0x0016); } /* @@ -753,8 +753,8 @@ } } - snacid = aim_cachesnac(od, 0x0001, 0x0017, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x0017, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, snacid, &bs); byte_stream_destroy(&bs); } @@ -861,8 +861,8 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x001e, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -952,13 +952,10 @@ byte_stream_putraw(&bs, buf, 0x10); } else if (buf && (len > 0)) { /* use input buffer */ - PurpleCipher *cipher; PurpleCipherContext *context; guchar digest[16]; - cipher = purple_ciphers_find_cipher("md5"); - - context = purple_cipher_context_new(cipher, NULL); + context = purple_cipher_context_new_by_name("md5", NULL); purple_cipher_context_append(context, buf, len); purple_cipher_context_digest(context, 16, digest, NULL); purple_cipher_context_destroy(context); @@ -966,7 +963,6 @@ byte_stream_putraw(&bs, digest, 0x10); } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ - PurpleCipher *cipher; PurpleCipherContext *context; guchar digest[16]; guint8 nil = '\0'; @@ -975,9 +971,7 @@ * I'm not sure if we really need the empty append with the * new MD5 functions, so I'll leave it in, just in case. */ - cipher = purple_ciphers_find_cipher("md5"); - - context = purple_cipher_context_new(cipher, NULL); + context = purple_cipher_context_new_by_name("md5", NULL); purple_cipher_context_append(context, &nil, 0); purple_cipher_context_digest(context, 16, digest, NULL); purple_cipher_context_destroy(context); @@ -1012,8 +1006,8 @@ } - snacid = aim_cachesnac(od, 0x0001, 0x0020, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, 0x0001, 0x0020, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, NULL, 0); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -1100,7 +1094,7 @@ int service_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0001; + mod->family = SNAC_FAMILY_OSERVICE; mod->version = 0x0003; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/family_popup.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_popup.c Mon Jun 30 23:12:54 2008 +0000 @@ -72,7 +72,7 @@ int popups_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x0008; + mod->family = SNAC_FAMILY_POPUP; mod->version = 0x0001; mod->toolid = 0x0104; mod->toolversion = 0x0001;
--- a/libpurple/protocols/oscar/family_stats.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_stats.c Mon Jun 30 23:12:54 2008 +0000 @@ -52,7 +52,7 @@ int stats_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000b; + mod->family = SNAC_FAMILY_STATS; mod->version = 0x0001; mod->toolid = 0x0104; mod->toolversion = 0x0001;
--- a/libpurple/protocols/oscar/family_translate.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_translate.c Mon Jun 30 23:12:54 2008 +0000 @@ -34,7 +34,7 @@ int translate_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000c; + mod->family = SNAC_FAMILY_TRANSLATE; mod->version = 0x0001; mod->toolid = 0x0104; mod->toolversion = 0x0001;
--- a/libpurple/protocols/oscar/family_userlookup.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/family_userlookup.c Mon Jun 30 23:12:54 2008 +0000 @@ -74,8 +74,8 @@ byte_stream_putstr(&bs, address); - snacid = aim_cachesnac(od, 0x000a, 0x0002, 0x0000, address, strlen(address)+1); - flap_connection_send_snac(od, conn, 0x000a, 0x0002, 0x0000, snacid, &bs); + snacid = aim_cachesnac(od, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, address, strlen(address)+1); + flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, snacid, &bs); byte_stream_destroy(&bs); @@ -145,7 +145,7 @@ int search_modfirst(OscarData *od, aim_module_t *mod) { - mod->family = 0x000a; + mod->family = SNAC_FAMILY_USERLOOKUP; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x0629;
--- a/libpurple/protocols/oscar/oscar.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Mon Jun 30 23:12:54 2008 +0000 @@ -131,8 +131,8 @@ N_("Busted SNAC payload"), N_("Insufficient rights"), N_("In local permit/deny"), - N_("Too evil (sender)"), - N_("Too evil (receiver)"), + N_("Warning level too high (sender)"), + N_("Warning level too high (receiver)"), N_("User temporarily unavailable"), N_("No match"), N_("List overflow"), @@ -707,6 +707,9 @@ case OSCAR_CAPABILITY_CAMERA: tmp = _("Camera"); break; + case OSCAR_CAPABILITY_ICHAT_SCREENSHARE: + tmp = _("Screen Sharing"); + break; default: tmp = NULL; break; @@ -753,7 +756,7 @@ const char *name, const char *value) { gchar *utf8; - + if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, value))) { purple_notify_user_info_add_pair(user_info, name, utf8); g_free(utf8); @@ -765,14 +768,148 @@ const char *name, const char *value) { gchar *utf8; - + if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, value))) { purple_notify_user_info_add_pair(user_info, name, utf8); g_free(utf8); } } -static void oscar_string_append_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) +/** + * @brief Append the status information to a user_info struct + * + * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML. + * + * @param gc The PurpleConnection + * @param user_info A PurpleNotifyUserInfo object to which status information will be added + * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status(). + * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status(). + * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped. + */ +static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags) +{ + PurpleAccount *account = purple_connection_get_account(gc); + OscarData *od; + PurplePresence *presence = NULL; + PurpleStatus *status = NULL; + gchar *message = NULL, *itmsurl = NULL, *tmp; + gboolean is_away; + + od = gc->proto_data; + + if (userinfo == NULL) + userinfo = aim_locate_finduserinfo(od, b->name); + + if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL))) + return; + + if (b == NULL) + b = purple_find_buddy(purple_connection_get_account(gc), userinfo->sn); + + if (b) { + presence = purple_buddy_get_presence(b); + status = purple_presence_get_active_status(presence); + + message = g_strdup(purple_status_get_attr_string(status, "message")); + itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl")); + + } else { + /* This is an OSCAR contact for whom we don't have a PurpleBuddy but do have information. */ + if ((userinfo->flags & AIM_FLAG_AWAY)) { + /* Away message? */ + if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { + tmp = oscar_encoding_extract(userinfo->away_encoding); + message = oscar_encoding_to_utf8(account, tmp, userinfo->away, + userinfo->away_len); + g_free(tmp); + } + } else { + /* Available message? */ + if ((userinfo->status != NULL) && userinfo->status[0] != '\0') { + message = oscar_encoding_to_utf8(account, userinfo->status_encoding, + userinfo->status, userinfo->status_len); + } +#if defined (_WIN32) || defined (__APPLE__) + if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) + itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, + userinfo->itmsurl, userinfo->itmsurl_len); +#endif + } + } + + is_away = ((status && !purple_status_is_available(status)) || + (userinfo && (userinfo->flags & AIM_FLAG_AWAY))); + + if (strip_html_tags) { + /* Away messges are HTML, but available messages were originally plain text. + * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags. + */ + if (is_away && message) { + gchar *tmp2; + tmp = purple_markup_strip_html(message); + g_free(message); + tmp2 = g_markup_escape_text(tmp, -1); + g_free(tmp); + message = tmp2; + } + + } else { + if (itmsurl) { + tmp = g_strdup_printf("<a href=\"%s\">%s</a>", + itmsurl, message); + g_free(itmsurl); + g_free(message); + message = tmp; + } + } + + if (is_away && message) { + tmp = purple_str_sub_away_formatters(message, purple_account_get_username(account)); + g_free(message); + message = tmp; + } + + if (b) { + if (purple_presence_is_online(presence)) { + if (aim_snvalid_icq(b->name) || is_away || !message || !(*message)) { + /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message. + * If the status name and the message are the same, only show one. */ + const char *status_name = purple_status_get_name(status); + if (status_name && message && !strcmp(status_name, message)) + status_name = NULL; + + tmp = g_strdup_printf("%s%s%s", + status_name, + ((status_name && message) && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } + + } else { + if (aim_ssi_waitingforauth(od->ssi.local, + aim_ssi_itemlist_findparentname(od->ssi.local, b->name), + b->name)) { + /* Note if an offline buddy is not authorized */ + tmp = g_strdup_printf("%s%s%s", + _("Not Authorized"), + (message && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } else { + g_free(message); + message = g_strdup(_("Offline")); + } + } + + } + + purple_notify_user_info_add_pair(user_info, _("Status"), message); + g_free(message); +} + +static void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) { OscarData *od; PurpleAccount *account; @@ -803,21 +940,6 @@ if (userinfo != NULL) bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->sn)); - if (b != NULL) { - if (purple_presence_is_online(presence)) { - if (aim_snvalid_icq(b->name)) { - PurpleStatus *status = purple_presence_get_active_status(presence); - oscar_user_info_add_pair(user_info, _("Status"), purple_status_get_name(status)); - } - } else { - tmp = aim_ssi_itemlist_findparentname(od->ssi.local, b->name); - if (aim_ssi_waitingforauth(od->ssi.local, tmp, b->name)) - oscar_user_info_add_pair(user_info, _("Status"), _("Not Authorized")); - else - oscar_user_info_add_pair(user_info, _("Status"), _("Offline")); - } - } - if ((bi != NULL) && (bi->ipaddr != 0)) { tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", (bi->ipaddr & 0xff000000) >> 24, @@ -828,7 +950,6 @@ g_free(tmp); } - if ((userinfo != NULL) && (userinfo->warnlevel != 0)) { tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5)); oscar_user_info_add_pair(user_info, _("Warning Level"), tmp); @@ -976,8 +1097,8 @@ if (source < 0) { - purple_debug_error("oscar", "unable to connect FLAP server " - "of type 0x%04hx\n", conn->type); + purple_debug_error("oscar", "unable to connect to FLAP " + "server of type 0x%04hx\n", conn->type); if (conn->type == SNAC_FAMILY_AUTH) { gchar *msg; @@ -1693,7 +1814,8 @@ aim_send_login(od, conn, purple_account_get_username(account), purple_connection_get_password(gc), truncate_pass, - od->icq ? &icqinfo : &aiminfo, key); + od->icq ? &icqinfo : &aiminfo, key, + /* allow multple logins? */ purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS)); purple_connection_update_progress(gc, _("Password sent"), 2, OSCAR_CONNECT_STEPS); ck[2] = 0x6c; @@ -1829,6 +1951,7 @@ { char *message = NULL; char *itmsurl = NULL; + char *tmp; if (info->status != NULL && info->status[0] != '\0') /* Grab the available message */ @@ -1840,15 +1963,31 @@ itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, info->itmsurl, info->itmsurl_len); + tmp = (message ? g_markup_escape_text(message, -1) : NULL); + + if (message == NULL && itmsurl != NULL) + message = ""; + purple_prpl_got_user_status(account, info->sn, status_id, - "message", message, "itmsurl", itmsurl, NULL); + "message", tmp, "itmsurl", itmsurl, NULL); + g_free(tmp); g_free(message); g_free(itmsurl); } else { - purple_prpl_got_user_status(account, info->sn, status_id, NULL); + PurpleBuddy *b = purple_find_buddy(account, info->sn); + PurplePresence *presence = purple_buddy_get_presence(b); + PurpleStatus *old_status = purple_presence_get_active_status(presence); + PurpleStatus *new_status = purple_presence_get_status(presence, status_id); + + /* If our status_id would change with this update, pass it to the core. + * However, if our status_id would not change, do nothing, as we would clear out any existing + * attributes on the status prematurely. purple_got_infoblock() will update the message as needed. + */ + if (old_status != new_status) + purple_prpl_got_user_status(account, info->sn, status_id, NULL); } /* Login time stuff */ @@ -2636,7 +2775,7 @@ switch(reason) { case 0: /* Invalid (0) */ buf = g_strdup_printf( - dngettext(PACKAGE, + dngettext(PACKAGE, "You missed %hu message from %s because it was invalid.", "You missed %hu messages from %s because they were invalid.", nummissed), @@ -2645,7 +2784,7 @@ break; case 1: /* Message too large */ buf = g_strdup_printf( - dngettext(PACKAGE, + dngettext(PACKAGE, "You missed %hu message from %s because it was too large.", "You missed %hu messages from %s because they were too large.", nummissed), @@ -2654,7 +2793,7 @@ break; case 2: /* Rate exceeded */ buf = g_strdup_printf( - dngettext(PACKAGE, + dngettext(PACKAGE, "You missed %hu message from %s because the rate limit has been exceeded.", "You missed %hu messages from %s because the rate limit has been exceeded.", nummissed), @@ -2663,25 +2802,25 @@ break; case 3: /* Evil Sender */ buf = g_strdup_printf( - dngettext(PACKAGE, - "You missed %hu message from %s because he/she was too evil.", - "You missed %hu messages from %s because he/she was too evil.", + dngettext(PACKAGE, + "You missed %hu message from %s because his/her warning level is too high.", + "You missed %hu messages from %s because his/her warning level is too high.", nummissed), nummissed, userinfo->sn); break; case 4: /* Evil Receiver */ buf = g_strdup_printf( - dngettext(PACKAGE, - "You missed %hu message from %s because you are too evil.", - "You missed %hu messages from %s because you are too evil.", + dngettext(PACKAGE, + "You missed %hu message from %s because your warning level is too high.", + "You missed %hu messages from %s because your warning level is too high.", nummissed), nummissed, userinfo->sn); break; default: buf = g_strdup_printf( - dngettext(PACKAGE, + dngettext(PACKAGE, "You missed %hu message from %s for an unknown reason.", "You missed %hu messages from %s for an unknown reason.", nummissed), @@ -2737,9 +2876,9 @@ /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ statusmsg = oscar_icqstatus(state); splitmsg = g_strsplit(msg, "\r\n", 0); - + user_info = purple_notify_user_info_new(); - + purple_notify_user_info_add_pair(user_info, _("UIN"), who); purple_notify_user_info_add_pair(user_info, _("Status"), statusmsg); purple_notify_user_info_add_section_break(user_info); @@ -2920,7 +3059,7 @@ PurpleConnection *gc = od->gc; PurpleAccount *account = purple_connection_get_account(gc); PurpleNotifyUserInfo *user_info; - gchar *tmp = NULL, *info_utf8 = NULL, *away_utf8 = NULL; + gchar *tmp = NULL, *info_utf8 = NULL; va_list ap; aim_userinfo_t *userinfo; @@ -2929,9 +3068,19 @@ va_end(ap); user_info = purple_notify_user_info_new(); - purple_notify_user_info_add_pair(user_info, _("Username"), userinfo->sn); - - if (userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) { + + oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE); + + if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) { + tmp = purple_str_seconds_to_string(userinfo->idletime*60); + oscar_user_info_add_pair(user_info, _("Idle"), tmp); + g_free(tmp); + } + + oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo); + + if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !aim_snvalid_sms(userinfo->sn)) { + /* An SMS contact is always online; its Online Since valid is not useful */ time_t t = userinfo->onlinesince; oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); } @@ -2947,50 +3096,6 @@ g_free(tmp); } - if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) { - tmp = purple_str_seconds_to_string(userinfo->idletime*60); - oscar_user_info_add_pair(user_info, _("Idle"), tmp); - g_free(tmp); - } - - oscar_string_append_info(gc, user_info, NULL, userinfo); - - /* Available message */ - if ((userinfo->status != NULL) && !(userinfo->flags & AIM_FLAG_AWAY)) - { - if (userinfo->status[0] != '\0') - tmp = oscar_encoding_to_utf8(account, userinfo->status_encoding, - userinfo->status, userinfo->status_len); -#if defined (_WIN32) || defined (__APPLE__) - if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) { - gchar *itmsurl, *tmp2; - itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, - userinfo->itmsurl, userinfo->itmsurl_len); - tmp2 = g_strdup_printf("<a href=\"%s\">%s</a>", - itmsurl, tmp); - g_free(tmp); - tmp = tmp2; - g_free(itmsurl); - } -#endif - oscar_user_info_add_pair(user_info, _("Available Message"), tmp); - g_free(tmp); - } - - /* Away message */ - if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { - tmp = oscar_encoding_extract(userinfo->away_encoding); - away_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->away, - userinfo->away_len); - g_free(tmp); - if (away_utf8 != NULL) { - tmp = purple_str_sub_away_formatters(away_utf8, purple_account_get_username(account)); - oscar_user_info_add_pair(user_info, _("Away Message"), tmp); - g_free(tmp); - g_free(away_utf8); - } - } - /* Info */ if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->info_encoding); @@ -3429,8 +3534,8 @@ if (code == AIM_RATE_CODE_LIMIT) { purple_debug_warning("oscar", _("The last action you attempted could not be " - "performed because you are over the rate limit. " - "Please wait 10 seconds and try again.")); + "performed because you are over the rate limit. " + "Please wait 10 seconds and try again.")); } return 1; @@ -3687,12 +3792,9 @@ PurpleConnection *gc; PurpleAccount *account; PurpleBuddy *buddy; - PurplePresence *presence; - PurpleStatus *status; struct buddyinfo *bi; gchar who[16]; PurpleNotifyUserInfo *user_info; - GString *tmp; gchar *utf8; gchar *buf; const gchar *alias; @@ -3710,7 +3812,7 @@ return 0; user_info = purple_notify_user_info_new(); - + g_snprintf(who, sizeof(who), "%u", info->uin); buddy = purple_find_buddy(purple_connection_get_account(gc), who); if (buddy != NULL) @@ -3782,24 +3884,8 @@ g_free(utf8); } - if (buddy != NULL) { - const gchar *message; - gchar *utf8, *tmp; - - presence = purple_buddy_get_presence(buddy); - status = purple_presence_get_active_status(presence); - message = purple_status_get_attr_string(status, "message"); - - utf8 = message && message[0] ? oscar_utf8_try_convert(account, message) : NULL; - tmp = g_strdup_printf("%s%s%s", - purple_status_get_name(status), - utf8 && *utf8 ? ": " : "", - utf8 && *utf8 ? utf8 : ""); - g_free(utf8); - - purple_notify_user_info_add_pair(user_info, _("Status"), tmp); - g_free(tmp); - } + if (buddy != NULL) + oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE); oscar_user_info_convert_and_add(account, user_info, _("Additional Information"), info->info); purple_notify_user_info_add_section_break(user_info); @@ -3814,7 +3900,7 @@ } if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { purple_notify_user_info_add_section_header(user_info, _("Work Address")); - + oscar_user_info_convert_and_add(account, user_info, _("Address"), info->workaddr); oscar_user_info_convert_and_add(account, user_info, _("City"), info->workcity); oscar_user_info_convert_and_add(account, user_info, _("State"), info->workstate); @@ -3822,11 +3908,11 @@ } if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { purple_notify_user_info_add_section_header(user_info, _("Work Information")); - + oscar_user_info_convert_and_add(account, user_info, _("Company"), info->workcompany); oscar_user_info_convert_and_add(account, user_info, _("Division"), info->workdivision); oscar_user_info_convert_and_add(account, user_info, _("Position"), info->workposition); - + if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->workwebpage))) { char *webpage = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8); purple_notify_user_info_add_pair(user_info, _("Web Page"), webpage); @@ -4333,14 +4419,14 @@ /* If the length was too long, try stripping the HTML and then running it back through * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ g_free((char *)args.msg); - + tmp2 = purple_markup_strip_html(tmp1); g_free(tmp1); /* re-escape the entities */ tmp1 = g_markup_escape_text(tmp2, -1); g_free(tmp2); - + tmp2 = purple_strdup_withhtml(tmp1); g_free(tmp1); tmp1 = tmp2; @@ -5570,7 +5656,7 @@ return "aim"; } -const char* oscar_list_emblem(PurpleBuddy *b) +const char *oscar_list_emblem(PurpleBuddy *b) { PurpleConnection *gc = NULL; OscarData *od = NULL; @@ -5600,7 +5686,7 @@ return "not-authorized"; } } - + if (userinfo != NULL ) { if (userinfo->flags & AIM_FLAG_ADMINISTRATOR) return "admin"; @@ -5616,54 +5702,23 @@ return NULL; } -void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) { - PurpleConnection *gc = b->account->gc; - OscarData *od = gc->proto_data; - aim_userinfo_t *userinfo = aim_locate_finduserinfo(od, b->name); - - if (PURPLE_BUDDY_IS_ONLINE(b)) { - PurplePresence *presence; - PurpleStatus *status; - const char *message; - - if (full) - oscar_string_append_info(gc, user_info, b, userinfo); - - presence = purple_buddy_get_presence(b); - status = purple_presence_get_active_status(presence); - message = purple_status_get_attr_string(status, "message"); - - if (purple_status_is_available(status)) - { - if (message != NULL) - { - /* Available status messages are plain text */ - gchar *tmp; - tmp = g_markup_escape_text(message, -1); - purple_notify_user_info_add_pair(user_info, _("Message"), tmp); - g_free(tmp); - } - } - else - { - if (message != NULL) - { - /* Away messages are HTML */ - gchar *tmp1, *tmp2; - tmp2 = purple_markup_strip_html(message); - tmp1 = g_markup_escape_text(tmp2, -1); - g_free(tmp2); - tmp2 = purple_str_sub_away_formatters(tmp1, purple_account_get_username(purple_connection_get_account(gc))); - g_free(tmp1); - purple_notify_user_info_add_pair(user_info, _("Away Message"), tmp2); - g_free(tmp2); - } - else - { - purple_notify_user_info_add_pair(user_info, _("Away Message"), _("<i>(retrieving)</i>")); - } - } - } +void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) +{ + PurpleConnection *gc; + OscarData *od; + aim_userinfo_t *userinfo; + + if (!PURPLE_BUDDY_IS_ONLINE(b)) + return; + + gc = b->account->gc; + od = gc->proto_data; + userinfo = aim_locate_finduserinfo(od, b->name); + + oscar_user_info_append_status(gc, user_info, b, userinfo, /* strip_html_tags */ TRUE); + + if (full) + oscar_user_info_append_extra_info(gc, user_info, b, userinfo); } char *oscar_status_text(PurpleBuddy *b) @@ -5698,7 +5753,7 @@ message = purple_status_get_attr_string(status, "message"); if (message != NULL) { - ret = g_markup_escape_text(message, -1); + ret = g_strdup(message); purple_util_chrreplace(ret, '\n', ' '); } } @@ -6369,15 +6424,12 @@ if (img == NULL) { aim_ssi_delicon(od); } else { - PurpleCipher *cipher; PurpleCipherContext *context; guchar md5[16]; gconstpointer data = purple_imgstore_get_data(img); size_t len = purple_imgstore_get_size(img); - - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); + context = purple_cipher_context_new_by_name("md5", NULL); purple_cipher_context_append(context, data, len); purple_cipher_context_digest(context, 16, md5, NULL); purple_cipher_context_destroy(context); @@ -6731,6 +6783,10 @@ OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY); prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); + option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins", + OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS); + prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); + if (init) return; init = TRUE;
--- a/libpurple/protocols/oscar/oscar.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.h Mon Jun 30 23:12:54 2008 +0000 @@ -353,7 +353,8 @@ OSCAR_CAPABILITY_ICHATAV = 0x02000000, OSCAR_CAPABILITY_LIVEVIDEO = 0x04000000, OSCAR_CAPABILITY_CAMERA = 0x08000000, - OSCAR_CAPABILITY_LAST = 0x10000000 + OSCAR_CAPABILITY_ICHAT_SCREENSHARE = 0x10000000, + OSCAR_CAPABILITY_LAST = 0x20000000 } OscarCapability; /* @@ -594,7 +595,7 @@ void aim_clientready(OscarData *od, FlapConnection *conn); int aim_request_login(OscarData *od, FlapConnection *conn, const char *sn); -int aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key); +int aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins); /* 0x000b */ int aim_auth_securid_send(OscarData *od, const char *securid); void aim_cleansnacs(OscarData *, int maxage);
--- a/libpurple/protocols/oscar/oscarcommon.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Mon Jun 30 23:12:54 2008 +0000 @@ -41,6 +41,7 @@ #define OSCAR_DEFAULT_HIDE_IP TRUE #define OSCAR_DEFAULT_WEB_AWARE FALSE #define OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY FALSE +#define OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS TRUE #ifdef _WIN32 const char *oscar_get_locale_charset(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/ChangeLog Mon Jun 30 23:12:54 2008 +0000 @@ -0,0 +1,49 @@ +2008.06.07 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com> + * Clean code and apply patches from QuLogic + +2008.05.19 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com> + * Reconnect server 5 time in 5000 ms, when connect failed + * Rename sendqueue.c/sendqueue.h to qq_trans.c/qq_trans.h + * Rewrite packet_process + * Rewrite qq_send_cmd + * Create server list, try to connect every server when failed + +2008.05.14 - ccpaging <ecc_hy(at)hotmail.com> + * Move function for before login packets storing to sendqueue + * Use transaction data structure to store before login packets + * Rewrite tcp_pending and packet_process in qq_network.c + +2008.05.09 - ccpaging <ecc_hy(at)hotmail.com> + * Remove function _create_packet_head_seq in qq_network.c + * Create new function encap in qq_netowork.c + * Clean code of qq_send_packet_request_login_token and qq_send_packet_login in login_out.c + +2008.05.09 - ccpaging <ecc_hy(at)hotmail.com> + * Clean code of packet_parse.c, enable PARSER_DEBUG + * Rewrite send_queue + +2008.05.08 - ccpaging <ecc_hy(at)hotmail.com> + * Rewrite qq_network + * Add srv resolve function when qq_login + * Merge function _qq_common_clean in qq_proxy.c to qq_disconnect + * Move orignal qq_disconnect to qq_close + * qq_data alloc in qq_open and release in qq_close + * Network connect of QQ is created in qq_connect, and release in qq_disconnect + +2008.05.05 - ccpaging <ecc_hy(at)hotmail.com> + * Merge function _qq_common_clean in qq_proxy.c to qq_disconnect + * Move orignal qq_disconnect to qq_close + * qq_data alloc in qq_open and release in qq_close + * Network connect of QQ is created in qq_connect, and release in qq_disconnect + +2008.05.05 - ccpaging <ecc_hy(at)hotmail.com> + * Add qq_hex_dump function + +2008.04.25 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com> + * Rewrite read_packet and create_packet functions, use qq_put and qq_get functions instead + * New logic in accord with protocol models to handle packets, some related functions rewritten + +2008.03.24 - ccpaging <ecc_hy(at)hotmail.com> + * Remove qq_crypt function in crypt.c, use qq_crypt and qq_decrypt directly + +** since pidgin-2.4.0 ***
--- a/libpurple/protocols/qq/Makefile.am Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.am Mon Jun 30 23:12:54 2008 +0000 @@ -52,20 +52,14 @@ packet_parse.h \ qq.c \ qq.h \ - qq_proxy.c \ - qq_proxy.h \ - recv_core.c \ - recv_core.h \ - send_core.c \ - send_core.h \ + qq_network.c \ + qq_network.h \ send_file.c \ send_file.h \ - sendqueue.c \ - sendqueue.h \ + qq_trans.c \ + qq_trans.h \ sys_msg.c \ sys_msg.h \ - udp_proxy_s5.c \ - udp_proxy_s5.h \ utils.c \ utils.h
--- a/libpurple/protocols/qq/Makefile.mingw Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.mingw Mon Jun 30 23:12:54 2008 +0000 @@ -63,13 +63,10 @@ login_logout.c \ packet_parse.c \ qq.c \ - qq_proxy.c \ - recv_core.c \ - send_core.c \ + qq_network.c \ send_file.c \ - sendqueue.c \ + qq_trans.c \ sys_msg.c \ - udp_proxy_s5.c \ utils.c OBJECTS = $(C_SRC:%.c=%.o)
--- a/libpurple/protocols/qq/buddy_info.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Mon Jun 30 23:12:54 2008 +0000 @@ -34,7 +34,7 @@ #include "crypt.h" #include "header_info.h" #include "keep_alive.h" -#include "send_core.h" +#include "qq_network.h" #define QQ_PRIMARY_INFORMATION _("Primary Information") #define QQ_ADDITIONAL_INFORMATION _("Additional Information") @@ -94,6 +94,46 @@ gboolean modify_info; } qq_info_query; +typedef struct _contact_info { + gchar *uid; + gchar *nick; + gchar *country; + gchar *province; + gchar *zipcode; + gchar *address; + gchar *tel; + gchar *age; + gchar *gender; + gchar *name; + gchar *email; + gchar *pager_sn; + gchar *pager_num; + gchar *pager_sp; + gchar *pager_base_num; + gchar *pager_type; + gchar *occupation; + gchar *homepage; + gchar *auth_type; + gchar *unknown1; + gchar *unknown2; + gchar *face; + gchar *hp_num; + gchar *hp_type; + gchar *intro; + gchar *city; + gchar *unknown3; + gchar *unknown4; + gchar *unknown5; + gchar *is_open_hp; + gchar *is_open_contact; + gchar *college; + gchar *horoscope; + gchar *zodiac; + gchar *blood; + gchar *qq_show; + gchar *unknown6; /* always 0x2D */ +} contact_info; + /* We get an info packet on ourselves before we modify our information. * Even though not all of the information is modifiable, it still * all needs to be there when we send out the modify info packet */ @@ -137,7 +177,7 @@ } else { return NULL; } - /* else ASCIIized index */ + /* else ASCIIized index */ } else { if (strcmp(choice[index], "-") != 0) return g_strdup(choice[index]); @@ -161,14 +201,14 @@ if (value != NULL) { purple_notify_user_info_add_pair(user_info, title, value); g_free(value); - + return TRUE; } - + return FALSE; } -static PurpleNotifyUserInfo * + static PurpleNotifyUserInfo * info_to_notify_user_info(const contact_info *info) { PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); @@ -209,25 +249,25 @@ /* for debugging */ /* - g_string_append_printf(info_text, "<br /><br /><b>%s</b><br />", "Miscellaneous"); - append_field_value(info_text, info->pager_sn, "pager_sn", NULL, 0); - append_field_value(info_text, info->pager_num, "pager_num", NULL, 0); - append_field_value(info_text, info->pager_sp, "pager_sp", NULL, 0); - append_field_value(info_text, info->pager_base_num, "pager_base_num", NULL, 0); - append_field_value(info_text, info->pager_type, "pager_type", NULL, 0); - append_field_value(info_text, info->auth_type, "auth_type", NULL, 0); - append_field_value(info_text, info->unknown1, "unknown1", NULL, 0); - append_field_value(info_text, info->unknown2, "unknown2", NULL, 0); - append_field_value(info_text, info->face, "face", NULL, 0); - append_field_value(info_text, info->hp_type, "hp_type", NULL, 0); - append_field_value(info_text, info->unknown3, "unknown3", NULL, 0); - append_field_value(info_text, info->unknown4, "unknown4", NULL, 0); - append_field_value(info_text, info->unknown5, "unknown5", NULL, 0); - append_field_value(info_text, info->is_open_hp, "is_open_hp", NULL, 0); - append_field_value(info_text, info->is_open_contact, "is_open_contact", NULL, 0); - append_field_value(info_text, info->qq_show, "qq_show", NULL, 0); - append_field_value(info_text, info->unknown6, "unknown6", NULL, 0); - */ + g_string_append_printf(info_text, "<br /><br /><b>%s</b><br />", "Miscellaneous"); + append_field_value(info_text, info->pager_sn, "pager_sn", NULL, 0); + append_field_value(info_text, info->pager_num, "pager_num", NULL, 0); + append_field_value(info_text, info->pager_sp, "pager_sp", NULL, 0); + append_field_value(info_text, info->pager_base_num, "pager_base_num", NULL, 0); + append_field_value(info_text, info->pager_type, "pager_type", NULL, 0); + append_field_value(info_text, info->auth_type, "auth_type", NULL, 0); + append_field_value(info_text, info->unknown1, "unknown1", NULL, 0); + append_field_value(info_text, info->unknown2, "unknown2", NULL, 0); + append_field_value(info_text, info->face, "face", NULL, 0); + append_field_value(info_text, info->hp_type, "hp_type", NULL, 0); + append_field_value(info_text, info->unknown3, "unknown3", NULL, 0); + append_field_value(info_text, info->unknown4, "unknown4", NULL, 0); + append_field_value(info_text, info->unknown5, "unknown5", NULL, 0); + append_field_value(info_text, info->is_open_hp, "is_open_hp", NULL, 0); + append_field_value(info_text, info->is_open_contact, "is_open_contact", NULL, 0); + append_field_value(info_text, info->qq_show, "qq_show", NULL, 0); + append_field_value(info_text, info->unknown6, "unknown6", NULL, 0); + */ return user_info; } @@ -243,7 +283,7 @@ qd = (qq_data *) gc->proto_data; g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(qd, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str)); query = g_new0(qq_info_query, 1); query->uid = uid; @@ -271,27 +311,141 @@ } /* send packet to modify personal information */ -static void qq_send_packet_modify_info(PurpleConnection *gc, gchar **segments) +static void qq_send_packet_modify_info(PurpleConnection *gc, contact_info *info) { - gint i; - guint8 *raw_data, *cursor, bar; + qq_data *qd = (qq_data *) gc->proto_data; + gint bytes = 0; + guint8 raw_data[MAX_PACKET_SIZE - 128] = {0}; + guint8 bar; - g_return_if_fail(segments != NULL); + g_return_if_fail(info != NULL); bar = 0x1f; - raw_data = g_newa(guint8, MAX_PACKET_SIZE - 128); - cursor = raw_data; - create_packet_b(raw_data, &cursor, bar); + bytes += qq_put8(raw_data + bytes, bar); /* important! skip the first uid entry */ - for (i = 1; i < QQ_CONTACT_FIELDS; i++) { - create_packet_b(raw_data, &cursor, bar); - create_packet_data(raw_data, &cursor, (guint8 *) segments[i], strlen(segments[i])); - } - create_packet_b(raw_data, &cursor, bar); + /* + for (i = 1; i < QQ_CONTACT_FIELDS; i++) { + create_packet_b(raw_data, &cursor, bar); + create_packet_data(raw_data, &cursor, (guint8 *) segments[i], strlen(segments[i])); + } + */ + /* uid */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->uid, strlen(info->uid)); + /* nick */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->nick, strlen(info->nick)); + /* country */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->country, strlen(info->country)); + /* province */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->province, strlen(info->province)); + /* zipcode */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->zipcode, strlen(info->zipcode)); + /* address */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->address, strlen(info->address)); + /* tel */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->tel, strlen(info->tel)); + /* age */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->age, strlen(info->age)); + /* gender */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->gender, strlen(info->gender)); + /* name */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->name, strlen(info->name)); + /* email */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->email, strlen(info->email)); + /* pager_sn */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_sn, strlen(info->pager_sn)); + /* pager_num */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_num, strlen(info->pager_num)); + /* pager_sp */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_sp, strlen(info->pager_sp)); + /* pager_base_num */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_base_num, strlen(info->pager_base_num)); + /* pager_type */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->pager_type, strlen(info->pager_type)); + /* occupation */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->occupation, strlen(info->occupation)); + /* homepage */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->homepage, strlen(info->homepage)); + /* auth_type */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->auth_type, strlen(info->auth_type)); + /* unknown1 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown1, strlen(info->unknown1)); + /* unknown2 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown2, strlen(info->unknown2)); + /* face */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->face, strlen(info->face)); + /* hp_num */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->hp_num, strlen(info->hp_num)); + /* hp_type */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->hp_type, strlen(info->hp_type)); + /* intro */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->intro, strlen(info->intro)); + /* city */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->city, strlen(info->city)); + /* unknown3 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown3, strlen(info->unknown3)); + /* unknown4 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown4, strlen(info->unknown4)); + /* unknown5 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown5, strlen(info->unknown5)); + /* is_open_hp */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->is_open_hp, strlen(info->is_open_hp)); + /* is_open_contact */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->is_open_contact, strlen(info->is_open_contact)); + /* college */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->college, strlen(info->college)); + /* horoscope */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->horoscope, strlen(info->horoscope)); + /* zodiac */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->zodiac, strlen(info->zodiac)); + /* blood */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->blood, strlen(info->blood)); + /* qq_show */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->qq_show, strlen(info->qq_show)); + /* unknown6 */ + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *)info->unknown6, strlen(info->unknown6)); - qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, cursor - raw_data); + bytes += qq_put8(raw_data + bytes, bar); + + qq_send_cmd(qd, QQ_CMD_UPDATE_INFO, raw_data, bytes); } @@ -407,8 +561,11 @@ groups = groups->next; } - /* This casting looks like a horrible idea to me -DAA */ - qq_send_packet_modify_info(gc, (gchar **) info); + /* This casting looks like a horrible idea to me -DAA + * yes, rewritten -s3e + * qq_send_packet_modify_info(gc, (gchar **) info); + */ + qq_send_packet_modify_info(gc, info); g_strfreev((gchar **) mid->info); g_free(mid); @@ -520,11 +677,11 @@ mid->info->unknown6 = g_strdup(info->unknown6); purple_request_fields(gc, _("Modify my information"), - _("Modify my information"), NULL, fields, - _("Update my information"), G_CALLBACK(modify_info_ok_cb), - _("Cancel"), G_CALLBACK(modify_info_cancel_cb), - purple_connection_get_account(gc), NULL, NULL, - mid); + _("Modify my information"), NULL, fields, + _("Update my information"), G_CALLBACK(modify_info_ok_cb), + _("Cancel"), G_CALLBACK(modify_info_cancel_cb), + purple_connection_get_account(gc), NULL, NULL, + mid); } } @@ -578,10 +735,9 @@ gchar *data; gsize len; - if (!g_file_get_contents(iconfile, &data, &len, NULL)) + if (!g_file_get_contents(iconfile, &data, &len, NULL)) { g_return_if_reached(); - else - { + } else { purple_buddy_icons_set_for_user(account, who, data, len, icon_num); } } @@ -608,10 +764,10 @@ /* make sure we're using an appropriate icon */ if (!(g_ascii_strncasecmp(icon_path, buddy_icon_dir, dir_len) == 0 - && icon_path[dir_len] == G_DIR_SEPARATOR - && g_ascii_strncasecmp(icon_path + dir_len + 1, QQ_ICON_PREFIX, prefix_len) == 0 - && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 - && icon_len <= 3)) { + && icon_path[dir_len] == G_DIR_SEPARATOR + && g_ascii_strncasecmp(icon_path + dir_len + 1, QQ_ICON_PREFIX, prefix_len) == 0 + && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 + && icon_len <= 3)) { if (icon_global) purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); else @@ -650,13 +806,13 @@ old_icon_num = purple_buddy_icons_get_checksum_for_user(buddy); if (old_icon_num == NULL || - strcmp(icon_num_str, old_icon_num)) + strcmp(icon_num_str, old_icon_num)) { gchar *icon_path; icon_path = g_strconcat(qq_buddy_icon_dir(), G_DIR_SEPARATOR_S, - QQ_ICON_PREFIX, icon_num_str, - QQ_ICON_SUFFIX, NULL); + QQ_ICON_PREFIX, icon_num_str, + QQ_ICON_SUFFIX, NULL); qq_set_buddy_icon_for_user(account, name, icon_num_str, icon_path); g_free(icon_path); @@ -665,7 +821,7 @@ } /* after getting info or modify myself, refresh the buddy list accordingly */ -void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc) +static void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc) { PurpleBuddy *b; qq_data *qd; @@ -728,7 +884,7 @@ qd->modifying_face = FALSE; g_free(info->face); info->face = icon; - qq_send_packet_modify_info(gc, segments); + qq_send_packet_modify_info(gc, (contact_info *)segments); } qq_refresh_buddy_and_myself(info, gc); @@ -777,39 +933,41 @@ void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid) { - guint8 buf[5]; - guint32 tmp = g_htonl(uid); - buf[0] = 0; - memcpy(buf+1, &tmp, 4); - qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, 5); + qq_data *qd = (qq_data *) gc->proto_data; + guint8 buf[16] = {0}; + gint bytes = 0; + + bytes += qq_put8(buf + bytes, 0x00); + bytes += qq_put32(buf + bytes, uid); + + qd = (qq_data *) gc->proto_data; + qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, bytes); } void qq_send_packet_get_buddies_levels(PurpleConnection *gc) { - guint8 *buf, *tmp; + guint8 *buf; guint16 size; qq_buddy *q_bud; qq_data *qd = (qq_data *) gc->proto_data; GList *node = qd->buddies; + gint bytes = 0; if (qd->buddies) { /* server only sends back levels for online buddies, no point - * in asking for anyone else */ - size = 4*g_list_length(qd->buddies) + 1; + * in asking for anyone else */ + size = 4 * g_list_length(qd->buddies) + 1; buf = g_new0(guint8, size); - tmp = buf + 1; + bytes += 1; - while (node != NULL) { - guint32 tmp4; + while (NULL != node) { q_bud = (qq_buddy *) node->data; - if (q_bud != NULL) { - tmp4 = g_htonl(q_bud->uid); - memcpy(tmp, &tmp4, 4); - tmp += 4; + if (NULL != q_bud) { + bytes += qq_put32(buf + bytes, q_bud->uid); } node = node->next; } - qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, size); + qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, size); g_free(buf); } } @@ -822,10 +980,11 @@ PurpleBuddy *b; qq_buddy *q_bud; gint decr_len, i; - guint8 *decr_buf, *tmp; + guint8 *decr_buf; PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd = (qq_data *) gc->proto_data; - + gint bytes = 0; + decr_len = buf_len; decr_buf = g_new0(guint8, buf_len); if (!qq_decrypt(buf, buf_len, qd->session_key, decr_buf, &decr_len)) { @@ -835,28 +994,23 @@ decr_len--; if (decr_len % 12 != 0) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); + "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); decr_len -= (decr_len % 12); } - - tmp = decr_buf + 1; + + bytes += 1; /* this byte seems random */ /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Byte one of get_level packet: %d\n", buf[0]); - */ + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Byte one of get_level packet: %d\n", buf[0]); + */ for (i = 0; i < decr_len; i += 12) { - uid = g_ntohl(*(guint32 *) tmp); - tmp += 4; - onlineTime = g_ntohl(*(guint32 *) tmp); - tmp += 4; - level = g_ntohs(*(guint16 *) tmp); - tmp += 2; - timeRemainder = g_ntohs(*(guint16 *) tmp); - tmp += 2; - /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Level packet entry:\nuid: %d\nonlineTime: %d\nlevel: %d\ntimeRemainder: %d\n", + bytes += qq_get32(&uid, decr_buf + bytes); + bytes += qq_get32(&onlineTime, decr_buf + bytes); + bytes += qq_get16(&level, decr_buf + bytes); + bytes += qq_get16(&timeRemainder, decr_buf + bytes); + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Level packet entry:\nuid: %d\nonlineTime: %d\nlevel: %d\ntimeRemainder: %d\n", uid, onlineTime, level, timeRemainder); - */ purple_name = uid_to_purple_name(uid); b = purple_find_buddy(account, purple_name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; @@ -872,7 +1026,7 @@ } } else { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Got an online buddy %d, but not in my buddy list\n", uid); + "Got an online buddy %d, but not in my buddy list\n", uid); } g_free(purple_name); }
--- a/libpurple/protocols/qq/buddy_info.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Mon Jun 30 23:12:54 2008 +0000 @@ -44,47 +44,6 @@ #define QQ_ICON_PREFIX "qq_" #define QQ_ICON_SUFFIX ".png" -typedef struct _contact_info { - gchar *uid; - gchar *nick; - gchar *country; - gchar *province; - gchar *zipcode; - gchar *address; - gchar *tel; - gchar *age; - gchar *gender; - gchar *name; - gchar *email; - gchar *pager_sn; - gchar *pager_num; - gchar *pager_sp; - gchar *pager_base_num; - gchar *pager_type; - gchar *occupation; - gchar *homepage; - gchar *auth_type; - gchar *unknown1; - gchar *unknown2; - gchar *face; - gchar *hp_num; - gchar *hp_type; - gchar *intro; - gchar *city; - gchar *unknown3; - gchar *unknown4; - gchar *unknown5; - gchar *is_open_hp; - gchar *is_open_contact; - gchar *college; - gchar *horoscope; - gchar *zodiac; - gchar *blood; - gchar *qq_show; - gchar *unknown6; /* always 0x2D */ -} contact_info; - -void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc); void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window); void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile);
--- a/libpurple/protocols/qq/buddy_list.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Mon Jun 30 23:12:54 2008 +0000 @@ -38,13 +38,12 @@ #include "crypt.h" #include "header_info.h" #include "keep_alive.h" -#include "send_core.h" #include "group.h" #include "group_find.h" #include "group_internal.h" #include "group_info.h" -#include "qq_proxy.h" +#include "qq_network.h" #define QQ_GET_ONLINE_BUDDY_02 0x02 #define QQ_GET_ONLINE_BUDDY_03 0x03 /* unknown function */ @@ -64,25 +63,25 @@ void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position) { qq_data *qd; - guint8 *raw_data, *cursor; + guint8 *raw_data; + gint bytes = 0; qd = (qq_data *) gc->proto_data; raw_data = g_newa(guint8, 5); - cursor = raw_data; /* 000-000 get online friends cmd * only 0x02 and 0x03 returns info from server, other valuse all return 0xff * I can also only send the first byte (0x02, or 0x03) * and the result is the same */ - create_packet_b(raw_data, &cursor, QQ_GET_ONLINE_BUDDY_02); + bytes += qq_put8(raw_data + bytes, QQ_GET_ONLINE_BUDDY_02); /* 001-001 seems it supports 255 online buddies at most */ - create_packet_b(raw_data, &cursor, position); + bytes += qq_put8(raw_data + bytes, position); /* 002-002 */ - create_packet_b(raw_data, &cursor, 0x00); + bytes += qq_put8(raw_data + bytes, 0x00); /* 003-004 */ - create_packet_w(raw_data, &cursor, 0x0000); + bytes += qq_put16(raw_data + bytes, 0x0000); - qq_send_cmd(gc, QQ_CMD_GET_FRIENDS_ONLINE, TRUE, 0, TRUE, raw_data, 5); + qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_ONLINE, raw_data, 5); qd->last_get_online = time(NULL); } @@ -90,42 +89,38 @@ * server may return a position tag if list is too long for one packet */ void qq_send_packet_get_buddies_list(PurpleConnection *gc, guint16 position) { - guint8 *raw_data, *cursor; - gint data_len; + qq_data *qd = (qq_data *) gc->proto_data; + guint8 raw_data[16] = {0}; + gint bytes = 0; - data_len = 3; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; /* 000-001 starting position, can manually specify */ - create_packet_w(raw_data, &cursor, position); + bytes += qq_put16(raw_data + bytes, position); /* before Mar 18, 2004, any value can work, and we sent 00 * I do not know what data QQ server is expecting, as QQ2003iii 0304 itself * even can sending packets 00 and get no response. * Now I tested that 00,00,00,00,00,01 work perfectly * March 22, found the 00,00,00 starts to work as well */ - create_packet_b(raw_data, &cursor, 0x00); + bytes += qq_put8(raw_data + bytes, 0x00); - qq_send_cmd(gc, QQ_CMD_GET_FRIENDS_LIST, TRUE, 0, TRUE, raw_data, data_len); + qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_LIST, raw_data, bytes); } /* get all list, buddies & Quns with groupsid support */ void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position) { - guint8 *raw_data, *cursor; - gint data_len; + qq_data *qd = (qq_data *) gc->proto_data; + guint8 raw_data[16] = {0}; + gint bytes = 0; - data_len = 10; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; /* 0x01 download, 0x02, upload */ - create_packet_b(raw_data, &cursor, 0x01); + bytes += qq_put8(raw_data + bytes, 0x01); /* unknown 0x02 */ - create_packet_b(raw_data, &cursor, 0x02); + bytes += qq_put8(raw_data + bytes, 0x02); /* unknown 00 00 00 00 */ - create_packet_dw(raw_data, &cursor, 0x00000000); - create_packet_dw(raw_data, &cursor, position); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put32(raw_data + bytes, position); - qq_send_cmd(gc, QQ_CMD_GET_ALL_LIST_WITH_GROUP, TRUE, 0, TRUE, raw_data, data_len); + qq_send_cmd(qd, QQ_CMD_GET_ALL_LIST_WITH_GROUP, raw_data, bytes); } static void _qq_buddies_online_reply_dump_unclear(qq_friends_online_entry *fe) @@ -151,8 +146,8 @@ void qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) { qq_data *qd; - gint len, bytes; - guint8 *data, *cursor, position; + gint len, bytes, bytes_buddy; + guint8 *data, position; PurpleBuddy *b; qq_buddy *q_bud; qq_friends_online_entry *fe; @@ -162,96 +157,100 @@ qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); - cursor = data; purple_debug(PURPLE_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n"); - - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - _qq_show_packet("Get buddies online reply packet", data, len); - - read_packet_b(data, &cursor, len, &position); - - fe = g_newa(qq_friends_online_entry, 1); - fe->s = g_newa(qq_buddy_status, 1); + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies online"); + return; + } - while (cursor < (data + len)) { - /* based on one online buddy entry */ - bytes = 0; - /* 000-030 qq_buddy_status */ - bytes += qq_buddy_status_read(data, &cursor, len, fe->s); - /* 031-032: unknown4 */ - bytes += read_packet_w(data, &cursor, len, &fe->unknown1); - /* 033-033: flag1 */ - bytes += read_packet_b(data, &cursor, len, &fe->flag1); - /* 034-034: comm_flag */ - bytes += read_packet_b(data, &cursor, len, &fe->comm_flag); - /* 035-036: */ - bytes += read_packet_w(data, &cursor, len, &fe->unknown2); - /* 037-037: */ - bytes += read_packet_b(data, &cursor, len, &fe->ending); /* 0x00 */ + qq_show_packet("Get buddies online reply packet", data, len); + + bytes = 0; + bytes += qq_get8(&position, data + bytes); + + fe = g_newa(qq_friends_online_entry, 1); + fe->s = g_newa(qq_buddy_status, 1); - if (fe->s->uid == 0 || bytes != QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "uid=0 or entry complete len(%d) != %d", - bytes, QQ_ONLINE_BUDDY_ENTRY_LEN); - g_free(fe->s->ip); - g_free(fe->s->unknown_key); - continue; - } /* check if it is a valid entry */ - - if (QQ_DEBUG) - _qq_buddies_online_reply_dump_unclear(fe); + while (bytes < len) { + /* set flag */ + bytes_buddy = bytes; + /* based on one online buddy entry */ + /* ATTTENTION! NEWED in the sub function, but FREED here */ + /* 000-030 qq_buddy_status */ + bytes += qq_buddy_status_read(fe->s, data + bytes); + /* 031-032: unknown4 */ + bytes += qq_get16(&fe->unknown1, data + bytes); + /* 033-033: flag1 */ + bytes += qq_get8(&fe->flag1, data + bytes); + /* 034-034: comm_flag */ + bytes += qq_get8(&fe->comm_flag, data + bytes); + /* 035-036: */ + bytes += qq_get16(&fe->unknown2, data + bytes); + /* 037-037: */ + bytes += qq_get8(&fe->ending, data + bytes); /* 0x00 */ - /* update buddy information */ - b = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(fe->s->uid)); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - - if (q_bud != NULL) { /* we find one and update qq_buddy */ - if(0 != fe->s->client_version) - q_bud->client_version = fe->s->client_version; - g_memmove(q_bud->ip, fe->s->ip, 4); - q_bud->port = fe->s->port; - q_bud->status = fe->s->status; - q_bud->flag1 = fe->flag1; - q_bud->comm_flag = fe->comm_flag; - qq_update_buddy_contact(gc, q_bud); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Got an online buddy %d, but not in my buddy list\n", fe->s->uid); - } - + if (fe->s->uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "uid=0 or entry complete len(%d) != %d", + (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN); g_free(fe->s->ip); g_free(fe->s->unknown_key); - } - - if(cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); + continue; + } /* check if it is a valid entry */ + + if (QQ_DEBUG) { + _qq_buddies_online_reply_dump_unclear(fe); } - if (position != QQ_FRIENDS_ONLINE_POSITION_END) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Has more online buddies, position from %d\n", position); + /* update buddy information */ + b = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(fe->s->uid)); + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - qq_send_packet_get_buddies_online(gc, position); + if (q_bud != NULL) { /* we find one and update qq_buddy */ + if(0 != fe->s->client_version) + q_bud->client_version = fe->s->client_version; + g_memmove(q_bud->ip, fe->s->ip, 4); + q_bud->port = fe->s->port; + q_bud->status = fe->s->status; + q_bud->flag1 = fe->flag1; + q_bud->comm_flag = fe->comm_flag; + qq_update_buddy_contact(gc, q_bud); } else { - qq_send_packet_get_buddies_levels(gc); - qq_refresh_all_buddy_status(gc); + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Got an online buddy %d, but not in my buddy list\n", fe->s->uid); } + g_free(fe->s->ip); + g_free(fe->s->unknown_key); + } + + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); + } + + if (position != QQ_FRIENDS_ONLINE_POSITION_END) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Has more online buddies, position from %d\n", position); + + qq_send_packet_get_buddies_online(gc, position); } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies online"); + qq_send_packet_get_buddies_levels(gc); + qq_refresh_all_buddy_status(gc); } } + /* process reply for get_buddies_list */ void qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) { qq_data *qd; qq_buddy *q_bud; - gint len, bytes, bytes_expected, i; + gint len, bytes_expected, i; + gint bytes, buddy_bytes; guint16 position, unknown; - guint8 *data, *cursor, pascal_len; + guint8 *data, pascal_len; gchar *name; PurpleBuddy *b; @@ -260,81 +259,84 @@ qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); - cursor = data; + + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies list"); + return; + } + bytes = 0; + bytes += qq_get16(&position, data + bytes); + /* the following data is buddy list in this packet */ + i = 0; + while (bytes < len) { + q_bud = g_new0(qq_buddy, 1); + /* set flag */ + buddy_bytes = bytes; + /* 000-003: uid */ + bytes += qq_get32(&q_bud->uid, data + bytes); + /* 004-005: icon index (1-255) */ + bytes += qq_get16(&q_bud->face, data + bytes); + /* 006-006: age */ + bytes += qq_get8(&q_bud->age, data + bytes); + /* 007-007: gender */ + bytes += qq_get8(&q_bud->gender, data + bytes); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - read_packet_w(data, &cursor, len, &position); - /* the following data is buddy list in this packet */ - i = 0; - while (cursor < (data + len)) { - q_bud = g_new0(qq_buddy, 1); - bytes = 0; - /* 000-003: uid */ - bytes += read_packet_dw(data, &cursor, len, &q_bud->uid); - /* 004-005: icon index (1-255) */ - bytes += read_packet_w(data, &cursor, len, &q_bud->face); - /* 006-006: age */ - bytes += read_packet_b(data, &cursor, len, &q_bud->age); - /* 007-007: gender */ - bytes += read_packet_b(data, &cursor, len, &q_bud->gender); - pascal_len = convert_as_pascal_string(cursor, &q_bud->nickname, QQ_CHARSET_DEFAULT); - cursor += pascal_len; - bytes += pascal_len; - bytes += read_packet_w(data, &cursor, len, &unknown); - /* flag1: (0-7) - * bit1 => qq show - * comm_flag: (0-7) - * bit1 => member - * bit4 => TCP mode - * bit5 => open mobile QQ - * bit6 => bind to mobile - * bit7 => whether having a video - */ - bytes += read_packet_b(data, &cursor, len, &q_bud->flag1); - bytes += read_packet_b(data, &cursor, len, &q_bud->comm_flag); + pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT); + bytes += pascal_len; - bytes_expected = 12 + pascal_len; - - if (q_bud->uid == 0 || bytes != bytes_expected) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes); - g_free(q_bud->nickname); - g_free(q_bud); - continue; - } else { - i++; - } + bytes += qq_get16(&unknown, data + bytes); + /* flag1: (0-7) + * bit1 => qq show + * comm_flag: (0-7) + * bit1 => member + * bit4 => TCP mode + * bit5 => open mobile QQ + * bit6 => bind to mobile + * bit7 => whether having a video + */ + bytes += qq_get8(&q_bud->flag1, data + bytes); + bytes += qq_get8(&q_bud->comm_flag, data + bytes); - if (QQ_DEBUG) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "buddy [%09d]: flag1=0x%02x, comm_flag=0x%02x\n", - q_bud->uid, q_bud->flag1, q_bud->comm_flag); - } + bytes_expected = 12 + pascal_len; - name = uid_to_purple_name(q_bud->uid); - b = purple_find_buddy(gc->account, name); - g_free(name); - - if (b == NULL) - b = qq_add_buddy_by_recv_packet(gc, q_bud->uid, TRUE, FALSE); - - b->proto_data = q_bud; - qd->buddies = g_list_append(qd->buddies, q_bud); - qq_update_buddy_contact(gc, q_bud); + if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes); + g_free(q_bud->nickname); + g_free(q_bud); + continue; + } else { + i++; } - if(cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); - } - if (position == QQ_FRIENDS_LIST_POSITION_END) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get friends list done, %d buddies\n", i); - qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_ONLINE_POSITION_START); - } else { - qq_send_packet_get_buddies_list(gc, position); + if (QQ_DEBUG) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "buddy [%09d]: flag1=0x%02x, comm_flag=0x%02x\n", + q_bud->uid, q_bud->flag1, q_bud->comm_flag); + } + + name = uid_to_purple_name(q_bud->uid); + b = purple_find_buddy(gc->account, name); + g_free(name); + + if (b == NULL) { + b = qq_add_buddy_by_recv_packet(gc, q_bud->uid, TRUE, FALSE); } + + b->proto_data = q_bud; + qd->buddies = g_list_append(qd->buddies, q_bud); + qq_update_buddy_contact(gc, q_bud); + } + + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); + } + if (position == QQ_FRIENDS_LIST_POSITION_END) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get friends list done, %d buddies\n", i); + qq_send_packet_get_buddies_online(gc, QQ_FRIENDS_ONLINE_POSITION_START); } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies list"); + qq_send_packet_get_buddies_list(gc, position); } } @@ -342,7 +344,8 @@ { qq_data *qd; gint len, i, j; - guint8 *data, *cursor; + gint bytes = 0; + guint8 *data; guint8 sub_cmd, reply_code; guint32 unknown, position; guint32 uid; @@ -354,62 +357,66 @@ qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); - cursor = data; + + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt all list with group"); + return; + } + + bytes += qq_get8(&sub_cmd, data + bytes); + g_return_if_fail(sub_cmd == 0x01); + + bytes += qq_get8(&reply_code, data + bytes); + if(0 != reply_code) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", + "Get all list with group reply, reply_code(%d) is not zero", reply_code); + } - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - read_packet_b(data, &cursor, len, &sub_cmd); - g_return_if_fail(sub_cmd == 0x01); - read_packet_b(data, &cursor, len, &reply_code); - if(0 != reply_code) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Get all list with group reply, reply_code(%d) is not zero", reply_code); + bytes += qq_get32(&unknown, data + bytes); + bytes += qq_get32(&position, data + bytes); + /* the following data is all list in this packet */ + i = 0; + j = 0; + while (bytes < len) { + /* 00-03: uid */ + bytes += qq_get32(&uid, data + bytes); + /* 04: type 0x1:buddy 0x4:Qun */ + bytes += qq_get8(&type, data + bytes); + /* 05: groupid*4 */ /* seems to always be 0 */ + bytes += qq_get8(&groupid, data + bytes); + /* + purple_debug(PURPLE_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); + groupid >>= 2; + */ + if (uid == 0 || (type != 0x1 && type != 0x4)) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Buddy entry, uid=%d, type=%d", uid, type); + continue; + } + if(0x1 == type) { /* a buddy */ + /* don't do anything but count - buddies are handled by + * qq_send_packet_get_buddies_list */ + ++i; + } else { /* a group */ + group = qq_group_find_by_id(gc, uid, QQ_INTERNAL_ID); + if(group == NULL) { + qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); + group = g_newa(qq_group, 1); + group->internal_group_id = uid; + qq_send_cmd_group_get_group_info(gc, group); + } else { + group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + qq_group_refresh(gc, group); + qq_send_cmd_group_get_group_info(gc, group); + } + ++j; } - read_packet_dw(data, &cursor, len, &unknown); - read_packet_dw(data, &cursor, len, &position); - /* the following data is all list in this packet */ - i = 0; - j = 0; - while (cursor < (data + len)) { - /* 00-03: uid */ - read_packet_dw(data, &cursor, len, &uid); - /* 04: type 0x1:buddy 0x4:Qun */ - read_packet_b(data, &cursor, len, &type); - /* 05: groupid*4 */ /* seems to always be 0 */ - read_packet_b(data, &cursor, len, &groupid); - /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); - groupid >>= 2; - */ - if (uid == 0 || (type != 0x1 && type != 0x4)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Buddy entry, uid=%d, type=%d", uid, type); - continue; - } - if(0x1 == type) { /* a buddy */ - /* don't do anything but count - buddies are handled by - * qq_send_packet_get_buddies_list */ - ++i; - } else { /* a group */ - group = qq_group_find_by_id(gc, uid, QQ_INTERNAL_ID); - if(group == NULL) { - qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); - group = g_newa(qq_group, 1); - group->internal_group_id = uid; - qq_send_cmd_group_get_group_info(gc, group); - } else { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; - qq_group_refresh(gc, group); - qq_send_cmd_group_get_group_info(gc, group); - } - ++j; - } - } - if(cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!"); - } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get all list done, %d buddies and %d Quns\n", i, j); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt all list with group"); } + + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!"); + } + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get all list done, %d buddies and %d Quns\n", i, j); }
--- a/libpurple/protocols/qq/buddy_opt.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Mon Jun 30 23:12:54 2008 +0000 @@ -36,7 +36,7 @@ #include "im.h" #include "keep_alive.h" #include "packet_parse.h" -#include "send_core.h" +#include "qq_network.h" #include "utils.h" #define PURPLE_GROUP_QQ_FORMAT "QQ (%s)" @@ -61,33 +61,33 @@ /* send packet to remove a buddy from my buddy list */ static void _qq_send_packet_remove_buddy(PurpleConnection *gc, guint32 uid) { + qq_data *qd = (qq_data *) gc->proto_data; gchar uid_str[11]; g_return_if_fail(uid > 0); g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_DEL_FRIEND, TRUE, 0, - TRUE, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(qd, QQ_CMD_DEL_FRIEND, (guint8 *) uid_str, strlen(uid_str)); } /* try to remove myself from someone's buddy list */ static void _qq_send_packet_remove_self_from(PurpleConnection *gc, guint32 uid) { - guint8 *raw_data, *cursor; + qq_data *qd = (qq_data *) gc->proto_data; + guint8 raw_data[16] = {0}; + gint bytes = 0; g_return_if_fail(uid > 0); - raw_data = g_newa(guint8, 4); - cursor = raw_data; - create_packet_dw(raw_data, &cursor, uid); + bytes += qq_put32(raw_data + bytes, uid); - qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, TRUE, 0, TRUE, raw_data, 4); + qq_send_cmd(qd, QQ_CMD_REMOVE_SELF, raw_data, bytes); } /* try to add a buddy without authentication */ static void _qq_send_packet_add_buddy(PurpleConnection *gc, guint32 uid) { - qq_data *qd; + qq_data *qd = (qq_data *) gc->proto_data; qq_add_buddy_request *req; gchar uid_str[11]; @@ -95,11 +95,9 @@ /* we need to send the ascii code of this uid to qq server */ g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(gc, QQ_CMD_ADD_FRIEND_WO_AUTH, TRUE, 0, - TRUE, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(qd, QQ_CMD_ADD_FRIEND_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); /* must be set after sending packet to get the correct send_seq */ - qd = (qq_data *) gc->proto_data; req = g_new0(qq_add_buddy_request, 1); req->seq = qd->send_seq; req->uid = uid; @@ -109,28 +107,29 @@ /* this buddy needs authentication, text conversion is done at lowest level */ static void _qq_send_packet_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) { + qq_data *qd = (qq_data *) gc->proto_data; gchar *text_qq, uid_str[11]; - guint8 bar, *cursor, *raw_data; + guint8 bar, *raw_data; + gint bytes = 0; g_return_if_fail(uid != 0); g_snprintf(uid_str, sizeof(uid_str), "%d", uid); bar = 0x1f; raw_data = g_newa(guint8, QQ_MSG_IM_MAX); - cursor = raw_data; - create_packet_data(raw_data, &cursor, (guint8 *) uid_str, strlen(uid_str)); - create_packet_b(raw_data, &cursor, bar); - create_packet_b(raw_data, &cursor, response); + bytes += qq_putdata(raw_data + bytes, (guint8 *) uid_str, strlen(uid_str)); + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_put8(raw_data + bytes, response); if (text != NULL) { text_qq = utf8_to_qq(text, QQ_CHARSET_DEFAULT); - create_packet_b(raw_data, &cursor, bar); - create_packet_data(raw_data, &cursor, (guint8 *) text_qq, strlen(text_qq)); + bytes += qq_put8(raw_data + bytes, bar); + bytes += qq_putdata(raw_data + bytes, (guint8 *) text_qq, strlen(text_qq)); g_free(text_qq); } - qq_send_cmd(gc, QQ_CMD_BUDDY_AUTH, TRUE, 0, TRUE, raw_data, cursor - raw_data); + qq_send_cmd(qd, QQ_CMD_BUDDY_AUTH, raw_data, bytes); } static void _qq_send_packet_add_buddy_auth_with_gc_and_uid(gc_and_uid *g, const gchar *text) @@ -210,10 +209,10 @@ nombre = uid_to_purple_name(uid); purple_request_input(gc, _("Reject request"), msg1, msg2, - _("Sorry, you are not my type..."), TRUE, FALSE, - NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, - purple_connection_get_account(gc), nombre, NULL, - g2); + _("Sorry, you are not my type..."), TRUE, FALSE, + NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, + purple_connection_get_account(gc), nombre, NULL, + g2); g_free(nombre); } @@ -257,7 +256,8 @@ { qq_data *qd; gint len; - guint8 *data, *cursor, reply; + gint bytes = 0; + guint8 *data, reply; gchar **segments, *msg_utf8; g_return_if_fail(buf != NULL && buf_len != 0); @@ -265,22 +265,23 @@ qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); - cursor = data; + + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt add buddy with auth reply\n"); + } + + bytes += qq_get8(&reply, data + bytes); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - read_packet_b(data, &cursor, len, &reply); - if (reply != QQ_ADD_BUDDY_AUTH_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy with auth request failed\n"); - if (NULL == (segments = split_data(data, len, "\x1f", 2))) - return; - msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); - purple_notify_error(gc, NULL, _("Add buddy with auth request failed"), msg_utf8); - g_free(msg_utf8); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy with auth request OK\n"); + if (reply != QQ_ADD_BUDDY_AUTH_REPLY_OK) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy with auth request failed\n"); + if (NULL == (segments = split_data(data, len, "\x1f", 2))) { + return; } + msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); + purple_notify_error(gc, NULL, _("Add buddy with auth request failed"), msg_utf8); + g_free(msg_utf8); } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt add buddy with auth reply\n"); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy with auth request OK\n"); } } @@ -289,7 +290,8 @@ { qq_data *qd; gint len; - guint8 *data, *cursor, reply; + gint bytes = 0; + guint8 *data, reply; g_return_if_fail(buf != NULL && buf_len != 0); @@ -297,20 +299,20 @@ len = buf_len; data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - cursor = data; - read_packet_b(data, &cursor, len, &reply); - if (reply != QQ_REMOVE_BUDDY_REPLY_OK) { - /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove buddy fails\n"); - } else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove buddy OK\n"); - /* TODO: We don't really need to notify the user about this, do we? */ - purple_notify_info(gc, NULL, _("You have successfully removed a buddy"), NULL); - } - } else { + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt remove buddy reply\n"); } + + bytes += qq_get8(&reply, data + bytes); + + if (reply != QQ_REMOVE_BUDDY_REPLY_OK) { + /* there is no reason return from server */ + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove buddy fails\n"); + } else { /* if reply */ + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove buddy OK\n"); + /* TODO: We don't really need to notify the user about this, do we? */ + purple_notify_info(gc, NULL, _("You have successfully removed a buddy"), NULL); + } } /* process the server reply for my request to remove myself from a buddy */ @@ -318,7 +320,8 @@ { qq_data *qd; gint len; - guint8 *data, *cursor, reply; + gint bytes = 0; + guint8 *data, reply; g_return_if_fail(buf != NULL && buf_len != 0); @@ -326,20 +329,20 @@ len = buf_len; data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - cursor = data; - read_packet_b(data, &cursor, len, &reply); - if (reply != QQ_REMOVE_SELF_REPLY_OK) - /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove self fails\n"); - else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove self from a buddy OK\n"); - /* TODO: Does the user really need to be notified about this? */ - purple_notify_info(gc, NULL, _("You have successfully removed yourself from your friend's buddy list"), NULL); - } - } else { + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt remove self reply\n"); } + + bytes += qq_get8(&reply, data + bytes); + + if (reply != QQ_REMOVE_SELF_REPLY_OK) { + /* there is no reason return from server */ + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove self fails\n"); + } else { /* if reply */ + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove self from a buddy OK\n"); + /* TODO: Does the user really need to be notified about this? */ + purple_notify_info(gc, NULL, _("You have successfully removed yourself from your friend's buddy list"), NULL); + } } void qq_process_add_buddy_reply(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc) @@ -403,14 +406,14 @@ g->uid = for_uid; msg = g_strdup_printf(_("User %d needs authentication"), for_uid); purple_request_input(gc, NULL, msg, - _("Input request here"), /* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */ - _("Would you be my friend?"), - TRUE, FALSE, NULL, _("Send"), - G_CALLBACK - (_qq_send_packet_add_buddy_auth_with_gc_and_uid), - _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), - purple_connection_get_account(gc), nombre, NULL, - g); + _("Input request here"), /* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */ + _("Would you be my friend?"), + TRUE, FALSE, NULL, _("Send"), + G_CALLBACK + (_qq_send_packet_add_buddy_auth_with_gc_and_uid), + _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), + purple_connection_get_account(gc), nombre, NULL, + g); g_free(msg); g_free(nombre); } else { /* add OK */ @@ -457,7 +460,7 @@ g_return_val_if_fail(a != NULL && uid != 0, NULL); group_name = is_known ? - g_strdup_printf(PURPLE_GROUP_QQ_FORMAT, purple_account_get_username(a)) : g_strdup(PURPLE_GROUP_QQ_UNKNOWN); + g_strdup_printf(PURPLE_GROUP_QQ_FORMAT, purple_account_get_username(a)) : g_strdup(PURPLE_GROUP_QQ_UNKNOWN); g = qq_get_purple_group(group_name); @@ -512,8 +515,8 @@ if (b != NULL) purple_blist_remove_buddy(b); purple_notify_error(gc, NULL, - _("QQid Error"), - _("Invalid QQid")); + _("QQid Error"), + _("Invalid QQid")); } }
--- a/libpurple/protocols/qq/buddy_status.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_status.c Mon Jun 30 23:12:54 2008 +0000 @@ -3,7 +3,7 @@ * * purple * - * Purple is the legal property of its developers, whose names are too numerous + * Purple is the legal property ofr its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * @@ -33,10 +33,9 @@ #include "header_info.h" #include "keep_alive.h" #include "packet_parse.h" -#include "send_core.h" #include "utils.h" -#include "qq_proxy.h" +#include "qq_network.h" #define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001 #define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 /* ASCII value of "0" */ @@ -57,7 +56,7 @@ g_string_append_printf(dump, "013-014: %04x (client_version)\n", s->client_version); /* g_string_append_printf(dump, "015-030: %s (unknown key)\n", s->unknown_key); */ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Buddy status entry, %s", dump->str); - _qq_show_packet("Unknown key", s->unknown_key, QQ_KEY_LENGTH); + qq_show_packet("Unknown key", s->unknown_key, QQ_KEY_LENGTH); g_string_free(dump, TRUE); } @@ -66,35 +65,33 @@ * using different accounts to get info. */ /* parse the data into qq_buddy_status */ -gint qq_buddy_status_read(guint8 *data, guint8 **cursor, gint len, qq_buddy_status *s) +gint qq_buddy_status_read(qq_buddy_status *s, guint8 *data) { - gint bytes; + gint bytes = 0; - g_return_val_if_fail(data != NULL && *cursor != NULL && s != NULL, -1); - - bytes = 0; + g_return_val_if_fail(data != NULL && s != NULL, -1); /* 000-003: uid */ - bytes += read_packet_dw(data, cursor, len, &s->uid); + bytes += qq_get32(&s->uid, data + bytes); /* 004-004: 0x01 */ - bytes += read_packet_b(data, cursor, len, &s->unknown1); + bytes += qq_get8(&s->unknown1, data + bytes); /* this is no longer the IP, it seems QQ (as of 2006) no longer sends * the buddy's IP in this packet. all 0s */ /* 005-008: ip */ s->ip = g_new0(guint8, 4); - bytes += read_packet_data(data, cursor, len, s->ip, 4); + bytes += qq_getdata(s->ip, 4, data + bytes); /* port info is no longer here either */ /* 009-010: port */ - bytes += read_packet_w(data, cursor, len, &s->port); + bytes += qq_get16(&s->port, data + bytes); /* 011-011: 0x00 */ - bytes += read_packet_b(data, cursor, len, &s->unknown2); + bytes += qq_get8(&s->unknown2, data + bytes); /* 012-012: status */ - bytes += read_packet_b(data, cursor, len, &s->status); + bytes += qq_get8(&s->status, data + bytes); /* 013-014: client_version */ - bytes += read_packet_w(data, cursor, len, &s->client_version); + bytes += qq_get16(&s->client_version, data + bytes); /* 015-030: unknown key */ s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH); - bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH); + bytes += qq_getdata(s->unknown_key, QQ_KEY_LENGTH, data + bytes); if (s->uid == 0 || bytes != 31) return -1; @@ -106,17 +103,17 @@ gboolean is_online(guint8 status) { switch(status) { - case QQ_BUDDY_ONLINE_NORMAL: - case QQ_BUDDY_ONLINE_AWAY: - case QQ_BUDDY_ONLINE_INVISIBLE: - return TRUE; - case QQ_BUDDY_ONLINE_OFFLINE: - return FALSE; + case QQ_BUDDY_ONLINE_NORMAL: + case QQ_BUDDY_ONLINE_AWAY: + case QQ_BUDDY_ONLINE_INVISIBLE: + return TRUE; + case QQ_BUDDY_ONLINE_OFFLINE: + return FALSE; } return FALSE; } - /* Help calculate the correct icon index to tell the server. */ +/* Help calculate the correct icon index to tell the server. */ gint get_icon_offset(PurpleConnection *gc) { PurpleAccount *account; @@ -131,7 +128,7 @@ || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY) || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) { return 1; - } else { + } else { return 0; } } @@ -140,7 +137,9 @@ void qq_send_packet_change_status(PurpleConnection *gc) { qq_data *qd; - guint8 *raw_data, *cursor, away_cmd; + guint8 raw_data[16] = {0}; + gint bytes = 0; + guint8 away_cmd; guint32 misc_status; gboolean fake_video; PurpleAccount *account; @@ -163,28 +162,24 @@ away_cmd = QQ_BUDDY_ONLINE_NORMAL; } - raw_data = g_new0(guint8, 5); - cursor = raw_data; misc_status = 0x00000000; - fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video"); if (fake_video) misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO; - create_packet_b(raw_data, &cursor, away_cmd); - create_packet_dw(raw_data, &cursor, misc_status); + bytes = 0; + bytes += qq_put8(raw_data + bytes, away_cmd); + bytes += qq_put32(raw_data + bytes, misc_status); - qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, 5); - - g_free(raw_data); + qq_send_cmd(qd, QQ_CMD_CHANGE_ONLINE_STATUS, raw_data, bytes); } /* parse the reply packet for change_status */ void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) { qq_data *qd; - gint len; - guint8 *data, *cursor, reply; + gint len, bytes; + guint8 *data, reply; PurpleBuddy *b; qq_buddy *q_bud; gchar *name; @@ -195,21 +190,22 @@ len = buf_len; data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - cursor = data; - read_packet_b(data, &cursor, len, &reply); - if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail\n"); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); - name = uid_to_purple_name(qd->uid); - b = purple_find_buddy(gc->account, name); - g_free(name); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - qq_update_buddy_contact(gc, q_bud); - } + if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n"); + return; + } + + bytes = 0; + bytes = qq_get8(&reply, data + bytes); + if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail\n"); } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n"); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); + name = uid_to_purple_name(qd->uid); + b = purple_find_buddy(gc->account, name); + g_free(name); + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + qq_update_buddy_contact(gc, q_bud); } } @@ -219,7 +215,7 @@ qq_data *qd; gint len, bytes; guint32 my_uid; - guint8 *data, *cursor; + guint8 *data; PurpleBuddy *b; qq_buddy *q_bud; qq_buddy_status *s; @@ -230,51 +226,53 @@ qd = (qq_data *) gc->proto_data; len = buf_len; data = g_newa(guint8, len); - cursor = data; - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - s = g_new0(qq_buddy_status, 1); - bytes = 0; - /* 000-030: qq_buddy_status */ - bytes += qq_buddy_status_read(data, &cursor, len, s); - /* 031-034: my uid */ - /* This has a value of 0 when we've changed our status to - * QQ_BUDDY_ONLINE_INVISIBLE */ - bytes += read_packet_dw(data, &cursor, len, &my_uid); - - if (bytes != 35) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "bytes(%d) != 35\n", bytes); - g_free(s->ip); - g_free(s->unknown_key); - g_free(s); - return; - } + if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n"); + return; + } - name = uid_to_purple_name(s->uid); - b = purple_find_buddy(gc->account, name); - g_free(name); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - if (q_bud) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid); - if(0 != *((guint32 *)s->ip)) { - g_memmove(q_bud->ip, s->ip, 4); - q_bud->port = s->port; - } - q_bud->status = s->status; - if(0 != s->client_version) - q_bud->client_version = s->client_version; - if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) - qq_send_packet_get_level(gc, q_bud->uid); - qq_update_buddy_contact(gc, q_bud); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "got information of unknown buddy %d\n", s->uid); - } + s = g_new0(qq_buddy_status, 1); + bytes = 0; + /* 000-030: qq_buddy_status */ + bytes += qq_buddy_status_read(s, data + bytes); + /* 031-034: my uid */ + /* This has a value of 0 when we've changed our status to + * QQ_BUDDY_ONLINE_INVISIBLE */ + bytes += qq_get32(&my_uid, data + bytes); + if (bytes != 35) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "bytes(%d) != 35\n", bytes); g_free(s->ip); g_free(s->unknown_key); g_free(s); + return; + } + + name = uid_to_purple_name(s->uid); + b = purple_find_buddy(gc->account, name); + g_free(name); + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + if (q_bud) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid); + if(0 != *((guint32 *)s->ip)) { + g_memmove(q_bud->ip, s->ip, 4); + q_bud->port = s->port; + } + q_bud->status = s->status; + if(0 != s->client_version) { + q_bud->client_version = s->client_version; + } + if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) { + qq_send_packet_get_level(gc, q_bud->uid); + } + qq_update_buddy_contact(gc, q_bud); } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n"); + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "got information of unknown buddy %d\n", s->uid); } + + g_free(s->ip); + g_free(s->unknown_key); + g_free(s); }
--- a/libpurple/protocols/qq/buddy_status.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/buddy_status.h Mon Jun 30 23:12:54 2008 +0000 @@ -52,7 +52,7 @@ void qq_buddy_status_dump_unclear(qq_buddy_status *s); gboolean is_online(guint8 status); -gint qq_buddy_status_read(guint8 *data, guint8 **cursor, gint len, qq_buddy_status *s); +gint qq_buddy_status_read(qq_buddy_status *s, guint8 *data); gint get_icon_offset(PurpleConnection *gc); void qq_send_packet_change_status(PurpleConnection *gc);
--- a/libpurple/protocols/qq/char_conv.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Mon Jun 30 23:12:54 2008 +0000 @@ -39,9 +39,6 @@ #define QQ_NULL_MSG "(NULL)" /* return this if conversion fails */ #define QQ_NULL_SMILEY "(SM)" /* return this if smiley conversion fails */ -/* a debug function */ -void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len); - const gchar qq_smiley_map[QQ_SMILEY_AMOUNT] = { 0x41, 0x43, 0x42, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x73, @@ -111,16 +108,19 @@ ret = g_convert(str, len, to_charset, from_charset, &byte_read, &byte_write, &error); - if (error == NULL) + if (error == NULL) { return ret; /* conversion is OK */ - else { /* conversion error */ - gchar *failed = hex_dump_to_str((guint8 *) str, (len == -1) ? strlen(str) : len); - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", error->message); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Dump failed text\n%s", failed); - g_free(failed); - g_error_free(error); - return g_strdup(QQ_NULL_MSG); } + + /* conversion error */ + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", error->message); + + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + (guint8 *) str, (len == -1) ? strlen(str) : len, + "Dump failed text"); + + g_error_free(error); + return g_strdup(QQ_NULL_MSG); } /* take the input as a pascal string and return a converted c-string in UTF-8 @@ -142,22 +142,23 @@ gchar *qq_encode_to_purple(guint8 *data, gint len, const gchar *msg) { GString *encoded; - guint8 font_attr, font_size, color[3], bar, *cursor; + guint8 font_attr, font_size, color[3], bar; gboolean is_bold, is_italic, is_underline; guint16 charset_code; gchar *font_name, *color_code, *msg_utf8, *tmp, *ret; + gint bytes = 0; - cursor = data; - _qq_show_packet("QQ_MESG recv for font style", data, len); + /* checked qq_show_packet OK */ + qq_show_packet("QQ_MESG recv for font style", data, len); - read_packet_b(data, &cursor, len, &font_attr); - read_packet_data(data, &cursor, len, color, 3); /* red,green,blue */ + bytes += qq_get8(&font_attr, data + bytes); + bytes += qq_getdata(color, 3, data + bytes); /* red,green,blue */ color_code = g_strdup_printf("#%02x%02x%02x", color[0], color[1], color[2]); - read_packet_b(data, &cursor, len, &bar); /* skip, not sure of its use */ - read_packet_w(data, &cursor, len, &charset_code); + bytes += qq_get8(&bar, data + bytes); /* skip, not sure of its use */ + bytes += qq_get16(&charset_code, data + bytes); - tmp = g_strndup((gchar *) cursor, data + len - cursor); + tmp = g_strndup((gchar *)(data + bytes), len - bytes); font_name = qq_to_utf8(tmp, QQ_CHARSET_DEFAULT); g_free(tmp); @@ -177,11 +178,11 @@ /* Henry: The range QQ sends rounds from 8 to 22, where a font size * of 10 is equal to 3 in html font tag */ g_string_append_printf(encoded, - "<font color=\"%s\"><font face=\"%s\"><font size=\"%d\">", - color_code, font_name, font_size / 3); + "<font color=\"%s\"><font face=\"%s\"><font size=\"%d\">", + color_code, font_name, font_size / 3); purple_debug(PURPLE_DEBUG_INFO, "QQ_MESG", - "recv <font color=\"%s\"><font face=\"%s\"><font size=\"%d\">\n", - color_code, font_name, font_size / 3); + "recv <font color=\"%s\"><font face=\"%s\"><font size=\"%d\">\n", + color_code, font_name, font_size / 3); g_string_append(encoded, msg_utf8); if (is_bold) {
--- a/libpurple/protocols/qq/crypt.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/crypt.c Mon Jun 30 23:12:54 2008 +0000 @@ -296,3 +296,20 @@ } return 1; } + +/* return 1 is succeed, otherwise return 0 +gint qq_crypt(gint flag, + const guint8 *const instr, gint instrlen, + const guint8 *const key, + guint8 *outstr, gint *outstrlen_ptr) +{ + if (flag == DECRYPT) + return qq_decrypt(instr, instrlen, key, outstr, outstrlen_ptr); + else if (flag == ENCRYPT) + qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr); + else + return 0; + + return 1; +} +*/
--- a/libpurple/protocols/qq/crypt.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/crypt.h Mon Jun 30 23:12:54 2008 +0000 @@ -35,4 +35,13 @@ const guint8 *const key, guint8 *outstr, gint *outstrlen_ptr); +/* +#define DECRYPT 0x00 +#define ENCRYPT 0x01 + +gint qq_crypt(gint flag, + const guint8 *const instr, gint instrlen, + const guint8 *const key, + guint8 *outstr, gint *outstrlen_ptr); +*/ #endif
--- a/libpurple/protocols/qq/file_trans.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/file_trans.c Mon Jun 30 23:12:54 2008 +0000 @@ -38,12 +38,11 @@ #include "im.h" #include "packet_parse.h" #include "proxy.h" -#include "send_core.h" +#include "qq_network.h" #include "send_file.h" #include "utils.h" struct _qq_file_header { - guint8 tag; guint16 client_ver; guint8 file_key; guint32 sender_uid; @@ -58,11 +57,11 @@ key = seed | (seed << 8) | (seed << 16) | (seed << 24); return key; } - + static guint32 _gen_file_key(void) { guint8 seed; - + seed = random(); return _get_file_key(seed); } @@ -126,16 +125,17 @@ purple_cipher_context_destroy(context); } -static void _qq_get_file_header(guint8 *buf, guint8 **cursor, gint buflen, qq_file_header *fh) +static gint _qq_get_file_header(qq_file_header *fh, guint8 *buf) { - read_packet_b(buf, cursor, buflen, &(fh->tag)); - read_packet_w(buf, cursor, buflen, &(fh->client_ver)); - read_packet_b(buf, cursor, buflen, &fh->file_key); - read_packet_dw(buf, cursor, buflen, &(fh->sender_uid)); - read_packet_dw(buf, cursor, buflen, &(fh->receiver_uid)); + gint bytes = 0; + bytes += qq_get16(&(fh->client_ver), buf + bytes); + bytes += qq_get8(&fh->file_key, buf + bytes); + bytes += qq_get32(&(fh->sender_uid), buf + bytes); + bytes += qq_get32(&(fh->receiver_uid), buf + bytes); fh->sender_uid = _decrypt_qq_uid(fh->sender_uid, _get_file_key(fh->file_key)); fh->receiver_uid = _decrypt_qq_uid(fh->receiver_uid, _get_file_key(fh->file_key)); + return bytes; } static const gchar *qq_get_file_cmd_desc(gint type) @@ -190,7 +190,7 @@ fd = open(purple_xfer_get_local_filename(xfer), O_RDWR|O_CREAT, 0644); info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0); } - + if (info->buffer == NULL) { return - 1; } @@ -258,8 +258,8 @@ static gint _qq_send_file(PurpleConnection *gc, guint8 *data, gint len, guint16 packet_type, guint32 to_uid) { - gint bytes; - guint8 *cursor, *buf; + guint8 *raw_data; + gint bytes = 0; guint32 file_key; qq_data *qd; ft_info *info; @@ -267,21 +267,19 @@ qd = (qq_data *) gc->proto_data; g_return_val_if_fail(qd->session_key != NULL, -1); info = (ft_info *) qd->xfer->data; - bytes = 0; - buf = g_newa(guint8, MAX_PACKET_SIZE); - cursor = buf; + raw_data = g_newa(guint8, MAX_PACKET_SIZE); file_key = _gen_file_key(); - bytes += create_packet_b(buf, &cursor, packet_type); - bytes += create_packet_w(buf, &cursor, QQ_CLIENT); - bytes += create_packet_b(buf, &cursor, file_key & 0xff); - bytes += create_packet_dw(buf, &cursor, _encrypt_qq_uid(qd->uid, file_key)); - bytes += create_packet_dw(buf, &cursor, _encrypt_qq_uid(to_uid, file_key)); - bytes += create_packet_data(buf, &cursor, data, len); + bytes += qq_put8(raw_data + bytes, packet_type); + bytes += qq_put16(raw_data + bytes, QQ_CLIENT); + bytes += qq_put8(raw_data + bytes, file_key & 0xff); + bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key)); + bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key)); + bytes += qq_putdata(raw_data + bytes, data, len); if (bytes == len + 12) { - _qq_xfer_write(buf, bytes, qd->xfer); + _qq_xfer_write(raw_data, bytes, qd->xfer); } else purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_file: want %d but got %d\n", len + 12, bytes); return bytes; @@ -292,57 +290,56 @@ { qq_data *qd; gint bytes, bytes_expected, encrypted_len; - guint8 *raw_data, *cursor, *encrypted_data; + guint8 *raw_data, *encrypted_data; time_t now; ft_info *info; - + qd = (qq_data *) gc->proto_data; info = (ft_info *) qd->xfer->data; - raw_data = g_new0 (guint8, 61); - cursor = raw_data; - + raw_data = g_newa (guint8, 61); bytes = 0; + now = time(NULL); - bytes += create_packet_data(raw_data, &cursor, qd->session_md5, 16); - bytes += create_packet_w(raw_data, &cursor, packet_type); + bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16); + bytes += qq_put16(raw_data + bytes, packet_type); switch (packet_type) { case QQ_FILE_CMD_SENDER_SAY_HELLO: case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: case QQ_FILE_CMD_NOTIFY_IP_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO: - bytes += create_packet_w(raw_data, &cursor, info->send_seq); + bytes += qq_put16(raw_data + bytes, info->send_seq); break; default: - bytes += create_packet_w(raw_data, &cursor, ++qd->send_seq); + bytes += qq_put16(raw_data + bytes, ++qd->send_seq); } - bytes += create_packet_dw(raw_data, &cursor, (guint32) now); - bytes += create_packet_b(raw_data, &cursor, 0x00); - bytes += create_packet_b(raw_data, &cursor, qd->my_icon); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); - bytes += create_packet_w(raw_data, &cursor, 0x0000); - bytes += create_packet_b(raw_data, &cursor, 0x00); + bytes += qq_put32(raw_data + bytes, (guint32) now); + bytes += qq_put8(raw_data + bytes, 0x00); + bytes += qq_put8(raw_data + bytes, qd->my_icon); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put16(raw_data + bytes, 0x0000); + bytes += qq_put8(raw_data + bytes, 0x00); /* 0x65: send a file, 0x6b: send a custom face */ - bytes += create_packet_b(raw_data, &cursor, QQ_FILE_TRANSFER_FILE); /* FIXME temp by gfhuang */ + bytes += qq_put8(raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME temp by gfhuang */ switch (packet_type) { case QQ_FILE_CMD_SENDER_SAY_HELLO: case QQ_FILE_CMD_RECEIVER_SAY_HELLO: case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: - bytes += create_packet_b(raw_data, &cursor, 0x00); - bytes += create_packet_b(raw_data, &cursor, hellobyte); + bytes += qq_put8(raw_data + bytes, 0x00); + bytes += qq_put8(raw_data + bytes, hellobyte); bytes_expected = 48; break; case QQ_FILE_CMD_PING: case QQ_FILE_CMD_PONG: case QQ_FILE_CMD_NOTIFY_IP_ACK: - bytes += qq_fill_conn_info(raw_data, &cursor, info); + bytes += qq_fill_conn_info(raw_data, info); bytes_expected = 61; break; default: @@ -350,51 +347,53 @@ packet_type); bytes_expected = 0; } - - if (bytes == bytes_expected) { - gchar *hex_dump = hex_dump_to_str(raw_data, bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "sending packet[%s]: \n%s", qq_get_file_cmd_desc(packet_type), hex_dump); - g_free(hex_dump); - encrypted_len = bytes + 16; - encrypted_data = g_newa(guint8, encrypted_len); - qq_encrypt(raw_data, bytes, info->file_session_key, encrypted_data, &encrypted_len); - /*debug: try to decrypt it */ - /* - if (QQ_DEBUG) { - guint8 *buf; - int buflen; - hex_dump = hex_dump_to_str(encrypted_data, encrypted_len); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "encrypted packet: \n%s", hex_dump); - g_free(hex_dump); - buf = g_newa(guint8, MAX_PACKET_SIZE); - buflen = encrypted_len; - if (qq_decrypt(encrypted_data, encrypted_len, info->file_session_key, buf, &buflen)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt success\n"); - if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) - purple_debug(PURPLE_DEBUG_INFO, "QQ", "checksum ok\n"); - hex_dump = hex_dump_to_str(buf, buflen); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypted packet: \n%s", hex_dump); - g_free(hex_dump); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt fail\n"); - } - } - */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); - _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); - } - else + if (bytes != bytes_expected) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d", bytes_expected, bytes); + return; + } + + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", + raw_data, bytes, + "sending packet[%s]:", qq_get_file_cmd_desc(packet_type)); + + encrypted_len = bytes + 16; + encrypted_data = g_newa(guint8, encrypted_len); + qq_encrypt(raw_data, bytes, info->file_session_key, encrypted_data, &encrypted_len); + /*debug: try to decrypt it */ + /* + if (QQ_DEBUG) { + guint8 *buf; + int buflen; + hex_dump = hex_dump_to_str(encrypted_data, encrypted_len); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "encrypted packet: \n%s", hex_dump); + g_free(hex_dump); + buf = g_newa(guint8, MAX_PACKET_SIZE); + buflen = encrypted_len; + if (qq_crypt(DECRYPT, encrypted_data, encrypted_len, info->file_session_key, buf, &buflen)) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt success\n"); + if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) + purple_debug(PURPLE_DEBUG_INFO, "QQ", "checksum ok\n"); + hex_dump = hex_dump_to_str(buf, buflen); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypted packet: \n%s", hex_dump); + g_free(hex_dump); + } else { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt fail\n"); + } + } + */ + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); + _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); } /* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */ static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type, guint32 fragment_index, guint16 seq, guint8 *data, gint len) { + guint8 *raw_data, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH]; gint bytes; - guint8 *raw_data, *cursor, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH]; guint32 fragment_size = 1000; gchar *filename; gint filename_len, filesize; @@ -408,17 +407,16 @@ filesize = purple_xfer_get_size(qd->xfer); raw_data = g_newa(guint8, MAX_PACKET_SIZE); - cursor = raw_data; bytes = 0; - bytes += create_packet_b(raw_data, &cursor, 0x00); - bytes += create_packet_w(raw_data, &cursor, packet_type); + bytes += qq_put8(raw_data + bytes, 0x00); + bytes += qq_put16(raw_data + bytes, packet_type); switch (packet_type) { case QQ_FILE_BASIC_INFO: case QQ_FILE_DATA_INFO: case QQ_FILE_EOF: - bytes += create_packet_w(raw_data, &cursor, 0x0000); - bytes += create_packet_b(raw_data, &cursor, 0x00); + bytes += qq_put16(raw_data + bytes, 0x0000); + bytes += qq_put8(raw_data + bytes, 0x00); break; case QQ_FILE_CMD_FILE_OP: switch(sub_type) @@ -437,44 +435,44 @@ "start transfering data, %d fragments with %d length each\n", info->fragment_num, info->fragment_len); /* Unknown */ - bytes += create_packet_w(raw_data, &cursor, 0x0000); + bytes += qq_put16(raw_data + bytes, 0x0000); /* Sub-operation type */ - bytes += create_packet_b(raw_data, &cursor, sub_type); + bytes += qq_put8(raw_data + bytes, sub_type); /* Length of file */ - bytes += create_packet_dw(raw_data, &cursor, filesize); + bytes += qq_put32(raw_data + bytes, filesize); /* Number of fragments */ - bytes += create_packet_dw(raw_data, &cursor, info->fragment_num); + bytes += qq_put32(raw_data + bytes, info->fragment_num); /* Length of a single fragment */ - bytes += create_packet_dw(raw_data, &cursor, info->fragment_len); - bytes += create_packet_data(raw_data, &cursor, file_md5, 16); - bytes += create_packet_data(raw_data, &cursor, filename_md5, 16); + bytes += qq_put32(raw_data + bytes, info->fragment_len); + bytes += qq_putdata(raw_data + bytes, file_md5, 16); + bytes += qq_putdata(raw_data + bytes, filename_md5, 16); /* Length of filename */ - bytes += create_packet_w(raw_data, &cursor, filename_len); + bytes += qq_put16(raw_data + bytes, filename_len); /* 8 unknown bytes */ - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); /* filename */ - bytes += create_packet_data(raw_data, &cursor, (guint8 *) filename, + bytes += qq_putdata(raw_data + bytes, (guint8 *) filename, filename_len); break; case QQ_FILE_DATA_INFO: purple_debug(PURPLE_DEBUG_INFO, "QQ", "sending %dth fragment with length %d, offset %d\n", fragment_index, len, (fragment_index-1)*fragment_size); - /* bytes += create_packet_w(raw_data, &cursor, ++(qd->send_seq)); */ - bytes += create_packet_w(raw_data, &cursor, info->send_seq); - bytes += create_packet_b(raw_data, &cursor, sub_type); - /* bytes += create_packet_dw(raw_data, &cursor, fragment_index); */ - bytes += create_packet_dw(raw_data, &cursor, fragment_index - 1); - bytes += create_packet_dw(raw_data, &cursor, (fragment_index - 1) * fragment_size); - bytes += create_packet_w(raw_data, &cursor, len); - bytes += create_packet_data(raw_data, &cursor, data, len); + /* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */ + bytes += qq_put16(raw_data + bytes, info->send_seq); + bytes += qq_put8(raw_data + bytes, sub_type); + /* bytes += qq_put32(raw_data + bytes, fragment_index); */ + bytes += qq_put32(raw_data + bytes, fragment_index - 1); + bytes += qq_put32(raw_data + bytes, (fragment_index - 1) * fragment_size); + bytes += qq_put16(raw_data + bytes, len); + bytes += qq_putdata(raw_data + bytes, data, len); break; case QQ_FILE_EOF: purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of sending data\n"); - /* bytes += create_packet_w(raw_data, &cursor, info->fragment_num + 1); */ - bytes += create_packet_w(raw_data, &cursor, info->fragment_num); - bytes += create_packet_b(raw_data, &cursor, sub_type); + /* bytes += qq_put16(raw_data + bytes, info->fragment_num + 1); */ + bytes += qq_put16(raw_data + bytes, info->fragment_num); + bytes += qq_put8(raw_data + bytes, sub_type); /* purple_xfer_set_completed(qd->xfer, TRUE); */ } break; @@ -482,18 +480,18 @@ switch (sub_type) { case QQ_FILE_BASIC_INFO: - bytes += create_packet_w(raw_data, &cursor, 0x0000); - bytes += create_packet_b(raw_data, &cursor, sub_type); - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); + bytes += qq_put16(raw_data + bytes, 0x0000); + bytes += qq_put8(raw_data + bytes, sub_type); + bytes += qq_put32(raw_data + bytes, 0x00000000); break; case QQ_FILE_DATA_INFO: - bytes += create_packet_w(raw_data, &cursor, seq); - bytes += create_packet_b(raw_data, &cursor, sub_type); - bytes += create_packet_dw(raw_data, &cursor, fragment_index); + bytes += qq_put16(raw_data + bytes, seq); + bytes += qq_put8(raw_data + bytes, sub_type); + bytes += qq_put32(raw_data + bytes, fragment_index); break; case QQ_FILE_EOF: - bytes += create_packet_w(raw_data, &cursor, filesize / QQ_FILE_FRAGMENT_MAXLEN + 2); - bytes += create_packet_b(raw_data, &cursor, sub_type); + bytes += qq_put16(raw_data + bytes, filesize / QQ_FILE_FRAGMENT_MAXLEN + 2); + bytes += qq_put8(raw_data + bytes, sub_type); break; } } @@ -520,9 +518,11 @@ */ -static void _qq_process_recv_file_ctl_packet(PurpleConnection *gc, guint8 *data, guint8 *cursor, - gint len, qq_file_header *fh) +static void _qq_process_recv_file_ctl_packet(PurpleConnection *gc, guint8 *data, gint len) { + gint bytes ; + gint decryped_bytes; + qq_file_header fh; guint8 *decrypted_data; gint decrypted_len; qq_data *qd = (qq_data *) gc->proto_data; @@ -531,60 +531,65 @@ guint8 hellobyte; ft_info *info = (ft_info *) qd->xfer->data; + bytes = 0; + bytes += _qq_get_file_header(&fh, data + bytes); + decrypted_data = g_newa(guint8, len); decrypted_len = len; - if (qq_decrypt(cursor, len - (cursor - data), qd->session_md5, decrypted_data, &decrypted_len)) { - gchar *hex_dump; - cursor = decrypted_data + 16; /* skip md5 section */ - read_packet_w(decrypted_data, &cursor, decrypted_len, &packet_type); - read_packet_w(decrypted_data, &cursor, decrypted_len, &seq); - cursor += 4+1+1+19+1; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); - hex_dump = hex_dump_to_str(decrypted_data, decrypted_len); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypted control packet received: \n%s", hex_dump); - g_free(hex_dump); - switch (packet_type) { - case QQ_FILE_CMD_NOTIFY_IP_ACK: - cursor = decrypted_data; - qq_get_conn_info(decrypted_data, &cursor, decrypted_len, info); -/* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */ - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh->sender_uid, 0); - break; - case QQ_FILE_CMD_SENDER_SAY_HELLO: - /* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */ - cursor += 47; - read_packet_b(decrypted_data, &cursor, - decrypted_len, &hellobyte); + if ( !qq_decrypt(data, len, qd->session_md5, decrypted_data, &decrypted_len) ) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rcv file ctrl packet\n"); + return; + } + + /* only for debug info */ + decryped_bytes = 16; /* skip md5 section */ + decryped_bytes += qq_get16(&packet_type, decrypted_data + decryped_bytes); + decryped_bytes += qq_get16(&seq, decrypted_data + decryped_bytes); + decryped_bytes += 4+1+1+19+1; /* skip something */ + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", + decrypted_data, decrypted_len, + "decrypted control packet received:"); - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO_ACK, fh->sender_uid, hellobyte); - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO, fh->sender_uid, 0); - break; - case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: - /* I'm sender, do nothing */ - break; - case QQ_FILE_CMD_RECEIVER_SAY_HELLO: - /* I'm sender, ack the hello packet and send the first data */ - cursor += 47; - read_packet_b(decrypted_data, &cursor, - decrypted_len, &hellobyte); - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK, fh->sender_uid, hellobyte); - _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_BASIC_INFO, 0, 0, NULL, 0); - break; - case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: - /* I'm receiver, do nothing */ - break; - case QQ_FILE_CMD_PING: - /* I'm receiver, ack the PING */ - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PONG, fh->sender_uid, 0); - break; - case QQ_FILE_CMD_PONG: - qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh->sender_uid, 0); - break; - default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "unprocess file command %d\n", packet_type); - } - } + switch (packet_type) { + case QQ_FILE_CMD_NOTIFY_IP_ACK: + decryped_bytes = 0; + qq_get_conn_info(info, decrypted_data + decryped_bytes); + /* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */ + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); + break; + case QQ_FILE_CMD_SENDER_SAY_HELLO: + /* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */ + decryped_bytes += 47; + decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes); + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO_ACK, fh.sender_uid, hellobyte); + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO, fh.sender_uid, 0); + break; + case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: + /* I'm sender, do nothing */ + break; + case QQ_FILE_CMD_RECEIVER_SAY_HELLO: + /* I'm sender, ack the hello packet and send the first data */ + decryped_bytes += 47; + decryped_bytes += qq_get8(&hellobyte, decrypted_data + decryped_bytes); + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK, fh.sender_uid, hellobyte); + _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_BASIC_INFO, 0, 0, NULL, 0); + break; + case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: + /* I'm receiver, do nothing */ + break; + case QQ_FILE_CMD_PING: + /* I'm receiver, ack the PING */ + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PONG, fh.sender_uid, 0); + break; + case QQ_FILE_CMD_PONG: + qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); + break; + default: + purple_debug(PURPLE_DEBUG_INFO, "QQ", "unprocess file command %d\n", packet_type); + } } static void _qq_recv_file_progess(PurpleConnection *gc, guint8 *buffer, guint16 len, guint32 index, guint32 offset) @@ -609,15 +614,15 @@ purple_debug(PURPLE_DEBUG_INFO, "QQ", "duplicate %dth fragment, drop it!\n", index+1); return; } - + info->window |= mask; _qq_xfer_write_file(buffer, index, len, xfer); - + xfer->bytes_sent += len; xfer->bytes_remaining -= len; purple_xfer_update_progress(xfer); - + mask = 0x1 << (info->max_fragment_index % sizeof(info->window)); while (info->window & mask) { @@ -639,7 +644,7 @@ guint8 *buffer; guint i; gint readbytes; - + if (purple_xfer_get_bytes_remaining(xfer) <= 0) return; if (info->window == 0 && info->max_fragment_index == 0) { @@ -655,7 +660,7 @@ readbytes = _qq_xfer_read_file(buffer, info->max_fragment_index + i, info->fragment_len, xfer); if (readbytes > 0) _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_DATA_INFO, - info->max_fragment_index + i + 1, 0, buffer, readbytes); + info->max_fragment_index + i + 1, 0, buffer, readbytes); } if (mask & 0x8000) mask = 0x0001; else mask = mask << 1; @@ -706,8 +711,8 @@ info->fragment_len, xfer); if (readbytes > 0) _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_DATA_INFO, - info->max_fragment_index + sizeof(info->window) + 1, 0, buffer, readbytes); - + info->max_fragment_index + sizeof(info->window) + 1, 0, buffer, readbytes); + info->max_fragment_index ++; if (mask & 0x8000) mask = 0x0001; else mask = mask << 1; @@ -718,9 +723,10 @@ fragment_index, info->window, info->max_fragment_index); } -static void _qq_process_recv_file_data(PurpleConnection *gc, guint8 *data, guint8 *cursor, - gint len, guint32 to_uid) +static void _qq_process_recv_file_data(PurpleConnection *gc, guint8 *data, gint len) { + gint bytes ; + qq_file_header fh; guint16 packet_type; guint16 packet_seq; guint8 sub_type; @@ -729,24 +735,27 @@ guint32 fragment_offset; qq_data *qd = (qq_data *) gc->proto_data; ft_info *info = (ft_info *) qd->xfer->data; - - cursor += 1; /* skip an unknown byte */ - read_packet_w(data, &cursor, len, &packet_type); + + bytes = 0; + bytes += _qq_get_file_header(&fh, data + bytes); + + bytes += 1; /* skip an unknown byte */ + bytes += qq_get16(&packet_type, data + bytes); switch(packet_type) { case QQ_FILE_CMD_FILE_OP: - read_packet_w(data, &cursor, len, &packet_seq); - read_packet_b(data, &cursor, len, &sub_type); + bytes += qq_get16(&packet_seq, data + bytes); + bytes += qq_get8(&sub_type, data + bytes); switch (sub_type) { case QQ_FILE_BASIC_INFO: - cursor += 4; /* file length, we have already known it from xfer */ - read_packet_dw(data, &cursor, len, &info->fragment_num); - read_packet_dw(data, &cursor, len, &info->fragment_len); + bytes += 4; /* file length, we have already known it from xfer */ + bytes += qq_get32(&info->fragment_num, data + bytes); + bytes += qq_get32(&info->fragment_len, data + bytes); - /* FIXME: We must check the md5 here, if md5 doesn't match - * we will ignore the packet or send sth as error number - */ + /* FIXME: We must check the md5 here, + * if md5 doesn't match we will ignore + * the packet or send sth as error number */ info->max_fragment_index = 0; info->window = 0; @@ -757,27 +766,27 @@ 0, 0, NULL, 0); break; case QQ_FILE_DATA_INFO: - read_packet_dw(data, &cursor, len, &fragment_index); - read_packet_dw(data, &cursor, len, &fragment_offset); - read_packet_w(data, &cursor, len, &fragment_len); + bytes += qq_get32(&fragment_index, data + bytes); + bytes += qq_get32(&fragment_offset, data + bytes); + bytes += qq_get16(&fragment_len, data + bytes); purple_debug(PURPLE_DEBUG_INFO, "QQ", "received %dth fragment with length %d, offset %d\n", fragment_index, fragment_len, fragment_offset); - + _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, fragment_index, packet_seq, NULL, 0); - _qq_recv_file_progess(gc, cursor, fragment_len, fragment_index, fragment_offset); + _qq_recv_file_progess(gc, data + bytes, fragment_len, fragment_index, fragment_offset); break; case QQ_FILE_EOF: purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of receiving\n"); _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, - 0, 0, NULL, 0); + 0, 0, NULL, 0); break; } break; case QQ_FILE_CMD_FILE_OP_ACK: - read_packet_w(data, &cursor, len, &packet_seq); - read_packet_b(data, &cursor, len, &sub_type); + bytes += qq_get16(&packet_seq, data + bytes); + bytes += qq_get8(&sub_type, data + bytes); switch (sub_type) { case QQ_FILE_BASIC_INFO: @@ -787,16 +796,16 @@ _qq_send_file_progess(gc); break; case QQ_FILE_DATA_INFO: - read_packet_dw(data, &cursor, len, &fragment_index); + bytes += qq_get32(&fragment_index, data + bytes); _qq_update_send_progess(gc, fragment_index); if (purple_xfer_is_completed(qd->xfer)) _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_EOF, 0, 0, NULL, 0); - /* else + /* else _qq_send_file_progess(gc); */ break; case QQ_FILE_EOF: /* FIXME: OK, we can end the connection successfully */ - + _qq_send_file_data_packet(gc, QQ_FILE_EOF, 0, 0, 0, NULL, 0); purple_xfer_set_completed(qd->xfer, TRUE); break; @@ -820,21 +829,21 @@ void qq_process_recv_file(PurpleConnection *gc, guint8 *data, gint len) { - guint8 *cursor; - qq_file_header fh; + gint bytes; + guint8 tag; qq_data *qd; qd = (qq_data *) gc->proto_data; - cursor = data; - _qq_get_file_header(data, &cursor, len, &fh); + bytes = 0; + bytes += qq_get8(&tag, data + bytes); - switch (fh.tag) { + switch (tag) { case QQ_FILE_CONTROL_PACKET_TAG: - _qq_process_recv_file_ctl_packet(gc, data, cursor, len, &fh); + _qq_process_recv_file_ctl_packet(gc, data + bytes, len - bytes); break; case QQ_FILE_DATA_PACKET_TAG: - _qq_process_recv_file_data(gc, data, cursor, len, fh.sender_uid); + _qq_process_recv_file_data(gc, data + bytes, len - bytes); break; default: purple_debug(PURPLE_DEBUG_INFO, "QQ", "unknown packet tag");
--- a/libpurple/protocols/qq/group_im.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Mon Jun 30 23:12:54 2008 +0000 @@ -58,7 +58,7 @@ void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg) { gint data_len, bytes; - guint8 *raw_data, *cursor, *send_im_tail; + guint8 *raw_data, *send_im_tail; guint16 msg_len; gchar *msg_filtered; @@ -67,19 +67,19 @@ msg_filtered = purple_markup_strip_html(msg); purple_debug_info("QQ_MESG", "filterd qq qun mesg: %s\n", msg_filtered); msg_len = strlen(msg_filtered); + data_len = 7 + msg_len + QQ_SEND_IM_AFTER_MSG_LEN; raw_data = g_newa(guint8, data_len); - cursor = raw_data; bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_SEND_MSG); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - bytes += create_packet_w(raw_data, &cursor, msg_len + QQ_SEND_IM_AFTER_MSG_LEN); - bytes += create_packet_data(raw_data, &cursor, (guint8 *) msg_filtered, msg_len); + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_SEND_MSG); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); + bytes += qq_put16(raw_data + bytes, msg_len + QQ_SEND_IM_AFTER_MSG_LEN); + bytes += qq_putdata(raw_data + bytes, (guint8 *) msg_filtered, msg_len); send_im_tail = qq_get_send_im_tail(NULL, NULL, NULL, - FALSE, FALSE, FALSE, - QQ_SEND_IM_AFTER_MSG_LEN); - bytes += create_packet_data(raw_data, &cursor, send_im_tail, QQ_SEND_IM_AFTER_MSG_LEN); + FALSE, FALSE, FALSE, + QQ_SEND_IM_AFTER_MSG_LEN); + bytes += qq_putdata(raw_data + bytes, send_im_tail, QQ_SEND_IM_AFTER_MSG_LEN); g_free(send_im_tail); g_free(msg_filtered); @@ -87,11 +87,11 @@ qq_send_group_cmd(gc, group, raw_data, data_len); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); + "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); } /* this is the ACK */ -void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc) { /* return should be the internal group id * but we have nothing to do with it */ @@ -99,29 +99,26 @@ } /* receive an application to join the group */ -void qq_process_recv_group_im_apply_join - (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) { guint32 external_group_id, user_uid; guint8 group_type; gchar *reason_utf8, *msg, *reason; group_member_opt *g; gchar *nombre; + gint bytes = 0; g_return_if_fail(internal_group_id > 0 && data != NULL && len > 0); - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group msg apply_join is empty\n"); - return; - } + /* FIXME: check length here */ - read_packet_dw(data, cursor, len, &external_group_id); - read_packet_b(data, cursor, len, &group_type); - read_packet_dw(data, cursor, len, &user_uid); + bytes += qq_get32(&external_group_id, data + bytes); + bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&user_uid, data + bytes); g_return_if_fail(external_group_id > 0 && user_uid > 0); - convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf(_("User %d requested to join group %d"), user_uid, external_group_id); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); @@ -134,17 +131,17 @@ nombre = uid_to_purple_name(user_uid); purple_request_action(gc, _("QQ Qun Operation"), - msg, reason, - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), nombre, NULL, - g, 3, - _("Approve"), - G_CALLBACK - (qq_group_approve_application_with_struct), - _("Reject"), - G_CALLBACK - (qq_group_reject_application_with_struct), - _("Search"), G_CALLBACK(qq_group_search_application_with_struct)); + msg, reason, + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), nombre, NULL, + g, 3, + _("Approve"), + G_CALLBACK + (qq_group_approve_application_with_struct), + _("Reject"), + G_CALLBACK + (qq_group_reject_application_with_struct), + _("Search"), G_CALLBACK(qq_group_search_application_with_struct)); g_free(nombre); g_free(reason); @@ -153,31 +150,28 @@ } /* the request to join a group is rejected */ -void qq_process_recv_group_im_been_rejected - (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) { guint32 external_group_id, admin_uid; guint8 group_type; gchar *reason_utf8, *msg, *reason; qq_group *group; + gint bytes = 0; g_return_if_fail(data != NULL && len > 0); - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group msg been_rejected is empty\n"); - return; - } + /* FIXME: check length here */ - read_packet_dw(data, cursor, len, &external_group_id); - read_packet_b(data, cursor, len, &group_type); - read_packet_dw(data, cursor, len, &admin_uid); + bytes += qq_get32(&external_group_id, data + bytes); + bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&admin_uid, data + bytes); g_return_if_fail(external_group_id > 0 && admin_uid > 0); - convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been rejected by admin %d"), external_group_id, admin_uid); + (_("Your request to join group %d has been rejected by admin %d"), external_group_id, admin_uid); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason); @@ -194,31 +188,28 @@ } /* the request to join a group is approved */ -void qq_process_recv_group_im_been_approved - (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) { guint32 external_group_id, admin_uid; guint8 group_type; gchar *reason_utf8, *msg; qq_group *group; + gint bytes = 0; g_return_if_fail(data != NULL && len > 0); - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group msg been_approved is empty\n"); - return; - } + /* FIXME: check length here */ - read_packet_dw(data, cursor, len, &external_group_id); - read_packet_b(data, cursor, len, &group_type); - read_packet_dw(data, cursor, len, &admin_uid); + bytes += qq_get32(&external_group_id, data + bytes); + bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&admin_uid, data + bytes); g_return_if_fail(external_group_id > 0 && admin_uid > 0); /* it is also a "无" here, so do not display */ - convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been approved by admin %d"), external_group_id, admin_uid); + (_("Your request to join group %d has been approved by admin %d"), external_group_id, admin_uid); purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); @@ -233,24 +224,21 @@ } /* process the packet when removed from a group */ -void qq_process_recv_group_im_been_removed - (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) { guint32 external_group_id, uid; guint8 group_type; gchar *msg; qq_group *group; + gint bytes = 0; g_return_if_fail(data != NULL && len > 0); - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group msg been_removed is empty\n"); - return; - } + /* FIXME: check length here */ - read_packet_dw(data, cursor, len, &external_group_id); - read_packet_b(data, cursor, len, &group_type); - read_packet_dw(data, cursor, len, &uid); + bytes += qq_get32(&external_group_id, data + bytes); + bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&uid, data + bytes); g_return_if_fail(external_group_id > 0 && uid > 0); @@ -267,24 +255,21 @@ } /* process the packet when added to a group */ -void qq_process_recv_group_im_been_added - (guint8 *data, guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) { guint32 external_group_id, uid; guint8 group_type; qq_group *group; gchar *msg; + gint bytes = 0; g_return_if_fail(data != NULL && len > 0); - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group msg been_added is empty\n"); - return; - } + /* FIXME: check length here */ - read_packet_dw(data, cursor, len, &external_group_id); - read_packet_b(data, cursor, len, &group_type); - read_packet_dw(data, cursor, len, &uid); + bytes += qq_get32(&external_group_id, data + bytes); + bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&uid, data + bytes); g_return_if_fail(external_group_id > 0 && uid > 0); @@ -307,10 +292,9 @@ } /* recv an IM from a group chat */ -void qq_process_recv_group_im(guint8 *data, guint8 **cursor, gint data_len, - guint32 internal_group_id, PurpleConnection *gc, guint16 im_type) +void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type) { - gchar *msg_with_purple_smiley, *msg_utf8_encoded, *im_src_name, *hex_dump; + gchar *msg_with_purple_smiley, *msg_utf8_encoded, *im_src_name; guint16 unknown; guint32 unknown4; PurpleConversation *conv; @@ -319,32 +303,32 @@ qq_group *group; qq_recv_group_im *im_group; gint skip_len; + gint bytes = 0; g_return_if_fail(data != NULL && data_len > 0); + + /* FIXME: check length here */ + qd = (qq_data *) gc->proto_data; - hex_dump = hex_dump_to_str(*cursor, data_len - (*cursor - data)); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group im hex dump\n%s\n", hex_dump); - - if (*cursor >= (data + data_len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received group im_group is empty\n"); - return; - } + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", + data, data_len, + "group im hex dump"); im_group = g_newa(qq_recv_group_im, 1); - read_packet_dw(data, cursor, data_len, &(im_group->external_group_id)); - read_packet_b(data, cursor, data_len, &(im_group->group_type)); + bytes += qq_get32(&(im_group->external_group_id), data + bytes); + bytes += qq_get8(&(im_group->group_type), data + bytes); if(QQ_RECV_IM_TEMP_QUN_IM == im_type) { - read_packet_dw(data, cursor, data_len, &(internal_group_id)); + bytes += qq_get32(&(internal_group_id), data + bytes); } - read_packet_dw(data, cursor, data_len, &(im_group->member_uid)); - read_packet_w(data, cursor, data_len, &unknown); /* 0x0001? */ - read_packet_w(data, cursor, data_len, &(im_group->msg_seq)); - read_packet_time(data, cursor, data_len, &im_group->send_time); - read_packet_dw(data, cursor, data_len, &unknown4); /* versionID */ + bytes += qq_get32(&(im_group->member_uid), bytes + data); + bytes += qq_get16(&unknown, data + bytes); /* 0x0001? */ + bytes += qq_get16(&(im_group->msg_seq), data + bytes); + bytes += qq_getime(&im_group->send_time, data + bytes); + bytes += qq_get32(&unknown4, data + bytes); /* versionID */ /* * length includes font_attr * this msg_len includes msg and font_attr @@ -355,7 +339,7 @@ * 3. font_attr */ - read_packet_w(data, cursor, data_len, &(im_group->msg_len)); + bytes += qq_get16(&(im_group->msg_len), data + bytes); g_return_if_fail(im_group->msg_len > 0); /* @@ -371,14 +355,14 @@ skip_len = 10; else skip_len = 0; - *cursor += skip_len; + bytes += skip_len; - im_group->msg = g_strdup((gchar *) *cursor); - *cursor += strlen(im_group->msg) + 1; + im_group->msg = g_strdup((gchar *) data + bytes); + bytes += strlen(im_group->msg) + 1; /* there might not be any font_attr, check it */ im_group->font_attr_len = im_group->msg_len - strlen(im_group->msg) - 1 - skip_len; if (im_group->font_attr_len > 0) - im_group->font_attr = g_memdup(*cursor, im_group->font_attr_len); + im_group->font_attr = g_memdup(data + bytes, im_group->font_attr_len); else im_group->font_attr = NULL; @@ -386,7 +370,7 @@ msg_with_purple_smiley = qq_smiley_to_purple(im_group->msg); if (im_group->font_attr_len > 0) msg_utf8_encoded = qq_encode_to_purple(im_group->font_attr, - im_group->font_attr_len, msg_with_purple_smiley); + im_group->font_attr_len, msg_with_purple_smiley); else msg_utf8_encoded = qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); @@ -406,11 +390,10 @@ else im_src_name = g_strdup(member->nickname); serv_got_chat_in(gc, - purple_conv_chat_get_id(PURPLE_CONV_CHAT - (conv)), im_src_name, 0, msg_utf8_encoded, im_group->send_time); + purple_conv_chat_get_id(PURPLE_CONV_CHAT + (conv)), im_src_name, 0, msg_utf8_encoded, im_group->send_time); g_free(im_src_name); } - g_free(hex_dump); g_free(msg_with_purple_smiley); g_free(msg_utf8_encoded); g_free(im_group->msg);
--- a/libpurple/protocols/qq/group_im.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Mon Jun 30 23:12:54 2008 +0000 @@ -30,17 +30,31 @@ #include "group.h" void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg); -void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_process_recv_group_im(guint8 *data, - guint8 **cursor, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); -void qq_process_recv_group_im_apply_join(guint8 *data, - guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc); -void qq_process_recv_group_im_been_rejected(guint8 *data, - guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc); -void qq_process_recv_group_im_been_approved(guint8 *data, - guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc); -void qq_process_recv_group_im_been_removed(guint8 *data, - guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc); -void qq_process_recv_group_im_been_added(guint8 *data, - guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc); + +/* void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); */ +void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc); + +/* void qq_process_recv_group_im(guint8 *data, guint8 **cursor, + * gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); */ +void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); + +/* void qq_process_recv_group_im_apply_join(guint8 *data, guint8 **cursor, gint len, + * guint32 internal_group_id, PurpleConnection *gc); */ +void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + +/* void qq_process_recv_group_im_been_rejected(guint8 *data, guint8 **cursor, gint len, + * guint32 internal_group_id, PurpleConnection *gc); */ +void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + +/* void qq_process_recv_group_im_been_approved(guint8 *data, guint8 **cursor, gint len, + * guint32 internal_group_id, PurpleConnection *gc); */ +void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + +/* void qq_process_recv_group_im_been_removed(guint8 *data, guint8 **cursor, gint len, + * guint32 internal_group_id, PurpleConnection *gc); */ +void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + +/* void qq_process_recv_group_im_been_added(guint8 *data, guint8 **cursor, gint len, + * guint32 internal_group_id, PurpleConnection *gc); */ +void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_info.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Mon Jun 30 23:12:54 2008 +0000 @@ -43,7 +43,7 @@ { g_return_val_if_fail(member != NULL, FALSE); return (member->nickname == NULL) || - (time(NULL) - member->last_refresh) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; + (time(NULL) - member->last_refresh) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; } /* this is done when we receive the reply to get_online_members sub_cmd @@ -65,100 +65,83 @@ /* send packet to get detailed information of one group */ void qq_send_cmd_group_get_group_info(PurpleConnection *gc, qq_group *group) { - guint8 *raw_data, *cursor; - gint bytes, data_len; + guint8 raw_data[16] = {0}; + gint bytes = 0; g_return_if_fail(group != NULL); - data_len = 5; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_GROUP_INFO); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); - bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_GET_GROUP_INFO); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - - if (bytes != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_GROUP_INFO)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + qq_send_group_cmd(gc, group, raw_data, bytes); } /* send packet to get online group member, called by keep_alive */ void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) { - guint8 *raw_data, *cursor; - gint bytes, data_len; + guint8 raw_data[16] = {0}; + gint bytes = 0; g_return_if_fail(group != NULL); /* only get online members when conversation window is on */ if (NULL == purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,group->group_name_utf8, purple_connection_get_account(gc))) { purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conv windows for \"%s\" is not on, do not get online members\n", group->group_name_utf8); + "Conv windows for \"%s\" is not on, do not get online members\n", group->group_name_utf8); return; } - data_len = 5; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_ONLINE_MEMBER); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); - bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_GET_ONLINE_MEMBER); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - - if (bytes != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_ONLINE_MEMBER)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + qq_send_group_cmd(gc, group, raw_data, bytes); } /* send packet to get info for each group member */ void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group) { - guint8 *raw_data, *cursor; - gint bytes, data_len, i; + guint8 *raw_data; + gint bytes, num, data_len; GList *list; qq_buddy *member; g_return_if_fail(group != NULL); - for (i = 0, list = group->members; list != NULL; list = list->next) { + for (num = 0, list = group->members; list != NULL; list = list->next) { member = (qq_buddy *) list->data; if (_is_group_member_need_update_info(member)) - i++; + num++; } - if (i <= 0) { + if (num <= 0) { purple_debug(PURPLE_DEBUG_INFO, "QQ", "No group member needs to to update info now.\n"); return; } - data_len = 5 + 4 * i; + data_len = 5 + 4 * num; raw_data = g_newa(guint8, data_len); - cursor = raw_data; bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_GET_MEMBER_INFO); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_MEMBER_INFO); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); list = group->members; while (list != NULL) { member = (qq_buddy *) list->data; if (_is_group_member_need_update_info(member)) - bytes += create_packet_dw(raw_data, &cursor, member->uid); + bytes += qq_put32(raw_data + bytes, member->uid); list = list->next; } - if (bytes != data_len) + if (bytes != data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_MEMBER_INFO)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_MEMBER_INFO)); + return; + } + + qq_send_group_cmd(gc, group, raw_data, bytes); } -void qq_process_group_cmd_get_group_info(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_get_group_info(guint8 *data, gint len, PurpleConnection *gc) { qq_group *group; qq_buddy *member; @@ -168,16 +151,18 @@ guint16 unknown, max_members; guint32 member_uid, internal_group_id, external_group_id; GSList *pending_id; - gint pascal_len, i; guint32 unknown4; guint8 unknown1; + gint bytes, num; g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; - read_packet_dw(data, cursor, len, &(internal_group_id)); + bytes = 0; + bytes += qq_get32(&(internal_group_id), data + bytes); g_return_if_fail(internal_group_id > 0); - read_packet_dw(data, cursor, len, &(external_group_id)); + + bytes += qq_get32(&(external_group_id), data + bytes); g_return_if_fail(internal_group_id > 0); pending_id = qq_get_pending_id(qd->adding_groups_from_server, internal_group_id); @@ -189,32 +174,30 @@ group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); - read_packet_b(data, cursor, len, &(group->group_type)); - read_packet_dw(data, cursor, len, &unknown4); /* unknown 4 bytes */ - read_packet_dw(data, cursor, len, &(group->creator_uid)); - read_packet_b(data, cursor, len, &(group->auth_type)); - read_packet_dw(data, cursor, len, &unknown4); /* oldCategory */ - read_packet_w(data, cursor, len, &unknown); - read_packet_dw(data, cursor, len, &(group->group_category)); - read_packet_w(data, cursor, len, &max_members); - read_packet_b(data, cursor, len, &unknown1); - read_packet_dw(data, cursor, len, &(unknown4)); /* versionID */ + bytes += qq_get8(&(group->group_type), data + bytes); + bytes += qq_get32(&unknown4, data + bytes); /* unknown 4 bytes */ + bytes += qq_get32(&(group->creator_uid), data + bytes); + bytes += qq_get8(&(group->auth_type), data + bytes); + bytes += qq_get32(&unknown4, data + bytes); /* oldCategory */ + bytes += qq_get16(&unknown, data + bytes); + bytes += qq_get32(&(group->group_category), data + bytes); + bytes += qq_get16(&max_members, data + bytes); + bytes += qq_get8(&unknown1, data + bytes); + bytes += qq_get32(&(unknown4), data + bytes); /* versionID */ - pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); - *cursor += pascal_len; - read_packet_w(data, cursor, len, &(unknown)); /* 0x0000 */ - pascal_len = convert_as_pascal_string(*cursor, &(group->notice_utf8), QQ_CHARSET_DEFAULT); - *cursor += pascal_len; - pascal_len = convert_as_pascal_string(*cursor, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - *cursor += pascal_len; + /* strlen + <str content> */ + bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); + bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ + bytes += convert_as_pascal_string(data + bytes, &(group->notice_utf8), QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - i = 0; + num = 0; /* now comes the member list separated by 0x00 */ - while (*cursor < data + len) { - read_packet_dw(data, cursor, len, &member_uid); - i++; - read_packet_b(data, cursor, len, &organization); - read_packet_b(data, cursor, len, &role); + while (bytes < len) { + bytes += qq_get32(&member_uid, data + bytes); + num++; + bytes += qq_get8(&organization, data + bytes); + bytes += qq_get8(&role, data + bytes); if(organization != 0 || role != 0) { purple_debug(PURPLE_DEBUG_INFO, "QQ", "group member %d: organization=%d, role=%d\n", member_uid, organization, role); @@ -223,11 +206,11 @@ if (member != NULL) member->role = role; } - if(*cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); - } + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); + } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, i); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, num); if (group->creator_uid == qd->uid) group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; @@ -237,33 +220,32 @@ purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->group_name_utf8, purple_connection_get_account(gc)); if(NULL == purple_conv) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conv windows for \"%s\" is not on, do not set topic\n", group->group_name_utf8); + purple_debug(PURPLE_DEBUG_WARNING, "QQ", + "Conv windows for \"%s\" is not on, do not set topic\n", group->group_name_utf8); } else { purple_conv_chat_set_topic(PURPLE_CONV_CHAT(purple_conv), NULL, group->notice_utf8); } } -void qq_process_group_cmd_get_online_members(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_get_online_members(guint8 *data, gint len, PurpleConnection *gc) { guint32 internal_group_id, member_uid; guint8 unknown; - gint bytes, i; + gint bytes, num; qq_group *group; qq_buddy *member; g_return_if_fail(data != NULL && len > 0); - if (data + len - *cursor < 4) { + if (len <= 3) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Invalid group online member reply, discard it!\n"); return; } bytes = 0; - i = 0; - bytes += read_packet_dw(data, cursor, len, &internal_group_id); - bytes += read_packet_b(data, cursor, len, &unknown); /* 0x3c ?? */ + bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get8(&unknown, data + bytes); /* 0x3c ?? */ g_return_if_fail(internal_group_id > 0); group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); @@ -275,61 +257,63 @@ /* set all offline first, then update those online */ _qq_group_set_members_all_offline(group); - while (*cursor < data + len) { - bytes += read_packet_dw(data, cursor, len, &member_uid); - i++; + num = 0; + while (bytes < len) { + bytes += qq_get32(&member_uid, data + bytes); + num++; member = qq_group_find_or_add_member(gc, group, member_uid); if (member != NULL) member->status = QQ_BUDDY_ONLINE_NORMAL; } - if(*cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); - } + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); + } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, i); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, num); } /* process the reply to get_members_info packet */ -void qq_process_group_cmd_get_members_info(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_get_members_info(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; + gint num; guint32 internal_group_id, member_uid; guint16 unknown; - gint pascal_len, i; qq_group *group; qq_buddy *member; g_return_if_fail(data != NULL && len > 0); - read_packet_dw(data, cursor, len, &internal_group_id); + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); g_return_if_fail(internal_group_id > 0); group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); g_return_if_fail(group != NULL); - i = 0; + num = 0; /* now starts the member info, as get buddy list reply */ - while (*cursor < data + len) { - read_packet_dw(data, cursor, len, &member_uid); + while (bytes < len) { + bytes += qq_get32(&member_uid, data + bytes); g_return_if_fail(member_uid > 0); member = qq_group_find_member_by_uid(group, member_uid); g_return_if_fail(member != NULL); - i++; - read_packet_w(data, cursor, len, &(member->face)); - read_packet_b(data, cursor, len, &(member->age)); - read_packet_b(data, cursor, len, &(member->gender)); - pascal_len = convert_as_pascal_string(*cursor, &(member->nickname), QQ_CHARSET_DEFAULT); - *cursor += pascal_len; - read_packet_w(data, cursor, len, &unknown); - read_packet_b(data, cursor, len, &(member->flag1)); - read_packet_b(data, cursor, len, &(member->comm_flag)); + num++; + bytes += qq_get16(&(member->face), data + bytes); + bytes += qq_get8(&(member->age), data + bytes); + bytes += qq_get8(&(member->gender), data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(member->nickname), QQ_CHARSET_DEFAULT); + bytes += qq_get16(&unknown, data + bytes); + bytes += qq_get8(&(member->flag1), data + bytes); + bytes += qq_get8(&(member->comm_flag), data + bytes); member->last_refresh = time(NULL); } - if(*cursor > (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); - } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, i); + if(bytes > len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); + } + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, num); }
--- a/libpurple/protocols/qq/group_info.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_info.h Mon Jun 30 23:12:54 2008 +0000 @@ -32,8 +32,8 @@ void qq_send_cmd_group_get_group_info(PurpleConnection *gc, qq_group *group); void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group); void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group); -void qq_process_group_cmd_get_group_info(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_process_group_cmd_get_online_members(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_process_group_cmd_get_members_info(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); +void qq_process_group_cmd_get_group_info(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_group_cmd_get_online_members(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_group_cmd_get_members_info(guint8 *data, gint len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_join.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Mon Jun 30 23:12:54 2008 +0000 @@ -64,8 +64,8 @@ /* send packet to join a group without auth */ void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group) { - guint8 *raw_data, *cursor; - gint bytes, data_len; + guint8 raw_data[16] = {0}; + gint bytes = 0; g_return_if_fail(group != NULL); @@ -86,19 +86,11 @@ break; } - data_len = 5; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; + bytes = 0; + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_JOIN_GROUP); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); - bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_JOIN_GROUP); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - - if (bytes != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_JOIN_GROUP)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + qq_send_group_cmd(gc, group, raw_data, bytes); } static void _qq_group_join_auth_with_gc_and_id(gc_and_uid *g, const gchar *reason_utf8) @@ -145,7 +137,7 @@ void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8) { - guint8 *raw_data, *cursor; + guint8 *raw_data; gchar *reason_qq; gint bytes, data_len; @@ -164,50 +156,42 @@ data_len = 10 + strlen(reason_qq) + 1; raw_data = g_newa(guint8, data_len); - cursor = raw_data; bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_JOIN_GROUP_AUTH); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - bytes += create_packet_b(raw_data, &cursor, opt); - bytes += create_packet_dw(raw_data, &cursor, uid); - bytes += create_packet_b(raw_data, &cursor, strlen(reason_qq)); - bytes += create_packet_data(raw_data, &cursor, (guint8 *) reason_qq, strlen(reason_qq)); + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_JOIN_GROUP_AUTH); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); + bytes += qq_put8(raw_data + bytes, opt); + bytes += qq_put32(raw_data + bytes, uid); + bytes += qq_put8(raw_data + bytes, strlen(reason_qq)); + bytes += qq_putdata(raw_data + bytes, (guint8 *) reason_qq, strlen(reason_qq)); - if (bytes != data_len) + if (bytes != data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_JOIN_GROUP_AUTH)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + return; + } + + qq_send_group_cmd(gc, group, raw_data, data_len); } /* send a packet to exit a group */ void qq_send_cmd_group_exit_group(PurpleConnection *gc, qq_group *group) { - guint8 *raw_data, *cursor; - gint bytes, data_len; + guint8 raw_data[16] = {0}; + gint bytes = 0; g_return_if_fail(group != NULL); - data_len = 5; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_EXIT_GROUP); + bytes += qq_put32(raw_data + bytes, group->internal_group_id); - bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_EXIT_GROUP); - bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); - - if (bytes != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_EXIT_GROUP)); - else - qq_send_group_cmd(gc, group, raw_data, data_len); + qq_send_group_cmd(gc, group, raw_data, bytes); } /* If comes here, cmd is OK already */ -void qq_process_group_cmd_exit_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc) { - gint bytes, expected_bytes; + gint bytes; guint32 internal_group_id; PurpleChat *chat; qq_group *group; @@ -216,96 +200,94 @@ g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; - bytes = 0; - expected_bytes = 4; - bytes += read_packet_dw(data, cursor, len, &internal_group_id); + if (len < 4) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); + return; + } - if (bytes == expected_bytes) { - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); - if (group != NULL) { - chat = - purple_blist_find_chat + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); + + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + if (group != NULL) { + chat = purple_blist_find_chat (purple_connection_get_account(gc), g_strdup_printf("%d", group->external_group_id)); - if (chat != NULL) - purple_blist_remove_chat(chat); - qq_group_delete_internal_record(qd, internal_group_id); - } - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the group"), NULL); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid exit group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); + if (chat != NULL) + purple_blist_remove_chat(chat); + qq_group_delete_internal_record(qd, internal_group_id); } + purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the group"), NULL); } /* Process the reply to group_auth subcmd */ -void qq_process_group_cmd_join_group_auth(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc) { - gint bytes, expected_bytes; + gint bytes; guint32 internal_group_id; qq_data *qd; g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; + if (len < 4) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Invalid join group reply, expect %d bytes, read %d bytes\n", 4, len); + return; + } bytes = 0; - expected_bytes = 4; - bytes += read_packet_dw(data, cursor, len, &internal_group_id); + bytes += qq_get32(&internal_group_id, data + bytes); g_return_if_fail(internal_group_id > 0); - if (bytes == expected_bytes) - purple_notify_info - (gc, _("QQ Group Auth"), + purple_notify_info(gc, _("QQ Group Auth"), _("Your authorization request has been accepted by the QQ server"), NULL); - else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid join group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); } /* process group cmd reply "join group" */ -void qq_process_group_cmd_join_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc) { - gint bytes, expected_bytes; + gint bytes; guint32 internal_group_id; guint8 reply; qq_group *group; g_return_if_fail(data != NULL && len > 0); - bytes = 0; - expected_bytes = 5; - bytes += read_packet_dw(data, cursor, len, &internal_group_id); - bytes += read_packet_b(data, cursor, len, &reply); - - if (bytes != expected_bytes) { + if (len < 5) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid join group reply, expect %d bytes, read %d bytes\n", expected_bytes, bytes); + "Invalid join group reply, expect %d bytes, read %d bytes\n", 5, len); return; - } else { /* join group OK */ - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); - /* need to check if group is NULL or not. */ - g_return_if_fail(group != NULL); - switch (reply) { - case QQ_GROUP_JOIN_OK: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed joining group \"%s\"\n", group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; - qq_group_refresh(gc, group); - /* this must be shown before getting online members */ - qq_group_conv_show_window(gc, group); - qq_send_cmd_group_get_group_info(gc, group); - break; - case QQ_GROUP_JOIN_NEED_AUTH: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Fail joining group [%d] %s, needs authentication\n", - group->external_group_id, group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; - qq_group_refresh(gc, group); - _qq_group_join_auth(gc, group); - break; - default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Error joining group [%d] %s, unknown reply: 0x%02x\n", - group->external_group_id, group->group_name_utf8, reply); - } + } + + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get8(&reply, data + bytes); + + /* join group OK */ + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + /* need to check if group is NULL or not. */ + g_return_if_fail(group != NULL); + switch (reply) { + case QQ_GROUP_JOIN_OK: + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed joining group \"%s\"\n", group->group_name_utf8); + group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + qq_group_refresh(gc, group); + /* this must be shown before getting online members */ + qq_group_conv_show_window(gc, group); + qq_send_cmd_group_get_group_info(gc, group); + break; + case QQ_GROUP_JOIN_NEED_AUTH: + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Fail joining group [%d] %s, needs authentication\n", + group->external_group_id, group->group_name_utf8); + group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + qq_group_refresh(gc, group); + _qq_group_join_auth(gc, group); + break; + default: + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Error joining group [%d] %s, unknown reply: 0x%02x\n", + group->external_group_id, group->group_name_utf8, reply); } }
--- a/libpurple/protocols/qq/group_join.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Mon Jun 30 23:12:54 2008 +0000 @@ -46,8 +46,8 @@ void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group); void qq_group_exit(PurpleConnection *gc, GHashTable *data); void qq_send_cmd_group_exit_group(PurpleConnection *gc, qq_group *group); -void qq_process_group_cmd_exit_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_process_group_cmd_join_group_auth(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_process_group_cmd_join_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); +void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_network.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_network.c Mon Jun 30 23:12:54 2008 +0000 @@ -39,7 +39,7 @@ #include "group_opt.h" #include "group_search.h" #include "header_info.h" -#include "send_core.h" +#include "qq_network.h" #include "utils.h" enum { @@ -81,12 +81,12 @@ } /* default process of reply error */ -static void _qq_process_group_cmd_reply_error_default(guint8 reply, guint8 *cursor, gint len, PurpleConnection *gc) +static void _qq_process_group_cmd_reply_error_default(guint8 reply, guint8 *data, gint len, PurpleConnection *gc) { gchar *msg, *msg_utf8; - g_return_if_fail(cursor != NULL && len > 0); + g_return_if_fail(data != NULL && len > 0); - msg = g_strndup((gchar *) cursor, len); /* it will append 0x00 */ + msg = g_strndup((gchar *) data, len); /* it will append 0x00 */ msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); g_free(msg); msg = g_strdup_printf(_("Code [0x%02X]: %s"), reply, msg_utf8); @@ -96,14 +96,13 @@ } /* default process, dump only */ -static void _qq_process_group_cmd_reply_default(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +static void _qq_process_group_cmd_reply_default(guint8 *data, gint len, PurpleConnection *gc) { - gchar *hex_dump; g_return_if_fail(data != NULL && len > 0); - hex_dump = hex_dump_to_str(data, len); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Dump unprocessed group cmd reply:\n%s", hex_dump); - g_free(hex_dump); + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", + data, len, + "Dump unprocessed group cmd reply:"); } /* The lower layer command of send group cmd */ @@ -116,7 +115,7 @@ qd = (qq_data *) gc->proto_data; - qq_send_cmd(gc, QQ_CMD_GROUP_CMD, TRUE, 0, TRUE, raw_data, data_len); + qq_send_cmd(qd, QQ_CMD_GROUP_CMD, raw_data, data_len); p = g_new0(group_packet, 1); @@ -136,7 +135,7 @@ qq_data *qd; gint len, bytes; guint32 internal_group_id; - guint8 *data, *cursor, sub_cmd, reply; + guint8 *data, sub_cmd, reply; g_return_if_fail(buf != NULL && buf_len != 0); @@ -149,102 +148,101 @@ return; } - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - if (len <= 2) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Group cmd reply is too short, only %d bytes\n", len); - return; - } + if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt group cmd reply\n"); + return; + } - bytes = 0; - cursor = data; - bytes += read_packet_b(data, &cursor, len, &sub_cmd); - bytes += read_packet_b(data, &cursor, len, &reply); - - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + if (len <= 2) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Group cmd reply is too short, only %d bytes\n", len); + return; + } - if (reply != QQ_GROUP_CMD_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Group cmd reply says cmd %s fails\n", qq_group_cmd_get_desc(sub_cmd)); + bytes = 0; + bytes += qq_get8(&sub_cmd, data + bytes); + bytes += qq_get8(&reply, data + bytes); - if (group != NULL) - qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); + group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); - switch (reply) { /* this should be all errors */ - case QQ_GROUP_CMD_REPLY_NOT_MEMBER: - if (group != NULL) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", - "You are not a member of group \"%s\"\n", group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; - qq_group_refresh(gc, group); - } - break; - case QQ_GROUP_CMD_REPLY_SEARCH_ERROR: - if (qd->roomlist != NULL) { - if (purple_roomlist_get_in_progress(qd->roomlist)) - purple_roomlist_set_in_progress(qd->roomlist, FALSE); - } - _qq_process_group_cmd_reply_error_default(reply, cursor, len - bytes, gc); - break; - default: - _qq_process_group_cmd_reply_error_default(reply, cursor, len - bytes, gc); - } - return; - } + if (reply != QQ_GROUP_CMD_REPLY_OK) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", + "Group cmd reply says cmd %s fails\n", qq_group_cmd_get_desc(sub_cmd)); + + if (group != NULL) + qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); - /* seems ok so far, so we process the reply according to sub_cmd */ - switch (sub_cmd) { - case QQ_GROUP_CMD_GET_GROUP_INFO: - qq_process_group_cmd_get_group_info(data, &cursor, len, gc); + switch (reply) { /* this should be all errors */ + case QQ_GROUP_CMD_REPLY_NOT_MEMBER: if (group != NULL) { - qq_send_cmd_group_get_members_info(gc, group); - qq_send_cmd_group_get_online_members(gc, group); + purple_debug(PURPLE_DEBUG_WARNING, + "QQ", + "You are not a member of group \"%s\"\n", group->group_name_utf8); + group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + qq_group_refresh(gc, group); } break; - case QQ_GROUP_CMD_CREATE_GROUP: - qq_group_process_create_group_reply(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_MODIFY_GROUP_INFO: - qq_group_process_modify_info_reply(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_MEMBER_OPT: - qq_group_process_modify_members_reply(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_ACTIVATE_GROUP: - qq_group_process_activate_group_reply(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_SEARCH_GROUP: - qq_process_group_cmd_search_group(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_JOIN_GROUP: - qq_process_group_cmd_join_group(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_JOIN_GROUP_AUTH: - qq_process_group_cmd_join_group_auth(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_EXIT_GROUP: - qq_process_group_cmd_exit_group(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_SEND_MSG: - qq_process_group_cmd_im(data, &cursor, len, gc); - break; - case QQ_GROUP_CMD_GET_ONLINE_MEMBER: - qq_process_group_cmd_get_online_members(data, &cursor, len, gc); - if (group != NULL) - qq_group_conv_refresh_online_member(gc, group); - break; - case QQ_GROUP_CMD_GET_MEMBER_INFO: - qq_process_group_cmd_get_members_info(data, &cursor, len, gc); - if (group != NULL) - qq_group_conv_refresh_online_member(gc, group); + case QQ_GROUP_CMD_REPLY_SEARCH_ERROR: + if (qd->roomlist != NULL) { + if (purple_roomlist_get_in_progress(qd->roomlist)) + purple_roomlist_set_in_progress(qd->roomlist, FALSE); + } + _qq_process_group_cmd_reply_error_default(reply, data + bytes, len - bytes, gc); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Group cmd %s is processed by default\n", qq_group_cmd_get_desc(sub_cmd)); - _qq_process_group_cmd_reply_default(data, &cursor, len, gc); + _qq_process_group_cmd_reply_error_default(reply, data + bytes, len - bytes, gc); + } + return; + } + + /* seems ok so far, so we process the reply according to sub_cmd */ + switch (sub_cmd) { + case QQ_GROUP_CMD_GET_GROUP_INFO: + qq_process_group_cmd_get_group_info(data + bytes, len - bytes, gc); + if (group != NULL) { + qq_send_cmd_group_get_members_info(gc, group); + qq_send_cmd_group_get_online_members(gc, group); } - - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt group cmd reply\n"); + break; + case QQ_GROUP_CMD_CREATE_GROUP: + qq_group_process_create_group_reply(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_MODIFY_GROUP_INFO: + qq_group_process_modify_info_reply(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_MEMBER_OPT: + qq_group_process_modify_members_reply(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_ACTIVATE_GROUP: + qq_group_process_activate_group_reply(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_SEARCH_GROUP: + qq_process_group_cmd_search_group(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_JOIN_GROUP: + qq_process_group_cmd_join_group(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_JOIN_GROUP_AUTH: + qq_process_group_cmd_join_group_auth(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_EXIT_GROUP: + qq_process_group_cmd_exit_group(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_SEND_MSG: + qq_process_group_cmd_im(data + bytes, len - bytes, gc); + break; + case QQ_GROUP_CMD_GET_ONLINE_MEMBER: + qq_process_group_cmd_get_online_members(data + bytes, len - bytes, gc); + if (group != NULL) + qq_group_conv_refresh_online_member(gc, group); + break; + case QQ_GROUP_CMD_GET_MEMBER_INFO: + qq_process_group_cmd_get_members_info(data + bytes, len - bytes, gc); + if (group != NULL) + qq_group_conv_refresh_online_member(gc, group); + break; + default: + purple_debug(PURPLE_DEBUG_WARNING, "QQ", + "Group cmd %s is processed by default\n", qq_group_cmd_get_desc(sub_cmd)); + _qq_process_group_cmd_reply_default(data + bytes, len, gc); } }
--- a/libpurple/protocols/qq/group_opt.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Mon Jun 30 23:12:54 2008 +0000 @@ -57,22 +57,24 @@ static void _qq_group_member_opt(PurpleConnection *gc, qq_group *group, gint operation, guint32 *members) { - guint8 *data, *cursor; + guint8 *data; gint i, count, data_len; + gint bytes; g_return_if_fail(members != NULL); - for (i = 0; members[i] != 0xffffffff; i++) {; + for (count = 0; members[count] != 0xffffffff; count++) {; } - count = i; data_len = 6 + count * 4; data = g_newa(guint8, data_len); - cursor = data; - create_packet_b(data, &cursor, QQ_GROUP_CMD_MEMBER_OPT); - create_packet_dw(data, &cursor, group->internal_group_id); - create_packet_b(data, &cursor, operation); + + bytes = 0; + bytes += qq_put8(data + bytes, QQ_GROUP_CMD_MEMBER_OPT); + bytes += qq_put32(data + bytes, group->internal_group_id); + bytes += qq_put8(data + bytes, operation); for (i = 0; i < count; i++) - create_packet_dw(data, &cursor, members[i]); - qq_send_group_cmd(gc, group, data, data_len); + bytes += qq_put32(data + bytes, members[i]); + + qq_send_group_cmd(gc, group, data, bytes); } static void _qq_group_do_nothing_with_struct(group_member_opt *g) @@ -97,11 +99,11 @@ qq_send_packet_get_info(g->gc, g->member, TRUE); /* we want to see window */ purple_request_action(g->gc, NULL, _("Do you want to approve the request?"), "", - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(g->gc), NULL, NULL, - g, 2, - _("Reject"), G_CALLBACK(qq_group_reject_application_with_struct), - _("Approve"), G_CALLBACK(qq_group_approve_application_with_struct)); + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(g->gc), NULL, NULL, + g, 2, + _("Reject"), G_CALLBACK(qq_group_reject_application_with_struct), + _("Approve"), G_CALLBACK(qq_group_approve_application_with_struct)); } void qq_group_reject_application_with_struct(group_member_opt *g) @@ -193,13 +195,15 @@ _qq_group_member_opt(gc, group, QQ_GROUP_MEMBER_ADD, add_members); } -void qq_group_process_modify_members_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; guint32 internal_group_id; qq_group *group; g_return_if_fail(data != NULL); - read_packet_dw(data, cursor, len, &internal_group_id); + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); g_return_if_fail(internal_group_id > 0); /* we should have its info locally */ @@ -213,8 +217,9 @@ void qq_group_modify_info(PurpleConnection *gc, qq_group *group) { - gint data_len, data_written; - guint8 *data, *cursor; + guint8 *data; + gint data_len; + gint bytes; gchar *group_name, *group_desc, *notice; g_return_if_fail(group != NULL); @@ -228,47 +233,50 @@ + 1 + strlen(notice); data = g_newa(guint8, data_len); - cursor = data; - data_written = 0; + bytes = 0; /* 000-000 */ - data_written += create_packet_b(data, &cursor, QQ_GROUP_CMD_MODIFY_GROUP_INFO); + bytes += qq_put8(data + bytes, QQ_GROUP_CMD_MODIFY_GROUP_INFO); /* 001-004 */ - data_written += create_packet_dw(data, &cursor, group->internal_group_id); + bytes += qq_put32(data + bytes, group->internal_group_id); /* 005-005 */ - data_written += create_packet_b(data, &cursor, 0x01); + bytes += qq_put8(data + bytes, 0x01); /* 006-006 */ - data_written += create_packet_b(data, &cursor, group->auth_type); + bytes += qq_put8(data + bytes, group->auth_type); /* 007-008 */ - data_written += create_packet_w(data, &cursor, 0x0000); + bytes += qq_put16(data + bytes, 0x0000); /* 009-010 */ - data_written += create_packet_w(data, &cursor, group->group_category); + bytes += qq_put16(data + bytes, group->group_category); - data_written += create_packet_b(data, &cursor, strlen(group_name)); - data_written += create_packet_data(data, &cursor, (guint8 *) group_name, strlen(group_name)); + bytes += qq_put8(data + bytes, strlen(group_name)); + bytes += qq_putdata(data + bytes, (guint8 *) group_name, strlen(group_name)); - data_written += create_packet_w(data, &cursor, 0x0000); + bytes += qq_put16(data + bytes, 0x0000); - data_written += create_packet_b(data, &cursor, strlen(notice)); - data_written += create_packet_data(data, &cursor, (guint8 *) notice, strlen(notice)); + bytes += qq_put8(data + bytes, strlen(notice)); + bytes += qq_putdata(data+ bytes, (guint8 *) notice, strlen(notice)); - data_written += create_packet_b(data, &cursor, strlen(group_desc)); - data_written += create_packet_data(data, &cursor, (guint8 *) group_desc, strlen(group_desc)); + bytes += qq_put8(data + bytes, strlen(group_desc)); + bytes += qq_putdata(data + bytes, (guint8 *) group_desc, strlen(group_desc)); - if (data_written != data_len) + if (bytes != data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail to create group_modify_info packet, expect %d bytes, wrote %d bytes\n", - data_len, data_written); - else - qq_send_group_cmd(gc, group, data, data_len); + data_len, bytes); + return; + } + + qq_send_group_cmd(gc, group, data, bytes); } -void qq_group_process_modify_info_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_group_process_modify_info_reply(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; guint32 internal_group_id; qq_group *group; g_return_if_fail(data != NULL); - read_packet_dw(data, cursor, len, &internal_group_id); + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); g_return_if_fail(internal_group_id > 0); /* we should have its info locally */ @@ -284,42 +292,44 @@ /* we create a very simple group first, and then let the user to modify */ void qq_group_create_with_name(PurpleConnection *gc, const gchar *name) { - gint data_len, data_written; - guint8 *data, *cursor; + gint data_len; + guint8 *data; + gint bytes; qq_data *qd; g_return_if_fail(name != NULL); qd = (qq_data *) gc->proto_data; data_len = 7 + 1 + strlen(name) + 2 + 1 + 1 + 4; data = g_newa(guint8, data_len); - cursor = data; - data_written = 0; + bytes = 0; /* we create the simpleset group, only group name is given */ /* 000 */ - data_written += create_packet_b(data, &cursor, QQ_GROUP_CMD_CREATE_GROUP); + bytes += qq_put8(data + bytes, QQ_GROUP_CMD_CREATE_GROUP); /* 001 */ - data_written += create_packet_b(data, &cursor, QQ_GROUP_TYPE_PERMANENT); + bytes += qq_put8(data + bytes, QQ_GROUP_TYPE_PERMANENT); /* 002 */ - data_written += create_packet_b(data, &cursor, QQ_GROUP_AUTH_TYPE_NEED_AUTH); + bytes += qq_put8(data + bytes, QQ_GROUP_AUTH_TYPE_NEED_AUTH); /* 003-004 */ - data_written += create_packet_w(data, &cursor, 0x0000); + bytes += qq_put16(data + bytes, 0x0000); /* 005-006 */ - data_written += create_packet_w(data, &cursor, 0x0003); + bytes += qq_put16(data + bytes, 0x0003); /* 007 */ - data_written += create_packet_b(data, &cursor, strlen(name)); - data_written += create_packet_data(data, &cursor, (guint8 *) name, strlen(name)); - data_written += create_packet_w(data, &cursor, 0x0000); - data_written += create_packet_b(data, &cursor, 0x00); /* no group notice */ - data_written += create_packet_b(data, &cursor, 0x00); /* no group desc */ - data_written += create_packet_dw(data, &cursor, qd->uid); /* I am member of coz */ + bytes += qq_put8(data + bytes, strlen(name)); + bytes += qq_putdata(data + bytes, (guint8 *) name, strlen(name)); + bytes += qq_put16(data + bytes, 0x0000); + bytes += qq_put8(data + bytes, 0x00); /* no group notice */ + bytes += qq_put8(data + bytes, 0x00); /* no group desc */ + bytes += qq_put32(data + bytes, qd->uid); /* I am member of coz */ - if (data_written != data_len) + if (bytes != data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create create_group packet, expect %d bytes, written %d bytes\n", - data_len, data_written); - else - qq_send_group_cmd(gc, NULL, data, data_len); + data_len, bytes); + return; + } + + qq_send_group_cmd(gc, NULL, data, bytes); } static void qq_group_setup_with_gc_and_uid(gc_and_uid *g) @@ -335,8 +345,9 @@ g_free(g); } -void qq_group_process_create_group_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_group_process_create_group_reply(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; guint32 internal_group_id, external_group_id; qq_group *group; gc_and_uid *g; @@ -346,8 +357,9 @@ g_return_if_fail(gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - read_packet_dw(data, cursor, len, &internal_group_id); - read_packet_dw(data, cursor, len, &external_group_id); + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get32(&external_group_id, data + bytes); g_return_if_fail(internal_group_id > 0 && external_group_id); group = qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); @@ -378,36 +390,29 @@ /* we have to activate group after creation, otherwise the group can not be searched */ void qq_group_activate_group(PurpleConnection *gc, guint32 internal_group_id) { - gint data_len, data_written; - guint8 *data, *cursor; + guint8 data[16] = {0}; + gint bytes = 0; g_return_if_fail(internal_group_id > 0); - data_len = 5; - data = g_newa(guint8, data_len); - cursor = data; - - data_written = 0; + bytes = 0; /* we create the simplest group, only group name is given */ /* 000 */ - data_written += create_packet_b(data, &cursor, QQ_GROUP_CMD_ACTIVATE_GROUP); + bytes += qq_put8(data + bytes, QQ_GROUP_CMD_ACTIVATE_GROUP); /* 001-005 */ - data_written += create_packet_dw(data, &cursor, internal_group_id); + bytes += qq_put32(data + bytes, internal_group_id); - if (data_written != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create activate_group packet, expect %d bytes, written %d bytes\n", - data_len, data_written); - else - qq_send_group_cmd(gc, NULL, data, data_len); + qq_send_group_cmd(gc, NULL, data, bytes); } -void qq_group_process_activate_group_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_group_process_activate_group_reply(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; guint32 internal_group_id; qq_group *group; g_return_if_fail(data != NULL); - read_packet_dw(data, cursor, len, &internal_group_id); + bytes = 0; + bytes += qq_get32(&internal_group_id, data + bytes); g_return_if_fail(internal_group_id > 0); /* we should have its info locally */
--- a/libpurple/protocols/qq/group_opt.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.h Mon Jun 30 23:12:54 2008 +0000 @@ -54,12 +54,12 @@ void qq_group_reject_application_with_struct(group_member_opt *g); void qq_group_search_application_with_struct(group_member_opt *g); -void qq_group_process_modify_info_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_group_process_modify_members_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); +void qq_group_process_modify_info_reply(guint8 *data, gint len, PurpleConnection *gc); +void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc); void qq_group_manage_group(PurpleConnection *gc, GHashTable *data); void qq_group_create_with_name(PurpleConnection *gc, const gchar *name); void qq_group_activate_group(PurpleConnection *gc, guint32 internal_group_id); -void qq_group_process_activate_group_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); -void qq_group_process_create_group_reply(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); +void qq_group_process_activate_group_reply(guint8 *data, gint len, PurpleConnection *gc); +void qq_group_process_create_group_reply(guint8 *data, gint len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_search.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Mon Jun 30 23:12:54 2008 +0000 @@ -43,24 +43,18 @@ /* send packet to search for qq_group */ void qq_send_cmd_group_search_group(PurpleConnection *gc, guint32 external_group_id) { - guint8 *raw_data, *cursor, type; - gint bytes, data_len; + guint8 raw_data[16] = {0}; + gint bytes = 0; + guint8 type; - data_len = 6; - raw_data = g_newa(guint8, data_len); - cursor = raw_data; type = (external_group_id == 0x00000000) ? QQ_GROUP_SEARCH_TYPE_DEMO : QQ_GROUP_SEARCH_TYPE_BY_ID; bytes = 0; - bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_SEARCH_GROUP); - bytes += create_packet_b(raw_data, &cursor, type); - bytes += create_packet_dw(raw_data, &cursor, external_group_id); + bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_SEARCH_GROUP); + bytes += qq_put8(raw_data + bytes, type); + bytes += qq_put32(raw_data + bytes, external_group_id); - if (bytes != data_len) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_SEARCH_GROUP)); - else - qq_send_group_cmd(gc, NULL, raw_data, data_len); + qq_send_group_cmd(gc, NULL, raw_data, bytes); } static void _qq_setup_roomlist(qq_data *qd, qq_group *group) @@ -89,55 +83,50 @@ } /* process group cmd reply "search group" */ -void qq_process_group_cmd_search_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +void qq_process_group_cmd_search_group(guint8 *data, gint len, PurpleConnection *gc) { + gint bytes; guint8 search_type; guint16 unknown; - gint bytes, pascal_len; + qq_group group; qq_data *qd; - qq_group *group; GSList *pending_id; g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; - read_packet_b(data, cursor, len, &search_type); - group = g_newa(qq_group, 1); + bytes = 0; + bytes += qq_get8(&search_type, data + bytes); /* now it starts with group_info_entry */ - bytes = 0; - bytes += read_packet_dw(data, cursor, len, &(group->internal_group_id)); - bytes += read_packet_dw(data, cursor, len, &(group->external_group_id)); - bytes += read_packet_b(data, cursor, len, &(group->group_type)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_dw(data, cursor, len, &(group->creator_uid)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_dw(data, cursor, len, &(group->group_category)); - pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); - bytes += pascal_len; - *cursor += pascal_len; - bytes += read_packet_w(data, cursor, len, &(unknown)); - bytes += read_packet_b(data, cursor, len, &(group->auth_type)); - pascal_len = convert_as_pascal_string(*cursor, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - bytes += pascal_len; - *cursor += pascal_len; + bytes += qq_get32(&(group.internal_group_id), data + bytes); + bytes += qq_get32(&(group.external_group_id), data + bytes); + bytes += qq_get8(&(group.group_type), data + bytes); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get32(&(group.creator_uid), data + bytes); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get32(&(group.group_category), data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.group_name_utf8), QQ_CHARSET_DEFAULT); + bytes += qq_get16(&(unknown), data + bytes); + bytes += qq_get8(&(group.auth_type), data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.group_desc_utf8), QQ_CHARSET_DEFAULT); /* end of one qq_group */ - if(*cursor != (data + len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); - } + if(bytes != len) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); + } - pending_id = qq_get_pending_id(qd->joining_groups, group->external_group_id); + pending_id = qq_get_pending_id(qd->joining_groups, group.external_group_id); if (pending_id != NULL) { - qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); - if (qq_group_find_by_id(gc, group->internal_group_id, QQ_INTERNAL_ID) == NULL) + qq_set_pending_id(&qd->joining_groups, group.external_group_id, FALSE); + if (qq_group_find_by_id(gc, group.internal_group_id, QQ_INTERNAL_ID) == NULL) qq_group_create_internal_record(gc, - group->internal_group_id, group->external_group_id, group->group_name_utf8); - qq_send_cmd_group_join_group(gc, group); + group.internal_group_id, group.external_group_id, group.group_name_utf8); + qq_send_cmd_group_join_group(gc, &group); } else { - _qq_setup_roomlist(qd, group); + _qq_setup_roomlist(qd, &group); } }
--- a/libpurple/protocols/qq/group_search.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/group_search.h Mon Jun 30 23:12:54 2008 +0000 @@ -29,6 +29,6 @@ #include "connection.h" void qq_send_cmd_group_search_group(PurpleConnection *gc, guint32 external_group_id); -void qq_process_group_cmd_search_group(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); +void qq_process_group_cmd_search_group(guint8 *data, gint len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/im.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/im.c Mon Jun 30 23:12:54 2008 +0000 @@ -40,19 +40,16 @@ #include "header_info.h" #include "im.h" #include "packet_parse.h" -#include "send_core.h" +#include "qq_network.h" #include "send_file.h" #include "utils.h" #define QQ_SEND_IM_REPLY_OK 0x00 #define DEFAULT_FONT_NAME_LEN 4 -/* a debug function */ -void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len); - enum { - QQ_NORMAL_IM_TEXT = 0x000b, + QQ_NORMAL_IM_TEXT = 0x000b, QQ_NORMAL_IM_FILE_REQUEST_TCP = 0x0001, QQ_NORMAL_IM_FILE_APPROVE_TCP = 0x0003, QQ_NORMAL_IM_FILE_REJECT_TCP = 0x0005, @@ -121,9 +118,9 @@ #define DEFAULT_FONT_NAME "\0xcb\0xce\0xcc\0xe5" guint8 *qq_get_send_im_tail(const gchar *font_color, - const gchar *font_size, - const gchar *font_name, - gboolean is_bold, gboolean is_italic, gboolean is_underline, gint tail_len) + const gchar *font_size, + const gchar *font_name, + gboolean is_bold, gboolean is_italic, gboolean is_underline, gint tail_len) { gchar *s1; unsigned char *rgb; @@ -141,7 +138,7 @@ send_im_tail = g_new0(guint8, tail_len); g_strlcpy((gchar *) (send_im_tail + QQ_SEND_IM_AFTER_MSG_HEADER_LEN), - font_name, tail_len - QQ_SEND_IM_AFTER_MSG_HEADER_LEN); + font_name, tail_len - QQ_SEND_IM_AFTER_MSG_HEADER_LEN); send_im_tail[tail_len - 1] = (guint8) tail_len; send_im_tail[0] = 0x00; @@ -182,39 +179,39 @@ send_im_tail[5] = 0x00; send_im_tail[6] = 0x86; send_im_tail[7] = 0x22; /* encoding, 0x8622=GB, 0x0000=EN, define BIG5 support here */ - _qq_show_packet("QQ_MESG", send_im_tail, tail_len); + qq_show_packet("QQ_MESG", send_im_tail, tail_len); return (guint8 *) send_im_tail; } static const gchar *qq_get_recv_im_type_str(gint type) { switch (type) { - case QQ_RECV_IM_TO_BUDDY: - return "QQ_RECV_IM_TO_BUDDY"; - case QQ_RECV_IM_TO_UNKNOWN: - return "QQ_RECV_IM_TO_UNKNOWN"; - case QQ_RECV_IM_UNKNOWN_QUN_IM: - return "QQ_RECV_IM_UNKNOWN_QUN_IM"; - case QQ_RECV_IM_ADD_TO_QUN: - return "QQ_RECV_IM_ADD_TO_QUN"; - case QQ_RECV_IM_DEL_FROM_QUN: - return "QQ_RECV_IM_DEL_FROM_QUN"; - case QQ_RECV_IM_APPLY_ADD_TO_QUN: - return "QQ_RECV_IM_APPLY_ADD_TO_QUN"; - case QQ_RECV_IM_CREATE_QUN: - return "QQ_RECV_IM_CREATE_QUN"; - case QQ_RECV_IM_SYS_NOTIFICATION: - return "QQ_RECV_IM_SYS_NOTIFICATION"; - case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: - return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN"; - case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: - return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN"; - case QQ_RECV_IM_TEMP_QUN_IM: - return "QQ_RECV_IM_TEMP_QUN_IM"; - case QQ_RECV_IM_QUN_IM: - return "QQ_RECV_IM_QUN_IM"; - default: - return "QQ_RECV_IM_UNKNOWN"; + case QQ_RECV_IM_TO_BUDDY: + return "QQ_RECV_IM_TO_BUDDY"; + case QQ_RECV_IM_TO_UNKNOWN: + return "QQ_RECV_IM_TO_UNKNOWN"; + case QQ_RECV_IM_UNKNOWN_QUN_IM: + return "QQ_RECV_IM_UNKNOWN_QUN_IM"; + case QQ_RECV_IM_ADD_TO_QUN: + return "QQ_RECV_IM_ADD_TO_QUN"; + case QQ_RECV_IM_DEL_FROM_QUN: + return "QQ_RECV_IM_DEL_FROM_QUN"; + case QQ_RECV_IM_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_CREATE_QUN: + return "QQ_RECV_IM_CREATE_QUN"; + case QQ_RECV_IM_SYS_NOTIFICATION: + return "QQ_RECV_IM_SYS_NOTIFICATION"; + case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: + return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN"; + case QQ_RECV_IM_TEMP_QUN_IM: + return "QQ_RECV_IM_TEMP_QUN_IM"; + case QQ_RECV_IM_QUN_IM: + return "QQ_RECV_IM_QUN_IM"; + default: + return "QQ_RECV_IM_UNKNOWN"; } } @@ -222,27 +219,29 @@ * we send an ACK which is the first 16 bytes of incoming packet */ static void _qq_send_packet_recv_im_ack(PurpleConnection *gc, guint16 seq, guint8 *data) { - qq_send_cmd(gc, QQ_CMD_RECV_IM, FALSE, seq, FALSE, data, 16); + qq_data *qd; + + qd = (qq_data *) gc->proto_data; + qq_send_cmd_detail(qd, QQ_CMD_RECV_IM, seq, FALSE, data, 16); } /* read the common parts of the normal_im, * returns the bytes read if succeed, or -1 if there is any error */ -static gint _qq_normal_im_common_read(guint8 *data, guint8 **cursor, gint len, qq_recv_normal_im_common *common) +static gint _qq_normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) { gint bytes; g_return_val_if_fail(data != NULL && len != 0 && common != NULL, -1); bytes = 0; /* now push data into common header */ - bytes += read_packet_w(data, cursor, len, &(common->sender_ver)); - bytes += read_packet_dw(data, cursor, len, &(common->sender_uid)); - bytes += read_packet_dw(data, cursor, len, &(common->receiver_uid)); + bytes += qq_get16(&(common->sender_ver), data + bytes); + bytes += qq_get32(&(common->sender_uid), data + bytes); + bytes += qq_get32(&(common->receiver_uid), data + bytes); - common->session_md5 = g_memdup(*cursor, QQ_KEY_LENGTH); + common->session_md5 = g_memdup(data + bytes, QQ_KEY_LENGTH); bytes += QQ_KEY_LENGTH; - *cursor += QQ_KEY_LENGTH; - bytes += read_packet_w(data, cursor, len, &(common->normal_im_type)); + bytes += qq_get16(&(common->normal_im_type), data + bytes); if (bytes != 28) { /* read common place fail */ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Expect 28 bytes, read %d bytes\n", bytes); @@ -253,8 +252,7 @@ } /* process received normal text IM */ -static void _qq_process_recv_normal_im_text - (guint8 *data, guint8 **cursor, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) +static void _qq_process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) { guint16 purple_msg_type; gchar *name; @@ -262,50 +260,52 @@ gchar *msg_utf8_encoded; qq_data *qd; qq_recv_normal_im_text *im_text; + gint bytes = 0; g_return_if_fail(common != NULL); qd = (qq_data *) gc->proto_data; /* now it is QQ_NORMAL_IM_TEXT */ - if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); - return; - } else - im_text = g_newa(qq_recv_normal_im_text, 1); + /* + if (*cursor >= (data + len - 1)) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + return; + } else + */ + im_text = g_newa(qq_recv_normal_im_text, 1); im_text->common = common; /* push data into im_text */ - read_packet_w(data, cursor, len, &(im_text->msg_seq)); - read_packet_dw(data, cursor, len, &(im_text->send_time)); - read_packet_w(data, cursor, len, &(im_text->sender_icon)); - read_packet_data(data, cursor, len, (guint8 *) & (im_text->unknown2), 3); - read_packet_b(data, cursor, len, &(im_text->is_there_font_attr)); + bytes += qq_get16(&(im_text->msg_seq), data + bytes); + bytes += qq_get32(&(im_text->send_time), data + bytes); + bytes += qq_get16(&(im_text->sender_icon), data + bytes); + bytes += qq_getdata((guint8 *) & (im_text->unknown2), 3, data + bytes); + bytes += qq_get8(&(im_text->is_there_font_attr), data + bytes); /** * from lumaqq for unknown3 * totalFragments = buf.get() & 255; - * fragmentSequence = buf.get() & 255; - * messageId = buf.getChar(); + * fragmentSequence = buf.get() & 255; + * messageId = buf.getChar(); */ - read_packet_data(data, cursor, len, (guint8 *) & (im_text->unknown3), 4); - read_packet_b(data, cursor, len, &(im_text->msg_type)); + bytes += qq_getdata((guint8 *) & (im_text->unknown3), 4, data + bytes); + bytes += qq_get8(&(im_text->msg_type), data + bytes); /* we need to check if this is auto-reply * QQ2003iii build 0304, returns the msg without font_attr * even the is_there_font_attr shows 0x01, and msg does not ends with 0x00 */ if (im_text->msg_type == QQ_IM_AUTO_REPLY) { im_text->is_there_font_attr = 0x00; /* indeed there is no this flag */ - im_text->msg = g_strndup(*(gchar **) cursor, data + len - *cursor); + im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes); } else { /* it is normal mesasge */ if (im_text->is_there_font_attr) { - im_text->msg = g_strdup(*(gchar **) cursor); - *cursor += strlen(im_text->msg) + 1; - im_text->font_attr_len = data + len - *cursor; - im_text->font_attr = g_memdup(*cursor, im_text->font_attr_len); + im_text->msg = g_strdup((gchar *)(data + bytes)); + bytes += strlen(im_text->msg) + 1; /* length decided by strlen! will it cause a crash? */ + im_text->font_attr_len = len - bytes; + im_text->font_attr = g_memdup(data + bytes, im_text->font_attr_len); } else /* not im_text->is_there_font_attr */ - im_text->msg = g_strndup(*(gchar **) cursor, data + len - *cursor); + im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes); } /* if im_text->msg_type */ - _qq_show_packet("QQ_MESG recv", data, *cursor - data); name = uid_to_purple_name(common->sender_uid); if (purple_find_buddy(gc->account, name) == NULL) @@ -315,9 +315,9 @@ msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg); msg_utf8_encoded = im_text->is_there_font_attr ? - qq_encode_to_purple(im_text->font_attr, - im_text->font_attr_len, - msg_with_purple_smiley) : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); + qq_encode_to_purple(im_text->font_attr, + im_text->font_attr_len, + msg_with_purple_smiley) : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); /* send encoded to purple, note that we use im_text->send_time, * not the time we receive the message @@ -333,81 +333,68 @@ } /* it is a normal IM, maybe text or video request */ -static void _qq_process_recv_normal_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc) +static void _qq_process_recv_normal_im(guint8 *data, gint len, PurpleConnection *gc) { - gint bytes; + gint bytes = 0; qq_recv_normal_im_common *common; qq_recv_normal_im_unprocessed *im_unprocessed; - gchar *hex_dump; g_return_if_fail (data != NULL && len != 0); - if (*cursor >= (data + len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received normal IM is empty\n"); - return; - } - else - common = g_newa (qq_recv_normal_im_common, 1); + common = g_newa (qq_recv_normal_im_common, 1); - bytes = _qq_normal_im_common_read (data, cursor, len, common); + bytes = _qq_normal_im_common_read(data, len, common); if (bytes < 0) { purple_debug (PURPLE_DEBUG_ERROR, "QQ", - "Fail read the common part of normal IM\n"); + "Fail read the common part of normal IM\n"); return; } switch (common->normal_im_type) { - case QQ_NORMAL_IM_TEXT: - purple_debug (PURPLE_DEBUG_INFO, - "QQ", - "Normal IM, text type:\n [%d] => [%d], src: %s\n", - common->sender_uid, common->receiver_uid, - qq_get_source_str (common->sender_ver)); - _qq_process_recv_normal_im_text (data, cursor, len, common, - gc); - break; - case QQ_NORMAL_IM_FILE_REJECT_UDP: - qq_process_recv_file_reject (data, cursor, len, - common->sender_uid, gc); - break; - case QQ_NORMAL_IM_FILE_APPROVE_UDP: - qq_process_recv_file_accept (data, cursor, len, - common->sender_uid, gc); - break; - case QQ_NORMAL_IM_FILE_REQUEST_UDP: - qq_process_recv_file_request (data, cursor, len, - common->sender_uid, gc); - break; - case QQ_NORMAL_IM_FILE_CANCEL: - qq_process_recv_file_cancel (data, cursor, len, - common->sender_uid, gc); - break; - case QQ_NORMAL_IM_FILE_NOTIFY: - qq_process_recv_file_notify (data, cursor, len, - common->sender_uid, gc); - break; - default: - im_unprocessed = g_newa (qq_recv_normal_im_unprocessed, 1); - im_unprocessed->common = common; - im_unprocessed->unknown = *cursor; - im_unprocessed->length = data + len - *cursor; - /* a simple process here, maybe more later */ - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Normal IM, unprocessed type [0x%04x]\n", - common->normal_im_type); - hex_dump = hex_dump_to_str(im_unprocessed->unknown, im_unprocessed->length); - purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Dump unknown part.\n%s", hex_dump); - g_free(hex_dump); - g_free (common->session_md5); - return; + case QQ_NORMAL_IM_TEXT: + purple_debug (PURPLE_DEBUG_INFO, "QQ", + "Normal IM, text type:\n [%d] => [%d], src: %s\n", + common->sender_uid, common->receiver_uid, + qq_get_source_str (common->sender_ver)); + if (bytes >= len - 1) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + return; + } + _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc); + break; + case QQ_NORMAL_IM_FILE_REJECT_UDP: + qq_process_recv_file_reject(data + bytes, len - bytes, common->sender_uid, gc); + break; + case QQ_NORMAL_IM_FILE_APPROVE_UDP: + qq_process_recv_file_accept(data + bytes, len - bytes, common->sender_uid, gc); + break; + case QQ_NORMAL_IM_FILE_REQUEST_UDP: + qq_process_recv_file_request(data + bytes, len - bytes, common->sender_uid, gc); + break; + case QQ_NORMAL_IM_FILE_CANCEL: + qq_process_recv_file_cancel(data + bytes, len - bytes, common->sender_uid, gc); + break; + case QQ_NORMAL_IM_FILE_NOTIFY: + qq_process_recv_file_notify(data + bytes, len - bytes, common->sender_uid, gc); + break; + default: + im_unprocessed = g_newa (qq_recv_normal_im_unprocessed, 1); + im_unprocessed->common = common; + im_unprocessed->unknown = data + bytes; + im_unprocessed->length = len - bytes; + /* a simple process here, maybe more later */ + purple_debug (PURPLE_DEBUG_WARNING, "QQ", + "Normal IM, unprocessed type [0x%04x], unknown [0x%02x], len %d\n", + common->normal_im_type, im_unprocessed->unknown, im_unprocessed->length); + g_free (common->session_md5); + return; } g_free (common->session_md5); } /* process im from system administrator */ -static void _qq_process_recv_sys_im(guint8 *data, guint8 **cursor, gint data_len, PurpleConnection *gc) +static void _qq_process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc) { gint len; guint8 reply; @@ -415,14 +402,9 @@ g_return_if_fail(data != NULL && data_len != 0); - if (*cursor >= (data + data_len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received sys IM is empty\n"); - return; - } + len = data_len; - len = data + data_len - *cursor; - - if (NULL == (segments = split_data(*cursor, len, "\x2f", 2))) + if (NULL == (segments = split_data(data, len, "\x2f", 2))) return; reply = strtol(segments[0], NULL, 10); @@ -436,7 +418,7 @@ void qq_send_packet_im(PurpleConnection *gc, guint32 to_uid, gchar *msg, gint type) { qq_data *qd; - guint8 *cursor, *raw_data, *send_im_tail; + guint8 *raw_data, *send_im_tail; guint16 client_tag, normal_im_type; gint msg_len, raw_len, font_name_len, tail_len, bytes; time_t now; @@ -500,52 +482,51 @@ raw_len = QQ_SEND_IM_BEFORE_MSG_LEN + msg_len + tail_len; raw_data = g_newa(guint8, raw_len); - cursor = raw_data; bytes = 0; /* 000-003: receiver uid */ - bytes += create_packet_dw(raw_data, &cursor, qd->uid); + bytes += qq_put32(raw_data + bytes, qd->uid); /* 004-007: sender uid */ - bytes += create_packet_dw(raw_data, &cursor, to_uid); + bytes += qq_put32(raw_data + bytes, to_uid); /* 008-009: sender client version */ - bytes += create_packet_w(raw_data, &cursor, client_tag); + bytes += qq_put16(raw_data + bytes, client_tag); /* 010-013: receiver uid */ - bytes += create_packet_dw(raw_data, &cursor, qd->uid); + bytes += qq_put32(raw_data + bytes, qd->uid); /* 014-017: sender uid */ - bytes += create_packet_dw(raw_data, &cursor, to_uid); + bytes += qq_put32(raw_data + bytes, to_uid); /* 018-033: md5 of (uid+session_key) */ - bytes += create_packet_data(raw_data, &cursor, qd->session_md5, 16); + bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16); /* 034-035: message type */ - bytes += create_packet_w(raw_data, &cursor, normal_im_type); + bytes += qq_put16(raw_data + bytes, normal_im_type); /* 036-037: sequence number */ - bytes += create_packet_w(raw_data, &cursor, qd->send_seq); + bytes += qq_put16(raw_data + bytes, qd->send_seq); /* 038-041: send time */ - bytes += create_packet_dw(raw_data, &cursor, (guint32) now); + bytes += qq_put32(raw_data + bytes, (guint32) now); /* 042-043: sender icon */ - bytes += create_packet_w(raw_data, &cursor, qd->my_icon); + bytes += qq_put16(raw_data + bytes, qd->my_icon); /* 044-046: always 0x00 */ - bytes += create_packet_w(raw_data, &cursor, 0x0000); - bytes += create_packet_b(raw_data, &cursor, 0x00); + bytes += qq_put16(raw_data + bytes, 0x0000); + bytes += qq_put8(raw_data + bytes, 0x00); /* 047-047: we use font attr */ - bytes += create_packet_b(raw_data, &cursor, 0x01); + bytes += qq_put8(raw_data + bytes, 0x01); /* 048-051: always 0x00 */ - bytes += create_packet_dw(raw_data, &cursor, 0x00000000); + bytes += qq_put32(raw_data + bytes, 0x00000000); /* 052-052: text message type (normal/auto-reply) */ - bytes += create_packet_b(raw_data, &cursor, type); + bytes += qq_put8(raw_data + bytes, type); /* 053- : msg ends with 0x00 */ - bytes += create_packet_data(raw_data, &cursor, (guint8 *) msg_filtered, msg_len); + bytes += qq_putdata(raw_data + bytes, (guint8 *) msg_filtered, msg_len); send_im_tail = qq_get_send_im_tail(font_color, font_size, font_name, is_bold, - is_italic, is_underline, tail_len); - _qq_show_packet("QQ_MESG debug", send_im_tail, tail_len); - bytes += create_packet_data(raw_data, &cursor, send_im_tail, tail_len); + is_italic, is_underline, tail_len); + qq_show_packet("QQ_send_im_tail debug", send_im_tail, tail_len); + bytes += qq_putdata(raw_data + bytes, send_im_tail, tail_len); - _qq_show_packet("QQ_MESG raw", raw_data, cursor - raw_data); + qq_show_packet("QQ_raw_data debug", raw_data, bytes); if (bytes == raw_len) /* create packet OK */ - qq_send_cmd(gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, cursor - raw_data); + qq_send_cmd(qd, QQ_CMD_SEND_IM, raw_data, bytes); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail creating send_im packet, expect %d bytes, build %d bytes\n", raw_len, bytes); + "Fail creating send_im packet, expect %d bytes, build %d bytes\n", raw_len, bytes); if (font_color) g_free(font_color); @@ -560,7 +541,8 @@ { qq_data *qd; gint len; - guint8 *data, *cursor, reply; + guint8 *data, reply; + gint bytes = 0; g_return_if_fail(buf != NULL && buf_len != 0); @@ -569,8 +551,7 @@ data = g_newa(guint8, len); if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - cursor = data; - read_packet_b(data, &cursor, len, &reply); + bytes += qq_get8(&reply, data + bytes); if (reply != QQ_SEND_IM_REPLY_OK) { purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Send IM fail\n"); purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL); @@ -588,7 +569,7 @@ { qq_data *qd; gint len, bytes; - guint8 *data, *cursor; + guint8 *data; qq_recv_im_header *im_header; g_return_if_fail(buf != NULL && buf_len != 0); @@ -597,98 +578,107 @@ len = buf_len; data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - if (len < 16) { /* we need to ack with the first 16 bytes */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM is too short\n"); - return; - } else - _qq_send_packet_recv_im_ack(gc, seq, data); + if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rev im\n"); + } + + if (len < 16) { /* we need to ack with the first 16 bytes */ + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM is too short\n"); + return; + } else { + _qq_send_packet_recv_im_ack(gc, seq, data); + } + + /* check len first */ + if (len < 20) { /* length of im_header */ + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Fail read recv IM header, len should longer than 20 bytes, read %d bytes\n", len); + return; + } - cursor = data; - bytes = 0; - im_header = g_newa(qq_recv_im_header, 1); - bytes += read_packet_dw(data, &cursor, len, &(im_header->sender_uid)); - bytes += read_packet_dw(data, &cursor, len, &(im_header->receiver_uid)); - bytes += read_packet_dw(data, &cursor, len, &(im_header->server_im_seq)); - /* if the message is delivered via server, it is server IP/port */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) & (im_header->sender_ip), 4); - bytes += read_packet_w(data, &cursor, len, &(im_header->sender_port)); - bytes += read_packet_w(data, &cursor, len, &(im_header->im_type)); + bytes = 0; + im_header = g_newa(qq_recv_im_header, 1); + bytes += qq_get32(&(im_header->sender_uid), data + bytes); + bytes += qq_get32(&(im_header->receiver_uid), data + bytes); + bytes += qq_get32(&(im_header->server_im_seq), data + bytes); + /* if the message is delivered via server, it is server IP/port */ + bytes += qq_getdata((guint8 *) & (im_header->sender_ip), 4, data + bytes); + bytes += qq_get16(&(im_header->sender_port), data + bytes); + bytes += qq_get16(&(im_header->im_type), data + bytes); + /* im_header prepared */ - if (bytes != 20) { /* length of im_header */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail read recv IM header, expect 20 bytes, read %d bytes\n", bytes); - return; - } + if (im_header->receiver_uid != qd->uid) { /* should not happen */ + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM to [%d], NOT me\n", im_header->receiver_uid); + return; + } - if (im_header->receiver_uid != qd->uid) { /* should not happen */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM to [%d], NOT me\n", im_header->receiver_uid); - return; - } + /* check bytes */ + if (bytes >= len - 1) { + purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received IM is empty\n"); + return; + } - switch (im_header->im_type) { + switch (im_header->im_type) { case QQ_RECV_IM_TO_BUDDY: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am in his/her buddy list\n", im_header->sender_uid); - _qq_process_recv_normal_im(data, &cursor, len, gc); + "IM from buddy [%d], I am in his/her buddy list\n", im_header->sender_uid); + _qq_process_recv_normal_im(data + bytes, len - bytes, gc); /* position and rest length */ break; case QQ_RECV_IM_TO_UNKNOWN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); - _qq_process_recv_normal_im(data, &cursor, len, gc); + "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); + _qq_process_recv_normal_im(data + bytes, len - bytes, gc); break; case QQ_RECV_IM_UNKNOWN_QUN_IM: case QQ_RECV_IM_TEMP_QUN_IM: case QQ_RECV_IM_QUN_IM: purple_debug(PURPLE_DEBUG_INFO, "QQ", "IM from group, internal_id [%d]\n", im_header->sender_uid); /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im(data, &cursor, len, im_header->sender_uid, gc, im_header->im_type); + qq_process_recv_group_im(data + bytes, len - bytes, im_header->sender_uid, gc, im_header->im_type); break; case QQ_RECV_IM_ADD_TO_QUN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, added by group internal_id [%d]\n", im_header->sender_uid); + "IM from group, added by group internal_id [%d]\n", im_header->sender_uid); /* sender_uid is in fact internal_group_id * we need this to create a dummy group and add to blist */ - qq_process_recv_group_im_been_added(data, &cursor, len, im_header->sender_uid, gc); + qq_process_recv_group_im_been_added(data + bytes, len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_DEL_FROM_QUN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, removed by group internal_ID [%d]\n", im_header->sender_uid); + "IM from group, removed by group internal_ID [%d]\n", im_header->sender_uid); /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_removed(data, &cursor, len, im_header->sender_uid, gc); + qq_process_recv_group_im_been_removed(data + bytes, len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPLY_ADD_TO_QUN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, apply to join group internal_ID [%d]\n", im_header->sender_uid); + "IM from group, apply to join group internal_ID [%d]\n", im_header->sender_uid); /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_apply_join(data, &cursor, len, im_header->sender_uid, gc); + qq_process_recv_group_im_apply_join(data + bytes, len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, approved by group internal_id [%d]\n", - im_header->sender_uid); + "IM for group system info, approved by group internal_id [%d]\n", + im_header->sender_uid); /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_approved(data, &cursor, len, im_header->sender_uid, gc); + qq_process_recv_group_im_been_approved(data + bytes, len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, rejected by group internal_id [%d]\n", - im_header->sender_uid); + "IM for group system info, rejected by group internal_id [%d]\n", + im_header->sender_uid); /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_rejected(data, &cursor, len, im_header->sender_uid, gc); + qq_process_recv_group_im_been_rejected(data + bytes, len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_SYS_NOTIFICATION: purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from [%d], should be a system administrator\n", im_header->sender_uid); - _qq_process_recv_sys_im(data, &cursor, len, gc); + "IM from [%d], should be a system administrator\n", im_header->sender_uid); + _qq_process_recv_sys_im(data + bytes, len - bytes, gc); break; default: purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "IM from [%d], [0x%02x] %s is not processed\n", - im_header->sender_uid, - im_header->im_type, qq_get_recv_im_type_str(im_header->im_type)); - } - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rev im\n"); + "IM from [%d], [0x%02x] %s is not processed\n", + im_header->sender_uid, + im_header->im_type, qq_get_recv_im_type_str(im_header->im_type)); } } +
--- a/libpurple/protocols/qq/keep_alive.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/keep_alive.c Mon Jun 30 23:12:54 2008 +0000 @@ -40,7 +40,7 @@ #include "header_info.h" #include "keep_alive.h" #include "packet_parse.h" -#include "send_core.h" +#include "qq_network.h" #include "utils.h" #define QQ_UPDATE_ONLINE_INTERVAL 300 /* in sec */ @@ -49,18 +49,17 @@ void qq_send_packet_keep_alive(PurpleConnection *gc) { qq_data *qd; - guint8 *raw_data, *cursor; + guint8 raw_data[16] = {0}; + gint bytes= 0; qd = (qq_data *) gc->proto_data; - raw_data = g_newa(guint8, 4); - cursor = raw_data; /* In fact, we can send whatever we like to server * with this command, server return the same result including * the amount of online QQ users, my ip and port */ - create_packet_dw(raw_data, &cursor, qd->uid); + bytes += qq_put32(raw_data + bytes, qd->uid); - qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, TRUE, 0, TRUE, raw_data, 4); + qq_send_cmd(qd, QQ_CMD_KEEP_ALIVE, raw_data, 4); } /* parse the return of keep-alive packet, it includes some system information */
--- a/libpurple/protocols/qq/login_logout.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/login_logout.c Mon Jun 30 23:12:54 2008 +0000 @@ -25,6 +25,7 @@ #include "debug.h" #include "internal.h" #include "server.h" +#include "cipher.h" #include "buddy_info.h" #include "buddy_list.h" @@ -36,8 +37,7 @@ #include "login_logout.h" #include "packet_parse.h" #include "qq.h" -#include "qq_proxy.h" -#include "send_core.h" +#include "qq_network.h" #include "utils.h" #define QQ_LOGIN_DATA_LENGTH 416 @@ -70,32 +70,36 @@ */ /* for QQ 2005? copy from lumaqq */ -static const gint8 login_23_51[29] = { - 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, - -52, 76, 53, 44, -45, 115, 108, 20, -10, -10, - -81, -61, -6, 51, -92, 1 +/* FIXME: change to guint8 */ +static const guint8 login_23_51[29] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x86, 0xcc, 0x4c, 0x35, + 0x2c, 0xd3, 0x73, 0x6c, 0x14, 0xf6, 0xf6, 0xaf, + 0xc3, 0xfa, 0x33, 0xa4, 0x01 }; -static const gint8 login_53_68[16] = { - -115, -117, -6, -20, -43, 82, 23, 74, -122, -7, - -89, 117, -26, 50, -47, 109 +static const guint8 login_53_68[16] = { + 0x8D, 0x8B, 0xFA, 0xEC, 0xD5, 0x52, 0x17, 0x4A, + 0x86, 0xF9, 0xA7, 0x75, 0xE6, 0x32, 0xD1, 0x6D }; -static const gint8 login_100_bytes[100] = { - 64, - 11, 4, 2, 0, 1, 0, 0, 0, 0, 0, - 3, 9, 0, 0, 0, 0, 0, 0, 0, 1, - -23, 3, 1, 0, 0, 0, 0, 0, 1, -13, - 3, 0, 0, 0, 0, 0, 0, 1, -19, 3, - 0, 0, 0, 0, 0, 0, 1, -20, 3, 0, - 0, 0, 0, 0, 0, 3, 5, 0, 0, 0, - 0, 0, 0, 0, 3, 7, 0, 0, 0, 0, - 0, 0, 0, 1, -18, 3, 0, 0, 0, 0, - 0, 0, 1, -17, 3, 0, 0, 0, 0, 0, - 0, 1, -21, 3, 0, 0, 0, 0, 0 +static const guint8 login_100_bytes[100] = { + 0x40, 0x0B, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xE9, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xEC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xEE, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xEF, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + /* fixed value, not affected by version, or mac address */ /* static const guint8 login_53_68[16] = { @@ -138,74 +142,80 @@ guint16 new_server_port; }; -extern gint /* defined in send_core.c */ - _create_packet_head_seq(guint8 *buf, - guint8 **cursor, PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 *seq); -extern gint /* defined in send_core.c */ - _qq_send_packet(PurpleConnection *gc, guint8 *buf, gint len, guint16 cmd); +/* generate a md5 key using uid and session_key */ +static guint8 *gen_session_md5(gint uid, guint8 *session_key) +{ + guint8 *src, md5_str[QQ_KEY_LENGTH]; + PurpleCipher *cipher; + PurpleCipherContext *context; -/* It is fixed to 16 bytes 0x01 for QQ2003, - * Any value works (or a random 16 bytes string) */ -static guint8 *_gen_login_key(void) -{ - return (guint8 *) g_strnfill(QQ_KEY_LENGTH, 0x01); + src = g_newa(guint8, 20); + /* bug found by QuLogic */ + memcpy(src, &uid, sizeof(uid)); + memcpy(src + sizeof(uid), session_key, QQ_KEY_LENGTH); + + cipher = purple_ciphers_find_cipher("md5"); + context = purple_cipher_context_new(cipher, NULL); + purple_cipher_context_append(context, src, 20); + purple_cipher_context_digest(context, sizeof(md5_str), md5_str, NULL); + purple_cipher_context_destroy(context); + + return g_memdup(md5_str, QQ_KEY_LENGTH); } /* process login reply which says OK */ static gint _qq_process_login_ok(PurpleConnection *gc, guint8 *data, gint len) { gint bytes; - guint8 *cursor; qq_data *qd; qq_login_reply_ok_packet lrop; qd = (qq_data *) gc->proto_data; - cursor = data; + /* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */ bytes = 0; /* 000-000: reply code */ - bytes += read_packet_b(data, &cursor, len, &lrop.result); + bytes += qq_get8(&lrop.result, data + bytes); /* 001-016: session key */ - lrop.session_key = g_memdup(cursor, QQ_KEY_LENGTH); - cursor += QQ_KEY_LENGTH; + lrop.session_key = g_memdup(data + bytes, QQ_KEY_LENGTH); bytes += QQ_KEY_LENGTH; purple_debug(PURPLE_DEBUG_INFO, "QQ", "Get session_key done\n"); /* 017-020: login uid */ - bytes += read_packet_dw(data, &cursor, len, &lrop.uid); + bytes += qq_get32(&lrop.uid, data + bytes); /* 021-024: server detected user public IP */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.client_ip, 4); + bytes += qq_getdata((guint8 *) &lrop.client_ip, 4, data + bytes); /* 025-026: server detected user port */ - bytes += read_packet_w(data, &cursor, len, &lrop.client_port); + bytes += qq_get16(&lrop.client_port, data + bytes); /* 027-030: server detected itself ip 127.0.0.1 ? */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.server_ip, 4); + bytes += qq_getdata((guint8 *) &lrop.server_ip, 4, data + bytes); /* 031-032: server listening port */ - bytes += read_packet_w(data, &cursor, len, &lrop.server_port); + bytes += qq_get16(&lrop.server_port, data + bytes); /* 033-036: login time for current session */ - bytes += read_packet_time(data, &cursor, len, &lrop.login_time); + bytes += qq_getime(&lrop.login_time, data + bytes); /* 037-062: 26 bytes, unknown */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown1, 26); + bytes += qq_getdata((guint8 *) &lrop.unknown1, 26, data + bytes); /* 063-066: unknown server1 ip address */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown_server1_ip, 4); + bytes += qq_getdata((guint8 *) &lrop.unknown_server1_ip, 4, data + bytes); /* 067-068: unknown server1 port */ - bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server1_port); + bytes += qq_get16(&lrop.unknown_server1_port, data + bytes); /* 069-072: unknown server2 ip address */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown_server2_ip, 4); + bytes += qq_getdata((guint8 *) &lrop.unknown_server2_ip, 4, data + bytes); /* 073-074: unknown server2 port */ - bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server2_port); + bytes += qq_get16(&lrop.unknown_server2_port, data + bytes); /* 075-076: 2 bytes unknown */ - bytes += read_packet_w(data, &cursor, len, &lrop.unknown2); + bytes += qq_get16(&lrop.unknown2, data + bytes); /* 077-078: 2 bytes unknown */ - bytes += read_packet_w(data, &cursor, len, &lrop.unknown3); + bytes += qq_get16(&lrop.unknown3, data + bytes); /* 079-110: 32 bytes unknown */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown4, 32); + bytes += qq_getdata((guint8 *) &lrop.unknown4, 32, data + bytes); /* 111-122: 12 bytes unknown */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown5, 12); + bytes += qq_getdata((guint8 *) &lrop.unknown5, 12, data + bytes); /* 123-126: login IP of last session */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.last_client_ip, 4); + bytes += qq_getdata((guint8 *) &lrop.last_client_ip, 4, data + bytes); /* 127-130: login time of last session */ - bytes += read_packet_time(data, &cursor, len, &lrop.last_login_time); + bytes += qq_getime(&lrop.last_login_time, data + bytes); /* 131-138: 8 bytes unknown */ - bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown6, 8); + bytes += qq_getdata((guint8 *) &lrop.unknown6, 8, data + bytes); if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ purple_debug(PURPLE_DEBUG_WARNING, "QQ", @@ -213,9 +223,15 @@ QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes); } /* but we still go on as login OK */ + g_return_val_if_fail(qd->session_key == NULL, QQ_LOGIN_REPLY_MISC_ERROR); qd->session_key = lrop.session_key; - qd->session_md5 = _gen_session_md5(qd->uid, qd->session_key); + + g_return_val_if_fail(qd->session_md5 == NULL, QQ_LOGIN_REPLY_MISC_ERROR); + qd->session_md5 = gen_session_md5(qd->uid, qd->session_key); + + g_return_val_if_fail(qd->my_ip == NULL, QQ_LOGIN_REPLY_MISC_ERROR); qd->my_ip = gen_ip_str(lrop.client_ip); + qd->my_port = lrop.client_port; qd->login_time = lrop.login_time; qd->last_login_time = lrop.last_login_time; @@ -247,34 +263,40 @@ static gint _qq_process_login_redirect(PurpleConnection *gc, guint8 *data, gint len) { gint bytes, ret; - guint8 *cursor; - gchar *new_server_str; qq_data *qd; qq_login_reply_redirect_packet lrrp; qd = (qq_data *) gc->proto_data; - cursor = data; bytes = 0; /* 000-000: reply code */ - bytes += read_packet_b(data, &cursor, len, &lrrp.result); + bytes += qq_get8(&lrrp.result, data + bytes); /* 001-004: login uid */ - bytes += read_packet_dw(data, &cursor, len, &lrrp.uid); + bytes += qq_get32(&lrrp.uid, data + bytes); /* 005-008: redirected new server IP */ - bytes += read_packet_data(data, &cursor, len, lrrp.new_server_ip, 4); + bytes += qq_getdata(lrrp.new_server_ip, 4, data + bytes); /* 009-010: redirected new server port */ - bytes += read_packet_w(data, &cursor, len, &lrrp.new_server_port); + bytes += qq_get16(&lrrp.new_server_port, data + bytes); if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail parsing login redirect packet, expect %d bytes, read %d bytes\n", QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes); ret = QQ_LOGIN_REPLY_MISC_ERROR; - } else { /* start new connection */ - new_server_str = gen_ip_str(lrrp.new_server_ip); + } else { + /* redirect to new server, do not disconnect or connect here + * those connect should be called at packet_process */ + if (qd->real_hostname) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); + g_free(qd->real_hostname); + qd->real_hostname = NULL; + } + qd->real_hostname = gen_ip_str(lrrp.new_server_ip); + qd->real_port = lrrp.new_server_port; + qd->is_redirect = TRUE; + purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Redirected to new server: %s:%d\n", new_server_str, lrrp.new_server_port); - qq_connect(gc->account, new_server_str, lrrp.new_server_port, qd->use_tcp, TRUE); - g_free(new_server_str); + "Redirected to new server: %s:%d\n", qd->real_hostname, qd->real_port); + ret = QQ_LOGIN_REPLY_REDIRECT; } @@ -299,89 +321,78 @@ void qq_send_packet_request_login_token(PurpleConnection *gc) { qq_data *qd; - guint8 *buf, *cursor; - guint16 seq_ret; - gint bytes; - - qd = (qq_data *) gc->proto_data; - buf = g_newa(guint8, MAX_PACKET_SIZE); + guint8 buf[16] = {0}; + gint bytes = 0; - cursor = buf; - bytes = 0; - bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_REQUEST_LOGIN_TOKEN, TRUE, &seq_ret); - bytes += create_packet_dw(buf, &cursor, qd->uid); - bytes += create_packet_b(buf, &cursor, 0); - bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; - if (bytes == (cursor - buf)) /* packet creation OK */ - _qq_send_packet(gc, buf, bytes, QQ_CMD_REQUEST_LOGIN_TOKEN); - else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create request login token packet\n"); + bytes += qq_put8(buf + bytes, 0); + + qq_send_data(qd, QQ_CMD_REQUEST_LOGIN_TOKEN, buf, bytes); } /* send login packet to QQ server */ static void qq_send_packet_login(PurpleConnection *gc, guint8 token_length, guint8 *token) { qq_data *qd; - guint8 *buf, *cursor, *raw_data, *encrypted_data; - guint16 seq_ret; - gint encrypted_len, bytes; - gint pos; + guint8 *buf, *raw_data; + gint bytes; + guint8 *encrypted_data; + gint encrypted_len; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - buf = g_newa(guint8, MAX_PACKET_SIZE); + raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); + memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); + encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ - qd->inikey = _gen_login_key(); + if (qd->inikey) { + g_free(qd->inikey); + } + qd->inikey = (guint8 *) g_strnfill(QQ_KEY_LENGTH, 0x01); + bytes = 0; /* now generate the encrypted data * 000-015 use pwkey as key to encrypt empty string */ - qq_encrypt((guint8 *) "", 0, qd->pwkey, raw_data, &encrypted_len); + qq_encrypt((guint8 *) "", 0, qd->pwkey, raw_data + bytes, &encrypted_len); + bytes += 16; /* 016-016 */ - raw_data[16] = 0x00; + bytes += qq_put8(raw_data + bytes, 0x00); /* 017-020, used to be IP, now zero */ - *((guint32 *) (raw_data + 17)) = 0x00000000; + bytes += qq_put32(raw_data + bytes, 0x00000000); /* 021-022, used to be port, now zero */ - *((guint16 *) (raw_data + 21)) = 0x0000; + bytes += qq_put16(raw_data + bytes, 0x0000); /* 023-051, fixed value, unknown */ - g_memmove(raw_data + 23, login_23_51, 29); + bytes += qq_putdata(raw_data + bytes, login_23_51, 29); /* 052-052, login mode */ - raw_data[52] = qd->login_mode; + bytes += qq_put8(raw_data + bytes, qd->login_mode); /* 053-068, fixed value, maybe related to per machine */ - g_memmove(raw_data + 53, login_53_68, 16); - + bytes += qq_putdata(raw_data + bytes, login_53_68, 16); /* 069, login token length */ - raw_data[69] = token_length; - pos = 70; + bytes += qq_put8(raw_data + bytes, token_length); /* 070-093, login token, normally 24 bytes */ - g_memmove(raw_data + pos, token, token_length); - pos += token_length; + bytes += qq_putdata(raw_data + bytes, token, token_length); /* 100 bytes unknown */ - g_memmove(raw_data + pos, login_100_bytes, 100); - pos += 100; + bytes += qq_putdata(raw_data + bytes, login_100_bytes, 100); /* all zero left */ - memset(raw_data+pos, 0, QQ_LOGIN_DATA_LENGTH - pos); qq_encrypt(raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len); - cursor = buf; + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_LOGIN, TRUE, &seq_ret); - bytes += create_packet_dw(buf, &cursor, qd->uid); - bytes += create_packet_data(buf, &cursor, qd->inikey, QQ_KEY_LENGTH); - bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len); - bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); + bytes += qq_putdata(buf + bytes, qd->inikey, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); - if (bytes == (cursor - buf)) /* packet creation OK */ - _qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN); - else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n"); + qq_send_data(qd, QQ_CMD_LOGIN, buf, bytes); } void qq_process_request_login_token_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) { qq_data *qd; - gchar *hex_dump; + gchar *error_msg; g_return_if_fail(buf != NULL && buf_len != 0); @@ -394,20 +405,24 @@ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Attempting to proceed with the actual packet length.\n"); } - hex_dump = hex_dump_to_str(buf+2, buf_len-2); - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<<< got a token with %d bytes -> [default] decrypt and dump\n%s", buf_len-2, hex_dump); + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", + buf+2, buf_len-2, + "<<< got a token -> [default] decrypt and dump"); qq_send_packet_login(gc, buf_len-2, buf+2); } else { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown request login token reply code : %d\n", buf[0]); - hex_dump = hex_dump_to_str(buf, buf_len); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - ">>> %d bytes -> [default] decrypt and dump\n%s", - buf_len, hex_dump); - try_dump_as_gbk(buf, buf_len); - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Error requesting login token")); + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + buf, buf_len, + ">>> [default] decrypt and dump"); + error_msg = try_dump_as_gbk(buf, buf_len); + if (error_msg) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); + } else { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Error requesting login token")); + } } - g_free(hex_dump); } /* send logout packets to QQ server */ @@ -418,7 +433,7 @@ qd = (qq_data *) gc->proto_data; for (i = 0; i < 4; i++) - qq_send_cmd(gc, QQ_CMD_LOGOUT, FALSE, 0xffff, FALSE, qd->pwkey, QQ_KEY_LENGTH); + qq_send_cmd_detail(qd, QQ_CMD_LOGOUT, 0xffff, FALSE, qd->pwkey, QQ_KEY_LENGTH); qd->logged_in = FALSE; /* update login status AFTER sending logout packets */ } @@ -429,7 +444,7 @@ gint len, ret, bytes; guint8 *data; qq_data *qd; - gchar *hex_dump; + gchar* error_msg; g_return_if_fail(buf != NULL && buf_len != 0); @@ -462,13 +477,14 @@ break; default: purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown reply code: %d\n", data[0]); - hex_dump = hex_dump_to_str(data, len); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - ">>> %d bytes -> [default] decrypt and dump\n%s", - buf_len, hex_dump); - g_free(hex_dump); - try_dump_as_gbk(data, len); - + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + data, len, + ">>> [default] decrypt and dump"); + error_msg = try_dump_as_gbk(data, len); + if (error_msg) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); + } ret = QQ_LOGIN_REPLY_MISC_ERROR; } } else { /* no idea how to decrypt */
--- a/libpurple/protocols/qq/packet_parse.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Mon Jun 30 23:12:54 2008 +0000 @@ -25,119 +25,147 @@ #include <string.h> #include "packet_parse.h" +#include "debug.h" + + +/*------------------------------------------------PUT------------------------------------------------*/ + +/* note: + * 1, in these functions, 'b' stands for byte, 'w' stands for word, 'dw' stands for double word. + * 2, we use '*cursor' and 'buf' as two addresses to calculate the length. + * 3, change '0' to '1', if want to get more info about the packet parsing. */ + +#if 0 +#define PARSER_DEBUG +#endif /* read one byte from buf, * return the number of bytes read if succeeds, otherwise return -1 */ -gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b) +gint qq_get8(guint8 *b, guint8 *buf) { - if (*cursor <= buf + buflen - sizeof(*b)) { - *b = **(guint8 **) cursor; - *cursor += sizeof(*b); - return sizeof(*b); - } else { - return -1; - } + guint8 b_dest; + memcpy(&b_dest, buf, sizeof(b_dest)); + *b = b_dest; +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b); +#endif + return sizeof(b_dest); } + /* read two bytes as "guint16" from buf, * return the number of bytes read if succeeds, otherwise return -1 */ -gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w) +gint qq_get16(guint16 *w, guint8 *buf) { - if (*cursor <= buf + buflen - sizeof(*w)) { - *w = g_ntohs(**(guint16 **) cursor); - *cursor += sizeof(*w); - return sizeof(*w); - } else { - return -1; - } + guint16 w_dest; + memcpy(&w_dest, buf, sizeof(w_dest)); + *w = g_ntohs(w_dest); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w); +#endif + return sizeof(w_dest); } + /* read four bytes as "guint32" from buf, * return the number of bytes read if succeeds, otherwise return -1 */ -gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw) +gint qq_get32(guint32 *dw, guint8 *buf) { - if (*cursor <= buf + buflen - sizeof(*dw)) { - *dw = g_ntohl(**(guint32 **) cursor); - *cursor += sizeof(*dw); - return sizeof(*dw); - } else { - return -1; - } + guint32 dw_dest; + memcpy(&dw_dest, buf, sizeof(dw_dest)); + *dw = g_ntohl(dw_dest); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw); +#endif + return sizeof(dw_dest); } + +/* read datalen bytes from buf, + * return the number of bytes read if succeeds, otherwise return -1 */ +gint qq_getdata(guint8 *data, gint datalen, guint8 *buf) +{ + memcpy(data, buf, datalen); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getdata] buf %p\n", (void *)buf); +#endif + return datalen; +} + + /* read four bytes as "time_t" from buf, * return the number of bytes read if succeeds, otherwise return -1 * This function is a wrapper around read_packet_dw() to avoid casting. */ -gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t) +gint qq_getime(time_t *t, guint8 *buf) { - guint32 time; - gint ret = read_packet_dw(buf, cursor, buflen, &time); - if (ret != -1 ) { - *t = time; - } - return ret; + guint32 dw_dest; + memcpy(&dw_dest, buf, sizeof(dw_dest)); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest); +#endif + dw_dest = g_ntohl(dw_dest); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest); +#endif + memcpy(t, &dw_dest, sizeof(dw_dest)); + return sizeof(dw_dest); } -/* read datalen bytes from buf, - * return the number of bytes read if succeeds, otherwise return -1 */ -gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen) { - if (*cursor <= buf + buflen - datalen) { - g_memmove(data, *cursor, datalen); - *cursor += datalen; - return datalen; - } else { - return -1; - } +/*------------------------------------------------PUT------------------------------------------------*/ +/* pack one byte into buf + * return the number of bytes packed, otherwise return -1 */ +gint qq_put8(guint8 *buf, guint8 b) +{ + memcpy(buf, &b, sizeof(b)); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] b 0x%02x\n", b); +#endif + return sizeof(b); } -/* pack one byte into buf - * return the number of bytes packed, otherwise return -1 */ -gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b) -{ - if (*cursor <= buf + MAX_PACKET_SIZE - sizeof(guint8)) { - **(guint8 **) cursor = b; - *cursor += sizeof(guint8); - return sizeof(guint8); - } else { - return -1; - } -} /* pack two bytes as "guint16" into buf * return the number of bytes packed, otherwise return -1 */ -gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w) +gint qq_put16(guint8 *buf, guint16 w) { - if (*cursor <= buf + MAX_PACKET_SIZE - sizeof(guint16)) { - **(guint16 **) cursor = g_htons(w); - *cursor += sizeof(guint16); - return sizeof(guint16); - } else { - return -1; - } + guint16 w_porter; + w_porter = g_htons(w); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter); +#endif + memcpy(buf, &w_porter, sizeof(w_porter)); + return sizeof(w_porter); } + /* pack four bytes as "guint32" into buf * return the number of bytes packed, otherwise return -1 */ -gint create_packet_dw(guint8 *buf, guint8 **cursor, guint32 dw) +gint qq_put32(guint8 *buf, guint32 dw) { - if (*cursor <= buf + MAX_PACKET_SIZE - sizeof(guint32)) { - **(guint32 **) cursor = g_htonl(dw); - *cursor += sizeof(guint32); - return sizeof(guint32); - } else { - return -1; - } + guint32 dw_porter; + dw_porter = g_htonl(dw); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] buf %p\n", (void *)buf); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter); +#endif + memcpy(buf, &dw_porter, sizeof(dw_porter)); + return sizeof(dw_porter); } + /* pack datalen bytes into buf * return the number of bytes packed, otherwise return -1 */ -gint create_packet_data(guint8 *buf, guint8 **cursor, guint8 *data, gint datalen) +gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen) { - if (*cursor <= buf + MAX_PACKET_SIZE - datalen) { - g_memmove(*cursor, data, datalen); - *cursor += datalen; - return datalen; - } else { - return -1; - } + memcpy(buf, data, datalen); +#ifdef PARSER_DEBUG + purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][putdata] buf %p\n", (void *)buf); +#endif + return datalen; }
--- a/libpurple/protocols/qq/packet_parse.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.h Mon Jun 30 23:12:54 2008 +0000 @@ -37,14 +37,28 @@ */ #define MAX_PACKET_SIZE 65535 +gint qq_get8(guint8 *b, guint8 *buf); +gint qq_get16(guint16 *w, guint8 *buf); +gint qq_get32(guint32 *dw, guint8 *buf); +gint qq_getime(time_t *t, guint8 *buf); +gint qq_getdata(guint8 *data, gint datalen, guint8 *buf); + +gint qq_put8(guint8 *buf, guint8 b); +gint qq_put16(guint8 *buf, guint16 w); +gint qq_put32(guint8 *buf, guint32 dw); +gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen); + +/* gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b); gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w); gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw); gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t); gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen); + gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b); gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w); gint create_packet_dw(guint8 *buf, guint8 **cursor, guint32 dw); gint create_packet_data(guint8 *buf, guint8 **cursor, guint8 *data, gint datalen); +*/ #endif
--- a/libpurple/protocols/qq/qq.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Mon Jun 30 23:12:54 2008 +0000 @@ -55,48 +55,94 @@ #include "login_logout.h" #include "packet_parse.h" #include "qq.h" -#include "qq_proxy.h" -#include "send_core.h" +#include "qq_network.h" #include "send_file.h" #include "utils.h" #include "version.h" #define OPENQ_AUTHOR "Puzzlebird" #define OPENQ_WEBSITE "http://openq.sourceforge.net" -#define QQ_TCP_QUERY_PORT "8000" -#define QQ_UDP_PORT "8000" + +#define QQ_TCP_PORT 8000 +#define QQ_UDP_PORT 8000 + +static void server_list_create(PurpleAccount *account) { + PurpleConnection *gc; + qq_data *qd; + const gchar *user_server; + int port; + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create server list\n"); + gc = purple_account_get_connection(account); + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = gc->proto_data; -const gchar *udp_server_list[] = { - "sz.tencent.com", - "sz2.tencent.com", - "sz3.tencent.com", - "sz4.tencent.com", - "sz5.tencent.com", - "sz6.tencent.com", - "sz7.tencent.com", - "sz8.tencent.com", - "sz9.tencent.com" -}; -const gint udp_server_amount = (sizeof(udp_server_list) / sizeof(udp_server_list[0])); + qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE); + port = purple_account_get_int(account, "port", 0); + if (port == 0) { + if (qd->use_tcp) { + port = QQ_TCP_PORT; + } else { + port = QQ_UDP_PORT; + } + } + qd->user_port = port; + g_return_if_fail(qd->user_server == NULL); + user_server = purple_account_get_string(account, "server", NULL); + if (user_server != NULL && strlen(user_server) > 0) { + qd->user_server = g_strdup(user_server); + } -const gchar *tcp_server_list[] = { - "tcpconn.tencent.com", - "tcpconn2.tencent.com", - "tcpconn3.tencent.com", - "tcpconn4.tencent.com", - "tcpconn5.tencent.com", - "tcpconn6.tencent.com" -}; -const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0])); + if (qd->user_server != NULL) { + qd->servers = g_list_append(qd->servers, qd->user_server); + return; + } + if (qd->use_tcp) { + qd->servers = g_list_append(qd->servers, "tcpconn.tencent.com"); + qd->servers = g_list_append(qd->servers, "tcpconn2.tencent.com"); + qd->servers = g_list_append(qd->servers, "tcpconn3.tencent.com"); + qd->servers = g_list_append(qd->servers, "tcpconn4.tencent.com"); + qd->servers = g_list_append(qd->servers, "tcpconn5.tencent.com"); + qd->servers = g_list_append(qd->servers, "tcpconn6.tencent.com"); + return; + } + + qd->servers = g_list_append(qd->servers, "sz.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz2.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz3.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz4.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz5.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz6.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz7.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz8.tencent.com"); + qd->servers = g_list_append(qd->servers, "sz9.tencent.com"); +} -static void _qq_login(PurpleAccount *account) +static void server_list_remove_all(qq_data *qd) { + g_return_if_fail(qd != NULL); + + if (qd->real_hostname) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); + g_free(qd->real_hostname); + qd->real_hostname = NULL; + } + + if (qd->user_server != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free user_server\n"); + g_free(qd->user_server); + qd->user_server = NULL; + } + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free server list\n"); + g_list_free(qd->servers); +} + +static void qq_login(PurpleAccount *account) { - const gchar *qq_server, *qq_port; + PurpleConnection *gc; qq_data *qd; - PurpleConnection *gc; PurplePresence *presence; - gboolean use_tcp; g_return_if_fail(account != NULL); @@ -109,13 +155,7 @@ qd->gc = gc; gc->proto_data = qd; - qq_server = purple_account_get_string(account, "server", NULL); - qq_port = purple_account_get_string(account, "port", NULL); - use_tcp = purple_account_get_bool(account, "use_tcp", FALSE); presence = purple_account_get_presence(account); - - qd->use_tcp = use_tcp; - if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { qd->login_mode = QQ_LOGIN_MODE_HIDDEN; } else if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY) @@ -125,26 +165,28 @@ qd->login_mode = QQ_LOGIN_MODE_NORMAL; } - if (qq_server == NULL || strlen(qq_server) == 0) - qq_server = use_tcp ? - tcp_server_list[random() % tcp_server_amount] : - udp_server_list[random() % udp_server_amount]; + server_list_create(account); + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Server list has %d\n", g_list_length(qd->servers)); - if (qq_port == NULL || strtol(qq_port, NULL, 10) == 0) - qq_port = use_tcp ? QQ_TCP_QUERY_PORT : QQ_UDP_PORT; - - purple_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS); - - if (qq_connect(account, qq_server, strtol(qq_port, NULL, 10), use_tcp, FALSE) < 0) - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to connect.")); + qq_connect(account); } -/* directly goes for qq_disconnect */ -static void _qq_close(PurpleConnection *gc) +/* clean up the given QQ connection and free all resources */ +static void qq_close(PurpleConnection *gc) { - g_return_if_fail(gc != NULL); + qq_data *qd; + + g_return_if_fail(gc != NULL && gc->proto_data); + qd = gc->proto_data; + qq_disconnect(gc); + + server_list_remove_all(qd); + + g_free(qd); + + gc->proto_data = NULL; } /* returns the icon name for a buddy or protocol */ @@ -442,8 +484,9 @@ g_string_append(info, "<hr>\n"); + g_string_append_printf(info, _("<b>Server</b>: %s: %d<br>\n"), qd->server_name, qd->real_port); g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP"); - g_string_append_printf(info, _("<b>Server IP</b>: %s: %d<br>\n"), qd->server_ip, qd->server_port); + g_string_append_printf(info, _("<b>Real hostname</b>: %s: %d<br>\n"), qd->real_hostname, qd->real_port); g_string_append_printf(info, _("<b>My Public IP</b>: %s<br>\n"), qd->my_ip); g_string_append(info, "<hr>\n"); @@ -594,7 +637,7 @@ } -static void _qq_keep_alive(PurpleConnection *gc) +static void qq_keep_alive(PurpleConnection *gc) { qq_group *group; qq_data *qd; @@ -651,8 +694,8 @@ _qq_buddy_menu, /* blist_node_menu */ qq_chat_info, /* chat_info */ qq_chat_info_defaults, /* chat_info_defaults */ - _qq_login, /* login */ - _qq_close, /* close */ + qq_login, /* open */ + qq_close, /* close */ _qq_send_im, /* send_im */ NULL, /* set_info */ NULL, /* send_typing */ @@ -676,7 +719,7 @@ NULL, /* chat_leave */ NULL, /* chat_whisper */ _qq_chat_send, /* chat_send */ - _qq_keep_alive, /* keepalive */ + qq_keep_alive, /* keepalive */ NULL, /* register_user */ _qq_get_chat_buddy_info, /* get_cb_info */ NULL, /* get_cb_away */ @@ -751,13 +794,13 @@ { PurpleAccountOption *option; - option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", FALSE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new(_("Server"), "server", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new(_("Port"), "port", NULL); + option = purple_account_option_int_new(_("Port"), "port", 0); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); my_protocol = plugin;
--- a/libpurple/protocols/qq/qq.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Mon Jun 30 23:12:54 2008 +0000 @@ -28,6 +28,9 @@ #include <glib.h> #include "internal.h" #include "ft.h" +#include "circbuffer.h" +#include "dnsquery.h" +#include "dnssrv.h" #include "proxy.h" #include "roomlist.h" @@ -66,7 +69,39 @@ }; struct _qq_data { - gint fd; /* socket file handler */ + PurpleConnection *gc; + + /* common network resource */ + GList *servers; + gchar *user_server; + gint user_port; + gboolean use_tcp; /* network in tcp or udp */ + + gchar *server_name; + gboolean is_redirect; + gchar *real_hostname; /* from real connction */ + guint16 real_port; + guint reconnect_timeout; + gint reconnect_times; + + PurpleProxyConnectData *connect_data; + gint fd; /* socket file handler */ + gint tx_handler; /* socket can_write handle, use in udp connecting and tcp send out */ + + GList *send_trans; /* check ack packet and resend */ + guint resend_timeout; + + guint8 rcv_window[1 << 13]; /* windows for check duplicate packet */ + GQueue *rcv_trans; /* queue to store packet can not process before login */ + + /* tcp related */ + PurpleCircBuffer *tcp_txbuf; + guint8 *tcp_rxqueue; + int tcp_rxlen; + + /* udp related */ + PurpleDnsQueryData *udp_query_data; + guint32 uid; /* QQ number */ guint8 *inikey; /* initial key to encrypt login packet */ guint8 *pwkey; /* password in md5 (or md5' md5) */ @@ -76,17 +111,9 @@ guint16 send_seq; /* send sequence number */ guint8 login_mode; /* online of invisible */ gboolean logged_in; /* used by qq-add_buddy */ - gboolean use_tcp; /* network in tcp or udp */ - - PurpleProxyType proxy_type; - PurpleConnection *gc; PurpleXfer *xfer; /* file transfer handler */ - struct sockaddr_in dest_sin; - /* from real connction */ - gchar *server_ip; - guint16 server_port; /* get from login reply packet */ time_t login_time; time_t last_login_time; @@ -99,9 +126,6 @@ guint32 all_online; /* the number of online QQ users */ time_t last_get_online; /* last time send get_friends_online packet */ - guint8 window[1 << 13]; /* check up for duplicated packet */ - gint sendqueue_timeout; - PurpleRoomlist *roomlist; gint channel; /* the id for opened chat conversation */ @@ -112,16 +136,12 @@ GList *buddies; GList *contact_info_window; GList *group_info_window; - GList *sendqueue; GList *info_query; GList *add_buddy_request; - GQueue *before_login_packets; /* TODO pass qq_send_packet_get_info() a callback and use signals to get rid of these */ gboolean modifying_info; gboolean modifying_face; }; -void qq_function_not_implemented(PurpleConnection *gc); - #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_network.c Mon Jun 30 23:12:54 2008 +0000 @@ -0,0 +1,1258 @@ +/** + * @file qq_network.c + * + * 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 + */ + +#include "cipher.h" +#include "debug.h" +#include "internal.h" + +#ifdef _WIN32 +#define random rand +#define srandom srand +#endif + +#include "buddy_info.h" +#include "buddy_list.h" +#include "buddy_opt.h" +#include "buddy_status.h" +#include "group_free.h" +#include "char_conv.h" +#include "crypt.h" +#include "group_network.h" +#include "header_info.h" +#include "keep_alive.h" +#include "im.h" +#include "login_logout.h" +#include "packet_parse.h" +#include "qq_network.h" +#include "qq_trans.h" +#include "sys_msg.h" +#include "utils.h" + +/* set QQ_RECONNECT_MAX to 1, when test reconnecting */ +#define QQ_RECONNECT_MAX 4 +#define QQ_RECONNECT_INTERVAL 5000 + +static gboolean set_new_server(qq_data *qd) +{ + gint count; + gint index; + GList *it = NULL; + + g_return_val_if_fail(qd != NULL, FALSE); + + if (qd->servers == NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list is NULL\n"); + return FALSE; + } + + if (qd->real_hostname) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); + g_free(qd->real_hostname); + qd->real_hostname = NULL; + } + + /* remove server used before */ + if (qd->server_name != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Remove previous server [%s]\n", qd->server_name); + qd->servers = g_list_remove(qd->servers, qd->server_name); + qd->server_name = NULL; + } + + count = g_list_length(qd->servers); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list has %d\n", count); + if (count <= 0) { + /* no server left, disconnect when result is false */ + qd->servers = NULL; + return FALSE; + } + + /* get new server */ + index = random() % count; + it = g_list_nth(qd->servers, index); + qd->server_name = it->data; /* do not free server_name */ + if (qd->server_name == NULL || strlen(qd->server_name) <= 0 ) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server name at %d is empty\n", index); + return FALSE; + } + + qd->real_hostname = g_strdup(qd->server_name); + qd->real_port = qd->user_port; + + qd->reconnect_times = QQ_RECONNECT_MAX; + + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "set new server to %s:%d\n", qd->real_hostname, qd->real_port); + return TRUE; +} + +/* QQ 2003iii uses double MD5 for the pwkey to get the session key */ +static guint8 *encrypt_account_password(const gchar *pwd) +{ + PurpleCipher *cipher; + PurpleCipherContext *context; + + guchar pwkey_tmp[QQ_KEY_LENGTH]; + + cipher = purple_ciphers_find_cipher("md5"); + context = purple_cipher_context_new(cipher, NULL); + purple_cipher_context_append(context, (guchar *) pwd, strlen(pwd)); + purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL); + purple_cipher_context_destroy(context); + context = purple_cipher_context_new(cipher, NULL); + purple_cipher_context_append(context, pwkey_tmp, QQ_KEY_LENGTH); + purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL); + purple_cipher_context_destroy(context); + + return g_memdup(pwkey_tmp, QQ_KEY_LENGTH); +} + +/* default process, decrypt and dump */ +static void process_cmd_unknow(PurpleConnection *gc, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq) +{ + qq_data *qd; + guint8 *data; + gint data_len; + gchar *msg_utf8 = NULL; + + g_return_if_fail(buf != NULL && buf_len != 0); + + qq_show_packet("Processing unknown packet", buf, buf_len); + + qd = (qq_data *) gc->proto_data; + + data_len = buf_len; + data = g_newa(guint8, data_len); + memset(data, 0, data_len); + if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &data_len )) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n"); + return; + } + + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + data, data_len, + ">>> [%d] %s -> [default] decrypt and dump", + seq, qq_get_cmd_desc(cmd)); + + msg_utf8 = try_dump_as_gbk(data, data_len); + if (msg_utf8) { + g_free(msg_utf8); + } +} + +static gint packet_get_header(guint8 *header_tag, guint16 *source_tag, + guint16 *cmd, guint16 *seq, guint8 *buf) +{ + gint bytes = 0; + bytes += qq_get8(header_tag, buf + bytes); + bytes += qq_get16(source_tag, buf + bytes); + bytes += qq_get16(cmd, buf + bytes); + bytes += qq_get16(seq, buf + bytes); + return bytes; +} + +/* check whether one sequence number is duplicated or not + * return TRUE if it is duplicated, otherwise FALSE */ +static gboolean packet_is_dup(qq_data *qd, guint16 seq) +{ + guint8 *byte, mask; + + g_return_val_if_fail(qd != NULL, FALSE); + + byte = &(qd->rcv_window[seq / 8]); + mask = (1 << (seq % 8)); + + if ((*byte) & mask) + return TRUE; /* check mask */ + (*byte) |= mask; + return FALSE; /* set mask */ +} + +static gboolean packet_check_ack(qq_data *qd, guint16 seq) +{ + gpointer trans; + + g_return_val_if_fail(qd != NULL, FALSE); + + trans = qq_send_trans_find(qd, seq); + if (trans == NULL) { + return FALSE; + } + + qq_send_trans_remove(qd, trans); + return TRUE; +} + +static gboolean reconnect_later_cb(gpointer data) +{ + PurpleConnection *gc; + qq_data *qd; + + gc = (PurpleConnection *) data; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + qd = (qq_data *) gc->proto_data; + + qd->reconnect_timeout = 0; + + qq_connect(gc->account); + return FALSE; /* timeout callback stops */ +} + +static void reconnect_later(PurpleConnection *gc) +{ + qq_data *qd; + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + qd->reconnect_times--; + if (qd->reconnect_times < 0) { + if ( set_new_server(qd) != TRUE) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Failed to connect server")); + return; + } + } + + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Reconnect to server %s:%d next retries %d in %d ms\n", + qd->real_hostname, qd->real_port, + qd->reconnect_times, QQ_RECONNECT_INTERVAL); + + qd->reconnect_timeout = purple_timeout_add(QQ_RECONNECT_INTERVAL, + reconnect_later_cb, gc); +} + +static void process_cmd_server( + PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +{ + /* now process the packet */ + switch (cmd) { + case QQ_CMD_RECV_IM: + qq_process_recv_im(data, data_len, seq, gc); + break; + case QQ_CMD_RECV_MSG_SYS: + qq_process_msg_sys(data, data_len, seq, gc); + break; + case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: + qq_process_friend_change_status(data, data_len, gc); + break; + default: + process_cmd_unknow(gc, data, data_len, cmd, seq); + break; + } +} + +static void process_cmd_reply( + PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +{ + /* now process the packet */ + switch (cmd) { + case QQ_CMD_KEEP_ALIVE: + qq_process_keep_alive_reply(data, data_len, gc); + break; + case QQ_CMD_UPDATE_INFO: + qq_process_modify_info_reply(data, data_len, gc); + break; + case QQ_CMD_ADD_FRIEND_WO_AUTH: + qq_process_add_buddy_reply(data, data_len, seq, gc); + break; + case QQ_CMD_DEL_FRIEND: + qq_process_remove_buddy_reply(data, data_len, gc); + break; + case QQ_CMD_REMOVE_SELF: + qq_process_remove_self_reply(data, data_len, gc); + break; + case QQ_CMD_BUDDY_AUTH: + qq_process_add_buddy_auth_reply(data, data_len, gc); + break; + case QQ_CMD_GET_USER_INFO: + qq_process_get_info_reply(data, data_len, gc); + break; + case QQ_CMD_CHANGE_ONLINE_STATUS: + qq_process_change_status_reply(data, data_len, gc); + break; + case QQ_CMD_SEND_IM: + qq_process_send_im_reply(data, data_len, gc); + break; + case QQ_CMD_LOGIN: + qq_process_login_reply(data, data_len, gc); + break; + case QQ_CMD_GET_FRIENDS_LIST: + qq_process_get_buddies_list_reply(data, data_len, gc); + break; + case QQ_CMD_GET_FRIENDS_ONLINE: + qq_process_get_buddies_online_reply(data, data_len, gc); + break; + case QQ_CMD_GROUP_CMD: + qq_process_group_cmd_reply(data, data_len, seq, gc); + break; + case QQ_CMD_GET_ALL_LIST_WITH_GROUP: + qq_process_get_all_list_with_group_reply(data, data_len, gc); + break; + case QQ_CMD_GET_LEVEL: + qq_process_get_level_reply(data, data_len, gc); + break; + case QQ_CMD_REQUEST_LOGIN_TOKEN: + qq_process_request_login_token_reply(data, data_len, gc); + break; + default: + process_cmd_unknow(gc, data, data_len, cmd, seq); + break; + } +} + +/* process the incoming packet from qq_pending */ +static void packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) +{ + qq_data *qd; + gint bytes, bytes_not_read; + + gboolean prev_login_status; + guint8 *new_data; + gint new_data_len; + + guint8 header_tag; + guint16 source_tag; + guint16 cmd; + guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ + + gboolean is_reply; + + g_return_if_fail(buf != NULL && buf_len > 0); + + qd = (qq_data *) gc->proto_data; + + prev_login_status = qd->logged_in; + + /* Len, header and tail tag have been checked before */ + bytes = 0; + bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); + + if (QQ_DEBUG) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "==> [%05d] 0x%04X %s, from (0x%04X %s)\n", + seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_source_str(source_tag)); + } + + bytes_not_read = buf_len - bytes - 1; + + /* ack packet, we need to update send tranactions */ + /* we do not check duplication for server ack */ + is_reply = packet_check_ack(qd, seq); + if ( !is_reply ) { + if ( !qd->logged_in ) { + /* packets before login */ + qq_rcv_trans_push(qd, cmd, seq, buf + bytes, bytes_not_read); + return; /* do not process it now */ + } + + /* server intiated packet, we need to send ack and check duplicaion + * this must be put after processing b4_packet + * as these packets will be passed in twice */ + if (packet_is_dup(qd, seq)) { + purple_debug(PURPLE_DEBUG_WARNING, + "QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); + return; + } + process_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); + return; + } + + /* this is the length of all the encrypted data (also remove tail tag */ + process_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read); + + /* check is redirect or not, and do it now */ + if (qd->is_redirect) { + /* free resource except real_hostname and port */ + qq_disconnect(gc); + qd->reconnect_times = QQ_RECONNECT_MAX; + reconnect_later(gc); + return; + } + + if (prev_login_status != qd->logged_in && qd->logged_in == TRUE) { + /* logged_in, but we have packets before login */ + new_data = g_newa(guint8, MAX_PACKET_SIZE); + while (1) { + memset(new_data, 0, MAX_PACKET_SIZE); + new_data_len = qq_rcv_trans_pop(qd, &cmd, &seq, new_data, MAX_PACKET_SIZE); + if (new_data_len < 0) { + break; + } + if (new_data_len == 0) { + continue; + } + process_cmd_reply(gc, seq, cmd, new_data, new_data_len); + } + } +} + +static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleConnection *gc; + qq_data *qd; + guint8 buf[1024]; /* set to 16 when test tcp_rxqueue */ + gint buf_len; + gint bytes; + + guint8 *pkt; + guint16 pkt_len; + + gchar *error_msg; + guint8 *jump; + gint jump_len; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + if(cond != PURPLE_INPUT_READ) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Socket error")); + return; + } + + qd = (qq_data *) gc->proto_data; + + /* test code, not using tcp_rxqueue + memset(pkt,0, sizeof(pkt)); + buf_len = read(qd->fd, pkt, sizeof(pkt)); + if (buf_len > 2) { + packet_process(gc, pkt + 2, buf_len - 2); + } + return; + */ + + buf_len = read(qd->fd, buf, sizeof(buf)); + if (buf_len < 0) { + if (errno == EAGAIN) + /* No worries */ + return; + + error_msg = g_strdup_printf(_("Lost connection with server:\n%d, %s"), errno, g_strerror(errno)); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); + return; + } else if (buf_len == 0) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Server closed the connection.")); + return; + } + + gc->last_received = time(NULL); + purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", + "Read %d bytes from socket, rxlen is %d\n", buf_len, qd->tcp_rxlen); + qd->tcp_rxqueue = g_realloc(qd->tcp_rxqueue, buf_len + qd->tcp_rxlen); + memcpy(qd->tcp_rxqueue + qd->tcp_rxlen, buf, buf_len); + qd->tcp_rxlen += buf_len; + + pkt = g_newa(guint8, MAX_PACKET_SIZE); + while (1) { + if (qd->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { + break; + } + + bytes = 0; + bytes += qq_get16(&pkt_len, qd->tcp_rxqueue + bytes); + if (qd->tcp_rxlen < pkt_len) { + break; + } + + purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", + "Packet len is %d bytes, rxlen is %d\n", pkt_len, qd->tcp_rxlen); + + if ( pkt_len < QQ_TCP_HEADER_LENGTH + || *(qd->tcp_rxqueue + bytes) != QQ_PACKET_TAG + || *(qd->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) { + /* HEY! This isn't even a QQ. What are you trying to pull? */ + + purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", + "Packet error, failed to check header and tail tag\n"); + + jump = memchr(qd->tcp_rxqueue + 1, QQ_PACKET_TAIL, qd->tcp_rxlen - 1); + if ( !jump ) { + purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", + "Failed to find next QQ_PACKET_TAIL, clear receive buffer\n"); + g_free(qd->tcp_rxqueue); + qd->tcp_rxqueue = NULL; + qd->tcp_rxlen = 0; + return; + } + + /* jump and over QQ_PACKET_TAIL */ + jump_len = (jump - qd->tcp_rxqueue) + 1; + purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", + "Find next QQ_PACKET_TAIL at %d, jump %d bytes\n", jump_len, jump_len + 1); + g_memmove(qd->tcp_rxqueue, jump, qd->tcp_rxlen - jump_len); + qd->tcp_rxlen -= jump_len; + continue; + } + + memset(pkt, 0, MAX_PACKET_SIZE); + g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes); + + /* jump to next packet */ + qd->tcp_rxlen -= pkt_len; + if (qd->tcp_rxlen) { + purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", + "shrink tcp_rxqueue to %d\n", qd->tcp_rxlen); + jump = g_memdup(qd->tcp_rxqueue + pkt_len, qd->tcp_rxlen); + g_free(qd->tcp_rxqueue); + qd->tcp_rxqueue = jump; + } else { + purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", + "free tcp_rxqueue\n"); + g_free(qd->tcp_rxqueue); + qd->tcp_rxqueue = NULL; + } + + if (pkt == NULL) { + continue; + } + /* do not call packet_process before jump + * packet_process may call disconnect and destory tcp_rxqueue */ + packet_process(gc, pkt, pkt_len - bytes); + } +} + +static void udp_pending(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleConnection *gc; + qq_data *qd; + guint8 *buf; + gint buf_len; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + if(cond != PURPLE_INPUT_READ) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Socket error")); + return; + } + + qd = (qq_data *) gc->proto_data; + g_return_if_fail(qd->fd >= 0); + + buf = g_newa(guint8, MAX_PACKET_SIZE); + + /* here we have UDP proxy suppport */ + buf_len = read(qd->fd, buf, MAX_PACKET_SIZE); + if (buf_len <= 0) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Unable to read from socket")); + return; + } + + gc->last_received = time(NULL); + + if (buf_len < QQ_UDP_HEADER_LENGTH) { + if (buf[0] != QQ_PACKET_TAG || buf[buf_len - 1] != QQ_PACKET_TAIL) { + qq_hex_dump(PURPLE_DEBUG_ERROR, "UDP_PENDING", + buf, buf_len, + "Received packet is too short, or no header and tail tag"); + return; + } + } + + packet_process(gc, buf, buf_len); +} + +static gint udp_send_out(qq_data *qd, guint8 *data, gint data_len) +{ + gint ret; + + g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Send %d bytes to socket %d\n", data_len, qd->fd); + + errno = 0; + ret = send(qd->fd, data, data_len, 0); + if (ret < 0 && errno == EAGAIN) { + return ret; + } + + if (ret < 0) { + /* TODO: what to do here - do we really have to disconnect? */ + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Send failed: %d, %s\n", errno, g_strerror(errno)); + purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + } + return ret; +} + +static void tcp_can_write(gpointer data, gint source, PurpleInputCondition cond) +{ + qq_data *qd = data; + int ret, writelen; + + writelen = purple_circ_buffer_get_max_read(qd->tcp_txbuf); + if (writelen == 0) { + purple_input_remove(qd->tx_handler); + qd->tx_handler = 0; + return; + } + + ret = write(qd->fd, qd->tcp_txbuf->outptr, writelen); + purple_debug(PURPLE_DEBUG_ERROR, "TCP_CAN_WRITE", + "total %d bytes is sent %d\n", writelen, ret); + + if (ret < 0 && errno == EAGAIN) + return; + else if (ret < 0) { + /* TODO: what to do here - do we really have to disconnect? */ + purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Write Error")); + return; + } + + purple_circ_buffer_mark_read(qd->tcp_txbuf, ret); +} + +static gint tcp_send_out(qq_data *qd, guint8 *data, gint data_len) +{ + gint ret; + + g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + + /* + * purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); + */ + + if (qd->tx_handler == 0) { + ret = write(qd->fd, data, data_len); + } else { + ret = -1; + errno = EAGAIN; + } + + purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + "Socket %d, total %d bytes is sent %d\n", qd->fd, data_len, ret); + if (ret < 0 && errno == EAGAIN) { + /* socket is busy, send later */ + /* + * purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n"); + */ + ret = 0; + } else if (ret <= 0) { + /* TODO: what to do here - do we really have to disconnect? */ + purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT", + "Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno)); + purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + return ret; + } + + if (ret < data_len) { + purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + "Add %d bytes to buffer\n", data_len - ret); + if (qd->tx_handler == 0) { + qd->tx_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, qd); + } + purple_circ_buffer_append(qd->tcp_txbuf, data + ret, data_len - ret); + } + return ret; +} + +static gboolean trans_timeout(gpointer data) +{ + PurpleConnection *gc; + qq_data *qd; + guint8 *buf; + gint buf_len = 0; + guint16 cmd; + gint retries = 0; + int index; + + gc = (PurpleConnection *) data; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, TRUE); + + qd = (qq_data *) gc->proto_data; + + index = 0; + buf = g_newa(guint8, MAX_PACKET_SIZE); + + while (1) { + if (index < 0) { + /* next record is NULL */ + break; + } + /* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "scan begin %d\n", index); */ + memset(buf, 0, MAX_PACKET_SIZE); + buf_len = qq_send_trans_scan(qd, &index, buf, MAX_PACKET_SIZE, &cmd, &retries); + if (buf_len <= 0) { + /* curr record is empty, whole trans is NULL */ + break; + } + /* index = -1, when get last record of transactions */ + + /* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "retries %d next index %d\n", retries, index); */ + if (retries > 0) { + if (qd->use_tcp) { + tcp_send_out(qd, buf, buf_len); + } else { + udp_send_out(qd, buf, buf_len); + } + continue; + } + + /* retries <= 0 */ + switch (cmd) { + case QQ_CMD_KEEP_ALIVE: + if (qd->logged_in) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection lost!\n"); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); + qd->logged_in = FALSE; + } + break; + case QQ_CMD_LOGIN: + case QQ_CMD_REQUEST_LOGIN_TOKEN: + if (!qd->logged_in) { + /* cancel login progress */ + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Login failed, no reply")); + } + break; + default: + purple_debug(PURPLE_DEBUG_WARNING, "QQ", + "%s packet lost.\n", qq_get_cmd_desc(cmd)); + } + } + + return TRUE; /* if return FALSE, timeout callback stops */ +} + +/* the callback function after socket is built + * we setup the qq protocol related configuration here */ +static void qq_connect_cb(gpointer data, gint source, const gchar *error_message) +{ + qq_data *qd; + PurpleConnection *gc; + gchar *conn_msg; + const gchar *passwd; + + gc = (PurpleConnection *) data; + + if (!PURPLE_CONNECTION_IS_VALID(gc)) { + purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection\n"); + close(source); + return; + } + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + /* Connect is now complete; clear the PurpleProxyConnectData */ + qd->connect_data = NULL; + + if (source < 0) { /* socket returns -1 */ + purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection, source is < 0\n"); + qq_disconnect(gc); + reconnect_later(gc); + return; + } + + /* _qq_show_socket("Got login socket", source); */ + + /* QQ use random seq, to minimize duplicated packets */ + srandom(time(NULL)); + qd->send_seq = random() & 0x0000ffff; + qd->fd = source; + qd->logged_in = FALSE; + qd->channel = 1; + qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); + + /* now generate md5 processed passwd */ + passwd = purple_account_get_password(purple_connection_get_account(gc)); + g_return_if_fail(qd->pwkey == NULL); + qd->pwkey = encrypt_account_password(passwd); + + g_return_if_fail(qd->resend_timeout == 0); + /* call trans_timeout every 5 seconds */ + qd->resend_timeout = purple_timeout_add(5000, trans_timeout, gc); + + if (qd->use_tcp) + gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, tcp_pending, gc); + else + gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc); + + /* Update the login progress status display */ + conn_msg = g_strdup_printf("Login as %d", qd->uid); + purple_connection_update_progress(gc, conn_msg, QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); + g_free(conn_msg); + + qq_send_packet_request_login_token(gc); +} + +static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleConnection *gc; + qq_data *qd; + socklen_t len; + int error=0, ret; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + + purple_debug_info("proxy", "Connected.\n"); + + /* + * getsockopt after a non-blocking connect returns -1 if something is + * really messed up (bad descriptor, usually). Otherwise, it returns 0 and + * error holds what connect would have returned if it blocked until now. + * Thus, error == 0 is success, error == EINPROGRESS means "try again", + * and anything else is a real error. + * + * (error == EINPROGRESS can happen after a select because the kernel can + * be overly optimistic sometimes. select is just a hint that you might be + * able to do something.) + */ + len = sizeof(error); + ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); + if (ret == 0 && error == EINPROGRESS) + return; /* we'll be called again later */ + + purple_input_remove(qd->tx_handler); + qd->tx_handler = 0; + if (ret < 0 || error != 0) { + if(ret != 0) + error = errno; + + close(source); + + purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); + + qq_connect_cb(gc, -1, _("Unable to connect")); + return; + } + + qq_connect_cb(gc, source, NULL); +} + +static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) { + PurpleConnection *gc; + qq_data *qd; + struct sockaddr server_addr; + int addr_size; + gint fd = -1; + int flags; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + /* udp_query_data must be set as NULL. + * Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error */ + qd->udp_query_data = NULL; + + if (!hosts || !hosts->data) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Couldn't resolve host")); + return; + } + + addr_size = GPOINTER_TO_INT(hosts->data); + hosts = g_slist_remove(hosts, hosts->data); + memcpy(&server_addr, hosts->data, addr_size); + g_free(hosts->data); + + hosts = g_slist_remove(hosts, hosts->data); + while(hosts) { + hosts = g_slist_remove(hosts, hosts->data); + g_free(hosts->data); + hosts = g_slist_remove(hosts, hosts->data); + } + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Unable to create socket: %s\n", g_strerror(errno)); + return; + } + + /* we use non-blocking mode to speed up connection */ + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ + * + * If a UDP socket is unconnected, which is the normal state after a + * bind() call, then send() or write() are not allowed, since no + * destination is available; only sendto() can be used to send data. + * + * Calling connect() on the socket simply records the specified address + * and port number as being the desired communications partner. That + * means that send() or write() are now allowed; they use the destination + * address and port given on the connect call as the destination of packets. + */ + if (connect(fd, &server_addr, addr_size) >= 0) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n"); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + qq_connect_cb(gc, fd, NULL); + return; + } + + /* [EINPROGRESS] + * The socket is marked as non-blocking and the connection cannot be + * completed immediately. It is possible to select for completion by + * selecting the socket for writing. + * [EINTR] + * A signal interrupted the call. + * The connection is established asynchronously. + */ + if ((errno == EINPROGRESS) || (errno == EINTR)) { + purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n"); + qd->tx_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); + return; + } + + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection failed: %d\n", g_strerror(errno)); + close(fd); +} + +/* establish a generic QQ connection + * TCP/UDP, and direct/redirected */ +void qq_connect(PurpleAccount *account) +{ + PurpleConnection *gc; + qq_data *qd; + gchar *conn_msg; + + gc = purple_account_get_connection(account); + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + + + /* test set_new_server + while (set_new_server(qd)) { + purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", + "New server %s:%d Real server %s:%d\n", + qd->server_name, qd->user_port, qd->real_hostname, qd->real_port); + } + purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", "qd->servers %lu\n", + qd->servers); + exit(1); + */ + if (qd->server_name == NULL) { + /* must be first call this function */ + if ( set_new_server(qd) != TRUE) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Failed to connect server")); + return; + } + } + + if (qd->real_hostname == NULL || qd->real_port == 0) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("hostname is NULL or port is 0")); + return; + } + + conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"), + qd->real_hostname, qd->reconnect_times); + purple_connection_update_progress(gc, conn_msg, 1, QQ_CONNECT_STEPS); + g_free(conn_msg); + + if (qd->is_redirect) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n", + qd->real_hostname, qd->real_port); + } + qd->is_redirect = FALSE; + + qd->fd = -1; + qd->tx_handler = 0; + + /* QQ connection via UDP/TCP. + * Now use Purple proxy function to provide TCP proxy support, + * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */ + if(qd->use_tcp) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "TCP Connect to %s:%d\n", + qd->real_hostname, qd->real_port); + + /* TODO: is there a good default grow size? */ + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create tcp_txbuf\n"); + qd->tcp_txbuf = purple_circ_buffer_new(0); + + qd->connect_data = purple_proxy_connect(NULL, account, + qd->real_hostname, qd->real_port, qq_connect_cb, gc); + if (qd->connect_data == NULL) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Unable to connect.")); + } + return; + } + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Connect to %s:%d\n", + qd->real_hostname, qd->real_port); + + g_return_if_fail(qd->udp_query_data == NULL); + qd->udp_query_data = purple_dnsquery_a(qd->real_hostname, qd->real_port, + udp_host_resolved, gc); + if (qd->udp_query_data == NULL) { + purple_connection_error_reason(qd->gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Could not resolve hostname")); + } +} + +/* clean up qq_data structure and all its components + * always used before a redirectly connection */ +void qq_disconnect(PurpleConnection *gc) +{ + qq_data *qd; + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Disconnecting ...\n"); + /* finish all I/O */ + if (qd->fd >= 0 && qd->logged_in) { + qq_send_packet_logout(gc); + } + + if (qd->resend_timeout > 0) { + purple_timeout_remove(qd->resend_timeout); + qd->resend_timeout = 0; + } + + if (gc->inpa > 0) { + purple_input_remove(gc->inpa); + gc->inpa = 0; + } + + if (qd->fd >= 0) { + close(qd->fd); + qd->fd = -1; + } + + if (qd->reconnect_timeout > 0) { + purple_timeout_remove(qd->reconnect_timeout); + qd->reconnect_timeout = 0; + } + + if (qd->connect_data != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Cancel connect_data\n"); + purple_proxy_connect_cancel(qd->connect_data); + } + + if(qd->tcp_txbuf != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_txbuf\n"); + purple_circ_buffer_destroy(qd->tcp_txbuf); + qd->tcp_txbuf = NULL; + } + + if (qd->tx_handler) { + purple_input_remove(qd->tx_handler); + qd->tx_handler = 0; + } + if (qd->tcp_rxqueue != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_rxqueue\n"); + g_free(qd->tcp_rxqueue); + qd->tcp_rxqueue = NULL; + qd->tcp_rxlen = 0; + } + + if (qd->udp_query_data != NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy udp_query_data\n"); + purple_dnsquery_destroy(qd->udp_query_data); + qd->udp_query_data = NULL; + } + + memset(qd->rcv_window, 0, sizeof(qd->rcv_window)); + qq_rcv_trans_remove_all(qd); + qq_send_trans_remove_all(qd); + + if (qd->inikey) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free inikey\n"); + g_free(qd->inikey); + qd->inikey = NULL; + } + if (qd->pwkey) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free pwkey\n"); + g_free(qd->pwkey); + qd->pwkey = NULL; + } + if (qd->session_key) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free session_key\n"); + g_free(qd->session_key); + qd->session_key = NULL; + } + if (qd->session_md5) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free session_md5\n"); + g_free(qd->session_md5); + qd->session_md5 = NULL; + } + if (qd->my_ip) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", "free my_ip\n"); + g_free(qd->my_ip); + qd->my_ip = NULL; + } + + qq_group_packets_free(qd); + qq_group_free_all(qd); + qq_add_buddy_request_free(qd); + qq_info_query_free(qd); + qq_buddies_list_free(gc->account, qd); +} + +static gint encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, + guint8 *data, gint data_len) +{ + gint bytes = 0; + g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1); + + if (data == NULL) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data is NULL\n"); + return -1; + } + if (data_len <= 0) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data len <= 0\n"); + return -1; + } + + /* QQ TCP packet has two bytes in the begining defines packet length + * so leave room here to store packet size */ + if (qd->use_tcp) { + bytes += qq_put16(buf + bytes, 0x0000); + } + /* now comes the normal QQ packet as UDP */ + bytes += qq_put8(buf + bytes, QQ_PACKET_TAG); + bytes += qq_put16(buf + bytes, QQ_CLIENT); + bytes += qq_put16(buf + bytes, cmd); + + bytes += qq_put16(buf + bytes, seq); + + bytes += qq_put32(buf + bytes, qd->uid); + bytes += qq_putdata(buf + bytes, data, data_len); + bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL); + + /* set TCP packet length at begin of the packet */ + if (qd->use_tcp) { + qq_put16(buf, bytes); + } + + return bytes; +} + +gint qq_send_data(qq_data *qd, guint16 cmd, guint8 *data, gint data_len) +{ + guint8 *buf; + gint buf_len; + gint bytes_sent; + gint seq; + + g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); + seq = ++(qd->send_seq); + buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); + if (buf_len <= 0) { + return -1; + } + + if (qd->use_tcp) { + bytes_sent = tcp_send_out(qd, buf, buf_len); + } else { + bytes_sent = udp_send_out(qd, buf, buf_len); + } + + /* always need ack */ + qq_send_trans_append(qd, buf, buf_len, cmd, seq); + + if (QQ_DEBUG) { + qq_show_packet("QQ_SEND_DATA", buf, buf_len); + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "<== [%05d], %s, total %d bytes is sent %d\n", + seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent); + } + return bytes_sent; +} + +/* send the packet generated with the given cmd and data + * return the number of bytes sent to socket if succeeds + * return -1 if there is any error */ +gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, + guint8 *data, gint data_len) +{ + guint8 *buf; + gint buf_len; + guint8 *encrypted_data; + gint encrypted_len; + gint bytes_sent; + + g_return_val_if_fail(qd != NULL && qd->session_key != NULL, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + encrypted_len = data_len + 16; /* at most 16 bytes more */ + encrypted_data = g_newa(guint8, encrypted_len); + + qq_encrypt(data, data_len, qd->session_key, encrypted_data, &encrypted_len); + + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); + buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, encrypted_data, encrypted_len); + if (buf_len <= 0) { + return -1; + } + + if (QQ_DEBUG) { + qq_show_packet("QQ_SEND_CMD", buf, buf_len); + } + if (qd->use_tcp) { + bytes_sent = tcp_send_out(qd, buf, buf_len); + } else { + bytes_sent = udp_send_out(qd, buf, buf_len); + } + + /* if it does not need ACK, we send ACK manually several times */ + if (need_ack) { + qq_send_trans_append(qd, buf, buf_len, cmd, seq); + } + + if (QQ_DEBUG) { + qq_show_packet("QQ_SEND_CMD", buf, buf_len); + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "<== [%05d], %s, total %d bytes is sent %d\n", + seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent); + } + return bytes_sent; +} + +gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint data_len) +{ + g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + qd->send_seq++; + return qq_send_cmd_detail(qd, cmd, qd->send_seq, TRUE, data, data_len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_network.h Mon Jun 30 23:12:54 2008 +0000 @@ -0,0 +1,44 @@ +/** + * @file qq_network.h + * + * 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 _QQ_PROXY_H +#define _QQ_PROXY_H + +#include <glib.h> +#include "connection.h" + +#include "qq.h" + +#define QQ_CONNECT_STEPS 3 /* steps in connection */ + +void qq_connect(PurpleAccount *account); +void qq_disconnect(PurpleConnection *gc); +void qq_connect_later(PurpleConnection *gc); + +gint qq_send_data(qq_data *qd, guint16 cmd, guint8 *data, gint datalen); +gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint datalen); +gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, + guint8 *data, gint data_len); + +#endif
--- a/libpurple/protocols/qq/qq_proxy.c Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,529 +0,0 @@ -/** - * @file qq_proxy.c - * - * 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 - */ - -#include "cipher.h" -#include "debug.h" -#include "internal.h" - -#ifdef _WIN32 -#define random rand -#define srandom srand -#endif - -#include "packet_parse.h" -#include "buddy_info.h" -#include "buddy_opt.h" -#include "char_conv.h" -#include "group_free.h" -#include "login_logout.h" -#include "qq_proxy.h" -#include "recv_core.h" -#include "send_core.h" -#include "sendqueue.h" -#include "udp_proxy_s5.h" -#include "utils.h" - -/* These functions are used only in development phase */ -/* -static void _qq_show_socket(gchar *desc, gint fd) { - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - getsockname(fd, (struct sockaddr *)&sin, &len); - purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n", - inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); -} -*/ - -void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len) -{ - char buf1[8*len+2], buf2[10]; - int i; - buf1[0] = 0; - for (i = 0; i < len; i++) { - sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff); - strcat(buf1, buf2); - } - strcat(buf1, "\n"); - purple_debug(PURPLE_DEBUG_INFO, desc, "%s", buf1); -} - -/* QQ 2003iii uses double MD5 for the pwkey to get the session key */ -static guint8 *_gen_pwkey(const gchar *pwd) -{ - PurpleCipher *cipher; - PurpleCipherContext *context; - - guchar pwkey_tmp[QQ_KEY_LENGTH]; - - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, (guchar *) pwd, strlen(pwd)); - purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL); - purple_cipher_context_destroy(context); - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, pwkey_tmp, QQ_KEY_LENGTH); - purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL); - purple_cipher_context_destroy(context); - - return g_memdup(pwkey_tmp, QQ_KEY_LENGTH); -} - -static gboolean _qq_fill_host(GSList *hosts, struct sockaddr_in *addr, gint *addr_size) -{ - if (!hosts || !hosts->data) - return FALSE; - - *addr_size = GPOINTER_TO_INT(hosts->data); - - hosts = g_slist_remove(hosts, hosts->data); - memcpy(addr, hosts->data, *addr_size); - g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); - while(hosts) { - hosts = g_slist_remove(hosts, hosts->data); - g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); - } - - return TRUE; -} - -/* set up any finalizing start-up stuff */ -static void _qq_start_services(PurpleConnection *gc) -{ - /* start watching for IMs about to be sent */ - /* - purple_signal_connect(purple_conversations_get_handle(), - "sending-im-msg", gc, - PURPLE_CALLBACK(qq_sending_im_msg_cb), NULL); - */ -} - -/* the callback function after socket is built - * we setup the qq protocol related configuration here */ -static void _qq_got_login(gpointer data, gint source, const gchar *error_message) -{ - qq_data *qd; - PurpleConnection *gc; - gchar *buf; - const gchar *passwd; - - gc = (PurpleConnection *) data; - - if (!PURPLE_CONNECTION_IS_VALID(gc)) { - close(source); - return; - } - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - - if (source < 0) { /* socket returns -1 */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message); - return; - } - - qd = (qq_data *) gc->proto_data; - - /* - _qq_show_socket("Got login socket", source); - */ - - /* QQ use random seq, to minimize duplicated packets */ - srandom(time(NULL)); - qd->send_seq = random() & 0x0000ffff; - qd->fd = source; - qd->logged_in = FALSE; - qd->channel = 1; - qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); - - /* now generate md5 processed passwd */ - passwd = purple_account_get_password(purple_connection_get_account(gc)); - qd->pwkey = _gen_pwkey(passwd); - - qd->sendqueue_timeout = purple_timeout_add(QQ_SENDQUEUE_TIMEOUT, qq_sendqueue_timeout_callback, gc); - gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, qq_input_pending, gc); - - /* Update the login progress status display */ - buf = g_strdup_printf("Login as %d", qd->uid); - purple_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS); - g_free(buf); - - _qq_start_services(gc); - - qq_send_packet_request_login_token(gc); -} - -/* clean up qq_data structure and all its components - * always used before a redirectly connection */ -static void _qq_common_clean(PurpleConnection *gc) -{ - qq_data *qd; - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; - - /* finish all I/O */ - if (qd->fd >= 0 && qd->logged_in) - qq_send_packet_logout(gc); - close(qd->fd); - - if (qd->sendqueue_timeout > 0) { - purple_timeout_remove(qd->sendqueue_timeout); - qd->sendqueue_timeout = 0; - } - - if (gc->inpa > 0) { - purple_input_remove(gc->inpa); - gc->inpa = 0; - } - - qq_b4_packets_free(qd); - qq_sendqueue_free(qd); - qq_group_packets_free(qd); - qq_group_free_all(qd); - qq_add_buddy_request_free(qd); - qq_info_query_free(qd); - qq_buddies_list_free(gc->account, qd); -} - -static void no_one_calls(gpointer data, gint source, PurpleInputCondition cond) -{ - struct PHB *phb = data; - socklen_t len; - int error=0, ret; - - purple_debug_info("proxy", "Connected.\n"); - - len = sizeof(error); - - /* - * getsockopt after a non-blocking connect returns -1 if something is - * really messed up (bad descriptor, usually). Otherwise, it returns 0 and - * error holds what connect would have returned if it blocked until now. - * Thus, error == 0 is success, error == EINPROGRESS means "try again", - * and anything else is a real error. - * - * (error == EINPROGRESS can happen after a select because the kernel can - * be overly optimistic sometimes. select is just a hint that you might be - * able to do something.) - */ - ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); - if (ret == 0 && error == EINPROGRESS) - return; /* we'll be called again later */ - if (ret < 0 || error != 0) { - if(ret!=0) - error = errno; - close(source); - purple_input_remove(phb->inpa); - - purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); - - phb->func(phb->data, -1, _("Unable to connect")); - return; - } - - purple_input_remove(phb->inpa); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, source, NULL); - } - - g_free(phb->host); - g_free(phb); -} - -/* returns -1 if fails, otherwise returns the file handle */ -static gint _qq_proxy_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) -{ - gint fd = -1; - int flags; - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Using UDP without proxy\n"); - fd = socket(PF_INET, SOCK_DGRAM, 0); - - if (fd < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ Redirect", - "Unable to create socket: %s\n", g_strerror(errno)); - return -1; - } - - /* we use non-blocking mode to speed up connection */ - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ - * - * If a UDP socket is unconnected, which is the normal state after a - * bind() call, then send() or write() are not allowed, since no - * destination is available; only sendto() can be used to send data. - * - * Calling connect() on the socket simply records the specified address - * and port number as being the desired communications partner. That - * means that send() or write() are now allowed; they use the destination - * address and port given on the connect call as the destination of packets. - */ - if (connect(fd, addr, addrlen) < 0) { - /* [EINPROGRESS] - * The socket is marked as non-blocking and the connection cannot be - * completed immediately. It is possible to select for completion by - * selecting the socket for writing. - * [EINTR] - * A signal interrupted the call. - * The connection is established asynchronously. - */ - if ((errno == EINPROGRESS) || (errno == EINTR)) { - purple_debug_warning("QQ", "Connect in asynchronous mode.\n"); - phb->inpa = purple_input_add(fd, PURPLE_INPUT_WRITE, no_one_calls, phb); - } else { - purple_debug_error("QQ", "Connection failed: %s\n", g_strerror(errno)); - close(fd); - return -1; - } /* if errno */ - } else { /* connect returns 0 */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n"); - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - phb->func(phb->data, fd, NULL); - } - - return fd; -} - -static void _qq_proxy_resolved(GSList *hosts, gpointer data, const char *error_message) -{ - struct PHB *phb = (struct PHB *) data; - struct sockaddr_in addr; - gint addr_size, ret = -1; - - if(_qq_fill_host(hosts, &addr, &addr_size)) - ret = qq_proxy_socks5(phb, (struct sockaddr *) &addr, addr_size); - - if (ret < 0) { - phb->func(phb->data, -1, _("Unable to connect")); - g_free(phb->host); - g_free(phb); - } -} - -static void _qq_server_resolved(GSList *hosts, gpointer data, const char *error_message) -{ - struct PHB *phb = (struct PHB *) data; - PurpleConnection *gc = (PurpleConnection *) phb->data; - qq_data *qd = (qq_data *) gc->proto_data; - struct sockaddr_in addr; - gint addr_size, ret = -1; - - if(_qq_fill_host(hosts, &addr, &addr_size)) { - switch (purple_proxy_info_get_type(phb->gpi)) { - case PURPLE_PROXY_NONE: - ret = _qq_proxy_none(phb, (struct sockaddr *) &addr, addr_size); - break; - case PURPLE_PROXY_SOCKS5: - ret = 0; - if (purple_proxy_info_get_host(phb->gpi) == NULL || - purple_proxy_info_get_port(phb->gpi) == 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Use of socks5 proxy selected but host or port info doesn't exist.\n"); - ret = -1; - } else { - /* as the destination is always QQ server during the session, - * we can set dest_sin here, instead of _qq_s5_canread_again */ - memcpy(&qd->dest_sin, &addr, addr_size); - if (purple_dnsquery_a(purple_proxy_info_get_host(phb->gpi), - purple_proxy_info_get_port(phb->gpi), - _qq_proxy_resolved, phb) == NULL) - ret = -1; - } - break; - default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Proxy type %i is unsupported, not using a proxy.\n", - purple_proxy_info_get_type(phb->gpi)); - ret = _qq_proxy_none(phb, (struct sockaddr *) &addr, addr_size); - } - } - - if (ret < 0) { - phb->func(gc, -1, _("Unable to connect")); - g_free(phb->host); - g_free(phb); - } -} - -/* returns -1 if dns lookup fails, otherwise returns 0 */ -static gint _qq_udp_proxy_connect(PurpleAccount *account, - const gchar *server, guint16 port, - void callback(gpointer, gint, const gchar *error_message), - PurpleConnection *gc) -{ - PurpleProxyInfo *info; - struct PHB *phb; - qq_data *qd = (qq_data *) gc->proto_data; - - g_return_val_if_fail(gc != NULL && qd != NULL, -1); - - info = purple_proxy_get_setup(account); - - phb = g_new0(struct PHB, 1); - phb->host = g_strdup(server); - phb->port = port; - phb->account = account; - phb->gpi = info; - phb->func = callback; - phb->data = gc; - qd->proxy_type = purple_proxy_info_get_type(phb->gpi); - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Choosing proxy type %d\n", - purple_proxy_info_get_type(phb->gpi)); - - if (purple_dnsquery_a(server, port, _qq_server_resolved, phb) == NULL) { - phb->func(gc, -1, _("Unable to connect")); - g_free(phb->host); - g_free(phb); - return -1; - } else { - return 0; - } -} - -/* QQ connection via UDP/TCP. - * I use Purple proxy function to provide TCP proxy support, - * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */ -static gint _proxy_connect_full (PurpleAccount *account, const gchar *host, guint16 port, - PurpleProxyConnectFunction func, gpointer data, gboolean use_tcp) -{ - PurpleConnection *gc; - qq_data *qd; - - gc = purple_account_get_connection(account); - qd = (qq_data *) gc->proto_data; - qd->server_ip = g_strdup(host); - qd->server_port = port; - - if(use_tcp) - return (purple_proxy_connect(NULL, account, host, port, func, data) == NULL); - else - return _qq_udp_proxy_connect(account, host, port, func, data); -} - -/* establish a generic QQ connection - * TCP/UDP, and direct/redirected */ -gint qq_connect(PurpleAccount *account, const gchar *host, guint16 port, - gboolean use_tcp, gboolean is_redirect) -{ - PurpleConnection *gc; - qq_data *qd; - - g_return_val_if_fail(host != NULL, -1); - g_return_val_if_fail(port > 0, -1); - - gc = purple_account_get_connection(account); - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); - - if (is_redirect) - _qq_common_clean(gc); - - qd = (qq_data *) gc->proto_data; - qd->before_login_packets = g_queue_new(); - - return _proxy_connect_full(account, host, port, _qq_got_login, gc, use_tcp); -} - -/* clean up the given QQ connection and free all resources */ -void qq_disconnect(PurpleConnection *gc) -{ - qq_data *qd; - - g_return_if_fail(gc != NULL); - - _qq_common_clean(gc); - - qd = gc->proto_data; - g_free(qd->inikey); - g_free(qd->pwkey); - g_free(qd->session_key); - g_free(qd->session_md5); - g_free(qd->my_ip); - g_free(qd); - - gc->proto_data = NULL; -} - -/* send packet with proxy support */ -gint qq_proxy_write(qq_data *qd, guint8 *data, gint len) -{ - guint8 *buf; - gint ret; - - g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && len > 0, -1); - - /* TCP sock5 may be processed twice - * so we need to check qd->use_tcp as well */ - if ((!qd->use_tcp) && qd->proxy_type == PURPLE_PROXY_SOCKS5) { /* UDP sock5 */ - buf = g_newa(guint8, len + 10); - buf[0] = 0x00; - buf[1] = 0x00; /* reserved */ - buf[2] = 0x00; /* frag */ - buf[3] = 0x01; /* type */ - g_memmove(buf + 4, &(qd->dest_sin.sin_addr.s_addr), 4); - g_memmove(buf + 8, &(qd->dest_sin.sin_port), 2); - g_memmove(buf + 10, data, len); - errno = 0; - ret = send(qd->fd, buf, len + 10, 0); - } else { - errno = 0; - ret = send(qd->fd, data, len, 0); - } - if (ret == -1) - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); - - return ret; -} - -/* read packet input with proxy support */ -gint qq_proxy_read(qq_data *qd, guint8 *data, gint len) -{ - guint8 *buf; - gint bytes; - buf = g_newa(guint8, MAX_PACKET_SIZE + 10); - - g_return_val_if_fail(qd != NULL && data != NULL && len > 0, -1); - g_return_val_if_fail(qd->fd > 0, -1); - - bytes = read(qd->fd, buf, len + 10); - if (bytes < 0) - return -1; - - if ((!qd->use_tcp) && qd->proxy_type == PURPLE_PROXY_SOCKS5) { /* UDP sock5 */ - if (bytes < 10) - return -1; - bytes -= 10; - g_memmove(data, buf + 10, bytes); /* cut off the header */ - } else { - g_memmove(data, buf, bytes); - } - - return bytes; -}
--- a/libpurple/protocols/qq/qq_proxy.h Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/** - * @file qq_proxy.h - * - * 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 _QQ_PROXY_H -#define _QQ_PROXY_H - -#include <glib.h> -#include "dnsquery.h" -#include "proxy.h" - -#include "qq.h" - -#define QQ_CONNECT_STEPS 2 /* steps in connection */ - -struct PHB { - PurpleProxyConnectFunction func; - gpointer data; - gchar *host; - gint port; - gint inpa; - PurpleProxyInfo *gpi; - PurpleAccount *account; - gint udpsock; - gpointer sockbuf; -}; - -gint qq_proxy_read(qq_data *qd, guint8 *data, gint len); -gint qq_proxy_write(qq_data *qd, guint8 *data, gint len); - -gint qq_connect(PurpleAccount *account, const gchar *host, guint16 port, gboolean use_tcp, gboolean is_redirect); -void qq_disconnect(PurpleConnection *gc); - -void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len); - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Mon Jun 30 23:12:54 2008 +0000 @@ -0,0 +1,246 @@ +/** + * @file qq_trans.c + * + * 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 + */ + +#include "internal.h" + +#include "connection.h" +#include "debug.h" +#include "notify.h" +#include "prefs.h" +#include "request.h" + +#include "header_info.h" +#include "qq_network.h" +#include "qq_trans.h" + +#define QQ_RESEND_MAX 8 /* max resend per packet */ + +typedef struct _transaction { + guint16 seq; + guint16 cmd; + guint8 *buf; + gint buf_len; + + gint fd; + gint retries; + time_t create_time; +} transaction; + +void qq_send_trans_append(qq_data *qd, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq) +{ + transaction *trans = g_new0(transaction, 1); + + g_return_if_fail(trans != NULL); + + trans->fd = qd->fd; + trans->cmd = cmd; + trans->seq = seq; + trans->retries = QQ_RESEND_MAX; + trans->create_time = time(NULL); + trans->buf = g_memdup(buf, buf_len); /* don't use g_strdup, may have 0x00 */ + trans->buf_len = buf_len; + + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Add to transaction, seq = %d, buf = %p, len = %d\n", + trans->seq, trans->buf, trans->buf_len); + qd->send_trans = g_list_append(qd->send_trans, trans); +} + +/* Remove a packet with seq from send trans */ +void qq_send_trans_remove(qq_data *qd, gpointer data) +{ + transaction *trans = (transaction *)data; + + g_return_if_fail(qd != NULL && data != NULL); + + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "ack [%05d] %s, remove from send tranactions\n", + trans->seq, qq_get_cmd_desc(trans->cmd)); + + if (trans->buf) g_free(trans->buf); + qd->send_trans = g_list_remove(qd->send_trans, trans); + g_free(trans); +} + +gpointer qq_send_trans_find(qq_data *qd, guint16 seq) +{ + GList *curr; + GList *next; + transaction *trans; + + curr = qd->send_trans; + while(curr) { + next = curr->next; + trans = (transaction *) (curr->data); + if(trans->seq == seq) { + return trans; + } + curr = next; + } + + return NULL; +} + +/* clean up send trans and free all contents */ +void qq_send_trans_remove_all(qq_data *qd) +{ + GList *curr; + GList *next; + transaction *trans; + gint count = 0; + + curr = qd->send_trans; + while(curr) { + next = curr->next; + + trans = (transaction *) (curr->data); + /* + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Remove to transaction, seq = %d, buf = %p, len = %d\n", + trans->seq, trans->buf, trans->len); + */ + qq_send_trans_remove(qd, trans); + + count++; + curr = next; + } + g_list_free(qd->send_trans); + + purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in send tranactions are freed!\n", count); +} + +gint qq_send_trans_scan(qq_data *qd, gint *start, + guint8 *buf, gint maxlen, guint16 *cmd, gint *retries) +{ + GList *curr; + GList *next = NULL; + transaction *trans; + gint copylen; + + g_return_val_if_fail(qd != NULL && *start >= 0 && maxlen > 0, -1); + + /* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Scan from %d\n", *start); */ + curr = g_list_nth(qd->send_trans, *start); + while(curr) { + next = curr->next; + *start = g_list_position(qd->send_trans, next); + + trans = (transaction *) (curr->data); + if (trans->buf == NULL || trans->buf_len <= 0) { + qq_send_trans_remove(qd, trans); + curr = next; + continue; + } + + if (trans->retries < 0) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Remove transaction, seq %d, buf %p, len %d, retries %d, next %d\n", + trans->seq, trans->buf, trans->buf_len, trans->retries, *start); + qq_send_trans_remove(qd, trans); + curr = next; + continue; + } + + purple_debug(PURPLE_DEBUG_ERROR, "QQ", + "Resend transaction, seq %d, buf %p, len %d, retries %d, next %d\n", + trans->seq, trans->buf, trans->buf_len, trans->retries, *start); + copylen = MIN(trans->buf_len, maxlen); + g_memmove(buf, trans->buf, copylen); + + *cmd = trans->cmd; + *retries = trans->retries; + trans->retries--; + return copylen; + } + + /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Scan finished\n"); */ + return -1; +} + +void qq_rcv_trans_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +{ + transaction *trans = g_new0(transaction, 1); + + g_return_if_fail(data != NULL && data_len > 0); + g_return_if_fail(trans != NULL); + + trans->cmd = cmd; + trans->seq = seq; + trans->buf = g_memdup(data, data_len); + trans->buf_len = data_len; + trans->create_time = time(NULL); + + if (qd->rcv_trans == NULL) + qd->rcv_trans = g_queue_new(); + + g_queue_push_head(qd->rcv_trans, trans); +} + +gint qq_rcv_trans_pop(qq_data *qd, guint16 *cmd, guint16 *seq, guint8 *data, gint max_len) +{ + transaction *trans = NULL; + gint copy_len; + + g_return_val_if_fail(data != NULL && max_len > 0, -1); + + if (g_queue_is_empty(qd->rcv_trans)) { + return -1; + } + trans = (transaction *) g_queue_pop_head(qd->rcv_trans); + if (trans == NULL) { + return 0; + } + if (trans->buf == NULL || trans->buf_len <= 0) { + return 0; + } + + copy_len = MIN(max_len, trans->buf_len); + g_memmove(data, trans->buf, copy_len); + *cmd = trans->cmd; + *seq = trans->seq; + + g_free(trans->buf); + g_free(trans); + return copy_len; +} + +/* clean up the packets before login */ +void qq_rcv_trans_remove_all(qq_data *qd) +{ + transaction *trans = NULL; + gint count = 0; + + g_return_if_fail(qd != NULL); + + /* now clean up my own data structures */ + if (qd->rcv_trans != NULL) { + while (NULL != (trans = g_queue_pop_tail(qd->rcv_trans))) { + g_free(trans->buf); + g_free(trans); + count++; + } + g_queue_free(qd->rcv_trans); + } + purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in receive tranactions are freed!\n", count); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Mon Jun 30 23:12:54 2008 +0000 @@ -0,0 +1,42 @@ +/** + * @file qq_trans.h + * + * 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 _QQ_SEND_QUEUE_H_ +#define _QQ_SEND_QUEUE_H_ + +#include <glib.h> +#include "qq.h" + +void qq_send_trans_append(qq_data *qd, guint8 *buf, gint bus_len, guint16 cmd, guint16 seq); +void qq_send_trans_remove(qq_data *qd, gpointer data); +gpointer qq_send_trans_find(qq_data *qd, guint16 seq); +void qq_send_trans_remove_all(qq_data *qd); + +gint qq_send_trans_scan(qq_data *qd, gint *start, guint8 *buf, gint maxlen, guint16 *cmd, gint *retries); + +void qq_rcv_trans_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len); +gint qq_rcv_trans_pop(qq_data *qd, guint16 *cmd, guint16* seq, guint8 *data, gint max_len); +void qq_rcv_trans_remove_all(qq_data *qd); + +#endif
--- a/libpurple/protocols/qq/recv_core.c Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,326 +0,0 @@ -/** - * @file recv_core.c - * - * 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 - */ - -#include "debug.h" -#include "internal.h" - -#include "buddy_info.h" -#include "buddy_list.h" -#include "buddy_opt.h" -#include "buddy_status.h" -#include "char_conv.h" -#include "crypt.h" -#include "group_network.h" -#include "header_info.h" -#include "keep_alive.h" -#include "im.h" -#include "login_logout.h" -#include "packet_parse.h" -#include "qq_proxy.h" -#include "recv_core.h" -#include "sendqueue.h" -#include "sys_msg.h" -#include "utils.h" - -typedef struct _packet_before_login packet_before_login; -typedef struct _qq_recv_msg_header qq_recv_msg_header; - -struct _packet_before_login { - guint8 *buf; - gint len; -}; - -struct _qq_recv_msg_header { - guint8 header_tag; - guint16 source_tag; - guint16 cmd; - guint16 seq; /* can be ack_seq or send_seq, depends on cmd */ -}; - -/* check whether one sequence number is duplicated or not - * return TRUE if it is duplicated, otherwise FALSE */ -static gboolean _qq_check_packet_set_window(guint16 seq, PurpleConnection *gc) -{ - qq_data *qd; - guint8 *byte, mask; - - qd = (qq_data *) gc->proto_data; - byte = &(qd->window[seq / 8]); - mask = (1 << (seq % 8)); - - if ((*byte) & mask) - return TRUE; /* check mask */ - (*byte) |= mask; - return FALSE; /* set mask */ -} - -/* default process, decrypt and dump */ -static void _qq_process_packet_default(guint8 *buf, gint buf_len, guint16 cmd, guint16 seq, PurpleConnection *gc) -{ - qq_data *qd; - guint8 *data; - gchar *msg_utf8; - gint len; - - g_return_if_fail(buf != NULL && buf_len != 0); - - qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - msg_utf8 = NULL; - - _qq_show_packet("Processing unknown packet", buf, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - gchar *hex_dump = hex_dump_to_str(data, len); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - ">>> [%d] %s, %d bytes -> [default] decrypt and dump\n%s", - seq, qq_get_cmd_desc(cmd), buf_len, hex_dump); - g_free(hex_dump); - try_dump_as_gbk(data, len); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n"); - } -} - -/* process the incoming packet from qq_pending */ -static void _qq_packet_process(guint8 *buf, gint buf_len, PurpleConnection *gc) -{ - qq_data *qd; - gint len, bytes_expected, bytes_read; - guint16 buf_len_read; /* two bytes in the begining of TCP packet */ - guint8 *cursor; - qq_recv_msg_header header; - packet_before_login *b4_packet; - - g_return_if_fail(buf != NULL && buf_len > 0); - - qd = (qq_data *) gc->proto_data; - bytes_expected = qd->use_tcp ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH; - - if (buf_len < bytes_expected) { - gchar *hex_dump = hex_dump_to_str(buf, buf_len); - purple_debug(PURPLE_DEBUG_ERROR, - "QQ", "Received packet is too short, dump and drop\n%s", hex_dump); - g_free(hex_dump); - return; - } - /* initialize */ - cursor = buf; - bytes_read = 0; - - /* QQ TCP packet returns first 2 bytes the length of this packet */ - if (qd->use_tcp) { - bytes_read += read_packet_w(buf, &cursor, buf_len, &buf_len_read); - if (buf_len_read != buf_len) { /* wrong */ - purple_debug - (PURPLE_DEBUG_ERROR, - "QQ", - "TCP read %d bytes, header says %d bytes, use header anyway\n", buf_len, buf_len_read); - buf_len = buf_len_read; /* we believe header is more accurate */ - } - } - - /* now goes the normal QQ packet as UDP packet */ - bytes_read += read_packet_b(buf, &cursor, buf_len, &header.header_tag); - bytes_read += read_packet_w(buf, &cursor, buf_len, &header.source_tag); - bytes_read += read_packet_w(buf, &cursor, buf_len, &header.cmd); - bytes_read += read_packet_w(buf, &cursor, buf_len, &header.seq); - - if (bytes_read != bytes_expected) { /* read error */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail reading packet header, expect %d bytes, read %d bytes\n", - bytes_expected, bytes_read); - return; - } - - if ((buf[buf_len - 1] != QQ_PACKET_TAIL) || (header.header_tag != QQ_PACKET_TAG)) { - gchar *hex_dump = hex_dump_to_str(buf, buf_len); - purple_debug(PURPLE_DEBUG_ERROR, - "QQ", "Unknown QQ proctocol, dump and drop\n%s", hex_dump); - g_free(hex_dump); - return; - } - - if (QQ_DEBUG) - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "==> [%05d] %s, from (%s)\n", - header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag)); - - if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_REQUEST_LOGIN_TOKEN) { - if (!qd->logged_in) { /* packets before login */ - b4_packet = g_new0(packet_before_login, 1); - /* must duplicate, buffer will be freed after exiting this function */ - b4_packet->buf = g_memdup(buf, buf_len); - b4_packet->len = buf_len; - if (qd->before_login_packets == NULL) - qd->before_login_packets = g_queue_new(); - g_queue_push_head(qd->before_login_packets, b4_packet); - return; /* do not process it now */ - } else if (!g_queue_is_empty(qd->before_login_packets)) { - /* logged_in, but we have packets before login */ - b4_packet = (packet_before_login *) - g_queue_pop_head(qd->before_login_packets); - _qq_packet_process(b4_packet->buf, b4_packet->len, gc); - /* in fact this is a recursive call, - * all packets before login will be processed before goes on */ - g_free(b4_packet->buf); /* the buf is duplicated, need to be freed */ - g_free(b4_packet); - } - } - - /* this is the length of all the encrypted data (also remove tail tag */ - len = buf_len - (bytes_read) - 1; - - /* whether it is an ack */ - switch (header.cmd) { - case QQ_CMD_RECV_IM: - case QQ_CMD_RECV_MSG_SYS: - case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: - /* server intiated packet, we need to send ack and check duplicaion - * this must be put after processing b4_packet - * as these packets will be passed in twice */ - if (_qq_check_packet_set_window(header.seq, gc)) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", "dup [%05d] %s, discard...\n", header.seq, qq_get_cmd_desc(header.cmd)); - return; - } - break; - default:{ /* ack packet, we need to update sendqueue */ - /* we do not check duplication for server ack */ - qq_sendqueue_remove(qd, header.seq); - if (QQ_DEBUG) - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "ack [%05d] %s, remove from sendqueue\n", - header.seq, qq_get_cmd_desc(header.cmd)); - } - } - - /* now process the packet */ - switch (header.cmd) { - case QQ_CMD_KEEP_ALIVE: - qq_process_keep_alive_reply(cursor, len, gc); - break; - case QQ_CMD_UPDATE_INFO: - qq_process_modify_info_reply(cursor, len, gc); - break; - case QQ_CMD_ADD_FRIEND_WO_AUTH: - qq_process_add_buddy_reply(cursor, len, header.seq, gc); - break; - case QQ_CMD_DEL_FRIEND: - qq_process_remove_buddy_reply(cursor, len, gc); - break; - case QQ_CMD_REMOVE_SELF: - qq_process_remove_self_reply(cursor, len, gc); - break; - case QQ_CMD_BUDDY_AUTH: - qq_process_add_buddy_auth_reply(cursor, len, gc); - break; - case QQ_CMD_GET_USER_INFO: - qq_process_get_info_reply(cursor, len, gc); - break; - case QQ_CMD_CHANGE_ONLINE_STATUS: - qq_process_change_status_reply(cursor, len, gc); - break; - case QQ_CMD_SEND_IM: - qq_process_send_im_reply(cursor, len, gc); - break; - case QQ_CMD_RECV_IM: - qq_process_recv_im(cursor, len, header.seq, gc); - break; - case QQ_CMD_LOGIN: - qq_process_login_reply(cursor, len, gc); - break; - case QQ_CMD_GET_FRIENDS_LIST: - qq_process_get_buddies_list_reply(cursor, len, gc); - break; - case QQ_CMD_GET_FRIENDS_ONLINE: - qq_process_get_buddies_online_reply(cursor, len, gc); - break; - case QQ_CMD_GROUP_CMD: - qq_process_group_cmd_reply(cursor, len, header.seq, gc); - break; - case QQ_CMD_GET_ALL_LIST_WITH_GROUP: - qq_process_get_all_list_with_group_reply(cursor, len, gc); - break; - case QQ_CMD_GET_LEVEL: - qq_process_get_level_reply(cursor, len, gc); - break; - case QQ_CMD_REQUEST_LOGIN_TOKEN: - qq_process_request_login_token_reply(cursor, len, gc); - break; - case QQ_CMD_RECV_MSG_SYS: - qq_process_msg_sys(cursor, len, header.seq, gc); - break; - case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: - qq_process_friend_change_status(cursor, len, gc); - break; - default: - _qq_process_packet_default(cursor, len, header.cmd, header.seq, gc); - break; - } -} - -/* clean up the packets before login */ -void qq_b4_packets_free(qq_data *qd) -{ - packet_before_login *b4_packet; - g_return_if_fail(qd != NULL); - /* now clean up my own data structures */ - if (qd->before_login_packets != NULL) { - while (NULL != (b4_packet = g_queue_pop_tail(qd->before_login_packets))) { - g_free(b4_packet->buf); - g_free(b4_packet); - } - g_queue_free(qd->before_login_packets); - } -} - -void qq_input_pending(gpointer data, gint source, PurpleInputCondition cond) -{ - PurpleConnection *gc; - qq_data *qd; - guint8 *buf; - gint len; - - gc = (PurpleConnection *) data; - - if(cond != PURPLE_INPUT_READ) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Socket error")); - return; - } - - qd = (qq_data *) gc->proto_data; - buf = g_newa(guint8, MAX_PACKET_SIZE); - - /* here we have UDP proxy suppport */ - len = qq_proxy_read(qd, buf, MAX_PACKET_SIZE); - if (len <= 0) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to read from socket")); - return; - } else { - _qq_packet_process(buf, len, gc); - } -}
--- a/libpurple/protocols/qq/recv_core.h Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/** - * @file recv_core.h - * - * 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 _QQ_RECV_CORE_H_ -#define _QQ_RECV_CORE_H_ - -#include <glib.h> -#include "connection.h" -#include "qq.h" - -void qq_b4_packets_free(qq_data *qd); - -void qq_input_pending(gpointer data, gint source, PurpleInputCondition cond); - -#endif
--- a/libpurple/protocols/qq/send_core.c Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/** - * @file send_core.c - * - * 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 - */ - -#include "debug.h" -#include "internal.h" - -#include "crypt.h" -#include "header_info.h" -#include "packet_parse.h" -#include "qq.h" -#include "qq_proxy.h" -#include "send_core.h" -#include "sendqueue.h" - -/* create qq packet header with given sequence - * return the number of bytes in header if succeeds - * return -1 if there is any error */ -gint _create_packet_head_seq(guint8 *buf, guint8 **cursor, - PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 *seq) -{ - qq_data *qd; - gint bytes_expected, bytes_written; - - g_return_val_if_fail(buf != NULL && cursor != NULL && *cursor != NULL, -1); - - qd = (qq_data *) gc->proto_data; - if (is_auto_seq) - *seq = ++(qd->send_seq); - - *cursor = buf; - bytes_written = 0; - bytes_expected = (qd->use_tcp) ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH; - - /* QQ TCP packet has two bytes in the begining defines packet length - * so I leave room here for size */ - if (qd->use_tcp) - bytes_written += create_packet_w(buf, cursor, 0x0000); - - /* now comes the normal QQ packet as UDP */ - bytes_written += create_packet_b(buf, cursor, QQ_PACKET_TAG); - bytes_written += create_packet_w(buf, cursor, QQ_CLIENT); - bytes_written += create_packet_w(buf, cursor, cmd); - bytes_written += create_packet_w(buf, cursor, *seq); - - if (bytes_written != bytes_expected) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create qq header, expect %d bytes, written %d bytes\n", bytes_expected, bytes_written); - bytes_written = -1; - } - return bytes_written; -} - -/* for those need ack and resend no ack feed back from server - * return number of bytes written to the socket, - * return -1 if there is any error */ -gint _qq_send_packet(PurpleConnection *gc, guint8 *buf, gint len, guint16 cmd) -{ - qq_data *qd; - qq_sendpacket *p; - gint bytes_sent; - guint8 *cursor; - - qd = (qq_data *) gc->proto_data; - - if (qd->use_tcp) { - if (len > MAX_PACKET_SIZE) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "xxx [%05d] %s, %d bytes is too large, do not send\n", - qd->send_seq, qq_get_cmd_desc(cmd), len); - return -1; - } else { /* I update the len for TCP packet */ - cursor = buf; - create_packet_w(buf, &cursor, len); - } - } - - bytes_sent = qq_proxy_write(qd, buf, len); - - if (bytes_sent >= 0) { /* put to queue, for matching server ACK usage */ - p = g_new0(qq_sendpacket, 1); - p->fd = qd->fd; - p->cmd = cmd; - p->send_seq = qd->send_seq; - p->resend_times = 0; - p->sendtime = time(NULL); - p->buf = g_memdup(buf, len); /* don't use g_strdup, may have 0x00 */ - p->len = len; - qd->sendqueue = g_list_append(qd->sendqueue, p); - } - - return bytes_sent; -} - -/* send the packet generated with the given cmd and data - * return the number of bytes sent to socket if succeeds - * return -1 if there is any error */ -gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, - gboolean is_auto_seq, guint16 seq, gboolean need_ack, guint8 *data, gint len) -{ - qq_data *qd; - guint8 *buf, *cursor, *encrypted_data; - guint16 seq_ret; - gint encrypted_len, bytes_written, bytes_expected, bytes_sent; - - qd = (qq_data *) gc->proto_data; - g_return_val_if_fail(qd->session_key != NULL, -1); - - buf = g_newa(guint8, MAX_PACKET_SIZE); - encrypted_len = len + 16; /* at most 16 bytes more */ - encrypted_data = g_newa(guint8, encrypted_len); - cursor = buf; - bytes_written = 0; - - qq_encrypt(data, len, qd->session_key, encrypted_data, &encrypted_len); - - seq_ret = seq; - if (_create_packet_head_seq(buf, &cursor, gc, cmd, is_auto_seq, &seq_ret) >= 0) { - bytes_expected = 4 + encrypted_len + 1; - bytes_written += create_packet_dw(buf, &cursor, (guint32) qd->uid); - bytes_written += create_packet_data(buf, &cursor, encrypted_data, encrypted_len); - bytes_written += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); - if (bytes_written == bytes_expected) { /* packet OK */ - /* if it does not need ACK, we send ACK manually several times */ - if (need_ack) /* my request, send it */ - bytes_sent = _qq_send_packet(gc, buf, cursor - buf, cmd); - else /* server's request, send ACK */ - bytes_sent = qq_proxy_write(qd, buf, cursor - buf); - - if (QQ_DEBUG) - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d] %s, %d bytes\n", seq_ret, qq_get_cmd_desc(cmd), bytes_sent); - return bytes_sent; - } else { /* bad packet */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail creating packet, expect %d bytes, written %d bytes\n", - bytes_expected, bytes_written); - return -1; - } - } - - return -1; -}
--- a/libpurple/protocols/qq/send_core.h Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/** - * @file send_core.h - * - * 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 _QQ_SEND_CORE_H_ -#define _QQ_SEND_CORE_H_ - -#include <glib.h> -#include "connection.h" - -gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 seq, - gboolean need_ack, guint8 *data, gint len); -gint _qq_send_packet(PurpleConnection * gc, guint8 *buf, gint len, guint16 cmd); -gint _create_packet_head_seq(guint8 *buf, guint8 **cursor, - PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 *seq); - -#endif
--- a/libpurple/protocols/qq/send_file.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Mon Jun 30 23:12:54 2008 +0000 @@ -36,7 +36,7 @@ #include "im.h" #include "keep_alive.h" #include "packet_parse.h" -#include "send_core.h" +#include "qq_network.h" #include "utils.h" enum @@ -103,6 +103,7 @@ return send(info->sender_fd, buf, len, 0); } */ + static ssize_t _qq_xfer_udp_send(const guint8 *buf, size_t len, PurpleXfer *xfer) { struct sockaddr_in sin; @@ -155,7 +156,7 @@ gint size; /* FIXME: It seems that the transfer never use a packet * larger than 1500 bytes, so if it happened to be a - * larger packet, either error occured or protocol should + * larger packet, either error occurred or protocol should * be modified */ ft_info *info; @@ -243,42 +244,45 @@ g_free(internet_ip_str); } -void qq_get_conn_info(guint8 *data, guint8 **cursor, gint data_len, ft_info *info) +#define QQ_CONN_INFO_LEN 61 +gint qq_get_conn_info(ft_info *info, guint8 *data) { - read_packet_data(data, cursor, data_len, info->file_session_key, 16); - *cursor += 30; - read_packet_b(data, cursor, data_len, &info->conn_method); - read_packet_dw(data, cursor, data_len, &info->remote_internet_ip); - read_packet_w(data, cursor, data_len, &info->remote_internet_port); - read_packet_w(data, cursor, data_len, &info->remote_major_port); - read_packet_dw(data, cursor, data_len, &info->remote_real_ip); - read_packet_w(data, cursor, data_len, &info->remote_minor_port); + gint bytes = 0; + /* 16 + 30 + 1 + 4 + 2 + 2 + 4 + 2 = 61 */ + bytes += qq_getdata(info->file_session_key, 16, data + bytes); + bytes += 30; /* skip 30 bytes */ + bytes += qq_get8(&info->conn_method, data + bytes); + bytes += qq_get32(&info->remote_internet_ip, data + bytes); + bytes += qq_get16(&info->remote_internet_port, data + bytes); + bytes += qq_get16(&info->remote_major_port, data + bytes); + bytes += qq_get32(&info->remote_real_ip, data + bytes); + bytes += qq_get16(&info->remote_minor_port, data + bytes); qq_show_conn_info(info); + return bytes; } -gint qq_fill_conn_info(guint8 *raw_data, guint8 **cursor, ft_info *info) +gint qq_fill_conn_info(guint8 *raw_data, ft_info *info) { - gint bytes; - bytes = 0; + gint bytes = 0; /* 064: connection method, UDP 0x00, TCP 0x03 */ - bytes += create_packet_b (raw_data, cursor, info->conn_method); + bytes += qq_put8 (raw_data + bytes, info->conn_method); /* 065-068: outer ip address of sender (proxy address) */ - bytes += create_packet_dw (raw_data, cursor, info->local_internet_ip); + bytes += qq_put32 (raw_data + bytes, info->local_internet_ip); /* 069-070: sender port */ - bytes += create_packet_w (raw_data, cursor, info->local_internet_port); + bytes += qq_put16 (raw_data + bytes, info->local_internet_port); /* 071-072: the first listening port(TCP doesn't have this part) */ - bytes += create_packet_w (raw_data, cursor, info->local_major_port); + bytes += qq_put16 (raw_data + bytes, info->local_major_port); /* 073-076: real ip */ - bytes += create_packet_dw (raw_data, cursor, info->local_real_ip); + bytes += qq_put32 (raw_data + bytes, info->local_real_ip); /* 077-078: the second listening port */ - bytes += create_packet_w (raw_data, cursor, info->local_minor_port); + bytes += qq_put16 (raw_data + bytes, info->local_minor_port); return bytes; } /* fill in the common information of file transfer */ static gint _qq_create_packet_file_header -(guint8 *raw_data, guint8 **cursor, guint32 to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack) +(guint8 *raw_data, guint32 to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack) { gint bytes; time_t now; @@ -294,42 +298,42 @@ } /* 000-003: receiver uid */ - bytes += create_packet_dw (raw_data, cursor, qd->uid); + bytes += qq_put32 (raw_data + bytes, qd->uid); /* 004-007: sender uid */ - bytes += create_packet_dw (raw_data, cursor, to_uid); + bytes += qq_put32 (raw_data + bytes, to_uid); /* 008-009: sender client version */ - bytes += create_packet_w (raw_data, cursor, QQ_CLIENT); + bytes += qq_put16 (raw_data + bytes, QQ_CLIENT); /* 010-013: receiver uid */ - bytes += create_packet_dw (raw_data, cursor, qd->uid); + bytes += qq_put32 (raw_data + bytes, qd->uid); /* 014-017: sender uid */ - bytes += create_packet_dw (raw_data, cursor, to_uid); + bytes += qq_put32 (raw_data + bytes, to_uid); /* 018-033: md5 of (uid+session_key) */ - bytes += create_packet_data (raw_data, cursor, qd->session_md5, 16); + bytes += qq_putdata (raw_data + bytes, qd->session_md5, 16); /* 034-035: message type */ - bytes += create_packet_w (raw_data, cursor, message_type); + bytes += qq_put16 (raw_data + bytes, message_type); /* 036-037: sequence number */ - bytes += create_packet_w (raw_data, cursor, seq); + bytes += qq_put16 (raw_data + bytes, seq); /* 038-041: send time */ - bytes += create_packet_dw (raw_data, cursor, (guint32) now); + bytes += qq_put32 (raw_data + bytes, (guint32) now); /* 042-042: always 0x00 */ - bytes += create_packet_b (raw_data, cursor, 0x00); + bytes += qq_put8 (raw_data + bytes, 0x00); /* 043-043: sender icon */ - bytes += create_packet_b (raw_data, cursor, qd->my_icon); + bytes += qq_put8 (raw_data + bytes, qd->my_icon); /* 044-046: always 0x00 */ - bytes += create_packet_w (raw_data, cursor, 0x0000); - bytes += create_packet_b (raw_data, cursor, 0x00); + bytes += qq_put16 (raw_data + bytes, 0x0000); + bytes += qq_put8 (raw_data + bytes, 0x00); /* 047-047: we use font attr */ - bytes += create_packet_b (raw_data, cursor, 0x01); + bytes += qq_put8 (raw_data + bytes, 0x01); /* 048-051: always 0x00 */ - bytes += create_packet_dw (raw_data, cursor, 0x00000000); + bytes += qq_put32 (raw_data + bytes, 0x00000000); /* 052-062: always 0x00 */ - bytes += create_packet_dw (raw_data, cursor, 0x00000000); - bytes += create_packet_dw (raw_data, cursor, 0x00000000); - bytes += create_packet_w (raw_data, cursor, 0x0000); - bytes += create_packet_b (raw_data, cursor, 0x00); + bytes += qq_put32 (raw_data + bytes, 0x00000000); + bytes += qq_put32 (raw_data + bytes, 0x00000000); + bytes += qq_put16 (raw_data + bytes, 0x0000); + bytes += qq_put8 (raw_data + bytes, 0x00); /* 063: transfer_type, 0x65: FILE 0x6b: FACE */ - bytes += create_packet_b (raw_data, cursor, QQ_FILE_TRANSFER_FILE); /* FIXME */ + bytes += qq_put8 (raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME */ return bytes; } @@ -433,7 +437,7 @@ static void _qq_send_packet_file_request (PurpleConnection *gc, guint32 to_uid, gchar *filename, gint filesize) { qq_data *qd; - guint8 *cursor, *raw_data; + guint8 *raw_data; gchar *filelen_str; gint filename_len, filelen_strlen, packet_len, bytes; ft_info *info; @@ -455,27 +459,24 @@ packet_len = 82 + filename_len + filelen_strlen; raw_data = g_newa(guint8, packet_len); - cursor = raw_data; + bytes = 0; - bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, + bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_REQ, qd, FALSE); - bytes += qq_fill_conn_info(raw_data, &cursor, info); + bytes += qq_fill_conn_info(raw_data + bytes, info); /* 079: 0x20 */ - bytes += create_packet_b (raw_data, &cursor, 0x20); + bytes += qq_put8 (raw_data + bytes, 0x20); /* 080: 0x1f */ - bytes += create_packet_b (raw_data, &cursor, 0x1f); + bytes += qq_put8 (raw_data + bytes, 0x1f); /* undetermined len: filename */ - bytes += create_packet_data (raw_data, &cursor, (guint8 *) filename, - filename_len); + bytes += qq_putdata (raw_data + bytes, (guint8 *) filename, filename_len); /* 0x1f */ - bytes += create_packet_b (raw_data, &cursor, 0x1f); + bytes += qq_put8 (raw_data + bytes, 0x1f); /* file length */ - bytes += create_packet_data (raw_data, &cursor, (guint8 *) filelen_str, - filelen_strlen); + bytes += qq_putdata (raw_data + bytes, (guint8 *) filelen_str, filelen_strlen); if (packet_len == bytes) - qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, - cursor - raw_data); + qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); else purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_request", "%d bytes expected but got %d bytes\n", @@ -488,7 +489,7 @@ static void _qq_send_packet_file_accept(PurpleConnection *gc, guint32 to_uid) { qq_data *qd; - guint8 *cursor, *raw_data; + guint8 *raw_data; guint16 minor_port; guint32 real_ip; gint packet_len, bytes; @@ -502,22 +503,21 @@ packet_len = 79; raw_data = g_newa (guint8, packet_len); - cursor = raw_data; + bytes = 0; minor_port = info->local_minor_port; real_ip = info->local_real_ip; info->local_minor_port = 0; info->local_real_ip = 0; - bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, QQ_FILE_TRANS_ACC_UDP, qd, TRUE); - bytes += qq_fill_conn_info(raw_data, &cursor, info); + bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_ACC_UDP, qd, TRUE); + bytes += qq_fill_conn_info(raw_data + bytes, info); info->local_minor_port = minor_port; info->local_real_ip = real_ip; if (packet_len == bytes) - qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, - cursor - raw_data); + qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); else purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_accept", "%d bytes expected but got %d bytes\n", @@ -529,7 +529,7 @@ PurpleXfer *xfer; ft_info *info; qq_data *qd; - guint8 *cursor, *raw_data; + guint8 *raw_data; gint packet_len, bytes; qd = (qq_data *) gc->proto_data; @@ -538,14 +538,13 @@ packet_len = 79; raw_data = g_newa (guint8, packet_len); - cursor = raw_data; + bytes = 0; purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== sending qq file notify ip packet\n"); - bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, QQ_FILE_TRANS_NOTIFY, qd, TRUE); - bytes += qq_fill_conn_info(raw_data, &cursor, info); + bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_NOTIFY, qd, TRUE); + bytes += qq_fill_conn_info(raw_data + bytes, info); if (packet_len == bytes) - qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, - cursor - raw_data); + qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); else purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_notify", "%d bytes expected but got %d bytes\n", @@ -560,7 +559,7 @@ static void _qq_send_packet_file_reject (PurpleConnection *gc, guint32 to_uid) { qq_data *qd; - guint8 *cursor, *raw_data; + guint8 *raw_data; gint packet_len, bytes; purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_reject", "start"); @@ -568,14 +567,12 @@ packet_len = 64; raw_data = g_newa (guint8, packet_len); - cursor = raw_data; bytes = 0; - bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, QQ_FILE_TRANS_DENY_UDP, qd, TRUE); + bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_DENY_UDP, qd, TRUE); if (packet_len == bytes) - qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, - cursor - raw_data); + qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); else purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", "%d bytes expected but got %d bytes\n", @@ -586,7 +583,7 @@ static void _qq_send_packet_file_cancel (PurpleConnection *gc, guint32 to_uid) { qq_data *qd; - guint8 *cursor, *raw_data; + guint8 *raw_data; gint packet_len, bytes; purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "start\n"); @@ -594,17 +591,15 @@ packet_len = 64; raw_data = g_newa (guint8, packet_len); - cursor = raw_data; bytes = 0; purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before create header\n"); - bytes = _qq_create_packet_file_header(raw_data, &cursor, to_uid, QQ_FILE_TRANS_CANCEL, qd, TRUE); + bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_CANCEL, qd, TRUE); purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "end create header\n"); if (packet_len == bytes) { purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before send cmd\n"); - qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, - cursor - raw_data); + qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); } else purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", @@ -688,7 +683,7 @@ } /* process reject im for file transfer request */ -void qq_process_recv_file_reject (guint8 *data, guint8 **cursor, gint data_len, +void qq_process_recv_file_reject (guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc) { gchar *msg, *filename; @@ -698,11 +693,13 @@ qd = (qq_data *) gc->proto_data; g_return_if_fail (qd->xfer != NULL); + /* border has been checked before if (*cursor >= (data + data_len - 1)) { purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received file reject message is empty\n"); return; } + */ filename = strrchr(purple_xfer_get_local_filename(qd->xfer), '/') + 1; msg = g_strdup_printf(_("%d has declined the file %s"), sender_uid, filename); @@ -715,7 +712,7 @@ } /* process cancel im for file transfer request */ -void qq_process_recv_file_cancel (guint8 *data, guint8 **cursor, gint data_len, +void qq_process_recv_file_cancel (guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc) { gchar *msg, *filename; @@ -726,11 +723,13 @@ g_return_if_fail (qd->xfer != NULL && purple_xfer_get_filename(qd->xfer) != NULL); + /* border has been checked before if (*cursor >= (data + data_len - 1)) { purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received file reject message is empty\n"); return; } + */ filename = strrchr(purple_xfer_get_local_filename(qd->xfer), '/') + 1; msg = g_strdup_printf (_("%d canceled the transfer of %s"), @@ -744,27 +743,26 @@ } /* process accept im for file transfer request */ -void qq_process_recv_file_accept(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc) +void qq_process_recv_file_accept(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc) { qq_data *qd; + gint bytes; ft_info *info; PurpleXfer *xfer; g_return_if_fail (data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; xfer = qd->xfer; + info = (ft_info *) qd->xfer->data; - if (*cursor >= (data + data_len - 1)) { + if (data_len <= 30 + QQ_CONN_INFO_LEN) { purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received file reject message is empty\n"); return; } - info = (ft_info *) qd->xfer->data; - - *cursor = data + 18 + 12; - qq_get_conn_info(data, cursor, data_len, info); + bytes = 18 + 12; /* skip 30 bytes */ + qq_get_conn_info(info, data + bytes); _qq_xfer_init_socket(qd->xfer); _qq_xfer_init_udp_channel(info); @@ -772,8 +770,7 @@ } /* process request from buddy's im for file transfer request */ -void qq_process_recv_file_request(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection * gc) +void qq_process_recv_file_request(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection * gc) { qq_data *qd; PurpleXfer *xfer; @@ -781,25 +778,27 @@ ft_info *info; PurpleBuddy *b; qq_buddy *q_bud; + gint bytes; g_return_if_fail (data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - if (*cursor >= (data + data_len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file reject message is empty\n"); - return; - } - - info = g_new0(ft_info, 1); + info = g_newa(ft_info, 1); info->local_internet_ip = g_ntohl(inet_addr(qd->my_ip)); info->local_internet_port = qd->my_port; info->local_real_ip = 0x00000000; info->to_uid = sender_uid; - read_packet_w(data, cursor, data_len, &(info->send_seq)); + + if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { + purple_debug (PURPLE_DEBUG_WARNING, "QQ", + "Received file request message is empty\n"); + return; + } + bytes = 0; + bytes += qq_get16(&(info->send_seq), data + bytes); - *cursor = data + 18 + 12; - qq_get_conn_info(data, cursor, data_len, info); + bytes += 18 + 12; /* skip 30 bytes */ + bytes += qq_get_conn_info(info, data + bytes); fileinfo = g_strsplit((gchar *) (data + 81 + 12), "\x1f", 2); g_return_if_fail (fileinfo != NULL && fileinfo[0] != NULL && fileinfo[1] != NULL); @@ -880,9 +879,10 @@ */ } -void qq_process_recv_file_notify(guint8 *data, guint8 **cursor, gint data_len, +void qq_process_recv_file_notify(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc) { + gint bytes; qq_data *qd; ft_info *info; PurpleXfer *xfer; @@ -890,19 +890,19 @@ g_return_if_fail (data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - if (*cursor >= (data + data_len - 1)) { + xfer = qd->xfer; + info = (ft_info *) qd->xfer->data; + if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received file notify message is empty\n"); return; } + + bytes = 0; + bytes += qq_get16(&(info->send_seq), data + bytes); - xfer = qd->xfer; - info = (ft_info *) qd->xfer->data; - /* FIXME */ - read_packet_w(data, cursor, data_len, &(info->send_seq)); - - *cursor = data + 18 + 12; - qq_get_conn_info(data, cursor, data_len, info); + bytes += 18 + 12; + bytes += qq_get_conn_info(info, data + bytes); _qq_xfer_init_udp_channel(info); @@ -938,7 +938,7 @@ /* static void qq_send_packet_request_key(PurpleConnection *gc, guint8 key) { - qq_send_cmd(gc, QQ_CMD_REQUEST_KEY, TRUE, 0, TRUE, &key, 1); + qq_send_cmd(gc, QQ_CMD_REQUEST_KEY, &key, 1); } static void qq_process_recv_request_key(PurpleConnection *gc)
--- a/libpurple/protocols/qq/send_file.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/send_file.h Mon Jun 30 23:12:54 2008 +0000 @@ -66,20 +66,15 @@ gboolean use_major; } ft_info; -void qq_process_recv_file_accept(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_reject(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_cancel(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_request(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_notify(guint8 *data, guint8 **cursor, gint data_len, - guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_accept(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_reject(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_cancel(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_request(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_notify(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); gboolean qq_can_receive_file(PurpleConnection *gc, const char *who); void qq_send_file(PurpleConnection *gc, const char *who, const char *file); -void qq_get_conn_info(guint8 *data, guint8 **cursor, gint data_len, ft_info *info); -gint qq_fill_conn_info(guint8 *data, guint8 **cursor, ft_info *info); +gint qq_get_conn_info(ft_info *info, guint8 *data); +gint qq_fill_conn_info(guint8 *data, ft_info *info); gssize _qq_xfer_write(const guint8 *buf, size_t len, PurpleXfer *xfer); #endif
--- a/libpurple/protocols/qq/sendqueue.c Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/** - * @file sendqueue.c - * - * 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 - */ - -#include "internal.h" - -#include "connection.h" -#include "debug.h" -#include "notify.h" -#include "prefs.h" -#include "request.h" - -#include "header_info.h" -#include "qq_proxy.h" -#include "sendqueue.h" - -#define QQ_RESEND_MAX 8 /* max resend per packet */ - -typedef struct _gc_and_packet gc_and_packet; - -struct _gc_and_packet { - PurpleConnection *gc; - qq_sendpacket *packet; -}; - -/* Remove a packet with send_seq from sendqueue */ -void qq_sendqueue_remove(qq_data *qd, guint16 send_seq) -{ - GList *list; - qq_sendpacket *p; - - list = qd->sendqueue; - while (list != NULL) { - p = (qq_sendpacket *) (list->data); - if (p->send_seq == send_seq) { - qd->sendqueue = g_list_remove(qd->sendqueue, p); - g_free(p->buf); - g_free(p); - break; - } - list = list->next; - } -} - -/* clean up sendqueue and free all contents */ -void qq_sendqueue_free(qq_data *qd) -{ - qq_sendpacket *p; - gint i; - - i = 0; - while (qd->sendqueue != NULL) { - p = (qq_sendpacket *) (qd->sendqueue->data); - qd->sendqueue = g_list_remove(qd->sendqueue, p); - g_free(p->buf); - g_free(p); - i++; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in sendqueue are freed!\n", i); -} - -/* FIXME We shouldn't be dropping packets, but for now we have to because - * somewhere we're generating invalid packets that the server won't ack. - * Given enough time, a buildup of those packets would crash the client. */ -gboolean qq_sendqueue_timeout_callback(gpointer data) -{ - PurpleConnection *gc; - qq_data *qd; - GList *list; - qq_sendpacket *p; - time_t now; - gint wait_time; - - gc = (PurpleConnection *) data; - qd = (qq_data *) gc->proto_data; - now = time(NULL); - list = qd->sendqueue; - - /* empty queue, return TRUE so that timeout continues functioning */ - if (qd->sendqueue == NULL) - return TRUE; - - while (list != NULL) { /* remove all packet whose resend_times == -1 */ - p = (qq_sendpacket *) list->data; - if (p->resend_times == -1) { /* to remove */ - qd->sendqueue = g_list_remove(qd->sendqueue, p); - g_free(p->buf); - g_free(p); - list = qd->sendqueue; - } else { - list = list->next; - } - } - - list = qd->sendqueue; - while (list != NULL) { - p = (qq_sendpacket *) list->data; - if (p->resend_times == QQ_RESEND_MAX) { /* reach max */ - switch (p->cmd) { - case QQ_CMD_KEEP_ALIVE: - if (qd->logged_in) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection lost!\n"); - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); - qd->logged_in = FALSE; - } - p->resend_times = -1; - break; - case QQ_CMD_LOGIN: - case QQ_CMD_REQUEST_LOGIN_TOKEN: - if (!qd->logged_in) /* cancel login progress */ - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Login failed, no reply")); - p->resend_times = -1; - break; - default:{ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "%s packet sent %d times but not acked. Not resending it.\n", - qq_get_cmd_desc(p->cmd), QQ_RESEND_MAX); - } - p->resend_times = -1; - } - } else { /* resend_times < QQ_RESEND_MAX, so sent it again */ - wait_time = (gint) (QQ_SENDQUEUE_TIMEOUT / 1000); - if (difftime(now, p->sendtime) > (wait_time * (p->resend_times + 1))) { - qq_proxy_write(qd, p->buf, p->len); - p->resend_times++; - purple_debug(PURPLE_DEBUG_INFO, - "QQ", "<<< [%05d] send again for %d times!\n", - p->send_seq, p->resend_times); - } - } - list = list->next; - } - return TRUE; /* if we return FALSE, the timeout callback stops functioning */ -}
--- a/libpurple/protocols/qq/sendqueue.h Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/** - * @file sendqueue.h - * - * 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 _QQ_SEND_QUEUE_H_ -#define _QQ_SEND_QUEUE_H_ - -#include <glib.h> -#include "qq.h" - -#define QQ_SENDQUEUE_TIMEOUT 5000 /* in 1/1000 sec */ - -typedef struct _qq_sendpacket qq_sendpacket; - -struct _qq_sendpacket { - gint fd; - gint len; - guint8 *buf; - guint16 cmd; - guint16 send_seq; - gint resend_times; - time_t sendtime; -}; - -void qq_sendqueue_free(qq_data *qd); - -void qq_sendqueue_remove(qq_data *qd, guint16 send_seq); -gboolean qq_sendqueue_timeout_callback(gpointer data); - -#endif
--- a/libpurple/protocols/qq/sys_msg.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.c Mon Jun 30 23:12:54 2008 +0000 @@ -35,7 +35,7 @@ #include "header_info.h" #include "packet_parse.h" #include "qq.h" -#include "send_core.h" +#include "qq_network.h" #include "sys_msg.h" #include "utils.h" @@ -120,27 +120,29 @@ /* Send ACK if the sys message needs an ACK */ static void _qq_send_packet_ack_msg_sys(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) { - guint8 bar, *ack, *cursor; + qq_data *qd; + guint8 bar, *ack; gchar *str; gint ack_len, bytes; + qd = (qq_data *) gc->proto_data; + str = g_strdup_printf("%d", from); bar = 0x1e; ack_len = 1 + 1 + strlen(str) + 1 + 2; ack = g_newa(guint8, ack_len); - cursor = ack; + bytes = 0; - - bytes += create_packet_b(ack, &cursor, code); - bytes += create_packet_b(ack, &cursor, bar); - bytes += create_packet_data(ack, &cursor, (guint8 *) str, strlen(str)); - bytes += create_packet_b(ack, &cursor, bar); - bytes += create_packet_w(ack, &cursor, seq); + bytes += qq_put8(ack + bytes, code); + bytes += qq_put8(ack + bytes, bar); + bytes += qq_putdata(ack + bytes, (guint8 *) str, strlen(str)); + bytes += qq_put8(ack + bytes, bar); + bytes += qq_put16(ack + bytes, seq); g_free(str); if (bytes == ack_len) /* creation OK */ - qq_send_cmd(gc, QQ_CMD_ACK_SYS_MSG, TRUE, 0, FALSE, ack, ack_len); + qq_send_cmd_detail(qd, QQ_CMD_ACK_SYS_MSG, 0, FALSE, ack, ack_len); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes);
--- a/libpurple/protocols/qq/udp_proxy_s5.c Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/** - * @file udp_proxy_s5.c - * - * 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 - */ - -#include "debug.h" - -#include "udp_proxy_s5.h" - -static void _qq_s5_canread_again(gpointer data, gint source, PurpleInputCondition cond) -{ - unsigned char buf[512]; - struct PHB *phb = data; - struct sockaddr_in sin; - int len, error; - socklen_t errlen; - int flags; - - purple_input_remove(phb->inpa); - purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Able to read again.\n"); - - len = read(source, buf, 10); - if (len < 10) { - purple_debug(PURPLE_DEBUG_WARNING, "socks5 proxy", "or not...\n"); - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, source, NULL); - } - - g_free(phb->host); - g_free(phb); - return; - } - if ((buf[0] != 0x05) || (buf[1] != 0x00)) { - if ((buf[0] == 0x05) && (buf[1] < 0x09)) - purple_debug(PURPLE_DEBUG_ERROR, "socks5 proxy", "socks5 error: %x\n", buf[1]); - else - purple_debug(PURPLE_DEBUG_ERROR, "socks5 proxy", "Bad data.\n"); - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr.s_addr, buf + 4, 4); - memcpy(&sin.sin_port, buf + 8, 2); - - if (connect(phb->udpsock, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) { - purple_debug(PURPLE_DEBUG_INFO, "s5_canread_again", "connect failed: %s\n", g_strerror(errno)); - close(phb->udpsock); - close(source); - g_free(phb->host); - g_free(phb); - return; - } - - error = ETIMEDOUT; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connect didn't block\n"); - errlen = sizeof(error); - if (getsockopt(phb->udpsock, SOL_SOCKET, SO_ERROR, &error, &errlen) < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "getsockopt failed.\n"); - close(phb->udpsock); - return; - } - flags = fcntl(phb->udpsock, F_GETFL); - fcntl(phb->udpsock, F_SETFL, flags & ~O_NONBLOCK); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - phb->func(phb->data, phb->udpsock, NULL); - } - - g_free(phb->host); - g_free(phb); -} - -static void _qq_s5_sendconnect(gpointer data, gint source) -{ - unsigned char buf[512]; - struct PHB *phb = data; - struct sockaddr_in sin, ctlsin; - int port; - socklen_t ctllen; - int flags; - - purple_debug(PURPLE_DEBUG_INFO, "s5_sendconnect", "remote host is %s:%d\n", phb->host, phb->port); - - buf[0] = 0x05; - buf[1] = 0x03; /* udp relay */ - buf[2] = 0x00; /* reserved */ - buf[3] = 0x01; /* address type -- ipv4 */ - memset(buf + 4, 0, 0x04); - - ctllen = sizeof(ctlsin); - if (getsockname(source, (struct sockaddr *) &ctlsin, &ctllen) < 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "getsockname: %s\n", g_strerror(errno)); - close(source); - g_free(phb->host); - g_free(phb); - return; - } - - phb->udpsock = socket(PF_INET, SOCK_DGRAM, 0); - purple_debug(PURPLE_DEBUG_INFO, "s5_sendconnect", "UDP socket=%d\n", phb->udpsock); - if (phb->udpsock < 0) { - close(source); - g_free(phb->host); - g_free(phb); - return; - } - - flags = fcntl(phb->udpsock, F_GETFL); - fcntl(phb->udpsock, F_SETFL, flags | O_NONBLOCK); - - port = g_ntohs(ctlsin.sin_port) + 1; - while (1) { - inet_aton("0.0.0.0", &(sin.sin_addr)); - sin.sin_family = AF_INET; - sin.sin_port = g_htons(port); - if (bind(phb->udpsock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - port++; - if (port > 65500) { - close(source); - g_free(phb->host); - g_free(phb); - return; - } - } else - break; - } - - memset(buf + 4, 0, 0x04); - memcpy(buf + 8, &(sin.sin_port), 0x02); - - if (write(source, buf, 10) < 10) { - close(source); - purple_debug(PURPLE_DEBUG_INFO, "s5_sendconnect", "packet too small\n"); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - phb->inpa = purple_input_add(source, PURPLE_INPUT_READ, _qq_s5_canread_again, phb); -} - -static void _qq_s5_readauth(gpointer data, gint source, PurpleInputCondition cond) -{ - unsigned char buf[512]; - struct PHB *phb = data; - - purple_input_remove(phb->inpa); - purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Got auth response.\n"); - - if (read(source, buf, 2) < 2) { - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - if ((buf[0] != 0x01) || (buf[1] != 0x00)) { - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - _qq_s5_sendconnect(phb, source); -} - -static void _qq_s5_canread(gpointer data, gint source, PurpleInputCondition cond) -{ - unsigned char buf[512]; - struct PHB *phb; - int ret; - - phb = data; - - purple_input_remove(phb->inpa); - purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Able to read.\n"); - - ret = read(source, buf, 2); - if (ret < 2) { - purple_debug(PURPLE_DEBUG_INFO, "s5_canread", "packet smaller than 2 octet\n"); - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - if ((buf[0] != 0x05) || (buf[1] == 0xff)) { - purple_debug(PURPLE_DEBUG_INFO, "s5_canread", "unsupport\n"); - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - if (buf[1] == 0x02) { - unsigned int i, j; - - i = strlen(purple_proxy_info_get_username(phb->gpi)); - j = strlen(purple_proxy_info_get_password(phb->gpi)); - - buf[0] = 0x01; /* version 1 */ - buf[1] = i; - memcpy(buf + 2, purple_proxy_info_get_username(phb->gpi), i); - buf[2 + i] = j; - memcpy(buf + 2 + i + 1, purple_proxy_info_get_password(phb->gpi), j); - - if (write(source, buf, 3 + i + j) < 3 + i + j) { - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - phb->inpa = purple_input_add(source, PURPLE_INPUT_READ, _qq_s5_readauth, phb); - } else { - purple_debug(PURPLE_DEBUG_INFO, "s5_canread", "calling s5_sendconnect\n"); - _qq_s5_sendconnect(phb, source); - } -} - -static void _qq_s5_canwrite(gpointer data, gint source, PurpleInputCondition cond) -{ - unsigned char buf[512]; - int i; - struct PHB *phb = data; - socklen_t len; - int error = ETIMEDOUT; - int flags; - - purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Connected.\n"); - - if (phb->inpa > 0) - purple_input_remove(phb->inpa); - - len = sizeof(error); - if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - purple_debug(PURPLE_DEBUG_INFO, "getsockopt", "%s\n", g_strerror(errno)); - close(source); - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - flags = fcntl(source, F_GETFL); - fcntl(source, F_SETFL, flags & ~O_NONBLOCK); - - i = 0; - buf[0] = 0x05; /* SOCKS version 5 */ - - if (purple_proxy_info_get_username(phb->gpi) != NULL) { - buf[1] = 0x02; /* two methods */ - buf[2] = 0x00; /* no authentication */ - buf[3] = 0x02; /* username/password authentication */ - i = 4; - } else { - buf[1] = 0x01; - buf[2] = 0x00; - i = 3; - } - - if (write(source, buf, i) < i) { - purple_debug(PURPLE_DEBUG_INFO, "write", "%s\n", g_strerror(errno)); - purple_debug(PURPLE_DEBUG_ERROR, "socks5 proxy", "Unable to write\n"); - close(source); - - if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, _("Unable to connect")); - } - - g_free(phb->host); - g_free(phb); - return; - } - - phb->inpa = purple_input_add(source, PURPLE_INPUT_READ, _qq_s5_canread, phb); -} - -gint qq_proxy_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) -{ - gint fd; - int flags; - - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Connecting to %s:%d via %s:%d using SOCKS5\n", - phb->host, phb->port, purple_proxy_info_get_host(phb->gpi), purple_proxy_info_get_port(phb->gpi)); - - if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) - return -1; - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "proxy_sock5 return fd=%d\n", fd); - - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (connect(fd, addr, addrlen) < 0) { - if ((errno == EINPROGRESS) || (errno == EINTR)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n"); - phb->inpa = purple_input_add(fd, PURPLE_INPUT_WRITE, _qq_s5_canwrite, phb); - } else { - close(fd); - return -1; - } - } else { - purple_debug(PURPLE_DEBUG_MISC, "QQ", "Connect in blocking mode.\n"); - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - _qq_s5_canwrite(phb, fd, PURPLE_INPUT_WRITE); - } - - return fd; -}
--- a/libpurple/protocols/qq/udp_proxy_s5.h Mon Jun 30 03:50:35 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/** - * @file udp_proxy_s5.h - * - * 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 _QQ_UDP_PROXY_S5_H_ -#define _QQ_UDP_PROXY_S5_H_ - -#include "internal.h" /* for socket stuff */ - -#include "qq_proxy.h" - -gint qq_proxy_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen); - -#endif
--- a/libpurple/protocols/qq/utils.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Mon Jun 30 23:12:54 2008 +0000 @@ -22,7 +22,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include "cipher.h" #include "limits.h" #include "stdlib.h" #include "string.h" @@ -40,6 +39,17 @@ #define QQ_NAME_FORMAT "%d" +/* These functions are used only in development phase */ +/* + static void _qq_show_socket(gchar *desc, gint fd) { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + getsockname(fd, (struct sockaddr *)&sin, &len); + purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n", + inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); + } + */ + gchar *get_name_by_index_str(gchar **array, const gchar *index_str, gint amount) { gint index; @@ -113,26 +123,6 @@ return segments; } -/* generate a md5 key using uid and session_key */ -guint8 *_gen_session_md5(gint uid, guint8 *session_key) -{ - guint8 *src, md5_str[QQ_KEY_LENGTH]; - PurpleCipher *cipher; - PurpleCipherContext *context; - - src = g_newa(guint8, 20); - memcpy(src, &uid, 4); - memcpy(src, session_key, QQ_KEY_LENGTH); - - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, src, 20); - purple_cipher_context_digest(context, sizeof(md5_str), md5_str, NULL); - purple_cipher_context_destroy(context); - - return g_memdup(md5_str, QQ_KEY_LENGTH); -} - /* given a four-byte ip data, convert it into a human readable ip string * the return needs to be freed */ gchar *gen_ip_str(guint8 *ip) @@ -194,7 +184,7 @@ } /* try to dump the data as GBK */ -void try_dump_as_gbk(const guint8 *const data, gint len) +gchar* try_dump_as_gbk(const guint8 *const data, gint len) { gint i; guint8 *incoming; @@ -215,8 +205,8 @@ if (msg_utf8 != NULL) { purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Try extract GB msg: %s\n", msg_utf8); - g_free(msg_utf8); } + return msg_utf8; } /* strips whitespace */ @@ -294,7 +284,7 @@ /* Dumps a chunk of raw data into an ASCII hex string. * The return should be freed later. */ -gchar *hex_dump_to_str(const guint8 *const buffer, gint bytes) +static gchar *hex_dump_to_str(const guint8 *const buffer, gint bytes) { GString *str; gchar *ret; @@ -331,6 +321,51 @@ return ret; } +void qq_hex_dump(PurpleDebugLevel level, const char *category, + const guint8 *pdata, gint bytes, + const char *format, ...) +{ + va_list args; + char *arg_s = NULL; + gchar *phex = NULL; + + g_return_if_fail(level != PURPLE_DEBUG_ALL); + g_return_if_fail(format != NULL); + + va_start(args, format); + arg_s = g_strdup_vprintf(format, args); + va_end(args); + + if (bytes <= 0) { + purple_debug(level, category, arg_s); + return; + } + + phex = hex_dump_to_str(pdata, bytes); + purple_debug(level, category, "%s - (len %d)\n%s", arg_s, bytes, phex); + g_free(phex); +} + +void qq_show_packet(const gchar *desc, const guint8 *buf, gint len) +{ + /* + char buf1[8*len+2], buf2[10]; + int i; + buf1[0] = 0; + for (i = 0; i < len; i++) { + sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff); + strcat(buf1, buf2); + } + strcat(buf1, "\n"); + purple_debug(PURPLE_DEBUG_INFO, desc, "%s", buf1); + */ + + /* modified by s3e, 20080424 */ + qq_hex_dump(PURPLE_DEBUG_INFO, desc, + buf, len, + ""); +} + /* convert face num from packet (0-299) to local face (1-100) */ gchar *face_to_icon_str(gint face) {
--- a/libpurple/protocols/qq/utils.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/qq/utils.h Mon Jun 30 23:12:54 2008 +0000 @@ -28,12 +28,13 @@ #include <stdio.h> #include <glib.h> +#include "debug.h" + gchar *get_name_by_index_str(gchar **array, const gchar *index_str, gint amount); gchar *get_index_str_by_name(gchar **array, const gchar *name, gint amount); gint qq_string_to_dec_value(const gchar *str); gchar **split_data(guint8 *data, gint len, const gchar *delimit, gint expected_fields); -guint8 *_gen_session_md5(gint uid, guint8 *session_key); gchar *gen_ip_str(guint8 *ip); guint8 *str_ip_gen(gchar *str); @@ -44,10 +45,13 @@ gchar *face_to_icon_str(gint face); -void try_dump_as_gbk(const guint8 *const data, gint len); +gchar *try_dump_as_gbk(const guint8 *const data, gint len); +void qq_show_packet(const gchar *desc, const guint8 *buf, gint len); +void qq_hex_dump(PurpleDebugLevel level, const char *category, + const guint8 *pdata, gint bytes, + const char *format, ...); guint8 *hex_str_to_bytes(const gchar *buf, gint *out_len); -gchar *hex_dump_to_str(const guint8 *buf, gint buf_len); const gchar *qq_buddy_icon_dir(void); const gchar *qq_win32_buddy_icon_dir(void);
--- a/libpurple/protocols/silc/buddy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/silc/buddy.c Mon Jun 30 23:12:54 2008 +0000 @@ -1434,13 +1434,25 @@ void silcpurple_idle_set(PurpleConnection *gc, int idle) { - SilcPurple sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; + SilcPurple sg; + SilcClient client; + SilcClientConnection conn; SilcAttributeObjService service; const char *server; int port; + sg = gc->proto_data; + if (sg == NULL) + return; + + client = sg->client; + if (client == NULL) + return; + + conn = sg->conn; + if (conn == NULL) + return; + server = purple_account_get_string(sg->account, "server", "silc.silcnet.org"); port = purple_account_get_int(sg->account, "port", 706),
--- a/libpurple/protocols/silc10/buddy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/silc10/buddy.c Mon Jun 30 23:12:54 2008 +0000 @@ -1434,13 +1434,25 @@ void silcpurple_idle_set(PurpleConnection *gc, int idle) { - SilcPurple sg = gc->proto_data; - SilcClient client = sg->client; - SilcClientConnection conn = sg->conn; + SilcPurple sg; + SilcClient client; + SilcClientConnection conn; SilcAttributeObjService service; const char *server; int port; + sg = gc->proto_data; + if (sg == NULL) + return; + + client = sg->client; + if (client == NULL) + return; + + conn = sg->conn; + if (conn == NULL) + return; + server = purple_account_get_string(sg->account, "server", "silc.silcnet.org"); port = purple_account_get_int(sg->account, "port", 706),
--- a/libpurple/protocols/simple/simple.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/simple/simple.c Mon Jun 30 23:12:54 2008 +0000 @@ -1898,7 +1898,7 @@ PurpleConnection *gc; struct simple_account_data *sip; gchar **userserver; - gchar *hosttoconnect; + const gchar *hosttoconnect; const char *username = purple_account_get_username(account); gc = purple_account_get_connection(account); @@ -1934,14 +1934,13 @@ sip->status = g_strdup("available"); if(!purple_account_get_bool(account, "useproxy", FALSE)) { - hosttoconnect = g_strdup(sip->servername); + hosttoconnect = sip->servername; } else { - hosttoconnect = g_strdup(purple_account_get_string(account, "proxy", sip->servername)); + hosttoconnect = purple_account_get_string(account, "proxy", sip->servername); } sip->srv_query_data = purple_srv_resolve("sip", sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip); - g_free(hosttoconnect); } static void simple_close(PurpleConnection *gc)
--- a/libpurple/protocols/yahoo/yahoo.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Mon Jun 30 23:12:54 2008 +0000 @@ -777,6 +777,7 @@ list = g_slist_append(list, im); im->from = pair->value; im->time = time(NULL); + im->utf8 = TRUE; } if (pair->key == 97) if (im)
--- a/libpurple/protocols/yahoo/yahoo_picture.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.c Mon Jun 30 23:12:54 2008 +0000 @@ -137,6 +137,9 @@ if (url_data != NULL) { yd = gc->proto_data; yd->url_datas = g_slist_prepend(yd->url_datas, url_data); + } else { + g_free(data->who); + g_free(data); } } else if (who && send_icon_info) { yahoo_send_picture_info(gc, who); @@ -244,13 +247,12 @@ } if (url) { - if (yd->picture_url) - g_free(yd->picture_url); + g_free(yd->picture_url); yd->picture_url = g_strdup(url); purple_account_set_string(account, YAHOO_PICURL_SETTING, url); purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum); + yahoo_send_picture_checksum(gc); yahoo_send_picture_update(gc, 2); - yahoo_send_picture_checksum(gc); } } @@ -402,8 +404,15 @@ if (ret < 0 && errno == EAGAIN) return; - else if (ret <= 0) + else if (ret <= 0) { + purple_debug_info("yahoo", "Buddy icon upload response (%d) bytes (> ~400 indicates failure):\n%.*s\n", + d->str->len, d->str->len, d->str->str); + yahoo_buddy_icon_upload_data_free(d); + return; + } + + g_string_append_len(d->str, buf, ret); } static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, PurpleInputCondition condition) @@ -421,6 +430,7 @@ if (wrote < 0 && errno == EAGAIN) return; if (wrote <= 0) { + purple_debug_info("yahoo", "Error uploading buddy icon.\n"); yahoo_buddy_icon_upload_data_free(d); return; } @@ -428,6 +438,9 @@ if (d->pos >= d->str->len) { purple_debug_misc("yahoo", "Finished uploading buddy icon.\n"); purple_input_remove(d->watcher); + /* Clean out the sent buffer and reuse it to read the result */ + g_string_free(d->str, TRUE); + d->str = g_string_new(""); d->watcher = purple_input_add(d->fd, PURPLE_INPUT_READ, yahoo_buddy_icon_upload_reading, d); } } @@ -436,16 +449,16 @@ { struct yahoo_buddy_icon_upload_data *d = data; struct yahoo_packet *pkt; - gchar *size, *header; + gchar *tmp, *header; guchar *pkt_buf; const char *host; int port; - size_t content_length, pkt_buf_len; - PurpleConnection *gc; + gsize pkt_buf_len; + PurpleConnection *gc = d->gc; PurpleAccount *account; struct yahoo_data *yd; + gboolean use_whole_url = FALSE; - gc = d->gc; account = purple_connection_get_account(gc); yd = gc->proto_data; @@ -457,44 +470,55 @@ yahoo_buddy_icon_upload_data_free(d); return; } + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) + && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; - pkt = yahoo_packet_new(0xc2, YAHOO_STATUS_AVAILABLE, yd->session_id); + pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id); - size = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len); + tmp = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len); /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */ yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); yahoo_packet_hash_str(pkt, 38, "604800"); /* time til expire */ purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800); yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc)); - yahoo_packet_hash_str(pkt, 28, size); - g_free(size); + yahoo_packet_hash_str(pkt, 28, tmp); + g_free(tmp); yahoo_packet_hash_str(pkt, 27, d->filename); yahoo_packet_hash_str(pkt, 14, ""); + /* 4 padding for the 29 key name */ + pkt_buf_len = yahoo_packet_build(pkt, 4, FALSE, yd->jp, &pkt_buf); + yahoo_packet_free(pkt); - content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); + /* header + packet + "29" + 0xc0 + 0x80) + pictureblob */ host = purple_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); - header = g_strdup_printf( - "POST http://%s:%d/notifyft HTTP/1.0\r\n" - "Content-length: %" G_GSIZE_FORMAT "\r\n" - "Host: %s:%d\r\n" - "Cookie: Y=%s; T=%s\r\n" - "\r\n", - host, port, content_length + 4 + d->str->len, - host, port, yd->cookie_y, yd->cookie_t); + tmp = g_strdup_printf("%s:%d", host, port); + header = g_strdup_printf("POST %s%s/notifyft HTTP/1.1\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n" + "Cookie: T=%s; Y=%s\r\n" + "Host: %s\r\n" + "Content-Length: %" G_GSIZE_FORMAT "\r\n" + "Cache-Control: no-cache\r\n\r\n", + use_whole_url ? "http://" : "", use_whole_url ? tmp : "", + yd->cookie_t, yd->cookie_y, + tmp, + pkt_buf_len + 4 + d->str->len); + g_free(tmp); /* There's no magic here, we just need to prepend in reverse order */ g_string_prepend(d->str, "29\xc0\x80"); - pkt_buf_len = yahoo_packet_build(pkt, 8, FALSE, yd->jp, &pkt_buf); - yahoo_packet_free(pkt); g_string_prepend_len(d->str, (char *)pkt_buf, pkt_buf_len); g_free(pkt_buf); g_string_prepend(d->str, header); g_free(header); + purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", d->str->len, d->str->str); + d->fd = source; d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d); @@ -525,6 +549,28 @@ } } +static int yahoo_buddy_icon_calculate_checksum(const guchar *data, gsize len) +{ + /* This code is borrowed from Kopete, which seems to be managing to calculate + checksums in such a manner that Yahoo!'s servers are happy */ + + const guchar *p = data; + int checksum = 0, g, i = len; + + while(i--) { + checksum = (checksum << 4) + *p++; + + if((g = (checksum & 0xf0000000)) != 0) + checksum ^= g >> 23; + + checksum &= ~g; + } + + purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d", checksum); + + return checksum; +} + void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { struct yahoo_data *yd = gc->proto_data; @@ -534,6 +580,8 @@ g_free(yd->picture_url); yd->picture_url = NULL; + /* TODO: don't we have to clear it on the server too?! */ + purple_account_set_string(account, YAHOO_PICURL_SETTING, NULL); purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0); purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0); @@ -549,14 +597,8 @@ int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL); - char *iconfile; - /* TODO: At some point, it'd be nice to fix this for real, or - * TODO: at least change it to be something like: - * TODO: purple_imgstore_get_filename(img); - * TODO: But it would be great if we knew how to calculate the - * TODO: Checksum correctly. */ - yd->picture_checksum = g_string_hash(s); + yd->picture_checksum = yahoo_buddy_icon_calculate_checksum(data, len); if ((yd->picture_checksum == oldcksum) && (expire > (time(NULL) + 60*60*24)) && oldurl) @@ -569,12 +611,11 @@ } /* We use this solely for sending a filename to the server */ - iconfile = g_strdup(purple_imgstore_get_filename(img)); d = g_new0(struct yahoo_buddy_icon_upload_data, 1); d->gc = gc; d->str = s; d->fd = -1; - d->filename = iconfile; + d->filename = g_strdup(purple_imgstore_get_filename(img)); if (!yd->logged_in) { yd->picture_upload_todo = d;
--- a/libpurple/protocols/yahoo/yahoo_profile.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_profile.c Mon Jun 30 23:12:54 2008 +0000 @@ -745,6 +745,7 @@ p += 1; /* skip only the ' ' */ q = strchr(p, ' '); if (q) { + g_free(it); it = g_strndup(p, q - p); } }
--- a/libpurple/proxy.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/proxy.c Mon Jun 30 23:12:54 2008 +0000 @@ -265,6 +265,7 @@ "'manual' but no proxy server is specified. Using " "Pidgin's proxy settings instead.\n"); g_free(info.host); + info.host = NULL; return purple_global_proxy_get_info(); } @@ -272,6 +273,7 @@ &info.username, NULL, NULL, NULL)) { g_free(info.host); + info.host = NULL; return purple_global_proxy_get_info(); } g_strchomp(info.username); @@ -280,7 +282,9 @@ &info.password, NULL, NULL, NULL)) { g_free(info.host); + info.host = NULL; g_free(info.username); + info.username = NULL; return purple_global_proxy_get_info(); } g_strchomp(info.password); @@ -289,8 +293,11 @@ &tmp, NULL, NULL, NULL)) { g_free(info.host); + info.host = NULL; g_free(info.username); + info.username = NULL; g_free(info.password); + info.password = NULL; return purple_global_proxy_get_info(); } info.port = atoi(tmp);
--- a/libpurple/proxy.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/proxy.h Mon Jun 30 23:12:54 2008 +0000 @@ -239,9 +239,9 @@ * to something descriptive (hopefully). * @param data User-defined data. * - * @return NULL if there was an error, or a reference to a data - * structure that can be used to cancel the pending - * connection, if needed. + * @return NULL if there was an error, or a reference to an + * opaque data structure that can be used to cancel + * the pending connection, if needed. */ PurpleProxyConnectData *purple_proxy_connect(void *handle, PurpleAccount *account, @@ -265,9 +265,9 @@ * to something descriptive (hopefully). * @param data User-defined data. * - * @return NULL if there was an error, or a reference to a data - * structure that can be used to cancel the pending - * connection, if needed. + * @return NULL if there was an error, or a reference to an + * opaque data structure that can be used to cancel + * the pending connection, if needed. */ PurpleProxyConnectData *purple_proxy_connect_socks5(void *handle, PurpleProxyInfo *gpi,
--- a/libpurple/prpl.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/prpl.h Mon Jun 30 23:12:54 2008 +0000 @@ -31,6 +31,7 @@ #define _PURPLE_PRPL_H_ typedef struct _PurplePluginProtocolInfo PurplePluginProtocolInfo; +/** @copydoc _PurpleAttentionType */ typedef struct _PurpleAttentionType PurpleAttentionType; /**************************************************************************/ @@ -99,6 +100,9 @@ gboolean secret; }; +/** Represents "nudges" and "buzzes" that you may send to a buddy to attract + * their attention (or vice-versa). + */ struct _PurpleAttentionType { const char *name; /**< Shown in GUI elements */
--- a/libpurple/roomlist.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/roomlist.h Mon Jun 30 23:12:54 2008 +0000 @@ -30,6 +30,7 @@ typedef struct _PurpleRoomlist PurpleRoomlist; typedef struct _PurpleRoomlistRoom PurpleRoomlistRoom; typedef struct _PurpleRoomlistField PurpleRoomlistField; +/** @copydoc _PurpleRoomlistUiOps */ typedef struct _PurpleRoomlistUiOps PurpleRoomlistUiOps; /**
--- a/libpurple/server.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/server.c Mon Jun 30 23:12:54 2008 +0000 @@ -151,7 +151,6 @@ */ auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply"); if((gc->flags & PURPLE_CONNECTION_AUTO_RESP) && - flags & PURPLE_MESSAGE_AUTO_RESP && !purple_presence_is_available(presence) && strcmp(auto_reply_pref, "never")) { @@ -728,6 +727,7 @@ PurpleStatusPrimitive primitive; const gchar *auto_reply_pref; const char *away_msg = NULL; + gboolean mobile = FALSE; auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply"); @@ -735,9 +735,10 @@ status = purple_presence_get_active_status(presence); status_type = purple_status_get_type(status); primitive = purple_status_type_get_primitive(status_type); + mobile = purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE); if ((primitive == PURPLE_STATUS_AVAILABLE) || (primitive == PURPLE_STATUS_INVISIBLE) || - (primitive == PURPLE_STATUS_MOBILE) || + mobile || !strcmp(auto_reply_pref, "never") || (!purple_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle"))) {
--- a/libpurple/smiley.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/smiley.c Mon Jun 30 23:12:54 2008 +0000 @@ -641,10 +641,9 @@ old_filename = purple_imgstore_get_filename(old_img); new_filename = purple_imgstore_get_filename(smiley->img); - if (g_ascii_strcasecmp(old_filename, new_filename)) { + if (g_ascii_strcasecmp(old_filename, new_filename)) purple_smiley_data_unstore(old_filename); - purple_imgstore_unref(old_img); - } + purple_imgstore_unref(old_img); }
--- a/libpurple/sound.h Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/sound.h Mon Jun 30 23:12:54 2008 +0000 @@ -55,6 +55,9 @@ } PurpleSoundEventID; +/** Operations used by the core to request that particular sound files, or the + * sound associated with a particular event, should be played. + */ typedef struct _PurpleSoundUiOps { void (*init)(void);
--- a/libpurple/status.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/status.c Mon Jun 30 23:12:54 2008 +0000 @@ -107,8 +107,6 @@ PurpleStatusType *type; PurplePresence *presence; - const char *title; - gboolean active; /*
--- a/libpurple/util.c Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/util.c Mon Jun 30 23:12:54 2008 +0000 @@ -832,6 +832,11 @@ if (offset_positive) tzoff *= -1; } + else if ((*c == 'Z') && (c = c + 1)) + { + /* 'Z' = Zulu = UTC */ + tzoff = 0; + } else if (utc) { static struct tm tmptm; @@ -1357,6 +1362,14 @@ GString *cdata = NULL; GList *tags = NULL, *tag; const char *c = html; + char quote = '\0'; + +#define CHECK_QUOTE(ptr) if (*(ptr) == '\'' || *(ptr) == '\"') \ + quote = *(ptr++); \ + else \ + quote = '\0'; + +#define VALID_CHAR(ptr) (*(ptr) && *(ptr) != quote && (quote || (*(ptr) != ' ' && *(ptr) != '>'))) g_return_if_fail(xhtml_out != NULL || plain_out != NULL); @@ -1514,38 +1527,37 @@ xhtml = g_string_append(xhtml, "<span style='vertical-align:super;'>"); continue; } - if(!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) { + const char *p = c + 4; GString *src = NULL, *alt = NULL; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "src=", strlen("src="))) { - const char *q = p + strlen("src="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "src=", 4)) { + const char *q = p + 4; if (src) g_string_free(src, TRUE); src = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { src = g_string_append_c(src, *q); q++; } p = q; - } else if(!g_ascii_strncasecmp(p, "alt=", strlen("alt="))) { - const char *q = p + strlen("alt="); + } else if (!g_ascii_strncasecmp(p, "alt=", 4)) { + const char *q = p + 4; if (alt) g_string_free(alt, TRUE); alt = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { alt = g_string_append_c(alt, *q); q++; } p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1562,21 +1574,20 @@ g_string_free(src, TRUE); continue; } - if(!g_ascii_strncasecmp(c, "<a", 2) && (*(c+2) == '>' || *(c+2) == ' ')) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<a", 2) && (*(c+2) == '>' || *(c+2) == ' ')) { + const char *p = c + 2; struct purple_parse_tag *pt; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "href=", strlen("href="))) { - const char *q = p + strlen("href="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "href=", 5)) { + const char *q = p + 5; if (url) g_string_free(url, TRUE); url = g_string_new(""); if (cdata) g_string_free(cdata, TRUE); cdata = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { int len; if ((*q == '&') && (purple_markup_unescape_entity(q, &len) == NULL)) url = g_string_append(url, "&"); @@ -1585,10 +1596,11 @@ q++; } p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1601,55 +1613,48 @@ continue; } if(!g_ascii_strncasecmp(c, "<font", 5) && (*(c+5) == '>' || *(c+5) == ' ')) { - const char *p = c; + const char *p = c + 5; GString *style = g_string_new(""); struct purple_parse_tag *pt; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "back=", strlen("back="))) { - const char *q = p + strlen("back="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "back=", 5)) { + const char *q = p + 5; GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } g_string_append_printf(style, "background: %s; ", color->str); g_string_free(color, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "color=", strlen("color="))) { - const char *q = p + strlen("color="); + } else if (!g_ascii_strncasecmp(p, "color=", 6)) { + const char *q = p + 6; GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } g_string_append_printf(style, "color: %s; ", color->str); g_string_free(color, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "face=", strlen("face="))) { - const char *q = p + strlen("face="); - gboolean space_allowed = FALSE; + } else if (!g_ascii_strncasecmp(p, "face=", 5)) { + const char *q = p + 5; GString *face = g_string_new(""); - if(*q == '\'' || *q == '\"') { - space_allowed = TRUE; - q++; - } - while(*q && *q != '\"' && *q != '\'' && (space_allowed || *q != ' ')) { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { face = g_string_append_c(face, *q); q++; } g_string_append_printf(style, "font-family: %s; ", g_strstrip(face->str)); g_string_free(face, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "size=", strlen("size="))) { - const char *q = p + strlen("size="); + } else if (!g_ascii_strncasecmp(p, "size=", 5)) { + const char *q = p + 5; int sz; const char *size = "medium"; - if(*q == '\'' || *q == '\"') - q++; + CHECK_QUOTE(q); sz = atoi(q); switch (sz) { @@ -1679,10 +1684,11 @@ } g_string_append_printf(style, "font-size: %s; ", size); p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1697,24 +1703,23 @@ g_string_free(style, TRUE); continue; } - if(!g_ascii_strncasecmp(c, "<body ", 6)) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<body ", 6)) { + const char *p = c + 6; gboolean did_something = FALSE; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "bgcolor=", strlen("bgcolor="))) { - const char *q = p + strlen("bgcolor="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "bgcolor=", 8)) { + const char *q = p + 8; struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1); GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } - if(xhtml) + if (xhtml) g_string_append_printf(xhtml, "<span style='background: %s;'>", g_strstrip(color->str)); g_string_free(color, TRUE); - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1726,7 +1731,7 @@ } p++; } - if(did_something) continue; + if (did_something) continue; } /* this has to come after the special case for bgcolor */ ALLOW_TAG("body"); @@ -1789,6 +1794,8 @@ g_string_free(url, TRUE); if (cdata) g_string_free(cdata, TRUE); +#undef CHECK_QUOTE +#undef VALID_CHAR } /* The following are probably reasonable changes: @@ -3529,7 +3536,7 @@ static void url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message); static gboolean -parse_redirect(const char *data, size_t data_len, gint sock, +parse_redirect(const char *data, size_t data_len, PurpleUtilFetchUrlData *gfud) { gchar *s; @@ -3703,7 +3710,7 @@ header_len, gfud->webdata); /* See if we can find a redirect. */ - if(parse_redirect(gfud->webdata, header_len, source, gfud)) + if(parse_redirect(gfud->webdata, header_len, gfud)) return; gfud->got_headers = TRUE;
--- a/libpurple/win32/global.mak Mon Jun 30 03:50:35 2008 +0000 +++ b/libpurple/win32/global.mak Mon Jun 30 23:12:54 2008 +0000 @@ -112,4 +112,4 @@ MINGW_MAKEFILE := Makefile.mingw INSTALL_PIXMAPS ?= 1 - +INSTALL_SSL_CERTIFICATES ?= 1
--- a/pidgin/gtkaccount.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkaccount.c Mon Jun 30 23:12:54 2008 +0000 @@ -2191,8 +2191,7 @@ G_TYPE_STRING, /* COLUMN_SCREENNAME */ G_TYPE_BOOLEAN, /* COLUMN_ENABLED */ G_TYPE_STRING, /* COLUMN_PROTOCOL */ - G_TYPE_POINTER, /* COLUMN_DATA */ - G_TYPE_POINTER /* COLUMN_PULSE_DATA */ + G_TYPE_POINTER /* COLUMN_DATA */ ); /* And now the actual treeview */
--- a/pidgin/gtkblist.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkblist.c Mon Jun 30 23:12:54 2008 +0000 @@ -130,6 +130,7 @@ static guint visibility_manager_count = 0; static GdkVisibilityState gtk_blist_visibility = GDK_VISIBILITY_UNOBSCURED; +static gboolean gtk_blist_focused = FALSE; static gboolean editing_blist = FALSE; static GList *pidgin_blist_sort_methods = NULL; @@ -3259,18 +3260,18 @@ /* Accounts menu */ { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, - { N_("/Accounts/Manage"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, + { N_("/Accounts/Manage Accounts"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, /* Tools */ { N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL }, { N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 1, "<Item>", NULL }, { N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL }, - { N_("/Tools/Smile_y"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY }, { N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS }, { N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES }, { N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL }, + { N_("/Tools/Smile_y"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY }, { "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL }, - { N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<Item>", NULL }, + { N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER }, { N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL }, { N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "<Item>", NULL }, { "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL }, @@ -5166,9 +5167,14 @@ /******************************************/ static int -blist_focus_cb(GtkWidget *widget, gpointer data, PidginBuddyList *gtkblist) -{ - pidgin_set_urgent(GTK_WINDOW(gtkblist->window), FALSE); +blist_focus_cb(GtkWidget *widget, GdkEventFocus *event, PidginBuddyList *gtkblist) +{ + if(event->in) { + gtk_blist_focused = TRUE; + pidgin_set_urgent(GTK_WINDOW(gtkblist->window), FALSE); + } else { + gtk_blist_focused = FALSE; + } return 0; } @@ -5255,6 +5261,8 @@ gtkblist->window = pidgin_create_window(_("Buddy List"), 0, "buddy_list", TRUE); g_signal_connect(G_OBJECT(gtkblist->window), "focus-in-event", G_CALLBACK(blist_focus_cb), gtkblist); + g_signal_connect(G_OBJECT(gtkblist->window), "focus-out-event", + G_CALLBACK(blist_focus_cb), gtkblist); GTK_WINDOW(gtkblist->window)->allow_shrink = TRUE; gtkblist->main_vbox = gtk_vbox_new(FALSE, 0); @@ -5305,7 +5313,7 @@ tmp = g_strdup_printf(_("<span weight='bold' size='larger'>Welcome to %s!</span>\n\n" "You have no accounts enabled. Enable your IM accounts from the " - "<b>Accounts</b> window at <b>Accounts->Manage</b>. Once you " + "<b>Accounts</b> window at <b>Accounts->Manage Accounts</b>. Once you " "enable accounts, you'll be able to sign on, set your status, " "and talk to your friends."), PIDGIN_NAME); pretty = pidgin_make_pretty_arrows(tmp); @@ -6474,6 +6482,10 @@ purple_blist_add_buddy(b, NULL, g, NULL); purple_account_add_buddy(data->account, b); + /* Offer to merge people with the same alias. */ + if (whoalias != NULL) + gtk_blist_auto_personize((PurpleBlistNode *)g, whoalias); + /* * XXX * It really seems like it would be better if the call to @@ -6984,8 +6996,15 @@ { if (gtkblist && gtkblist->window) { if (GTK_WIDGET_VISIBLE(gtkblist->window)) { + /* make the buddy list visible if it is iconified or if it is + * obscured and not currently focused (the focus part ensures + * that we do something reasonable if the buddy list is obscured + * by a window set to always be on top), otherwise hide the + * buddy list + */ purple_blist_set_visible(PIDGIN_WINDOW_ICONIFIED(gtkblist->window) || - gtk_blist_visibility != GDK_VISIBILITY_UNOBSCURED); + ((gtk_blist_visibility != GDK_VISIBILITY_UNOBSCURED) && + !gtk_blist_focused)); } else { purple_blist_set_visible(TRUE); } @@ -7609,12 +7628,58 @@ for (l = gtk_container_get_children(GTK_CONTAINER(accountmenu)); l; l = g_list_delete_link(l, l)) { menuitem = l->data; - if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage"))) + if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage Accounts"))) gtk_widget_destroy(menuitem); } for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) { char *buf = NULL; + GtkWidget *image = NULL; + PurpleAccount *account = NULL; + GdkPixbuf *pixbuf = NULL; + + account = accounts->data; + + if(!purple_account_get_enabled(account, PIDGIN_UI)) { + if (!disabled_accounts) { + menuitem = gtk_menu_item_new_with_label(_("Enable Account")); + gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem); + gtk_widget_show(menuitem); + + submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group); + gtk_menu_set_accel_path(GTK_MENU(submenu), N_("<PurpleMain>/Accounts/Enable Account")); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); + gtk_widget_show(submenu); + + disabled_accounts = TRUE; + } + + buf = g_strconcat(purple_account_get_username(account), " (", + purple_account_get_protocol_name(account), ")", NULL); + menuitem = gtk_image_menu_item_new_with_label(buf); + g_free(buf); + pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + if (pixbuf != NULL) + { + if (!purple_account_is_connected(account)) + gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(G_OBJECT(pixbuf)); + gtk_widget_show(image); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); + } + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(enable_account_cb), account); + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); + gtk_widget_show(menuitem); + } + } + + pidgin_separator(accountmenu); + + for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) { + char *buf = NULL; char *accel_path_buf = NULL; GtkWidget *image = NULL; PurpleConnection *gc = NULL; @@ -7684,51 +7749,6 @@ } } - if(disabled_accounts) { - pidgin_separator(accountmenu); - menuitem = gtk_menu_item_new_with_label(_("Enable Account")); - gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem); - gtk_widget_show(menuitem); - - submenu = gtk_menu_new(); - gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group); - gtk_menu_set_accel_path(GTK_MENU(submenu), N_("<PurpleMain>/Accounts/Enable Account")); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); - gtk_widget_show(submenu); - - for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) { - char *buf = NULL; - GtkWidget *image = NULL; - PurpleAccount *account = NULL; - GdkPixbuf *pixbuf = NULL; - - account = accounts->data; - - if(!purple_account_get_enabled(account, PIDGIN_UI)) { - - disabled_accounts = TRUE; - - buf = g_strconcat(purple_account_get_username(account), " (", - purple_account_get_protocol_name(account), ")", NULL); - menuitem = gtk_image_menu_item_new_with_label(buf); - g_free(buf); - pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); - if (pixbuf != NULL) - { - if (!purple_account_is_connected(account)) - gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(G_OBJECT(pixbuf)); - gtk_widget_show(image); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); - } - g_signal_connect(G_OBJECT(menuitem), "activate", - G_CALLBACK(enable_account_cb), account); - gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); - gtk_widget_show(menuitem); - } - } - } } static GList *plugin_submenus = NULL;
--- a/pidgin/gtkconv.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkconv.c Mon Jun 30 23:12:54 2008 +0000 @@ -1481,7 +1481,7 @@ PurpleAccount *account; PurpleConnection *gc; PurplePluginProtocolInfo *prpl_info = NULL; - char *real_who; + gchar *real_who = NULL; account = purple_conversation_get_account(conv); g_return_if_fail(account != NULL); @@ -1494,13 +1494,11 @@ if (prpl_info && prpl_info->get_cb_real_name) real_who = prpl_info->get_cb_real_name(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who); - else - real_who = g_strdup(who); - - if(!real_who) + + if(!who && !real_who) return; - pidgin_dialogs_im_with_user(account, real_who); + pidgin_dialogs_im_with_user(account, real_who ? real_who : who); g_free(real_who); } @@ -1539,11 +1537,22 @@ static void menu_chat_send_file_cb(GtkWidget *w, PidginConversation *gtkconv) { + PurplePluginProtocolInfo *prpl_info; PurpleConversation *conv = gtkconv->active_conv; const char *who = g_object_get_data(G_OBJECT(w), "user_data"); PurpleConnection *gc = purple_conversation_get_gc(conv); - - serv_send_file(gc, who, NULL); + gchar *real_who = NULL; + + g_return_if_fail(gc != NULL); + + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + + if (prpl_info && prpl_info->get_cb_real_name) + real_who = prpl_info->get_cb_real_name(gc, + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who); + + serv_send_file(gc, real_who ? real_who : who, NULL); + g_free(real_who); } static void @@ -1659,23 +1668,34 @@ if (gc == NULL) gtk_widget_set_sensitive(button, FALSE); - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); if (prpl_info && prpl_info->send_file) { + gboolean can_receive_file = TRUE; + button = pidgin_new_item_from_stock(menu, _("Send File"), PIDGIN_STOCK_TOOLBAR_SEND_FILE, G_CALLBACK(menu_chat_send_file_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); - if (gc == NULL || prpl_info == NULL || - !(!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who))) - { + if (gc == NULL || prpl_info == NULL) + can_receive_file = FALSE; + else { + gchar *real_who = NULL; + if (prpl_info->get_cb_real_name) + real_who = prpl_info->get_cb_real_name(gc, + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who); + if (!(!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, real_who ? real_who : who))) + can_receive_file = FALSE; + g_free(real_who); + } + + if (!can_receive_file) gtk_widget_set_sensitive(button, FALSE); - } - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } @@ -1688,8 +1708,8 @@ if (gc == NULL) gtk_widget_set_sensitive(button, FALSE); - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } if (prpl_info && (prpl_info->get_info || prpl_info->get_cb_info)) { @@ -1698,8 +1718,8 @@ if (gc == NULL) gtk_widget_set_sensitive(button, FALSE); - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } if (prpl_info && prpl_info->get_cb_away) { @@ -1708,8 +1728,8 @@ if (gc == NULL) gtk_widget_set_sensitive(button, FALSE); - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } if (!is_me && prpl_info && !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { @@ -1722,8 +1742,8 @@ if (gc == NULL) gtk_widget_set_sensitive(button, FALSE); - - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); + else + g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } button = pidgin_new_item_from_stock(menu, _("Last said"), GTK_STOCK_INDEX, @@ -3156,7 +3176,8 @@ PurpleAccount *account = purple_conversation_get_account(conv); PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account)); PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); - if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, chat_info_defaults)) { + if (purple_account_get_connection(account) != NULL && + PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, chat_info_defaults)) { components = prpl_info->chat_info_defaults(purple_account_get_connection(account), purple_conversation_get_name(conv)); } else {
--- a/pidgin/gtkdialogs.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkdialogs.c Mon Jun 30 23:12:54 2008 +0000 @@ -75,7 +75,7 @@ {"Thomas Butter", N_("developer"), NULL}, {"Ka-Hing Cheung", N_("developer"), NULL}, {"Sadrul Habib Chowdhury", N_("developer"), NULL}, - {"Mark 'KingAnt' Doliner", N_("developer"), NULL}, + {"Mark 'KingAnt' Doliner", N_("developer"), "mark@kingant.net"}, {"Sean Egan", N_("developer"), "sean.egan@gmail.com"}, {"Casey Harkins", N_("developer"), NULL}, {"Gary 'grim' Kramlich", N_("developer"), NULL},
--- a/pidgin/gtkft.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkft.c Mon Jun 30 23:12:54 2008 +0000 @@ -226,8 +226,10 @@ total_pct = 100 * total_bytes_xferred / total_file_size; } - title = g_strdup_printf(_("File Transfers - %d%% of %d files"), - total_pct, num_active_xfers); + title = g_strdup_printf(ngettext("File Transfers - %d%% of %d file", + "File Transfers - %d%% of %d files", + num_active_xfers), + total_pct, num_active_xfers); gtk_window_set_title(GTK_WINDOW(dialog->window), title); g_free(title); } else {
--- a/pidgin/gtkimhtml.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkimhtml.c Mon Jun 30 23:12:54 2008 +0000 @@ -514,6 +514,7 @@ tmp); g_free(tmp); + g_object_unref(layout); return FALSE; } @@ -551,6 +552,7 @@ gtk_widget_show (imhtml->tip_window); pango_font_metrics_unref(font_metrics); + g_object_unref(font); g_object_unref(layout); return FALSE; @@ -766,7 +768,7 @@ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &end, buf_x + event->area.width, buf_y + event->area.height); - + gtk_text_iter_order(&start, &end); cur = start; @@ -4864,7 +4866,7 @@ gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), ebox ? ebox : icon, anchor); } else if (imhtml_smiley != NULL && (imhtml->format_functions & GTK_IMHTML_SMILEY)) { anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); - imhtml_smiley->anchors = g_slist_append(imhtml_smiley->anchors, anchor); + imhtml_smiley->anchors = g_slist_append(imhtml_smiley->anchors, g_object_ref(anchor)); if (ebox) { GtkWidget *img = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU); char *text = g_strdup(unescaped); @@ -5023,9 +5025,9 @@ str += g_snprintf(str, sizeof(buf) - (str - buf), "color: #%02x%02x%02x;", color->red >> 8, color->green >> 8, color->blue >> 8); - gdk_color_free(color); empty = FALSE; } + gdk_color_free(color); /* Background color */ g_object_get(obj, "background-set", &isset, "background-gdk", &color, NULL); @@ -5033,9 +5035,9 @@ str += g_snprintf(str, sizeof(buf) - (str - buf), "background: #%02x%02x%02x;", color->red >> 8, color->green >> 8, color->blue >> 8); - gdk_color_free(color); empty = FALSE; } + gdk_color_free(color); /* Underline */ g_object_get(obj, "underline-set", &isset, "underline", &ivalue, NULL); @@ -5046,6 +5048,7 @@ break; default: str += g_snprintf(str, sizeof(buf) - (str - buf), "text-decoration: underline;"); + empty = FALSE; } } @@ -5097,6 +5100,38 @@ } } +typedef struct { + GtkTextTag *tag; + char *end; + char *start; +} PidginTextTagData; + +static PidginTextTagData *text_tag_data_new(GtkTextTag *tag) +{ + const char *start, *end; + PidginTextTagData *ret = NULL; + + start = tag_to_html_start(tag); + if (!start || !*start) + return NULL; + end = tag_to_html_end(tag); + if (!end || !*end) + return NULL; + + ret = g_new0(PidginTextTagData, 1); + ret->start = g_strdup(start); + ret->end = g_strdup(end); + ret->tag = tag; + return ret; +} + +static void text_tag_data_destroy(PidginTextTagData *data) +{ + g_free(data->start); + g_free(data->end); + g_free(data); +} + static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) { return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && @@ -5117,12 +5152,11 @@ gboolean is_rtl_message = FALSE; GString *str = g_string_new(""); GSList *tags, *sl; - GQueue *q, *r; + GQueue *q; GtkTextTag *tag; + PidginTextTagData *tagdata; q = g_queue_new(); - r = g_queue_new(); - gtk_text_iter_order(start, end); non_neutral_iter = next_iter = iter = *start; @@ -5145,9 +5179,11 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { - if (strlen(tag_to_html_end(tag)) > 0) - g_string_append(str, tag_to_html_start(tag)); - g_queue_push_tail(q, tag); + PidginTextTagData *data = text_tag_data_new(tag); + if (data) { + g_string_append(str, data->start); + g_queue_push_tail(q, data); + } } } g_slist_free(tags); @@ -5159,13 +5195,14 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { - if (strlen(tag_to_html_end(tag)) > 0) - g_string_append(str, tag_to_html_start(tag)); - g_queue_push_tail(q, tag); + PidginTextTagData *data = text_tag_data_new(tag); + if (data) { + g_string_append(str, data->start); + g_queue_push_tail(q, data); + } } } - if (c == 0xFFFC) { GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); if (anchor) { @@ -5191,28 +5228,33 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; /** don't worry about non-printing tags ending */ - if (tag_ends_here(tag, &iter, &next_iter) && strlen(tag_to_html_end(tag)) > 0) { - - GtkTextTag *tmp; - - while ((tmp = g_queue_pop_tail(q)) != tag) { - if (tmp == NULL) - break; - - if (!tag_ends_here(tmp, &iter, &next_iter) && strlen(tag_to_html_end(tmp)) > 0) + if (tag_ends_here(tag, &iter, &next_iter) && + strlen(tag_to_html_end(tag)) > 0 && + strlen(tag_to_html_start(tag)) > 0) { + + PidginTextTagData *tmp; + GQueue *r = g_queue_new(); + + while ((tmp = g_queue_pop_tail(q)) && tmp->tag != tag) { + g_string_append(str, tmp->end); + if (!tag_ends_here(tmp->tag, &iter, &next_iter)) g_queue_push_tail(r, tmp); - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); + else + text_tag_data_destroy(tmp); } if (tmp == NULL) purple_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); - else - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); + else { + g_string_append(str, tmp->end); + text_tag_data_destroy(tmp); + } while ((tmp = g_queue_pop_head(r))) { - g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); + g_string_append(str, tmp->start); g_queue_push_tail(q, tmp); } + g_queue_free(r); } } @@ -5221,15 +5263,16 @@ gtk_text_iter_forward_char(&next_iter); } - while ((tag = g_queue_pop_tail(q))) - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); + while ((tagdata = g_queue_pop_tail(q))) { + g_string_append(str, tagdata->end); + text_tag_data_destroy(tagdata); + } /* Bi-directional text support - close tags */ if (is_rtl_message) g_string_append(str, "</SPAN>"); g_queue_free(q); - g_queue_free(r); return g_string_free(str, FALSE); } @@ -5465,8 +5508,11 @@ } for (current = smiley->anchors; current; current = g_slist_next(current)) { - - icon = gtk_image_new_from_animation(smiley->icon); + anchor = GTK_TEXT_CHILD_ANCHOR(current->data); + if (gtk_text_child_anchor_get_deleted(anchor)) + icon = NULL; + else + icon = gtk_image_new_from_animation(smiley->icon); #ifdef DEBUG_CUSTOM_SMILEY purple_debug_info("custom-smiley", "gtk_custom_smiley_closed(): got GtkImage %p from GtkPixbufAnimation %p for smiley '%s'\n", @@ -5476,7 +5522,6 @@ GList *wids; gtk_widget_show(icon); - anchor = GTK_TEXT_CHILD_ANCHOR(current->data); wids = gtk_text_child_anchor_get_widgets(anchor); g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", purple_unescape_html(smiley->smile), g_free); @@ -5493,7 +5538,7 @@ } g_list_free(wids); } - + g_object_unref(anchor); } g_slist_free(smiley->anchors);
--- a/pidgin/gtkimhtml.h Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkimhtml.h Mon Jun 30 23:12:54 2008 +0000 @@ -854,11 +854,36 @@ */ void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags); +/** + * Create a new GtkIMHtmlSmiley. + * + * @param file The image file for the smiley + * @param shortcut The key shortcut for the smiley + * @param hide @c TRUE if the smiley should be hidden in the smiley dialog, @c FALSE otherwise + * @param flags The smiley flags + * + * @return The newly created smiley + * @since 2.5.0 + */ GtkIMHtmlSmiley *gtk_imhtml_smiley_create(const char *file, const char *shortcut, gboolean hide, GtkIMHtmlSmileyFlags flags); +/** + * Reload the image data for the smiley. + * + * @param smiley The smiley to reload + * + * @since 2.5.0 + */ void gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley); +/** + * Destroy a GtkIMHtmlSmiley. + * + * @param smiley The smiley to destroy + * + * @since 2.5.0 + */ void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley); /*@}*/
--- a/pidgin/gtkimhtmltoolbar.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Mon Jun 30 23:12:54 2008 +0000 @@ -614,8 +614,7 @@ static struct smiley_button_list * sort_smileys(struct smiley_button_list *ls, GtkIMHtmlToolbar *toolbar, - int *width, const GtkIMHtmlSmiley *smiley, - const GSList *custom_smileys) + int *width, const GtkIMHtmlSmiley *smiley) { GtkWidget *image; GtkWidget *button; @@ -625,6 +624,7 @@ const gchar *filename = smiley->file; gchar *face = smiley->smile; PurpleSmiley *psmiley = NULL; + gboolean supports_custom = (gtk_imhtml_get_format_functions(GTK_IMHTML(toolbar->imhtml)) & GTK_IMHTML_CUSTOM_SMILEY); cur = g_new0(struct smiley_button_list, 1); it = ls; @@ -678,10 +678,12 @@ /* If this is a "non-custom" smiley, check to see if its shortcut is "shadowed" by any custom smiley. This can only happen if the connection is custom smiley-enabled */ - if (psmiley && !(smiley->flags & GTK_IMHTML_SMILEY_CUSTOM)) { - gtk_tooltips_set_tip(toolbar->tooltips, button, - _("This smiley is disabled because a custom smiley exists for this shortcut."), - NULL); + if (supports_custom && psmiley && !(smiley->flags & GTK_IMHTML_SMILEY_CUSTOM)) { + gchar tip[128]; + g_snprintf(tip, sizeof(tip), + _("This smiley is disabled because a custom smiley exists for this shortcut:\n %s"), + face); + gtk_tooltips_set_tip(toolbar->tooltips, button, tip, NULL); gtk_widget_set_sensitive(button, FALSE); } else if (psmiley) { /* Remove the button if the smiley is destroyed */ @@ -783,11 +785,14 @@ else smileys = pidgin_themes_get_proto_smileys(NULL); + /* Note: prepend smileys to list to avoid O(n^2) overhead when there is + a large number of smileys... need to revers the list after for the dialog + work... */ while(smileys) { GtkIMHtmlSmiley *smiley = (GtkIMHtmlSmiley *) smileys->data; if(!smiley->hidden) { if(smiley_is_unique(unique_smileys, smiley)) { - unique_smileys = g_slist_append(unique_smileys, smiley); + unique_smileys = g_slist_prepend(unique_smileys, smiley); } } smileys = smileys->next; @@ -800,9 +805,12 @@ for (iterator = custom_smileys ; iterator ; iterator = g_slist_next(iterator)) { GtkIMHtmlSmiley *smiley = (GtkIMHtmlSmiley *) iterator->data; - unique_smileys = g_slist_append(unique_smileys, smiley); + unique_smileys = g_slist_prepend(unique_smileys, smiley); } } + + /* we need to reverse the list to get the smileys in the correct order */ + unique_smileys = g_slist_reverse(unique_smileys); dialog = pidgin_create_dialog(_("Smile!"), 0, "smiley_dialog", FALSE); gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE); @@ -834,7 +842,7 @@ while (unique_smileys) { GtkIMHtmlSmiley *smiley = (GtkIMHtmlSmiley *) unique_smileys->data; if (!smiley->hidden) { - ls = sort_smileys(ls, toolbar, &max_line_width, smiley, custom_smileys); + ls = sort_smileys(ls, toolbar, &max_line_width, smiley); } unique_smileys = g_slist_delete_link(unique_smileys, unique_smileys); }
--- a/pidgin/gtkmenutray.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkmenutray.c Mon Jun 30 23:12:54 2008 +0000 @@ -84,19 +84,24 @@ } static void -pidgin_menu_tray_finalize(GObject *obj) { +pidgin_menu_tray_finalize(GObject *obj) +{ + PidginMenuTray *tray = PIDGIN_MENU_TRAY(obj); #if 0 /* This _might_ be leaking, but I have a sneaking suspicion that the widget is * getting destroyed in GtkContainer's finalize function. But if were are * leaking here, be sure to figure out why this causes a crash. * -- Gary */ - PidginMenuTray *tray = PIDGIN_MENU_TRAY(obj); if(GTK_IS_WIDGET(tray->tray)) gtk_widget_destroy(GTK_WIDGET(tray->tray)); #endif + if (tray->tooltips) { + gtk_object_sink(GTK_OBJECT(tray->tooltips)); + } + G_OBJECT_CLASS(parent_class)->finalize(obj); }
--- a/pidgin/gtksavedstatuses.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtksavedstatuses.c Mon Jun 30 23:12:54 2008 +0000 @@ -59,6 +59,7 @@ STATUS_WINDOW_COLUMN_MESSAGE, /** A hidden column containing a pointer to the editor for this saved status. */ STATUS_WINDOW_COLUMN_WINDOW, + STATUS_WINDOW_COLUMN_ICON, STATUS_WINDOW_NUM_COLUMNS }; @@ -80,6 +81,7 @@ STATUS_EDITOR_COLUMN_STATUS_ID, STATUS_EDITOR_COLUMN_STATUS_NAME, STATUS_EDITOR_COLUMN_STATUS_MESSAGE, + STATUS_EDITOR_COLUMN_STATUS_ICON, STATUS_EDITOR_NUM_COLUMNS }; @@ -392,12 +394,35 @@ g_list_free(sel_paths); } +static const gchar * +get_stock_icon_from_primitive(PurpleStatusPrimitive type) +{ + switch (type) { + case PURPLE_STATUS_AVAILABLE: + return PIDGIN_STOCK_STATUS_AVAILABLE; + case PURPLE_STATUS_AWAY: + return PIDGIN_STOCK_STATUS_AWAY; + case PURPLE_STATUS_EXTENDED_AWAY: + return PIDGIN_STOCK_STATUS_XA; + case PURPLE_STATUS_INVISIBLE: + return PIDGIN_STOCK_STATUS_INVISIBLE; + case PURPLE_STATUS_OFFLINE: + return PIDGIN_STOCK_STATUS_OFFLINE; + case PURPLE_STATUS_UNAVAILABLE: + return PIDGIN_STOCK_STATUS_BUSY; + default: + /* this shouldn't happen */ + return NULL; + } +} + static void add_status_to_saved_status_list(GtkListStore *model, PurpleSavedStatus *saved_status) { GtkTreeIter iter; const char *title; const char *type; + const gchar *icon; char *message; if (purple_savedstatus_is_transient(saved_status)) @@ -406,14 +431,16 @@ title = purple_savedstatus_get_title(saved_status); type = purple_primitive_get_name_from_type(purple_savedstatus_get_type(saved_status)); message = purple_markup_strip_html(purple_savedstatus_get_message(saved_status)); + icon = get_stock_icon_from_primitive(purple_savedstatus_get_type(saved_status)); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, + STATUS_WINDOW_COLUMN_ICON, icon, STATUS_WINDOW_COLUMN_TITLE, title, STATUS_WINDOW_COLUMN_TYPE, type, STATUS_WINDOW_COLUMN_MESSAGE, message, -1); - free(message); + g_free(message); } static void @@ -479,7 +506,8 @@ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER); + G_TYPE_POINTER, + G_TYPE_STRING); /* Create the treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); @@ -517,6 +545,10 @@ gtk_tree_view_column_set_sort_column_id(column, STATUS_WINDOW_COLUMN_TYPE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, "stock-id", + STATUS_WINDOW_COLUMN_ICON); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", @@ -717,8 +749,8 @@ } -static gboolean -status_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +static void +status_editor_destroy_cb(GtkWidget *widget, gpointer user_data) { StatusEditor *dialog = user_data; @@ -726,19 +758,13 @@ g_free(dialog->original_title); g_object_unref(G_OBJECT(dialog->model)); g_free(dialog); - - return FALSE; } static void status_editor_cancel_cb(GtkButton *button, gpointer user_data) { StatusEditor *dialog = user_data; - - status_editor_remove_dialog(dialog); gtk_widget_destroy(dialog->window); - g_free(dialog->original_title); - g_free(dialog); } static void @@ -842,20 +868,11 @@ g_free(message); g_free(unformatted); - status_editor_remove_dialog(dialog); - gtk_widget_destroy(dialog->window); - g_free(dialog->original_title); - -/* - if (status_window != NULL) - add_status_to_saved_status_list(status_window->model, saved_status); -*/ - /* If they clicked on "Save & Use" or "Use," then activate the status */ if (button != dialog->save_button) purple_savedstatus_activate(saved_status); - g_free(dialog); + gtk_widget_destroy(dialog->window); } static void @@ -871,6 +888,26 @@ } static GtkWidget * +create_stock_item(const gchar *str, const gchar *icon) +{ + GtkWidget *menuitem = gtk_menu_item_new(); + GtkWidget *label = gtk_label_new_with_mnemonic(str); + GtkWidget *hbox = gtk_hbox_new(FALSE, 4); + GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); + GtkWidget *image = gtk_image_new_from_stock(icon, icon_size);; + + gtk_widget_show(label); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(menuitem), hbox); + + return menuitem; +} + +static GtkWidget * create_status_type_menu(PurpleStatusPrimitive type) { int i; @@ -889,7 +926,9 @@ * status types, so don't show them in the list. */ continue; - item = gtk_menu_item_new_with_label(purple_primitive_get_name_from_type(i)); + + item = create_stock_item(purple_primitive_get_name_from_type(i), + get_stock_icon_from_primitive(i)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } @@ -945,6 +984,7 @@ STATUS_EDITOR_COLUMN_STATUS_ID, NULL, STATUS_EDITOR_COLUMN_STATUS_NAME, NULL, STATUS_EDITOR_COLUMN_STATUS_MESSAGE, NULL, + STATUS_EDITOR_COLUMN_STATUS_ICON, NULL, -1); } } @@ -990,6 +1030,10 @@ gtk_tree_view_column_set_title(column, _("Status")); gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); gtk_tree_view_column_set_resizable(column, TRUE); + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_add_attribute(column, renderer, "stock-id", + STATUS_EDITOR_COLUMN_STATUS_ICON); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", @@ -1016,6 +1060,7 @@ { GdkPixbuf *pixbuf; const char *id = NULL, *name = NULL, *message = NULL; + PurpleStatusPrimitive prim = PURPLE_STATUS_UNSET; pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM); if ((pixbuf != NULL) && !purple_account_is_connected(account)) @@ -1030,6 +1075,7 @@ type = purple_savedstatus_substatus_get_type(substatus); id = purple_status_type_get_id(type); name = purple_status_type_get_name(type); + prim = purple_status_type_get_primitive(type); if (purple_status_type_get_attr(type, "message")) message = purple_savedstatus_substatus_get_message(substatus); } @@ -1042,6 +1088,7 @@ STATUS_EDITOR_COLUMN_STATUS_ID, id, STATUS_EDITOR_COLUMN_STATUS_NAME, name, STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, + STATUS_EDITOR_COLUMN_STATUS_ICON, get_stock_icon_from_primitive(prim), -1); if (pixbuf != NULL) @@ -1133,7 +1180,7 @@ dialog->window = win = pidgin_create_dialog(_("Status"), PIDGIN_HIG_BORDER, "status", TRUE); - g_signal_connect(G_OBJECT(win), "delete_event", + g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(status_editor_destroy_cb), dialog); /* Setup the vbox */ @@ -1198,6 +1245,7 @@ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING); /* Create the treeview */ @@ -1325,25 +1373,20 @@ } } -static gboolean -substatus_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +static void +substatus_editor_destroy_cb(GtkWidget *widget, gpointer user_data) { SubStatusEditor *dialog = user_data; substatus_editor_remove_dialog(dialog); g_free(dialog); - - return FALSE; } static void substatus_editor_cancel_cb(GtkButton *button, gpointer user_data) { SubStatusEditor *dialog = user_data; - - substatus_editor_remove_dialog(dialog); gtk_widget_destroy(dialog->window); - g_free(dialog); } @@ -1356,12 +1399,11 @@ PurpleStatusType *type; char *id = NULL; char *message = NULL; - const char *name = NULL; + const char *name = NULL, *stock = NULL; if (!gtk_combo_box_get_active_iter(dialog->box, &iter)) { gtk_widget_destroy(dialog->window); - g_free(dialog); return; } @@ -1372,6 +1414,7 @@ if (purple_status_type_get_attr(type, "message") != NULL) message = gtk_imhtml_get_markup(GTK_IMHTML(dialog->message)); name = purple_status_type_get_name(type); + stock = get_stock_icon_from_primitive(purple_status_type_get_primitive(type)); status_editor = dialog->status_editor; @@ -1383,13 +1426,13 @@ STATUS_EDITOR_COLUMN_STATUS_NAME, name, STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, STATUS_EDITOR_COLUMN_WINDOW, NULL, + STATUS_EDITOR_COLUMN_STATUS_ICON, stock, -1); } gtk_widget_destroy(dialog->window); g_free(id); g_free(message); - g_free(dialog); } static void @@ -1438,7 +1481,7 @@ dialog->window = win = pidgin_create_dialog(tmp, PIDGIN_HIG_BORDER, "substatus", TRUE); g_free(tmp); - g_signal_connect(G_OBJECT(win), "delete_event", + g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(substatus_editor_destroy_cb), dialog); /* Setup the vbox */ @@ -1679,6 +1722,96 @@ return currently_selected; } +static void +pidgin_status_menu_update_iter(GtkWidget *combobox, GtkListStore *store, GtkTreeIter *iter, + PurpleSavedStatus *status) +{ + GdkPixbuf *pixbuf; + + if (store == NULL) + store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox))); + + pixbuf = pidgin_create_status_icon(purple_savedstatus_get_type(status), + combobox, PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); + gtk_list_store_set(store, iter, + SS_MENU_TYPE_COLUMN, SS_MENU_ENTRY_TYPE_SAVEDSTATUS, + SS_MENU_ICON_COLUMN, pixbuf, + SS_MENU_TEXT_COLUMN, purple_savedstatus_get_title(status), + SS_MENU_DATA_COLUMN, GINT_TO_POINTER(purple_savedstatus_get_creation_time(status)), + SS_MENU_EMBLEM_COLUMN, GTK_STOCK_SAVE, + SS_MENU_EMBLEM_VISIBLE_COLUMN, TRUE, + -1); + if (pixbuf) + g_object_unref(G_OBJECT(pixbuf)); +} + +static gboolean +pidgin_status_menu_find_iter(GtkListStore *store, GtkTreeIter *iter, PurpleSavedStatus *find) +{ + int type; + gpointer data; + time_t creation_time = purple_savedstatus_get_creation_time(find); + GtkTreeModel *model = GTK_TREE_MODEL(store); + + if (!gtk_tree_model_get_iter_first(model, iter)) + return FALSE; + + do { + gtk_tree_model_get(model, iter, + SS_MENU_TYPE_COLUMN, &type, + SS_MENU_DATA_COLUMN, &data, + -1); + if (type == SS_MENU_ENTRY_TYPE_PRIMITIVE) + continue; + if (GPOINTER_TO_INT(data) == creation_time) + return TRUE; + } while (gtk_tree_model_iter_next(model, iter)); + + return FALSE; +} + +static void +savedstatus_added_cb(PurpleSavedStatus *status, GtkWidget *combobox) +{ + GtkListStore *store; + GtkTreeIter iter; + + if (purple_savedstatus_is_transient(status)) + return; + + store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox))); + gtk_list_store_append(store, &iter); + pidgin_status_menu_update_iter(combobox, store, &iter, status); +} + +static void +savedstatus_deleted_cb(PurpleSavedStatus *status, GtkWidget *combobox) +{ + GtkListStore *store; + GtkTreeIter iter; + + if (purple_savedstatus_is_transient(status)) + return; + + store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox))); + if (pidgin_status_menu_find_iter(store, &iter, status)) + gtk_list_store_remove(store, &iter); +} + +static void +savedstatus_modified_cb(PurpleSavedStatus *status, GtkWidget *combobox) +{ + GtkListStore *store; + GtkTreeIter iter; + + if (purple_savedstatus_is_transient(status)) + return; + + store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox))); + if (pidgin_status_menu_find_iter(store, &iter, status)) + pidgin_status_menu_update_iter(combobox, store, &iter, status); +} + GtkWidget *pidgin_status_menu(PurpleSavedStatus *current_status, GCallback callback) { GtkWidget *combobox; @@ -1686,7 +1819,6 @@ GList *sorted, *cur; int i = 0; int index = -1; - GdkPixbuf *pixbuf; GtkTreeIter iter; GtkCellRenderer *text_rend; GtkCellRenderer *icon_rend; @@ -1720,18 +1852,9 @@ PurpleSavedStatus *status = (PurpleSavedStatus *) cur->data; if (!purple_savedstatus_is_transient(status)) { - pixbuf = pidgin_create_status_icon(purple_savedstatus_get_type(status), - combobox, PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - SS_MENU_TYPE_COLUMN, SS_MENU_ENTRY_TYPE_SAVEDSTATUS, - SS_MENU_ICON_COLUMN, pixbuf, - SS_MENU_TEXT_COLUMN, purple_savedstatus_get_title(status), - SS_MENU_DATA_COLUMN, GINT_TO_POINTER(purple_savedstatus_get_creation_time(status)), - SS_MENU_EMBLEM_COLUMN, GTK_STOCK_SAVE, - SS_MENU_EMBLEM_VISIBLE_COLUMN, TRUE, - -1); - g_object_unref(G_OBJECT(pixbuf)); + + pidgin_status_menu_update_iter(combobox, model, &iter, status); if (status == current_status) index = i; @@ -1756,6 +1879,17 @@ gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index); g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(status_menu_cb), callback); + /* Make sure the list is updated dynamically when a substatus is changed/deleted + * or a new one is added. */ + purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-added", + combobox, G_CALLBACK(savedstatus_added_cb), combobox); + purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-deleted", + combobox, G_CALLBACK(savedstatus_deleted_cb), combobox); + purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-modified", + combobox, G_CALLBACK(savedstatus_modified_cb), combobox); + g_signal_connect(G_OBJECT(combobox), "destroy", + G_CALLBACK(purple_signals_disconnect_by_handle), NULL); + return combobox; }
--- a/pidgin/gtksmiley.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtksmiley.c Mon Jun 30 23:12:54 2008 +0000 @@ -96,6 +96,18 @@ gtksmiley->smile = g_strdup(purple_smiley_get_shortcut(smiley)); } +static void +image_changed_cb(PurpleSmiley *smiley, gpointer dontcare, GtkIMHtmlSmiley *gtksmiley) +{ + const char *file; + + g_free(gtksmiley->file); + + file = purple_imgstore_get_filename(purple_smiley_get_stored_image(smiley)); + gtksmiley->file = g_build_filename(purple_smileys_get_storing_dir(), file, NULL); + gtk_imhtml_smiley_reload(gtksmiley); +} + static GtkIMHtmlSmiley *smiley_purple_to_gtkimhtml(PurpleSmiley *smiley) { GtkIMHtmlSmiley *gtksmiley; @@ -114,6 +126,10 @@ g_signal_connect(G_OBJECT(smiley), "notify::shortcut", G_CALLBACK(shortcut_changed_cb), gtksmiley); + /* And update the pixbuf too when the image is changed */ + g_signal_connect(G_OBJECT(smiley), "notify::image", + G_CALLBACK(image_changed_cb), gtksmiley); + return gtksmiley; }
--- a/pidgin/gtkstatusbox.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkstatusbox.c Mon Jun 30 23:12:54 2008 +0000 @@ -209,7 +209,8 @@ for (l = purple_account_get_status_types(account); l != NULL; l = l->next) { PurpleStatusType *status_type = (PurpleStatusType *)l->data; - if (!purple_status_type_is_user_settable(status_type)) + if (!purple_status_type_is_user_settable(status_type) || + purple_status_type_is_independent(status_type)) continue; status_no++; if (statustype == status_type) @@ -769,7 +770,8 @@ for (i = 0; l; l = l->next) { PurpleStatusType *status_type = l->data; - if (!purple_status_type_is_user_settable(status_type)) + if (!purple_status_type_is_user_settable(status_type) || + purple_status_type_is_independent(status_type)) continue; if (active == i) @@ -1030,12 +1032,13 @@ PurpleStatusType *status_type = (PurpleStatusType *)l->data; PurpleStatusPrimitive prim; - if (!purple_status_type_is_user_settable(status_type)) + if (!purple_status_type_is_user_settable(status_type) || + purple_status_type_is_independent(status_type)) continue; - prim = purple_status_type_get_primitive(status_type); - - pixbuf = pidgin_status_box_get_pixbuf(status_box, prim); + prim = purple_status_type_get_primitive(status_type); + + pixbuf = pidgin_status_box_get_pixbuf(status_box, prim); pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf, @@ -1706,6 +1709,48 @@ } static void +treeview_cursor_changed_cb(GtkTreeView *treeview, gpointer data) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (treeview); + GtkTreeModel *model = GTK_TREE_MODEL (data); + GtkTreeIter iter; + GtkTreePath *cursor; + GtkTreePath *selection; + gint cmp; + + if (gtk_tree_selection_get_selected (sel, NULL, &iter)) { + if ((selection = gtk_tree_model_get_path (model, &iter)) == NULL) { + /* Shouldn't happen, but ignore anyway */ + return; + } + } else { + /* I don't think this can happen, but we'll just ignore it */ + return; + } + + gtk_tree_view_get_cursor (treeview, &cursor, NULL); + if (cursor == NULL) { + /* Probably won't happen in a 'cursor-changed' event? */ + gtk_tree_path_free (selection); + return; + } + + cmp = gtk_tree_path_compare (cursor, selection); + if (cmp < 0) { + /* The cursor moved up without moving the selection, so move it up again */ + gtk_tree_path_prev (cursor); + gtk_tree_view_set_cursor (treeview, cursor, NULL, FALSE); + } else if (cmp > 0) { + /* The cursor moved down without moving the selection, so move it down again */ + gtk_tree_path_next (cursor); + gtk_tree_view_set_cursor (treeview, cursor, NULL, FALSE); + } + + gtk_tree_path_free (selection); + gtk_tree_path_free (cursor); +} + +static void pidgin_status_box_init (PidginStatusBox *status_box) { GtkCellRenderer *text_rend; @@ -1869,6 +1914,8 @@ G_CALLBACK(imhtml_scroll_event_cb), status_box->imhtml); g_signal_connect(G_OBJECT(status_box->popup_window), "button_release_event", G_CALLBACK(treeview_button_release_cb), status_box); g_signal_connect(G_OBJECT(status_box->popup_window), "key_press_event", G_CALLBACK(treeview_key_press_event), status_box); + g_signal_connect(G_OBJECT(status_box->tree_view), "cursor-changed", + G_CALLBACK(treeview_cursor_changed_cb), status_box->dropdown_store); #if GTK_CHECK_VERSION(2,6,0) gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(status_box->tree_view), dropdown_store_row_separator_func, NULL, NULL);
--- a/pidgin/gtkutils.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/gtkutils.c Mon Jun 30 23:12:54 2008 +0000 @@ -1001,13 +1001,14 @@ } prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(conn->prpl); + if (prpl_info != NULL && prpl_info->get_cb_real_name) + who = prpl_info->get_cb_real_name(conn, chat, name); if (prpl_info == NULL || prpl_info->get_cb_info == NULL) { - pidgin_retrieve_user_info(conn, name); + pidgin_retrieve_user_info(conn, who ? who : name); + g_free(who); return; } - if (prpl_info->get_cb_real_name) - who = prpl_info->get_cb_real_name(conn, chat, name); show_retrieveing_info(conn, who ? who : name); prpl_info->get_cb_info(conn, chat, name); g_free(who);
--- a/pidgin/pidginstock.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pidginstock.c Mon Jun 30 23:12:54 2008 +0000 @@ -168,6 +168,7 @@ { PIDGIN_STOCK_TOOLBAR_UNBLOCK, "toolbar", "unblock.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR, "toolbar", "select-avatar.png", FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_TOOLBAR_SEND_FILE, "toolbar", "send-file.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TOOLBAR_TRANSFER, "toolbar", "transfer.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_TRAY_INVISIBLE, "tray", "tray-invisible.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
--- a/pidgin/pidginstock.h Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pidginstock.h Mon Jun 30 23:12:54 2008 +0000 @@ -129,6 +129,7 @@ #define PIDGIN_STOCK_TOOLBAR_UNBLOCK "pidgin-unblock" #define PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR "pidgin-select-avatar" #define PIDGIN_STOCK_TOOLBAR_SEND_FILE "pidgin-send-file" +#define PIDGIN_STOCK_TOOLBAR_TRANSFER "pidgin-transfer" /* Tray icons */ #define PIDGIN_STOCK_TRAY_AVAILABLE "pidgin-tray-available"
--- a/pidgin/pixmaps/Makefile.am Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/Makefile.am Mon Jun 30 23:12:54 2008 +0000 @@ -565,6 +565,7 @@ toolbar/16/message-new.png \ toolbar/16/plugins.png \ toolbar/16/send-file.png \ + toolbar/16/transfer.png \ toolbar/16/unblock.png TOOLBAR_22_SCALABLE = \
--- a/pidgin/pixmaps/status/16/scalable/available.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/available.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,7 +2,7 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" @@ -13,9 +13,9 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.45" + inkscape:version="0.46+devel" version="1.0" - inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/available.png" + inkscape:export-filename="/home/hbons/Desktop/available.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" @@ -26,6 +26,25 @@ id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient3286"> + <stop + style="stop-color:#459000;stop-opacity:1" + offset="0" + id="stop3288" /> + <stop + style="stop-color:#204300;stop-opacity:1" + offset="1" + id="stop3290" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective43" /> + <linearGradient + inkscape:collect="always" id="linearGradient2898"> <stop style="stop-color:white;stop-opacity:1;" @@ -50,10 +69,10 @@ xlink:href="#linearGradient3149" id="linearGradient4740" gradientUnits="userSpaceOnUse" - x1="15.498499" - y1="9.4211226" - x2="24.240097" - y2="36.603138" /> + x1="11.127699" + y1="10.823074" + x2="30.341434" + y2="31.325201" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient3149" @@ -230,6 +249,39 @@ fx="31.112698" fy="19.008621" r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3286" + id="linearGradient3292" + x1="15.893391" + y1="15.213944" + x2="26.533659" + y2="28.579245" + gradientUnits="userSpaceOnUse" /> + <filter + inkscape:collect="always" + id="filter3360" + x="-0.13093077" + width="1.2618615" + y="-0.11042095" + height="1.2208419"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="0.19314814" + id="feGaussianBlur3362" /> + </filter> + <filter + inkscape:collect="always" + id="filter3374" + x="-0.13117394" + width="1.2623479" + y="-0.11015608" + height="1.2203122"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="0.19309804" + id="feGaussianBlur3376" /> + </filter> </defs> <sodipodi:namedview id="base" @@ -239,16 +291,27 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="4.1907826" - inkscape:cy="8.6773979" + inkscape:cx="12.058565" + inkscape:cy="10.562588" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1274" - inkscape:window-height="844" - inkscape:window-x="3" - inkscape:window-y="25" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" + inkscape:snap-bbox="true" + inkscape:snap-nodes="false" + objecttolerance="13" + gridtolerance="10"> + <inkscape:grid + type="xygrid" + id="grid3284" + empspacing="5" + visible="true" + enabled="true" /> + </sodipodi:namedview> <metadata id="metadata7"> <rdf:RDF> @@ -265,14 +328,24 @@ inkscape:groupmode="layer" id="layer1"> <path - transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)" - style="fill:url(#linearGradient4738);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:1.85770929;stroke-miterlimit:4;stroke-opacity:1" + style="fill:url(#linearGradient4738);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3292);stroke-width:1.85770929000000007;stroke-miterlimit:4;stroke-opacity:1" d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " - id="path4331" /> + id="path4331" + transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)" /> + <path + style="opacity:0.59999999999999998;fill:url(#linearGradient4740);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:2.14350747999999980;stroke-miterlimit:4;stroke-opacity:1" + d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " + id="path4333" + transform="matrix(0.466524,0,0,0.466525,-0.346154,-0.198015)" /> <path - transform="matrix(0.466524,0,0,0.466525,-0.346154,-0.198015)" - style="opacity:0.6;fill:url(#linearGradient4740);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:2.14350748;stroke-miterlimit:4;stroke-opacity:1" - d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " - id="path4333" /> + sodipodi:type="arc" + style="opacity:0.19499996000000000;fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter3374)" + id="path3302" + sodipodi:cx="11.484269" + sodipodi:cy="4.7465701" + sodipodi:rx="1.8659533" + sodipodi:ry="1.9428998" + d="m 13.350222,4.7465701 a 1.8659533,1.9428998 0 1 1 -3.7319067,0 A 1.8659533,1.9428998 0 1 1 13.350222,4.7465701 z" + transform="matrix(2.2014717,-1.281888,0.9447394,1.6503281,-23.266565,12.888149)" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/away.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/away.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,7 +2,7 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" @@ -13,9 +13,9 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.45" + inkscape:version="0.46+devel" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" + inkscape:export-filename="/home/hbons/Desktop/away.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" @@ -26,6 +26,37 @@ id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient3284"> + <stop + style="stop-color:#173867;stop-opacity:1;" + offset="0" + id="stop3286" /> + <stop + style="stop-color:#173867;stop-opacity:0;" + offset="1" + id="stop3288" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3276"> + <stop + style="stop-color:#2863b7;stop-opacity:1" + offset="0" + id="stop3278" /> + <stop + style="stop-color:#14325c;stop-opacity:1" + offset="1" + id="stop3280" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective35" /> + <linearGradient + inkscape:collect="always" id="linearGradient2812"> <stop style="stop-color:#2e3436;stop-opacity:1;" @@ -94,9 +125,9 @@ xlink:href="#linearGradient2804" id="linearGradient2810" x1="4.5264969" - y1="2.7991772" - x2="10.623409" - y2="11.024895" + y1="2.6807978" + x2="9.7444448" + y2="9.9594812" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" @@ -108,6 +139,24 @@ fy="19.008621" r="8.6620579" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3276" + id="linearGradient3282" + x1="15.377563" + y1="12.744186" + x2="22.868998" + y2="29.821121" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3284" + id="linearGradient3290" + x1="23.221344" + y1="24.700239" + x2="8.2601509" + y2="0.92288947" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -117,8 +166,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="14.729231" - inkscape:cy="2.7799575" + inkscape:cx="13.286484" + inkscape:cy="9.6281985" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" @@ -126,11 +175,22 @@ inkscape:window-width="1434" inkscape:window-height="840" inkscape:window-x="3" - inkscape:window-y="25" + inkscape:window-y="27" inkscape:object-paths="false" inkscape:grid-bbox="true" inkscape:guide-bbox="false" - inkscape:grid-points="true" /> + inkscape:grid-points="true" + objecttolerance="14" + gridtolerance="18" + inkscape:snap-bbox="true" + inkscape:snap-nodes="false"> + <inkscape:grid + type="xygrid" + id="grid3274" + empspacing="5" + visible="true" + enabled="true" /> + </sodipodi:namedview> <metadata id="metadata7"> <rdf:RDF> @@ -148,7 +208,7 @@ id="layer1"> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.91314828px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3282);stroke-width:1.91314827999999992px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1339" sodipodi:cx="15.590227" sodipodi:cy="16.57217" @@ -168,7 +228,7 @@ transform="matrix(2.192102,0,0,2.091316,16.34939,1.090661)" /> <path sodipodi:type="arc" - style="opacity:0.40340911;color:black;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:2.60821199px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:0.40340911000000002;color:black;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3290);stroke-width:2.60821199000000004px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1341" sodipodi:cx="15.590227" sodipodi:cy="16.57217" @@ -188,7 +248,7 @@ transform="matrix(3.094296,0,0,3.766968,-10.69048,-20.45989)" /> <path sodipodi:type="arc" - style="opacity:0.76704544;fill:none;fill-opacity:1;stroke:url(#linearGradient2810);stroke-width:0.80677563;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.76704543999999986;fill:none;fill-opacity:1;stroke:url(#linearGradient2810);stroke-width:0.80677562999999985;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2802" sodipodi:cx="7.5" sodipodi:cy="7" @@ -197,7 +257,7 @@ d="M 13 7 A 5.5 5 0 1 1 2,7 A 5.5 5 0 1 1 13 7 z" transform="matrix(1.18182,0,0,1.3,-0.86365,-1.1)" /> <rect - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect2820" width="1" height="1" @@ -231,7 +291,7 @@ y="-10" transform="matrix(0,1,-1,0,0,0)" /> <rect - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect2846" width="1" height="1"
--- a/pidgin/pixmaps/status/16/scalable/busy.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/busy.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,7 +2,7 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" @@ -13,9 +13,9 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.45" + inkscape:version="0.46+devel" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" + inkscape:export-filename="/home/hbons/Desktop/busy.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" @@ -26,6 +26,37 @@ id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient3290"> + <stop + style="stop-color:#ffffff;stop-opacity:1" + offset="0" + id="stop3292" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3294" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3280"> + <stop + style="stop-color:#a60000;stop-opacity:1" + offset="0" + id="stop3282" /> + <stop + style="stop-color:#460000;stop-opacity:1" + offset="1" + id="stop3284" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective39" /> + <linearGradient + inkscape:collect="always" id="linearGradient2898"> <stop style="stop-color:white;stop-opacity:1;" @@ -71,28 +102,6 @@ r="8.6620579" /> <linearGradient inkscape:collect="always" - id="linearGradient2186"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop2188" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop2190" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2186" - id="linearGradient2194" - x1="9.2594385" - y1="-1.5641226" - x2="11.226587" - y2="17.697369" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.684526,0,0,0.687171,-0.20455,-0.253325)" /> - <linearGradient - inkscape:collect="always" id="linearGradient2239"> <stop style="stop-color:#ffffff;stop-opacity:1;" @@ -107,12 +116,12 @@ inkscape:collect="always" xlink:href="#linearGradient2239" id="linearGradient2245" - x1="8.7505674" - y1="4.5934086" - x2="31.18539" - y2="39.834526" + x1="-1.5418521" + y1="-6.2826729" + x2="63.127094" + y2="59.183727" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" /> + gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.2698205)" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient3149" @@ -177,6 +186,240 @@ x2="12.233074" y2="27.77807" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3280" + id="linearGradient3286" + x1="11.549973" + y1="7.078577" + x2="33.836056" + y2="45.494511" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3290" + id="linearGradient3282" + x1="5.8424845" + y1="-1.2794704" + x2="10.945268" + y2="11.145247" + gradientUnits="userSpaceOnUse" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="28.579245" + x2="26.533659" + y1="15.213944" + x1="15.893391" + id="linearGradient3292" + xlink:href="#linearGradient3280" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2621" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3007" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3005" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2804"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2806" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2808" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2949" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2951"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2953" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2955" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2963" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2601" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2599" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2597" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2579"> + <stop + id="stop2581" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2583" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2577" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="31.325201" + x2="30.341434" + y1="10.823074" + x1="11.127699" + gradientUnits="userSpaceOnUse" + id="linearGradient4740" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient4738" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <inkscape:perspective + id="perspective43" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + inkscape:vp_z="16 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 8 : 1" + sodipodi:type="inkscape:persp3d" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2635" + gradientUnits="userSpaceOnUse" + x1="11.127699" + y1="10.823074" + x2="30.341434" + y2="31.325201" + gradientTransform="matrix(0.466524,0,0,0.466525,-23.253129,0.8019768)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2638" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientTransform="matrix(0.538297,0,0,0.538297,-24.537152,-0.4592542)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3280" + id="linearGradient2640" + gradientUnits="userSpaceOnUse" + x1="15.893391" + y1="15.213944" + x2="26.533659" + y2="28.579245" + gradientTransform="matrix(0.538297,0,0,0.538297,-24.537152,-0.4592542)" /> + <filter + inkscape:collect="always" + id="filter3416" + x="-0.13117394" + width="1.2623479" + y="-0.11015608" + height="1.2203122"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="0.19309804" + id="feGaussianBlur3418" /> + </filter> </defs> <sodipodi:namedview id="base" @@ -185,17 +428,21 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="25.992076" - inkscape:cx="8.3811422" - inkscape:cy="5.1075896" + inkscape:zoom="18.379173" + inkscape:cx="0.35485832" + inkscape:cy="7.0130435" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="844" - inkscape:window-x="3" - inkscape:window-y="25" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22"> + <inkscape:grid + type="xygrid" + id="grid2508" /> + </sodipodi:namedview> <metadata id="metadata7"> <rdf:RDF> @@ -223,7 +470,7 @@ transform="matrix(0.468971,0,0,0.468971,0.730372,0.26987)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#f24747;fill-opacity:1;fill-rule:evenodd;stroke:#820000;stroke-width:1.91298747px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;color:#000000;fill:#f13d3d;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3286);stroke-width:1.91298747000000002px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1339" sodipodi:cx="15.590227" sodipodi:cy="16.57217" @@ -232,17 +479,27 @@ d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" transform="matrix(0.522706,0,0,0.522779,-0.14857,-0.663013)" /> <path - style="opacity:0.6;color:#000000;fill:url(#linearGradient2194);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.00000012px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 14.525974,7.9894993 C 14.525974,11.598577 11.608166,14.527685 8.0130095,14.527685 C 4.4178543,14.527685 1.500047,11.598577 1.500047,7.9894993 C 1.500047,4.3804219 4.4178543,1.4513155 8.0130095,1.4513155 C 11.608166,1.4513155 14.525974,4.3804219 14.525974,7.9894993 z " + style="opacity:0.75000000000000000;color:#000000;fill:url(#linearGradient3282);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.00000011999999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + d="m 14.525974,7.9894993 c 0,3.6090777 -2.917808,6.5381857 -6.5129645,6.5381857 -3.5951552,0 -6.5129625,-2.929108 -6.5129625,-6.5381857 0,-3.6090774 2.9178073,-6.5381838 6.5129625,-6.5381838 3.5951565,0 6.5129645,2.9291064 6.5129645,6.5381838 z" id="path2220" /> + <path + sodipodi:type="arc" + style="opacity:0.19499996000000000;fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter3416)" + id="path3302" + sodipodi:cx="11.484269" + sodipodi:cy="4.7465701" + sodipodi:rx="1.8659533" + sodipodi:ry="1.9428998" + d="m 13.350222,4.7465701 a 1.8659533,1.9428998 0 1 1 -3.7319067,0 A 1.8659533,1.9428998 0 1 1 13.350222,4.7465701 z" + transform="matrix(2.2014717,-1.281888,0.9447394,1.6503281,-23.212768,12.908772)" /> <rect - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#a40000;stroke-width:1.00000024;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#a40000;stroke-width:1.00000024000000010;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="rect3207" width="11.000004" height="2.9999959" x="2.500001" y="6.5000038" - rx="0.96183157" - ry="0.96183157" /> + rx="1.0387781" + ry="1.0387781" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/chat.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/chat.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,92 +2,313 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="16" height="16" - id="svg13306" + id="svg7380" sodipodi:version="0.32" - inkscape:version="0.43" - version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/irc16.png" + inkscape:version="0.46+devel" + sodipodi:docbase="/home/hbons/Desktop" + sodipodi:docname="person.svg" + inkscape:export-filename="/home/hbons/Desktop/person.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/16/scalable" - sodipodi:docname="irc16.svg"> + inkscape:output_extension="org.inkscape.output.svg.inkscape" + version="1.0"> <defs - id="defs13308"> + id="defs7382"> + <linearGradient + inkscape:collect="always" + id="linearGradient3301"> + <stop + style="stop-color:#46284e;stop-opacity:1;" + offset="0" + id="stop3303" /> + <stop + style="stop-color:#7a4588;stop-opacity:1" + offset="1" + id="stop3305" /> + </linearGradient> <linearGradient inkscape:collect="always" - id="linearGradient2280"> + id="linearGradient3483"> + <stop + style="stop-color:#c17802;stop-opacity:1" + offset="0" + id="stop3485" /> <stop - style="stop-color:#d3d7cf;stop-opacity:1;" + style="stop-color:#935a00;stop-opacity:1" + offset="1" + id="stop3487" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3475"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" offset="0" - id="stop2282" /> + id="stop3477" /> <stop - style="stop-color:#d3d7cf;stop-opacity:0;" + style="stop-color:#eeeeec;stop-opacity:0;" offset="1" - id="stop2284" /> + id="stop3479" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3451"> + <stop + style="stop-color:#3465a4;stop-opacity:1" + offset="0" + id="stop3453" /> + <stop + style="stop-color:#15325b;stop-opacity:1" + offset="1" + id="stop3455" /> </linearGradient> <linearGradient inkscape:collect="always" - id="linearGradient3150"> + id="linearGradient3335"> + <stop + style="stop-color:#b2730d;stop-opacity:1;" + offset="0" + id="stop3337" /> <stop - style="stop-color:#2e3436;stop-opacity:1;" + style="stop-color:#935f0a;stop-opacity:1" + offset="1" + id="stop3339" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3327"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" offset="0" - id="stop3152" /> + id="stop3329" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3331" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 5.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="11 : 5.5 : 1" + inkscape:persp3d-origin="5.5 : 3.6666667 : 1" + id="perspective28" /> + <linearGradient + id="linearGradient3800"> + <stop + style="stop-color:#f4d9b1;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop3802" /> <stop - style="stop-color:#2e3436;stop-opacity:0;" + style="stop-color:#df9725;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop3804" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3800" + id="radialGradient4171" + gradientUnits="userSpaceOnUse" + cx="27.702486" + cy="14.540437" + fx="27.702486" + fy="14.540437" + r="9.1620579" + gradientTransform="matrix(1.191087,0,0,1.124022,-5.086983,-1.361697)" /> + <linearGradient + inkscape:collect="always" + id="linearGradient7300"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop7302" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" offset="1" - id="stop3154" /> + id="stop7304" /> </linearGradient> <radialGradient inkscape:collect="always" - xlink:href="#linearGradient3150" - id="radialGradient3156" - cx="10.748654" - cy="10.457643" - fx="10.748654" - fy="10.457643" - r="6.6449099" - gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)" + xlink:href="#linearGradient7300" + id="radialGradient7306" + cx="24.248138" + cy="27.184834" + fx="24.248138" + fy="27.184834" + r="12.499089" + gradientTransform="matrix(0.964825,0,0,0.631898,0.954495,11.94073)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" - id="linearGradient3131"> + id="linearGradient3816"> <stop - style="stop-color:#eeeeec;stop-opacity:1;" + style="stop-color:#000000;stop-opacity:1;" offset="0" - id="stop3133" /> + id="stop3818" /> <stop - style="stop-color:#d3d7cf" + style="stop-color:#000000;stop-opacity:0;" offset="1" - id="stop3135" /> + id="stop3820" /> </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient4179" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient7300" + id="radialGradient4244" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.964825,0,0,0.631898,0.954495,11.94073)" + cx="24.248138" + cy="27.184834" + fx="24.248138" + fy="27.184834" + r="12.499089" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3800" + id="radialGradient4246" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.191087,0,0,1.124022,-5.086983,-1.361697)" + cx="27.702486" + cy="14.540437" + fx="27.702486" + fy="14.540437" + r="9.1620579" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient7300" + id="radialGradient2631" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.964825,0,0,0.631898,0.954495,11.94073)" + cx="24.248138" + cy="27.184834" + fx="24.248138" + fy="27.184834" + r="12.499089" /> + <inkscape:perspective + id="perspective2506" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient3131" - id="linearGradient3137" - x1="18.206755" - y1="4.8468447" - x2="18.150391" - y2="13.775416" + xlink:href="#linearGradient3327" + id="linearGradient3333" + x1="32.26284" + y1="18.39094" + x2="40.463146" + y2="28.908117" + gradientUnits="userSpaceOnUse" /> + <inkscape:perspective + id="perspective3358" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <radialGradient + r="9.1620579" + fy="14.809424" + fx="26.819485" + cy="14.809424" + cx="26.819485" + gradientTransform="matrix(0.9647715,0.3755394,-0.3764009,0.966985,7.9289748,-9.623708)" + gradientUnits="userSpaceOnUse" + id="radialGradient3376" + xlink:href="#linearGradient3800" + inkscape:collect="always" /> + <linearGradient + y2="25.307449" + x2="33.637684" + y1="20.449879" + x1="30.189112" + gradientUnits="userSpaceOnUse" + id="linearGradient3378" + xlink:href="#linearGradient3335" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3327" + id="linearGradient3409" + gradientUnits="userSpaceOnUse" + x1="32.26284" + y1="18.39094" + x2="40.463146" + y2="28.908117" /> + <inkscape:perspective + id="perspective3418" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient7300" + id="radialGradient3449" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.964825,0,0,0.631898,0.954495,11.94073)" + cx="24.248138" + cy="27.184834" + fx="24.248138" + fy="27.184834" + r="12.499089" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3451" + id="linearGradient3457" + x1="5.0000005" + y1="11.446214" + x2="8.2252016" + y2="16.493296" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" - xlink:href="#linearGradient2280" - id="radialGradient2286" - cx="10.332581" - cy="6.9103003" - fx="10.332581" - fy="6.9103003" - r="9.5" - gradientTransform="matrix(1.895669,2.346468e-16,-3.526656e-16,2.238626,-11.89066,-12.56638)" + xlink:href="#linearGradient3475" + id="radialGradient3481" + cx="28.779234" + cy="14.68485" + fx="28.779234" + fy="14.68485" + r="9.8994964" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1189106,0,0,1.1189106,-3.422157,-1.7461848)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3483" + id="linearGradient3489" + x1="30.669531" + y1="17.247086" + x2="34.812038" + y2="24.987169" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3301" + id="linearGradient3307" + x1="16.510134" + y1="13.467242" + x2="13.781501" + y2="9.1689024" gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview @@ -97,20 +318,34 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="39.59798" - inkscape:cx="14.115129" - inkscape:cy="9.9583634" + inkscape:zoom="36.060436" + inkscape:cx="12.472661" + inkscape:cy="7.0601917" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" + width="11px" + height="11px" + inkscape:snap-nodes="false" + inkscape:snap-bbox="true" + objecttolerance="7" + gridtolerance="7" + showguides="true" + inkscape:guide-bbox="true"> + <inkscape:grid + type="xygrid" + id="grid2497" + empspacing="5" + visible="true" + enabled="true" /> + </sodipodi:namedview> <metadata - id="metadata13311"> + id="metadata7385"> <rdf:RDF> <cc:Work rdf:about=""> @@ -125,91 +360,80 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> <path - style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00000095;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 0.49919572,3.436028 L 0.49919572,8.024108 C 0.49919572,10.030365 0.43094041,12.50277 3.4779698,12.50277 L 3.5190997,14.938304 L 6.2391563,12.547388 L 10.144168,12.531827 C 13.477975,12.531827 15.5,11.518177 15.5,9.379431 L 15.484468,3.556577 C 15.484468,1.4311219 14.423292,0.51556128 12.453894,0.51556128 L 3.4753207,0.50000048 C 1.4741104,0.50000048 0.49919572,1.561826 0.49919572,3.436028 z " - id="path2199" - sodipodi:nodetypes="ccccccccccc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 10.03125 5.5 C 5.2809556 5.6861502 1.5 8.7231084 1.5 12.4375 C 1.5 14.570281 2.4139213 16.850503 4.375 18.125 C 4.790921 19.906271 3.5825788 21.282326 3.375 21.5 C 3.7506605 21.398222 6.7302843 20.58004 7.84375 19.375 C 8.9660824 19.328744 9.5914383 19.40625 10.5 19.40625 C 15.465015 19.40625 19.500001 16.271711 19.5 12.4375 C 19.499999 8.6032883 15.465015 5.5 10.5 5.5 C 10.344844 5.4999998 10.184486 5.4939951 10.03125 5.5 z " - xlink:href="#path13316" - style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2288" - inkscape:href="#path13316" - d="M 10.0625,6.5 C 7.8900031,6.5851338 5.9762716,7.3427975 4.625,8.4375 C 3.2737284,9.5322025 2.5,10.920293 2.5,12.4375 C 2.5,14.284032 3.2837785,16.226812 4.90625,17.28125 C 5.1287835,17.423752 5.2860248,17.648382 5.34375,17.90625 C 5.4955807,18.556498 5.4707531,19.125743 5.375,19.65625 C 6.0781419,19.333618 6.8270886,18.976092 7.09375,18.6875 C 7.2809756,18.490079 7.540428,18.377274 7.8125,18.375 C 8.9961476,18.326217 9.6484235,18.40625 10.5,18.40625 C 12.771643,18.40625 14.815021,17.674738 16.25,16.5625 C 17.684979,15.450262 18.5,14.003112 18.5,12.4375 C 18.5,10.871887 17.684227,9.4172787 16.25,8.3125 C 14.815773,7.2077213 12.773745,6.5 10.5,6.5 C 10.318992,6.4999998 10.162289,6.4960896 10.0625,6.5 z " - transform="matrix(-1,0,0,1,23.99247,-3.990738)" /> - <path - style="opacity:1;fill:url(#radialGradient2286);fill-opacity:1;stroke:#555753;stroke-width:1.00000095;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 0.49919572,3.436028 L 0.49919572,8.024108 C 0.49919572,10.030365 0.43094041,12.50277 3.4779698,12.50277 L 3.5190997,14.938304 L 6.2391563,12.547388 L 10.144168,12.531827 C 13.477975,12.531827 15.5,11.518177 15.5,9.379431 L 15.484468,3.556577 C 15.484468,1.4311219 14.423292,0.51556128 12.453894,0.51556128 L 3.4753207,0.50000048 C 1.4741104,0.50000048 0.49919572,1.561826 0.49919572,3.436028 z " - id="rect1326" - sodipodi:nodetypes="ccccccccccc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.99553573" - inkscape:original="M 3.46875 0.5 C 1.4675396 0.5 0.5 1.563298 0.5 3.4375 L 0.5 8.03125 C 0.5 10.037507 0.42172061 12.5 3.46875 12.5 L 3.53125 14.9375 L 6.25 12.5625 L 10.15625 12.53125 C 13.490057 12.53125 15.5 11.513746 15.5 9.375 L 15.5 3.5625 C 15.5 1.4370449 14.438148 0.5 12.46875 0.5 L 3.46875 0.5 z " - xlink:href="#rect1326" - style="opacity:1;fill:none;fill-opacity:1;stroke:#eeeeec;stroke-width:1.03363752;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2248" - inkscape:href="#rect1326" - d="M 3.96875,9.0625 C 3.1444632,9.0625002 2.7022172,9.2621947 2.4375,9.53125 C 2.1727828,9.8003053 2,10.234211 2,11 L 2,15.59375 C 2,16.609826 2.0106197,17.613475 2.25,18.1875 C 2.4893803,18.761525 2.71342,19.0625 3.96875,19.0625 C 4.5099878,19.05993 4.9541408,19.490203 4.96875,20.03125 L 4.96875,20.34375 L 6.09375,19.34375 C 6.2748748,19.183476 6.5081463,19.094611 6.75,19.09375 L 10.65625,19.09375 C 12.221872,19.09375 13.413842,18.823397 14.09375,18.4375 C 14.773658,18.051603 15,17.695013 15,16.9375 L 15,11.125 C 15,10.228058 14.802621,9.7651678 14.53125,9.5 C 14.259879,9.2348322 13.795556,9.0625 12.96875,9.0625 L 3.96875,9.0625 z " - transform="matrix(0.997403,0,0,0.938411,3.636372e-2,0.123235)" /> - <path - sodipodi:type="arc" - style="opacity:0.2;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3140" - sodipodi:cx="10.748654" - sodipodi:cy="10.457643" - sodipodi:rx="6.6449099" - sodipodi:ry="2.3675451" - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z" - transform="matrix(1.655402,0,0,1.267134,-5.793347,6.748769)" /> + style="opacity:1;color:#000000;fill:#855b8c;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3307);stroke-width:0.99999987999999995px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + d="m 9.2852706,13.499999 3.6531493,0 c 1.0350584,0 2.059811,-0.3777864 2.4354322,-1.4545452 C 15.730548,11.022944 15.434737,9.0757587 13.121077,7.5000022 l -4.3228932,0 C 6.4845226,8.9545462 6.1953886,10.943768 6.7280666,12.106061 7.2707356,13.290156 8.1893256,13.5 9.2852706,13.5 z" + id="path3443" + sodipodi:nodetypes="cczcczc" /> <path sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 10.03125 5.5 C 5.2809556 5.6861502 1.5 8.7231084 1.5 12.4375 C 1.5 14.570281 2.4139213 16.850503 4.375 18.125 C 4.790921 19.906271 3.5825788 21.282326 3.375 21.5 C 3.7506605 21.398222 6.7302843 20.58004 7.84375 19.375 C 8.9660824 19.328744 9.5914383 19.40625 10.5 19.40625 C 15.465015 19.40625 19.500001 16.271711 19.5 12.4375 C 19.499999 8.6032883 15.465015 5.5 10.5 5.5 C 10.344844 5.4999998 10.184486 5.4939951 10.03125 5.5 z " - xlink:href="#path13316" - style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path13434" - inkscape:href="#path13316" - d="M 10.0625,6.5 C 7.8900031,6.5851338 5.9762716,7.3427975 4.625,8.4375 C 3.2737284,9.5322025 2.5,10.920293 2.5,12.4375 C 2.5,14.284032 3.2837785,16.226812 4.90625,17.28125 C 5.1287835,17.423752 5.2860248,17.648382 5.34375,17.90625 C 5.4955807,18.556498 5.4707531,19.125743 5.375,19.65625 C 6.0781419,19.333618 6.8270886,18.976092 7.09375,18.6875 C 7.2809756,18.490079 7.540428,18.377274 7.8125,18.375 C 8.9961476,18.326217 9.6484235,18.40625 10.5,18.40625 C 12.771643,18.40625 14.815021,17.674738 16.25,16.5625 C 17.684979,15.450262 18.5,14.003112 18.5,12.4375 C 18.5,10.871887 17.684227,9.4172787 16.25,8.3125 C 14.815773,7.2077213 12.773745,6.5 10.5,6.5 C 10.318992,6.4999998 10.162289,6.4960896 10.0625,6.5 z " - transform="matrix(-1,0,0,1,32,-8.84375)" /> + inkscape:radius="-1.1784238" + inkscape:original="M 24.5625 24.125 C 17.844986 28.367641 17.015916 34.172303 18.5625 37.5625 C 20.138096 41.016289 22.818019 41.625 26 41.625 L 36.59375 41.625 C 39.598953 41.624999 42.565667 40.546959 43.65625 37.40625 C 44.691891 34.423774 43.842514 28.721194 37.125 24.125 L 24.5625 24.125 z " + style="opacity:0.5;color:#000000;fill:url(#radialGradient3449);fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:3.58186674000000016px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path3445" + d="m 24.96875,25.3125 c -6.080867,3.980556 -6.594767,9.007702 -5.34375,11.75 0.693936,1.521145 1.541625,2.278662 2.5625,2.75 1.020875,0.471338 2.296653,0.625 3.8125,0.625 l 10.59375,0 c 1.361692,0 2.658712,-0.23791 3.6875,-0.78125 1.028788,-0.54334 1.79962,-1.327976 2.25,-2.625 0.804003,-2.315397 0.274744,-7.39869 -5.8125,-11.71875 z" + transform="matrix(0.2947246,0,0,0.2644629,1.8788978,1.8057826)" /> + <path + style="opacity:0.78977272;fill:#eeeeec;fill-opacity:1;stroke:none" + d="m 12.999999,10.150001 c 0,1.0212 -1.053115,1.320578 -2,1.85 -1.339673,-0.49828 -2,-0.8288 -2,-1.85 0,-1.0212014 0.8959998,-1.8500014 2,-1.8500014 1.104,0 2,0.8288 2,1.8500014 z" + id="path3447" + sodipodi:nodetypes="ccssc" /> + <path + sodipodi:type="arc" + style="opacity:1;color:#000000;fill:#d28812;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3489);stroke-width:1.92490505999999995px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path2549" + sodipodi:cx="31.112698" + sodipodi:cy="19.008621" + sodipodi:rx="8.6620579" + sodipodi:ry="8.6620579" + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" + transform="matrix(0.5195068,0,0,0.5195069,-5.1632599,-4.8751084)" /> + <path + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path2551" + style="opacity:0.625;color:#000000;fill:url(#radialGradient3481);fill-opacity:1;stroke:url(#linearGradient3333);stroke-width:2.47487712px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + sodipodi:type="arc" + transform="matrix(0.4040609,0,0,0.4040609,-1.5714252,-2.6806412)" /> + <path + style="opacity:1;color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3457);stroke-width:0.99999987999999995px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + d="m 3.2852716,15.499999 3.6531493,0 c 1.0350584,0 2.059811,-0.3777864 2.4354322,-1.4545452 C 9.7305489,13.022944 9.4347379,11.075758 7.1210779,9.5000014 l -4.3228932,0 c -2.3136607,1.454544 -2.6027951,3.443766 -2.0701172,4.606059 0.54266971,1.184095 1.4612592,1.393939 2.5572041,1.393939 z" + id="path4308" + sodipodi:nodetypes="cczcczc" /> <path sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 10.03125 5.5 C 5.2809556 5.6861502 1.5 8.7231084 1.5 12.4375 C 1.5 14.570281 2.4139213 16.850503 4.375 18.125 C 4.790921 19.906271 3.5825788 21.282326 3.375 21.5 C 3.7506605 21.398222 6.7302843 20.58004 7.84375 19.375 C 8.9660824 19.328744 9.5914383 19.40625 10.5 19.40625 C 15.465015 19.40625 19.500001 16.271711 19.5 12.4375 C 19.499999 8.6032883 15.465015 5.5 10.5 5.5 C 10.344844 5.4999998 10.184486 5.4939951 10.03125 5.5 z " - xlink:href="#path13316" - style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path13323" - inkscape:href="#path13316" - d="M 10.0625,6.5 C 7.8900031,6.5851338 5.9762716,7.3427975 4.625,8.4375 C 3.2737284,9.5322025 2.5,10.920293 2.5,12.4375 C 2.5,14.284032 3.2837785,16.226812 4.90625,17.28125 C 5.1287835,17.423752 5.2860248,17.648382 5.34375,17.90625 C 5.4955807,18.556498 5.4707531,19.125743 5.375,19.65625 C 6.0781419,19.333618 6.8270886,18.976092 7.09375,18.6875 C 7.2809756,18.490079 7.540428,18.377274 7.8125,18.375 C 8.9961476,18.326217 9.6484235,18.40625 10.5,18.40625 C 12.771643,18.40625 14.815021,17.674738 16.25,16.5625 C 17.684979,15.450262 18.5,14.003112 18.5,12.4375 C 18.5,10.871887 17.684227,9.4172787 16.25,8.3125 C 14.815773,7.2077213 12.773745,6.5 10.5,6.5 C 10.318992,6.4999998 10.162289,6.4960896 10.0625,6.5 z " - transform="matrix(0.750603,0,0,0.750603,0.123492,-2.625632)" /> - <rect - style="opacity:1;fill:#9a9b96;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2207" - width="9" - height="1" - x="3" - y="4" - rx="0.5" - ry="0.5" /> - <rect - style="opacity:1;fill:#9a9b96;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect1343" - width="8" - height="1" - x="3" - y="8" - rx="0.5" - ry="0.5" /> - <rect - style="opacity:1;fill:#9a9b96;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect1345" - width="7" - height="1" - x="3" - y="6" - rx="0.5" - ry="0.5" /> + inkscape:radius="-1.1784238" + inkscape:original="M 24.5625 24.125 C 17.844986 28.367641 17.015916 34.172303 18.5625 37.5625 C 20.138096 41.016289 22.818019 41.625 26 41.625 L 36.59375 41.625 C 39.598953 41.624999 42.565667 40.546959 43.65625 37.40625 C 44.691891 34.423774 43.842514 28.721194 37.125 24.125 L 24.5625 24.125 z " + style="opacity:0.5;color:#000000;fill:url(#radialGradient2631);fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:3.58186674000000016px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path7281" + d="m 24.96875,25.3125 c -6.080867,3.980556 -6.594767,9.007702 -5.34375,11.75 0.693936,1.521145 1.541625,2.278662 2.5625,2.75 1.020875,0.471338 2.296653,0.625 3.8125,0.625 l 10.59375,0 c 1.361692,0 2.658712,-0.23791 3.6875,-0.78125 1.028788,-0.54334 1.79962,-1.327976 2.25,-2.625 0.804003,-2.315397 0.274744,-7.39869 -5.8125,-11.71875 z" + transform="matrix(0.2947246,0,0,0.2644629,-4.1211012,3.8057819)" /> + <path + style="opacity:0.78977272;fill:#eeeeec;fill-opacity:1;stroke:none" + d="M 7,12.15 C 7,13.1712 5.9468852,13.470578 5.0000003,14 3.6603268,13.50172 2.9999998,13.1712 2.9999998,12.15 c 0,-1.021201 0.896,-1.850001 2.000001,-1.850001 1.1039998,0 1.9999997,0.8288 1.9999997,1.850001 z" + id="path7285" + sodipodi:nodetypes="ccssc" /> + <path + sodipodi:type="arc" + style="opacity:1;color:#000000;fill:url(#radialGradient3376);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3378);stroke-width:1.92490506px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path3405" + sodipodi:cx="31.112698" + sodipodi:cy="19.008621" + sodipodi:rx="8.6620579" + sodipodi:ry="8.6620579" + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" + transform="matrix(0.5195068,0,0,0.5195069,-11.163257,-2.8751094)" /> + <path + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path3407" + style="opacity:0.625;color:#000000;fill:none;stroke:url(#linearGradient3409);stroke-width:2.47487712px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + sodipodi:type="arc" + transform="matrix(0.4040609,0,0,0.4040609,-7.5714222,-0.6806422)" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/offline.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/offline.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,7 +2,7 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" @@ -13,7 +13,7 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.45" + inkscape:version="0.46+devel" version="1.0" inkscape:export-filename="/home/hbons/Desktop/offline.png" inkscape:export-xdpi="90" @@ -26,25 +26,47 @@ id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient2225"> + id="linearGradient3303"> <stop - style="stop-color:#eeeeec;stop-opacity:1;" + style="stop-color:#ffffff;stop-opacity:1;" offset="0" - id="stop2227" /> + id="stop3305" /> <stop - style="stop-color:#eeeeec;stop-opacity:0;" + style="stop-color:#ffffff;stop-opacity:0;" offset="1" - id="stop2229" /> + id="stop3307" /> </linearGradient> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2225" - id="linearGradient2231" - x1="11.802028" - y1="1.9986149" - x2="11.802028" - y2="14.895812" - gradientUnits="userSpaceOnUse" /> + id="linearGradient3295"> + <stop + style="stop-color:#babdb6;stop-opacity:1" + offset="0" + id="stop3297" /> + <stop + style="stop-color:#888a85;stop-opacity:1" + offset="1" + id="stop3299" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3275"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3277" /> + <stop + style="stop-color:#61635f;stop-opacity:1" + offset="1" + id="stop3279" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective34" /> <linearGradient inkscape:collect="always" id="linearGradient2186"> @@ -153,6 +175,33 @@ x2="12.233074" y2="27.77807" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3275" + id="linearGradient3281" + x1="14.345539" + y1="14.69435" + x2="6.8097677" + y2="4.3450422" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3295" + id="linearGradient3301" + x1="4.8374491" + y1="3.565635" + x2="12.060304" + y2="13.821809" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3303" + id="linearGradient3309" + x1="6.8490844" + y1="8.6799088" + x2="-3.3852992" + y2="-4.1349444" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -161,17 +210,28 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="25.992076" - inkscape:cx="26.27121" - inkscape:cy="5.5692688" + inkscape:zoom="8" + inkscape:cx="1.3444167" + inkscape:cy="3.0859953" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1434" - inkscape:window-height="844" - inkscape:window-x="3" - inkscape:window-y="25" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" + inkscape:snap-nodes="false" + inkscape:snap-bbox="true" + objecttolerance="11" + gridtolerance="10"> + <inkscape:grid + type="xygrid" + empspacing="5" + visible="true" + enabled="true" + id="grid2503" /> + </sodipodi:namedview> <metadata id="metadata7"> <rdf:RDF> @@ -188,7 +248,7 @@ inkscape:groupmode="layer" id="layer1"> <path - style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999827;stroke-miterlimit:4;stroke-opacity:1" + style="fill:url(#linearGradient3301);fill-opacity:1;stroke:url(#linearGradient3281);stroke-width:0.99999826999999997;stroke-miterlimit:4;stroke-opacity:1" d="M 13.307074,13.307079 C 10.376958,16.237198 5.6213214,16.237693 2.6918157,13.308187 C -0.23769028,10.378679 -0.23719421,5.623042 2.692923,2.6929237 C 5.62304,-0.23719442 10.378675,-0.23769056 13.308181,2.6918165 C 16.237687,5.6213234 16.237192,10.376962 13.307074,13.307079 z " id="path2187" /> <path @@ -196,15 +256,22 @@ inkscape:radius="-1.0137641" inkscape:original="M 8 0.5 C 6.0786384 0.50020041 4.1525585 1.2224409 2.6875 2.6875 C -0.24261721 5.6176183 -0.24200589 10.382992 2.6875 13.3125 C 5.6170057 16.242006 10.382384 16.242619 13.3125 13.3125 C 16.242618 10.382383 16.242006 5.6170068 13.3125 2.6875 C 11.847747 1.2227465 9.9213616 0.49979959 8 0.5 z " xlink:href="#path2187" - style="opacity:0.4;fill:url(#linearGradient2231);fill-opacity:1;stroke:#ffffff;stroke-width:0.99995583;stroke-miterlimit:4;stroke-opacity:1" + style="opacity:0.40000000000000002;fill:none;fill-opacity:1;stroke:url(#linearGradient3309);stroke-width:0.99995583000000021;stroke-miterlimit:4;stroke-opacity:1" id="path2215" inkscape:href="#path2187" - d="M 8,1.5 C 6.3326173,1.5001739 4.674966,2.1375335 3.40625,3.40625 C 0.86479124,5.9477097 0.86538373,10.052882 3.40625,12.59375 C 5.9471154,15.134616 10.052293,15.135209 12.59375,12.59375 C 15.135209,10.052292 15.134616,5.9471167 12.59375,3.40625 C 11.325315,2.1378146 9.6669929,1.4998261 8,1.5 z " - transform="matrix(1.000056,0,0,1.000028,-4.353349e-4,-2.926381e-5)" /> + d="M 8,1.5 C 6.3326173,1.5001739 4.674966,2.1375335 3.40625,3.40625 c -2.5414588,2.5414597 -2.5408663,6.646632 0,9.1875 2.5408654,2.540866 6.646043,2.541459 9.1875,0 2.541459,-2.541458 2.540866,-6.6466333 0,-9.1875 C 11.325315,2.1378146 9.6669929,1.4998261 8,1.5 z" + transform="matrix(-1.000056,0,0,-1.000028,16.000461,16.000041)" /> <path - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#555753;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 11.54182,4.2658182 C 10.931116,3.6551131 10.447965,3.347327 9.8372602,3.9580321 L 8.0000001,5.7952921 L 6.1627401,3.9580321 C 5.5520351,3.3473271 4.9919392,3.7705329 4.381234,4.381238 C 3.770529,4.991943 3.347323,5.5520393 3.9580281,6.1627441 L 5.7952881,8.0000041 L 3.9580281,9.8372641 C 3.3473229,10.447969 3.6935827,10.969592 4.3042875,11.580298 C 4.9149927,12.191002 5.5520349,12.652681 6.1627401,12.041977 L 8.0000001,10.204716 L 9.8372602,12.041977 C 10.447965,12.652681 11.046535,12.306422 11.657239,11.695718 C 12.267944,11.085012 12.652677,10.447969 12.041972,9.8372641 L 10.204713,8.0000041 L 12.041972,6.1627441 C 12.652677,5.552039 12.152526,4.8765236 11.54182,4.2658182 z " + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#555753;stroke-width:1.00000036;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="M 11.85704,4.0822721 C 11.226174,3.4531102 10.534706,3.2129687 9.903839,3.8421305 L 8.0059223,5.7349162 6.1080057,3.8421305 C 5.4771385,3.2129688 4.7446581,3.5335449 4.1137906,4.1627068 3.4829234,4.7918685 3.1996385,5.4843118 3.8305058,6.1134733 L 5.7284224,8.006259 3.8305058,9.8990447 C 3.1996384,10.528207 3.4803833,11.334907 4.1112504,11.96407 4.7421178,12.59323 5.4771383,12.799549 6.1080057,12.170389 L 8.0059223,10.277602 9.903839,12.170389 C 10.534706,12.799549 11.306931,12.596719 11.937797,11.967558 12.568664,11.338395 12.812206,10.528207 12.181339,9.8990449 L 10.283423,8.0062592 12.181339,6.1134736 C 12.812206,5.4843115 12.487908,4.7114342 11.85704,4.0822721 z" id="rect2920" sodipodi:nodetypes="ccccscccscccscccc" /> + <rect + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none" + id="rect3285" + width="4" + height="4" + x="6" + y="6" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/person.svg Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/pixmaps/status/16/scalable/person.svg Mon Jun 30 23:12:54 2008 +0000 @@ -2,26 +2,107 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" + xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16px" - height="16px" + width="16" + height="16" id="svg7380" sodipodi:version="0.32" - inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/status/16/scalable" + inkscape:version="0.46+devel" + sodipodi:docbase="/home/hbons/Desktop" sodipodi:docname="person.svg" - inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/person.png" + inkscape:export-filename="/home/hbons/Desktop/person.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + version="1.0"> <defs id="defs7382"> <linearGradient + inkscape:collect="always" + id="linearGradient3301"> + <stop + style="stop-color:#46284e;stop-opacity:1;" + offset="0" + id="stop3303" /> + <stop + style="stop-color:#7a4588;stop-opacity:1" + offset="1" + id="stop3305" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3483"> + <stop + style="stop-color:#c17802;stop-opacity:1" + offset="0" + id="stop3485" /> + <stop + style="stop-color:#935a00;stop-opacity:1" + offset="1" + id="stop3487" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3475"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3477" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3479" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3451"> + <stop + style="stop-color:#3465a4;stop-opacity:1" + offset="0" + id="stop3453" /> + <stop + style="stop-color:#15325b;stop-opacity:1" + offset="1" + id="stop3455" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3335"> + <stop + style="stop-color:#b2730d;stop-opacity:1;" + offset="0" + id="stop3337" /> + <stop + style="stop-color:#935f0a;stop-opacity:1" + offset="1" + id="stop3339" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3327"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3329" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3331" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 5.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="11 : 5.5 : 1" + inkscape:persp3d-origin="5.5 : 3.6666667 : 1" + id="perspective28" /> + <linearGradient id="linearGradient3800"> <stop style="stop-color:#f4d9b1;stop-opacity:1.0000000;" @@ -110,6 +191,160 @@ fx="27.702486" fy="14.540437" r="9.1620579" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient7300" + id="radialGradient2631" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.964825,0,0,0.631898,0.954495,11.94073)" + cx="24.248138" + cy="27.184834" + fx="24.248138" + fy="27.184834" + r="12.499089" /> + <inkscape:perspective + id="perspective2506" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3327" + id="linearGradient3333" + x1="32.26284" + y1="18.39094" + x2="40.463146" + y2="28.908117" + gradientUnits="userSpaceOnUse" /> + <inkscape:perspective + id="perspective3358" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <radialGradient + r="9.1620579" + fy="14.809424" + fx="26.819485" + cy="14.809424" + cx="26.819485" + gradientTransform="matrix(0.9647715,0.3755394,-0.3764009,0.966985,7.9289748,-9.623708)" + gradientUnits="userSpaceOnUse" + id="radialGradient3376" + xlink:href="#linearGradient3800" + inkscape:collect="always" /> + <linearGradient + y2="25.307449" + x2="33.637684" + y1="20.449879" + x1="30.189112" + gradientUnits="userSpaceOnUse" + id="linearGradient3378" + xlink:href="#linearGradient3335" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3327" + id="linearGradient3409" + gradientUnits="userSpaceOnUse" + x1="32.26284" + y1="18.39094" + x2="40.463146" + y2="28.908117" /> + <inkscape:perspective + id="perspective3418" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3451" + id="linearGradient3457" + x1="5.0000005" + y1="11.446214" + x2="8.2252016" + y2="16.493296" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3475" + id="radialGradient3481" + cx="28.779234" + cy="14.68485" + fx="28.779234" + fy="14.68485" + r="9.8994964" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1189106,0,0,1.1189106,-3.422157,-1.7461848)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3483" + id="linearGradient3489" + x1="30.669531" + y1="17.247086" + x2="34.812038" + y2="24.987169" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3301" + id="linearGradient3307" + x1="13.753093" + y1="16.35816" + x2="11.875512" + y2="10.748822" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1111113,0,0,1.1666667,-4.7222232,-0.2500063)" /> + <inkscape:perspective + id="perspective2538" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <radialGradient + r="9.1620579" + fy="14.809424" + fx="26.819485" + cy="14.809424" + cx="26.819485" + gradientTransform="matrix(0.9647715,0.3755394,-0.3764009,0.966985,7.9289748,-9.623708)" + gradientUnits="userSpaceOnUse" + id="radialGradient2556" + xlink:href="#linearGradient3800" + inkscape:collect="always" /> + <linearGradient + y2="25.307449" + x2="33.637684" + y1="20.449879" + x1="30.189112" + gradientUnits="userSpaceOnUse" + id="linearGradient2558" + xlink:href="#linearGradient3335" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3327" + id="linearGradient2587" + gradientUnits="userSpaceOnUse" + x1="32.26284" + y1="18.39094" + x2="40.463146" + y2="28.908117" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient7300" + id="linearGradient3300" + x1="17.57398" + y1="32.875" + x2="44.321774" + y2="32.875" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -118,17 +353,32 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="36.060436" - inkscape:cx="13.280605" - inkscape:cy="9.4853742" + inkscape:zoom="25.498579" + inkscape:cx="8.3447229" + inkscape:cy="9.4891345" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="972" - inkscape:window-x="6" - inkscape:window-y="25" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" + width="11px" + height="11px" + inkscape:snap-nodes="false" + inkscape:snap-bbox="true" + objecttolerance="7" + gridtolerance="7" + showguides="true" + inkscape:guide-bbox="true"> + <inkscape:grid + type="xygrid" + id="grid2497" + empspacing="5" + visible="true" + enabled="true" /> + </sodipodi:namedview> <metadata id="metadata7385"> <rdf:RDF> @@ -145,44 +395,42 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> <path - style="opacity:1;color:black;fill:#ad7fa8;fill-opacity:1;fill-rule:evenodd;stroke:#5c3566;stroke-width:2.39089775px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 25.986174,41.636039 L 36.592776,41.636039 C 39.59798,41.636039 42.57326,40.534107 43.663843,37.393398 C 44.699482,34.410922 43.84062,28.73134 37.123106,24.135146 L 24.57196,24.135146 C 17.854446,28.377786 17.014969,34.179977 18.561553,37.570174 C 20.137148,41.023964 22.804193,41.636039 25.986174,41.636039 z " - id="path4308" - sodipodi:nodetypes="cczcczc" - transform="matrix(0.382691,0,0,0.457119,-3.349933,-3.532635)" /> + style="opacity:1;color:#000000;fill:#855b8c;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3307);stroke-width:0.99999963999999997px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + d="m 5.5947456,15.499992 4.0590553,0 c 1.1500651,0 2.2886792,-0.44075079 2.7060362,-1.6969693 C 12.756166,12.610095 12.427487,10.338379 9.856753,8.4999962 l -4.8032154,0 C 2.4828029,10.196964 2.1615429,12.517723 2.7534074,13.873731 c 0.6029656,1.381444 1.6236213,1.626262 2.8413382,1.626262 z" + id="path3443" + sodipodi:nodetypes="cczcczc" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.1784238" inkscape:original="M 24.5625 24.125 C 17.844986 28.367641 17.015916 34.172303 18.5625 37.5625 C 20.138096 41.016289 22.818019 41.625 26 41.625 L 36.59375 41.625 C 39.598953 41.624999 42.565667 40.546959 43.65625 37.40625 C 44.691891 34.423774 43.842514 28.721194 37.125 24.125 L 24.5625 24.125 z " - style="opacity:0.45454544;color:black;fill:url(#radialGradient7306);fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:2.73569775px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path7281" - d="M 24.96875,25.3125 C 18.887883,29.293056 18.373983,34.320202 19.625,37.0625 C 20.318936,38.583645 21.166625,39.341162 22.1875,39.8125 C 23.208375,40.283838 24.484153,40.4375 26,40.4375 L 36.59375,40.4375 C 37.955442,40.4375 39.252462,40.19959 40.28125,39.65625 C 41.310038,39.11291 42.08087,38.328274 42.53125,37.03125 C 43.335253,34.715853 42.805994,29.63256 36.71875,25.3125 L 24.96875,25.3125 z " - transform="matrix(0.336828,0,0,0.396695,-1.924113,-1.54134)" /> + style="opacity:0.5;color:#000000;fill:url(#linearGradient3300);fill-opacity:1;fill-rule:evenodd;stroke:#eeeeec;stroke-width:2.99680495px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path3445" + d="m 24.96875,25.3125 c -6.080867,3.980556 -6.594767,9.007702 -5.34375,11.75 0.693936,1.521145 1.541625,2.278662 2.5625,2.75 1.020875,0.471338 2.296653,0.625 3.8125,0.625 l 10.59375,0 c 1.361692,0 2.658712,-0.23791 3.6875,-0.78125 1.028788,-0.54334 1.79962,-1.327976 2.25,-2.625 0.804003,-2.315397 0.274744,-7.39869 -5.8125,-11.71875 z" + transform="matrix(-0.3368281,0,0,0.3305786,17.924115,1.1322288)" /> <path - transform="matrix(0.761596,0,0,0.870395,-3.301291,-7.391088)" - style="opacity:0.78977272;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 20.091094,19.980694 C 20.091094,21.249084 17.671238,21.620929 15.495478,22.278502 C 12.417166,21.65961 10.899861,21.249084 10.899861,19.980694 C 10.899861,18.712304 12.958697,17.682885 15.495478,17.682885 C 18.032258,17.682885 20.091094,18.712304 20.091094,19.980694 z " - id="path7285" + style="opacity:0.78977272;fill:#eeeeec;fill-opacity:1;stroke:none" + d="M 10,10.500001 C 10,11.88 8.6836063,12.284565 7.5,13 5.8254087,12.326649 5,11.88 5,10.500001 5,9.1200001 6.1199997,8 7.5,8 8.88,8 10,9.1199996 10,10.500001 z" + id="path3447" sodipodi:nodetypes="ccssc" /> <path sodipodi:type="arc" - style="opacity:1;color:black;fill:url(#radialGradient4171);fill-opacity:1;fill-rule:evenodd;stroke:#b2730d;stroke-width:1.73241472px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path4320" + style="opacity:1;color:#000000;fill:url(#radialGradient2556);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2558);stroke-width:1.73241425px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" + id="path3405" sodipodi:cx="31.112698" sodipodi:cy="19.008621" sodipodi:rx="8.6620579" sodipodi:ry="8.6620579" - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" - transform="matrix(0.57723,0,0,0.57723,-9.459179,-5.472346)" /> + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" + transform="matrix(0.57723,0,0,0.5772299,-10.459182,-5.4723453)" /> <path - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" + d="m 39.774755,19.008621 a 8.6620579,8.6620579 0 1 1 -17.324116,0 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" sodipodi:ry="8.6620579" sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4322" - style="opacity:0.25;color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:2.165519px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path3407" + style="opacity:0.625;color:#000000;fill:none;stroke:url(#linearGradient2587);stroke-width:2.16551685px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(0.461783,0,0,0.461784,-5.867326,-3.277881)" /> + transform="matrix(0.461784,0,0,0.461784,-6.8673454,-3.2778773)" /> </g> </svg>
--- a/pidgin/plugins/Makefile.mingw Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/plugins/Makefile.mingw Mon Jun 30 23:12:54 2008 +0000 @@ -84,6 +84,7 @@ notify.dll \ pidginrc.dll \ relnot.dll \ + sendbutton.dll \ spellchk.dll \ timestamp_format.dll \ timestamp.dll
--- a/pidgin/plugins/cap/cap.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/plugins/cap/cap.c Mon Jun 30 23:12:54 2008 +0000 @@ -333,7 +333,7 @@ static gboolean max_message_difference_cb(gpointer data) { CapStatistics *stats = data; - purple_debug_info("cap", "Max Message Difference timeout occured\n"); + purple_debug_info("cap", "Max Message Difference timeout occurred\n"); insert_cap_failure(stats); stats->timeout_source_id = 0; return FALSE;
--- a/pidgin/plugins/spellchk.c Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/plugins/spellchk.c Mon Jun 30 23:12:54 2008 +0000 @@ -1740,6 +1740,7 @@ "BAD wroking\nGOOD working\n" "BAD wtih\nGOOD with\n" "BAD wuould\nGOOD would\n" + "BAD wud\nGOOD would\n" "BAD wut\nGOOD what\n" "BAD wya\nGOOD way\n" "BAD y\nGOOD why\n"
--- a/pidgin/win32/nsis/pidgin-installer.nsi Mon Jun 30 03:50:35 2008 +0000 +++ b/pidgin/win32/nsis/pidgin-installer.nsi Mon Jun 30 23:12:54 2008 +0000 @@ -748,6 +748,7 @@ Delete "$INSTDIR\plugins\pidginrc.dll" Delete "$INSTDIR\plugins\psychic.dll" Delete "$INSTDIR\plugins\relnot.dll" + Delete "$INSTDIR\plugins\sendbutton.dll" Delete "$INSTDIR\plugins\spellchk.dll" Delete "$INSTDIR\plugins\ssl-nss.dll" Delete "$INSTDIR\plugins\ssl.dll" @@ -1387,67 +1388,6 @@ FunctionEnd -; This is a modified StartRadioButtons (from Sections.nsh) -; The only difference is that it allows for nothing in the group to be selected -; In that case, the default variable should be set to "" -!macro StartRadioButtonsUnselectable var - - !define StartRadioButtons_Var "${var}" - - Push $R0 - Push $R1 - - ;If we have no selection, don't try to unselect it - StrCmp "${StartRadioButtons_Var}" "" +4 - SectionGetFlags "${StartRadioButtons_Var}" $R0 - IntOp $R1 $R0 & ${SF_SELECTED} - IntOp $R0 $R0 & ${SECTION_OFF} - SectionSetFlags "${StartRadioButtons_Var}" $R0 - - ; If the previous value isn't currently selected, - ; we don't want to select it at the end - IntCmp $R1 ${SF_SELECTED} +2 - StrCpy "${StartRadioButtons_Var}" "" - - StrCpy $R1 "${StartRadioButtons_Var}" - -!macroend - -Function .onSelChange - Push $0 - Push $1 - Push $2 - - ; Check that at most one of the non-readonly spelling dictionaries are selected - ; We can't use $R0 or $R1 in this block since they're used in the macros - !insertmacro StartRadioButtonsUnselectable $SPELLCHECK_SEL - ; Start with the first language dictionary - IntOp $2 ${SecSpellCheck} + 1 - - start_spellcheck_radio: - SectionGetFlags $2 $0 - - IntOp $1 $0 & ${SF_SECGRPEND} - ; If it is the end of the section group, stop - IntCmp $1 ${SF_SECGRPEND} end_spellcheck_radio - - IntOp $0 $0 & ${SF_RO} - IntCmp $0 ${SF_RO} after_button_insert - ; If !readonly, then it is part of the radiobutton group - !insertmacro RadioButton $2 - after_button_insert: - - IntOp $2 $2 + 1 ;Advance to the next section - Goto start_spellcheck_radio - - end_spellcheck_radio: - !insertmacro EndRadioButtons - - Pop $2 - Pop $1 - Pop $0 -FunctionEnd - ; Page enter and exit functions.. Function preWelcomePage
--- a/po/ar.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ar.po Mon Jun 30 23:12:54 2008 +0000 @@ -12918,12 +12918,18 @@ #, c-format msgid "%s requests %s to accept %d file: %s (%.2f %s)%s%s" msgid_plural "%s requests %s to accept %d files: %s (%.2f %s)%s%s" -msgstr[0] "%1$s لا يطلب من %2$s أن يقبل أيّة ملفات : %4$s (%5$.2f %6$s)%7$s%8$s" -msgstr[1] "%1$s يطلب من %2$s أن يقبل ملفا واحدا: %4$s (%5$.2f %6$s)%7$s%8$s" -msgstr[2] "%1$s يطلب من %2$s أن يقبل ملفين: %4$s (%5$.2f %6$s)%7$s%8$s" -msgstr[3] "%s يطلب من %s أن يقبل %Id ملفات: %s (%.2f %s)%s%s" -msgstr[4] "%s يطلب من %s أن يقبل %Id ملفا: %s (%.2f %s)%s%s" -msgstr[5] "%s يطلب من %s أن يقبل %Id ملف: %s (%.2f %s)%s%s" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" +#msgstr[0] "%1$s لا يطلب من %2$s أن يقبل أيّة ملفات : %4$s (%5$.2f %6$s)%7$s%8$s" +#msgstr[1] "%1$s يطلب من %2$s أن يقبل ملفا واحدا: %4$s (%5$.2f %6$s)%7$s%8$s" +#msgstr[2] "%1$s يطلب من %2$s أن يقبل ملفين: %4$s (%5$.2f %6$s)%7$s%8$s" +#msgstr[3] "%s يطلب من %s أن يقبل %Id ملفات: %s (%.2f %s)%s%s" +#msgstr[4] "%s يطلب من %s أن يقبل %Id ملفا: %s (%.2f %s)%s%s" +#msgstr[5] "%s يطلب من %s أن يقبل %Id ملف: %s (%.2f %s)%s%s" #: ../libpurple/protocols/toc/toc.c:2216 #, c-format @@ -14108,12 +14114,18 @@ #, c-format msgid "You have %d contact named %s. Would you like to merge them?" msgid_plural "You currently have %d contacts named %s. Would you like to merge them?" -msgstr[0] "لا مراسلين لديك باسم %2$s. أتريد دمجهم؟" -msgstr[1] "لديك مراسل واحد باسم %2$s. أتريد دمجه؟" -msgstr[2] "لديك مراسليْن باسم %2$s. أتريد دمجهما؟" -msgstr[3] "لديك %Id مراسلين باسم %s. أتريد دمجهم؟" -msgstr[4] "لديك %Id مراسلا باسم %s. أتريد دمجهم؟" -msgstr[5] "لديك %Id مراسل باسم %s. أتريد دمجهم؟" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" +#msgstr[0] "لا مراسلين لديك باسم %2$s. أتريد دمجهم؟" +#msgstr[1] "لديك مراسل واحد باسم %2$s. أتريد دمجه؟" +#msgstr[2] "لديك مراسليْن باسم %2$s. أتريد دمجهما؟" +#msgstr[3] "لديك %Id مراسلين باسم %s. أتريد دمجهم؟" +#msgstr[4] "لديك %Id مراسلا باسم %s. أتريد دمجهم؟" +#msgstr[5] "لديك %Id مراسل باسم %s. أتريد دمجهم؟" #: ../pidgin/gtkblist.c:550 msgid "" @@ -14476,12 +14488,18 @@ #, c-format msgid "%d unread message from %s\n" msgid_plural "%d unread messages from %s\n" -msgstr[0] "لا رسائل غير مقروءة من %2$s\n" -msgstr[1] "رسالة واحدة غير مقروءة من %2$s\n" -msgstr[2] "رسالتان غير مقروءتان من %2$s\n" -msgstr[3] "%Id رسائل غير مقروءة من %s\n" -msgstr[4] "%Id رسالة غير مقروءة من %s\n" -msgstr[5] "%Id رسالة غير مقروءة من %s\n" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" +#msgstr[0] "لا رسائل غير مقروءة من %2$s\n" +#msgstr[1] "رسالة واحدة غير مقروءة من %2$s\n" +#msgstr[2] "رسالتان غير مقروءتان من %2$s\n" +#msgstr[3] "%Id رسائل غير مقروءة من %s\n" +#msgstr[4] "%Id رسالة غير مقروءة من %s\n" +#msgstr[5] "%Id رسالة غير مقروءة من %s\n" #: ../pidgin/gtkblist.c:4238 msgid "Manually"
--- a/po/bn.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/bn.po Mon Jun 30 23:12:54 2008 +0000 @@ -6296,8 +6296,9 @@ "%s on the local list is inside the group \"%s\" but not on the server list. " "Do you want this buddy to be added?" msgstr "" -"স্থানীয় তালিকার %s গ্রুপ এ আছেন কিন্তু সার্ভার তালিকায় নেই।আপনি কি এই বন্ধুটিকে যোগ " -"করতে চান?" +#msgstr "" +#"স্থানীয় তালিকার %s গ্রুপ এ আছেন কিন্তু সার্ভার তালিকায় নেই।আপনি কি এই বন্ধুটিকে যোগ " +#"করতে চান?" #: ../libpurple/protocols/msn/dialog.c:124 #, c-format @@ -7833,7 +7834,8 @@ #: ../libpurple/protocols/novell/novell.c:705 #, c-format msgid "Could not get details for user %s (%s)." -msgstr "ব্যবহারকারী %s এর বিবরন পাওয়া যাচ্ছে না" +msgstr "" +#msgstr "ব্যবহারকারী %s এর বিবরন পাওয়া যাচ্ছে না" #: ../libpurple/protocols/novell/novell.c:751 #: ../libpurple/protocols/novell/novell.c:897 @@ -13730,8 +13732,8 @@ #, c-format msgid "%d unread message from %s\n" msgid_plural "%d unread messages from %s\n" -msgstr[0] "%s এর %d টি না পড়া বার্তা রয়েছে\n" -msgstr[1] "%s এর %d টি না পড়া বার্তা রয়েছে\n" +msgstr[0] "%2$s এর %1$d টি না পড়া বার্তা রয়েছে\n" +msgstr[1] "%2$s এর %1$d টি না পড়া বার্তা রয়েছে\n" #: ../pidgin/gtkblist.c:3822 msgid "Manually"
--- a/po/bs.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/bs.po Mon Jun 30 23:12:54 2008 +0000 @@ -8858,7 +8858,7 @@ msgid "You missed %hu message from %s because it was too large." msgid_plural "You missed %hu messages from %s because they were too large." msgstr[0] "Propustili ste %hu poruku od %s, jer je bila prevelika." -msgstr[1] "Propustili ste %hu poruke, jer su bile prevelike." +msgstr[1] "Propustili ste %hu poruke od %s, jer su bile prevelike." #: ../libpurple/protocols/oscar/oscar.c:2614 #, c-format
--- a/po/ca@valencia.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ca@valencia.po Mon Jun 30 23:12:54 2008 +0000 @@ -13740,15 +13740,16 @@ "You can come back to this window to add, edit, or remove accounts from " "<b>Accounts->Add/Edit</b> in the Buddy List window" msgstr "" -"<span size='larger' weight='bold'>Benvinguts al %s!</span>\n" -"\n" -"No teniu cap compte de MI configurat. Per a connectar-vos amb el %s premeu " -"el botó <b>Afig</b> de davall, i configureu el vostre primer compte. Si " -"voleu connectar-vos amb més d'un compte de MI, torneu a prémer <b>Afig</b> " -"fins a configurar-los tots.\n" -"\n" -"Podeu tornar a esta finestra per afegir, editar o suprimir comptes, a partir " -"del menú <b>Comptes->Afig/Edita</b> de la finestra de la llista d'amics." +#msgstr "" +#"<span size='larger' weight='bold'>Benvinguts al %s!</span>\n" +#"\n" +#"No teniu cap compte de MI configurat. Per a connectar-vos amb el %s premeu " +#"el botó <b>Afig</b> de davall, i configureu el vostre primer compte. Si " +#"voleu connectar-vos amb més d'un compte de MI, torneu a prémer <b>Afig</b> " +#"fins a configurar-los tots.\n" +#"\n" +#"Podeu tornar a esta finestra per afegir, editar o suprimir comptes, a partir " +#"del menú <b>Comptes->Afig/Edita</b> de la finestra de la llista d'amics." #: ../pidgin/gtkblist.c:767 msgid "Join a Chat"
--- a/po/de.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/de.po Mon Jun 30 23:12:54 2008 +0000 @@ -11,9 +11,9 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-05-26 21:14+0200\n" -"PO-Revision-Date: 2008-05-26 21:14+0200\n" -"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n" +"POT-Creation-Date: 2008-06-25 23:30+0200\n" +"PO-Revision-Date: 2008-06-25 23:27+0200\n" +"Last-Translator: Bjoern Voigt <bjoern@cs.tu-berlin.de>\n" "Language-Team: Deutsch <de@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -413,6 +413,9 @@ msgid "View Log..." msgstr "Mitschnitt anzeigen..." +msgid "View All Logs" +msgstr "Alle Mitschnitte anzeigen" + msgid "Show" msgstr "Anzeigen" @@ -612,6 +615,19 @@ msgid "Send To" msgstr "Senden an" +msgid "Invite message" +msgstr "Einladungsnachricht" + +msgid "Invite" +msgstr "Einladen" + +msgid "" +"Please enter the name of the user you wish to invite,\n" +"along with an optional invite message." +msgstr "" +"Bitte geben Sie den Benutzernamen der Person ein, die Sie einladen möchten " +"zusammen mit einer optionalen Einladungsnachricht." + msgid "Conversation" msgstr "Unterhaltung" @@ -624,6 +640,9 @@ msgid "Add Buddy Pounce..." msgstr "Buddy-Alarm hinzufügen..." +msgid "Invite..." +msgstr "Einladen..." + msgid "Enable Logging" msgstr "Mitschnitt einschalten" @@ -651,6 +670,20 @@ "zu erhalten.\n" "Die folgenden Kommandos sind in diesem Kontext verfügbar:\n" +#, c-format +msgid "" +"%s is not a valid message class. See '/help msgcolor' for valid message " +"classes." +msgstr "" +"%s ist keine gültige Nachrichtenklasse. Die gültigen Nachrichtenklassen " +"finden Sie unter '/help msgcolor'." + +#, c-format +msgid "%s is not a valid color. See '/help msgcolor' for valid colors." +msgstr "" +"%s ist keine gültige Farbe. Die gültigen Farben finden Sie unter '/help " +"msgcolor'." + msgid "" "say <message>: Send a message normally as if you weren't using a " "command." @@ -697,6 +730,20 @@ msgid "statuses: Show the savedstatuses window." msgstr "statuses: Das Fenster mit gespeicherten Status-Infos anzeigen." +msgid "" +"msgcolor <class> <foreground> <background>: Set the color " +"for different classes of messages in the conversation window.<br> <" +"class>: receive, send, highlight, action, timestamp<br> <foreground/" +"background>: black, red, green, blue, white, gray, darkgray, magenta, " +"cyan, default<br><br>EXAMPLE:<br> msgcolor send cyan default" +msgstr "" +"msgcolor <Klasse> <Vordergrund> <Hintergrund>: Die Farbe " +"für verschiedene Klassen von Nachrichten im Gesprächsfenster festlegen." +"<br> <Klasse>: receive, send, highlight, action, timestamp<br> " +"<Vordergrund/Hintergrund>: black, red, green, blue, white, gray, " +"darkgray, magenta, cyan, default<br><br>BEISPIEL:<br> msgcolor send cyan " +"default" + msgid "Unable to open file." msgstr "Konnte die Datei nicht öffnen." @@ -717,8 +764,10 @@ msgstr "Pause" #, c-format -msgid "File Transfers - %d%% of %d files" -msgstr "Dateiübertragungen - %d%% von %d Dateien" +msgid "File Transfers - %d%% of %d file" +msgid_plural "File Transfers - %d%% of %d files" +msgstr[0] "Dateiübertragungen - %d%% von %d Datei" +msgstr[1] "Dateiübertragungen - %d%% von %d Dateien" #. Create the window. msgid "File Transfers" @@ -833,11 +882,14 @@ msgid "Conversations with %s" msgstr "Unterhaltung mit %s" +msgid "All Conversations" +msgstr "Alle Unterhaltungen" + msgid "System Log" msgstr "System-Mitschnitt" msgid "Emails" -msgstr "Emails" +msgstr "E-Mails" msgid "You have mail!" msgstr "Sie haben Post!" @@ -870,9 +922,6 @@ msgid "IM" msgstr "Nachricht" -msgid "Invite" -msgstr "Einladen" - msgid "(none)" msgstr "(kein)" @@ -2785,7 +2834,7 @@ msgstr "Nachname" msgid "Email" -msgstr "Email" +msgstr "E-Mail" msgid "AIM Account" msgstr "AIM-Konto" @@ -2875,6 +2924,9 @@ msgid "Save buddylist..." msgstr "Buddy-Liste speichern..." +msgid "Load buddylist from file..." +msgstr "Buddy-Liste aus Datei laden..." + msgid "Fill in the registration fields." msgstr "Füllen Sie die Registrierungsfelder aus." @@ -3051,9 +3103,6 @@ msgid "Save buddylist to file..." msgstr "Buddy-Liste in Datei speichern..." -msgid "Load buddylist from file..." -msgstr "Buddy-Liste aus Datei laden..." - #. magic #. major_version #. minor_version @@ -3183,8 +3232,10 @@ msgstr "Falscher Modus" #, c-format -msgid "Ban on %s by %s, set %ld seconds ago" -msgstr "Verbot zu %s von %s, gesetzt vor %ld Sekunden" +msgid "Ban on %s by %s, set %ld second ago" +msgid_plural "Ban on %s by %s, set %ld seconds ago" +msgstr[0] "Verbot zu %s von %s, gesetzt vor %ld Sekunde" +msgstr[1] "Verbot zu %s von %s, gesetzt vor %ld Sekunden" #, c-format msgid "Ban on %s" @@ -3620,6 +3671,8 @@ msgid "Country" msgstr "Land" +#. lots of clients (including purple) do this, but it's +#. * out of spec msgid "Telephone" msgstr "Telefon" @@ -3807,12 +3860,12 @@ msgid "Capabilities" msgstr "Fähigkeiten" +msgid "Priority" +msgstr "Priorität" + msgid "Resource" msgstr "Ressource" -msgid "Priority" -msgstr "Priorität" - msgid "Middle Name" msgstr "Zweiter Name" @@ -3897,7 +3950,7 @@ "Benutzern zu suchen." msgid "Email Address" -msgstr "Email-Adresse" +msgstr "E-Mail-Adresse" msgid "Search for XMPP users" msgstr "Suche nach XMPP-Benutzern" @@ -4534,14 +4587,14 @@ msgstr "Standards _akzeptieren" #, c-format +msgid "Error joining chat %s" +msgstr "Fehler beim Betreten des Chats %s" + +#, c-format msgid "Error in chat %s" msgstr "Fehler im Chat %s" #, c-format -msgid "Error joining chat %s" -msgstr "Fehler beim Betreten des Chats %s" - -#, c-format msgid "Unable to send file to %s, user does not support file transfers" msgstr "" "Kann die Datei nicht an %s senden, da der Client des Benutzers keine " @@ -4635,7 +4688,7 @@ msgstr "Syntaxfehler (wahrscheinlich ein Client-Bug)" msgid "Invalid email address" -msgstr "Ungültige Email-Adresse" +msgstr "Ungültige E-Mail-Adresse" msgid "User does not exist" msgstr "Benutzer existiert nicht" @@ -4808,7 +4861,7 @@ msgstr "%s anstoßen..." msgid "Email Address..." -msgstr "Email-Adresse..." +msgstr "E-Mail-Adresse..." msgid "Your new MSN friendly name is too long." msgstr "Ihr neuer MSN-Benutzername zu lang." @@ -4997,7 +5050,7 @@ msgstr "Fax (privat)" msgid "Personal Email" -msgstr "Email (privat)" +msgstr "E-Mail (privat)" msgid "Personal IM" msgstr "IM (privat)" @@ -5040,7 +5093,7 @@ msgstr "Fax (geschäftlich)" msgid "Work Email" -msgstr "Email (geschäftlich)" +msgstr "E-Mail (geschäftlich)" msgid "Work IM" msgstr "IM (geschäftlich)" @@ -5367,8 +5420,11 @@ msgstr "Logge ein" #, c-format -msgid "Connection to server lost (no data received within %d seconds)" -msgstr "" +msgid "Connection to server lost (no data received within %d second)" +msgid_plural "Connection to server lost (no data received within %d seconds)" +msgstr[0] "" +"Verbindung zum Server verloren (seit %d Sekunde keine Daten empfangen)" +msgstr[1] "" "Verbindung zum Server verloren (seit %d Sekunden keine Daten empfangen)" #. Can't write _()'d strings in array initializers. Workaround. @@ -5468,9 +5524,15 @@ #, c-format msgid "" +"%d buddy was added or updated from the server (including buddies already on " +"the server-side list)" +msgid_plural "" "%d buddies were added or updated from the server (including buddies already " "on the server-side list)" -msgstr "" +msgstr[0] "" +"%d Buddy wurde vom Server hinzugefügt oder aktualisiert (inklusive der " +"Buddys, die schon auf der Serverliste sind)" +msgstr[1] "" "%d Buddys wurden vom Server hinzugefügt oder aktualisiert (inklusive der " "Buddys, die schon auf der Serverliste sind)" @@ -6110,11 +6172,11 @@ msgid "In local permit/deny" msgstr "In lokaler erlaubt/verboten-Liste" -msgid "Too evil (sender)" -msgstr "Zu boshaft (Sender)" - -msgid "Too evil (receiver)" -msgstr "Zu boshaft (Empfänger)" +msgid "Warning level too high (sender)" +msgstr "Warnstufe zu hoch (Absender)" + +msgid "Warning level too high (receiver)" +msgstr "Warnstufe zu hoch (Empfänger)" msgid "User temporarily unavailable" msgstr "Benutzer ist temporär nicht verfügbar" @@ -6218,6 +6280,9 @@ msgid "Camera" msgstr "Kamera" +msgid "Screen Sharing" +msgstr "Gemeinsamer Bildschirm" + msgid "Free For Chat" msgstr "Bereit zum Chatten" @@ -6275,7 +6340,7 @@ "only letters, numbers and spaces, or contain only numbers." msgstr "" "Anmeldung fehlgeschlagen: Sie konnten nicht als %s angemeldet werden, da der " -"Benutzername fehlerhaft ist. Benutzernamen müssen gültige Email-Adressen " +"Benutzername fehlerhaft ist. Benutzernamen müssen gültige E-Mail-Adressen " "sein oder mit einem Buchstaben beginnen und nur Buchstaben, Ziffern und " "Leerzeichen enthalten oder nur aus Ziffern bestehen." @@ -6350,6 +6415,7 @@ msgid "Unable to get a valid login hash." msgstr "Konnte keinen gültigen Login-Hash bekommen." +#. allow multple logins? msgid "Password sent" msgstr "Passwort gesendet" @@ -6424,7 +6490,7 @@ "Message is:\n" "%s" msgstr "" -"Sie haben eine ICQ-Email empfangen von %s [%s]\n" +"Sie haben eine ICQ-E-Mail empfangen von %s [%s]\n" "\n" "Nachricht:\n" "%s" @@ -6469,20 +6535,26 @@ "überschritten wurde." #, c-format -msgid "You missed %hu message from %s because he/she was too evil." -msgid_plural "You missed %hu messages from %s because he/she was too evil." +msgid "" +"You missed %hu message from %s because his/her warning level is too high." +msgid_plural "" +"You missed %hu messages from %s because his/her warning level is too high." msgstr[0] "" -"Sie haben %hu Nachricht von %s nicht erhalten, da er/sie zu boshaft war." +"Sie haben %hu Nachricht von %s nicht erhalten, da seine/ihre Warnstufe zu " +"hoch ist." msgstr[1] "" -"Sie haben %hu Nachrichten von %s nicht erhalten,/sie zu boshaft war." - -#, c-format -msgid "You missed %hu message from %s because you are too evil." -msgid_plural "You missed %hu messages from %s because you are too evil." +"Sie haben %hu Nachrichten von %s nicht erhalten, da seine/ihre Warnstufe zu " +"hoch ist." + +#, c-format +msgid "You missed %hu message from %s because your warning level is too high." +msgid_plural "" +"You missed %hu messages from %s because your warning level is too high." msgstr[0] "" -"Sie haben %hu Nachricht von %s nicht erhalten, da Sie zu boshaft sind." +"Sie haben %hu Nachricht von %s nicht erhalten, da Ihre Warnstufe zu hoch ist." msgstr[1] "" -"Sie haben %hu Nachrichten von %s nicht erhalten, da Sie zu boshaft sind." +"Sie haben %hu Nachrichten von %s nicht erhalten, da Ihre Warnstufe zu hoch " +"ist." #, c-format msgid "You missed %hu message from %s for an unknown reason." @@ -6514,9 +6586,6 @@ msgid "Member Since" msgstr "Mitglied seit" -msgid "Available Message" -msgstr "Verfügbarkeitsnachricht" - msgid "Your AIM connection may be lost." msgstr "Ihre AIM-Verbindung könnte unterbrochen sein." @@ -6546,12 +6615,17 @@ msgid "Personal Web Page" msgstr "Persönliche Webseite" +#. aim_userinfo_t +#. strip_html_tags msgid "Additional Information" msgstr "Zusätzliche Informationen" msgid "Zip Code" msgstr "PLZ" +msgid "Work Information" +msgstr "Information (Arbeit)" + msgid "Division" msgstr "Abteilung" @@ -6561,9 +6635,6 @@ msgid "Web Page" msgstr "Webseite" -msgid "Work Information" -msgstr "Information (Arbeit)" - msgid "Pop-Up Message" msgstr "Pop-Up Nachricht" @@ -6575,12 +6646,12 @@ #, c-format msgid "No results found for email address %s" -msgstr "Keine Ergebnisse für die Email-Adresse %s gefunden" +msgstr "Keine Ergebnisse für die E-Mail-Adresse %s gefunden" #, c-format msgid "You should receive an email asking to confirm %s." msgstr "" -"Sie sollten eine Email erhalten, in der Sie aufgefordert werden, %s zu " +"Sie sollten eine E-Mail erhalten, in der Sie aufgefordert werden, %s zu " "bestätigen." msgid "Account Confirmation Requested" @@ -6613,7 +6684,7 @@ "Error 0x%04x: Unable to change email address because there is already a " "request pending for this username." msgstr "" -"Error 0x%04x: Kann die Email-Adresse nicht ändern, weil es schon eine " +"Error 0x%04x: Kann die E-Mail-Adresse nicht ändern, weil es schon eine " "laufende Anfrage für diesen Benutzernamen gibt." #, c-format @@ -6621,7 +6692,7 @@ "Error 0x%04x: Unable to change email address because the given address has " "too many usernames associated with it." msgstr "" -"Fehler 0x%04x: Kann die Email-Adresse nicht ändern, weil zu dieser Adresse " +"Fehler 0x%04x: Kann die E-Mail-Adresse nicht ändern, weil zu dieser Adresse " "schon zu viele Benutzernamen gehören." #, c-format @@ -6629,7 +6700,7 @@ "Error 0x%04x: Unable to change email address because the given address is " "invalid." msgstr "" -"Fehler 0x%04x: Kann die Email-Adresse nicht ändern, weil die angegebene " +"Fehler 0x%04x: Kann die E-Mail-Adresse nicht ändern, weil die angegebene " "Adresse falsch ist." #, c-format @@ -6641,7 +6712,7 @@ #, c-format msgid "The email address for %s is %s" -msgstr "Die Email-Adresse für %s ist %s" +msgstr "Die E-Mail-Adresse für %s ist %s" msgid "Account Info" msgstr "Konto-Info" @@ -6705,7 +6776,7 @@ "numbers and spaces, or contain only numbers." msgstr "" "Konnte den Buddy %s nicht hinzufügen, da der Benutzername falsch ist. " -"Benutzernamen müssen gültige Email-Adressen sein oder mit einem Buchstaben " +"Benutzernamen müssen gültige E-Mail-Adressen sein oder mit einem Buchstaben " "beginnen und nur Buchstaben, Ziffern und Leerzeichen enthalten oder nur aus " "Ziffern bestehen." @@ -6784,12 +6855,6 @@ "Ihr IM-Bild wurde nicht gesendet. Sie können keine IM-Bilder in AIM-Chats " "senden." -msgid "Away Message" -msgstr "Abwesenheitsnachricht" - -msgid "<i>(retrieving)</i>" -msgstr "<i>(empfange)</i>" - msgid "iTunes Music Store Link" msgstr "iTunes Music Store Link" @@ -6864,13 +6929,13 @@ "fragen“ auswählen." msgid "Find Buddy by Email" -msgstr "Suche Buddys nach Email-Adresse" +msgstr "Suche Buddys nach E-Mail-Adresse" msgid "Search for a buddy by email address" -msgstr "Suche nach einem Buddy mit einer bestimmten Email-Adresse" +msgstr "Suche nach einem Buddy mit einer bestimmten E-Mail-Adresse" msgid "Type the email address of the buddy you are searching for." -msgstr "Geben Sie die Email-Adresse des Buddys ein, nach dem Sie suchen." +msgstr "Geben Sie die E-Mail-Adresse des Buddys ein, nach dem Sie suchen." msgid "_Search" msgstr "_Suchen" @@ -6893,16 +6958,16 @@ msgstr "Konto bestätigen" msgid "Display Currently Registered Email Address" -msgstr "Zeige die aktuell registrierte Email-Adresse" +msgstr "Zeige die aktuell registrierte E-Mail-Adresse" msgid "Change Currently Registered Email Address..." -msgstr "Ändere die aktuell registrierte Email-Adresse..." +msgstr "Ändere die aktuell registrierte E-Mail-Adresse..." msgid "Show Buddies Awaiting Authorization" msgstr "Zeige Buddys, von denen Sie Autorisierung erwarten" msgid "Search for Buddy by Email Address..." -msgstr "Suche Buddys nach Email-Adresse..." +msgstr "Suche Buddys nach E-Mail-Adresse..." msgid "Search for Buddy by Information" msgstr "Suche Buddy nach Information" @@ -6916,6 +6981,9 @@ "Dateiübertragungen und Direkt-IM (langsamer,\n" "aber zeigt Ihre IP-Adresse nicht)" +msgid "Allow multiple simultaneous logins" +msgstr "Mehrere gleichzeitige Logins erlauben" + #, c-format msgid "Asking %s to connect to us at %s:%hu for Direct IM." msgstr "Frage %s, ob er sich zu uns auf %s:%hu für Direkt-IM verbinden möchte." @@ -8740,7 +8808,7 @@ #, c-format msgid "Email: \t\t%s\n" -msgstr "Email: \t\t%s\n" +msgstr "E-Mail: \t\t%s\n" #, c-format msgid "Host Name: \t%s\n" @@ -8988,7 +9056,7 @@ msgstr "Verzeichnis-Dienst ist zur Zeit nicht verfügbar." msgid "Email lookup restricted." -msgstr "Email-Suche eingeschränkt." +msgstr "E-Mail-Suche eingeschränkt." msgid "Keyword ignored." msgstr "Stichwort ignoriert." @@ -9695,7 +9763,6 @@ msgid "Stored Image" msgstr "Gespeichertes Bild" -#, fuzzy msgid "Stored Image. (that'll have to do for now)" msgstr "Gespeichertes Bild. (Das muss erstmal reichen)" @@ -10185,8 +10252,8 @@ msgid "/_Accounts" msgstr "/_Konten" -msgid "/Accounts/Manage" -msgstr "/Konten/Verwalten" +msgid "/Accounts/Manage Accounts" +msgstr "/Konten/Konten verwalten" #. Tools msgid "/_Tools" @@ -10198,9 +10265,6 @@ msgid "/Tools/_Certificates" msgstr "/Werkzeuge/_Zertifikate" -msgid "/Tools/Smile_y" -msgstr "/Werkzeuge/Smile_y" - msgid "/Tools/Plu_gins" msgstr "/Werkzeuge/Plu_gins" @@ -10210,6 +10274,9 @@ msgid "/Tools/Pr_ivacy" msgstr "/Werkzeuge/Pri_vatsphäre" +msgid "/Tools/Smile_y" +msgstr "/Werkzeuge/Smile_y" + msgid "/Tools/_File Transfers" msgstr "/Werkzeuge/_Dateiübertragungen" @@ -10376,13 +10443,13 @@ "<span weight='bold' size='larger'>Welcome to %s!</span>\n" "\n" "You have no accounts enabled. Enable your IM accounts from the <b>Accounts</" -"b> window at <b>Accounts->Manage</b>. Once you enable accounts, you'll be " -"able to sign on, set your status, and talk to your friends." +"b> window at <b>Accounts->Manage Accounts</b>. Once you enable accounts, " +"you'll be able to sign on, set your status, and talk to your friends." msgstr "" "<span weight='bold' size='larger'>Willkommen bei %s!</span>\n" "\n" "Sie haben keine Konten aktiviert. Aktivieren Sie Ihre IM-Konten vom " -"<b>Konten</b>-Fenster über <b>Konten->Verwalten</b>. Wenn Sie Konten " +"<b>Konten</b>-Fenster über <b>Konten->Konten verwalten</b>. Wenn Sie Konten " "aktiviert haben, können Sie sich anmelden, Ihren Status setzen und mit Ihren " "Freunden reden." @@ -10443,6 +10510,12 @@ msgid "Please enter the name of the group to be added." msgstr "Bitte geben Sie den Namen der Gruppe ein, die hinzugefügt werden soll." +msgid "Enable Account" +msgstr "Konten aktivieren" + +msgid "<PurpleMain>/Accounts/Enable Account" +msgstr "<PurpleMain>/Konten/Konto aktivieren" + msgid "<PurpleMain>/Accounts/" msgstr "<PurpleMain>/Konten/" @@ -10455,12 +10528,6 @@ msgid "_Disable" msgstr "_Deaktivieren" -msgid "Enable Account" -msgstr "Konten aktivieren" - -msgid "<PurpleMain>/Accounts/Enable Account" -msgstr "<PurpleMain>/Konten/Konto aktivieren" - msgid "/Tools" msgstr "/Werkzeuge" @@ -11375,9 +11442,8 @@ msgid "Color to draw the name of an action message." msgstr "Farbe, mit der der Name in einer Aktions-Nachricht dargestellt wird." -#, fuzzy msgid "Action Message Name Color for Whispered Message" -msgstr "Farbe des Absendernamens für Aktions-Nachrichten" +msgstr "Farbe des Absendernamens für geflüsterte Aktions-Nachrichten" msgid "Whisper Message Name Color" msgstr "Farbe des Absendernamens für Flüster-Nachrichten" @@ -11400,7 +11466,7 @@ msgstr "Tipp-Benachrichtigung aktivieren" msgid "_Copy Email Address" -msgstr "Kopiere _Email-Adresse" +msgstr "Kopiere _E-Mail-Adresse" msgid "_Open Link in Browser" msgstr "Ö_ffne Link im Browser" @@ -11452,7 +11518,6 @@ msgid "_Save Image..." msgstr "Bild _speichern..." -#, fuzzy msgid "_Add Custom Smiley..." msgstr "Benutzerdefinierten Smiley _hinzufügen..." @@ -11494,16 +11559,18 @@ msgid "Insert Image" msgstr "Bild einfügen" -msgid "" -"This smiley is disabled because a custom smiley exists for this shortcut." +#, c-format +msgid "" +"This smiley is disabled because a custom smiley exists for this shortcut:\n" +" %s" msgstr "" "Dieser Smiley ist deaktiviert, da ein benutzerdefinierter Smiley für diese " -"Tastenkombination existiert." +"Tastenkombination existiert:\n" +" %s" msgid "Smile!" msgstr "Lächeln!" -#, fuzzy msgid "_Manage custom smileys" msgstr "Benutzerdefinierte Smileys _verwalten" @@ -11771,8 +11838,8 @@ #, c-format msgid "<b>%d new email.</b>" msgid_plural "<b>%d new emails.</b>" -msgstr[0] "<b>%d neue Email.</b>" -msgstr[1] "<b>%d neue Emails.</b>" +msgstr[0] "<b>%d neue E-Mail.</b>" +msgstr[1] "<b>%d neue E-Mails.</b>" #, c-format msgid "The browser command \"%s\" is invalid." @@ -12857,19 +12924,19 @@ msgstr "_Assoziiere den Buddy" msgid "Unable to send email" -msgstr "Email konnte nicht gesendet werden" +msgstr "E-Mail konnte nicht gesendet werden" msgid "The evolution executable was not found in the PATH." msgstr "Die ausführbare Evolution-Datei wurde nicht im Pfad (PATH) gefunden." msgid "An email address was not found for this buddy." -msgstr "Für diesen Buddy wurde keine Email-Adresse gefunden." +msgstr "Für diesen Buddy wurde keine E-Mail-Adresse gefunden." msgid "Add to Address Book" msgstr "Zum Adressbuch hinzufügen" msgid "Send Email" -msgstr "Email senden" +msgstr "E-Mail senden" #. Configuration frame msgid "Evolution Integration Configuration" @@ -12919,7 +12986,7 @@ msgstr "Nachname:" msgid "Email:" -msgstr "Email:" +msgstr "E-Mail:" #. *< type #. *< ui_requirement @@ -12972,7 +13039,7 @@ msgid "Adds a small box to the buddy list that shows if you have new mail." msgstr "" -"Fügt eine kleine Box zur Buddy-Liste hinzu, die zeigt, ob Sie neue Emails " +"Fügt eine kleine Box zur Buddy-Liste hinzu, die zeigt, ob Sie neue E-Mails " "haben." msgid "Markerline"
--- a/po/en_AU.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/en_AU.po Mon Jun 30 23:12:54 2008 +0000 @@ -14896,7 +14896,7 @@ msgid "%d person in room" msgid_plural "%d people in room" msgstr[0] "%d person in room" -msgstr[1] "%d person in room" +msgstr[1] "%d people in room" #: ../pidgin/gtkconv.c:6486 ../pidgin/gtkstatusbox.c:660 #, fuzzy
--- a/po/en_GB.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/en_GB.po Mon Jun 30 23:12:54 2008 +0000 @@ -2911,7 +2911,7 @@ msgstr "Your current password is different from the one that you specified." msgid "Unable to change password. Error occurred.\n" -msgstr "Unable to change password. An error occured.\n" +msgstr "Unable to change password. An error occurred.\n" msgid "Change password for the Gadu-Gadu account" msgstr "Change password for the Gadu-Gadu account" @@ -5270,7 +5270,7 @@ msgstr "Message could not be sent because the user is offline:" msgid "Message could not be sent because a connection error occurred:" -msgstr "Message could not be sent because a connection error occured:" +msgstr "Message could not be sent because a connection error occurred:" msgid "Message could not be sent because we are sending too quickly:" msgstr "Message could not be sent because we are sending too quickly:"
--- a/po/fi.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/fi.po Mon Jun 30 23:12:54 2008 +0000 @@ -16488,7 +16488,6 @@ "<span foreground=\"red\" weight=\"bold\">Error: %s\n" "Check the plugin website for an update.</span>" msgstr "" -"%s\n" "<span foreground=\"red\" weight=\"bold\">Virhe: %s\n" "Tarkista onko liitännäisen WWW-sivustolla päivitystä.</span>"
--- a/po/gl.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/gl.po Mon Jun 30 23:12:54 2008 +0000 @@ -14,7 +14,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: KBabel 1.11.4\n" #: ../finch/finch.c:64 ../finch/finch.c:301 ../finch/finch.c:330
--- a/po/it.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/it.po Mon Jun 30 23:12:54 2008 +0000 @@ -3833,8 +3833,8 @@ msgstr "Impossibile trovare un'installazione di ActiveTCL. Se vuoi usare i plugin TCL, installa ActiveTCL da http://www.activestate.com\n" #: ../libpurple/protocols/bonjour/bonjour.c:107 -msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging for more information." -msgstr "Il toolkit Apple Bonjour per Windows non è stato trovato. Leggi le FAQ su: http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging per maggiori informazioni." +msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://d.pidgin.im/BonjourWindows for more information." +msgstr "Il toolkit Apple Bonjour per Windows non è stato trovato. Leggi le FAQ su: http://d.pidgin.im/BonjourWindows per maggiori informazioni." #: ../libpurple/protocols/bonjour/bonjour.c:126 msgid "Unable to listen for incoming IM connections\n"
--- a/po/ko.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ko.po Mon Jun 30 23:12:54 2008 +0000 @@ -913,7 +913,7 @@ msgid "%s (%s) has %d new message." msgid_plural "%s (%s) has %d new messages." msgstr[0] "%s (%s) 에는 %d 개의 새 메일이 있습니다." -msgstr[1] "%s (%s) 에는 %d 개의 새 메일이 있습니다." +#msgstr[1] "%s (%s) 에는 %d 개의 새 메일이 있습니다." #: ../console/gntnotify.c:206 #: ../gtk/gtknotify.c:322 @@ -1875,7 +1875,7 @@ msgid "%d unread message from %s\n" msgid_plural "%d unread messages from %s\n" msgstr[0] "%2$s 님으로부터 %1$d개의 읽지 않은 메일이 있습니다.\n" -msgstr[1] "%2$s さんから %1$d個の未?のメッセ?ジがあります\n" +#msgstr[1] "%2$s さんから %1$d個の未?のメッセ?ジがあります\n" #: ../gtk/gtkblist.c:3654 msgid "Manually" @@ -2357,7 +2357,7 @@ msgid "%d person in room" msgid_plural "%d people in room" msgstr[0] "대화실에 %d 명이 있습니다." -msgstr[1] "대화실에 %d 명이 있습니다." +#msgstr[1] "대화실에 %d 명이 있습니다." #: ../gtk/gtkconv.c:5855 #: ../gtk/gtkstatusbox.c:567 @@ -2902,7 +2902,7 @@ msgid "You are about to remove the contact containing %s and %d other buddy from your buddy list. Do you want to continue?" msgid_plural "You are about to remove the contact containing %s and %d other buddies from your buddy list. Do you want to continue?" msgstr[0] "친구 목록에서 %s 님을 포함한 %d 명의 친구의 삭제하려고 합니다. 계속 하시겠습니까?" -msgstr[1] "친구 목록에서 %s 님을 포함한 %d 명의 친구의 삭제하려고 합니다. 계속 하시겠습니까?" +#msgstr[1] "친구 목록에서 %s 님을 포함한 %d 명의 친구의 삭제하려고 합니다. 계속 하시겠습니까?" #: ../gtk/gtkdialogs.c:1016 msgid "Remove Contact" @@ -3598,14 +3598,14 @@ msgid "%s has %d new message." msgid_plural "%s has %d new messages." msgstr[0] "%s 에는 %d 개의 새로운 메시지가 있습니다." -msgstr[1] "%s 에는 %d 개의 새로운 메시지가 있습니다." +#msgstr[1] "%s 에는 %d 개의 새로운 메시지가 있습니다." #: ../gtk/gtknotify.c:511 #, c-format msgid "<b>You have %d new email.</b>" msgid_plural "<b>You have %d new emails.</b>" msgstr[0] "<b>%d 개의 새로운 메시지가 있습니다.</b>" -msgstr[1] "<b>%d 개의 새로운 메시지가 있습니다.</b>" +#msgstr[1] "<b>%d 개의 새로운 메시지가 있습니다.</b>" #: ../gtk/gtknotify.c:699 #: ../libgaim/protocols/sametime/sametime.c:5548 @@ -5919,7 +5919,7 @@ msgid "%d buddy from group %s was not removed because it belongs to an account which is disabled or offline. This buddy and the group were not removed.\n" msgid_plural "%d buddies from group %s were not removed because they belong to accounts which are currently disabled or offline. These buddies and the group were not removed.\n" msgstr[0] "%d 개의 계정이 사용 안 함 또는 오프라인 상태이기 때문에 그 계정을 그룹 %s (으)로부터 삭제하지 못했습니다. 그 친구와 그룹은 삭제할 수 없습니다.\n" -msgstr[1] "%d 개의 계정이 사용 안 함 또는 오프라인 상태이기 때문에 그 계정을 그룹 %s (으)로부터 삭제하지 못했습니다. 그 친구와 그룹은 삭제할 수 없습니다.\n" +#msgstr[1] "%d 개의 계정이 사용 안 함 또는 오프라인 상태이기 때문에 그 계정을 그룹 %s (으)로부터 삭제하지 못했습니다. 그 친구와 그룹은 삭제할 수 없습니다.\n" #: ../libgaim/blist.c:1929 msgid "Group not removed" @@ -9869,10 +9869,10 @@ "MSN 서비스가 유지보수를 위해 %d 분간 정지하고 있습니다. 자동으로 접속이 끊길 예정이므로, 지금 수행되고 있는 대화를 종료해 주십시오.\n" "\n" "유지보수가 완료되면 다시 접속이 가능합니다." -msgstr[1] "" -"MSN 서비스가 유지보수를 위해 %d 분간 정지하고 있습니다. 자동으로 접속이 끊길 예정이므로, 지금 수행되고 있는 대화를 종료해 주십시오.\n" -"\n" -"유지보수가 완료되면 다시 접속이 가능합니다." +#msgstr[1] "" +#"MSN 서비스가 유지보수를 위해 %d 분간 정지하고 있습니다. 자동으로 접속이 끊길 예정이므로, 지금 수행되고 있는 대화를 종료해 주십시오.\n" +#"\n" +#"유지보수가 완료되면 다시 접속이 가능합니다." #: ../libgaim/protocols/msn/servconn.c:135 msgid "Writing error" @@ -10921,42 +10921,42 @@ msgid "You missed %hu message from %s because it was invalid." msgid_plural "You missed %hu messages from %s because they were invalid." msgstr[0] "%2$s 님으로부터의 %1$hu 개의 메시지는 타당하지 않아 받지 못했습니다." -msgstr[1] "%2$s 님으로부터의 %1$hu 개의 메시지는 타당하지 않아 받지 못했습니다." +#msgstr[1] "%2$s 님으로부터의 %1$hu 개의 메시지는 타당하지 않아 받지 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2560 #, c-format msgid "You missed %hu message from %s because it was too large." msgid_plural "You missed %hu messages from %s because they were too large." msgstr[0] "%2$s 님으로부터의 %1$hu개의 메시지는 너무 커서 받지 못했습니다." -msgstr[1] "%2$s 님으로부터의 %1$hu개의 메시지는 너무 커서 받지 못했습니다." +#msgstr[1] "%2$s 님으로부터의 %1$hu개의 메시지는 너무 커서 받지 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2569 #, c-format msgid "You missed %hu message from %s because the rate limit has been exceeded." msgid_plural "You missed %hu messages from %s because the rate limit has been exceeded." msgstr[0] "속도 제한을 상회하여, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." -msgstr[1] "속도 제한을 상회하여, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." +#msgstr[1] "속도 제한을 상회하여, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2578 #, c-format msgid "You missed %hu message from %s because he/she was too evil." msgid_plural "You missed %hu messages from %s because he/she was too evil." msgstr[0] "유해한 상대방이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." -msgstr[1] "유해한 상대방이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." +#msgstr[1] "유해한 상대방이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2587 #, c-format msgid "You missed %hu message from %s because you are too evil." msgid_plural "You missed %hu messages from %s because you are too evil." msgstr[0] "유해한 자신이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." -msgstr[1] "유해한 자신이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." +#msgstr[1] "유해한 자신이어서, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2596 #, c-format msgid "You missed %hu message from %s for an unknown reason." msgid_plural "You missed %hu messages from %s for an unknown reason." msgstr[0] "원인은 알 수 없지만, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." -msgstr[1] "원인은 알 수 없지만, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." +#msgstr[1] "원인은 알 수 없지만, %2$s 님으로부터의 %1$hu개의 메시지를 못했습니다." #: ../libgaim/protocols/oscar/oscar.c:2718 #, c-format @@ -11178,7 +11178,7 @@ msgid "The maximum profile length of %d byte has been exceeded. It has been truncated for you." msgid_plural "The maximum profile length of %d bytes has been exceeded. It has been truncated for you." msgstr[0] "프로파일 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." -msgstr[1] "프로파일 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." +#msgstr[1] "프로파일 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." #: ../libgaim/protocols/oscar/oscar.c:4461 msgid "Profile too long." @@ -11189,7 +11189,7 @@ msgid "The maximum away message length of %d byte has been exceeded. It has been truncated for you." msgid_plural "The maximum away message length of %d bytes has been exceeded. It has been truncated for you." msgstr[0] "자리 비움 메시지 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." -msgstr[1] "자리 비움 메시지 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." +#msgstr[1] "자리 비움 메시지 길이가 최대값 %d 바이트를 초과하여 일부가 잘렸습니다." #: ../libgaim/protocols/oscar/oscar.c:4510 msgid "Away message too long." @@ -14183,7 +14183,7 @@ msgid "%s requests %s to accept %d file: %s (%.2f %s)%s%s" msgid_plural "%s requests %s to accept %d files: %s (%.2f %s)%s%s" msgstr[0] "%s 님으로부터 %s 님에게 %d 개의 파일 요청: %s (%.2f %s)%s%s" -msgstr[1] "%s 님으로부터 %s 님에게 %d 개의 파일 요청: %s (%.2f %s)%s%s" +#msgstr[1] "%s 님으로부터 %s 님에게 %d 개의 파일 요청: %s (%.2f %s)%s%s" #: ../libgaim/protocols/toc/toc.c:2236 #, c-format @@ -14945,42 +14945,42 @@ msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d 초" -msgstr[1] "%d 초" +#msgstr[1] "%d 초" #: ../libgaim/util.c:2939 #, c-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d 일" -msgstr[1] "%d 일" +#msgstr[1] "%d 일" #: ../libgaim/util.c:2947 #, c-format msgid "%s, %d hour" msgid_plural "%s, %d hours" msgstr[0] "%s %d 시간" -msgstr[1] "%s %d 시간" +#msgstr[1] "%s %d 시간" #: ../libgaim/util.c:2953 #, c-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d 시간" -msgstr[1] "%d 시간" +#msgstr[1] "%d 시간" #: ../libgaim/util.c:2961 #, c-format msgid "%s, %d minute" msgid_plural "%s, %d minutes" msgstr[0] "%s %d 분" -msgstr[1] "%s %d 분" +#msgstr[1] "%s %d 분" #: ../libgaim/util.c:2967 #, c-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d 분" -msgstr[1] "%d 분" +#msgstr[1] "%d 분" #: ../libgaim/util.c:3166 #: ../libgaim/util.c:3464
--- a/po/lo.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/lo.po Mon Jun 30 23:12:54 2008 +0000 @@ -14,7 +14,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +#"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../finch/finch.c:64 ../finch/finch.c:301 ../finch/finch.c:330 #: ../finch/finch.c:418
--- a/po/lt.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/lt.po Mon Jun 30 23:12:54 2008 +0000 @@ -721,8 +721,11 @@ msgstr "Pristabdyti" #, c-format -msgid "File Transfers - %d%% of %d files" -msgstr "Failų perdavimai – %d%% iš %d" +msgid "File Transfers - %d%% of %d file" +msgid_plural "File Transfers - %d%% of %d files" +msgstr[0] "Failų perdavimai – %d%% iš %d failo" +msgstr[1] "Failų perdavimai – %d%% iš %d failų" +msgstr[2] "Failų perdavimai – %d%% iš %d failų" #. Create the window. msgid "File Transfers" @@ -3258,8 +3261,11 @@ msgstr "Bloga būsena" #, c-format -msgid "Ban on %s by %s, set %ld seconds ago" -msgstr "Vartotojui %s uždraudė prisijungti %s prieš %ld sekundžių" +msgid "Ban on %s by %s, set %ld second ago" +msgid_plural "Ban on %s by %s, set %ld seconds ago" +msgstr[0] "Vartotojui %s uždraudė prisijungti %s prieš %ld sekundę" +msgstr[1] "Vartotojui %s uždraudė prisijungti %s prieš %ld sekundes" +msgstr[2] "Vartotojui %s uždraudė prisijungti %s prieš %ld sekundžių" #, c-format msgid "Ban on %s" @@ -5439,8 +5445,11 @@ msgstr "Prisijungiama" #, c-format -msgid "Connection to server lost (no data received within %d seconds)" -msgstr "Nutrūko ryšys su serveriu (negauta jokių duomenų per %d sekundžių)" +msgid "Connection to server lost (no data received within %d second)" +msgid_plural "Connection to server lost (no data received within %d seconds)" +msgstr[0] "Nutrūko ryšys su serveriu (negauta jokių duomenų per %d sekundę)" +msgstr[1] "Nutrūko ryšys su serveriu (negauta jokių duomenų per %d sekundes)" +msgstr[2] "Nutrūko ryšys su serveriu (negauta jokių duomenų per %d sekundžių)" #. Can't write _()'d strings in array initializers. Workaround. msgid "New mail messages" @@ -5538,9 +5547,18 @@ #, c-format msgid "" +"%d buddy was added or updated from the server (including buddies already on " +"the server-side list)" +msgid_plural "" "%d buddies were added or updated from the server (including buddies already " "on the server-side list)" -msgstr "" +msgstr[0] "" +"%d bičiulis buvo pridėtas ar atnaujintas iš serverio (įskaitant ir " +"bičiulius, jau esančius serverio sąraše)" +msgstr[1] "" +"%d bičiuliai buvo pridėti ar atnaujinti iš serverio (įskaitant ir bičiulius, " +"jau esančius serverio sąraše)" +msgstr[2] "" "%d bičiulių buvo pridėta ar atnaujinta iš serverio (įskaitant ir bičiulius, " "jau esančius serverio sąraše)"
--- a/po/nb.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/nb.po Mon Jun 30 23:12:54 2008 +0000 @@ -3877,7 +3877,7 @@ msgstr "Kunne ikke finne en ActiveTCL installasjon. Om du ønsker å bruke TCL tillegg, installer ActiveTCL fra http://www.activestate.com\n" #: ../libpurple/protocols/bonjour/bonjour.c:101 -msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging for more information." +msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://d.pidgin.im/BonjourWindows for more information." msgstr "" #: ../libpurple/protocols/bonjour/bonjour.c:120 @@ -10311,7 +10311,7 @@ #: ../libpurple/protocols/qq/sys_msg.c:166 #, c-format msgid "You have been added by %s" -msgstr "Du har blitt lagt til av %s (%s)" +msgstr "Du har blitt lagt til av %s" #: ../libpurple/protocols/qq/sys_msg.c:169 #: ../libpurple/protocols/qq/sys_msg.c:263
--- a/po/nl.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/nl.po Mon Jun 30 23:12:54 2008 +0000 @@ -2489,10 +2489,11 @@ "Activation date: %s\n" "Expiration date: %s\n" msgstr "" -"Gemeenschappelijke naam: %s\n" -"\n" -"Vingerafdruk (SHA1): %s\n" -"\n" +#msgstr "" +#"Gemeenschappelijke naam: %s\n" +#"\n" +#"Vingerafdruk (SHA1): %s\n" +#"\n" #. TODO: Find what the handle ought to be #: ../libpurple/certificate.c:1905 @@ -6982,7 +6983,7 @@ #: ../libpurple/protocols/msn/msn.c:129 ../libpurple/protocols/msnp9/msn.c:130 #, c-format msgid "%s has nudged you!" -msgstr "%s heeft je aangestoten [%s]" +msgstr "%s heeft je aangestoten" #: ../libpurple/protocols/msn/msn.c:129 ../libpurple/protocols/msnp9/msn.c:130 #, c-format @@ -8177,7 +8178,8 @@ #: ../libpurple/protocols/myspace/zap.c:59 #, c-format msgid "%s has torched you!" -msgstr "De gebruiker heeft u befakkeld" +msgstr "" +#msgstr "De gebruiker heeft u befakkeld" #: ../libpurple/protocols/myspace/zap.c:59 #, c-format @@ -8876,9 +8878,10 @@ "(There was an error receiving this message. Either you and %s have " "different encodings selected, or %s has a buggy client.)" msgstr "" -"(Er is een fout opgetreden bij het ontvangen van het bericht. Of jij en %s " -"hebben verschillende coderingen geselecteerd of de andere persoon gebruikt " -"een chatprogramma met fouten.)" +#msgstr "" +#"(Er is een fout opgetreden bij het ontvangen van het bericht. Of jij en %s " +#"hebben verschillende coderingen geselecteerd of de andere persoon gebruikt " +#"een chatprogramma met fouten.)" #. Label #: ../libpurple/protocols/oscar/oscar.c:640 ../pidgin/gtkutils.c:2449 @@ -10452,7 +10455,7 @@ #: ../libpurple/protocols/qq/send_file.c:707 #, c-format msgid "%d has declined the file %s" -msgstr "%s heeft het onderwerp veranderd naar: %sx" +msgstr "%d heeft het onderwerp veranderd naar: %s" #: ../libpurple/protocols/qq/send_file.c:710 #: ../libpurple/protocols/qq/send_file.c:739 @@ -14558,7 +14561,7 @@ "<b>Occupants:</b> %d" msgstr "" "\n" -"<b>Deelnemers:</b> %s" +"<b>Deelnemers:</b> %d" #: ../pidgin/gtkblist.c:3253 #, c-format
--- a/po/ps.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ps.po Mon Jun 30 23:12:54 2008 +0000 @@ -15,7 +15,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +#"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../finch/finch.c:64 ../finch/finch.c:301 ../finch/finch.c:330 #: ../finch/finch.c:418
--- a/po/sq.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/sq.po Mon Jun 30 23:12:54 2008 +0000 @@ -14,6 +14,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: KBabel 1.0.2\n" "X-Poedit-Language: Albanian\n" "X-Poedit-Country: ALBANIA\n"
--- a/po/ta.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ta.po Mon Jun 30 23:12:54 2008 +0000 @@ -17,7 +17,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"Plural-Forms: Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-Country: INDIA\n" "X-Generator: KBabel 1.11.4\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,-1,-1,-1,-1,1715\n"
--- a/po/te.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/te.po Mon Jun 30 23:12:54 2008 +0000 @@ -9,6 +9,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Translate Toolkit 0.10\n" "X-Poedit-Language: Telugu\n" "X-Poedit-SourceCharset: utf-8\n" @@ -349,7 +350,7 @@ #: ../pidgin/gtkaccount.c:2447 #, c-format msgid "%s%s%s%s has made %s his or her buddy%s%s" -msgstr " %s%s%s తన మిత్రుడు లేదా స్నేహితురాలు %s%s గా %s ను చేర్చుకున్నారు " +msgstr "%s%s%s%s తన మిత్రుడు లేదా స్నేహితురాలు %s%s గా %s ను చేర్చుకున్నారు " #: ../finch/gntaccount.c:884 #: ../pidgin/gtkaccount.c:2499 @@ -1044,7 +1045,7 @@ msgstr "" "%s\n" "\n" -"%s లోపాన్ని సరిచేసి అకౌంటును తిరిగి క్రియాశీలం చేసేదాకా అకౌంటుకు మళ్ళీ కనెక్ట్ చేయడానికి ప్రయత్నించదు." +"లోపాన్ని సరిచేసి అకౌంటును తిరిగి క్రియాశీలం చేసేదాకా అకౌంటుకు మళ్ళీ కనెక్ట్ చేయడానికి ప్రయత్నించదు." #: ../finch/gntconn.c:138 msgid "Re-enable Account" @@ -1427,8 +1428,8 @@ #, c-format msgid "%s (%s) has %d new message." msgid_plural "%s (%s) has %d new messages." -msgstr[0] "%s has %d new message." -msgstr[1] "%s के %d लिए नये संदेश हैं।" +msgstr[0] "%s (%s) has %d new message." +msgstr[1] "%s (%s) के %d लिए नये संदेश हैं।" #: ../finch/gntnotify.c:226 #: ../pidgin/gtknotify.c:342 @@ -2496,7 +2497,8 @@ #: ../libpurple/certificate.c:1185 #, c-format msgid "Accept certificate for %s?" -msgstr "సంభాషణ ఆహ్వానాన్ని అంగీకరించారా?" +msgstr "" +#msgstr "సంభాషణ ఆహ్వానాన్ని అంగీకరించారా?" #. TODO: Find what the handle ought to be #: ../libpurple/certificate.c:1191 @@ -3122,7 +3124,8 @@ #: ../libpurple/plugin.c:663 #, c-format msgid "%s requires %s, but it failed to unload." -msgstr "%s డిపెండర్ ప్లగ్ ఇన్ అన్ లోడ్ కావడంలో వైఫల్యం." +msgstr "" +#msgstr "%s డిపెండర్ ప్లగ్ ఇన్ అన్ లోడ్ కావడంలో వైఫల్యం." #: ../libpurple/plugins/autoaccept.c:23 msgid "Autoaccept" @@ -3508,7 +3511,7 @@ #: ../libpurple/plugins/statenotify.c:80 #, c-format msgid "%s has signed off." -msgstr "%s సైన్ ఆఫ్ చేశారు. (%s)" +msgstr "%s సైన్ ఆఫ్ చేశారు." #: ../libpurple/plugins/log_reader.c:1587 msgid "One or more messages may have been undeliverable." @@ -4056,7 +4059,7 @@ msgstr "ActiveTCL ఇన్స్టాలేషన్ ను కనుగొనడంలో అశక్తత. మీరు TCL ప్లగ్ ఇన్లను ఉపయోగించాలనుకుంటే http://www.activestate.com\n" #: ../libpurple/protocols/bonjour/bonjour.c:108 -msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging for more information." +msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://d.pidgin.im/BonjourWindows for more information." msgstr "" #: ../libpurple/protocols/bonjour/bonjour.c:127 @@ -4197,7 +4200,8 @@ #: ../libpurple/protocols/gg/gg.c:278 #, c-format msgid "Couldn't write buddy list for %s to %s" -msgstr "మిత్రుల జాబితాను లోడ్ చేయలేకపోతోంది" +msgstr "" +#msgstr "మిత్రుల జాబితాను లోడ్ చేయలేకపోతోంది" #: ../libpurple/protocols/gg/gg.c:303 #: ../libpurple/protocols/gg/gg.c:304 @@ -5024,7 +5028,8 @@ #: ../libpurple/protocols/irc/msgs.c:1113 #, c-format msgid "Cannot join %s: Registration is required." -msgstr "నమోదు అవసరం" +msgstr "" +#msgstr "నమోదు అవసరం" #: ../libpurple/protocols/irc/msgs.c:1114 #: ../libpurple/protocols/silc/ops.c:1093 @@ -5234,7 +5239,8 @@ #: ../libpurple/protocols/jabber/auth.c:518 #, c-format msgid "%s requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?" -msgstr "ఈ సర్వర్కు ఎన్ క్రిప్ట్ కాని కనెక్షన్ కన్నా సాధారణ టెక్స్ట్ ప్రమాణీకరణ అవసరం. దీనికి అనుమతించి ప్రమాణీకరణను కొనసాగించమంటారా?" +msgstr "" +#msgstr "ఈ సర్వర్కు ఎన్ క్రిప్ట్ కాని కనెక్షన్ కన్నా సాధారణ టెక్స్ట్ ప్రమాణీకరణ అవసరం. దీనికి అనుమతించి ప్రమాణీకరణను కొనసాగించమంటారా?" #: ../libpurple/protocols/jabber/auth.c:325 #: ../libpurple/protocols/jabber/auth.c:326 @@ -6007,7 +6013,8 @@ #: ../libpurple/protocols/jabber/jabber.c:689 #, c-format msgid "Registration to %s successful" -msgstr "%s@%s నమోదు విజయవంతమైనది" +msgstr "" +#msgstr "%s@%s నమోదు విజయవంతమైనది" #: ../libpurple/protocols/jabber/jabber.c:691 #: ../libpurple/protocols/jabber/jabber.c:692 @@ -6022,7 +6029,8 @@ #: ../libpurple/protocols/jabber/jabber.c:719 #, c-format msgid "Registration from %s successfully removed" -msgstr "%s@%s నమోదు విజయవంతమైనది" +msgstr "" +#msgstr "%s@%s నమోదు విజయవంతమైనది" #: ../libpurple/protocols/jabber/jabber.c:721 #: ../libpurple/protocols/jabber/jabber.c:722 @@ -6101,7 +6109,8 @@ #: ../libpurple/protocols/jabber/jabber.c:1040 #, c-format msgid "Register New Account at %s" -msgstr "కొత్త జాబర్ అకౌంట్ను నమోదు చేయండి" +msgstr "" +#msgstr "కొత్త జాబర్ అకౌంట్ను నమోదు చేయండి" #: ../libpurple/protocols/jabber/jabber.c:1043 msgid "Change Registration" @@ -6582,7 +6591,8 @@ #: ../libpurple/protocols/yahoo/yahoo.c:4131 #, c-format msgid "%s has buzzed you!" -msgstr "%s మీకు [%s] ను చేర్చారు" +msgstr "" +#msgstr "%s మీకు [%s] ను చేర్చారు" #: ../libpurple/protocols/jabber/jabber.c:2281 #: ../libpurple/protocols/yahoo/yahoo.c:4132 @@ -7185,7 +7195,8 @@ #: ../libpurple/protocols/msnp9/msn.c:131 #, c-format msgid "%s has nudged you!" -msgstr "%s మీకు [%s] ను చేర్చారు" +msgstr "" +#msgstr "%s మీకు [%s] ను చేర్చారు" #: ../libpurple/protocols/msn/msn.c:132 #: ../libpurple/protocols/msnp9/msn.c:132 @@ -7767,7 +7778,8 @@ #: ../libpurple/protocols/msn/notification.c:836 #, c-format msgid "Unknown error (%d)" -msgstr "అజ్ఞాత పొరపాటు" +msgstr "" +#msgstr "అజ్ఞాత పొరపాటు" #: ../libpurple/protocols/msn/notification.c:837 #: ../libpurple/protocols/sametime/sametime.c:4471 @@ -8151,7 +8163,8 @@ #: ../libpurple/protocols/myspace/myspace.c:1794 #, c-format msgid "Protocol error, code %d: %s" -msgstr "లోపం కోడ్ %d ను ప్రక్రియ తిప్పి పంపింది " +msgstr "" +#msgstr "లోపం కోడ్ %d ను ప్రక్రియ తిప్పి పంపింది " #: ../libpurple/protocols/myspace/myspace.c:1990 #: ../libpurple/protocols/myspace/myspace.c:2024 @@ -8211,7 +8224,8 @@ #: ../libpurple/protocols/myspace/myspace.c:2499 #, c-format msgid "Couldn't connect to host: %s (%d)" -msgstr "హోస్ట్కు కనెక్ట్ చేయలేదు" +msgstr "" +#msgstr "హోస్ట్కు కనెక్ట్ చేయలేదు" #: ../libpurple/protocols/myspace/myspace.c:2670 #, fuzzy @@ -9503,8 +9517,10 @@ #, c-format msgid "You missed %hu message from %s for an unknown reason." msgid_plural "You missed %hu messages from %s for an unknown reason." -msgstr[0] "అజ్ఞాత కారణములచేత మీరు %hu సందేశాలను %s నుండి కోల్పోయినారు. " -msgstr[1] "आपको अज्ञात कारनों से साइन-ऑफ करा गया है।" +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "అజ్ఞాత కారణములచేత మీరు %hu సందేశాలను %s నుండి కోల్పోయినారు. " +#msgstr[1] "आपको अज्ञात कारनों से साइन-ऑफ करा गया है।" # Data is assumed to be the destination sn #. Data is assumed to be the destination sn @@ -9757,7 +9773,8 @@ #: ../libpurple/protocols/oscar/oscar.c:5109 #, c-format msgid "Could not add the buddy %s for an unknown reason." -msgstr "అజ్ఞాత కారణంవల్ల మీ కమాండ్ విఫలమైనది." +msgstr "" +#msgstr "అజ్ఞాత కారణంవల్ల మీ కమాండ్ విఫలమైనది." #: ../libpurple/protocols/oscar/oscar.c:5226 #, c-format @@ -10169,7 +10186,8 @@ #: ../libpurple/protocols/qq/buddy_info.c:601 #, c-format msgid "Setting custom faces is not currently supported. Please choose an image from %s." -msgstr "మీకిష్టమైన ముఖారవిందాలను సెట్ చేయడానికి ఇప్పుడు అవకాశంలేదు. ఇక్కడున్న బొమ్మల్లో ఒకదాన్ని దయచేసి ఎంపికచేసుకోండి" +msgstr "" +#msgstr "మీకిష్టమైన ముఖారవిందాలను సెట్ చేయడానికి ఇప్పుడు అవకాశంలేదు. ఇక్కడున్న బొమ్మల్లో ఒకదాన్ని దయచేసి ఎంపికచేసుకోండి" #: ../libpurple/protocols/qq/buddy_info.c:618 #: ../libpurple/protocols/qq/buddy_info.c:631 @@ -10598,7 +10616,7 @@ #: ../libpurple/protocols/qq/send_file.c:707 #, c-format msgid "%d has declined the file %s" -msgstr "ఫైలు %s ను %d నిరాకరించింది " +msgstr "ఫైలు %2$s ను %1$d నిరాకరించింది " #: ../libpurple/protocols/qq/send_file.c:710 #: ../libpurple/protocols/qq/send_file.c:739 @@ -10608,7 +10626,8 @@ #: ../libpurple/protocols/qq/send_file.c:736 #, c-format msgid "%d canceled the transfer of %s" -msgstr "%sను ట్రాన్స్ఫర్ చేయడాన్ని %s రద్దు చేశారు." +msgstr "" +#msgstr "%sను ట్రాన్స్ఫర్ చేయడాన్ని %s రద్దు చేశారు." #: ../libpurple/protocols/qq/sendqueue.c:124 msgid "Connection lost" @@ -10637,7 +10656,8 @@ #: ../libpurple/protocols/qq/sys_msg.c:176 #, c-format msgid "%s has added you [%s] to his or her buddy list" -msgstr "%s మిమ్మల్ని తన మిత్రుల జాబితాలో చేర్చారు." +msgstr "" +#msgstr "%s మిమ్మల్ని తన మిత్రుల జాబితాలో చేర్చారు." #: ../libpurple/protocols/qq/sys_msg.c:192 #, c-format @@ -13318,8 +13338,9 @@ "Lost connection with %s:\n" "%s" msgstr "" -"సర్వర్ తో కనెక్షన్ పోయింది:\n" -"%s" +#msgstr "" +#"సర్వర్ తో కనెక్షన్ పోయింది:\n" +#"%s" #: ../libpurple/protocols/yahoo/yahoo.c:2733 #, c-format @@ -13327,8 +13348,9 @@ "Could not establish a connection with %s:\n" "%s" msgstr "" -"సర్వర్ తో కనెక్షన్ సాధ్యపడలేదు: \n" -"%s" +#msgstr "" +#"సర్వర్ తో కనెక్షన్ సాధ్యపడలేదు: \n" +#"%s" #: ../libpurple/protocols/yahoo/yahoo.c:3092 #: ../libpurple/protocols/yahoo/yahoo.c:3778 @@ -13836,7 +13858,8 @@ msgid "" "Unable to create socket:\n" "%s" -msgstr "సాకెట్ను సృష్టించలేదు. " +msgstr "" +#msgstr "సాకెట్ను సృష్టించలేదు. " #: ../libpurple/proxy.c:662 #, c-format @@ -14012,7 +14035,8 @@ #: ../libpurple/status.c:613 #, c-format msgid "%s (%s) changed status from %s to %s" -msgstr "%s స్థితిని %s నుంచి %s కు మార్చబడింది" +msgstr "" +#msgstr "%s స్థితిని %s నుంచి %s కు మార్చబడింది" #: ../libpurple/status.c:624 #, c-format @@ -14022,17 +14046,20 @@ #: ../libpurple/status.c:626 #, c-format msgid "%s (%s) is now %s" -msgstr "%s ఇప్పుడు %s" +msgstr "" +#msgstr "%s ఇప్పుడు %s" #: ../libpurple/status.c:632 #, c-format msgid "%s is no longer %s" -msgstr "ఇప్పుడు %s దూరంలో లేరు/దు." +msgstr "" +#msgstr "ఇప్పుడు %s దూరంలో లేరు/దు." #: ../libpurple/status.c:634 #, c-format msgid "%s (%s) is no longer %s" -msgstr "ఇప్పుడు %s దూరంలో లేరు/దు." +msgstr "" +#msgstr "ఇప్పుడు %s దూరంలో లేరు/దు." #: ../libpurple/status.c:1247 #, c-format @@ -14131,7 +14158,8 @@ #: ../libpurple/util.c:3943 #, c-format msgid "Unable to connect to %s" -msgstr ",ర్వర్కు కనెక్ట్చేయలేని స్థితి. " +msgstr "" +#msgstr ",ర్వర్కు కనెక్ట్చేయలేని స్థితి. " #: ../libpurple/util.c:3770 #, c-format @@ -14151,7 +14179,8 @@ #: ../libpurple/util.c:3861 #, c-format msgid "Unable to connect to %s: %s" -msgstr "సర్వర్కు కనెక్ట్చేయలేని స్థితి. " +msgstr "" +#msgstr "సర్వర్కు కనెక్ట్చేయలేని స్థితి. " #: ../pidgin.desktop.in.h:1 msgid "Internet Messenger" @@ -14345,9 +14374,10 @@ "\n" "You can come back to this window to add, edit, or remove accounts from <b>Accounts->Add/Edit</b> in the Buddy List window" msgstr "" -"<స్పాన్ పరిమాణం='పెద్ద' బరువు='బోల్డ్'>స్వాగతం %s!</స్పాన్>\n" -"\n" -"మీ IM అకౌంట్లు కన్ఫిగర్ కాలేదు. %s తో కనెక్ట్ కావడం ప్రారంభించడానికి <b>Add</b> ప్రెస్ చేయండి" +#msgstr "" +#"<స్పాన్ పరిమాణం='పెద్ద' బరువు='బోల్డ్'>స్వాగతం %s!</స్పాన్>\n" +#"\n" +#"మీ IM అకౌంట్లు కన్ఫిగర్ కాలేదు. %s తో కనెక్ట్ కావడం ప్రారంభించడానికి <b>Add</b> ప్రెస్ చేయండి" #: ../pidgin/gtkblist.c:543 #, c-format @@ -14679,7 +14709,8 @@ #: ../pidgin/gtkblist.c:3693 #, c-format msgid "Idle %dd %dh %02dm" -msgstr "ఖాళీ %dh %02dm" +msgstr "" +#msgstr "ఖాళీ %dh %02dm" #: ../pidgin/gtkblist.c:3695 #, c-format @@ -14754,7 +14785,8 @@ #: ../pidgin/gtkblist.c:4494 #, c-format msgid "%s disabled" -msgstr "కమాండ్ పని చేయడం లేదు" +msgstr "" +#msgstr "కమాండ్ పని చేయడం లేదు" #: ../pidgin/gtkblist.c:4498 msgid "Reconnect" @@ -14778,8 +14810,10 @@ #, c-format msgid "%d account was disabled because you signed on from another location." msgid_plural "%d accounts were disabled because you signed on from another location." -msgstr[0] "మీరు మరో ప్రదేశంనుండి సైన్ ఆన్ చేశారు." -msgstr[1] "మీరు మరో ప్రదేశంనుండి సైన్ ఆన్ చేశారు." +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "మీరు మరో ప్రదేశంనుండి సైన్ ఆన్ చేశారు." +#msgstr[1] "మీరు మరో ప్రదేశంనుండి సైన్ ఆన్ చేశారు." #: ../pidgin/gtkblist.c:4860 msgid "<b>Username:</b>" @@ -15277,8 +15311,10 @@ #, c-format msgid "%d person in room" msgid_plural "%d people in room" -msgstr[0] "గదిలో %d మనుషులున్నారు " -msgstr[1] "कक्ष में 0 लोग हैं" +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "గదిలో %d మనుషులున్నారు " +#msgstr[1] "कक्ष में 0 लोग हैं" #: ../pidgin/gtkconv.c:6574 #: ../pidgin/gtkstatusbox.c:660 @@ -16545,7 +16581,7 @@ #: ../pidgin/gtkmain.c:398 #, c-format msgid "%s %s. Try `%s -h' for more information.\n" -msgstr "Gaim %s. ఇంకా వివరములకు `%s -h' ప్రయత్నించండి.\n" +msgstr "%s %s. ఇంకా వివరములకు `%s -h' ప్రయత్నించండి.\n" #: ../pidgin/gtkmain.c:400 #, c-format @@ -16595,23 +16631,6 @@ "on other protocols is at\n" "%swiki/DeveloperPages\n" msgstr "" -"%s has segfaulted and attempted to dump a core file.\n" -"This is a bug in the software and has happened through\n" -"no fault of your own.\n" -"\n" -"If you can reproduce the crash, please notify the Pidgin\n" -"developers by reporting a bug at\n" -"%sbug.php\n" -"\n" -"Please make sure to specify what you were doing at the time\n" -"and post the backtrace from the core file. If you do not know\n" -"how to get the backtrace, please read the instructions at\n" -"%sgdb.php\n" -"\n" -"If you need further assistance, please IM either SeanEgn or \n" -"LSchiere (via AIM). Contact information for Sean and Luke \n" -"on other protocols is at\n" -"%scontactinfo.php\n" #. Translators may want to transliterate the name. #. It is not to be translated. @@ -16644,8 +16663,10 @@ #, c-format msgid "<b>%d new email.</b>" msgid_plural "<b>%d new emails.</b>" -msgstr[0] "<b>ప్లగ్ ఇన్ వివరాలు</b>" -msgstr[1] "<b>ప్లగ్ ఇన్ వివరాలు</b>" +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "<b>ప్లగ్ ఇన్ వివరాలు</b>" +#msgstr[1] "<b>ప్లగ్ ఇన్ వివరాలు</b>" #: ../pidgin/gtknotify.c:998 #, c-format @@ -18136,8 +18157,8 @@ "\n" "<b>Buddy Note</b>: %s" msgstr "" -"\n" -"<b>సోమరి:</b>" +#"\n" +#"<b>సోమరి:</b>" #: ../pidgin/plugins/history.c:195 msgid "History" @@ -18560,7 +18581,8 @@ #: ../pidgin/plugins/relnot.c:71 #, c-format msgid "You are using %s version %s. The current version is %s. You can get it from <a href=\"%s\">%s</a><hr>" -msgstr "మీరు %s వెర్షన్ అనువాదాన్ని ఉపయోగిస్తున్నారు. ప్రస్తుత వెర్షన్ %s.<hr>" +msgstr "" +#msgstr "మీరు %s వెర్షన్ అనువాదాన్ని ఉపయోగిస్తున్నారు. ప్రస్తుత వెర్షన్ %s.<hr>" #: ../pidgin/plugins/relnot.c:79 #, c-format
--- a/po/th.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/th.po Mon Jun 30 23:12:54 2008 +0000 @@ -16,7 +16,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"Plural-Forms: nplurals=1; plural=0;\n" #: ../finch/finch.c:64 ../finch/finch.c:301 ../finch/finch.c:330 #: ../finch/finch.c:418 @@ -15016,8 +15016,9 @@ "\n" "%s" msgstr "" -"เกิดข้อผิดพลาดขณะบันทึกรูป: %s\n" -"%s" +#msgstr "" +#"เกิดข้อผิดพลาดขณะบันทึกรูป: %s\n" +#"%s" #: ../pidgin/gtkimhtml.c:3482 ../pidgin/gtkimhtml.c:3494 msgid "Save Image"
--- a/po/ur.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/ur.po Mon Jun 30 23:12:54 2008 +0000 @@ -13,6 +13,7 @@ "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Translate Toolkit 0.10\n" "X-Poedit-Language: Urdu\n" "X-Poedit-SourceCharset: utf.8\n" @@ -1398,8 +1399,10 @@ #, c-format msgid "%s (%s) has %d new message." msgid_plural "%s (%s) has %d new messages." -msgstr[0] "%s کے پاس %dنیا پیام ہے۔" -msgstr[1] "%sک ےپاس %dنئے پیامات ہیں۔" +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "%s کے پاس %dنیا پیام ہے۔" +#msgstr[1] "%sک ےپاس %dنئے پیامات ہیں۔" #: ../finch/gntnotify.c:226 #: ../pidgin/gtknotify.c:342 @@ -2466,7 +2469,8 @@ #: ../libpurple/certificate.c:1185 #, c-format msgid "Accept certificate for %s?" -msgstr "دعوت گفتگو قبول ؟" +msgstr "" +#msgstr "دعوت گفتگو قبول ؟" #. TODO: Find what the handle ought to be #: ../libpurple/certificate.c:1191 @@ -3083,7 +3087,8 @@ #: ../libpurple/plugin.c:663 #, c-format msgid "%s requires %s, but it failed to unload." -msgstr "انحصاری پلگ ان%sان لوڈہونے میں ناكام ہوا۔" +msgstr "" +#msgstr "انحصاری پلگ ان%sان لوڈہونے میں ناكام ہوا۔" #: ../libpurple/plugins/autoaccept.c:23 #, fuzzy @@ -3099,7 +3104,8 @@ #: ../libpurple/plugins/autoaccept.c:80 #, c-format msgid "Autoaccepted file transfer of \"%s\" from \"%s\" completed." -msgstr "%s سے ٹرانسفردرخواست فائل قبول؟" +msgstr "" +#msgstr "%s سے ٹرانسفردرخواست فائل قبول؟" #: ../libpurple/plugins/autoaccept.c:82 msgid "Autoaccept complete" @@ -3885,7 +3891,7 @@ msgstr "ایكٹیو TCL ا نسٹالیشن كی جانچ نا ممكن۔ اگر آپ TCL پلگ انس استعمال كرنا چاہتے ہیں ، ایكٹیوTCL انسٹال كروfrom http://www.activestate.com\n" #: ../libpurple/protocols/bonjour/bonjour.c:108 -msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging for more information." +msgid "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://d.pidgin.im/BonjourWindows for more information." msgstr "" #: ../libpurple/protocols/bonjour/bonjour.c:127 @@ -4025,7 +4031,8 @@ #: ../libpurple/protocols/gg/gg.c:278 #, c-format msgid "Couldn't write buddy list for %s to %s" -msgstr "بڈّی لسٹ لوڈ نہیں كرسكا" +msgstr "" +#msgstr "بڈّی لسٹ لوڈ نہیں كرسكا" #: ../libpurple/protocols/gg/gg.c:303 #: ../libpurple/protocols/gg/gg.c:304 @@ -4821,7 +4828,8 @@ #: ../libpurple/protocols/irc/msgs.c:1113 #, c-format msgid "Cannot join %s: Registration is required." -msgstr "رجسٹریشن کی ضروت تھی" +msgstr "" +#msgstr "رجسٹریشن کی ضروت تھی" #: ../libpurple/protocols/irc/msgs.c:1114 #: ../libpurple/protocols/silc/ops.c:1093 @@ -5028,7 +5036,8 @@ #: ../libpurple/protocols/jabber/auth.c:518 #, c-format msgid "%s requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?" -msgstr "اس سرور کو ان اینکریپٹیڈ کنیکشن پر سادہ متن تصدیق کی ضرورت ہے ۔ اس کو اجازت ہے اور تصدیق جاری رکھنا ہے؟" +msgstr "" +#msgstr "اس سرور کو ان اینکریپٹیڈ کنیکشن پر سادہ متن تصدیق کی ضرورت ہے ۔ اس کو اجازت ہے اور تصدیق جاری رکھنا ہے؟" #: ../libpurple/protocols/jabber/auth.c:325 #: ../libpurple/protocols/jabber/auth.c:326 @@ -5789,7 +5798,7 @@ #: ../libpurple/protocols/jabber/jabber.c:689 #, c-format msgid "Registration to %s successful" -msgstr "کا رجسٹریشن %s@%s کامیاب" +msgstr "کا رجسٹریشن %s کامیاب" #: ../libpurple/protocols/jabber/jabber.c:691 #: ../libpurple/protocols/jabber/jabber.c:692 @@ -5804,7 +5813,7 @@ #: ../libpurple/protocols/jabber/jabber.c:719 #, c-format msgid "Registration from %s successfully removed" -msgstr "کا رجسٹریشن %s@%s کامیاب" +msgstr "کا رجسٹریشن %s کامیاب" #: ../libpurple/protocols/jabber/jabber.c:721 #: ../libpurple/protocols/jabber/jabber.c:722 @@ -5880,7 +5889,8 @@ #: ../libpurple/protocols/jabber/jabber.c:1040 #, c-format msgid "Register New Account at %s" -msgstr "نیا مہمل اکاؤنٹ رجسٹر کریں" +msgstr "" +#msgstr "نیا مہمل اکاؤنٹ رجسٹر کریں" #: ../libpurple/protocols/jabber/jabber.c:1043 msgid "Change Registration" @@ -6342,7 +6352,8 @@ #: ../libpurple/protocols/yahoo/yahoo.c:4131 #, c-format msgid "%s has buzzed you!" -msgstr "%s has added you [%s]" +msgstr "" +#msgstr "%s has added you [%s]" #: ../libpurple/protocols/jabber/jabber.c:2281 #: ../libpurple/protocols/yahoo/yahoo.c:4132 @@ -6935,7 +6946,8 @@ #: ../libpurple/protocols/msnp9/msn.c:131 #, c-format msgid "%s has nudged you!" -msgstr "%s has added you [%s]" +msgstr "" +#msgstr "%s has added you [%s]" #: ../libpurple/protocols/msn/msn.c:132 #: ../libpurple/protocols/msnp9/msn.c:132 @@ -7495,7 +7507,8 @@ #: ../libpurple/protocols/msn/notification.c:836 #, c-format msgid "Unknown error (%d)" -msgstr "نامعلوم خامی " +msgstr "" +#msgstr "نامعلوم خامی " #: ../libpurple/protocols/msn/notification.c:837 #: ../libpurple/protocols/sametime/sametime.c:4471 @@ -7864,7 +7877,8 @@ #: ../libpurple/protocols/myspace/myspace.c:1794 #, c-format msgid "Protocol error, code %d: %s" -msgstr "پروسیس لوٹایا گيا خامی کوڈ %d" +msgstr "" +#msgstr "پروسیس لوٹایا گيا خامی کوڈ %d" #: ../libpurple/protocols/myspace/myspace.c:1990 #: ../libpurple/protocols/myspace/myspace.c:2024 @@ -7923,7 +7937,8 @@ #: ../libpurple/protocols/myspace/myspace.c:2499 #, c-format msgid "Couldn't connect to host: %s (%d)" -msgstr "ہاسٹ سے کنیکٹ نہیں ہو سکا" +msgstr "" +#msgstr "ہاسٹ سے کنیکٹ نہیں ہو سکا" #: ../libpurple/protocols/myspace/myspace.c:2670 #, fuzzy @@ -8728,7 +8743,8 @@ #: ../libpurple/protocols/oscar/oscar.c:457 #, c-format msgid "(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)" -msgstr "(پیام موصول ہونے میں خامی تھی۔ جس بڈی سے آپ بات کررہے تھے بہت حد تک قیاس ہے کہ کلائنٹ بگی تھا۔)" +msgstr "" +#msgstr "(پیام موصول ہونے میں خامی تھی۔ جس بڈی سے آپ بات کررہے تھے بہت حد تک قیاس ہے کہ کلائنٹ بگی تھا۔)" #. Label #: ../libpurple/protocols/oscar/oscar.c:639 @@ -9123,22 +9139,24 @@ #, c-format msgid "You missed %hu message from %s because it was invalid." msgid_plural "You missed %hu messages from %s because they were invalid." -msgstr[0] "آپ نے %huپیام" -msgstr[1] "آپ نے " +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "آپ نے %huپیام" +#msgstr[1] "آپ نے " #: ../libpurple/protocols/oscar/oscar.c:2615 #, c-format msgid "You missed %hu message from %s because it was too large." msgid_plural "You missed %hu messages from %s because they were too large." -msgstr[0] "آپ نے %sسے %hu پیام کو مس کردیا کیونکہ یہ بہت بڑا تھا۔" -msgstr[1] "آپ نے %sسے %hu پیامات کو مس کردیا کیونکہ یہ بہت بڑےتھے۔" +msgstr[0] "آپ نے %2$sسے %1$hu پیام کو مس کردیا کیونکہ یہ بہت بڑا تھا۔" +msgstr[1] "آپ نے %2$sسے %1$hu پیامات کو مس کردیا کیونکہ یہ بہت بڑےتھے۔" #: ../libpurple/protocols/oscar/oscar.c:2624 #, c-format msgid "You missed %hu message from %s because the rate limit has been exceeded." msgid_plural "You missed %hu messages from %s because the rate limit has been exceeded." -msgstr[0] "آپ نے %sسے %huپیام مس کردیا کیونکہ قیمت حد گذر گئی۔" -msgstr[1] "آپ نے%sسے %hu پیامات مس کردیئے کیونکہ قیمت حد گذر گئی۔" +msgstr[0] "آپ نے %2$sسے %1$huپیام مس کردیا کیونکہ قیمت حد گذر گئی۔" +msgstr[1] "آپ نے%2$sسے %1$hu پیامات مس کردیئے کیونکہ قیمت حد گذر گئی۔" #: ../libpurple/protocols/oscar/oscar.c:2633 #, c-format @@ -9151,15 +9169,15 @@ #, c-format msgid "You missed %hu message from %s because you are too evil." msgid_plural "You missed %hu messages from %s because you are too evil." -msgstr[0] "آپ نے %sسے%huپیام مس کردیا کیونکہ آپ بہت ناشائستہ ہیں۔" -msgstr[1] "آپ نے %sسے%huپیامات مس کردیئے کیونکہ آپ بہت ناشائستہ ہیں ۔" +msgstr[0] "آپ نے %2$sسے%1$huپیام مس کردیا کیونکہ آپ بہت ناشائستہ ہیں۔" +msgstr[1] "آپ نے %2$sسے%1$huپیامات مس کردیئے کیونکہ آپ بہت ناشائستہ ہیں ۔" #: ../libpurple/protocols/oscar/oscar.c:2651 #, c-format msgid "You missed %hu message from %s for an unknown reason." msgid_plural "You missed %hu messages from %s for an unknown reason." -msgstr[0] " آپ نے نا معلوم وجہ کےلئے %sسے%hu پیام مس کردیا ۔" -msgstr[1] " آپ نے نا معلوم وجہ کےلئے %sسے%hu پیامات مس کردیئے ۔" +msgstr[0] " آپ نے نا معلوم وجہ کےلئے %2$sسے%1$hu پیام مس کردیا ۔" +msgstr[1] " آپ نے نا معلوم وجہ کےلئے %2$sسے%1$hu پیامات مس کردیئے ۔" # Data is assumed to be the destination sn #. Data is assumed to be the destination sn @@ -9405,7 +9423,8 @@ #: ../libpurple/protocols/oscar/oscar.c:5109 #, c-format msgid "Could not add the buddy %s for an unknown reason." -msgstr "آپ کا کمانڈ نا معلوم سبب کے لئے ناکام ہوا۔" +msgstr "" +#msgstr "آپ کا کمانڈ نا معلوم سبب کے لئے ناکام ہوا۔" #: ../libpurple/protocols/oscar/oscar.c:5226 #, c-format @@ -9810,7 +9829,8 @@ #: ../libpurple/protocols/qq/buddy_info.c:601 #, c-format msgid "Setting custom faces is not currently supported. Please choose an image from %s." -msgstr "آپ كسٹم فیس سیٹ كرنے كی كوشش كررہے ہیں ۔ گائم جاری طورپر صرف معیاری فیسیس كو اجازت دیتا ہے۔ براہ كرم ایك امیج منتخب كیجیے" +msgstr "" +#msgstr "آپ كسٹم فیس سیٹ كرنے كی كوشش كررہے ہیں ۔ گائم جاری طورپر صرف معیاری فیسیس كو اجازت دیتا ہے۔ براہ كرم ایك امیج منتخب كیجیے" #: ../libpurple/protocols/qq/buddy_info.c:618 #: ../libpurple/protocols/qq/buddy_info.c:631 @@ -10271,7 +10291,8 @@ #: ../libpurple/protocols/qq/sys_msg.c:176 #, c-format msgid "%s has added you [%s] to his or her buddy list" -msgstr "%sنے آپ كواپنی بڈی لسٹ میں شامل كردیا۔" +msgstr "" +#msgstr "%sنے آپ كواپنی بڈی لسٹ میں شامل كردیا۔" #: ../libpurple/protocols/qq/sys_msg.c:192 #, c-format @@ -12897,8 +12918,9 @@ "Lost connection with %s:\n" "%s" msgstr "" -"سرور كے ساتھ كنیكشن گم ہوا:\n" -"%s" +#msgstr "" +#"سرور كے ساتھ كنیكشن گم ہوا:\n" +#"%s" #: ../libpurple/protocols/yahoo/yahoo.c:2733 #, c-format @@ -12906,8 +12928,9 @@ "Could not establish a connection with %s:\n" "%s" msgstr "" -"سرور كے ساتھ كوئی كنیكشن اسٹابلیش نہیں كیا جاسكتا:\n" -"%s" +#msgstr "" +#"سرور كے ساتھ كوئی كنیكشن اسٹابلیش نہیں كیا جاسكتا:\n" +#"%s" #: ../libpurple/protocols/yahoo/yahoo.c:3092 #: ../libpurple/protocols/yahoo/yahoo.c:3778 @@ -13551,12 +13574,12 @@ #: ../libpurple/status.c:610 #, c-format msgid "%s changed status from %s to %s" -msgstr "%s changed status from %s to %s" +msgstr "" #: ../libpurple/status.c:613 #, c-format msgid "%s (%s) changed status from %s to %s" -msgstr "%s changed status from %s to %s" +msgstr "" #: ../libpurple/status.c:624 #, c-format @@ -13566,7 +13589,8 @@ #: ../libpurple/status.c:626 #, c-format msgid "%s (%s) is now %s" -msgstr "%sابھی ہے %s" +msgstr "" +#msgstr "%sابھی ہے %s" #: ../libpurple/status.c:632 #, c-format @@ -13576,7 +13600,8 @@ #: ../libpurple/status.c:634 #, c-format msgid "%s (%s) is no longer %s" -msgstr "%s اوریادہ نہیں ہےr %s" +msgstr "" +#msgstr "%s اوریادہ نہیں ہےr %s" #: ../libpurple/status.c:1247 #, c-format @@ -13673,7 +13698,8 @@ #: ../libpurple/util.c:3943 #, c-format msgid "Unable to connect to %s" -msgstr "ہوسٹ سےكنیكٹ ہونے میں نااہل" +msgstr "" +#msgstr "ہوسٹ سےكنیكٹ ہونے میں نااہل" #: ../libpurple/util.c:3770 #, c-format @@ -13689,7 +13715,8 @@ #: ../libpurple/util.c:3861 #, c-format msgid "Unable to connect to %s: %s" -msgstr "ہوسٹ سےكنیكٹ ہونے میں نااہل" +msgstr "" +#msgstr "ہوسٹ سےكنیكٹ ہونے میں نااہل" #: ../pidgin.desktop.in.h:1 msgid "Internet Messenger" @@ -13873,11 +13900,12 @@ "\n" "You can come back to this window to add, edit, or remove accounts from <b>Accounts->Add/Edit</b> in the Buddy List window" msgstr "" -"<span size='larger' weight='bold'> گائم میں خوش آمدید!</span>\n" -"\n" -"آپ كوئي ہیئت والاIM اكاؤنٹس نہیں ركھتے ہیں ۔ گائم كے ساتھ جوڑنا شروع كرنے كے لیے <b>ملاؤ</b> بٹن پر نیچے كلك كیجیےا ور آپ كا پہلا اكاؤنٹ كو ہیئت دیجیے۔ اگر آپ گائم كو متعدد IM اكاؤنٹس میں چاہتے ہیں ، مال كو ہیئت دینے كے لیے دوبارہ <b>ملاؤ</b> پر كلك كیجیے۔\n" -"\n" -"آپ ملانے ، مرتب، یا اكاؤنٹس نكالنے كے لیے اس ونڈو كو واپس جاسكتے ہیں ،بڈی فہرست ونڈو میں <b>اكاؤنٹس->ملاؤ/مرتب</b>" +#msgstr "" +#"<span size='larger' weight='bold'> گائم میں خوش آمدید!</span>\n" +#"\n" +#"آپ كوئي ہیئت والاIM اكاؤنٹس نہیں ركھتے ہیں ۔ گائم كے ساتھ جوڑنا شروع كرنے كے لیے <b>ملاؤ</b> بٹن پر نیچے كلك كیجیےا ور آپ كا پہلا اكاؤنٹ كو ہیئت دیجیے۔ اگر آپ گائم كو متعدد IM اكاؤنٹس میں چاہتے ہیں ، مال كو ہیئت دینے كے لیے دوبارہ <b>ملاؤ</b> پر كلك كیجیے۔\n" +#"\n" +#"آپ ملانے ، مرتب، یا اكاؤنٹس نكالنے كے لیے اس ونڈو كو واپس جاسكتے ہیں ،بڈی فہرست ونڈو میں <b>اكاؤنٹس->ملاؤ/مرتب</b>" #: ../pidgin/gtkblist.c:543 #, c-format @@ -14203,7 +14231,7 @@ #: ../pidgin/gtkblist.c:3693 #, c-format msgid "Idle %dd %dh %02dm" -msgstr "Idle %dh %02dm" +msgstr "" #: ../pidgin/gtkblist.c:3695 #, c-format @@ -14278,7 +14306,8 @@ #: ../pidgin/gtkblist.c:4494 #, c-format msgid "%s disabled" -msgstr "نااہل كیاگیا" +msgstr "" +#msgstr "نااہل كیاگیا" #: ../pidgin/gtkblist.c:4498 msgid "Reconnect" @@ -14300,8 +14329,10 @@ #, c-format msgid "%d account was disabled because you signed on from another location." msgid_plural "%d accounts were disabled because you signed on from another location." -msgstr[0] "آپ نے دوسرے لوکیشن سے سائنڈ آن کیا ہے۔" -msgstr[1] "آپ نے دوسرے لوکیشن سے سائنڈ آن کیا ہے۔" +msgstr[0] "" +msgstr[1] "" +#msgstr[0] "آپ نے دوسرے لوکیشن سے سائنڈ آن کیا ہے۔" +#msgstr[1] "آپ نے دوسرے لوکیشن سے سائنڈ آن کیا ہے۔" #: ../pidgin/gtkblist.c:4860 msgid "<b>Username:</b>" @@ -14327,9 +14358,10 @@ "\n" "You have no accounts enabled. Enable your IM accounts from the <b>Accounts</b> window at <b>Accounts->Manage</b>. Once you enable accounts, you'll be able to sign on, set your status, and talk to your friends." msgstr "" -"<span weight='bold' size='larger'>گائم كو خوش آمدید!</span>\n" -"\n" -" آپ كوئی اكاؤنٹ ممكن نہيں ركھتے ہیں ۔<b>Accounts</b> اكاؤنٹس<b>Accounts->Add/Edit</b>ونڈو سے آپ كا IM اكاؤنٹس ممكن كرو۔ایك بار آپ اكاؤنٹس ممكن كرتے ہیں ،آپ سائن آن كو قابل كرتے ہیں ،آپ كا اسٹیٹس سیٹ كیجیے ، اورآپ كے فرینڈس سے بات كیجیے۔" +#msgstr "" +#"<span weight='bold' size='larger'>گائم كو خوش آمدید!</span>\n" +#"\n" +#" آپ كوئی اكاؤنٹ ممكن نہيں ركھتے ہیں ۔<b>Accounts</b> اكاؤنٹس<b>Accounts->Add/Edit</b>ونڈو سے آپ كا IM اكاؤنٹس ممكن كرو۔ایك بار آپ اكاؤنٹس ممكن كرتے ہیں ،آپ سائن آن كو قابل كرتے ہیں ،آپ كا اسٹیٹس سیٹ كیجیے ، اورآپ كے فرینڈس سے بات كیجیے۔" #. set the Show Offline Buddies option. must be done #. * after the treeview or faceprint gets mad. -Robot101 @@ -14756,8 +14788,9 @@ #, c-format msgid "%d person in room" msgid_plural "%d people in room" -msgstr[0] "%d فرد کمرے میں" +msgstr[0] "" msgstr[1] "" +#msgstr[0] "%d فرد کمرے میں" #: ../pidgin/gtkconv.c:6574 #: ../pidgin/gtkstatusbox.c:660 @@ -15310,12 +15343,14 @@ #: ../pidgin/gtkdialogs.c:368 #, c-format msgid "About %s" -msgstr "گائم کےبارےمیں" +msgstr "" +#msgstr "گائم کےبارےمیں" #: ../pidgin/gtkdialogs.c:411 #, c-format msgid "%s is a graphical modular messaging client based on libpurple which is capable of connecting to AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, SIP/SIMPLE, Novell GroupWise, Lotus Sametime, Bonjour, Zephyr, MySpaceIM, Gadu-Gadu, and QQ all at once. It is written using GTK+.<BR><BR>You may modify and redistribute the program under the terms of the GPL (version 2 or later). A copy of the GPL is contained in the 'COPYING' file distributed with %s. %s is copyrighted by its contributors. See the 'COPYRIGHT' file for the complete list of contributors. We provide no warranty for this program.<BR><BR>" -msgstr "گائم AIM, MSN, Yahoo!, كو استعمال كرتے ہوئے ایك ماڈیولر میسیجینگ كلائںٹ كیبل ہے ۔Jabber, ICQ, IRC, SILC, SIP/SIMPLE, ناول گروپ وائس، لوٹس مشابہ ٹائم،بونزور، زیفیر،گڈو گڈو، اورQQایك بار میں ۔یہ GTK+.<BR><BR> استعمال كرتے ہوئے لكھا جاتا ہے آپ ترمیم كرینگے اور پروگرام كوGPL شرطوں كے ماتحٹ دوبارہ تقسیم كرینگے (version 2 or later).GPLكی ایك كاپی 'COPYING' فائل میں ركھتی ہے گائم سے تقسیم كی جاتی ہے۔ گائم اسے شراكت داروں سے كاپی رائٹیڈ ہے ۔ شراكت داروں كی مكمل فہرست كے لیے گائم كی 'COPYRIGHT' فائل دیكھیے۔ ہم اس پروگرام كے لیے كوئي وارنٹی مہیا نہیں كرتے ہیں ۔<BR><BR>" +msgstr "" +#msgstr "گائم AIM, MSN, Yahoo!, كو استعمال كرتے ہوئے ایك ماڈیولر میسیجینگ كلائںٹ كیبل ہے ۔Jabber, ICQ, IRC, SILC, SIP/SIMPLE, ناول گروپ وائس، لوٹس مشابہ ٹائم،بونزور، زیفیر،گڈو گڈو، اورQQایك بار میں ۔یہ GTK+.<BR><BR> استعمال كرتے ہوئے لكھا جاتا ہے آپ ترمیم كرینگے اور پروگرام كوGPL شرطوں كے ماتحٹ دوبارہ تقسیم كرینگے (version 2 or later).GPLكی ایك كاپی 'COPYING' فائل میں ركھتی ہے گائم سے تقسیم كی جاتی ہے۔ گائم اسے شراكت داروں سے كاپی رائٹیڈ ہے ۔ شراكت داروں كی مكمل فہرست كے لیے گائم كی 'COPYRIGHT' فائل دیكھیے۔ ہم اس پروگرام كے لیے كوئي وارنٹی مہیا نہیں كرتے ہیں ۔<BR><BR>" #: ../pidgin/gtkdialogs.c:429 #, fuzzy @@ -15898,17 +15933,18 @@ #: ../pidgin/gtklog.c:309 #, c-format msgid "Are you sure you want to permanently delete the system log which started at %s?" -msgstr "كیا آپ واقعی %s for %sپرجھپٹنا خارج كرناچاہتےہیں؟" +msgstr "" +#msgstr "كیا آپ واقعی %s for %sپرجھپٹنا خارج كرناچاہتےہیں؟" #: ../pidgin/gtklog.c:453 #, c-format msgid "<span size='larger' weight='bold'>Conversation in %s on %s</span>" -msgstr "<span size='larger' weight='bold'>Conversation in %s on %s</span>" +msgstr "" #: ../pidgin/gtklog.c:456 #, c-format msgid "<span size='larger' weight='bold'>Conversation with %s on %s</span>" -msgstr "<span size='larger' weight='bold'>Conversation with %s on %s</span>" +msgstr "" #: ../pidgin/gtklog.c:503 msgid "%B %Y" @@ -15957,7 +15993,7 @@ #: ../pidgin/gtkmain.c:398 #, c-format msgid "%s %s. Try `%s -h' for more information.\n" -msgstr "%s. كوشش `%s -h' مزید معلومات كے لیے.\n" +msgstr "%s %s. كوشش `%s -h' مزید معلومات كے لیے.\n" #: ../pidgin/gtkmain.c:400 #, c-format @@ -15975,16 +16011,6 @@ " --display=DISPLAY X display to use\n" " -v, --version display the current version and exit\n" msgstr "" -"Gaim %s\n" -"Usage: %s [OPTION]...\n" -"\n" -" -c, --config=DIR use DIR for config files\n" -" -d, --debug print debugging messages to stdout\n" -" -h, --help display this help and exit\n" -" -n, --nologin don't automatically login\n" -" -l, --login[=NAME] automatically login (optional argument NAME specifies\n" -" account(s) to use, separated by commas)\n" -" -v, --version display the current version and exit\n" #: ../pidgin/gtkmain.c:528 #, c-format @@ -16007,23 +16033,24 @@ "on other protocols is at\n" "%swiki/DeveloperPages\n" msgstr "" -"گائم سیگافالٹ ہوگیاہےاوراہم فائل كوپھینكنےكی كوشش كی۔ \n" -"یہ سافٹ وئرمیں بگ ہے اوراس كے ذریعے ہواہے \n" -"آپ كی كوئی غلطی نہیں۔\n" -"\n" -"اگرآپ دوبارہ كریش پروڈیوس كرسكتے ہیں تو، براہ كرم گائم\n" -"ڈیولپرز كو بگ كی رپورٹ كریں\n" -"%sbug.php\n" -"\n" -"اس بات كا خیال ركھیں یہ بتانانہ بھولیں كہ آپ اس وقت كیاكررہےتھے\n" -"اور اہم فائل سےبیك ٹریس پوسٹ كریں۔ اگرآپ كو معلوم نہیں ہے \n" -"بیك ٹریس كس طرح حاصل كریں تو،براہ كرم ہدایات پڑھیں\n" -"%sgdb.php\n" -"\n" -"اگرآپ كومزیدمددكی ضرورت ہےتو، براہ كرم IM either SeanEgn or \n" -"LSchiere (via AIM)٫ سین اورلیوك معلومات كےلیےرابطہ كریں \n" -"دیگرپروٹوكالزہے\n" -"%scontactinfo.php\n" +#msgstr "" +#"گائم سیگافالٹ ہوگیاہےاوراہم فائل كوپھینكنےكی كوشش كی۔ \n" +#"یہ سافٹ وئرمیں بگ ہے اوراس كے ذریعے ہواہے \n" +#"آپ كی كوئی غلطی نہیں۔\n" +#"\n" +#"اگرآپ دوبارہ كریش پروڈیوس كرسكتے ہیں تو، براہ كرم گائم\n" +#"ڈیولپرز كو بگ كی رپورٹ كریں\n" +#"%sbug.php\n" +#"\n" +#"اس بات كا خیال ركھیں یہ بتانانہ بھولیں كہ آپ اس وقت كیاكررہےتھے\n" +#"اور اہم فائل سےبیك ٹریس پوسٹ كریں۔ اگرآپ كو معلوم نہیں ہے \n" +#"بیك ٹریس كس طرح حاصل كریں تو،براہ كرم ہدایات پڑھیں\n" +#"%sgdb.php\n" +#"\n" +#"اگرآپ كومزیدمددكی ضرورت ہےتو، براہ كرم IM either SeanEgn or \n" +#"LSchiere (via AIM)٫ سین اورلیوك معلومات كےلیےرابطہ كریں \n" +#"دیگرپروٹوكالزہے\n" +#"%scontactinfo.php\n" #. Translators may want to transliterate the name. #. It is not to be translated. @@ -16052,8 +16079,8 @@ #, c-format msgid "<b>%d new email.</b>" msgid_plural "<b>%d new emails.</b>" -msgstr[0] "<b>Plugin Details</b>" -msgstr[1] "<b>Plugin Details</b>" +msgstr[0] "" +msgstr[1] "" #: ../pidgin/gtknotify.c:998 #, c-format @@ -16891,7 +16918,8 @@ #: ../pidgin/gtkutils.c:1501 #, c-format msgid "%s cannot transfer a folder. You will need to send the files within individually." -msgstr "گائم فولڈ رٹرانسفر نہیں کر سکا ۔آپ کو انفرادی طور پر فائلیں بھیجنے کی ضرورت ہے" +msgstr "" +#msgstr "گائم فولڈ رٹرانسفر نہیں کر سکا ۔آپ کو انفرادی طور پر فائلیں بھیجنے کی ضرورت ہے" #: ../pidgin/gtkutils.c:1535 #: ../pidgin/gtkutils.c:1547 @@ -17806,7 +17834,8 @@ #: ../pidgin/plugins/relnot.c:71 #, c-format msgid "You are using %s version %s. The current version is %s. You can get it from <a href=\"%s\">%s</a><hr>" -msgstr "آپ گائم ورجن %s استعمال کررہے ہیں۔حالیہ ورجن ہے%s.<hr>" +msgstr "" +#msgstr "آپ گائم ورجن %s استعمال کررہے ہیں۔حالیہ ورجن ہے%s.<hr>" #: ../pidgin/plugins/relnot.c:79 #, c-format @@ -18091,7 +18120,8 @@ #: ../pidgin/plugins/win32/winprefs/winprefs.c:312 #, c-format msgid "_Start %s on Windows startup" -msgstr "_ ونڈوز اسٹارٹ اپ پر گائم شروع کریں" +msgstr "" +#msgstr "_ ونڈوز اسٹارٹ اپ پر گائم شروع کریں" #: ../pidgin/plugins/win32/winprefs/winprefs.c:327 msgid "_Dockable Buddy List"
--- a/po/vi.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/vi.po Mon Jun 30 23:12:54 2008 +0000 @@ -3916,7 +3916,7 @@ "The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: http://" "developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-" "LocalMessaging for more information." -msgstr "Không tìm thấy bộ công cụ Apple Bonjour For Windows, xem FAQ (Hỏi Đáp) ở địa chỉ « http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging » để tìm chi tiết." +msgstr "Không tìm thấy bộ công cụ Apple Bonjour For Windows, xem FAQ (Hỏi Đáp) ở địa chỉ « http://d.pidgin.im/BonjourWindows » để tìm chi tiết." #: ../libpurple/protocols/bonjour/bonjour.c:120 msgid "Unable to listen for incoming IM connections\n" @@ -5860,7 +5860,8 @@ #: ../libpurple/protocols/jabber/jabber.c:710 #, c-format msgid "Registration to %s successful" -msgstr "Đăng ký thành công với %s@%" +msgstr "" +#msgstr "Đăng ký thành công với %s@%" #: ../libpurple/protocols/jabber/jabber.c:712 #: ../libpurple/protocols/jabber/jabber.c:713 @@ -11668,7 +11669,7 @@ #: ../libpurple/protocols/silc10/ops.c:712 #, c-format msgid "You have been kicked off <I>%s</I> by <I>%s</I> (%s)" -msgstr "Bạn đã bị <I>%2$s</I> đã khỏi <I>%1$s</I> (%s)" +msgstr "Bạn đã bị <I>%2$s</I> đã khỏi <I>%1$s</I> (%3$s)" #: ../libpurple/protocols/silc/ops.c:718 #: ../libpurple/protocols/silc/ops.c:723
--- a/po/zh_CN.po Mon Jun 30 03:50:35 2008 +0000 +++ b/po/zh_CN.po Mon Jun 30 23:12:54 2008 +0000 @@ -13383,7 +13383,7 @@ msgid "You have %d contact named %s. Would you like to merge them?" msgid_plural "" "You currently have %d contacts named %s. Would you like to merge them?" -msgstr[0] "您已经有名为 %s 的 %d 位联系人。您是否想要合并?" +msgstr[0] "您已经有名为 %2$s 的 %1$d 位联系人。您是否想要合并?" #: ../pidgin/gtkblist.c:525 msgid ""
--- a/share/ca-certs/Makefile.am Mon Jun 30 03:50:35 2008 +0000 +++ b/share/ca-certs/Makefile.am Mon Jun 30 23:12:54 2008 +0000 @@ -1,5 +1,4 @@ -cacertsdir = $(datadir)/purple/ca-certs -cacerts_DATA = \ +CERTIFICATES = \ Equifax_Secure_CA.pem \ GTE_CyberTrust_Global_Root.pem \ Microsoft_Secure_Server_Authority.pem \ @@ -7,7 +6,12 @@ Verisign_RSA_Secure_Server_CA.pem \ Verisign_Class3_Primary_CA.pem +if INSTALL_SSL_CERTIFICATES +cacertsdir = $(datadir)/purple/ca-certs +cacerts_DATA = $(CERTIFICATES) +endif + EXTRA_DIST = \ Makefile.mingw \ - $(cacerts_DATA) + $(CERTIFICATES)
--- a/share/ca-certs/Makefile.mingw Mon Jun 30 03:50:35 2008 +0000 +++ b/share/ca-certs/Makefile.mingw Mon Jun 30 23:12:54 2008 +0000 @@ -8,14 +8,17 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak datadir := $(PIDGIN_INSTALL_DIR) -include ./Makefile.am +-include ./Makefile.am.mingw cacertsdir := $(PIDGIN_INSTALL_DIR)/ca-certs .PHONY: install -install: +install: ./Makefile.am.mingw if test '$(cacerts_DATA)'; then \ mkdir -p $(cacertsdir); \ cp $(cacerts_DATA) $(cacertsdir); \ fi; +./Makefile.am.mingw: ./Makefile.am + sed -e 's/^if\ INSTALL_SSL_CERTIFICATES/ifeq (\$$(INSTALL_SSL_CERTIFICATES), 1)/' ./Makefile.am > $@ +