Mon, 01 Oct 2007 17:51:20 +0000
Updated German translation from Bjoern Voigt. Fixes #3258.
| po/ChangeLog | file | annotate | diff | comparison | revisions | |
| po/de.po | file | annotate | diff | comparison | revisions |
--- a/COPYRIGHT Mon Oct 01 17:49:01 2007 +0000 +++ b/COPYRIGHT Mon Oct 01 17:51:20 2007 +0000 @@ -279,6 +279,7 @@ Eduardo Pérez Matt Perry Nathan Peterson +Sebastián E. Peyrott Celso Pinto Joao Luís Marques Pinto Aleksander Piotrowski
--- a/ChangeLog Mon Oct 01 17:49:01 2007 +0000 +++ b/ChangeLog Mon Oct 01 17:51:20 2007 +0000 @@ -1,34 +1,70 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -Version 2.2.1: - http://developer.pidgin.im/query?status=closed&milestone=2.2.1 - NOTE: Due to the backporting that happened for the actual - release, it is possible bugs marked as fixed in 2.2.1 - will not be fixed until 2.2.2. +version 2.2.2: + http://developer.pidgin.im/query?status=closed&milestone=2.2.2 + NOTE: Due to the backporting that happened for the 2.2.1 + release, it is possible bugs this release fixes bugs + that were marked as fixed in 2.2.1. + + libpurple: + * Real usernames are now shown in the system log. - libpurple: - * A few build issues on Solaris were fixed. - * Cancelling the password prompt for an account will no longer leave - it in an ambiguous state. (It will be disabled.) - * Fixed an erroneous size display for MSN file transfers. (galt) - * Gmail notifications are better tracked + Pidgin: + * If you alias a buddy to an alias that is already present within + a particular group, we now offer to merge the buddies into the + same contact. + * A music emblem is now displayed in the buddy list for a buddy if we + know she is listening to some soothing music. + * Added a 'Move to' menu in buddy list context menu for moving buddies + to other groups as an alternative to dragging. + * Group headings are now marked via an underline instead of a + different color background. + * It is now possible to mark a chat on your buddy list as "Persistent" + so you do not leave the chat when the window or tab is closed. + * The auto-join option for chats is now listed in the "Add Chat" + dialog along with the new persistence option. + * Closing an IM no longer immediately closes your conversation. It + will now remain active for a short time so that if the conversation + resumes, the history will be retained. A preference has been added + to toggle this behavior. + * The "Smiley" menu has been moved to the top-level of the toolbar. + * Pidgin's display is now saved with the command line for session + restoration. (David Mohr) + * ICQ Birthday notifications are shown as buddy list emblems. - Pidgin: - * Fixed keyboard tab reordering to move tabs one step instead of two. - * You should no longer lose proxy settings when Pidgin is restarted. +version 2.2.1 (09/29/2007): + http://developer.pidgin.im/query?status=closed&milestone=2.2.1 + NOTE: Due to the backporting that happened for the actual + release, it is possible bugs marked as fixed in 2.2.1 + will not be fixed until 2.2.2. - Finch: - * Pressing 'Insert' in the buddylist will bring up the 'Add Buddy' - dialog. + libpurple: + * A few build issues on Solaris were fixed. + * Cancelling the password prompt for an account will no longer leave + it in an ambiguous state. (It will be disabled.) + * Fixed an erroneous size display for MSN file transfers. (galt) + * Fixed multiple memory leaks, particularly in XMPP and MySpace + protocols + * Fixed remembering proxy preferences and status scores + * Gmail notifications are better tracked -Version 2.2.0 (09/13/2007): + Pidgin: + * Fixed keyboard tab reordering to move tabs one step instead of two. + * You should no longer lose proxy settings when Pidgin is restarted. + * Fixed detection of X11 when compiling + + Finch: + * Pressing 'Insert' in the buddylist will bring up the 'Add Buddy' + dialog. + +version 2.2.0 (09/13/2007): http://developer.pidgin.im/query?status=closed&milestone=2.2.0 Libpurple: * New protocol plugin: MySpaceIM (Jeff Connelly, Google Summer of Code) * XMPP enhancements. See - http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas + http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas Monitzer, Google Summer of Code for Adium) * Certificate management. Libpurple will validate certificates on SSL-encrypted protocols (William Ehlhardt, Google Summer of Code)
--- a/NEWS Mon Oct 01 17:49:01 2007 +0000 +++ b/NEWS Mon Oct 01 17:51:20 2007 +0000 @@ -5,20 +5,6 @@ ready for a general release. Instead, this is basically a bug fix release. - Luke: Unfortunately the necessity of this bug fix release means - some of the tickets that have been closed as part of the 2.2.1 - milestone are not actually fixed yet. We have grabbed as many - of the changes as we could while avoiding those that are as - yet unstable though, and this should still be a marked - improvement over 2.2.0. We have spent a lot of time since the - last release looking at the tickets that have been submitted - and many of them have been closed. - - Stu: I haven't NEWS'd in a while. I haven't actually done much for - too long also, maybe I'll find some time soon. This release is - basically what 2.2.0 should have been - it actually compiles this - time. - 2.2.0 (9/13/2007): Sean: 2.2.0 contains the results of several major Google Summer of Code branches bringing some new, extraordinary features. We
--- a/configure.ac Mon Oct 01 17:49:01 2007 +0000 +++ b/configure.ac Mon Oct 01 17:51:20 2007 +0000 @@ -46,7 +46,7 @@ m4_define([purple_lt_current], [2]) m4_define([purple_major_version], [2]) m4_define([purple_minor_version], [2]) -m4_define([purple_micro_version], [1]) +m4_define([purple_micro_version], [2]) m4_define([purple_version_suffix], []) m4_define([purple_version], [purple_major_version.purple_minor_version.purple_micro_version]) @@ -55,7 +55,7 @@ m4_define([gnt_lt_current], [2]) m4_define([gnt_major_version], [2]) m4_define([gnt_minor_version], [2]) -m4_define([gnt_micro_version], [1]) +m4_define([gnt_micro_version], [2]) m4_define([gnt_version_suffix], []) m4_define([gnt_version], [gnt_major_version.gnt_minor_version.gnt_micro_version]) @@ -352,13 +352,19 @@ dnl ####################################################################### if test "x$with_x" = "xyes" ; then PKG_CHECK_MODULES(X11, x11, - [AC_DEFINE(HAVE_X, 1, [Define to 1 if you have X11])], + [AC_DEFINE(HAVE_X11, 1, [Define to 1 if you have X11])], [AC_MSG_RESULT(no) - with_x=no]) + if test "x$x_incpath_add" != "x" -a "x$x_libpath_add" != "x"; then + X11_LIBS="$x_libpath_add" + X11_CFLAGS="$x_incpath_add" + else + with_x=no + fi + ]) AC_SUBST(X11_LIBS) AC_SUBST(X11_CFLAGS) fi - + dnl ####################################################################### dnl # Check for XScreenSaver dnl ####################################################################### @@ -1454,7 +1460,7 @@ [enable_nss="$enableval"], [enable_nss="yes"]) -msg_ssl="None (MSN and Google Talk will not work without SSL!)" +msg_ssl="None. MSN, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!" dnl # dnl # Check for GnuTLS if it's specified.
--- a/doc/funniest_home_convos.txt Mon Oct 01 17:49:01 2007 +0000 +++ b/doc/funniest_home_convos.txt Mon Oct 01 17:51:20 2007 +0000 @@ -487,3 +487,21 @@ established that 19:03 <user> its functioning just fine +-- + +17:12 <a_user> I think I foundage a bug +17:13 <a_user> I don't think blocking works correctly for the AIM protocol +17:13 <a_user> because a girl attempted to block me in pidgin and I can still + talk to her +17:14 <a_user> [screen name expunged]: I already told you yesterday. You don't + need me to ease your mind, you want me to change MY mind. Well, + you're out of luck. I don't know how you're still messaging me, + because I already blocked you, but I demand you stop immediately. + For now on, I will save every message that you send me as + evidence for the next time I decide to call the police. I did + call them yesterday, but I didn't have evidence. The more you + message me now, the more you're digging you're own grave, so I + advice you to stop. +17:14 <a_user> see? +17:16 <sadrul> I think blocking in pidgin not working is not your biggest + problem here.
--- a/finch/gntblist.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntblist.c Mon Oct 01 17:51:20 2007 +0000 @@ -1510,6 +1510,8 @@ } else if (strcmp(text, GNT_KEY_CTRL_O) == 0) { purple_prefs_set_bool(PREF_ROOT "/showoffline", !purple_prefs_get_bool(PREF_ROOT "/showoffline")); + } else if (strcmp(text, GNT_KEY_INS) == 0) { + purple_blist_request_add_buddy(NULL, NULL, NULL, NULL); } else if (!gnt_tree_is_searching(GNT_TREE(ggblist->tree))) { if (strcmp(text, "t") == 0) { finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree))); @@ -2225,9 +2227,27 @@ } static void +menu_add_buddy_cb(GntMenuItem *item, gpointer null) +{ + purple_blist_request_add_buddy(NULL, NULL, NULL, NULL); +} + +static void +menu_add_chat_cb(GntMenuItem *item, gpointer null) +{ + purple_blist_request_add_chat(NULL, NULL, NULL, NULL); +} + +static void +menu_add_group_cb(GntMenuItem *item, gpointer null) +{ + purple_blist_request_add_group(); +} + +static void create_menu() { - GntWidget *menu, *sub; + GntWidget *menu, *sub, *subsub; GntMenuItem *item; GntWindow *window; @@ -2248,29 +2268,57 @@ gnt_menu_add_item(GNT_MENU(sub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), send_im_select, NULL); - item = gnt_menuitem_check_new(_("Show empty groups")); + item = gnt_menuitem_new(_("Show")); + gnt_menu_add_item(GNT_MENU(sub), item); + subsub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); + + item = gnt_menuitem_check_new(_("Empty groups")); gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), purple_prefs_get_bool(PREF_ROOT "/emptygroups")); - gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/emptygroups"); - item = gnt_menuitem_check_new(_("Show offline buddies")); + item = gnt_menuitem_check_new(_("Offline buddies")); gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), purple_prefs_get_bool(PREF_ROOT "/showoffline")); - gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/showoffline"); - item = gnt_menuitem_new(_("Sort by status")); + item = gnt_menuitem_new(_("Sort")); gnt_menu_add_item(GNT_MENU(sub), item); + subsub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); + + item = gnt_menuitem_new(_("By Status")); + gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "status"); - item = gnt_menuitem_new(_("Sort alphabetically")); - gnt_menu_add_item(GNT_MENU(sub), item); + item = gnt_menuitem_new(_("Alphabetically")); + gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "text"); - item = gnt_menuitem_new(_("Sort by log size")); + item = gnt_menuitem_new(_("By Log Size")); + gnt_menu_add_item(GNT_MENU(subsub), item); + gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log"); + + item = gnt_menuitem_new(_("Add")); gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log"); + + subsub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); + + item = gnt_menuitem_new("Buddy"); + gnt_menu_add_item(GNT_MENU(subsub), item); + gnt_menuitem_set_callback(item, menu_add_buddy_cb, NULL); + + item = gnt_menuitem_new("Chat"); + gnt_menu_add_item(GNT_MENU(subsub), item); + gnt_menuitem_set_callback(item, menu_add_chat_cb, NULL); + + item = gnt_menuitem_new("Group"); + gnt_menu_add_item(GNT_MENU(subsub), item); + gnt_menuitem_set_callback(item, menu_add_group_cb, NULL); reconstruct_accounts_menu(); gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts);
--- a/finch/gntconv.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntconv.c Mon Oct 01 17:51:20 2007 +0000 @@ -326,8 +326,8 @@ list = purple_get_chats(); while (list) { PurpleConversation *conv = list->data; - gboolean del = FALSE; PurpleChat *chat; + GHashTable *comps = NULL; list = list->next; if (conv->account != gc->account || @@ -336,15 +336,14 @@ chat = purple_blist_find_chat(conv->account, conv->name); if (chat == NULL) { - GHashTable *hash = NULL; if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) - hash = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name); - chat = purple_chat_new(gc->account, conv->name, hash); - del = TRUE; + comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name); + } else { + comps = chat->components; } - serv_join_chat(gc, chat->components); - if (del) - purple_blist_remove_chat(chat); + serv_join_chat(gc, comps); + if (chat == NULL && comps != NULL) + g_hash_table_destroy(comps); } } } @@ -766,7 +765,8 @@ gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), _("<AUTO-REPLY> "), GNT_TEXT_FLAG_BOLD); - if (who && *who && (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV))) + if (who && *who && (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) && + !(flags & PURPLE_MESSAGE_NOTIFY)) { char * name = NULL; @@ -959,7 +959,7 @@ { FinchConv *fc = FINCH_CONV(conv); if (fc && fc->window) - return gnt_window_present(fc->window); + gnt_window_present(fc->window); } static gboolean
--- a/finch/gntdebug.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntdebug.c Mon Oct 01 17:51:20 2007 +0000 @@ -28,12 +28,14 @@ #include <gntbutton.h> #include <gntcheckbox.h> #include <gntentry.h> +#include <gntfilesel.h> #include <gntlabel.h> #include <gntline.h> #include <gnttextview.h> #include "gntdebug.h" #include "finch.h" +#include "notify.h" #include "util.h" #include <stdio.h> @@ -220,9 +222,43 @@ (GDestroyNotify)g_source_remove); } +static void +file_save(GntFileSel *fs, const char *path, const char *file, GntTextView *tv) +{ + FILE *fp; + + if ((fp = g_fopen(path, "w+")) == NULL) { + purple_notify_error(NULL, NULL, _("Unable to open file."), NULL); + return; + } + + fprintf(fp, "Finch Debug Log : %s\n", purple_date_format_full(NULL)); + fprintf(fp, tv->string->str); + fclose(fp); + gnt_widget_destroy(GNT_WIDGET(fs)); +} + +static void +file_cancel(GntWidget *w, GntFileSel *fs) +{ + gnt_widget_destroy(GNT_WIDGET(fs)); +} + +static void +save_debug_win(GntWidget *w, GntTextView *tv) +{ + GntWidget *window = gnt_file_sel_new(); + GntFileSel *sel = GNT_FILE_SEL(window); + gnt_file_sel_set_current_location(sel, purple_home_dir()); + gnt_file_sel_set_suggested_filename(sel, "debug.txt"); + g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(file_save), tv); + g_signal_connect(G_OBJECT(sel->cancel), "activate", G_CALLBACK(file_cancel), sel); + gnt_widget_show(window); +} + void finch_debug_window_show() { - GntWidget *wid, *box; + GntWidget *wid, *box, *label; debug.paused = FALSE; if (debug.window) { @@ -258,8 +294,15 @@ GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); gnt_box_add_widget(GNT_BOX(box), wid); + wid = gnt_button_new(_("Save")); + g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(save_debug_win), debug.tview); + GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); + gnt_box_add_widget(GNT_BOX(box), wid); + debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter")); - gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Filter: "))); + label = gnt_label_new(_("Filter:")); + GNT_WIDGET_UNSET_FLAGS(label, GNT_WIDGET_GROW_X); + gnt_box_add_widget(GNT_BOX(box), label); gnt_box_add_widget(GNT_BOX(box), debug.search); g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL);
--- a/finch/gntplugin.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntplugin.c Mon Oct 01 17:51:20 2007 +0000 @@ -32,6 +32,7 @@ #include "finch.h" +#include "debug.h" #include "notify.h" #include "request.h" @@ -127,8 +128,8 @@ /* XXX: Use formatting and stuff */ gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot)); text = g_strdup_printf(_("Name: %s\nVersion: %s\nDescription: %s\nAuthor: %s\nWebsite: %s\nFilename: %s\n"), - SAFE(plugin->info->name), SAFE(plugin->info->version), SAFE(plugin->info->description), - SAFE(plugin->info->author), SAFE(plugin->info->homepage), SAFE(plugin->path)); + SAFE(_(plugin->info->name)), SAFE(_(plugin->info->version)), SAFE(_(plugin->info->description)), + SAFE(_(plugin->info->author)), SAFE(_(plugin->info->homepage)), SAFE(plugin->path)); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(plugins.aboot), text, GNT_TEXT_FLAG_NORMAL); gnt_text_view_scroll(GNT_TEXT_VIEW(plugins.aboot), 0); @@ -237,6 +238,93 @@ } } +static void +install_selected_file_cb(gpointer handle, const char *filename) +{ + /* Try to init the selected file. + * If it succeeds, try to make a copy of the file in $USERDIR/plugins/. + * If the copy succeeds, unload and destroy the plugin in the original + * location and init+load the new one. + * Select the plugin in the plugin list. + */ + char *path; + PurplePlugin *plugin; + + g_return_if_fail(plugins.window); + + plugin = purple_plugin_probe(filename); + if (!plugin) { + purple_notify_error(handle, _("Error loading plugin"), + _("The selected file is not a valid plugin."), + _("Please open the debug window and try again to see the exact error message.")); + return; + } + if (g_list_find(gnt_tree_get_rows(GNT_TREE(plugins.tree)), plugin)) { + purple_plugin_load(plugin); + gnt_tree_set_choice(GNT_TREE(plugins.tree), plugin, purple_plugin_is_loaded(plugin)); + gnt_tree_set_selected(GNT_TREE(plugins.tree), plugin); + return; + } + + path = g_build_filename(purple_user_dir(), "plugins", NULL); + if (purple_build_dir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0) { + char *content = NULL; + gsize length = 0; + + if (g_file_get_contents(filename, &content, &length, NULL)) { + char *file = g_path_get_basename(filename); + g_free(path); + path = g_build_filename(purple_user_dir(), "plugins", file, NULL); + if (purple_util_write_data_to_file_absolute(path, content, length)) { + purple_plugin_destroy(plugin); + plugin = purple_plugin_probe(path); + if (!plugin) { + purple_debug_warning("gntplugin", "This is really strange. %s can be loaded, but %s can't!\n", + filename, path); + g_unlink(path); + plugin = purple_plugin_probe(filename); + } + } else { + } + } + g_free(content); + } + g_free(path); + + purple_plugin_load(plugin); + + if (plugin->info->type == PURPLE_PLUGIN_LOADER) { + GList *cur; + for (cur = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts; cur != NULL; + cur = cur->next) + purple_plugins_probe(cur->data); + return; + } + + if (plugin->info->type != PURPLE_PLUGIN_STANDARD || + (plugin->info->flags & PURPLE_PLUGIN_FLAG_INVISIBLE) || + plugin->error) + return; + + gnt_tree_add_choice(GNT_TREE(plugins.tree), plugin, + gnt_tree_create_row(GNT_TREE(plugins.tree), plugin->info->name), NULL, NULL); + gnt_tree_set_choice(GNT_TREE(plugins.tree), plugin, purple_plugin_is_loaded(plugin)); + gnt_tree_set_row_flags(GNT_TREE(plugins.tree), plugin, GNT_TEXT_FLAG_BOLD); + gnt_tree_set_selected(GNT_TREE(plugins.tree), plugin); +} + +static void +install_plugin_cb(GntWidget *w, gpointer null) +{ + static int handle; + + purple_request_close_with_handle(&handle); + purple_request_file(&handle, _("Select plugin to install"), NULL, + FALSE, G_CALLBACK(install_selected_file_cb), NULL, + NULL, NULL, NULL, &handle); + g_signal_connect_swapped(G_OBJECT(w), "destroy", G_CALLBACK(purple_request_close_with_handle), &handle); +} + void finch_plugins_show_all() { GntWidget *window, *tree, *box, *aboot, *button; @@ -272,6 +360,7 @@ gnt_box_add_widget(GNT_BOX(box), gnt_vline_new()); plugins.aboot = aboot = gnt_text_view_new(); + gnt_text_view_set_flag(GNT_TEXT_VIEW(aboot), GNT_TEXT_VIEW_TOP_ALIGN); gnt_widget_set_size(aboot, 40, 20); gnt_box_add_widget(GNT_BOX(box), aboot); @@ -307,6 +396,10 @@ box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); + button = gnt_button_new(_("Install Plugin...")); + gnt_box_add_widget(GNT_BOX(box), button); + g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(install_plugin_cb), NULL); + button = gnt_button_new(_("Close")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect_swapped(G_OBJECT(button), "activate",
--- a/finch/gntpounce.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntpounce.c Mon Oct 01 17:51:20 2007 +0000 @@ -964,10 +964,15 @@ PURPLE_CALLBACK(signed_on_off_cb), NULL); } +static void +dummy_pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data) +{ +} + /* XXX: There's no such thing in pidgin. Perhaps there should be? */ void finch_pounces_uninit() { - purple_pounces_register_handler(FINCH_UI, NULL, NULL, NULL); + purple_pounces_register_handler(FINCH_UI, dummy_pounce_cb, NULL, NULL); purple_signals_disconnect_by_handle(finch_pounces_get_handle()); }
--- a/finch/gntrequest.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/gntrequest.c Mon Oct 01 17:51:20 2007 +0000 @@ -76,6 +76,8 @@ static void setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data) { + if (default_cb == NULL) + return; g_object_set_data(G_OBJECT(window), "default-callback", default_cb); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data); }
--- a/finch/libgnt/gntstyle.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/libgnt/gntstyle.c Mon Oct 01 17:51:20 2007 +0000 @@ -26,6 +26,7 @@ #include <glib.h> #include <ctype.h> +#include <glib/gprintf.h> #include <stdlib.h> #include <string.h>
--- a/finch/libgnt/gntwm.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/libgnt/gntwm.c Mon Oct 01 17:51:20 2007 +0000 @@ -27,8 +27,8 @@ #include "config.h" -#include <glib.h> #include <ctype.h> +#include <glib/gprintf.h> #include <gmodule.h> #include <stdlib.h> #include <string.h>
--- a/finch/libgnt/pygnt/gntmodule.c Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/libgnt/pygnt/gntmodule.c Mon Oct 01 17:51:20 2007 +0000 @@ -1,7 +1,74 @@ #include <pygobject.h> +#include "gnt.h" void gnt_register_classes (PyObject *d); extern PyMethodDef gnt_functions[]; + +static void +gnt_add_string_constants(PyObject *module) +{ +#define define_key(x) if (GNT_KEY_##x && *(GNT_KEY_##x)) PyModule_AddStringConstant(module, "KEY_" #x, GNT_KEY_##x) + + define_key(POPUP); + + define_key(LEFT); + define_key(RIGHT); + define_key(UP); + define_key(DOWN); + + define_key(CTRL_UP); + define_key(CTRL_DOWN); + define_key(CTRL_RIGHT); + define_key(CTRL_LEFT); + + define_key(PGUP); + define_key(PGDOWN); + define_key(HOME); + define_key(END); + + define_key(ENTER); + + define_key(BACKSPACE); + define_key(DEL); + define_key(INS); + define_key(BACK_TAB); + + define_key(CTRL_A); + define_key(CTRL_B); + define_key(CTRL_D); + define_key(CTRL_E); + define_key(CTRL_F); + define_key(CTRL_G); + define_key(CTRL_H); + define_key(CTRL_I); + define_key(CTRL_J); + define_key(CTRL_K); + define_key(CTRL_L); + define_key(CTRL_M); + define_key(CTRL_N); + define_key(CTRL_O); + define_key(CTRL_P); + define_key(CTRL_R); + define_key(CTRL_T); + define_key(CTRL_U); + define_key(CTRL_V); + define_key(CTRL_W); + define_key(CTRL_X); + define_key(CTRL_Y); + + define_key(F1); + define_key(F2); + define_key(F3); + define_key(F4); + define_key(F5); + define_key(F6); + define_key(F7); + define_key(F8); + define_key(F9); + define_key(F10); + define_key(F11); + define_key(F12); +} DL_EXPORT(void) initgnt(void) @@ -19,5 +86,8 @@ if (PyErr_Occurred ()) { Py_FatalError ("can't initialise module sad"); } + + gnt_init(); + gnt_add_string_constants(m); }
--- a/finch/libgnt/pygnt/gnttree.override Mon Oct 01 17:49:01 2007 +0000 +++ b/finch/libgnt/pygnt/gnttree.override Mon Oct 01 17:51:20 2007 +0000 @@ -62,13 +62,14 @@ { static char *kwlist[] = {"key", "row", "parent", "bigbro", NULL}; PyObject *py_list; - gpointer key, parent, bigbro; + gpointer key, parent, bigbro = NULL; int len, i; GList *list = NULL; GntTreeRow *row; + gboolean insert_last = FALSE; if (!PyArg_ParseTuple(args, - "OOOO:GntTree.add_row_after", + "OOO|O:GntTree.add_row_after", &key, &py_list, &parent, @@ -92,13 +93,20 @@ parent = NULL; if (bigbro == Py_None) bigbro = NULL; + else if (bigbro == NULL) + insert_last = TRUE; + + Py_INCREF((PyObject*)key); list = g_list_reverse(list); row = gnt_tree_create_row_from_list(GNT_TREE(self->obj), list); - gnt_tree_add_row_after(GNT_TREE(self->obj), - key, - row, - parent, bigbro); + if (insert_last) + gnt_tree_add_row_last(GNT_TREE(self->obj), + key, row, parent); + else + gnt_tree_add_row_after(GNT_TREE(self->obj), + key, row, + parent, bigbro); g_list_free(list); Py_INCREF(Py_None); @@ -179,4 +187,27 @@ Py_INCREF(Py_None); return Py_None; } +%% +override gnt_tree_set_compare_func +static PyObject * +_wrap_gnt_tree_set_compare_func(PyGObject *self, PyObject *args) +{ + static char *kwlist[] = {"compare_func", NULL}; + PyGObject *compare; + if (!PyArg_ParseTuple(args, "O:GntTree.set_compare_func", &compare)) { + return NULL; + } + + if (!PyCallable_Check(compare)) { + PyErr_SetString(PyExc_TypeError, "the callback must be callable ... doh!"); + return NULL; + } + + Py_INCREF(compare); + gnt_tree_set_compare_func(GNT_TREE(self->obj), (GCompareFunc)compare->obj); + + Py_INCREF(Py_None); + return Py_None; +} +
--- a/libpurple/blist.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/blist.c Mon Oct 01 17:51:20 2007 +0000 @@ -632,12 +632,13 @@ continue; buddy = (PurpleBuddy*)bnode; - - if (!purple_account_is_connected(buddy->account)) + if (new_priority == NULL) + { + new_priority = buddy; continue; - if (new_priority == NULL) - new_priority = buddy; - else + } + + if (purple_account_is_connected(buddy->account)) { int cmp; @@ -1442,29 +1443,7 @@ void purple_contact_set_alias(PurpleContact *contact, const char *alias) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - char *old_alias; - - g_return_if_fail(contact != NULL); - - if (!purple_strings_are_different(contact->alias, alias)) - return; - - old_alias = contact->alias; - - if ((alias != NULL) && (*alias != '\0')) - contact->alias = g_strdup(alias); - else - contact->alias = NULL; - - purple_blist_schedule_save(); - - if (ops && ops->update) - ops->update(purplebuddylist, (PurpleBlistNode*)contact); - - purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased", - contact, old_alias); - g_free(old_alias); + purple_blist_alias_contact(contact,alias); } const char *purple_contact_get_alias(PurpleContact* contact)
--- a/libpurple/blist.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/blist.h Mon Oct 01 17:51:20 2007 +0000 @@ -65,11 +65,11 @@ typedef enum { - PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 /**< node should not be saved with the buddy list */ + PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 << 0, /**< node should not be saved with the buddy list */ } PurpleBlistNodeFlags; -#define PURPLE_BLIST_NODE_HAS_FLAG(b, f) ((b)->flags & (f)) +#define PURPLE_BLIST_NODE_HAS_FLAG(b, f) (((PurpleBlistNode*)(b))->flags & (f)) #define PURPLE_BLIST_NODE_SHOULD_SAVE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_NO_SAVE)) #define PURPLE_BLIST_NODE_NAME(n) ((n)->type == PURPLE_BLIST_CHAT_NODE ? purple_chat_get_name((PurpleChat*)n) : \ @@ -488,6 +488,8 @@ * * @param contact The contact * @param alias The alias to set, or NULL to unset + * + * @deprecated Use purple_blist_alias_contact() instead. */ void purple_contact_set_alias(PurpleContact *contact, const char *alias);
--- a/libpurple/conversation.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/conversation.c Mon Oct 01 17:51:20 2007 +0000 @@ -2348,7 +2348,7 @@ purple_signal_register(handle, "chat-invited", purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER, - NULL, 5, + purple_value_new(PURPLE_TYPE_INT), 5, purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT), purple_value_new(PURPLE_TYPE_STRING),
--- a/libpurple/dnssrv.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/dnssrv.c Mon Oct 01 17:51:20 2007 +0000 @@ -69,6 +69,7 @@ char *error_message; GSList *results; #else + int fd_in, fd_out; pid_t pid; #endif }; @@ -112,8 +113,11 @@ purple_restore_default_signal_handlers(); #endif - if (read(in, query, 256) <= 0) + if (read(in, query, 256) <= 0) { + close(out); + close(in); _exit(0); + } size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); @@ -179,6 +183,9 @@ ret = g_list_remove(ret, ret->data); } + close(out); + close(in); + _exit(0); } @@ -358,6 +365,8 @@ query_data->cb = cb; query_data->extradata = extradata; query_data->pid = pid; + query_data->fd_out = out[0]; + query_data->fd_in = in[1]; query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); g_free(query); @@ -414,6 +423,9 @@ } g_free(query_data->query); g_free(query_data->error_message); +#else + close(query_data->fd_out); + close(query_data->fd_in); #endif g_free(query_data); }
--- a/libpurple/ft.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/ft.c Mon Oct 01 17:51:20 2007 +0000 @@ -67,6 +67,7 @@ xfer->ui_ops = purple_xfers_get_ui_ops(); xfer->message = NULL; xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; + xfer->fd = -1; ui_ops = purple_xfer_get_ui_ops(xfer);
--- a/libpurple/internal.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/internal.h Mon Oct 01 17:51:20 2007 +0000 @@ -80,6 +80,7 @@ #ifndef _WIN32 #include <sys/time.h> #include <sys/wait.h> +#include <sys/time.h> #endif #include <ctype.h> #include <errno.h>
--- a/libpurple/notify.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/notify.c Mon Oct 01 17:51:20 2007 +0000 @@ -150,8 +150,6 @@ { PurpleNotifyUiOps *ops; - g_return_val_if_fail(count != 0, NULL); - if (count == 1) { return purple_notify_email(handle, (subjects == NULL ? NULL : *subjects), @@ -506,7 +504,7 @@ g_return_if_fail(user_info_entry != NULL); g_free(user_info_entry->label); - g_free(user_info_entry->value); + g_free(user_info_entry->value); PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry); g_free(user_info_entry); } @@ -568,7 +566,7 @@ if (user_info_entry->label && user_info_entry->value) g_string_append(text, ": "); if (user_info_entry->value) - g_string_append(text, user_info_entry->value); + g_string_append(text, user_info_entry->value); /* Display a section break as a horizontal line */ if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK)
--- a/libpurple/plugin.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/plugin.c Mon Oct 01 17:51:20 2007 +0000 @@ -1275,13 +1275,9 @@ if (basename) basename = purple_plugin_get_basename(filename); - if ((plugin = purple_plugins_find_with_filename(filename)) != NULL) - { - purple_debug_info("plugins", "Loading saved plugin %s\n", - plugin->path); - purple_plugin_load(plugin); - } - else if (basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) + if (((plugin = purple_plugins_find_with_filename(filename)) != NULL) || + (basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) || + ((plugin = purple_plugin_probe(filename)) != NULL)) { purple_debug_info("plugins", "Loading saved plugin %s\n", plugin->path);
--- a/libpurple/plugins/tcl/tcl.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/plugins/tcl/tcl.c Mon Oct 01 17:51:20 2007 +0000 @@ -60,6 +60,7 @@ PurpleStringref *PurpleTclRefStatusAttr; PurpleStringref *PurpleTclRefStatusType; PurpleStringref *PurpleTclRefXfer; +PurpleStringref *PurpleTclRefHandle; static GHashTable *tcl_plugins = NULL; @@ -363,6 +364,7 @@ PurpleTclRefStatusAttr = purple_stringref_new("StatusAttr"); PurpleTclRefStatusType = purple_stringref_new("StatusType"); PurpleTclRefXfer = purple_stringref_new("Xfer"); + PurpleTclRefHandle = purple_stringref_new("Handle"); tcl_plugins = g_hash_table_new(g_direct_hash, g_direct_equal);
--- a/libpurple/plugins/tcl/tcl_cmds.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/plugins/tcl/tcl_cmds.c Mon Oct 01 17:51:20 2007 +0000 @@ -55,7 +55,7 @@ return account; } if (interp != NULL) - Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid account", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid account", -1)); return NULL; } @@ -74,7 +74,7 @@ return convo; } if (interp != NULL) - Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid conversation", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid conversation", -1)); return NULL; } @@ -97,7 +97,7 @@ int tcl_cmd_account(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem; + Tcl_Obj *result, *list, *elem; const char *cmds[] = { "alias", "connect", "connection", "disconnect", "enabled", "find", "handle", "isconnected", "list", "presence", "protocol", "status", @@ -139,7 +139,7 @@ if ((account = tcl_validate_account(objv[2], interp)) == NULL) return TCL_ERROR; alias = purple_account_get_alias(account); - Tcl_SetStringObj(result, alias ? (char *)alias : "", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj(alias ? (char *)alias : "", -1)); break; case CMD_ACCOUNT_CONNECT: if (objc != 3) { @@ -164,7 +164,7 @@ return TCL_ERROR; Tcl_SetObjResult(interp, purple_tcl_ref_new(PurpleTclRefConnection, - purple_account_get_connection(account))); + purple_account_get_connection(account))); break; case CMD_ACCOUNT_DISCONNECT: if (objc != 3) { @@ -183,9 +183,10 @@ if ((account = tcl_validate_account(objv[2], interp)) == NULL) return TCL_ERROR; if (objc == 3) { - Tcl_SetBooleanObj(result, - purple_account_get_enabled(account, - purple_core_get_ui())); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_account_get_enabled(account, + purple_core_get_ui()))); } else { if ((error = Tcl_GetBooleanFromObj(interp, objv[3], &b)) != TCL_OK) return TCL_ERROR; @@ -207,7 +208,9 @@ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_accounts_get_handle()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_accounts_get_handle())); break; case CMD_ACCOUNT_ISCONNECTED: if (objc != 3) { @@ -216,7 +219,9 @@ } if ((account = tcl_validate_account(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_account_is_connected(account)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_account_is_connected(account))); break; case CMD_ACCOUNT_LIST: listopt = CMD_ACCOUNTLIST_ALL; @@ -255,7 +260,7 @@ } if ((account = tcl_validate_account(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, (char *)purple_account_get_protocol_id(account), -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj((char *)purple_account_get_protocol_id(account), -1)); break; case CMD_ACCOUNT_STATUS: if (objc < 3) { @@ -271,19 +276,19 @@ } else { GList *l = NULL; if (objc % 2) { - Tcl_SetStringObj(result, "name without value setting status", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("name without value setting status", -1)); return TCL_ERROR; } status = purple_account_get_status(account, Tcl_GetString(objv[3])); if (status == NULL) { - Tcl_SetStringObj(result, "invalid status for account", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid status for account", -1)); return TCL_ERROR; } for (i = 4; i < objc; i += 2) { attr_id = Tcl_GetString(objv[i]); value = purple_status_get_attr_value(status, attr_id); if (value == NULL) { - Tcl_SetStringObj(result, "invalid attribute for account", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid attribute for account", -1)); return TCL_ERROR; } switch (purple_value_get_type(value)) { @@ -306,7 +311,7 @@ l = g_list_append(l, Tcl_GetString(objv[i + 1])); break; default: - Tcl_SetStringObj(result, "unknown PurpleValue type", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unknown PurpleValue type", -1)); return TCL_ERROR; } } @@ -327,10 +332,10 @@ } else { PurpleStatusPrimitive primitive; if (strcmp(Tcl_GetString(objv[3]), "-primitive")) { - Tcl_SetStringObj(result, "bad option \"", -1); + result = Tcl_NewStringObj("bad option \"", -1); Tcl_AppendObjToObj(result, objv[3]); - Tcl_AppendToObj(result, - "\": should be -primitive", -1); + Tcl_AppendToObj(result, "\": should be -primitive", -1); + Tcl_SetObjResult(interp,result); return TCL_ERROR; } primitive = purple_primitive_get_type_from_id(Tcl_GetString(objv[4])); @@ -338,7 +343,7 @@ primitive); } if (status_type == NULL) { - Tcl_SetStringObj(result, "status type not found", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("status type not found", -1)); return TCL_ERROR; } Tcl_SetObjResult(interp, @@ -368,7 +373,8 @@ } if ((account = tcl_validate_account(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, (char *)purple_account_get_username(account), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj((char *)purple_account_get_username(account), -1)); break; } @@ -383,7 +389,8 @@ char *type; if (count < 3) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), "list too short", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("list too short", -1)); return NULL; } @@ -420,8 +427,6 @@ if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) return error; - result = Tcl_GetObjResult(interp); - switch (cmd) { case CMD_BUDDY_ALIAS: if (objc != 3) { @@ -433,9 +438,11 @@ if ((node = tcl_list_to_buddy(interp, count, elems)) == NULL) return TCL_ERROR; if (node->type == PURPLE_BLIST_CHAT_NODE) - Tcl_SetStringObj(result, ((PurpleChat *)node)->alias, -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(((PurpleChat *)node)->alias, -1)); else if (node->type == PURPLE_BLIST_BUDDY_NODE) - Tcl_SetStringObj(result, (char *)purple_buddy_get_alias((PurpleBuddy *)node), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj((char *)purple_buddy_get_alias((PurpleBuddy *)node), -1)); return TCL_OK; break; case CMD_BUDDY_HANDLE: @@ -443,7 +450,9 @@ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_blist_get_handle()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_blist_get_handle())); break; case CMD_BUDDY_INFO: if (objc != 3 && objc != 4) { @@ -454,11 +463,13 @@ if ((error = Tcl_ListObjGetElements(interp, objv[2], &count, &elems)) != TCL_OK) return error; if (count < 3) { - Tcl_SetStringObj(result, "buddy too short", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("buddy too short", -1)); return TCL_ERROR; } if (strcmp("buddy", Tcl_GetString(elems[0]))) { - Tcl_SetStringObj(result, "invalid buddy", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("invalid buddy", -1)); return TCL_ERROR; } if ((account = tcl_validate_account(elems[2], interp)) == NULL) @@ -475,8 +486,9 @@ if (!strcmp("-all", Tcl_GetString(objv[2]))) { all = 1; } else { - Tcl_SetStringObj(result, "", -1); + result = Tcl_NewStringObj("",-1); Tcl_AppendStringsToObj(result, "unknown option: ", Tcl_GetString(objv[2]), NULL); + Tcl_SetObjResult(interp,result); return TCL_ERROR; } } @@ -547,7 +559,7 @@ const char *cmds[] = { "do", "help", "list", "register", "unregister", NULL }; enum { CMD_CMD_DO, CMD_CMD_HELP, CMD_CMD_LIST, CMD_CMD_REGISTER, CMD_CMD_UNREGISTER } cmd; struct tcl_cmd_handler *handler; - Tcl_Obj *list, *elem, *result = Tcl_GetObjResult(interp); + Tcl_Obj *list, *elem; PurpleConversation *convo; PurpleCmdId id; PurpleCmdStatus status; @@ -575,7 +587,8 @@ status = purple_cmd_do_command(convo, Tcl_GetString(objv[3]), escaped, &errstr); g_free(escaped); - Tcl_SetStringObj(result, errstr ? (char *)errstr : "", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(errstr ? (char *)errstr : "", -1)); g_free(errstr); if (status != PURPLE_CMD_STATUS_OK) { return TCL_ERROR; @@ -640,10 +653,10 @@ handler->interp = interp; if ((id = tcl_cmd_register(handler)) == 0) { tcl_cmd_handler_free(handler); - Tcl_SetIntObj(result, 0); + Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } else { handler->id = id; - Tcl_SetIntObj(result, id); + Tcl_SetObjResult(interp, Tcl_NewIntObj(id)); } break; case CMD_CMD_UNREGISTER: @@ -663,7 +676,7 @@ int tcl_cmd_connection(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem; + Tcl_Obj *list, *elem; const char *cmds[] = { "account", "displayname", "handle", "list", NULL }; enum { CMD_CONN_ACCOUNT, CMD_CONN_DISPLAYNAME, CMD_CONN_HANDLE, CMD_CONN_LIST } cmd; int error; @@ -697,14 +710,16 @@ } if ((gc = tcl_validate_gc(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, (char *)purple_connection_get_display_name(gc), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_connection_get_display_name(gc), -1)); break; case CMD_CONN_HANDLE: if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_connections_get_handle()); + Tcl_SetObjResult(interp, purple_tcl_ref_new(PurpleTclRefHandle, + purple_connections_get_handle())); break; case CMD_CONN_LIST: if (objc != 2) { @@ -725,7 +740,7 @@ int tcl_cmd_conversation(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *list, *elem, *result = Tcl_GetObjResult(interp); + Tcl_Obj *list, *elem; const char *cmds[] = { "find", "handle", "list", "new", "write", "name", "title", "send", NULL }; enum { CMD_CONV_FIND, CMD_CONV_HANDLE, CMD_CONV_LIST, CMD_CONV_NEW, CMD_CONV_WRITE , CMD_CONV_NAME, CMD_CONV_TITLE, CMD_CONV_SEND } cmd; const char *styles[] = { "send", "recv", "system", NULL }; @@ -766,7 +781,9 @@ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_conversations_get_handle()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_conversations_get_handle())); break; case CMD_CONV_LIST: list = Tcl_NewListObj(0, NULL); @@ -847,7 +864,8 @@ if ((convo = tcl_validate_conversation(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, (char *)purple_conversation_get_name(convo), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj((char *)purple_conversation_get_name(convo), -1)); break; case CMD_CONV_TITLE: if (objc != 3) { @@ -857,7 +875,8 @@ if ((convo = tcl_validate_conversation(objv[2], interp)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, (char *)purple_conversation_get_title(convo), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj((char *)purple_conversation_get_title(convo), -1)); break; case CMD_CONV_SEND: if (objc != 4) { @@ -879,7 +898,6 @@ int tcl_cmd_core(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result = Tcl_GetObjResult(interp); const char *cmds[] = { "handle", "quit", NULL }; enum { CMD_CORE_HANDLE, CMD_CORE_QUIT } cmd; int error; @@ -898,7 +916,9 @@ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_get_core()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_get_core())); break; case CMD_CORE_QUIT: if (objc != 2) { @@ -970,7 +990,6 @@ int tcl_cmd_plugins(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result = Tcl_GetObjResult(interp); const char *cmds[] = { "handle", NULL }; enum { CMD_PLUGINS_HANDLE } cmd; int error; @@ -989,7 +1008,9 @@ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_plugins_get_handle()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_plugins_get_handle())); break; } @@ -998,7 +1019,7 @@ int tcl_cmd_prefs(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result, *list, *elem, **elems; + Tcl_Obj *list, *elem, **elems; const char *cmds[] = { "get", "set", "type", NULL }; enum { CMD_PREFS_GET, CMD_PREFS_SET, CMD_PREFS_TYPE } cmd; /* char *types[] = { "none", "boolean", "int", "string", "stringlist", NULL }; */ @@ -1015,7 +1036,6 @@ if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) return error; - result = Tcl_GetObjResult(interp); switch (cmd) { case CMD_PREFS_GET: if (objc != 3) { @@ -1025,17 +1045,21 @@ preftype = purple_prefs_get_type(Tcl_GetString(objv[2])); switch (preftype) { case PURPLE_PREF_NONE: - Tcl_SetStringObj(result, "pref type none", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("pref type none", -1)); return TCL_ERROR; break; case PURPLE_PREF_BOOLEAN: - Tcl_SetBooleanObj(result, purple_prefs_get_bool(Tcl_GetString(objv[2]))); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_prefs_get_bool(Tcl_GetString(objv[2])))); break; case PURPLE_PREF_INT: - Tcl_SetIntObj(result, purple_prefs_get_int(Tcl_GetString(objv[2]))); + Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_prefs_get_int(Tcl_GetString(objv[2])))); break; case PURPLE_PREF_STRING: - Tcl_SetStringObj(result, (char *)purple_prefs_get_string(Tcl_GetString(objv[2])), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj((char *)purple_prefs_get_string(Tcl_GetString(objv[2])), -1)); break; case PURPLE_PREF_STRING_LIST: cur = purple_prefs_get_string_list(Tcl_GetString(objv[2])); @@ -1049,7 +1073,8 @@ break; default: purple_debug(PURPLE_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype); - Tcl_SetStringObj(result, "unknown pref type", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("unknown pref type", -1)); return TCL_ERROR; } break; @@ -1061,7 +1086,8 @@ preftype = purple_prefs_get_type(Tcl_GetString(objv[2])); switch (preftype) { case PURPLE_PREF_NONE: - Tcl_SetStringObj(result, "bad path or pref type none", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("bad path or pref type none", -1)); return TCL_ERROR; break; case PURPLE_PREF_BOOLEAN: @@ -1100,23 +1126,23 @@ preftype = purple_prefs_get_type(Tcl_GetString(objv[2])); switch (preftype) { case PURPLE_PREF_NONE: - Tcl_SetStringObj(result, "none", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1)); break; case PURPLE_PREF_BOOLEAN: - Tcl_SetStringObj(result, "boolean", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("boolean", -1)); break; case PURPLE_PREF_INT: - Tcl_SetStringObj(result, "int", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("int", -1)); break; case PURPLE_PREF_STRING: - Tcl_SetStringObj(result, "string", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("string", -1)); break; case PURPLE_PREF_STRING_LIST: - Tcl_SetStringObj(result, "stringlist", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("stringlist", -1)); break; default: purple_debug(PURPLE_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype); - Tcl_SetStringObj(result, "unknown", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unknown", -1)); } break; } @@ -1134,7 +1160,7 @@ CMD_PRESENCE_CONTEXT, CMD_PRESENCE_CONVERSATION, CMD_PRESENCE_IDLE, CMD_PRESENCE_LOGIN, CMD_PRESENCE_ONLINE, CMD_PRESENCE_STATUS, CMD_PRESENCE_STATUSES } cmd; - Tcl_Obj *result = Tcl_GetObjResult(interp); + Tcl_Obj *result; Tcl_Obj *list, *elem; PurplePresence *presence; GList *cur; @@ -1171,25 +1197,30 @@ purple_tcl_ref_new(PurpleTclRefStatus, purple_presence_get_active_status(presence))); } else if (objc == 4) { - Tcl_SetBooleanObj(result, - purple_presence_is_status_active(presence, - Tcl_GetString(objv[3]))); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_presence_is_status_active(presence, + Tcl_GetString(objv[3])))); } else { PurpleStatusPrimitive primitive; if (strcmp(Tcl_GetString(objv[3]), "-primitive")) { - Tcl_SetStringObj(result, "bad option \"", -1); + result = Tcl_NewStringObj("bad option \"", -1); Tcl_AppendObjToObj(result, objv[3]); Tcl_AppendToObj(result, "\": should be -primitive", -1); + Tcl_SetObjResult(interp,result); return TCL_ERROR; } primitive = purple_primitive_get_type_from_id(Tcl_GetString(objv[4])); if (primitive == PURPLE_STATUS_UNSET) { - Tcl_SetStringObj(result, "invalid primitive ", -1); + result = Tcl_NewStringObj("invalid primitive ", -1); Tcl_AppendObjToObj(result, objv[4]); + Tcl_SetObjResult(interp,result); return TCL_ERROR; } - Tcl_SetBooleanObj(result, purple_presence_is_status_primitive_active(presence, primitive)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_presence_is_status_primitive_active(presence, primitive))); break; } break; @@ -1200,7 +1231,8 @@ } if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_presence_is_available(presence)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(purple_presence_is_available(presence))); break; case CMD_PRESENCE_CHAT_USER: if (objc != 3) { @@ -1209,7 +1241,8 @@ } if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_presence_get_chat_user(presence), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_presence_get_chat_user(presence), -1)); break; case CMD_PRESENCE_CONTEXT: if (objc != 3) { @@ -1220,16 +1253,16 @@ return TCL_ERROR; switch (purple_presence_get_context(presence)) { case PURPLE_PRESENCE_CONTEXT_UNSET: - Tcl_SetStringObj(result, "unset", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unset", -1)); break; case PURPLE_PRESENCE_CONTEXT_ACCOUNT: - Tcl_SetStringObj(result, "account", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("account", -1)); break; case PURPLE_PRESENCE_CONTEXT_CONV: - Tcl_SetStringObj(result, "conversation", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("conversation", -1)); break; case PURPLE_PRESENCE_CONTEXT_BUDDY: - Tcl_SetStringObj(result, "buddy", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj("buddy", -1)); break; } break; @@ -1253,7 +1286,7 @@ if (objc == 3) { if (purple_presence_is_idle(presence)) { idle_time = purple_presence_get_idle_time (presence); - Tcl_SetIntObj(result, idle_time); + Tcl_SetObjResult(interp, Tcl_NewIntObj(idle_time)); } else { result = Tcl_NewListObj(0, NULL); Tcl_SetObjResult(interp, result); @@ -1280,7 +1313,7 @@ if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL) return TCL_ERROR; if (objc == 3) { - Tcl_SetIntObj(result, purple_presence_get_login_time(presence)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_presence_get_login_time(presence))); } else { if ((error == Tcl_GetIntFromObj(interp, objv[3], @@ -1296,7 +1329,9 @@ } if ((presence = purple_tcl_ref_get(interp, objv[2], PurpleTclRefPresence)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_presence_is_online(presence)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_presence_is_online(presence))); break; case CMD_PRESENCE_STATUS: if (objc != 4) { @@ -1332,7 +1367,7 @@ int tcl_cmd_savedstatus(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - Tcl_Obj *result = Tcl_GetObjResult(interp); + Tcl_Obj *result; const char *cmds[] = { "current", "handle", NULL }; enum { CMD_SAVEDSTATUS_CURRENT, CMD_SAVEDSTATUS_HANDLE } cmd; int error; @@ -1354,16 +1389,20 @@ } if ((saved_status = purple_savedstatus_get_current()) == NULL) return TCL_ERROR; + result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(purple_savedstatus_get_title(saved_status), -1)); Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(purple_savedstatus_get_type(saved_status))); Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(purple_savedstatus_get_message(saved_status), -1)); + Tcl_SetObjResult(interp,result); break; case CMD_SAVEDSTATUS_HANDLE: if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } - Tcl_SetIntObj(result, (int)purple_savedstatuses_get_handle()); + Tcl_SetObjResult(interp, + purple_tcl_ref_new(PurpleTclRefHandle, + purple_savedstatuses_get_handle())); break; } @@ -1396,7 +1435,6 @@ const char *cmds[] = { "connect", "disconnect", NULL }; enum { CMD_SIGNAL_CONNECT, CMD_SIGNAL_DISCONNECT } cmd; struct tcl_signal_handler *handler; - Tcl_Obj *result = Tcl_GetObjResult(interp); void *instance; int error; @@ -1415,7 +1453,7 @@ return TCL_ERROR; } handler = g_new0(struct tcl_signal_handler, 1); - if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&handler->instance)) != TCL_OK) { + if ((handler->instance = purple_tcl_ref_get(interp, objv[2],PurpleTclRefHandle)) == NULL) { g_free(handler); return error; } @@ -1426,9 +1464,9 @@ handler->interp = interp; if (!tcl_signal_connect(handler)) { tcl_signal_handler_free(handler); - Tcl_SetIntObj(result, 1); + Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); } else { - Tcl_SetIntObj(result, 0); + Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } break; case CMD_SIGNAL_DISCONNECT: @@ -1436,7 +1474,7 @@ Tcl_WrongNumArgs(interp, 2, objv, "instance signal"); return TCL_ERROR; } - if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&instance)) != TCL_OK) + if ((instance = purple_tcl_ref_get(interp, objv[2],PurpleTclRefHandle)) == NULL) return error; tcl_signal_disconnect(instance, Tcl_GetString(objv[3]), interp); break; @@ -1449,7 +1487,6 @@ { const char *cmds[] = { "attr", "type", NULL }; enum { CMD_STATUS_ATTR, CMD_STATUS_TYPE } cmd; - Tcl_Obj *result = Tcl_GetObjResult(interp); PurpleStatus *status; PurpleStatusType *status_type; PurpleValue *value; @@ -1475,13 +1512,15 @@ attr = Tcl_GetString(objv[3]); value = purple_status_get_attr_value(status, attr); if (value == NULL) { - Tcl_SetStringObj(result, "no such attribute", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("no such attribute", -1)); return TCL_ERROR; } switch (purple_value_get_type(value)) { case PURPLE_TYPE_BOOLEAN: if (objc == 4) { - Tcl_SetBooleanObj(result, purple_value_get_boolean(value)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(purple_value_get_boolean(value))); } else { if ((error = Tcl_GetBooleanFromObj(interp, objv[4], &v)) != TCL_OK) return error; @@ -1490,7 +1529,7 @@ break; case PURPLE_TYPE_INT: if (objc == 4) { - Tcl_SetIntObj(result, purple_value_get_int(value)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(purple_value_get_int(value))); } else { if ((error = Tcl_GetIntFromObj(interp, objv[4], &v)) != TCL_OK) return error; @@ -1499,12 +1538,14 @@ break; case PURPLE_TYPE_STRING: if (objc == 4) - Tcl_SetStringObj(result, purple_value_get_string(value), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_value_get_string(value), -1)); else purple_status_set_attr_string(status, attr, Tcl_GetString(objv[4])); break; default: - Tcl_SetStringObj(result, "attribute has unknown type", -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj("attribute has unknown type", -1)); return TCL_ERROR; } break; @@ -1528,7 +1569,6 @@ { const char *cmds[] = { "id", "name", NULL }; enum { CMD_STATUS_ATTR_ID, CMD_STATUS_ATTR_NAME } cmd; - Tcl_Obj *result = Tcl_GetObjResult(interp); PurpleStatusAttr *attr; int error; @@ -1548,7 +1588,8 @@ } if ((attr = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusAttr)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_status_attr_get_id(attr), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_status_attr_get_id(attr), -1)); break; case CMD_STATUS_ATTR_NAME: if (objc != 3) { @@ -1557,7 +1598,8 @@ } if ((attr = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusAttr)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_status_attr_get_name(attr), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_status_attr_get_name(attr), -1)); break; } @@ -1576,7 +1618,6 @@ CMD_STATUS_TYPE_NAME, CMD_STATUS_TYPE_PRIMARY_ATTR, CMD_STATUS_TYPE_PRIMITIVE, CMD_STATUS_TYPE_SAVEABLE, CMD_STATUS_TYPE_USER_SETTABLE } cmd; - Tcl_Obj *result = Tcl_GetObjResult(interp); PurpleStatusType *status_type; Tcl_Obj *list, *elem; GList *cur; @@ -1598,7 +1639,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_status_type_is_available(status_type)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(purple_status_type_is_available(status_type))); break; case CMD_STATUS_TYPE_ATTR: if (objc != 4) { @@ -1634,7 +1676,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_status_type_is_exclusive(status_type)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(purple_status_type_is_exclusive(status_type))); break; case CMD_STATUS_TYPE_ID: if (objc != 3) { @@ -1643,7 +1686,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_status_type_get_id(status_type), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_status_type_get_id(status_type), -1)); break; case CMD_STATUS_TYPE_INDEPENDENT: if (objc != 3) { @@ -1652,7 +1696,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_status_type_is_independent(status_type)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(purple_status_type_is_independent(status_type))); break; case CMD_STATUS_TYPE_NAME: if (objc != 3) { @@ -1661,7 +1706,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_status_type_get_name(status_type), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_status_type_get_name(status_type), -1)); break; case CMD_STATUS_TYPE_PRIMITIVE: if (objc != 3) { @@ -1670,7 +1716,9 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_primitive_get_id_from_type(purple_status_type_get_primitive(status_type)), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_primitive_get_id_from_type + (purple_status_type_get_primitive(status_type)), -1)); break; case CMD_STATUS_TYPE_PRIMARY_ATTR: if (objc != 3) { @@ -1679,7 +1727,8 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetStringObj(result, purple_status_type_get_primary_attr(status_type), -1); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(purple_status_type_get_primary_attr(status_type), -1)); break; case CMD_STATUS_TYPE_SAVEABLE: if (objc != 3) { @@ -1688,7 +1737,9 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_status_type_is_saveable(status_type)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_status_type_is_saveable(status_type))); break; case CMD_STATUS_TYPE_USER_SETTABLE: if (objc != 3) { @@ -1697,7 +1748,9 @@ } if ((status_type = purple_tcl_ref_get(interp, objv[2], PurpleTclRefStatusType)) == NULL) return TCL_ERROR; - Tcl_SetBooleanObj(result, purple_status_type_is_user_settable(status_type)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj( + purple_status_type_is_user_settable(status_type))); break; }
--- a/libpurple/plugins/tcl/tcl_purple.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/plugins/tcl/tcl_purple.h Mon Oct 01 17:51:20 2007 +0000 @@ -76,6 +76,7 @@ extern PurpleStringref *PurpleTclRefStatusAttr; extern PurpleStringref *PurpleTclRefStatusType; extern PurpleStringref *PurpleTclRefXfer; +extern PurpleStringref *PurpleTclRefHandle; PurplePlugin *tcl_interp_get_plugin(Tcl_Interp *interp);
--- a/libpurple/protocols/irc/msgs.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon Oct 01 17:51:20 2007 +0000 @@ -751,7 +751,10 @@ } purple_conversation_set_data(convo, IRC_NAMES_FLAG, GINT_TO_POINTER(FALSE)); - purple_conversation_present(convo); + /* Until purple_conversation_present does something that + * one would expect in Pidgin, this call produces buggy + * behavior both for the /join and auto-join cases. */ + /* purple_conversation_present(convo); */ return; }
--- a/libpurple/protocols/jabber/google.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/jabber/google.c Mon Oct 01 17:51:20 2007 +0000 @@ -64,8 +64,7 @@ message = xmlnode_get_child(child, "mail-thread-info"); if (count == 0 || !message) { - if (count > 0) - purple_notify_emails(js->gc, count, FALSE, NULL, NULL, (const char**) default_tos, NULL, NULL, NULL); + purple_notify_emails(js->gc, count, FALSE, NULL, NULL, (const char**) default_tos, NULL, NULL, NULL); g_free(default_tos[0]); return; }
--- a/libpurple/protocols/jabber/jutil.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/jabber/jutil.h Mon Oct 01 17:51:20 2007 +0000 @@ -22,6 +22,8 @@ #ifndef _PURPLE_JABBER_JUTIL_H_ #define _PURPLE_JABBER_JUTIL_H_ +#include "account.h" + typedef struct _JabberID { char *node; char *domain;
--- a/libpurple/protocols/jabber/libxmpp.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon Oct 01 17:51:20 2007 +0000 @@ -113,8 +113,8 @@ jabber_prpl_send_raw, /* send_raw */ jabber_roomlist_room_serialize, /* roomlist_room_serialize */ jabber_unregister_account, /* unregister_user */ - jabber_attention_types, /* attention_types */ - jabber_send_attention, /* send_attention */ + jabber_send_attention, /* send_attention */ + jabber_attention_types, /* attention_types */ /* padding */ NULL
--- a/libpurple/protocols/jabber/message.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/jabber/message.c Mon Oct 01 17:51:20 2007 +0000 @@ -41,7 +41,10 @@ g_free(jm->body); g_free(jm->xhtml); g_free(jm->password); + g_free(jm->error); + g_free(jm->thread_id); g_list_free(jm->etc); + g_list_free(jm->eventitems); g_free(jm); }
--- a/libpurple/protocols/msn/Makefile.am Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Mon Oct 01 17:51:20 2007 +0000 @@ -1,4 +1,6 @@ EXTRA_DIST = \ + directconn.c \ + directconn.h \ Makefile.mingw pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) @@ -8,10 +10,10 @@ cmdproc.h \ command.c \ command.h \ + contact.c\ + contact.h\ dialog.c \ dialog.h \ - directconn.c \ - directconn.h \ error.c \ error.h \ group.c \ @@ -30,6 +32,8 @@ notification.h \ object.c \ object.h \ + oim.c\ + oim.h\ page.c \ page.h \ servconn.c \ @@ -46,6 +50,8 @@ slpmsg.h \ slpsession.c \ slpsession.h \ + soap.c\ + soap.h\ state.c \ state.h \ switchboard.c \ @@ -60,8 +66,8 @@ user.h \ userlist.c \ userlist.h \ - msn-utils.c \ - msn-utils.h + msnutils.c \ + msnutils.h AM_CFLAGS = $(st)
--- a/libpurple/protocols/msn/Makefile.mingw Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Mon Oct 01 17:51:20 2007 +0000 @@ -39,6 +39,7 @@ ## C_SRC = cmdproc.c \ command.c \ + contact.c\ dialog.c \ directconn.c \ error.c \ @@ -50,6 +51,7 @@ nexus.c \ notification.c \ object.c \ + oim.c\ page.c \ servconn.c \ session.c \ @@ -58,6 +60,7 @@ slplink.c \ slpmsg.c \ slpsession.c \ + soap.c\ state.c \ switchboard.c \ sync.c \ @@ -65,7 +68,7 @@ transaction.c \ user.c \ userlist.c \ - msn-utils.c + msnutils.c OBJECTS = $(C_SRC:%.c=%.o)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/README Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,55 @@ +MSNP14 Implementation +by Ma Yuan<mayuan2006@gmail.com> + +1. Introduction +------------- + +MSNP14 Protocol, proposed by Windows Live Messenger, is new, and there is no available implementation except the official one on Windows Platform. + +It has introduced many new features attractable to many users, such as: +* Offline Instant Message + You can send the offline Message to the offline User, + The message will be posted to that user the next time when he is online. + +* Communicate with Yahoo User + U can chat with the Yahoo User in MSN, That's Fantastic! Till now , + you can send text/Nudge to Yahoo User. + +* Windows Live ID authentition + WLM use the Window Live ID Authentication process,Known as Passport 3.0, + The procedure is totally different to the previous Passport 2.0 + +* Video/Audio Conversation + U can communicate with other's via Video/Audio. +(Though very interesting, not implemented in this version) + +2.New Features Added +----------------- + +Till now, This project has implemented the following Feature: +* Windows Live ID authentication. + +* Offline Instant Message +Now can send and receive the Offline Instant Message to MSN user and Yahoo User. + +*contact management +Can add/delete Contact +Can add/delete Group + +* Communicate with Yahoo User +Can send/receive Message/Nudge to Yahoo User. + +*. Changes to made to fit MSNP14 Protocol + +3. Reference +------------- + +The very useful sites of MSN Protocol: +MSNpiki site: +reverse engineer of MSN Protocol.up to dated. +http://msnpiki.msnfanatic.com/index.php/MSN_Protocol_Version_13 + +hypothetic site: +old MSN Protocol Introduction,but very useful for basic idea of MSN protocol +http://www.hypothetic.org/docs/msn/index.php +
--- a/libpurple/protocols/msn/cmdproc.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Mon Oct 01 17:51:20 2007 +0000 @@ -258,8 +258,10 @@ trans = msn_history_find(cmdproc->history, cmd->trId); if (trans != NULL) - if (trans->timer) + if (trans->timer) { purple_timeout_remove(trans->timer); + trans->timer = 0; + } if (g_ascii_isdigit(cmd->command[0])) {
--- a/libpurple/protocols/msn/command.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/command.c Mon Oct 01 17:51:20 2007 +0000 @@ -36,6 +36,50 @@ return TRUE; } +/* + * check the command is the command with payload content + * if it is return TRUE + * else return FALSE + */ +static gboolean +msn_check_payload_cmd(char *str) +{ + if( (!strcmp(str,"ADL")) || + (!strcmp(str,"GCF")) || + (!strcmp(str,"SG")) || + (!strcmp(str,"MSG")) || + (!strcmp(str,"RML")) || + (!strcmp(str,"UBX")) || + (!strcmp(str,"UBN")) || + (!strcmp(str,"UUM")) || + (!strcmp(str,"UBM")) || + (!strcmp(str,"FQY")) || + (!strcmp(str,"UUN")) || + (!strcmp(str,"UUX")) || + (is_num(str))){ + return TRUE; + } + + return FALSE; +} + +/* + * set command Payload length + */ +static void +msn_set_payload_len(MsnCommand *cmd) +{ + char *param; + int len = 0; + + if (msn_check_payload_cmd(cmd->command) && (cmd->param_count > 0)){ + param = cmd->params[cmd->param_count - 1]; + len = is_num(param) ? atoi(param) : 0; + } + + cmd->payload_len = len; +} + MsnCommand * msn_command_from_string(const char *string) { @@ -70,7 +114,13 @@ cmd->trId = is_num(param) ? atoi(param) : 0; } else + { cmd->trId = 0; + } + + /*add payload Length checking*/ + msn_set_payload_len(cmd); + purple_debug_info("MSNP14","get payload len:%d\n",cmd->payload_len); msn_command_ref(cmd);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.c Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,1897 @@ +/** + * @file contact.c + * get MSN contacts via SOAP request + * created by MaYuan<mayuan2006@gmail.com> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "msn.h" +#include "contact.h" +#include "xmlnode.h" +#include "group.h" + +const char *MsnSoapPartnerScenarioText[] = +{ + "Initial", + "ContactSave", + "MessengerPendingList", + "ContactMsgrAPI", + "BlockUnblock" +}; + +const char *MsnMemberRole[] = +{ + "Forward", + "Allow", + "Block", + "Reverse", + "Pending" +}; + +/* new a contact */ +MsnContact * +msn_contact_new(MsnSession *session) +{ + MsnContact *contact; + + contact = g_new0(MsnContact, 1); + contact->session = session; + contact->soapconn = msn_soap_new(session,contact,1); + + return contact; +} + +/* destroy the contact */ +void +msn_contact_destroy(MsnContact *contact) +{ + msn_soap_destroy(contact->soapconn); + g_free(contact); +} + +MsnCallbackState * +msn_callback_state_new(void) +{ + return g_new0(MsnCallbackState, 1); +} + +void +msn_callback_state_free(MsnCallbackState *state) +{ + if (state == NULL) + return; + + g_free(state->who); + g_free(state->uid); + g_free(state->old_group_name); + g_free(state->new_group_name); + g_free(state->guid); + + g_free(state); +} + +void +msn_callback_state_set_who(MsnCallbackState *state, const gchar *who) +{ + gchar *new_str = NULL; + + g_return_if_fail(state != NULL); + + if (who != NULL) + new_str = g_strdup(who); + + g_free(state->who); + state->who = new_str; +} + +void +msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid) +{ + gchar *new_str = NULL; + + g_return_if_fail(state != NULL); + + if (uid != NULL) + new_str = g_strdup(uid); + + g_free(state->uid); + state->uid = new_str; +} + +void +msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name) +{ + gchar *new_str = NULL; + + g_return_if_fail(state != NULL); + + if (old_group_name != NULL) + new_str = g_strdup(old_group_name); + + g_free(state->old_group_name); + state->old_group_name = new_str; +} + +void +msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name) +{ + gchar *new_str = NULL; + + g_return_if_fail(state != NULL); + + if (new_group_name != NULL) + new_str = g_strdup(new_group_name); + + g_free(state->new_group_name); + state->new_group_name = new_str; +} + +void +msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid) +{ + gchar *new_str = NULL; + + g_return_if_fail(state != NULL); + + if (guid != NULL) + new_str = g_strdup(guid); + + g_free(state->guid); + state->guid = new_str; +} + + +void +msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id) +{ + g_return_if_fail(state != NULL); + + state->list_id = list_id; +} + +void +msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action) +{ + g_return_if_fail(state != NULL); + + state->action |= action; +} + +/*contact SOAP server login error*/ +static void +msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) +{ + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + + msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server")); +} + +/*msn contact SOAP server connect process*/ +static gboolean +msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) +{ + MsnSession * session; + MsnContact *contact; + + contact = soapconn->parent; + g_return_val_if_fail(contact != NULL, TRUE); + + session = contact->session; + g_return_val_if_fail(session != NULL, FALSE); + + /*login ok!We can retrieve the contact list*/ +// msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + return TRUE; +} + +/*get MSN member role utility*/ +static MsnListId +msn_get_memberrole(char *role) +{ + g_return_val_if_fail(role != NULL, 0); + + if (!strcmp(role,"Allow")) { + return MSN_LIST_AL; + } else if (!strcmp(role,"Block")) { + return MSN_LIST_BL; + } else if (!strcmp(role,"Reverse")) { + return MSN_LIST_RL; + } else if (!strcmp(role,"Pending")) { + return MSN_LIST_PL; + } + return 0; +} + +/*get User Type*/ +static int +msn_get_user_type(char *type) +{ + g_return_val_if_fail(type != NULL, 0); + + if (!strcmp(type,"Regular")) { + return MSN_USER_TYPE_PASSPORT; + } + if (!strcmp(type,"Live")) { + return MSN_USER_TYPE_PASSPORT; + } + if (!strcmp(type,"LivePending")) { + return MSN_USER_TYPE_PASSPORT; + } + + return MSN_USER_TYPE_UNKNOWN; +} + +/* Create the AddressBook in the server, if we don't have one */ +static gboolean +msn_create_address_cb(MsnSoapConn *soapconn) +{ + MsnContact *contact; + + if (soapconn->body == NULL) + return TRUE; + + contact = soapconn->parent; + g_return_val_if_fail(contact != NULL, TRUE); + + purple_debug_info("MSN AddressBook", "Address Book successfully created!\n"); + msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); + +// msn_soap_free_read_buf(soapconn); + return TRUE; +} + +static void +msn_create_address_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN AddressBook","AddressBookAdd written\n"); + soapconn->read_cb = msn_create_address_cb; + + return; +} + +static void +msn_create_address_book(MsnContact * contact) +{ + MsnSoapReq *soap_request; + gchar *body; + + g_return_if_fail(contact != NULL); + 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("MSN AddressBook","Creating an Address Book.\n"); + + body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport); + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION, + body, + NULL, + msn_create_address_cb, + msn_create_address_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn, soap_request); + + g_free(body); + + return; +} + +/*parse contact list*/ +static void +msn_parse_contact_list(MsnContact * contact) +{ + MsnSession * session; + MsnListOp list_op = 0; + MsnListId list; + char * passport, *typedata; + xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; + xmlnode *node, *body, *response, *result, *services; + xmlnode *service, *memberships, *info, *handle, *handletype; + xmlnode *membershipnode, *members, *member, *passportNode; + + session = contact->session; + node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); + + if (node == NULL) { + purple_debug_error("MSNCL","Unable to parse SOAP data!\n"); + return; + } + + purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len); + + purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node, + node->name ? node->name : "(null)", + (node->child && node->child->name) ? node->child->name : "(null)", + (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); + + body = xmlnode_get_child(node, "Body"); + + if (body == NULL) { + purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n"); + xmlnode_free(node); + return; + } + purple_debug_info("MSNCL","Body @ %p: Name: '%s'\n",body,body->name); + + /* Did we receive a <Fault> ? */ + if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { + purple_debug_info("MSNCL","Fault received from SOAP server!\n"); + + if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { + gchar * faultstring = xmlnode_get_data(faultstringnode); + purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)"); + g_free(faultstring); + } + if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { + purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name); + + if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { + purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name); + + if (errorcode->child != NULL) { + gchar *errorcodestring = xmlnode_get_data(errorcode); + purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); + + if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + xmlnode_free(node); + g_free(errorcodestring); + msn_create_address_book(contact); + return; + } + g_free(errorcodestring); + } + } + } + xmlnode_free(node); + msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + return; + } + + response = xmlnode_get_child(body,"FindMembershipResponse"); + + if (response == NULL) { + /* we may get a response if our cache data is too old: + * + * <faultstring>Need to do full sync. Can't sync deltas Client + * has too old a copy for us to do a delta sync</faultstring> + */ + xmlnode_free(node); + msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + return; + } + purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name); + + result = xmlnode_get_child(response,"FindMembershipResult"); + if (result == NULL) { + purple_debug_warning("MSNCL","Received No Update!\n"); + xmlnode_free(node); + return; + } + purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name); + + if ( (services = xmlnode_get_child(result,"Services")) == NULL) { + purple_debug_misc("MSNCL","No <Services> received.\n"); + xmlnode_free(node); + return; + } + + purple_debug_info("MSNCL","Services @ %p\n",services); + + for (service = xmlnode_get_child(services, "Service"); service; + service = xmlnode_get_next_twin(service)) { + purple_debug_info("MSNCL","Service @ %p\n",service); + + if ( (info = xmlnode_get_child(service,"Info")) == NULL ) { + purple_debug_error("MSNCL","Error getting 'Info' child node\n"); + continue; + } + if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) { + purple_debug_error("MSNCL","Error getting 'Handle' child node\n"); + continue; + } + if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) { + purple_debug_error("MSNCL","Error getting 'Type' child node\n"); + continue; + } + + if ( (typedata = xmlnode_get_data(handletype)) == NULL) { + purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n"); + continue; + } + + purple_debug_info("MSNCL","processing '%s' Service\n", typedata); + + if ( !g_strcasecmp(typedata, "Profile") ) { + /* Process Windows Live 'Messenger Roaming Identity' */ + g_free(typedata); + continue; + } + + if ( !g_strcasecmp(typedata, "Messenger") ) { + char *LastChangeStr = NULL; + xmlnode *LastChangeNode; + + /*Last Change Node*/ + if ((LastChangeNode = xmlnode_get_child(service, "LastChange"))) + LastChangeStr = xmlnode_get_data(LastChangeNode); + purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)"); + purple_account_set_string(session->account, "CLLastChange", LastChangeStr); + g_free(LastChangeStr); + + memberships = xmlnode_get_child(service,"Memberships"); + if (memberships == NULL) { + purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n"); + g_free(typedata); + xmlnode_free(node); + return; + } + purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name); + for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; + membershipnode = xmlnode_get_next_twin(membershipnode)){ + xmlnode *roleNode; + char *role = NULL; + list = 0; + + if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) { + role = xmlnode_get_data(roleNode); + list = msn_get_memberrole(role); + } + list_op = 1 << list; + + purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op); + + g_free(role); + + members = xmlnode_get_child(membershipnode, "Members"); + for (member = xmlnode_get_child(members, "Member"); member; + member = xmlnode_get_next_twin(member)){ + MsnUser *user = NULL; + xmlnode *typeNode, *membershipIdNode = NULL; + gchar *type, *membershipId = NULL; + const char *member_type = xmlnode_get_attrib(member, "type"); + + if (!member_type) { + purple_debug_error("msn", "No Member Type specified for Member.\n"); + continue; + } + + if(!g_strcasecmp(member_type, "PassportMember") ) { + passport = type = NULL; + if ((passportNode = xmlnode_get_child(member, "PassportName"))) + passport = xmlnode_get_data(passportNode); + if ((typeNode = xmlnode_get_child(member, "Type"))) + type = xmlnode_get_data(typeNode); + purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)"); + /* Why do we even bother parsing it just to free it??? */ + g_free(type); + + user = msn_userlist_find_add_user(session->userlist,passport,NULL); + g_free(passport); + + membershipIdNode = xmlnode_get_child(member,"MembershipId"); + if (membershipIdNode != NULL) { + membershipId = xmlnode_get_data(membershipIdNode); + if (membershipId != NULL) { + user->membership_id[list] = atoi(membershipId); + g_free(membershipId); + } + } + + msn_got_lst_user(session, user, list_op, NULL); + } + else if (!g_strcasecmp(member_type, "PhoneMember")) { + purple_debug_info("msn", "Recieved Phone Member; ignoring.\n"); + } + else if (!g_strcasecmp(member_type, "EmailMember")) { + xmlnode *emailNode; + passport = NULL; + + if ((emailNode = xmlnode_get_child(member, "Email"))) + passport = xmlnode_get_data(emailNode); + purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op); + + user = msn_userlist_find_add_user(session->userlist, passport, NULL); + g_free(passport); + + membershipIdNode = xmlnode_get_child(member,"MembershipId"); + if (membershipIdNode != NULL) { + membershipId = xmlnode_get_data(membershipIdNode); + if (membershipId != NULL) { + user->membership_id[list] = atoi(membershipId); + g_free(membershipId); + } + } + + msn_got_lst_user(session, user, list_op, NULL); + } else { + purple_debug_info("msn", "Unknown Member type: %s\n", member_type); + } + } + } + g_free(typedata); /* Free 'Type' node data after processing 'Messenger' Service */ + } + } + + xmlnode_free(node); /* Free the whole XML tree */ +} + +static gboolean +msn_get_contact_list_cb(MsnSoapConn *soapconn) +{ + MsnContact *contact; + MsnSession *session; + const char *abLastChange; + const char *dynamicItemLastChange; + gchar *partner_scenario; + + if (soapconn->body == NULL) + return TRUE; + + purple_debug_misc("MSNCL","Got the contact list!\n"); + + contact = soapconn->parent; + g_return_val_if_fail(contact != NULL, TRUE); + session = soapconn->session; + g_return_val_if_fail(session != NULL, FALSE); + g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); + + partner_scenario = soapconn->data_cb; + + msn_parse_contact_list(contact); + /*free the read buffer*/ + msn_soap_free_read_buf(soapconn); + + abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); + dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL); + + if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) { + +#ifdef MSN_PARTIAL_LISTS + /* XXX: this should be enabled when we can correctly do partial + syncs with the server. Currently we need to retrieve the whole + list to detect sync issues */ + msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); +#else + msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); +#endif + } else { + msn_soap_free_read_buf(soapconn); + } + + return TRUE; +} + +static void +msn_get_contact_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n"); + soapconn->read_cb = msn_get_contact_list_cb; +} + +/* SOAP get contact list*/ +void +msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time) +{ + MsnSoapReq *soap_request; + gchar *body; + gchar *update_str = NULL; + const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; + + purple_debug_misc("MSNCL","Getting Contact List.\n"); + + if ( update_time != NULL ) { + purple_debug_info("MSNCL","Last update time: %s\n",update_time); + update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time); + } + + body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : ""); + g_free(update_str); + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_GET_CONTACT_POST_URL, + MSN_GET_CONTACT_SOAP_ACTION, + body, + (gpointer) partner_scenario_str, + msn_get_contact_list_cb, + msn_get_contact_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + g_free(body); +} + +static void +msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node) +{ + MsnSession *session = contact->session; + xmlnode *group; + + purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n"); + + for(group = xmlnode_get_child(node, "Group"); group; + group = xmlnode_get_next_twin(group)){ + xmlnode *groupId, *groupInfo, *groupname; + char *group_id = NULL, *group_name = NULL; + + if ((groupId = xmlnode_get_child(group, "groupId"))) + group_id = xmlnode_get_data(groupId); + if ((groupInfo = xmlnode_get_child(group, "groupInfo")) && (groupname = xmlnode_get_child(groupInfo, "name"))) + group_name = xmlnode_get_data(groupname); + + msn_group_new(session->userlist, group_id, group_name); + + if (group_id == NULL){ + /* Group of ungroupped buddies */ + g_free(group_name); + continue; + } + + purple_debug_info("MsnAB","group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)"); + if ((purple_find_group(group_name)) == NULL){ + PurpleGroup *g = purple_group_new(group_name); + purple_blist_add_group(g, NULL); + } + g_free(group_id); + g_free(group_name); + } +} + +static void +msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node) +{ + MsnSession *session = contact->session; + xmlnode *contactNode; + char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL; + + for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; + contactNode = xmlnode_get_next_twin(contactNode)) { + xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds; + MsnUser *user; + MsnUserType usertype; + + if (!(contactId = xmlnode_get_child(contactNode,"contactId")) + || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo")) + || !(contactType = xmlnode_get_child(contactInfo, "contactType"))) + continue; + + g_free(passport); + g_free(Name); + g_free(uid); + g_free(type); + passport = Name = uid = type = NULL; + + uid = xmlnode_get_data(contactId); + type = xmlnode_get_data(contactType); + + /*setup the Display Name*/ + if (type && !strcmp(type, "Me")){ + char *friendly = NULL; + if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) + friendly = xmlnode_get_data(displayName); + purple_connection_set_display_name(session->account->gc, friendly ? purple_url_decode(friendly) : NULL); + g_free(friendly); + continue; /* Not adding own account as buddy to buddylist */ + } + + usertype = msn_get_user_type(type); + passportName = xmlnode_get_child(contactInfo, "passportName"); + if (passportName == NULL) { + xmlnode *emailsNode, *contactEmailNode, *emailNode; + xmlnode *messengerEnabledNode; + char *msnEnabled; + + /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/ + /*Yahoo User?*/ + emailsNode = xmlnode_get_child(contactInfo, "emails"); + if (emailsNode == NULL) { + /*TODO: need to support the Mobile type*/ + continue; + } + for(contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode; + contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){ + if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) { + /* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */ + break; + } + + msnEnabled = xmlnode_get_data(messengerEnabledNode); + + if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) { + g_free(passport); + passport = xmlnode_get_data(emailNode); + } + + if(msnEnabled && !strcmp(msnEnabled, "true")) { + /*Messenger enabled, Get the Passport*/ + purple_debug_info("MsnAB", "Yahoo User %s\n", passport ? passport : "(null)"); + usertype = MSN_USER_TYPE_YAHOO; + g_free(msnEnabled); + break; + } else { + /*TODO maybe we can just ignore it in Purple?*/ + purple_debug_info("MSNAB", "Other type user\n"); + } + + g_free(msnEnabled); + } + } else { + passport = xmlnode_get_data(passportName); + } + + if (passport == NULL) + continue; + + if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) + Name = xmlnode_get_data(displayName); + else + Name = g_strdup(passport); + + purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n", + passport, uid ? uid : "(null)", Name ? Name : "(null)"); + + user = msn_userlist_find_add_user(session->userlist, passport, Name); + msn_user_set_uid(user, uid); + msn_user_set_type(user, usertype); + + groupIds = xmlnode_get_child(contactInfo, "groupIds"); + if (groupIds) { + for (guid = xmlnode_get_child(groupIds, "guid"); guid; + guid = xmlnode_get_next_twin(guid)){ + char *group_id = xmlnode_get_data(guid); + msn_user_add_group_id(user, group_id); + purple_debug_misc("MsnAB", "guid:%s\n", group_id ? group_id : "(null)"); + g_free(group_id); + } + } else { + purple_debug_info("msn", "User not in any groups, adding to default group.\n"); + /*not in any group,Then set default group*/ + msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID); + } + + msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL); + } + + g_free(passport); + g_free(Name); + g_free(uid); + g_free(type); +} + +static gboolean +msn_parse_addressbook(MsnContact * contact) +{ + MsnSession *session; + xmlnode * node,*body,*response,*result; + xmlnode *groups; + xmlnode *contacts; + xmlnode *abNode; + xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; + + session = contact->session; + + node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); + if ( node == NULL ) { + purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len); + return FALSE; + } + + purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len); + + purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n", node, + node->name ? node->name : "(null)", + (node->child && node->child->name) ? node->child->name : "(null)", + (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); + + body = xmlnode_get_child(node,"Body"); + purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name); + + /* TODO: This appears to be used in a number of places and should be de-duplicated */ + if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { + purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n"); + + if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { + gchar *faultstring = xmlnode_get_data(faultstringnode); + purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)"); + g_free(faultstring); + } + if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { + purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name); + + if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { + gchar *errorcodestring; + purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name); + + errorcodestring = xmlnode_get_data(errorcode); + purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); + + if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + g_free(errorcodestring); + xmlnode_free(node); + return TRUE; + } + g_free(errorcodestring); + } + } + xmlnode_free(node); + return FALSE; + } + + + response = xmlnode_get_child(body,"ABFindAllResponse"); + + if (response == NULL) { + xmlnode_free(node); + return FALSE; + } + + purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name); + result = xmlnode_get_child(response,"ABFindAllResult"); + if(result == NULL){ + purple_debug_misc("MSNAB","receive no address book update\n"); + xmlnode_free(node); + return TRUE; + } + purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name); + + /*Process Group List*/ + groups = xmlnode_get_child(result,"groups"); + if (groups != NULL) { + msn_parse_addressbook_groups(contact, groups); + } + + /*add a default No group to set up the no group Membership*/ + msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID, + MSN_INDIVIDUALS_GROUP_NAME); + purple_debug_misc("MsnAB","group_id:%s name:%s\n", + MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); + if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){ + PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME); + purple_blist_add_group(g, NULL); + } + + /*add a default No group to set up the no group Membership*/ + msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); + purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); + if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){ + PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME); + purple_blist_add_group(g, NULL); + } + + /*Process contact List*/ + purple_debug_info("MSNAB","process contact list...\n"); + contacts =xmlnode_get_child(result,"contacts"); + if (contacts != NULL) { + msn_parse_addressbook_contacts(contact, contacts); + } + + abNode =xmlnode_get_child(result,"ab"); + if(abNode != NULL){ + xmlnode *node2; + char *tmp = NULL; + + if ((node2 = xmlnode_get_child(abNode, "lastChange"))) + tmp = xmlnode_get_data(node2); + purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); + purple_account_set_string(session->account, "ablastChange", tmp); + + g_free(tmp); tmp = NULL; + if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged"))) + tmp = xmlnode_get_data(node2); + purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)"); + purple_account_set_string(session->account, "DynamicItemLastChanged", tmp); + g_free(tmp); + } + + xmlnode_free(node); + msn_soap_free_read_buf(contact->soapconn); + return TRUE; +} + +static gboolean +msn_get_address_cb(MsnSoapConn *soapconn) +{ + MsnContact *contact; + MsnSession *session; + + if (soapconn->body == NULL) + return TRUE; + + contact = soapconn->parent; + g_return_val_if_fail(contact != NULL, TRUE); + session = soapconn->session; + g_return_val_if_fail(session != NULL, FALSE); + + purple_debug_misc("MSN AddressBook", "Got the Address Book!\n"); + + if ( msn_parse_addressbook(contact) ) { + //msn_soap_free_read_buf(soapconn); + + if (!session->logged_in) { + msn_send_privacy(session->account->gc); + msn_notification_dump_contact(session); + } + + /*free the read buffer*/ + msn_soap_free_read_buf(soapconn); + return TRUE; + } else { + /* This is making us loop infinitely when we fail to parse the address book, + disable for now (we should re-enable when we send timestamps) + */ + /* + msn_get_address_book(contact, NULL, NULL); + */ + msn_session_disconnect(session); + purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book")); + return FALSE; + } +} + +/**/ +static void +msn_address_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n"); + soapconn->read_cb = msn_get_address_cb; +} + +/*get the address book*/ +void +msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange) +{ + MsnSoapReq *soap_request; + char *body; + char *update_str = NULL; + + purple_debug_misc("MSN AddressBook","Getting Address Book\n"); + + /*build SOAP and POST it*/ + if (dynamicItemLastChange != NULL) + update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange); + else if (LastChanged != NULL) + update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); + + + body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : ""); + g_free(update_str); + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION, + body, + NULL, + msn_get_address_cb, + msn_address_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + g_free(body); +} + +static gboolean +msn_add_contact_read_cb(MsnSoapConn *soapconn) +{ + MsnCallbackState *state = NULL; + MsnUserList *userlist; + MsnUser *user; + + g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + + state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + userlist = soapconn->session->userlist; + + purple_debug_info("MSNCL","Contact added successfully\n"); + + // the code this block is replacing didn't send ADL for yahoo contacts, + // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts + + if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { + + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } + msn_notification_send_fqy(soapconn->session, state->who); + + user = msn_userlist_find_add_user(userlist, state->who, state->who); + msn_user_add_group_id(user, state->guid); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) { + msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL); + } else { + msn_soap_free_read_buf(soapconn); + } + + msn_callback_state_free(state); + + return TRUE; +} + +static void +msn_add_contact_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSNCL","Add contact request written\n"); + soapconn->read_cb = msn_add_contact_read_cb; +} + +/* add a Contact in MSN_INDIVIDUALS_GROUP */ +void +msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport) +{ + MsnSoapReq *soap_request; + gchar *body = NULL; + gchar *contact_xml = NULL; + + g_return_if_fail(passport != NULL); +/* gchar *escaped_displayname; + + + if (displayname != NULL) { + escaped_displayname = g_markup_decode_text(displayname, -1); + } else { + escaped_displayname = passport; + } + contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport); +*/ + purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport); + +// if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) { + contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); +// } + body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml); + + g_free(contact_xml); + + /*build SOAP and POST it*/ + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_CONTACT_ADD_SOAP_ACTION, + body, + state, + msn_add_contact_read_cb, + msn_add_contact_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + + g_free(body); +} + +static gboolean +msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn) +{ + MsnCallbackState *state; + MsnUserList *userlist; + + g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + + userlist = soapconn->session->userlist; + + state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) { + purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); + } else { + purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + } + + if (state->action & MSN_ADD_BUDDY) { + MsnUser *user = msn_userlist_find_user(userlist, state->who); + + if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { + + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } + msn_notification_send_fqy(soapconn->session, state->who); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) { + msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL); + msn_callback_state_free(state); + return TRUE; + } + } + + if (state->action & MSN_MOVE_BUDDY) { + msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name); + } else { + msn_callback_state_free(state); + msn_soap_free_read_buf(soapconn); + } + return TRUE; +} + +static void +msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSNCL","Add contact to group request sent!\n"); + soapconn->read_cb = msn_add_contact_to_group_read_cb; +} + +void +msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, + const char *passport, const char *groupId) +{ + MsnSoapReq *soap_request; + MsnUserList *userlist; + MsnUser *user; + gchar *body = NULL, *contact_xml; + + g_return_if_fail(passport != NULL); + g_return_if_fail(groupId != 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; + + 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) { + msn_add_contact(contact, state, passport); + return; + } + + if (state->action & MSN_MOVE_BUDDY) { + msn_user_add_group_id(user, groupId); + msn_del_contact_from_group(contact, passport, state->old_group_name); + } else { + msn_callback_state_free(state); + } + + return; + } + + + 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("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport); + } + + if (user->uid != NULL) { + contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); + } else { + contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); + } + + body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml); + g_free(contact_xml); + + /*build SOAP and POST it*/ + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_ADD_CONTACT_GROUP_SOAP_ACTION, + body, + state, + msn_add_contact_to_group_read_cb, + msn_add_contact_to_group_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + + g_free(body); +} + + + +static gboolean +msn_delete_contact_read_cb(MsnSoapConn *soapconn) +{ + MsnUser *user; + MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; + MsnUserList *userlist; + + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + + userlist = soapconn->session->userlist; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + purple_debug_info("MSNCL","Delete contact successful\n"); + + user = msn_userlist_find_user_with_id(userlist, state->uid); + if (user != NULL) { + msn_userlist_remove_user(userlist, user); + } + + msn_callback_state_free(state); + msn_soap_free_read_buf(soapconn); + + return TRUE; +} + +static void +msn_delete_contact_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSNCL","Delete contact request written\n"); + soapconn->read_cb = msn_delete_contact_read_cb; +} + +/*delete a Contact*/ +void +msn_delete_contact(MsnContact *contact, const char *contactId) +{ + gchar *body = NULL; + gchar *contact_id_xml = NULL ; + MsnSoapReq *soap_request; + MsnCallbackState *state; + + g_return_if_fail(contactId != NULL); + contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId); + + state = msn_callback_state_new(); + msn_callback_state_set_uid(state, contactId); + + /* build SOAP request */ + purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId); + body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml); + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_CONTACT_DEL_SOAP_ACTION, + body, + state, + msn_delete_contact_read_cb, + msn_delete_contact_written_cb, + msn_contact_connect_init); + + g_free(contact_id_xml); + + /* POST the SOAP request */ + msn_soap_post(contact->soapconn, soap_request); + + g_free(body); +} + +static gboolean +msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn) +{ + MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) { + purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); + } else { + purple_debug_info("MSN CL", "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); + msn_soap_free_read_buf(soapconn); + + return TRUE; +} + +static void +msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN CL","Del contact from group request sent!\n"); + soapconn->read_cb = msn_del_contact_from_group_read_cb; +} + +void +msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name) +{ + MsnSoapReq *soap_request; + MsnUserList * userlist; + MsnUser *user; + MsnCallbackState *state; + gchar *body = NULL, *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("MSN CL", "Deleting user %s from group %s\n", passport, group_name); + } else { + purple_debug_warning("MSN CL", "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("MSN CL", "Unable to retrieve user from passport %s!\n", passport); + return; + } + + if ( !strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) { + msn_user_remove_group_id(user, groupId); + return; + } + + state = msn_callback_state_new(); + msn_callback_state_set_who(state, passport); + msn_callback_state_set_guid(state, groupId); + msn_callback_state_set_old_group_name(state, group_name); + + contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); + body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId); + g_free(contact_id_xml); + + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_CONTACT_DEL_GROUP_SOAP_ACTION, + body, + state, + msn_del_contact_from_group_read_cb, + msn_del_contact_from_group_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + + g_free(body); +} + + +static gboolean +msn_update_contact_read_cb(MsnSoapConn *soapconn) +{ + if (soapconn->body == NULL) + return TRUE; + + purple_debug_info("MSN CL","Contact updated successfully\n"); + + return TRUE; +} + +static void +msn_update_contact_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN CL","Update contact information request sent\n"); + soapconn->read_cb = msn_update_contact_read_cb; +} + +/* Update a contact's nickname */ + +void +msn_update_contact(MsnContact *contact, const char* nickname) +{ + MsnSoapReq *soap_request; + gchar *body, *escaped_nickname; + + /* I'm not sure this is right, but if it isn't, the rest of this function will need to be fixed */ + g_return_if_fail(nickname != NULL); + + purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname); + + escaped_nickname = g_markup_escape_text(nickname, -1); + + body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname); + + g_free(escaped_nickname); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_CONTACT_UPDATE_SOAP_ACTION, + body, + NULL, + msn_update_contact_read_cb, + msn_update_contact_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn, soap_request); + + g_free(body); +} + + +static gboolean +msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn) +{ + MsnCallbackState *state = NULL; + + g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); + + state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + + if (state->list_id == MSN_LIST_PL) { + msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL); + return TRUE; + } + + if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE); + msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); + msn_callback_state_free(state); + return TRUE; + } + + if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE); + msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL); + msn_callback_state_free(state); + return TRUE; + } + + msn_callback_state_free(state); + msn_soap_free_read_buf(soapconn); + + return TRUE; +} + +static void +msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n"); + soapconn->read_cb = msn_del_contact_from_list_read_cb; +} + +void +msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, + const gchar *passport, const MsnListId list) +{ + MsnSoapReq *soap_request; + gchar *body = NULL, *member = NULL; + MsnSoapPartnerScenario partner_scenario; + MsnUser *user; + + g_return_if_fail(contact != NULL); + g_return_if_fail(passport != NULL); + g_return_if_fail(list < 5); + + purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); + + if (state == NULL) { + state = msn_callback_state_new(); + } + msn_callback_state_set_list_id(state, list); + msn_callback_state_set_who(state, passport); + + if (list == MSN_LIST_PL) { + g_return_if_fail(contact->session != NULL); + g_return_if_fail(contact->session->userlist != NULL); + + user = msn_userlist_find_user(contact->session->userlist, passport); + + partner_scenario = MSN_PS_CONTACT_API; + member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]); + } else { + /* list == MSN_LIST_AL || list == MSN_LIST_BL */ + partner_scenario = MSN_PS_BLOCK_UNBLOCK; + + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport); + } + + body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE, + MsnSoapPartnerScenarioText[partner_scenario], + MsnMemberRole[list], + member); + g_free(member); + + soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, + MSN_SHARE_POST_URL, + MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION, + body, + state, + msn_del_contact_from_list_read_cb, + msn_del_contact_from_list_written_cb, + msn_contact_connect_init); + + msn_soap_post(contact->soapconn,soap_request); + + g_free(body); +} + +static gboolean +msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn) +{ + MsnCallbackState *state = NULL; + + g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); + + state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + 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 && (state->action & MSN_DENIED_BUDDY) ) { + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); + + msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); + return TRUE; + } + + if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_add(soapconn->session->account, state->who, TRUE); + } else if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_add(soapconn->session->account, state->who, TRUE); + } + + msn_callback_state_free(state); + msn_soap_free_read_buf(soapconn); + return TRUE; +} + + +static void +msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n"); + soapconn->read_cb = msn_add_contact_to_list_read_cb; +} + +void +msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, + const gchar *passport, const MsnListId list) +{ + MsnSoapReq *soap_request; + gchar *body = NULL, *member = NULL; + MsnSoapPartnerScenario partner_scenario; + + g_return_if_fail(contact != NULL); + g_return_if_fail(passport != NULL); + g_return_if_fail(list < 5); + + purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); + + if (state == NULL) { + state = msn_callback_state_new(); + } + msn_callback_state_set_list_id(state, list); + msn_callback_state_set_who(state, passport); + + partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK; + + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport); + + body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, + MsnSoapPartnerScenarioText[partner_scenario], + MsnMemberRole[list], + member); + + g_free(member); + + soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, + MSN_SHARE_POST_URL, + MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION, + body, + state, + msn_add_contact_to_list_read_cb, + msn_add_contact_to_list_written_cb, + msn_contact_connect_init); + + msn_soap_post(contact->soapconn, soap_request); + + g_free(body); +} + + +#if 0 +static gboolean +msn_gleams_read_cb(MsnSoapConn * soapconn) +{ + purple_debug_info("MSN CL","Gleams read done\n"); + return TRUE; +} + +static void +msn_gleams_written_cb(MsnSoapConn * soapconn) +{ + purple_debug_info("MSNP14","finish Group written\n"); + soapconn->read_cb = msn_gleams_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*get the gleams info*/ +void +msn_get_gleams(MsnContact *contact) +{ + MsnSoapReq *soap_request; + + purple_debug_info("MSNP14","msn get gleams info...\n"); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_GET_GLEAMS_SOAP_ACTION, + MSN_GLEAMS_TEMPLATE, + NULL, + msn_gleams_read_cb, + msn_gleams_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); +} +#endif + + +/*************************************************************** + * Group Operations + ***************************************************************/ + +static gboolean +msn_group_read_cb(MsnSoapConn *soapconn) +{ + MsnUserList *userlist; + MsnCallbackState *state = NULL; + + purple_debug_info("MSN CL", "Group request successful.\n"); + + g_return_val_if_fail(soapconn->session != NULL, FALSE); + g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); + + state = (MsnCallbackState *) soapconn->data_cb; + + if (soapconn->body == NULL) { + msn_callback_state_free(state); + return TRUE; + } + + if (state) { + userlist = soapconn->session->userlist; + + if (state->action & MSN_RENAME_GROUP) { + msn_userlist_rename_group_id(soapconn->session->userlist, + state->guid, + state->new_group_name); + } + + if (state->action & MSN_ADD_GROUP) { + gchar *guid, *endguid; + + guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "<guid>"); + guid += 6; + endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "</guid>"); + *endguid = '\0'; + /* create and add the new group to the userlist */ + purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); + msn_group_new(soapconn->session->userlist, guid, state->new_group_name); + + if (state->action & MSN_ADD_BUDDY) { + msn_userlist_add_buddy(soapconn->session->userlist, + state->who, + state->new_group_name); + msn_callback_state_free(state); + return TRUE; + } + + if (state->action & MSN_MOVE_BUDDY) { + msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid); + return TRUE; + } + } + + if (state->action & MSN_DEL_GROUP) { + GList *l; + + msn_userlist_remove_group_id(soapconn->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); + } + + msn_soap_free_read_buf(soapconn); + return TRUE; +} + +static void +msn_group_written_cb(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN CL","Sent group request.\n"); + soapconn->read_cb = msn_group_read_cb; +} + +/* add group */ +void +msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name) +{ + MsnSoapReq *soap_request; + MsnContact *contact; + char *body = NULL; + gchar *escaped_group_name; + + g_return_if_fail(session != NULL); + g_return_if_fail(group_name != NULL); + + contact = session->contact; + purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name); + + if (state == NULL) { + state = msn_callback_state_new(); + } + + msn_callback_state_set_action(state, MSN_ADD_GROUP); + msn_callback_state_set_new_group_name(state, group_name); + + /* escape group name's html special chars so it can safely be sent + * in a XML SOAP request + */ + escaped_group_name = g_markup_escape_text(group_name, -1); + body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name); + g_free(escaped_group_name); + + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_GROUP_ADD_SOAP_ACTION, + body, + state, + msn_group_read_cb, + msn_group_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn,soap_request); + + g_free(body); +} + +/* delete group */ +void +msn_del_group(MsnSession *session, const gchar *group_name) +{ + MsnSoapReq *soap_request; + MsnContact *contact; + MsnCallbackState *state; + char *body = NULL; + const gchar *guid; + + g_return_if_fail(session != NULL); + + g_return_if_fail(group_name != NULL); + contact = session->contact; + purple_debug_info("MSN CL","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, + * we need to delete nothing + */ + if (guid == NULL) { + purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name); + return; + } + + if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { + // XXX add back PurpleGroup since it isn't really removed in the server? + return; + } + + state = msn_callback_state_new(); + 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); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_GROUP_DEL_SOAP_ACTION, + body, + state, + msn_group_read_cb, + msn_group_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn, soap_request); + + g_free(body); +} + +/* rename group */ +void +msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name) +{ + MsnSoapReq *soap_request; + MsnContact *contact; + gchar * escaped_group_name, *body = NULL; + const gchar * guid; + MsnCallbackState *state = msn_callback_state_new(); + + 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); + + contact = session->contact; + 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; + + msn_callback_state_set_guid(state, guid); + msn_callback_state_set_new_group_name(state, new_group_name); + + if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { + msn_add_group(session, state, new_group_name); + // XXX move every buddy there (we probably need to fix concurrent SOAP reqs first) + } + + msn_callback_state_set_action(state, MSN_RENAME_GROUP); + + /* escape group name's html special chars so it can safely be sent + * in a XML SOAP request + */ + escaped_group_name = g_markup_escape_text(new_group_name, -1); + + body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name); + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_GROUP_RENAME_SOAP_ACTION, + body, + state, + msn_group_read_cb, + msn_group_written_cb, + msn_contact_connect_init); + msn_soap_post(contact->soapconn, soap_request); + + g_free(escaped_group_name); + g_free(body); +} + +void +msn_contact_connect_init(MsnSoapConn *soapconn) +{ + msn_soap_init(soapconn, MSN_CONTACT_SERVER, 1, + msn_contact_login_connect_cb, + msn_contact_login_error_cb); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.h Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,448 @@ +/** + * @file contact.h Header file for contact.c + * Author + * MaYuan<mayuan2006@gmail.com> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_CONTACT_H_ +#define _MSN_CONTACT_H_ + +#define MSN_CONTACT_SERVER "contacts.msn.com" + +/* Get Contact List */ + +#define MSN_GET_CONTACT_POST_URL "/abservice/SharingService.asmx" +#define MSN_GET_CONTACT_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" +#define MSN_GET_CONTACT_UPDATE_XML "<View>Full</View>"\ + "<deltasOnly>true</deltasOnly>"\ + "<lastChange>%s</lastChange>" +#define MSN_GET_CONTACT_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\ +"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>"\ + "<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<Types xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType>"\ + "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType>"\ + "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType>"\ + "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType>"\ + "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType>"\ + "</Types>"\ + "</serviceFilter>"\ + "%s"\ + "</FindMembership>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/************************************************ + * Address Book SOAP + * *********************************************/ + +#define MSN_ADDRESS_BOOK_POST_URL "/abservice/abservice.asmx" + +/* Create AddressBook template */ +#define MSN_ADD_ADDRESSBOOK_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABAdd" + +#define MSN_ADD_ADDRESSBOOK_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>Initial</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abInfo>"\ + "<name/>"\ + "<ownerPuid>0</ownerPuid>"\ + "<ownerEmail>%s</ownerEmail>"\ + "<fDefault>true</fDefault>"\ + "</abInfo>"\ + "</ABAdd>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/* Get AddressBook */ +#define MSN_GET_ADDRESS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" +#define MSN_GET_ADDRESS_FULL_TIME "0001-01-01T00:00:00.0000000-08:00" +#define MSN_GET_ADDRESS_UPDATE_XML "<deltasOnly>true</deltasOnly>"\ + "<lastChange>%s</lastChange>" + +#define MSN_GET_GLEAM_UPDATE_XML \ + "%s"\ + "<dynamicItemView>Gleam</dynamicItemView>"\ + "<dynamicItemLastChange>%s</dynamicItemLastChange>" + +#define MSN_GET_ADDRESS_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>%s</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<abView>Full</abView>"\ + "%s"\ + "</ABFindAll>"\ + "</soap:Body>"\ +"</soap:Envelope>" + + +/*Gleams SOAP request template*/ +#define MSN_GET_GLEAMS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" +#define MSN_GLEAMS_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>Initial</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<abView>Full</abView>"\ + "<dynamicItemView>Gleam</dynamicItemView>"\ + "<dynamicItemLastChange>0001-01-01T00:00:00.0000000-08:00</dynamicItemLastChange>"\ + "</ABFindAll>"\ + "</soap:Body>"\ +"</soap:Envelope>" + + +/******************************************************* + * Contact Management SOAP actions + *******************************************************/ + +/* Add a new contact t*/ +#define MSN_CONTACT_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" +#define MSN_CONTACT_LIVE_PENDING_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><contactType>LivePending</contactType><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></contactInfo></Contact>" + +#define MSN_CONTACT_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<contactInfo>"\ + "<passportName>%s</passportName>"\ + "<isSmtp>false</isSmtp>"\ + "<isMessengerUser>true</isMessengerUser>"\ + "</contactInfo>"\ + "</Contact>" + +#define MSN_CONTACT_DISPLAYNAME_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><displayName>%s</displayName><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></contactInfo></Contact>" + +#define MSN_ADD_CONTACT_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>ContactSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><options><EnableAllowListManagement>true</EnableAllowListManagement></options></ABContactAdd></soap:Body></soap:Envelope>" + +/* Add a contact to a group */ +#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactAdd" +#define MSN_ADD_CONTACT_GROUP_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>ContactSave</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABGroupContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<groupFilter>"\ + "<groupIds>"\ + "<guid>%s</guid>"\ + "</groupIds>"\ + "</groupFilter>"\ + "<contacts>%s</contacts>"\ + "<groupContactAddOptions>"\ + "<fGenerateMissingQuickName>true</fGenerateMissingQuickName>"\ + "<EnableAllowListManagement>true</EnableAllowListManagement>"\ + "</groupContactAddOptions>"\ + "</ABGroupContactAdd>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/* Delete a contact from the Contact List */ +#define MSN_CONTACT_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" +#define MSN_CONTACT_ID_XML "<Contact><contactId>%s</contactId></Contact>" +#define MSN_DEL_CONTACT_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><ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts></ABContactDelete></soap:Body></soap:Envelope>" + +/* Remove a contact from a group */ +#define MSN_CONTACT_DEL_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactDelete" +#define MSN_CONTACT_DEL_GROUP_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><ABGroupContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupContactDelete></soap:Body></soap:Envelope>" + + +/* Update Contact Nickname */ +#define MSN_CONTACT_UPDATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" +#define MSN_CONTACT_UPDATE_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>"\ + "<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<contacts>"\ + "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<contactInfo>"\ + "<contactType>Me</contactType>"\ + "<displayName>%s</displayName>"\ + "</contactInfo>"\ + "<propertiesChanged>DisplayName</propertiesChanged>"\ + "</Contact>"\ + "</contacts>"\ + "</ABContactUpdate>"\ + "</soap:Body>"\ +"</soap:Envelope>" + + +/******************************************************* + * Add/Delete contact from lists SOAP actions + *******************************************************/ + +/* block means delete from allow list and add contact to block list */ +#define MSN_SHARE_POST_URL "/abservice/SharingService.asmx" + +#define MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" +#define MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" + +#define MSN_MEMBER_PASSPORT_XML "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ + "<Type>Passport</Type>"\ + "<State>Accepted</State>"\ + "<PassportName>%s</PassportName>"\ + "</Member>" + +#define MSN_MEMBER_MEMBERSHIPID_XML "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ + "<Type>Passport</Type>"\ + "<MembershipId>%u</MembershipId>"\ + "<State>Accepted</State>"\ + "</Member>" + +/* first delete contact from allow list */ + +#define MSN_CONTACT_DELECT_FROM_LIST_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>%s</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<DeleteMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<serviceHandle>"\ + "<Id>0</Id>"\ + "<Type>Messenger</Type>"\ + "<ForeignId></ForeignId>"\ + "</serviceHandle>"\ + "<memberships>"\ + "<Membership>"\ + "<MemberRole>%s</MemberRole>"\ + "<Members>"\ + "%s"\ + "</Members>"\ + "</Membership>"\ + "</memberships>"\ + "</DeleteMember>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +#define MSN_CONTACT_ADD_TO_LIST_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>%s</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<AddMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<serviceHandle>"\ + "<Id>0</Id>"\ + "<Type>Messenger</Type>"\ + "<ForeignId></ForeignId>"\ + "</serviceHandle>"\ + "<memberships>"\ + "<Membership>"\ + "<MemberRole>%s</MemberRole>"\ + "<Members>"\ + "%s"\ + "</Members>"\ + "</Membership>"\ + "</memberships>"\ + "</AddMember>"\ + "</soap:Body>"\ +"</soap:Envelope>" + + + +/******************************************************* + * Group management SOAP actions + *******************************************************/ + +/* add a group */ +#define MSN_GROUP_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupAdd" +#define MSN_GROUP_ADD_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>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo><GroupInfo><name>%s</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo></groupInfo></ABGroupAdd></soap:Body></soap:Envelope>" + +/* delete a group */ +#define MSN_GROUP_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupDelete" +#define MSN_GROUP_DEL_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><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>" + +/* change a group's name */ +#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 +{ + MSN_ADD_BUDDY = 0x01, + MSN_MOVE_BUDDY = 0x02, + MSN_ACCEPTED_BUDDY = 0x04, + MSN_DENIED_BUDDY = 0x08, + MSN_ADD_GROUP = 0x10, + MSN_DEL_GROUP = 0x20, + MSN_RENAME_GROUP = 0x40, +} MsnCallbackAction; + +typedef struct _MsnContact MsnContact; + +struct _MsnContact +{ + MsnSession *session; + + MsnSoapConn *soapconn; +}; + +typedef struct _MsnCallbackState MsnCallbackState; + +struct _MsnCallbackState +{ + gchar * who; + gchar * uid; + gchar * old_group_name; + gchar * new_group_name; + gchar * guid; + MsnListId list_id; + MsnCallbackAction action; +}; + +typedef enum +{ + MSN_PS_INITIAL, + MSN_PS_SAVE_CONTACT, + MSN_PS_PENDING_LIST, + MSN_PS_CONTACT_API, + MSN_PS_BLOCK_UNBLOCK +} MsnSoapPartnerScenario; + +/************************************************ + * function prototype + ************************************************/ +MsnContact * msn_contact_new(MsnSession *session); +void msn_contact_destroy(MsnContact *contact); + +MsnCallbackState * msn_callback_state_new(void); +void msn_callback_state_free(MsnCallbackState *state); +void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who); +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, + 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, + MsnCallbackAction action); + +void msn_contact_connect(MsnContact *contact); +void msn_get_contact_list(MsnContact * contact, + const MsnSoapPartnerScenario partner_scenario, + const char *update); +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, + const char *passport); +void msn_delete_contact(MsnContact *contact, const char *contactId); + +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, + const char *group_name); +/* group operations */ +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, + const char *new_group_name); + +/* lists operations */ +void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, + const gchar *passport, const MsnListId list); +void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, + const gchar *passport, const MsnListId list); + +void msn_contact_connect_init(MsnSoapConn *soapconn); + +#endif /* _MSN_CONTACT_H_ */ +
--- a/libpurple/protocols/msn/dialog.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/dialog.c Mon Oct 01 17:51:20 2007 +0000 @@ -36,6 +36,7 @@ /* Remove the buddy referenced by the MsnAddRemData before the serverside list is changed. * If the buddy will be added, he'll be added back; if he will be removed, he won't be. */ +/* Actually with our MSNP14 code that isn't true yet, he won't be added back :( */ static void msn_complete_sync_issue(MsnAddRemData *data) { @@ -44,28 +45,32 @@ if (data->group != NULL) group = purple_find_group(data->group); - + if (group != NULL) buddy = purple_find_buddy_in_group(purple_connection_get_account(data->gc), data->who, group); else buddy = purple_find_buddy(purple_connection_get_account(data->gc), data->who); - + if (buddy != NULL) purple_blist_remove_buddy(buddy); } + static void msn_add_cb(MsnAddRemData *data) { - MsnSession *session; - MsnUserList *userlist; - +#if 0 + /* this *should* be necessary !! */ msn_complete_sync_issue(data); +#endif - session = data->gc->proto_data; - userlist = session->userlist; + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group); + msn_userlist_add_buddy(userlist, data->who, data->group); + } g_free(data->group); g_free(data->who); @@ -75,17 +80,20 @@ static void msn_rem_cb(MsnAddRemData *data) { - MsnSession *session; - MsnUserList *userlist; - msn_complete_sync_issue(data); - session = data->gc->proto_data; - userlist = session->userlist; + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group); + if (data->group == NULL) { + msn_userlist_rem_buddy_from_list(userlist, data->who, MSN_LIST_FL); + } else { + g_free(data->group); + } + } - g_free(data->group); g_free(data->who); g_free(data); } @@ -104,7 +112,7 @@ data = g_new0(MsnAddRemData, 1); data->who = g_strdup(passport); - data->group = g_strdup(group_name); + data->group = group_name != NULL ? g_strdup(group_name) : NULL; data->gc = gc; msg = g_strdup_printf(_("Buddy list synchronization issue in %s (%s)"),
--- a/libpurple/protocols/msn/directconn.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/directconn.c Mon Oct 01 17:51:20 2007 +0000 @@ -76,7 +76,6 @@ * Connection Functions **************************************************************************/ -#if 0 static int create_listener(int port) { @@ -160,7 +159,6 @@ return fd; } -#endif static size_t msn_directconn_write(MsnDirectConn *directconn, @@ -288,6 +286,11 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); return; @@ -302,6 +305,11 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); return; @@ -348,17 +356,22 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); } } static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnDirectConn* directconn; int fd; - purple_debug_misc("msn", "directconn: connect_cb: %d\n", source); + purple_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond); directconn = data; directconn->connect_data = NULL; @@ -438,7 +451,6 @@ return (directconn->connect_data != NULL); } -#if 0 void msn_directconn_listen(MsnDirectConn *directconn) { @@ -458,7 +470,6 @@ directconn->port = port; directconn->c = 0; } -#endif MsnDirectConn* msn_directconn_new(MsnSlpLink *slplink)
--- a/libpurple/protocols/msn/directconn.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/directconn.h Mon Oct 01 17:51:20 2007 +0000 @@ -52,9 +52,7 @@ MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink); gboolean msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port); -#if 0 void msn_directconn_listen(MsnDirectConn *directconn); -#endif void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg); void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce); void msn_directconn_destroy(MsnDirectConn *directconn);
--- a/libpurple/protocols/msn/group.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/group.c Mon Oct 01 17:51:20 2007 +0000 @@ -25,18 +25,18 @@ #include "group.h" MsnGroup * -msn_group_new(MsnUserList *userlist, int id, const char *name) +msn_group_new(MsnUserList *userlist, const char *id, const char *name) { MsnGroup *group; - g_return_val_if_fail(id >= 0, NULL); + g_return_val_if_fail(id != NULL, NULL); g_return_val_if_fail(name != NULL, NULL); group = g_new0(MsnGroup, 1); msn_userlist_add_group(userlist, group); - group->id = id; + group->id = g_strdup(id); group->name = g_strdup(name); return group; @@ -47,17 +47,18 @@ { g_return_if_fail(group != NULL); + g_free(group->id); g_free(group->name); g_free(group); } void -msn_group_set_id(MsnGroup *group, int id) +msn_group_set_id(MsnGroup *group, const char *id) { g_return_if_fail(group != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); - group->id = id; + group->id = g_strdup(id); } void @@ -72,10 +73,10 @@ group->name = g_strdup(name); } -int +char* msn_group_get_id(const MsnGroup *group) { - g_return_val_if_fail(group != NULL, -1); + g_return_val_if_fail(group != NULL, NULL); return group->id; }
--- a/libpurple/protocols/msn/group.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/group.h Mon Oct 01 17:51:20 2007 +0000 @@ -30,8 +30,21 @@ #include "session.h" #include "user.h" +#include "soap.h" +#include "userlist.h" -#include "userlist.h" +#define MSN_ADD_GROUPS "<GroupInfo><name>test111</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo>" + +#define MSN_ADD_GROUP_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>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo>%s</groupInfo></ABGroupAdd></soap:Body></soap:Envelope>" + +#define MSN_GROUP_IDS "<guid>9e57e654-59f0-44d1-aedc-0a7500b7e51f</guid>" +#define MSN_DELETE_GROUP_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><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds>%s</groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>" + +#define MSN_INDIVIDUALS_GROUP_ID "1983" +#define MSN_INDIVIDUALS_GROUP_NAME "Other Contacts" + +#define MSN_NON_IM_GROUP_ID "email" +#define MSN_NON_IM_GROUP_NAME "Non-IM Contacts" /** * A group. @@ -39,8 +52,9 @@ struct _MsnGroup { MsnSession *session; /**< The MSN session. */ + MsnSoapConn *soapconn; - int id; /**< The group ID. */ + char *id; /**< The group ID. */ char *name; /**< The name of the group. */ }; @@ -58,7 +72,7 @@ * * @return A new group structure. */ -MsnGroup *msn_group_new(MsnUserList *userlist, int id, const char *name); +MsnGroup *msn_group_new(MsnUserList *userlist, const char *id, const char *name); /** * Destroys a group structure. @@ -73,7 +87,7 @@ * @param group The group. * @param id The ID. */ -void msn_group_set_id(MsnGroup *group, int id); +void msn_group_set_id(MsnGroup *group, const char *id); /** * Sets the name for a group. @@ -90,7 +104,7 @@ * * @return The ID. */ -int msn_group_get_id(const MsnGroup *group); +char* msn_group_get_id(const MsnGroup *group); /** * Returns the name for a group.
--- a/libpurple/protocols/msn/history.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/history.c Mon Oct 01 17:51:20 2007 +0000 @@ -84,3 +84,4 @@ msn_transaction_destroy(trans); } } +
--- a/libpurple/protocols/msn/msg.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/msg.c Mon Oct 01 17:51:20 2007 +0000 @@ -126,7 +126,7 @@ msn_message_set_charset(msg, "UTF-8"); msn_message_set_flag(msg, 'A'); msn_message_set_attr(msg, "X-MMS-IM-Format", - "FN=MS%20Sans%20Serif; EF=; CO=0; PF=0"); + "FN=MS%20Sans%20Serif; EF=; CO=0; CS=86;PF=0"); message_cr = purple_str_add_cr(message); msn_message_set_bin_data(msg, message_cr, strlen(message_cr)); @@ -206,7 +206,8 @@ void msn_message_parse_payload(MsnMessage *msg, - const char *payload, size_t payload_len) + const char *payload, size_t payload_len, + const char *line_dem,const char *body_dem) { char *tmp_base, *tmp; const char *content_type; @@ -214,12 +215,11 @@ char **elems, **cur, **tokens; g_return_if_fail(payload != NULL); - tmp_base = tmp = g_malloc0(payload_len + 1); memcpy(tmp_base, payload, payload_len); /* Parse the attributes. */ - end = strstr(tmp, "\r\n\r\n"); + end = strstr(tmp, body_dem); /* TODO? some clients use \r delimiters instead of \r\n, the official client * doesn't send such messages, but does handle receiving them. We'll just * avoid crashing for now */ @@ -229,7 +229,7 @@ } *end = '\0'; - elems = g_strsplit(tmp, "\r\n", 0); + elems = g_strsplit(tmp, line_dem, 0); for (cur = elems; *cur != NULL; cur++) { @@ -240,6 +240,7 @@ key = tokens[0]; value = tokens[1]; + /*if not MIME content ,then return*/ if (!strcmp(key, "MIME-Version")) { g_strfreev(tokens); @@ -274,7 +275,7 @@ g_strfreev(elems); /* Proceed to the end of the "\r\n\r\n" */ - tmp = end + 4; + tmp = end + strlen(body_dem); /* Now we *should* be at the body. */ content_type = msn_message_get_content_type(msg); @@ -480,6 +481,7 @@ { memcpy(n, body, body_len); n += body_len; + *n = '\0'; } }
--- a/libpurple/protocols/msn/msg.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/msg.h Mon Oct 01 17:51:20 2007 +0000 @@ -34,6 +34,12 @@ typedef void (*MsnMsgCb)(MsnMessage *, void *data); +#define MSG_BODY_DEM "\r\n\r\n" +#define MSG_LINE_DEM "\r\n" + +#define MSG_OIM_BODY_DEM "\n\n" +#define MSG_OIM_LINE_DEM "\n" + /* typedef enum { @@ -180,7 +186,8 @@ * @param payload_len The length of the payload. */ void msn_message_parse_payload(MsnMessage *msg, const char *payload, - size_t payload_len); + size_t payload_len, + const char *line_dem,const char *body_dem); /** * Destroys a message.
--- a/libpurple/protocols/msn/msn-utils.c Mon Oct 01 17:49:01 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,440 +0,0 @@ -/** - * @file msn-utils.c Utility functions - * - * 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 "msn.h" -#include "msn-utils.h" - -void -msn_parse_format(const char *mime, char **pre_ret, char **post_ret) -{ - char *cur; - GString *pre = g_string_new(NULL); - GString *post = g_string_new(NULL); - unsigned int colors[3]; - - if (pre_ret != NULL) *pre_ret = NULL; - if (post_ret != NULL) *post_ret = NULL; - - cur = strstr(mime, "FN="); - - if (cur && (*(cur = cur + 3) != ';')) - { - pre = g_string_append(pre, "<FONT FACE=\""); - - while (*cur && *cur != ';') - { - pre = g_string_append_c(pre, *cur); - cur++; - } - - pre = g_string_append(pre, "\">"); - post = g_string_prepend(post, "</FONT>"); - } - - cur = strstr(mime, "EF="); - - if (cur && (*(cur = cur + 3) != ';')) - { - while (*cur && *cur != ';') - { - pre = g_string_append_c(pre, '<'); - pre = g_string_append_c(pre, *cur); - pre = g_string_append_c(pre, '>'); - post = g_string_prepend_c(post, '>'); - post = g_string_prepend_c(post, *cur); - post = g_string_prepend_c(post, '/'); - post = g_string_prepend_c(post, '<'); - cur++; - } - } - - cur = strstr(mime, "CO="); - - if (cur && (*(cur = cur + 3) != ';')) - { - int i; - - i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); - - if (i > 0) - { - char tag[64]; - - if (i == 1) - { - colors[1] = 0; - colors[2] = 0; - } - else if (i == 2) - { - unsigned int temp = colors[0]; - - colors[0] = colors[1]; - colors[1] = temp; - colors[2] = 0; - } - else if (i == 3) - { - unsigned int temp = colors[2]; - - colors[2] = colors[0]; - colors[0] = temp; - } - - g_snprintf(tag, sizeof(tag), - "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", - colors[0], colors[1], colors[2]); - - pre = g_string_append(pre, tag); - post = g_string_prepend(post, "</FONT>"); - } - } - - cur = strstr(mime, "RL="); - - if (cur && (*(cur = cur + 3) != ';')) - { - if (*cur == '1') - { - /* RTL text was received */ - pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">"); - post = g_string_prepend(post, "</SPAN>"); - } - } - - cur = g_strdup(purple_url_decode(pre->str)); - g_string_free(pre, TRUE); - - if (pre_ret != NULL) - *pre_ret = cur; - else - g_free(cur); - - cur = g_strdup(purple_url_decode(post->str)); - g_string_free(post, TRUE); - - if (post_ret != NULL) - *post_ret = cur; - else - g_free(cur); -} - -/* - * We need this because we're only supposed to encode spaces in the font - * names. purple_url_encode() isn't acceptable. - */ -static const char * -encode_spaces(const char *str) -{ - static char buf[BUF_LEN]; - const char *c; - char *d; - - g_return_val_if_fail(str != NULL, NULL); - - for (c = str, d = buf; *c != '\0'; c++) - { - if (*c == ' ') - { - *d++ = '%'; - *d++ = '2'; - *d++ = '0'; - } - else - *d++ = *c; - } - - return buf; -} - -/* - * Taken from the zephyr plugin. - * This parses HTML formatting (put out by one of the gtkimhtml widgets - * and converts it to msn formatting. It doesn't deal with the tag closing, - * but gtkimhtml widgets give valid html. - * It currently deals properly with <b>, <u>, <i>, <font face=...>, - * <font color=...>, <span dir=...>, <span style="direction: ...">. - * It ignores <font back=...> and <font size=...> - */ -void -msn_import_html(const char *html, char **attributes, char **message) -{ - int len, retcount = 0; - const char *c; - char *msg; - char *fontface = NULL; - char fonteffect[4]; - char fontcolor[7]; - char direction = '0'; - - gboolean has_bold = FALSE; - gboolean has_italic = FALSE; - gboolean has_underline = FALSE; - gboolean has_strikethrough = FALSE; - - g_return_if_fail(html != NULL); - g_return_if_fail(attributes != NULL); - g_return_if_fail(message != NULL); - - len = strlen(html); - msg = g_malloc0(len + 1); - - memset(fontcolor, 0, sizeof(fontcolor)); - strcat(fontcolor, "0"); - memset(fonteffect, 0, sizeof(fonteffect)); - - for (c = html; *c != '\0';) - { - if (*c == '<') - { - if (!g_ascii_strncasecmp(c + 1, "br>", 3)) - { - msg[retcount++] = '\r'; - msg[retcount++] = '\n'; - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) - { - if (!has_italic) - { - strcat(fonteffect, "I"); - has_italic = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) - { - if (!has_bold) - { - strcat(fonteffect, "B"); - has_bold = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) - { - if (!has_underline) - { - strcat(fonteffect, "U"); - has_underline = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) - { - if (!has_strikethrough) - { - strcat(fonteffect, "S"); - has_strikethrough = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) - { - c += 9; - - if (!g_ascii_strncasecmp(c, "mailto:", 7)) - c += 7; - - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - msg[retcount++] = *c++; - - if (*c != '\0') - c += 2; - - /* ignore descriptive string */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4)) - c++; - - if (*c != '\0') - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "span", 4)) - { - /* Bi-directional text support using CSS properties in span tags */ - c += 5; - - while (*c != '\0' && *c != '>') - { - while (*c == ' ') - c++; - if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) - { - c += 9; - direction = '1'; - } - else if (!g_ascii_strncasecmp(c, "style=\"", 7)) - { - /* Parse inline CSS attributes */ - char *attributes; - int attr_len = 0; - c += 7; - while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') - attr_len++; - if (*(c + attr_len) == '"') - { - char *attr_dir; - attributes = g_strndup(c, attr_len); - attr_dir = purple_markup_get_css_property(attributes, "direction"); - if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3))) - direction = '1'; - g_free(attr_dir); - g_free(attributes); - } - - } - else - { - c++; - } - } - if (*c == '>') - c++; - } - else if (!g_ascii_strncasecmp(c + 1, "font", 4)) - { - c += 5; - - while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) - c++; - - if (!g_ascii_strncasecmp(c, "color=\"#", 7)) - { - c += 8; - - fontcolor[0] = *(c + 4); - fontcolor[1] = *(c + 5); - fontcolor[2] = *(c + 2); - fontcolor[3] = *(c + 3); - fontcolor[4] = *c; - fontcolor[5] = *(c + 1); - - c += 8; - } - else if (!g_ascii_strncasecmp(c, "face=\"", 6)) - { - const char *end = NULL; - const char *comma = NULL; - unsigned int namelen = 0; - - c += 6; - end = strchr(c, '\"'); - comma = strchr(c, ','); - - if (comma == NULL || comma > end) - namelen = (unsigned int)(end - c); - else - namelen = (unsigned int)(comma - c); - - fontface = g_strndup(c, namelen); - c = end + 2; - } - else - { - /* Drop all unrecognized/misparsed font tags */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - c++; - - if (*c != '\0') - c += 2; - } - } - else - { - while ((*c != '\0') && (*c != '>')) - c++; - if (*c != '\0') - c++; - } - } - else if (*c == '&') - { - if (!g_ascii_strncasecmp(c, "<", 4)) - { - msg[retcount++] = '<'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, ">", 4)) - { - msg[retcount++] = '>'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, " ", 6)) - { - msg[retcount++] = ' '; - c += 6; - } - else if (!g_ascii_strncasecmp(c, """, 6)) - { - msg[retcount++] = '"'; - c += 6; - } - else if (!g_ascii_strncasecmp(c, "&", 5)) - { - msg[retcount++] = '&'; - c += 5; - } - else if (!g_ascii_strncasecmp(c, "'", 6)) - { - msg[retcount++] = '\''; - c += 6; - } - else - msg[retcount++] = *c++; - } - else - msg[retcount++] = *c++; - } - - if (fontface == NULL) - fontface = g_strdup("MS Sans Serif"); - - *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", - encode_spaces(fontface), - fonteffect, fontcolor, direction); - *message = g_strdup(msg); - - g_free(fontface); - g_free(msg); -} - -void -msn_parse_socket(const char *str, char **ret_host, int *ret_port) -{ - char *host; - char *c; - int port; - - host = g_strdup(str); - - if ((c = strchr(host, ':')) != NULL) - { - *c = '\0'; - port = atoi(c + 1); - } - else - port = 1863; - - *ret_host = host; - *ret_port = port; -}
--- a/libpurple/protocols/msn/msn-utils.h Mon Oct 01 17:49:01 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/** - * @file msn-utils.h Utility functions - * - * 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 _MSN_UTILS_H_ -#define _MSN_UTILS_H_ - -/** - * Parses the MSN message formatting into a format compatible with Purple. - * - * @param mime The mime header with the formatting. - * @param pre_ret The returned prefix string. - * @param post_ret The returned postfix string. - * - * @return The new message. - */ -void msn_parse_format(const char *mime, char **pre_ret, char **post_ret); - -/** - * Parses the Purple message formatting (html) into the MSN format. - * - * @param html The html message to format. - * @param attributes The returned attributes string. - * @param message The returned message string. - * - * @return The new message. - */ -void msn_import_html(const char *html, char **attributes, char **message); - -void msn_parse_socket(const char *str, char **ret_host, int *ret_port); - -#endif /* _MSN_UTILS_H_ */
--- a/libpurple/protocols/msn/msn.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Mon Oct 01 17:51:20 2007 +0000 @@ -37,7 +37,7 @@ #include "cmds.h" #include "core.h" #include "prpl.h" -#include "msn-utils.h" +#include "msnutils.h" #include "version.h" #include "switchboard.h" @@ -151,7 +151,7 @@ return PURPLE_CMD_RET_OK; } -static void +void msn_act_id(PurpleConnection *gc, const char *entry) { MsnCmdProc *cmdproc; @@ -175,9 +175,12 @@ return; } - msn_cmdproc_send(cmdproc, "REA", "%s %s", - purple_account_get_username(account), - alias); + if (*alias == '\0') { + alias = purple_url_encode(purple_account_get_username(account)); + } + + msn_cmdproc_send(cmdproc, "PRP", "MFN %s", alias); + } static void @@ -414,6 +417,28 @@ return user && user->mobile; } +void +msn_send_privacy(PurpleConnection *gc) +{ + PurpleAccount *account; + MsnSession *session; + MsnCmdProc *cmdproc; + + account = purple_connection_get_account(gc); + session = gc->proto_data; + cmdproc = session->notification->cmdproc; + + if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL || + account->perm_deny == PURPLE_PRIVACY_DENY_USERS) + { + msn_cmdproc_send(cmdproc, "BLP", "%s", "AL"); + } + else + { + msn_cmdproc_send(cmdproc, "BLP", "%s", "BL"); + } +} + static void initiate_chat_cb(PurpleBlistNode *node, gpointer data) { @@ -460,6 +485,7 @@ session = gc->proto_data; xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who); + if (xfer) { slplink = msn_session_get_slplink(session, who); @@ -511,20 +537,27 @@ return "msn"; } +/* + * Set the User status text + * Add the PSM String Using "Name - PSM String" format + */ static char * msn_status_text(PurpleBuddy *buddy) { PurplePresence *presence; PurpleStatus *status; + const char *msg, *cmedia; presence = purple_buddy_get_presence(buddy); status = purple_presence_get_active_status(presence); - if (!purple_presence_is_available(presence) && !purple_presence_is_idle(presence)) - { - return g_strdup(purple_status_get_name(status)); - } + msg = purple_status_get_attr_string(status, "message"); + cmedia = purple_status_get_attr_string(status, "currentmedia"); + if (cmedia) + return g_markup_escape_text(cmedia, -1); + else if (msg) + return g_markup_escape_text(msg, -1); return NULL; } @@ -540,14 +573,43 @@ if (purple_presence_is_online(presence)) { - purple_notify_user_info_add_pair(user_info, _("Status"), - (purple_presence_is_idle(presence) ? _("Idle") : purple_status_get_name(status))); - } + const char *psm, *currentmedia, *name; + char *tmp; + + psm = purple_status_get_attr_string(status, "message"); + currentmedia = purple_status_get_attr_string(status, "currentmedia"); + + if (!purple_presence_is_available(presence)) { + name = purple_status_get_name(status); + } else { + name = NULL; + } + + if (name != NULL && *name) { + char *tmp2 = g_markup_escape_text(name, -1); - if (full && user) - { - purple_notify_user_info_add_pair(user_info, _("Has you"), - ((user->list_op & (1 << MSN_LIST_RL)) ? _("Yes") : _("No"))); + if (psm != NULL && *psm) { + tmp = g_markup_escape_text(psm, -1); + purple_notify_user_info_add_pair(user_info, tmp2, tmp); + g_free(tmp); + } else { + purple_notify_user_info_add_pair(user_info, _("Status"), tmp2); + } + + g_free(tmp2); + } else { + if (psm != NULL && *psm) { + tmp = g_markup_escape_text(psm, -1); + purple_notify_user_info_add_pair(user_info, _("Status"), tmp); + g_free(tmp); + } + } + + if (currentmedia) { + tmp = g_markup_escape_text(currentmedia, -1); + purple_notify_user_info_add_pair(user_info, _("Current media"), tmp); + g_free(tmp); + } } /* XXX: This is being shown in non-full tooltips because the @@ -567,28 +629,44 @@ PurpleStatusType *status; GList *types = NULL; - status = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, - NULL, NULL, FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - NULL, NULL, FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - "brb", _("Be Right Back"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, "brb", _("Be Right Back"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, - "busy", _("Busy"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_UNAVAILABLE, "busy", _("Busy"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, - "phone", _("On the Phone"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_UNAVAILABLE, "phone", _("On the Phone"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - "lunch", _("Out to Lunch"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, @@ -731,7 +809,7 @@ http_method = purple_account_get_bool(account, "http_method", FALSE); if (http_method) - host = purple_account_get_string(account, "http_method_server", MSN_SERVER); + host = purple_account_get_string(account, "http_method_server", MSN_HTTPCONN_SERVER); else host = purple_account_get_string(account, "server", MSN_SERVER); port = purple_account_get_int(account, "port", MSN_PORT); @@ -788,6 +866,7 @@ char *msgformat; char *msgtext; + purple_debug_info("MSNP14","send IM {%s} to %s\n",message,who); account = purple_connection_get_account(gc); if (buddy) { @@ -801,62 +880,91 @@ } msn_import_html(message, &msgformat, &msgtext); + if(msn_user_is_online(account, who)|| + msn_user_is_yahoo(account, who)){ + /*User online,then send Online Instant Message*/ - if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564) - { + if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564) + { + g_free(msgformat); + g_free(msgtext); + + return -E2BIG; + } + + msg = msn_message_new_plain(msgtext); + msg->remote_user = g_strdup(who); + msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); + g_free(msgformat); g_free(msgtext); - return -E2BIG; - } + purple_debug_info("MSNP14","prepare to send online Message\n"); + if (g_ascii_strcasecmp(who, purple_account_get_username(account))) + { + MsnSession *session; + MsnSwitchBoard *swboard; - msg = msn_message_new_plain(msgtext); - msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); - - g_free(msgformat); - g_free(msgtext); + session = gc->proto_data; + if(msn_user_is_yahoo(account,who)){ + /*we send the online and offline Message to Yahoo User via UBM*/ + purple_debug_info("MSNP14","send to Yahoo User\n"); + uum_send_msg(session,msg); + }else{ + purple_debug_info("MSNP14","send via switchboard\n"); + swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM); + msn_switchboard_send_msg(swboard, msg, TRUE); + } + } + else + { + char *body_str, *body_enc, *pre, *post; + const char *format; + MsnIMData *imdata = g_new0(MsnIMData, 1); + /* + * In MSN, you can't send messages to yourself, so + * we'll fake like we received it ;) + */ + body_str = msn_message_to_string(msg); + body_enc = g_markup_escape_text(body_str, -1); + g_free(body_str); - if (g_ascii_strcasecmp(who, purple_account_get_username(account))) - { - MsnSession *session; - MsnSwitchBoard *swboard; + format = msn_message_get_attr(msg, "X-MMS-IM-Format"); + msn_parse_format(format, &pre, &post); + body_str = g_strdup_printf("%s%s%s", pre ? pre : "", + body_enc ? body_enc : "", post ? post : ""); + g_free(body_enc); + g_free(pre); + g_free(post); + + serv_got_typing_stopped(gc, who); + imdata->gc = gc; + imdata->who = who; + imdata->msg = body_str; + imdata->flags = flags; + imdata->when = time(NULL); + g_idle_add(msn_send_me_im, imdata); + } + msn_message_destroy(msg); + }else { + /*send Offline Instant Message,only to MSN Passport User*/ + MsnSession *session; + MsnOim *oim; + char *friendname; + + purple_debug_info("MSNP14","prepare to send offline Message\n"); session = gc->proto_data; - swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM); + /* XXX/khc: hack */ + if (!session->oim) + session->oim = msn_oim_new(session); - msn_switchboard_send_msg(swboard, msg, TRUE); + oim = session->oim; + friendname = msn_encode_mime(account->username); + msn_oim_prep_send_msg_info(oim, purple_account_get_username(account), + friendname, who, message); + msn_oim_send_msg(oim); } - else - { - char *body_str, *body_enc, *pre, *post; - const char *format; - MsnIMData *imdata = g_new0(MsnIMData, 1); - /* - * In MSN, you can't send messages to yourself, so - * we'll fake like we received it ;) - */ - body_str = msn_message_to_string(msg); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - format = msn_message_get_attr(msg, "X-MMS-IM-Format"); - msn_parse_format(format, &pre, &post); - body_str = g_strdup_printf("%s%s%s", pre ? pre : "", - body_enc ? body_enc : "", post ? post : ""); - g_free(body_enc); - g_free(pre); - g_free(post); - - serv_got_typing_stopped(gc, who); - imdata->gc = gc; - imdata->who = who; - imdata->msg = body_str; - imdata->flags = flags; - imdata->when = time(NULL); - g_idle_add(msn_send_me_im, imdata); - } - - msn_message_destroy(msg); return 1; } @@ -995,6 +1103,7 @@ userlist = session->userlist; who = msn_normalize(gc->account, buddy->name); + purple_debug_info("MSN","Add user:%s to group:%s\n", who, group->name); if (!session->logged_in) { #if 0 @@ -1028,8 +1137,7 @@ /* XXX - Would group ever be NULL here? I don't think so... * shx: Yes it should; MSN handles non-grouped buddies, and this is only * internal. */ - msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, - group ? group->name : NULL); + msn_userlist_add_buddy(userlist, who, group ? group->name : NULL); } static void @@ -1045,7 +1153,7 @@ return; /* XXX - Does buddy->name need to be msn_normalize'd here? --KingAnt */ - msn_userlist_rem_buddy(userlist, buddy->name, MSN_LIST_FL, group->name); + msn_userlist_rem_buddy(userlist, buddy->name); } static void @@ -1062,10 +1170,18 @@ if (!session->logged_in) return; - if (user != NULL && user->list_op & MSN_LIST_BL_OP) - msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL); + if (user != NULL && user->list_op & MSN_LIST_BL_OP) { + msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); - msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL); + /* delete contact from Block list and add it to Allow in the callback */ + msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL); + } else { + /* just add the contact to Allow list */ + msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_AL); + } + + + msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL); } static void @@ -1082,10 +1198,17 @@ if (!session->logged_in) return; - if (user != NULL && user->list_op & MSN_LIST_AL_OP) - msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL); + if (user != NULL && user->list_op & MSN_LIST_AL_OP) { + msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); - msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL); + /* delete contact from Allow list and add it to Block in the callback */ + msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL); + } else { + /* just add the contact to Block list */ + msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_BL); + } + + msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); } static void @@ -1103,10 +1226,12 @@ user = msn_userlist_find_user(userlist, who); - msn_userlist_rem_buddy(userlist, who, MSN_LIST_AL, NULL); + msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); + + msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL); if (user != NULL && user->list_op & MSN_LIST_RL_OP) - msn_userlist_add_buddy(userlist, who, MSN_LIST_BL, NULL); + msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); } static void @@ -1124,32 +1249,18 @@ user = msn_userlist_find_user(userlist, who); - msn_userlist_rem_buddy(userlist, who, MSN_LIST_BL, NULL); + msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); + + msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL); if (user != NULL && user->list_op & MSN_LIST_RL_OP) - msn_userlist_add_buddy(userlist, who, MSN_LIST_AL, NULL); + msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL); } static void msn_set_permit_deny(PurpleConnection *gc) { - PurpleAccount *account; - MsnSession *session; - MsnCmdProc *cmdproc; - - account = purple_connection_get_account(gc); - session = gc->proto_data; - cmdproc = session->notification->cmdproc; - - if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL || - account->perm_deny == PURPLE_PRIVACY_DENY_USERS) - { - msn_cmdproc_send(cmdproc, "BLP", "%s", "AL"); - } - else - { - msn_cmdproc_send(cmdproc, "BLP", "%s", "BL"); - } + msn_send_privacy(gc); } static void @@ -1286,24 +1397,20 @@ PurpleGroup *group, GList *moved_buddies) { MsnSession *session; - MsnCmdProc *cmdproc; - int old_gid; - const char *enc_new_group_name; session = gc->proto_data; - cmdproc = session->notification->cmdproc; - enc_new_group_name = purple_url_encode(group->name); - - old_gid = msn_userlist_find_group_id(session->userlist, old_name); - - if (old_gid >= 0) + + 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_cmdproc_send(cmdproc, "REG", "%d %s 0", old_gid, - enc_new_group_name); + msn_contact_rename_group(session, old_name, group->name); } else { - msn_cmdproc_send(cmdproc, "ADG", "%s 0", enc_new_group_name); + /* not found */ + msn_add_group(session, NULL, group->name); } } @@ -1363,15 +1470,20 @@ { MsnSession *session; MsnCmdProc *cmdproc; - int group_id; session = gc->proto_data; cmdproc = session->notification->cmdproc; - if ((group_id = msn_userlist_find_group_id(session->userlist, group->name)) >= 0) + purple_debug_info("MSN", "Remove group %s\n", group->name); + /*we can't delete the default group*/ + if(!strcmp(group->name, MSN_INDIVIDUALS_GROUP_NAME)|| + !strcmp(group->name, MSN_NON_IM_GROUP_NAME)) { - msn_cmdproc_send(cmdproc, "RMG", "%d", group_id); + purple_debug_info("MSN", "This group can't be removed, returning.\n"); + return ; } + + msn_del_group(session, group->name); } /** @@ -1421,12 +1533,11 @@ { char *p, *q; - if ((p = strstr(url_text, " contactparams:photopreauthurl=\"")) != NULL) + if ((p = strstr(url_text, PHOTO_URL)) != NULL) { - p += strlen(" contactparams:photopreauthurl=\""); + p += strlen(PHOTO_URL); } - - if (p && (strncmp(p, "http://", 8) == 0) && ((q = strchr(p, '"')) != NULL)) + if (p && (strncmp(p, "http://",strlen("http://")) == 0) && ((q = strchr(p, '"')) != NULL)) return g_strndup(p, q - p); return NULL; @@ -1464,8 +1575,7 @@ msn_info_strip_search_link(const char *field, size_t len) { const char *c; - if ((c = strstr(field, " (http://spaces.live.com/default.aspx?page=searchresults")) == NULL && - (c = strstr(field, " (http://spaces.msn.com/default.aspx?page=searchresults")) == NULL) + if ((c = strstr(field, " (http://")) == NULL) return g_strndup(field, len); return g_strndup(field, c - field); } @@ -1491,7 +1601,7 @@ MsnGetInfoStepTwoData *info2_data = NULL; #endif - purple_debug_info("msn", "In msn_got_info\n"); + purple_debug_info("msn", "In msn_got_info,url_text:{%s}\n",url_text); /* Make sure the connection is still valid */ if (g_list_find(purple_connections_get_all(), info_data->gc) == NULL) @@ -1875,6 +1985,7 @@ #if PHOTO_SUPPORT /* Find the URL to the photo; must be before the marshalling [Bug 994207] */ photo_url_text = msn_get_photo_url(url_text); + purple_debug_info("MSNP14","photo url:{%s}\n",photo_url_text); /* Marshall the existing state */ info2_data = g_malloc0(sizeof(MsnGetInfoStepTwoData)); @@ -2099,7 +2210,7 @@ msn_add_deny, /* add_deny */ msn_rem_permit, /* rem_permit */ msn_rem_deny, /* rem_deny */ - msn_set_permit_deny, /* set_permit_deny */ + msn_set_permit_deny, /* set_permit_deny */ NULL, /* join_chat */ NULL, /* reject chat invite */ NULL, /* get_chat_name */ @@ -2155,10 +2266,11 @@ "MSN", /**< name */ VERSION, /**< version */ /** summary */ - N_("MSN Protocol Plugin"), + N_("Windows Live Messenger Protocol Plugin"), /** description */ - N_("MSN Protocol Plugin"), - "Christian Hammond <chipx86@gnupdate.org>", /**< author */ + N_("Windows Live Messenger Protocol Plugin"), + "Christian Hammond <chipx86@gnupdate.org>, " + "MaYuan <mayuan2006@gmail.com>", /**< author */ PURPLE_WEBSITE, /**< homepage */ msn_load, /**< load */ @@ -2183,11 +2295,11 @@ PurpleAccountOption *option; option = purple_account_option_string_new(_("Server"), "server", - MSN_SERVER); + WLM_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("Port"), "port", 1863); + option = purple_account_option_int_new(_("Port"), "port", WLM_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
--- a/libpurple/protocols/msn/msn.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/msn.h Mon Oct 01 17:51:20 2007 +0000 @@ -63,12 +63,23 @@ #define USEROPT_MSNPORT 4 #define MSN_PORT 1863 +/* Windows Live Messenger Server*/ +#define WLM_SERVER "muser.messenger.hotmail.com" +#define WLM_PORT 1863 +#define WLM_PROT_VER 13 +/*This MSNP14 Support chat with Yahoo Messenger*/ +#define WLM_YAHOO_PROT_VER 14 + +#define WLM_MAX_PROTOCOL 14 +#define WLM_MIN_PROTOCOL 13 + #define MSN_TYPING_RECV_TIMEOUT 6 #define MSN_TYPING_SEND_TIMEOUT 4 -#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders" +#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders"w3 #define PASSPORT_URL "http://lc1.law13.hotmail.passport.com/cgi-bin/dologin?login=" #define PROFILE_URL "http://spaces.live.com/profile.aspx?mem=" +#define PHOTO_URL " contactparams:photopreauthurl=\"" #define USEROPT_HOTMAIL 0 @@ -88,9 +99,11 @@ MSN_LIST_FL_OP = 0x01, MSN_LIST_AL_OP = 0x02, MSN_LIST_BL_OP = 0x04, - MSN_LIST_RL_OP = 0x08 + MSN_LIST_RL_OP = 0x08, + MSN_LIST_PL_OP = 0x10 } MsnListOp; +#define MSN_LIST_OP_MASK 0x07 typedef enum { @@ -131,4 +144,7 @@ (MSN_CLIENT_ID_RESERVED_2 << 8) | \ (MSN_CLIENT_ID_CAPABILITIES)) +void msn_act_id(PurpleConnection *gc, const char *entry); +void msn_send_privacy(PurpleConnection *gc); + #endif /* _MSN_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.c Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,591 @@ +/** + * @file msnutils.c Utility functions + * + * 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 "msn.h" +#include "msnutils.h" +#include "time.h" +//#include <openssl/md5.h> + +char *rand_guid(void); + +/************************************************************************** + * Util + **************************************************************************/ +char * +rand_guid() +{ + return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111); +} + +void +msn_parse_format(const char *mime, char **pre_ret, char **post_ret) +{ + char *cur; + GString *pre = g_string_new(NULL); + GString *post = g_string_new(NULL); + unsigned int colors[3]; + + if (pre_ret != NULL) *pre_ret = NULL; + if (post_ret != NULL) *post_ret = NULL; + + cur = strstr(mime, "FN="); + + if (cur && (*(cur = cur + 3) != ';')) + { + pre = g_string_append(pre, "<FONT FACE=\""); + + while (*cur && *cur != ';') + { + pre = g_string_append_c(pre, *cur); + cur++; + } + + pre = g_string_append(pre, "\">"); + post = g_string_prepend(post, "</FONT>"); + } + + cur = strstr(mime, "EF="); + + if (cur && (*(cur = cur + 3) != ';')) + { + while (*cur && *cur != ';') + { + pre = g_string_append_c(pre, '<'); + pre = g_string_append_c(pre, *cur); + pre = g_string_append_c(pre, '>'); + post = g_string_prepend_c(post, '>'); + post = g_string_prepend_c(post, *cur); + post = g_string_prepend_c(post, '/'); + post = g_string_prepend_c(post, '<'); + cur++; + } + } + + cur = strstr(mime, "CO="); + + if (cur && (*(cur = cur + 3) != ';')) + { + int i; + + i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); + + if (i > 0) + { + char tag[64]; + + if (i == 1) + { + colors[1] = 0; + colors[2] = 0; + } + else if (i == 2) + { + unsigned int temp = colors[0]; + + colors[0] = colors[1]; + colors[1] = temp; + colors[2] = 0; + } + else if (i == 3) + { + unsigned int temp = colors[2]; + + colors[2] = colors[0]; + colors[0] = temp; + } + + g_snprintf(tag, sizeof(tag), + "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", + colors[0], colors[1], colors[2]); + + pre = g_string_append(pre, tag); + post = g_string_prepend(post, "</FONT>"); + } + } + + cur = strstr(mime, "RL="); + + if (cur && (*(cur = cur + 3) != ';')) + { + if (*cur == '1') + { + /* RTL text was received */ + pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">"); + post = g_string_prepend(post, "</SPAN>"); + } + } + + cur = g_strdup(purple_url_decode(pre->str)); + g_string_free(pre, TRUE); + + if (pre_ret != NULL) + *pre_ret = cur; + else + g_free(cur); + + cur = g_strdup(purple_url_decode(post->str)); + g_string_free(post, TRUE); + + if (post_ret != NULL) + *post_ret = cur; + else + g_free(cur); +} + +/*encode the str to RFC2047 style + * Currently only support the UTF-8 and base64 encode + */ +char * +msn_encode_mime(const char *str) +{ + char *base64; + + base64 = purple_base64_encode((guchar *)str, strlen(str)); + return g_strdup_printf("=?utf-8?B?%s?=", base64); +} + +/* + * We need this because we're only supposed to encode spaces in the font + * names. purple_url_encode() isn't acceptable. + */ +static const char * +encode_spaces(const char *str) +{ + static char buf[BUF_LEN]; + const char *c; + char *d; + + g_return_val_if_fail(str != NULL, NULL); + + for (c = str, d = buf; *c != '\0'; c++) + { + if (*c == ' ') + { + *d++ = '%'; + *d++ = '2'; + *d++ = '0'; + } + else + *d++ = *c; + } + + return buf; +} + +/* + * Taken from the zephyr plugin. + * This parses HTML formatting (put out by one of the gtkimhtml widgets + * and converts it to msn formatting. It doesn't deal with the tag closing, + * but gtkimhtml widgets give valid html. + * It currently deals properly with <b>, <u>, <i>, <font face=...>, + * <font color=...>, <span dir=...>, <span style="direction: ...">. + * It ignores <font back=...> and <font size=...> + */ +void +msn_import_html(const char *html, char **attributes, char **message) +{ + int len, retcount = 0; + const char *c; + char *msg; + char *fontface = NULL; + char fonteffect[4]; + char fontcolor[7]; + char direction = '0'; + + gboolean has_bold = FALSE; + gboolean has_italic = FALSE; + gboolean has_underline = FALSE; + gboolean has_strikethrough = FALSE; + + g_return_if_fail(html != NULL); + g_return_if_fail(attributes != NULL); + g_return_if_fail(message != NULL); + + len = strlen(html); + msg = g_malloc0(len + 1); + + memset(fontcolor, 0, sizeof(fontcolor)); + strcat(fontcolor, "0"); + memset(fonteffect, 0, sizeof(fonteffect)); + + for (c = html; *c != '\0';) + { + if (*c == '<') + { + if (!g_ascii_strncasecmp(c + 1, "br>", 3)) + { + msg[retcount++] = '\r'; + msg[retcount++] = '\n'; + c += 4; + } + else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) + { + if (!has_italic) + { + strcat(fonteffect, "I"); + has_italic = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) + { + if (!has_bold) + { + strcat(fonteffect, "B"); + has_bold = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) + { + if (!has_underline) + { + strcat(fonteffect, "U"); + has_underline = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) + { + if (!has_strikethrough) + { + strcat(fonteffect, "S"); + has_strikethrough = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) + { + c += 9; + + if (!g_ascii_strncasecmp(c, "mailto:", 7)) + c += 7; + + while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) + msg[retcount++] = *c++; + + if (*c != '\0') + c += 2; + + /* ignore descriptive string */ + while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4)) + c++; + + if (*c != '\0') + c += 4; + } + else if (!g_ascii_strncasecmp(c + 1, "span", 4)) + { + /* Bi-directional text support using CSS properties in span tags */ + c += 5; + + while (*c != '\0' && *c != '>') + { + while (*c == ' ') + c++; + if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) + { + c += 9; + direction = '1'; + } + else if (!g_ascii_strncasecmp(c, "style=\"", 7)) + { + /* Parse inline CSS attributes */ + char *attributes; + int attr_len = 0; + c += 7; + while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') + attr_len++; + if (*(c + attr_len) == '"') + { + char *attr_dir; + attributes = g_strndup(c, attr_len); + attr_dir = purple_markup_get_css_property(attributes, "direction"); + if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3))) + direction = '1'; + g_free(attr_dir); + g_free(attributes); + } + + } + else + { + c++; + } + } + if (*c == '>') + c++; + } + else if (!g_ascii_strncasecmp(c + 1, "font", 4)) + { + c += 5; + + while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) + c++; + + if (!g_ascii_strncasecmp(c, "color=\"#", 7)) + { + c += 8; + + fontcolor[0] = *(c + 4); + fontcolor[1] = *(c + 5); + fontcolor[2] = *(c + 2); + fontcolor[3] = *(c + 3); + fontcolor[4] = *c; + fontcolor[5] = *(c + 1); + + c += 8; + } + else if (!g_ascii_strncasecmp(c, "face=\"", 6)) + { + const char *end = NULL; + const char *comma = NULL; + unsigned int namelen = 0; + + c += 6; + end = strchr(c, '\"'); + comma = strchr(c, ','); + + if (comma == NULL || comma > end) + namelen = (unsigned int)(end - c); + else + namelen = (unsigned int)(comma - c); + + fontface = g_strndup(c, namelen); + c = end + 2; + } + else + { + /* Drop all unrecognized/misparsed font tags */ + while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) + c++; + + if (*c != '\0') + c += 2; + } + } + else + { + while ((*c != '\0') && (*c != '>')) + c++; + if (*c != '\0') + c++; + } + } + else if (*c == '&') + { + if (!g_ascii_strncasecmp(c, "<", 4)) + { + msg[retcount++] = '<'; + c += 4; + } + else if (!g_ascii_strncasecmp(c, ">", 4)) + { + msg[retcount++] = '>'; + c += 4; + } + else if (!g_ascii_strncasecmp(c, " ", 6)) + { + msg[retcount++] = ' '; + c += 6; + } + else if (!g_ascii_strncasecmp(c, """, 6)) + { + msg[retcount++] = '"'; + c += 6; + } + else if (!g_ascii_strncasecmp(c, "&", 5)) + { + msg[retcount++] = '&'; + c += 5; + } + else if (!g_ascii_strncasecmp(c, "'", 6)) + { + msg[retcount++] = '\''; + c += 6; + } + else + msg[retcount++] = *c++; + } + else + msg[retcount++] = *c++; + } + + if (fontface == NULL) + fontface = g_strdup("MS Sans Serif"); + + *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", + encode_spaces(fontface), + fonteffect, fontcolor, direction); + *message = g_strdup(msg); + + g_free(fontface); + g_free(msg); +} + +void +msn_parse_socket(const char *str, char **ret_host, int *ret_port) +{ + char *host; + char *c; + int port; + + host = g_strdup(str); + + if ((c = strchr(host, ':')) != NULL){ + *c = '\0'; + port = atoi(c + 1); + }else{ + port = 1863; + } + + *ret_host = host; + *ret_port = port; +} +/*************************************************************************** + * MSN Time Related Funciton + ***************************************************************************/ +#if 0 +int +msn_convert_iso8601(const char *timestr,struct tm tm_time) +{ + char temp[64]; + struct tm ctime; + time_t ts; + + purple_debug_info("MSNP14","convert string is{%s}\n",timestr); + tzset(); + /*copy string first*/ + memset(temp, 0, sizeof(temp)); + strncpy(temp, timestr, strlen(timestr)); + + /*convert via strptime()*/ + memset(&ctime, 0, sizeof(struct tm)); + strptime(temp, "%d %b %Y %T %Z", &ctime); + ts = mktime(&ctime) - timezone; + localtime_r(&ts, tm_time); +} +#endif + +/*************************************************************************** + * MSN Challenge Computing Function + ***************************************************************************/ + +/* + * Handle MSN Chanllege computation + *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges + */ +#define BUFSIZE 256 +void +msn_handle_chl(char *input, char *output) +{ + PurpleCipher *cipher; + PurpleCipherContext *context; + char *productKey = MSNP13_WLM_PRODUCT_KEY, + *productID = MSNP13_WLM_PRODUCT_ID, + *hexChars = "0123456789abcdef", + buf[BUFSIZE]; + unsigned char md5Hash[16], *newHash; + unsigned int *md5Parts, *chlStringParts, newHashParts[5]; + + long long nHigh=0, nLow=0; + + int i; + + /* Create the MD5 hash by using Purple MD5 algorithm*/ + cipher = purple_ciphers_find_cipher("md5"); + context = purple_cipher_context_new(cipher, NULL); + + purple_cipher_context_append(context, (const guchar *)input, + strlen(input)); + purple_cipher_context_append(context, (const guchar *)productKey, + strlen(productKey)); + purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); + purple_cipher_context_destroy(context); + + /* Split it into four integers */ + md5Parts = (unsigned int *)md5Hash; + for(i=0; i<4; i++){ + /* adjust endianess */ + md5Parts[i] = GUINT_TO_LE(md5Parts[i]); + + /* & each integer with 0x7FFFFFFF */ + /* and save one unmodified array for later */ + newHashParts[i] = md5Parts[i]; + md5Parts[i] &= 0x7FFFFFFF; + } + + /* make a new string and pad with '0' */ + snprintf(buf, BUFSIZE-5, "%s%s", input, productID); + i = strlen(buf); + memset(&buf[i], '0', 8 - (i % 8)); + buf[i + (8 - (i % 8))]='\0'; + + /* split into integers */ + chlStringParts = (unsigned int *)buf; + + /* this is magic */ + for (i=0; i<(strlen(buf)/4)-1; i+=2){ + long long temp; + + chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); + chlStringParts[i+1] = GUINT_TO_LE(chlStringParts[i+1]); + + temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; + nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; + nLow=nLow + nHigh + temp; + } + nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF; + nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF; + + newHashParts[0]^=nHigh; + newHashParts[1]^=nLow; + newHashParts[2]^=nHigh; + newHashParts[3]^=nLow; + + /* adjust endianness */ + for(i=0; i<4; i++) + newHashParts[i] = GUINT_TO_LE(newHashParts[i]); + + /* make a string of the parts */ + newHash = (unsigned char *)newHashParts; + + /* convert to hexadecimal */ + for (i=0; i<16; i++) + { + output[i*2]=hexChars[(newHash[i]>>4)&0xF]; + output[(i*2)+1]=hexChars[newHash[i]&0xF]; + } + + output[32]='\0'; + +// purple_debug_info("MSNP14","chl output{%s}\n",output); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.h Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,60 @@ +/** + * @file msnutils.h Utility functions + * + * 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 _MSN_UTILS_H_ +#define _MSN_UTILS_H_ + +/*encode the str to RFC2047 style*/ +char * msn_encode_mime(const char *str); + +/** + * Generate the Random GUID + */ +char * rand_guid(void); + +/** + * Parses the MSN message formatting into a format compatible with Purple. + * + * @param mime The mime header with the formatting. + * @param pre_ret The returned prefix string. + * @param post_ret The returned postfix string. + * + * @return The new message. + */ +void msn_parse_format(const char *mime, char **pre_ret, char **post_ret); + +/** + * Parses the Purple message formatting (html) into the MSN format. + * + * @param html The html message to format. + * @param attributes The returned attributes string. + * @param message The returned message string. + * + * @return The new message. + */ +void msn_import_html(const char *html, char **attributes, char **message); + +void msn_parse_socket(const char *str, char **ret_host, int *ret_port); +void msn_handle_chl(char *input, char *output); + +#endif /* _MSN_UTILS_H_ */
--- a/libpurple/protocols/msn/nexus.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Mon Oct 01 17:51:20 2007 +0000 @@ -22,9 +22,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" +#include "soap.h" #include "nexus.h" #include "notification.h" +#undef NEXUS_LOGIN_TWN + +/*Local Function Prototype*/ +static gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc); + /************************************************************************** * Main **************************************************************************/ @@ -36,6 +42,9 @@ nexus = g_new0(MsnNexus, 1); nexus->session = session; + /*we must use SSL connection to do Windows Live ID authentication*/ + nexus->soapconn = msn_soap_new(session,nexus,1); + nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -45,24 +54,14 @@ void msn_nexus_destroy(MsnNexus *nexus) { - if (nexus->gsc) - purple_ssl_close(nexus->gsc); - - g_free(nexus->login_host); - - g_free(nexus->login_path); - if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); - if (nexus->input_handler > 0) - purple_input_remove(nexus->input_handler); - g_free(nexus->write_buf); - g_free(nexus->read_buf); - + msn_soap_destroy(nexus->soapconn); g_free(nexus); } +#if 0 /* khc */ /************************************************************************** * Util **************************************************************************/ @@ -121,285 +120,237 @@ nexus->written_cb(nexus, source, 0); } +#endif /************************************************************************** * Login **************************************************************************/ - static void -login_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond); - -static void -login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +nexus_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) { - MsnNexus *nexus; MsnSession *session; - nexus = data; - g_return_if_fail(nexus != NULL); - - nexus->gsc = NULL; - - session = nexus->session; + session = soapconn->session; g_return_if_fail(session != NULL); - msn_session_set_error(session, MSN_ERROR_AUTH, _("Unable to connect")); + soapconn->gsc = NULL; + + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); /* the above line will result in nexus being destroyed, so we don't want * to destroy it here, or we'd crash */ } -static void -nexus_login_written_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnNexus *nexus = data; - MsnSession *session; - int len; - - session = nexus->session; - g_return_if_fail(session != NULL); - - if (nexus->input_handler == 0) - /* TODO: Use purple_ssl_input_add()? */ - nexus->input_handler = purple_input_add(nexus->gsc->fd, - PURPLE_INPUT_READ, nexus_login_written_cb, nexus); - - - len = msn_ssl_read(nexus); - - if (len < 0 && errno == EAGAIN) - return; - else if (len < 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - /* TODO: error handling */ - return; - } - - if (g_strstr_len(nexus->read_buf, nexus->read_len, - "\r\n\r\n") == NULL) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - purple_ssl_close(nexus->gsc); - nexus->gsc = NULL; - - purple_debug_misc("msn", "ssl buffer: {%s}\n", nexus->read_buf); - - if (strstr(nexus->read_buf, "HTTP/1.1 302") != NULL) - { - /* Redirect. */ - char *location, *c; - - location = strstr(nexus->read_buf, "Location: "); - if (location == NULL) - { - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - - return; - } - location = strchr(location, ' ') + 1; - - if ((c = strchr(location, '\r')) != NULL) - *c = '\0'; - - /* Skip the http:// */ - if ((c = strchr(location, '/')) != NULL) - location = c + 2; - - if ((c = strchr(location, '/')) != NULL) - { - g_free(nexus->login_path); - nexus->login_path = g_strdup(c); - - *c = '\0'; - } - - g_free(nexus->login_host); - nexus->login_host = g_strdup(location); - - nexus->gsc = purple_ssl_connect(session->account, - nexus->login_host, PURPLE_SSL_DEFAULT_PORT, - login_connect_cb, login_error_cb, nexus); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 401 Unauthorized") != NULL) - { - const char *error; - - if ((error = strstr(nexus->read_buf, "WWW-Authenticate")) != NULL) - { - if ((error = strstr(error, "cbtxt=")) != NULL) - { - const char *c; - char *temp; - - error += strlen("cbtxt="); - - if ((c = strchr(error, '\n')) == NULL) - c = error + strlen(error); - - temp = g_strndup(error, c - error); - error = purple_url_decode(temp); - g_free(temp); - if ((temp = strstr(error, " Do one of the following or try again:")) != NULL) - *temp = '\0'; - } - } - - msn_session_set_error(session, MSN_ERROR_AUTH, error); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 503 Service Unavailable")) - { - msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 200 OK")) - { - char *base, *c; - char *login_params; - -#if 0 - /* All your base are belong to us. */ - base = buffer; - - /* For great cookie! */ - while ((base = strstr(base, "Set-Cookie: ")) != NULL) - { - base += strlen("Set-Cookie: "); - - c = strchr(base, ';'); - - session->login_cookies = - g_list_append(session->login_cookies, - g_strndup(base, c - base)); - } -#endif - - base = strstr(nexus->read_buf, "Authentication-Info: "); - - g_return_if_fail(base != NULL); - - base = strstr(base, "from-PP='"); - base += strlen("from-PP='"); - c = strchr(base, '\''); - - login_params = g_strndup(base, c - base); - - msn_got_login_params(session, login_params); - - g_free(login_params); - - msn_nexus_destroy(nexus); - session->nexus = NULL; - return; - } - - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - -} - -/* this guards against missing hash entries */ -static char * -nexus_challenge_data_lookup(GHashTable *challenge_data, const char *key) -{ - char *entry; - - return (entry = (char *)g_hash_table_lookup(challenge_data, key)) ? - entry : "(null)"; -} - -void -login_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond) +/*process the SOAP reply, get the Authentication Info*/ +static gboolean +nexus_login_read_cb(MsnSoapConn *soapconn) { MsnNexus *nexus; MsnSession *session; + + char *base, *c; + char *msn_twn_t,*msn_twn_p; + char *login_params; + char **elems, **cur, **tokens; + char * cert_str; + + nexus = soapconn->parent; + g_return_val_if_fail(nexus != NULL, TRUE); + session = nexus->session; + g_return_val_if_fail(session != NULL, FALSE); + + /*reply OK, we should process the SOAP body*/ + purple_debug_info("MSN Nexus","TWN Server Windows Live ID Reply OK!\n"); + + //TODO: we should parse it using XML +#ifdef NEXUS_LOGIN_TWN + base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN); + base += strlen(TWN_START_TOKEN); + c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN); +#else + base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN); + base += strlen(TWN_LIVE_START_TOKEN); + c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN); +#endif + login_params = g_strndup(base, c - base); + + // purple_debug_info("msn", "TWN Cert: {%s}\n", login_params); + + /* Parse the challenge data. */ + elems = g_strsplit(login_params, "&", 0); + + for (cur = elems; *cur != NULL; cur++){ + tokens = g_strsplit(*cur, "=", 2); + g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + + g_strfreev(elems); + + msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t"); + msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p"); + + /*setup the t and p parameter for session*/ + if (session->passport_info.t != NULL){ + g_free(session->passport_info.t); + } + session->passport_info.t = g_strdup(msn_twn_t); + + if (session->passport_info.p != NULL) + g_free(session->passport_info.p); + session->passport_info.p = g_strdup(msn_twn_p); + + cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); + msn_got_login_params(session, cert_str); + + purple_debug_info("MSN Nexus","Close nexus connection!\n"); + g_free(cert_str); + g_free(login_params); + msn_nexus_destroy(nexus); + session->nexus = NULL; + + return FALSE; +} + +static void +nexus_login_written_cb(MsnSoapConn *soapconn) +{ + soapconn->read_cb = nexus_login_read_cb; +// msn_soap_read_cb(data,source,cond); +} + + +/*when connect, do the SOAP Style windows Live ID authentication */ +gboolean +nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) +{ + MsnNexus * nexus; + MsnSession *session; + char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; + char *fs0,*fs; char *username, *password; char *request_str, *head, *tail; - char *buffer = NULL; - guint32 ctint; +#ifdef NEXUS_LOGIN_TWN + char *challenge_str; +#else + char *rst1_str,*rst2_str,*rst3_str; +#endif + + purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); - nexus = data; - g_return_if_fail(nexus != NULL); + g_return_val_if_fail(soapconn != NULL, FALSE); + + nexus = soapconn->parent; + g_return_val_if_fail(nexus != NULL, TRUE); - session = nexus->session; - g_return_if_fail(session != NULL); + session = soapconn->session; + g_return_val_if_fail(session != NULL, FALSE); + + msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); - username = - g_strdup(purple_url_encode(purple_account_get_username(session->account))); + /*prepare the Windows Live ID authentication token*/ + username = g_strdup(purple_account_get_username(session->account)); + password = g_strdup(purple_connection_get_password(session->account->gc)); - password = - g_strdup(purple_url_encode(purple_connection_get_password(session->account->gc))); + lc = (char *)g_hash_table_lookup(nexus->challenge_data, "lc"); + id = (char *)g_hash_table_lookup(nexus->challenge_data, "id"); + tw = (char *)g_hash_table_lookup(nexus->challenge_data, "tw"); + fs0= (char *)g_hash_table_lookup(nexus->challenge_data, "fs"); + ru = (char *)g_hash_table_lookup(nexus->challenge_data, "ru"); + ct = (char *)g_hash_table_lookup(nexus->challenge_data, "ct"); + kpp= (char *)g_hash_table_lookup(nexus->challenge_data, "kpp"); + kv = (char *)g_hash_table_lookup(nexus->challenge_data, "kv"); + ver= (char *)g_hash_table_lookup(nexus->challenge_data, "ver"); + rn = (char *)g_hash_table_lookup(nexus->challenge_data, "rn"); + tpf= (char *)g_hash_table_lookup(nexus->challenge_data, "tpf"); - ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200; + /* + * add some fail-safe code to avoid windows Purple Crash bug #1540454 + * If any of these string is NULL, will return Authentication Fail! + * for when windows g_strdup_printf() implementation get NULL point,It crashed! + */ + if(!(lc && id && tw && ru && ct && kpp && kv && ver && tpf)){ + purple_debug_error("MSN Nexus","WLM Authenticate Key Error!\n"); + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); + g_free(username); + g_free(password); + purple_ssl_close(gsc); + msn_nexus_destroy(nexus); + session->nexus = NULL; + return FALSE; + } - head = g_strdup_printf( - "GET %s HTTP/1.1\r\n" - "Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s", - nexus->login_path, - (char *)g_hash_table_lookup(nexus->challenge_data, "ru"), - username); + /* + * in old MSN NS server's "USR TWN S" return,didn't include fs string + * so we use a default "1" for fs. + */ + if(fs0){ + fs = g_strdup(fs0); + }else{ + fs = g_strdup("1"); + } - tail = g_strdup_printf( - "lc=%s,id=%s,tw=%s,fs=%s,ru=%s,ct=%" G_GUINT32_FORMAT ",kpp=%s,kv=%s,ver=%s,tpf=%s\r\n" - "User-Agent: MSMSGS\r\n" - "Host: %s\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n", - nexus_challenge_data_lookup(nexus->challenge_data, "lc"), - nexus_challenge_data_lookup(nexus->challenge_data, "id"), - nexus_challenge_data_lookup(nexus->challenge_data, "tw"), - nexus_challenge_data_lookup(nexus->challenge_data, "fs"), - nexus_challenge_data_lookup(nexus->challenge_data, "ru"), - ctint, - nexus_challenge_data_lookup(nexus->challenge_data, "kpp"), - nexus_challenge_data_lookup(nexus->challenge_data, "kv"), - nexus_challenge_data_lookup(nexus->challenge_data, "ver"), - nexus_challenge_data_lookup(nexus->challenge_data, "tpf"), - nexus->login_host); +#ifdef NEXUS_LOGIN_TWN + challenge_str = g_strdup_printf( + "lc=%s&id=%s&tw=%s&fs=%s&ru=%s&ct=%s&kpp=%s&kv=%s&ver=%s&rn=%s&tpf=%s\r\n", + lc,id,tw,fs,ru,ct,kpp,kv,ver,rn,tpf + ); - buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail); - request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail); + /*build the SOAP windows Live ID XML body */ + tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE,username,password,challenge_str ); + g_free(challenge_str); +#else + rst1_str = g_strdup_printf( + "id=%s&tw=%s&fs=%s&kpp=%s&kv=%s&ver=%s&rn=%s", + id,tw,fs,kpp,kv,ver,rn + ); + rst2_str = g_strdup_printf( + "fs=%s&id=%s&kv=%s&rn=%s&tw=%s&ver=%s", + fs,id,kv,rn,tw,ver + ); + rst3_str = g_strdup_printf("id=%s",id); + tail = g_strdup_printf(TWN_LIVE_ENVELOP_TEMPLATE,username,password,rst1_str,rst2_str,rst3_str); + g_free(rst1_str); + g_free(rst2_str); + g_free(rst3_str); +#endif + g_free(fs); - purple_debug_misc("msn", "Sending: {%s}\n", buffer); + soapconn->login_path = g_strdup(TWN_POST_URL); + head = g_strdup_printf( + "POST %s HTTP/1.1\r\n" + "Accept: text/*\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" + "Host: %s\r\n" + "Content-Length: %" G_GSIZE_FORMAT "\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n\r\n", + soapconn->login_path, soapconn->login_host, strlen(tail)); - g_free(buffer); + request_str = g_strdup_printf("%s%s", head,tail); + +#ifdef MSN_SOAP_DEBUG + purple_debug_misc("MSN Nexus", "TWN Sending:\n%s\n", request_str); +#endif g_free(head); g_free(tail); g_free(username); g_free(password); - nexus->write_buf = request_str; - nexus->written_len = 0; - - nexus->read_len = 0; - - nexus->written_cb = nexus_login_written_cb; + /*prepare to send the SOAP request*/ + msn_soap_write(soapconn, request_str, nexus_login_written_cb); - nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE, - nexus_write_cb, nexus); - - nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); - - return; - - + return TRUE; } +#if 0 /* khc */ static void nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnNexus *nexus = data; int len; + char *da_login; char *base, *c; @@ -408,6 +359,7 @@ nexus->input_handler = purple_input_add(nexus->gsc->fd, PURPLE_INPUT_READ, nexus_connect_written_cb, nexus); + /* Get the PassportURLs line. */ len = msn_ssl_read(nexus); @@ -470,10 +422,13 @@ } +#endif + /************************************************************************** * Connect **************************************************************************/ +#if 0 /* khc */ static void nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) @@ -502,10 +457,12 @@ nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); } +#endif + void msn_nexus_connect(MsnNexus *nexus) { - nexus->gsc = purple_ssl_connect(nexus->session->account, - "nexus.passport.com", PURPLE_SSL_DEFAULT_PORT, - nexus_connect_cb, login_error_cb, nexus); + /* Authenticate via Windows Live ID. */ + msn_soap_init(nexus->soapconn, MSN_TWN_SERVER, 1, nexus_login_connect_cb, nexus_login_error_cb); + msn_soap_connect(nexus->soapconn); }
--- a/libpurple/protocols/msn/nexus.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Mon Oct 01 17:51:20 2007 +0000 @@ -24,25 +24,124 @@ #ifndef _MSN_NEXUS_H_ #define _MSN_NEXUS_H_ +#include "soap.h" + +/*#define MSN_TWN_SERVER "loginnet.passport.com"*/ +#define MSN_TWN_SERVER "login.live.com" + +#define TWN_START_TOKEN "<wsse:BinarySecurityToken Id=\"PPToken1\">" +#define TWN_END_TOKEN "</wsse:BinarySecurityToken>" + +#define TWN_POST_URL "/RST.srf" +#define TWN_ENVELOP_TEMPLATE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\ + "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ + "<Header>"\ + "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ + "<ps:HostingApp>{3:B}</ps:HostingApp>"\ + "<ps:BinaryVersion>4</ps:BinaryVersion>"\ + "<ps:UIVersion>1</ps:UIVersion>"\ + "<ps:Cookies></ps:Cookies>"\ + "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>"\ + "</ps:AuthInfo>"\ + "<wsse:Security>"\ + "<wsse:UsernameToken Id=\"user\">"\ + "<wsse:Username>%s</wsse:Username>"\ + "<wsse:Password>%s</wsse:Password>"\ + "</wsse:UsernameToken>"\ + "</wsse:Security>"\ + "</Header>"\ + "<Body>"\ + "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\ + "<wst:RequestSecurityToken Id=\"RST0\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "</wst:RequestSecurityToken>"\ + "<wst:RequestSecurityToken Id=\"RST1\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>messenger.msn.com</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "<wsse:PolicyReference URI=\"?%s\">"\ + "</wsse:PolicyReference>"\ + "</wst:RequestSecurityToken>"\ + "</ps:RequestMultipleSecurityTokens>"\ + "</Body>"\ + "</Envelope>" + +#define TWN_LIVE_START_TOKEN "<wsse:BinarySecurityToken Id=\"PPToken1\">" +#define TWN_LIVE_END_TOKEN "</wsse:BinarySecurityToken>" +#define TWN_LIVE_ENVELOP_TEMPLATE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\ +"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ + "<Header>"\ + "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ + "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ + "<ps:BinaryVersion>4</ps:BinaryVersion>"\ + "<ps:UIVersion>1</ps:UIVersion>"\ + "<ps:Cookies></ps:Cookies>"\ + "<ps:RequestParams>AQAAAAIAAABsYwQAAAAyMDUy</ps:RequestParams>"\ + "</ps:AuthInfo>"\ + "<wsse:Security>"\ + "<wsse:UsernameToken Id=\"user\">"\ + "<wsse:Username>%s</wsse:Username>"\ + "<wsse:Password>%s</wsse:Password>"\ + "</wsse:UsernameToken>"\ + "</wsse:Security>"\ + "</Header>"\ + "<Body>"\ + "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\ + "<wst:RequestSecurityToken Id=\"RST0\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "</wst:RequestSecurityToken>"\ + "<wst:RequestSecurityToken Id=\"RST1\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>messenger.msn.com</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ + "</wst:RequestSecurityToken>"\ + "<wst:RequestSecurityToken Id=\"RST2\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>contacts.msn.com</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ + " </wst:RequestSecurityToken>"\ + "<wst:RequestSecurityToken Id=\"RST3\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ + "<wsa:Address>voice.messenger.msn.com</wsa:Address>"\ + "</wsa:EndpointReference>"\ + " </wsp:AppliesTo>"\ + "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ + "</wst:RequestSecurityToken>"\ + "</ps:RequestMultipleSecurityTokens>"\ + "</Body>"\ +"</Envelope>" + typedef struct _MsnNexus MsnNexus; struct _MsnNexus { MsnSession *session; - - char *login_host; - char *login_path; + MsnSoapConn *soapconn; + char * challenge_data_str; GHashTable *challenge_data; - PurpleSslConnection *gsc; - - guint input_handler; - - char *write_buf; - gsize written_len; - PurpleInputFunction written_cb; - - char *read_buf; - gsize read_len; }; void msn_nexus_connect(MsnNexus *nexus);
--- a/libpurple/protocols/msn/notification.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Oct 01 17:51:20 2007 +0000 @@ -25,7 +25,7 @@ #include "notification.h" #include "state.h" #include "error.h" -#include "msn-utils.h" +#include "msnutils.h" #include "page.h" #include "userlist.h" @@ -34,6 +34,15 @@ 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 **************************************************************************/ @@ -92,7 +101,8 @@ MsnCmdProc *cmdproc; MsnSession *session; PurpleAccount *account; - char **a, **c, *vers; + GString *vers; + const char *ver_str; int i; g_return_if_fail(servconn != NULL); @@ -101,25 +111,24 @@ session = servconn->session; account = session->account; - /* Allocate an array for CVR0, NULL, and all the versions */ - a = c = g_new0(char *, session->protocol_ver - 8 + 3); + vers = g_string_new(""); - for (i = session->protocol_ver; i >= 8; i--) - *c++ = g_strdup_printf("MSNP%d", i); +/* for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) */ + for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) + g_string_append_printf(vers, " MSNP%d", i); - *c++ = g_strdup("CVR0"); - - vers = g_strjoinv(" ", a); + g_string_append(vers, " CVR0"); if (session->login_step == MSN_LOGIN_STEP_START) msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE); else msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2); - msn_cmdproc_send(cmdproc, "VER", "%s", vers); + /* Skip the initial space */ + ver_str = (vers->str + 1); + msn_cmdproc_send(cmdproc, "VER", "%s", ver_str); - g_strfreev(a); - g_free(vers); + g_string_free(vers, TRUE); } gboolean @@ -153,7 +162,7 @@ **************************************************************************/ static void -group_error_helper(MsnSession *session, const char *msg, int group_id, int error) +group_error_helper(MsnSession *session, const char *msg, const char *group_id, int error) { PurpleAccount *account; PurpleConnection *gc; @@ -172,11 +181,9 @@ else { const char *group_name; - group_name = - msn_userlist_find_group_name(session->userlist, - group_id); + group_name = msn_userlist_find_group_name(session->userlist,group_id); reason = g_strdup_printf(_("%s is not a valid group."), - group_name); + group_name ? group_name : ""); } } else @@ -214,7 +221,6 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", purple_account_get_username(account)); } @@ -232,14 +238,17 @@ if (!g_ascii_strcasecmp(cmd->params[1], "OK")) { - /* OK */ + /* authenticate OK */ + /* friendly name part no longer true in msnp11 */ +#if 0 const char *friendly = purple_url_decode(cmd->params[3]); purple_connection_set_display_name(gc, friendly); - +#endif msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN); - msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); +// msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); + //TODO we should use SOAP contact to fetch contact list } else if (!g_ascii_strcasecmp(cmd->params[1], "TWN")) { @@ -249,15 +258,20 @@ session->nexus = msn_nexus_new(session); /* Parse the challenge data. */ - + session->nexus->challenge_data_str = g_strdup(cmd->params[3]); elems = g_strsplit(cmd->params[3], ",", 0); for (cur = elems; *cur != NULL; cur++) { - tokens = g_strsplit(*cur, "=", 2); + tokens = g_strsplit(*cur, "=", 2); + if(tokens[0]&&tokens[1]) + { + purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n", + session->nexus->challenge_data,tokens[0],tokens[1]); g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); + } + /* Don't free each of the tokens, only the array. */ + g_free(tokens); } g_strfreev(elems); @@ -322,8 +336,15 @@ return; } + /* + * Windows Live Messenger 8.0 + * Notice :CVR String discriminate! + * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx + * to see the Local ID + */ msn_cmdproc_send(cmdproc, "CVR", - "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s", +// "0x0409 winnt 5.1 i386 MSG80BETA 8.0.0689 msmsgs %s", + "0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s", purple_account_get_username(account)); } @@ -366,7 +387,7 @@ msg = msn_message_new_from_cmd(cmdproc->session, cmd); - msn_message_parse_payload(msg, payload, len); + msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM); #ifdef MSN_DEBUG_NS msn_message_show_readable(msg, "Notification", TRUE); #endif @@ -379,9 +400,12 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { + purple_debug_info("MSNP14","Processing MSG... \n"); + if(cmd->payload_len == 0){ + return; + } /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued * command and we are processing it */ - if (cmd->payload == NULL) { cmdproc->last_cmd->payload_cb = msg_cmd_post; @@ -391,32 +415,145 @@ { g_return_if_fail(cmd->payload_cb != NULL); + purple_debug_info("MSNP14","MSG payload:{%s}\n",cmd->payload); cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); } } +/*send Message to Yahoo Messenger*/ +void +uum_send_msg(MsnSession *session,MsnMessage *msg) +{ + MsnCmdProc *cmdproc; + MsnTransaction *trans; + 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); + purple_debug_info("MSNP14","send UUM,payload{%s},strlen:%d,len:%d\n", + payload,strlen(payload),payload_len); + type = msg->type; + trans = msn_transaction_new(cmdproc, "UUM","%s 32 %d %d",msg->remote_user,type,payload_len); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + +static void +ubm_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + MsnMessage *msg; + PurpleConnection *gc; + const char *passport; + const char *content_type; + + purple_debug_info("MSNP14","Process UBM payload:%s\n",payload); + msg = msn_message_new_from_cmd(cmdproc->session, cmd); + + msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM); +#ifdef MSN_DEBUG_NS + msn_message_show_readable(msg, "Notification", TRUE); +#endif + + gc = cmdproc->session->account->gc; + passport = msg->remote_user; + + content_type = msn_message_get_content_type(msg); + purple_debug_info("MSNP14","type:%d\n",content_type); + if(!strcmp(content_type,"text/plain")){ + const char *value; + const char *body; + char *body_str; + char *body_enc; + char *body_final = NULL; + size_t body_len; + + body = msn_message_get_bin_data(msg, &body_len); + body_str = g_strndup(body, body_len); + body_enc = g_markup_escape_text(body_str, -1); + g_free(body_str); + + if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) { + char *pre, *post; + + msn_parse_format(value, &pre, &post); + body_final = g_strdup_printf("%s%s%s", pre ? pre : "", + body_enc ? body_enc : "", post ? post : ""); + g_free(pre); + g_free(post); + } + g_free(body_enc); + serv_got_im(gc, passport, body_final, 0, time(NULL)); + } + if(!strcmp(content_type,"text/x-msmsgscontrol")){ + if(msn_message_get_attr(msg, "TypingUser") != NULL){ + serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, + PURPLE_TYPING); + } + } + if(!strcmp(content_type,"text/x-msnmsgr-datacast")){ + char *username, *str; + PurpleAccount *account; + PurpleBuddy *buddy; + const char *user; + + account = cmdproc->session->account; + user = msg->remote_user; + + if ((buddy = purple_find_buddy(account, user)) != NULL){ + username = g_markup_escape_text(purple_buddy_get_alias(buddy), -1); + }else{ + username = g_markup_escape_text(user, -1); + } + + str = g_strdup_printf(_("%s just sent you a Nudge!"), username); + g_free(username); + msn_session_report_user(cmdproc->session,user,str,PURPLE_MESSAGE_SYSTEM); + g_free(str); + } + msn_message_destroy(msg); +} + +/*Yahoo msg process*/ +static void +ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MSNP14","Processing UBM... \n"); + if(cmd->payload_len == 0){ + return; + } + /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued + * command and we are processing it */ + if (cmd->payload == NULL){ + cmdproc->last_cmd->payload_cb = ubm_cmd_post; + cmdproc->servconn->payload_len = atoi(cmd->params[2]); + }else{ + g_return_if_fail(cmd->payload_cb != NULL); + + purple_debug_info("MSNP14","UBM payload:{%s}\n",cmd->payload); + ubm_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len); + } +} + /************************************************************************** * Challenges + * we use MD5 to caculate the Challenges **************************************************************************/ - static void chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnTransaction *trans; char buf[33]; - const char *challenge_resp; - PurpleCipher *cipher; - PurpleCipherContext *context; - guchar digest[16]; - int i; +#if 0 cipher = purple_ciphers_find_cipher("md5"); context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, (const guchar *)cmd->params[1], strlen(cmd->params[1])); - - challenge_resp = "VT6PX?UQTM4WM%YR"; + challenge_resp = MSNP13_WLM_PRODUCT_KEY; purple_cipher_context_append(context, (const guchar *)challenge_resp, strlen(challenge_resp)); @@ -424,9 +561,14 @@ purple_cipher_context_destroy(context); for (i = 0; i < 16; i++) + { g_snprintf(buf + (i*2), 3, "%02x", digest[i]); - - trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9"); + } +#else + msn_handle_chl(cmd->params[1], buf); +#endif +// purple_debug_info("MSNP14","<<challenge:{%s}:{%s}\n",cmd->params[1],buf); + trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP13_WLM_PRODUCT_ID); msn_transaction_set_payload(trans, buf, 32); @@ -436,43 +578,303 @@ /************************************************************************** * Buddy Lists **************************************************************************/ +/* add contact to xmlnode */ +static void +msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport, MsnListOp list_op, MsnUserType type) +{ + xmlnode *d_node,*c_node; + char **tokens; + const char *email,*domain; + char fmt_str[3]; + + g_return_if_fail(passport != NULL); + + purple_debug_info("MSNP14","Passport: %s, type: %d\n", passport, type); + tokens = g_strsplit(passport, "@", 2); + email = tokens[0]; + domain = tokens[1]; + + if (email == NULL || domain == NULL) { + purple_debug_error("msn", "Invalid passport (%s) specified to add to contact xml.\n", passport); + g_strfreev(tokens); + g_return_if_reached(); + } + + /*find a domain Node*/ + for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node)) + { + const char *attr = xmlnode_get_attrib(d_node,"n"); + if (attr == NULL) + continue; + if (!strcmp(attr,domain)) + break; + } + + if(d_node == NULL) + { + /*domain not found, create a new domain Node*/ + purple_debug_info("msn", "Didn't find existing domain node, adding one.\n"); + d_node = xmlnode_new("d"); + xmlnode_set_attrib(d_node, "n", domain); + xmlnode_insert_child(mlNode, d_node); + } + + /*create contact node*/ + c_node = xmlnode_new("c"); + xmlnode_set_attrib(c_node, "n", email); + + purple_debug_info("MSNP14", "list_op: %d\n", list_op); + g_snprintf(fmt_str, sizeof(fmt_str), "%d", list_op); + xmlnode_set_attrib(c_node, "l", fmt_str); + + if (type != MSN_USER_TYPE_UNKNOWN) + g_snprintf(fmt_str, sizeof(fmt_str), "%d", type); + else if (msn_user_is_yahoo(session->account, passport)) + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_YAHOO); + else + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_PASSPORT); + + /*mobile*/ + //type_str = g_strdup_printf("4"); + xmlnode_set_attrib(c_node, "t", fmt_str); + + xmlnode_insert_child(d_node, c_node); + + g_strfreev(tokens); +} static void -add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len) +{ + MsnTransaction *trans; + purple_debug_info("MSN Notification","Sending ADL with payload: %s\n", payload); + trans = msn_transaction_new(cmdproc, "ADL","%d", strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + +/*dump contact info to NS*/ +void +msn_notification_dump_contact(MsnSession *session) +{ + MsnUser *user; + GList *l; + xmlnode *adl_node; + char *payload; + int payload_len; + int adl_count = 0; + const char *display_name; + + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + xmlnode_set_attrib(adl_node, "l", "1"); + + /*get the userlist*/ + for (l = session->userlist->users; l != NULL; l = l->next){ + user = l->data; + + /* skip RL & PL during initial dump */ + if (!(user->list_op & MSN_LIST_OP_MASK)) + continue; + + msn_add_contact_xml(session, adl_node, user->passport, + user->list_op & MSN_LIST_OP_MASK, user->type); + + /* each ADL command may contain up to 150 contacts */ + if (++adl_count % 150 == 0 || l->next == NULL) { + payload = xmlnode_to_str(adl_node,&payload_len); + + msn_notification_post_adl(session->notification->cmdproc, + payload, payload_len); + + g_free(payload); + xmlnode_free(adl_node); + + if (l->next) { + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + xmlnode_set_attrib(adl_node, "l", "1"); + } + } + } + + if (adl_count == 0) { + payload = xmlnode_to_str(adl_node,&payload_len); + + msn_notification_post_adl(session->notification->cmdproc, payload, payload_len); + + g_free(payload); + xmlnode_free(adl_node); + } + + display_name = purple_connection_get_display_name(session->account->gc); + if (display_name + && strcmp(display_name, + purple_account_get_username(session->account))) { + msn_act_id(session->account->gc, display_name); + } + +} + +/*Post FQY to NS,Inform add a Yahoo User*/ +void +msn_notification_send_fqy(MsnSession *session, const char *passport) +{ + MsnTransaction *trans; + MsnCmdProc *cmdproc; + char* email,*domain,*payload; + char **tokens; + + cmdproc = session->notification->cmdproc; + + tokens = g_strsplit(passport, "@", 2); + email = tokens[0]; + domain = tokens[1]; + + payload = g_strdup_printf("<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>", domain, email); + trans = msn_transaction_new(cmdproc, "FQY","%d", strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); + + g_free(payload); + g_free(tokens); +} + +static void +blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ +} + +static void +adl_cmd_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + xmlnode *root, *domain_node; + + 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; + xmlnode *contact_node = NULL; + + domain = xmlnode_get_attrib(domain_node, "n"); + + for (contact_node = xmlnode_get_child(domain_node, "c"); contact_node; contact_node = xmlnode_get_next_twin(contact_node)) { +// gchar *name = NULL, *friendlyname = NULL, *passport= NULL; + const gchar *list; + gint list_op = 0; + +// name = xmlnode_get_attrib(contact_node, "n"); + list = xmlnode_get_attrib(contact_node, "l"); + if (list != NULL) { + list_op = atoi(list); + } +// friendlyname = xmlnode_get_attrib(contact_node, "f"); + +// passport = g_strdup_printf("%s@%s", name, domain); + +// if (friendlyname != NULL) { +// decoded_friendlyname = g_strdup(purple_url_decode(friendlyname)); +// } else { +// decoded_friendlyname = g_strdup(passport); +// } + + if (list_op & MSN_LIST_RL_OP) { + /* someone is adding us */ +// got_new_entry(cmdproc->session->account->gc, passport, decoded_friendly_name); + msn_get_contact_list(cmdproc->session->contact, MSN_PS_PENDING_LIST, NULL); + } + +// g_free(decoded_friendly_name); +// g_free(passport); + } + } + + xmlnode_free(root); +} + +static void +adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - MsnUser *user; - const char *list; - const char *passport; - const char *friendly; - MsnListId list_id; - int group_id; - list = cmd->params[1]; - passport = cmd->params[3]; - friendly = purple_url_decode(cmd->params[4]); + g_return_if_fail(cmdproc != NULL); + g_return_if_fail(cmdproc->session != NULL); + g_return_if_fail(cmdproc->last_cmd != NULL); + g_return_if_fail(cmd != NULL); session = cmdproc->session; - user = msn_userlist_find_user(session->userlist, passport); + if ( !strcmp(cmd->params[1], "OK")) { + /* ADL ack */ + msn_session_finish_login(session); + } else { + cmdproc->last_cmd->payload_cb = adl_cmd_parse; + } + + return; +} - if (user == NULL) - { - user = msn_user_new(session->userlist, passport, friendly); - msn_userlist_add_user(session->userlist, user); - } - else - msn_user_set_friendly_name(user, friendly); +static void +adl_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) +{ + MsnSession *session; + PurpleAccount *account; + PurpleConnection *gc; + char *reason = NULL; + + session = cmdproc->session; + account = session->account; + gc = purple_account_get_connection(account); + + purple_debug_error("msn","ADL error\n"); + reason = g_strdup_printf(_("Unknown error (%d)"), error); + purple_notify_error(gc, NULL, _("Unable to add user"), reason); + g_free(reason); +} - list_id = msn_get_list_id(list); +static void +fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + purple_debug_info("MSN Notification","FQY payload:\n%s\n", payload); + g_return_if_fail(cmdproc->session != NULL); + g_return_if_fail(cmdproc->session->contact != NULL); +// msn_notification_post_adl(cmdproc, payload, len); +// msn_get_address_book(cmdproc->session->contact, MSN_AB_SAVE_CONTACT, NULL, NULL); +} - if (cmd->param_count >= 6) - group_id = atoi(cmd->params[5]); - else - group_id = -1; +static void +fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MSNP14","Process FQY\n"); + cmdproc->last_cmd->payload_cb = fqy_cmd_post; +} - msn_got_add_user(session, user, list_id, group_id); - msn_user_update(user); +static void +rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ +#if 0 + MsnTransaction *trans; + char * payload; +#endif + + purple_debug_info("MSNP14","Process RML\n"); +#if 0 + trans = msn_transaction_new(cmdproc, "RML",""); + + msn_transaction_set_payload(trans, payload, strlen(payload)); + + msn_cmdproc_send_trans(cmdproc, trans); +#endif } static void @@ -567,24 +969,22 @@ group_name = purple_url_decode(cmd->params[2]); - msn_group_new(session->userlist, group_id, group_name); + msn_group_new(session->userlist, cmd->params[3], group_name); - /* There is a user that must me moved to this group */ + /* There is a user that must be moved to this group */ if (cmd->trans->data) { /* msn_userlist_move_buddy(); */ MsnUserList *userlist = cmdproc->session->userlist; - MsnMoveBuddy *data = cmd->trans->data; + MsnCallbackState *data = cmd->trans->data; if (data->old_group_name != NULL) { - msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->old_group_name); + msn_userlist_move_buddy(userlist, data->who, data->old_group_name, group_name); g_free(data->old_group_name); + } else { + // msn_add_contact_to_group(userlist, data, data->who, group_name); } - - msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, group_name); - g_free(data->who); - } } @@ -642,6 +1042,7 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; + int wlmclient; const char *state, *passport, *friendly; session = cmdproc->session; @@ -650,7 +1051,9 @@ state = cmd->params[1]; passport = cmd->params[2]; - friendly = purple_url_decode(cmd->params[3]); + /*if a contact is actually on the WLM part or the yahoo part*/ + wlmclient = atoi(cmd->params[3]); + friendly = purple_url_decode(cmd->params[4]); user = msn_userlist_find_user(session->userlist, passport); @@ -658,9 +1061,9 @@ msn_user_set_friendly_name(user, friendly); - if (session->protocol_ver >= 9 && cmd->param_count == 6) + if (session->protocol_ver >= 9 && cmd->param_count == 8) { - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); + msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6])); msn_user_set_object(user, msnobj); } @@ -692,6 +1095,7 @@ MsnUser *user; MsnObject *msnobj; int clientid; + int wlmclient; const char *state, *passport, *friendly, *old_friendly; session = cmdproc->session; @@ -700,7 +1104,8 @@ state = cmd->params[0]; passport = cmd->params[1]; - friendly = purple_url_decode(cmd->params[2]); + wlmclient = atoi(cmd->params[2]); + friendly = purple_url_decode(cmd->params[3]); user = msn_userlist_find_user(session->userlist, passport); @@ -713,10 +1118,9 @@ if (session->protocol_ver >= 9) { - if (cmd->param_count == 5) + if (cmd->param_count == 7) { - msnobj = - msn_object_new_from_string(purple_url_decode(cmd->params[4])); + msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); msn_user_set_object(user, msnobj); } else @@ -725,7 +1129,7 @@ } } - clientid = atoi(cmd->params[3]); + clientid = atoi(cmd->params[4]); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE); msn_user_set_state(user, state); @@ -797,7 +1201,9 @@ prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session = cmdproc->session; - const char *type, *value; + const char *type, *value, *friendlyname; + + purple_debug_info("MSN Notification", "prp_cmd()\n"); g_return_if_fail(cmd->param_count >= 3); @@ -821,6 +1227,18 @@ msn_user_set_work_phone(session->user, NULL); else if (!strcmp(type, "PHM")) msn_user_set_mobile_phone(session->user, NULL); + else { + 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( + purple_account_get_connection(session->account), + friendlyname); + } + } } } @@ -828,11 +1246,10 @@ reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - int group_id; - const char *group_name; + const char *group_id, *group_name; session = cmdproc->session; - group_id = atoi(cmd->params[2]); + group_id = cmd->params[2]; group_name = purple_url_decode(cmd->params[3]); msn_userlist_rename_group_id(session->userlist, group_id, group_name); @@ -841,27 +1258,26 @@ static void reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { - int group_id; + const char * group_id; char **params; params = g_strsplit(trans->params, " ", 0); - group_id = atoi(params[0]); + group_id = params[0]; group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error); g_strfreev(params); } +#if 0 static void rem_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; MsnUser *user; - const char *list; - const char *passport; + const char *group_id, *list, *passport; MsnListId list_id; - int group_id; session = cmdproc->session; list = cmd->params[1]; @@ -873,22 +1289,23 @@ list_id = msn_get_list_id(list); if (cmd->param_count == 5) - group_id = atoi(cmd->params[4]); + group_id = cmd->params[4]; else - group_id = -1; + group_id = NULL; msn_got_rem_user(session, user, list_id, group_id); msn_user_update(user); } +#endif static void rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - int group_id; + const char *group_id; session = cmdproc->session; - group_id = atoi(cmd->params[2]); + group_id = cmd->params[2]; msn_userlist_remove_group_id(session->userlist, group_id); } @@ -896,18 +1313,19 @@ static void rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { - int group_id; + const char *group_id; char **params; params = g_strsplit(trans->params, " ", 0); - group_id = atoi(params[0]); + group_id = params[0]; group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error); g_strfreev(params); } +#if 0 static void syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { @@ -938,6 +1356,7 @@ session->sync = sync; cmdproc->cbs_table = sync->cbs_table; } +#endif /************************************************************************** * Misc commands @@ -1146,6 +1565,103 @@ g_free(host); } +static void +gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + xmlnode * root; + gchar * buf; + + g_return_if_fail(cmd->payload != NULL); + + if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL) + { + purple_debug_error("MSN","Unable to parse GCF payload into a XML tree"); + return; + } + + buf = xmlnode_to_formatted_str(root, NULL); + + /* get the payload content */ + purple_debug_info("MSNP14","GCF command payload:\n%s\n",buf); + + g_free(buf); + xmlnode_free(root); +} + +static void +gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MSNP14","Processing GCF command\n"); + cmdproc->last_cmd->payload_cb = gcf_cmd_post; + return; +} + +static void +sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MSNP14","Processing SBS... \n"); + if(cmd->payload_len == 0){ + return; + } + /*get the payload content*/ +} + +/* + * Get the UBX's PSM info + * Post it to the User status + * Thanks for Chris <ukdrizzle@yahoo.co.uk>'s code + */ +static void +ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + MsnSession *session; + PurpleAccount *account; + PurpleConnection *gc; + MsnUser *user; + const char *passport; + char *psm_str, *currentmedia_str, *str; + + /*get the payload content*/ +// purple_debug_info("MSNP14","UBX {%s} payload{%s}\n",cmd->params[0], cmd->payload); + + session = cmdproc->session; + account = session->account; + gc = purple_account_get_connection(account); + + passport = cmd->params[0]; + user = msn_userlist_find_user(session->userlist, passport); + + psm_str = msn_get_psm(cmd->payload,len); + currentmedia_str = msn_parse_currentmedia( + str = msn_get_currentmedia(cmd->payload, len)); + g_free(str); + + msn_user_set_statusline(user, psm_str); + msn_user_set_currentmedia(user, currentmedia_str); + msn_user_update(user); + + g_free(psm_str); + g_free(currentmedia_str); +} + +static void +ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_misc("MSNP14","UBX received.\n"); + if(cmd->payload_len == 0){ + return; + } + cmdproc->last_cmd->payload_cb = ubx_cmd_post; +} + +static void +uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_misc("MSNP14","UUX received.\n"); +} + /************************************************************************** * Message Types **************************************************************************/ @@ -1155,6 +1671,7 @@ { MsnSession *session; const char *value; + const char *clLastChange; session = cmdproc->session; @@ -1187,10 +1704,27 @@ } if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL) + { session->passport_info.client_port = ntohs(atoi(value)); + } if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL) session->passport_info.sl = atol(value); + + /*starting retrieve the contact list*/ + clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL); + session->contact = msn_contact_new(session); +#ifdef MSN_PARTIAL_LISTS + /* msn_userlist_load defeats all attempts at trying to detect blist sync issues */ + msn_userlist_load(session); + msn_get_contact_list(session->contact, MSN_PS_INITIAL, clLastChange); +#else + /* always get the full list? */ + msn_get_contact_list(session->contact, MSN_PS_INITIAL, NULL); +#endif +#if 0 + msn_contact_connect(session->contact); +#endif } static void @@ -1246,6 +1780,86 @@ g_hash_table_destroy(table); } +/*offline Message notification process*/ +static void +initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + MsnSession *session; + PurpleConnection *gc; + GHashTable *table; + const char *mdata, *unread; + + session = cmdproc->session; + gc = session->account->gc; + + if (strcmp(msg->remote_user, "Hotmail")) + /* This isn't an official message. */ + return; + + /*new a oim session*/ + session->oim = msn_oim_new(session); +// msn_oim_connect(session->oim); + + table = msn_message_get_hashtable_from_body(msg); + + mdata = g_hash_table_lookup(table, "Mail-Data"); + + if (mdata != NULL) + msn_parse_oim_msg(session->oim, mdata); + + if (g_hash_table_lookup(table, "Inbox-URL") == NULL) + { + g_hash_table_destroy(table); + return; + } + + if (session->passport_info.file == NULL) + { + MsnTransaction *trans; + trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); + msn_transaction_queue_cmd(trans, msg->cmd); + + msn_cmdproc_send_trans(cmdproc, trans); + + g_hash_table_destroy(table); + return; + } + + if (!purple_account_get_check_mail(session->account)) + { + g_hash_table_destroy(table); + return; + } + + unread = g_hash_table_lookup(table, "Inbox-Unread"); + + if (unread != NULL) + { + int count = atoi(unread); + + if (count > 0) + { + const char *passport; + const char *url; + + passport = msn_user_get_passport(session->user); + url = session->passport_info.file; + + purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL, + &passport, &url, NULL, NULL); + } + } + + g_hash_table_destroy(table); +} + +/*offline Message Notification*/ +static void +delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + purple_debug_misc("MSN Notification","Delete OIM message.\n"); +} + static void email_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { @@ -1347,48 +1961,62 @@ } void -msn_notification_add_buddy(MsnNotification *notification, const char *list, - const char *who, const char *store_name, - int group_id) +msn_notification_add_buddy_to_list(MsnNotification *notification, MsnListId list_id, + const char *who) { MsnCmdProc *cmdproc; + MsnListOp list_op = 1 << list_id; + xmlnode *adl_node; + char *payload; + int payload_len; + cmdproc = notification->servconn->cmdproc; - if (group_id < 0 && !strcmp(list, "FL")) - group_id = 0; + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + + msn_add_contact_xml(notification->session, adl_node, who, list_op, + MSN_USER_TYPE_PASSPORT); - if (group_id >= 0) - { - msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d", - list, who, store_name, group_id); - } - else - { - msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name); - } + 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); } void -msn_notification_rem_buddy(MsnNotification *notification, const char *list, - const char *who, int group_id) +msn_notification_rem_buddy_from_list(MsnNotification *notification, MsnListId list_id, + const char *who) { MsnCmdProc *cmdproc; + MsnTransaction *trans; + MsnListOp list_op = 1 << list_id; + xmlnode *rml_node; + char *payload; + int payload_len; + cmdproc = notification->servconn->cmdproc; - if (group_id >= 0) - { - msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id); - } - else - { - msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who); - } + rml_node = xmlnode_new("ml"); + rml_node->child = NULL; + + msn_add_contact_xml(notification->session, rml_node, who, list_op, MSN_USER_TYPE_PASSPORT); + + payload = xmlnode_to_str(rml_node, &payload_len); + xmlnode_free(rml_node); + + purple_debug_info("MSN Notification","Send RML with payload:\n%s\n", payload); + trans = msn_transaction_new(cmdproc, "RML","%d", strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); + g_free(payload); } /************************************************************************** * Init **************************************************************************/ - void msn_notification_init(void) { @@ -1399,18 +2027,18 @@ /* Synchronous */ msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL); msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd); - msn_table_add_cmd(cbs_table, "ADD", "ADD", add_cmd); - msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd); - msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd); + msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd); +// msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd); /* Removed as of MSNP13 */ msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd); - msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd); + msn_table_add_cmd(cbs_table, "USR", "GCF", gcf_cmd); +// msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd); /* Removed as of MSNP13 */ msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd); msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd); msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd); msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd); - /* msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); */ - msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL); + msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); +// msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL); msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd); msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd); msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd); @@ -1419,11 +2047,15 @@ /* Asynchronous */ msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd); msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd); + msn_table_add_cmd(cbs_table, NULL, "GCF", gcf_cmd); + msn_table_add_cmd(cbs_table, NULL, "SBS", sbs_cmd); msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd); msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd); - msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd); - msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd); + msn_table_add_cmd(cbs_table, NULL, "RML", rml_cmd); + msn_table_add_cmd(cbs_table, NULL, "ADL", adl_cmd); + msn_table_add_cmd(cbs_table, NULL, "FQY", fqy_cmd); msn_table_add_cmd(cbs_table, NULL, "QRY", NULL); msn_table_add_cmd(cbs_table, NULL, "QNG", qng_cmd); @@ -1433,11 +2065,15 @@ msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd); + msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd); + msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd); msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd); msn_table_add_error(cbs_table, "ADD", add_error); + msn_table_add_error(cbs_table, "ADL", adl_error); msn_table_add_error(cbs_table, "REG", reg_error); msn_table_add_error(cbs_table, "RMG", rmg_error); /* msn_table_add_error(cbs_table, "REA", rea_error); */ @@ -1446,12 +2082,24 @@ msn_table_add_msg_type(cbs_table, "text/x-msmsgsprofile", profile_msg); + /*initial OIM notification*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsinitialmdatanotification", + initial_mdata_msg); + /*OIM notification when user online*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsoimnotification", + initial_mdata_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgsinitialemailnotification", initial_email_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgsemailnotification", email_msg); + /*delete an offline Message notification*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsactivemailnotification", + delete_oim_msg); msn_table_add_msg_type(cbs_table, "application/x-msmsgssystemmessage", system_msg); @@ -1462,3 +2110,4 @@ { msn_table_destroy(cbs_table); } +
--- a/libpurple/protocols/msn/notification.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/notification.h Mon Oct 01 17:51:20 2007 +0000 @@ -24,6 +24,14 @@ #ifndef _MSN_NOTIFICATION_H_ #define _MSN_NOTIFICATION_H_ +/*MSN protocol challenge info*/ +/*MSNP13 challenge*/ +#define MSNP13_WLM_PRODUCT_KEY "O4BG@C7BWLYQX?5G" +#define MSNP13_WLM_PRODUCT_ID "PROD01065C%ZFN6F" + +#define MSNP10_PRODUCT_KEY "VT6PX?UQTM4WM%YR" +#define MSNP10_PRODUCT_ID "PROD0038W!61ZTF9" + typedef struct _MsnNotification MsnNotification; #include "session.h" @@ -40,21 +48,24 @@ }; #include "state.h" +void uum_send_msg(MsnSession *session,MsnMessage *msg); void msn_notification_end(void); void msn_notification_init(void); -void msn_notification_add_buddy(MsnNotification *notification, - const char *list, const char *who, - const char *store_name, int group_id); -void msn_notification_rem_buddy(MsnNotification *notification, - const char *list, const char *who, - int group_id); +void msn_notification_add_buddy_to_list(MsnNotification *notification, + MsnListId list_id, const char *who); +void msn_notification_rem_buddy_from_list(MsnNotification *notification, + MsnListId list_id, const char *who); + +void msn_notification_send_fqy(MsnSession *session, const char *passport); + MsnNotification *msn_notification_new(MsnSession *session); void msn_notification_destroy(MsnNotification *notification); gboolean msn_notification_connect(MsnNotification *notification, - const char *host, int port); + const char *host, int port); void msn_notification_disconnect(MsnNotification *notification); +void msn_notification_dump_contact(MsnSession *session); /** * Closes a notification.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.c Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,712 @@ +/** + * @file oim.c + * get and send MSN offline Instant Message via SOAP request + * Author + * MaYuan<mayuan2006@gmail.com> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msn.h" +#include "soap.h" +#include "oim.h" +#include "msnutils.h" + +/*Local Function Prototype*/ +static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid); +static MsnOimSendReq *msn_oim_new_send_req(const char *from_member, + const char *friendname, + const char* to_member, + gint send_seq, + const char *msg); +static void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn); +static void msn_oim_send_connect_init(MsnSoapConn *soapconn); +static void msn_oim_free_send_req(MsnOimSendReq *req); +static void msn_oim_report_to_user(MsnOim *oim, const char *msg_str); +static void msn_oim_get_process(MsnOim *oim, const char *oim_msg); +static char *msn_oim_msg_to_str(MsnOim *oim, const char *body); +static void msn_oim_send_process(MsnOim *oim, const char *body, int len); + +/*new a OIM object*/ +MsnOim * +msn_oim_new(MsnSession *session) +{ + MsnOim *oim; + + oim = g_new0(MsnOim, 1); + oim->session = session; + oim->retrieveconn = msn_soap_new(session,oim,1); + + oim->oim_list = NULL; + oim->sendconn = msn_soap_new(session,oim,1); + oim->run_id = rand_guid(); + oim->challenge = NULL; + oim->send_queue = g_queue_new(); + oim->send_seq = 1; + return oim; +} + +/*destroy the oim object*/ +void +msn_oim_destroy(MsnOim *oim) +{ + MsnOimSendReq *request; + + purple_debug_info("OIM","destroy the OIM \n"); + msn_soap_destroy(oim->retrieveconn); + msn_soap_destroy(oim->sendconn); + g_free(oim->run_id); + g_free(oim->challenge); + + while((request = g_queue_pop_head(oim->send_queue)) != NULL){ + msn_oim_free_send_req(request); + } + g_queue_free(oim->send_queue); + + g_free(oim); +} + +static MsnOimSendReq * +msn_oim_new_send_req(const char *from_member, const char*friendname, + const char* to_member, gint send_seq, + const char *msg) +{ + MsnOimSendReq *request; + + request = g_new0(MsnOimSendReq, 1); + request->from_member =g_strdup(from_member); + request->friendname = g_strdup(friendname); + request->to_member = g_strdup(to_member); + request->send_seq = send_seq; + request->oim_msg = g_strdup(msg); + return request; +} + +static void +msn_oim_free_send_req(MsnOimSendReq *req) +{ + g_return_if_fail(req != NULL); + + g_free(req->from_member); + g_free(req->friendname); + g_free(req->to_member); + g_free(req->oim_msg); + + g_free(req); +} + +/**************************************** + * OIM send SOAP request + * **************************************/ +/*encode the message to OIM Message Format*/ +static char * +msn_oim_msg_to_str(MsnOim *oim, const char *body) +{ + char *oim_body,*oim_base64; + + 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); + oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE, + oim->run_id,oim->send_seq,oim_base64); + + return oim_body; +} + +/*oim SOAP server login error*/ +static void +msn_oim_send_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) +{ + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + + msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); +} + +/*msn oim SOAP server connect process*/ +static gboolean +msn_oim_send_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) +{ + MsnSession * session; + MsnOim *oim; + + oim = soapconn->parent; + g_return_val_if_fail(oim != NULL, TRUE); + + session = oim->session; + g_return_val_if_fail(session != NULL, FALSE); + + return TRUE; +} + +/* + * Process the send return SOAP string + * If got SOAP Fault,get the lock key,and resend it. + */ +static void +msn_oim_send_process(MsnOim *oim, const char *body, int len) +{ + xmlnode *responseNode, *bodyNode; + xmlnode *faultNode, *faultCodeNode, *faultstringNode; + xmlnode *detailNode, *challengeNode; + char *faultCodeStr = NULL, *faultstring = NULL; + + responseNode = xmlnode_from_str(body,len); + g_return_if_fail(responseNode != NULL); + bodyNode = xmlnode_get_child(responseNode,"Body"); + faultNode = xmlnode_get_child(bodyNode,"Fault"); + if(faultNode == NULL){ + /*Send OK! return*/ + MsnOimSendReq *request; + + purple_debug_info("MSN OIM","send OIM OK!"); + xmlnode_free(responseNode); + request = g_queue_pop_head(oim->send_queue); + msn_oim_free_send_req(request); + /*send next buffered Offline Message*/ + msn_soap_post(oim->sendconn, NULL); + return; + } + /*get the challenge,and repost it*/ + faultCodeNode = xmlnode_get_child(faultNode,"faultcode"); + if(faultCodeNode == NULL){ + purple_debug_info("MSN OIM","faultcode Node is NULL\n"); + goto oim_send_process_fail; + } + faultCodeStr = xmlnode_get_data(faultCodeNode); + purple_debug_info("MSN OIM","fault code:{%s}\n",faultCodeStr); +#if 0 + if(!strcmp(faultCodeStr,"q0:AuthenticationFailed")){ + /*other Fault Reason?*/ + goto oim_send_process_fail; + } +#endif + + faultstringNode = xmlnode_get_child(faultNode,"faultstring"); + faultstring = xmlnode_get_data(faultstringNode); + purple_debug_info("MSN OIM","fault string :{%s}\n",faultstring); + + /* lock key fault reason, + * compute the challenge and resend it + */ + detailNode = xmlnode_get_child(faultNode, "detail"); + if(detailNode == NULL){ + goto oim_send_process_fail; + } + challengeNode = xmlnode_get_child(detailNode,"LockKeyChallenge"); + if (challengeNode == NULL) { + goto oim_send_process_fail; + } + + g_free(oim->challenge); + oim->challenge = xmlnode_get_data(challengeNode); + purple_debug_info("MSN OIM","lockkey:{%s}\n",oim->challenge); + + /*repost the send*/ + purple_debug_info("MSN OIM","prepare to repost the send...\n"); + msn_oim_send_msg(oim); + +oim_send_process_fail: + g_free(faultstring); + g_free(faultCodeStr); + xmlnode_free(responseNode); + return ; +} + +static gboolean +msn_oim_send_read_cb(MsnSoapConn *soapconn) +{ + MsnSession *session = soapconn->session; + MsnOim * oim; + + if (soapconn->body == NULL) + return TRUE; + + g_return_val_if_fail(session != NULL, FALSE); + oim = soapconn->session->oim; + g_return_val_if_fail(oim != NULL, TRUE); + + purple_debug_info("MSN OIM","read buffer:{%s}\n", soapconn->body); + msn_oim_send_process(oim,soapconn->body,soapconn->body_len); + + return TRUE; +} + +static void +msn_oim_send_written_cb(MsnSoapConn *soapconn) +{ + soapconn->read_cb = msn_oim_send_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +void +msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, + const char* friendname, const char *tomember, + const char * msg) +{ + MsnOimSendReq *request; + + g_return_if_fail(oim != NULL); + + request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg); + g_queue_push_tail(oim->send_queue,request); +} + +/*post send single message request to oim server*/ +void +msn_oim_send_msg(MsnOim *oim) +{ + MsnSoapReq *soap_request; + MsnOimSendReq *oim_request; + char *soap_body,*mspauth; + char *msg_body; + char buf[33]; + + g_return_if_fail(oim != NULL); + oim_request = g_queue_pop_head(oim->send_queue); + g_return_if_fail(oim_request != NULL); + + purple_debug_info("MSN OIM","send single OIM Message\n"); + mspauth = g_strdup_printf("t=%s&p=%s", + oim->session->passport_info.t, + oim->session->passport_info.p + ); + g_queue_push_head(oim->send_queue,oim_request); + + /* if we got the challenge lock key, we compute it + * else we go for the SOAP fault and resend it. + */ + if(oim->challenge != NULL){ + msn_handle_chl(oim->challenge, buf); + }else{ + purple_debug_info("MSN OIM","no lock key challenge,wait for SOAP Fault and Resend\n"); + buf[0]='\0'; + } + purple_debug_info("MSN OIM","get the lock key challenge {%s}\n",buf); + + msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); + soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE, + oim_request->from_member, + oim_request->friendname, + oim_request->to_member, + mspauth, + MSNP13_WLM_PRODUCT_ID, + buf, + oim_request->send_seq, + msg_body + ); + soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST, + MSN_OIM_SEND_URL, + MSN_OIM_SEND_SOAP_ACTION, + soap_body, + NULL, + msn_oim_send_read_cb, + msn_oim_send_written_cb, + msn_oim_send_connect_init); + g_free(mspauth); + g_free(msg_body); + g_free(soap_body); + + /*increase the offline Sequence control*/ + if(oim->challenge != NULL){ + oim->send_seq++; + } + msn_soap_post(oim->sendconn,soap_request); +} + +/**************************************** + * OIM delete SOAP request + * **************************************/ +static gboolean +msn_oim_delete_read_cb(MsnSoapConn *soapconn) +{ + if (soapconn->body == NULL) + return TRUE; + purple_debug_info("MSN OIM","OIM delete read buffer:{%s}\n",soapconn->body); + + msn_soap_free_read_buf(soapconn); + /*get next single Offline Message*/ +// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ + return TRUE; +} + +static void +msn_oim_delete_written_cb(MsnSoapConn *soapconn) +{ + soapconn->read_cb = msn_oim_delete_read_cb; +} + +/*Post to get the Offline Instant Message*/ +static void +msn_oim_post_delete_msg(MsnOim *oim,const char *msgid) +{ + MsnSoapReq *soap_request; + const char *soap_body,*t,*p; + + g_return_if_fail(oim != NULL); + g_return_if_fail(msgid != NULL); + + purple_debug_info("MSN OIM","Delete single OIM Message {%s}\n",msgid); + t = oim->session->passport_info.t; + p = oim->session->passport_info.p; + + soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, + t, + p, + msgid + ); + soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL, + MSN_OIM_DEL_SOAP_ACTION, + soap_body, + NULL, + msn_oim_delete_read_cb, + msn_oim_delete_written_cb, + msn_oim_retrieve_connect_init); + msn_soap_post(oim->retrieveconn,soap_request); +} + +/**************************************** + * OIM get SOAP request + * **************************************/ +/*oim SOAP server login error*/ +static void +msn_oim_get_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) +{ + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + msn_soap_clean_unhandled_requests(soapconn); + +// msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); +} + +/*msn oim SOAP server connect process*/ +static gboolean +msn_oim_get_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) +{ + MsnSession * session; + MsnOim *oim; + + oim = soapconn->parent; + g_return_val_if_fail(oim != NULL, TRUE); + + session = oim->session; + g_return_val_if_fail(session != NULL, FALSE); + + purple_debug_info("MSN OIM","Connected and ready to get OIM!\n"); + + return TRUE; +} + +/* like purple_str_to_time, but different. The format of the timestamp + * is like this: 5 Sep 2007 21:42:12 -0700 */ +static time_t +msn_oim_parse_timestamp(const char *timestamp) +{ + char month_str[4], tz_str[6]; + char *tz_ptr = tz_str; + static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL + }; + struct tm t; + memset(&t, 0, sizeof(t)); + + if (sscanf(timestamp, "%02d %03s %04d %02d:%02d:%02d %05s", + &t.tm_mday, month_str, &t.tm_year, + &t.tm_hour, &t.tm_min, &t.tm_sec, tz_str) == 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++); + if (months[t.tm_mon] != NULL) { + if (*tz_str == '-') { + offset_positive = FALSE; + tz_ptr++; + } else if (*tz_str == '+') { + tz_ptr++; + } + + if (sscanf(tz_ptr, "%02d%02d", &tzhrs, &tzmins) == 2) { + time_t tzoff = tzhrs * 60 * 60 + tzmins * 60; +#ifdef _WIN32 + long sys_tzoff; +#endif + + if (!offset_positive) + tzoff *= -1; + + t.tm_year -= 1900; + t.tm_isdst = 0; + +#ifdef _WIN32 + if ((sys_tzoff = wpurple_get_tz_offset()) != -1) + tzoff += sys_tzoff; +#else +#ifdef HAVE_TM_GMTOFF + tzoff += t.tm_gmtoff; +#else +# ifdef HAVE_TIMEZONE + tzset(); /* making sure */ + tzoff -= timezone; +# endif +#endif +#endif /* _WIN32 */ + + return mktime(&t) + tzoff; + } + } + } + + purple_debug_info("MSN OIM:OIM", "Can't parse timestamp %s\n", timestamp); + return time(NULL); +} + +/*Post the Offline Instant Message to User Conversation*/ +static void +msn_oim_report_to_user(MsnOim *oim, const char *msg_str) +{ + MsnMessage *message; + char *date,*from,*decode_msg; + gsize body_len; + char **tokens; + char *start,*end; + int has_nick = 0; + char *passport_str, *passport; + char *msg_id; + time_t stamp; + + message = msn_message_new(MSN_MSG_UNKNOWN); + + msn_message_parse_payload(message, msg_str, strlen(msg_str), + MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); + purple_debug_info("MSN OIM","oim body:{%s}\n",message->body); + decode_msg = (char *)purple_base64_decode(message->body,&body_len); + date = (char *)g_hash_table_lookup(message->attr_table, "Date"); + from = (char *)g_hash_table_lookup(message->attr_table, "From"); + if(strstr(from," ")){ + has_nick = 1; + } + if(has_nick){ + tokens = g_strsplit(from , " " , 2); + passport_str = g_strdup(tokens[1]); + purple_debug_info("MSN OIM","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", + date,tokens[0],tokens[1],passport_str); + g_strfreev(tokens); + }else{ + passport_str = g_strdup(from); + purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n", + date,passport_str); + } + start = strstr(passport_str,"<"); + start += 1; + end = strstr(passport_str,">"); + passport = g_strndup(start,end - start); + g_free(passport_str); + purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n",date,passport); + + stamp = msn_oim_parse_timestamp(date); + + serv_got_im(oim->session->account->gc, passport, decode_msg, 0, stamp); + + /*Now get the oim message ID from the oim_list. + * and append to read list to prepare for deleting the Offline Message when sign out + */ + if(oim->oim_list != NULL){ + msg_id = oim->oim_list->data; + msn_oim_post_delete_msg(oim,msg_id); + oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data); + g_free(msg_id); + } + + g_free(passport); +} + +/* Parse the XML data, + * prepare to report the OIM to user + */ +static void +msn_oim_get_process(MsnOim *oim, const char *oim_msg) +{ + xmlnode *oim_node,*bodyNode,*responseNode,*msgNode; + char *msg_str; + + oim_node = xmlnode_from_str(oim_msg, strlen(oim_msg)); + bodyNode = xmlnode_get_child(oim_node,"Body"); + responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse"); + msgNode = xmlnode_get_child(responseNode,"GetMessageResult"); + msg_str = xmlnode_get_data(msgNode); + purple_debug_info("OIM","msg:{%s}\n",msg_str); + msn_oim_report_to_user(oim,msg_str); + + g_free(msg_str); + xmlnode_free(oim_node); +} + +static gboolean +msn_oim_get_read_cb(MsnSoapConn *soapconn) +{ + MsnOim * oim = soapconn->session->oim; + + if (soapconn->body == NULL) + return TRUE; + + purple_debug_info("MSN OIM","OIM get read buffer:{%s}\n",soapconn->body); + + /*we need to process the read message!*/ + msn_oim_get_process(oim,soapconn->body); + msn_soap_free_read_buf(soapconn); + + /*get next single Offline Message*/ +// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ + return TRUE; +} + +static void +msn_oim_get_written_cb(MsnSoapConn *soapconn) +{ + soapconn->read_cb = msn_oim_get_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/* parse the oim XML data + * and post it to the soap server to get the Offline Message + * */ +void +msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) +{ + xmlnode *node, *mNode,*ENode,*INode,*rtNode,*nNode; + char *passport,*msgid,*nickname, *unread, *rTime = NULL; + MsnSession *session = oim->session; + + purple_debug_info("MSN OIM:OIM", "%s", xmlmsg); + + node = xmlnode_from_str(xmlmsg, strlen(xmlmsg)); + if (strcmp(node->name, "MD") != 0) { + xmlnode_free(node); + return; + } + + ENode = xmlnode_get_child(node, "E"); + INode = xmlnode_get_child(ENode, "IU"); + unread = xmlnode_get_data(INode); + + if (unread != NULL && purple_account_get_check_mail(session->account)) + { + int count = atoi(unread); + + if (count > 0) + { + const char *passport; + const char *url; + + passport = msn_user_get_passport(session->user); + url = session->passport_info.file; + + purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL, + &passport, &url, NULL, NULL); + } + } + + for(mNode = xmlnode_get_child(node, "M"); mNode; + mNode = xmlnode_get_next_twin(mNode)){ + /*email Node*/ + ENode = xmlnode_get_child(mNode,"E"); + passport = xmlnode_get_data(ENode); + /*Index */ + INode = xmlnode_get_child(mNode,"I"); + msgid = xmlnode_get_data(INode); + /*Nickname*/ + nNode = xmlnode_get_child(mNode,"N"); + nickname = xmlnode_get_data(nNode); + /*receive time*/ + rtNode = xmlnode_get_child(mNode,"RT"); + if(rtNode != NULL) { + rTime = xmlnode_get_data(rtNode); + rtNode = NULL; + } +/* purple_debug_info("MSN OIM","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + + oim->oim_list = g_list_append(oim->oim_list,strdup(msgid)); + msn_oim_post_single_get_msg(oim,msgid); + g_free(passport); + g_free(msgid); + g_free(rTime); + rTime = NULL; + g_free(nickname); + } + g_free(unread); + xmlnode_free(node); +} + +/*Post to get the Offline Instant Message*/ +static void +msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid) +{ + MsnSoapReq *soap_request; + const char *soap_body,*t,*p; + + purple_debug_info("MSN OIM","Get single OIM Message\n"); + t = oim->session->passport_info.t; + p = oim->session->passport_info.p; + + soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, + t, + p, + msgid + ); + soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL, + MSN_OIM_GET_SOAP_ACTION, + soap_body, + NULL, + msn_oim_get_read_cb, + msn_oim_get_written_cb, + msn_oim_retrieve_connect_init); + msn_soap_post(oim->retrieveconn,soap_request); +} + +/*msn oim retrieve server connect init */ +static void +msn_oim_retrieve_connect_init(MsnSoapConn *soapconn) +{ + purple_debug_info("MSN OIM","Initializing OIM retrieve connection\n"); + msn_soap_init(soapconn, MSN_OIM_RETRIEVE_HOST, 1, + msn_oim_get_connect_cb, + msn_oim_get_error_cb); +} + +/*Msn OIM Send Server Connect Init Function*/ +static void +msn_oim_send_connect_init(MsnSoapConn *sendconn) +{ + purple_debug_info("MSN OIM","Initializing OIM send connection\n"); + msn_soap_init(sendconn, MSN_OIM_SEND_HOST, 1, + msn_oim_send_connect_cb, + msn_oim_send_error_cb); +} + +/* EOF oim.c*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.h Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,148 @@ +/** + * @file oim.h Header file for oim.c + * Author + * MaYuan<mayuan2006@gmail.com> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_OIM_H_ +#define _MSN_OIM_H_ + +/*OIM Retrieve SOAP Template*/ +#define MSN_OIM_RETRIEVE_HOST "rsi.hotmail.com" +#define MSN_OIM_RETRIEVE_URL "/rsi/rsi.asmx" +#define MSN_OIM_GET_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage" + +#define MSN_OIM_GET_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<soap:Header>"\ + "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ + "<t>%s</t>"\ + "<p>%s</p>"\ + "</PassportCookie>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<GetMessage xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ + "<messageId>%s</messageId>"\ + "<alsoMarkAsRead>false</alsoMarkAsRead>"\ + "</GetMessage>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/*OIM Delete SOAP Template*/ +#define MSN_OIM_DEL_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages" + +#define MSN_OIM_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<soap:Header>"\ + "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ + "<t>%s</t>"\ + " <p>%s</p>"\ + "</PassportCookie>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<DeleteMessages xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ + "<messageIds>"\ + "<messageId>%s</messageId>"\ + "</messageIds>"\ + "</DeleteMessages>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/*OIM Send SOAP Template*/ +#define MSN_OIM_MSG_TEMPLATE "MIME-Version: 1.0\n"\ + "Content-Type: text/plain; charset=UTF-8\n"\ + "Content-Transfer-Encoding: base64\n"\ + "X-OIM-Message-Type: OfflineMessage\n"\ + "X-OIM-Run-Id: {%s}\n"\ + "X-OIM-Sequence-Num: %d\n\n"\ + "%s" + +#define MSN_OIM_SEND_HOST "ows.messenger.msn.com" +#define MSN_OIM_SEND_URL "/OimWS/oim.asmx" +#define MSN_OIM_SEND_SOAP_ACTION "http://messenger.msn.com/ws/2004/09/oim/Store" +#define MSN_OIM_SEND_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<soap:Header>"\ + "<From memberName=\"%s\" friendlyName=\"%s\" xml:lang=\"en-US\" proxy=\"MSNMSGR\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\" msnpVer=\"MSNP14\" buildVer=\"8.0.0792\"/>"\ + "<To memberName=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ + "<Ticket passport=\"%s\" appid=\"%s\" lockkey=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ + "<Sequence xmlns=\"http://schemas.xmlsoap.org/ws/2003/03/rm\">"\ + "<Identifier xmlns=\"http://schemas.xmlsoap.org/ws/2002/07/utility\">http://messenger.msn.com</Identifier>"\ + "<MessageNumber>%d</MessageNumber>"\ + "</Sequence>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<MessageType xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">text</MessageType>"\ + "<Content xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">%s</Content>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +typedef struct _MsnOimSendReq MsnOimSendReq; + +struct _MsnOimSendReq +{ + char *from_member; + char *friendname; + char *to_member; + char *oim_msg; + gint send_seq; +}; + +typedef struct _MsnOim MsnOim; + +struct _MsnOim +{ + MsnSession *session; + + MsnSoapConn *retrieveconn; + GList * oim_list; + + MsnSoapConn *sendconn; + char *challenge; + char *run_id; + gint send_seq; + GQueue *send_queue; +}; + +/**************************************************** + * function prototype + * **************************************************/ +MsnOim * msn_oim_new(MsnSession *session); +void msn_oim_destroy(MsnOim *oim); +void msn_oim_connect(MsnOim *oim); + +void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg); + +/*Send OIM Message*/ +void msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, + const char *friendname, const char *tomember, + const char * msg); + +void msn_oim_send_msg(MsnOim *oim); + +/*get the OIM message*/ +void msn_oim_get_msg(MsnOim *oim); + +/*report the oim message to the conversation*/ +void msn_oim_report_user(MsnOim *oim,const char *passport,char *msg); + +#endif/* _MSN_OIM_H_*/ +/*endof oim.h*/
--- a/libpurple/protocols/msn/servconn.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Mon Oct 01 17:51:20 2007 +0000 @@ -168,7 +168,7 @@ **************************************************************************/ static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, const char *error_message) { MsnServConn *servconn; @@ -245,7 +245,9 @@ return TRUE; } else + { return FALSE; + } } void @@ -390,14 +392,21 @@ len = read(servconn->fd, buf, sizeof(buf) - 1); - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0) - { - purple_debug_error("msn", "servconn read error, len: %d error: %s\n", len, strerror(errno)); - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ); + if (len <= 0) { + switch (errno) { + + case 0: - return; + case EBADF: + case EAGAIN: return; + + default: purple_debug_error("msn", "servconn read error," + "len: %d, errno: %d, error: %s\n", + len, errno, strerror(errno)); + msn_servconn_got_error(servconn, + MSN_SERVCONN_ERROR_READ); + return; + } } buf[len] = '\0'; @@ -446,6 +455,7 @@ else { msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); + servconn->payload_len = servconn->cmdproc->last_cmd->payload_len; } } while (servconn->connected && !servconn->wasted && servconn->rx_len > 0);
--- a/libpurple/protocols/msn/session.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/session.c Mon Oct 01 17:51:20 2007 +0000 @@ -43,7 +43,9 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); - session->protocol_ver = 9; + /*if you want to chat with Yahoo Messenger*/ + //session->protocol_ver = WLM_YAHOO_PROT_VER; + session->protocol_ver = WLM_PROT_VER; session->conv_seq = 1; return session; @@ -70,6 +72,8 @@ msn_userlist_destroy(session->userlist); + g_free(session->passport_info.t); + g_free(session->passport_info.p); g_free(session->passport_info.kv); g_free(session->passport_info.sid); g_free(session->passport_info.mspauth); @@ -87,6 +91,11 @@ if (session->nexus != NULL) msn_nexus_destroy(session->nexus); + if (session->contact != NULL) + msn_contact_destroy(session->contact); + if (session->oim != NULL) + msn_oim_destroy(session->oim); + if (session->user != NULL) msn_user_destroy(session->user); @@ -154,6 +163,37 @@ return NULL; } +static PurpleConversation * +msn_session_get_conv(MsnSession *session,const char *passport) +{ + PurpleAccount *account; + PurpleConversation * conv; + + g_return_val_if_fail(session != NULL, NULL); + account = session->account; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + passport, account); + if(conv == NULL){ + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, passport); + } + return conv; +} + +/* put Message to User Conversation + * + * passport - the one want to talk to you + */ +void +msn_session_report_user(MsnSession *session,const char *passport,char *msg,PurpleMessageFlags flags) +{ + PurpleConversation * conv; + + if ((conv = msn_session_get_conv(session,passport)) != NULL){ + purple_conversation_write(conv, NULL, msg, flags, time(NULL)); + } +} + MsnSwitchBoard * msn_session_find_swboard_with_conv(MsnSession *session, PurpleConversation *conv) { @@ -229,13 +269,14 @@ /* The core used to use msn_add_buddy to add all buddies before * being logged in. This no longer happens, so we manually iterate - * over the whole buddy list to identify sync issues. */ - - for (gnode = purple_blist_get_root(); gnode; gnode = gnode->next) { + * over the whole buddy list to identify sync issues. + */ + for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) { PurpleGroup *group = (PurpleGroup *)gnode; - const char *group_name = group->name; + const char *group_name; if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue; + group_name = group->name; for(cnode = gnode->child; cnode; cnode = cnode->next) { if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue; @@ -252,21 +293,17 @@ if ((remote_user != NULL) && (remote_user->list_op & MSN_LIST_FL_OP)) { - int group_id; GList *l; - group_id = msn_userlist_find_group_id(remote_user->userlist, - group_name); - for (l = remote_user->group_ids; l != NULL; l = l->next) { - if (group_id == GPOINTER_TO_INT(l->data)) + const char *name = msn_userlist_find_group_name(remote_user->userlist, l->data); + if (name && !g_strcasecmp(group_name, name)) { found = TRUE; break; } } - } if (!found) @@ -305,6 +342,8 @@ case MSN_ERROR_SIGN_OTHER: gc->wants_to_die = TRUE; msg = g_strdup(_("You have signed on from another location.")); + if (!purple_account_get_remember_password(session->account)) + purple_account_set_password(session->account, NULL); break; case MSN_ERROR_SERV_UNAVAILABLE: msg = g_strdup(_("The MSN servers are temporarily " @@ -419,3 +458,4 @@ msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX"); } } +
--- a/libpurple/protocols/msn/session.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/session.h Mon Oct 01 17:51:20 2007 +0000 @@ -38,6 +38,8 @@ #include "cmdproc.h" #include "nexus.h" #include "httpconn.h" +#include "contact.h" +#include "oim.h" #include "userlist.h" #include "sync.h" @@ -94,6 +96,8 @@ MsnNotification *notification; MsnNexus *nexus; + MsnContact *contact; + MsnOim *oim; MsnSync *sync; MsnUserList *userlist; @@ -105,8 +109,15 @@ int conv_seq; /**< The current conversation sequence number. */ + /*psm info*/ + char *psm; + struct { + /*t and p, get via USR TWN*/ + char *t; + char *p; + char *kv; char *sid; char *mspauth; @@ -114,7 +125,6 @@ char *file; char *client_ip; int client_port; - } passport_info; }; @@ -224,4 +234,8 @@ */ void msn_session_finish_login(MsnSession *session); +/*post message to User*/ +void msn_session_report_user(MsnSession *session,const char *passport, + char *msg,PurpleMessageFlags flags); + #endif /* _MSN_SESSION_H_ */
--- a/libpurple/protocols/msn/slp.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Mon Oct 01 17:51:20 2007 +0000 @@ -33,6 +33,8 @@ /* ms to delay between sending buddy icon requests to the server. */ #define BUDDY_ICON_DELAY 20000 +/*debug SLP*/ +#define MSN_DEBUG_UD static void send_ok(MsnSlpCall *slpcall, const char *branch, const char *type, const char *content); @@ -777,11 +779,11 @@ if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) { /* FIXME: it would be better if we wrote the data as we received it - instead of all at once, calling write multiple times and - close once at the very end - */ + instead of all at once, calling write multiple times and + close once at the very end + */ purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); - purple_conv_custom_smiley_close(conv, slpcall->data_info); + purple_conv_custom_smiley_close(conv, slpcall->data_info ); } #ifdef MSN_DEBUG_UD purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info);
--- a/libpurple/protocols/msn/slpcall.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/slpcall.c Mon Oct 01 17:51:20 2007 +0000 @@ -22,6 +22,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" +#include "msnutils.h" #include "slpcall.h" #include "slpsession.h" @@ -30,24 +31,6 @@ /* #define MSN_DEBUG_SLPCALL */ /************************************************************************** - * Util - **************************************************************************/ - -static char * -rand_guid() -{ - return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111); -} - -/************************************************************************** * Main **************************************************************************/
--- a/libpurple/protocols/msn/slplink.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Mon Oct 01 17:51:20 2007 +0000 @@ -112,8 +112,10 @@ if (slplink->remote_user != NULL) g_free(slplink->remote_user); +#if 0 if (slplink->directconn != NULL) msn_directconn_destroy(slplink->directconn); +#endif while (slplink->slp_calls != NULL) msn_slp_call_destroy(slplink->slp_calls->data); @@ -244,11 +246,13 @@ void msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg) { +#if 0 if (slplink->directconn != NULL) { msn_directconn_send_msg(slplink->directconn, msg); } else +#endif { if (slplink->swboard == NULL) { @@ -634,9 +638,10 @@ MsnDirectConn *directconn; directconn = slplink->directconn; - +#if 0 if (!directconn->acked) msn_directconn_send_handshake(directconn); +#endif } else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.c Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,870 @@ +/** + * @file soap.c + * SOAP connection related process + * Author + * MaYuan<mayuan2006@gmail.com> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msn.h" +#include "soap.h" + + +/*local function prototype*/ +void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step); + +/*setup the soap process step*/ +void +msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step) +{ +#ifdef MSN_SOAP_DEBUG + const char *MsnSoapStepText[] = + { + "Unconnected", + "Connecting", + "Connected", + "Processing", + "Connected Idle" + }; + + purple_debug_info("MSN SOAP", "Setting SOAP process step to %s\n", MsnSoapStepText[step]); +#endif + soapconn->step = step; +} + +//msn_soap_new(MsnSession *session,gpointer data,int sslconn) +/*new a soap connection*/ +MsnSoapConn * +msn_soap_new(MsnSession *session,gpointer data,int sslconn) +{ + MsnSoapConn *soapconn; + + soapconn = g_new0(MsnSoapConn, 1); + soapconn->session = session; + soapconn->parent = data; + soapconn->ssl_conn = sslconn; + + soapconn->gsc = NULL; + soapconn->input_handler = 0; + soapconn->output_handler = 0; + + msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); + soapconn->soap_queue = g_queue_new(); + + return soapconn; +} + +/*ssl soap connect callback*/ +void +msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn * soapconn; + MsnSession *session; + gboolean soapconn_is_valid = FALSE; + + purple_debug_misc("MSN SOAP","SOAP server connection established!\n"); + + soapconn = data; + g_return_if_fail(soapconn != NULL); + + session = soapconn->session; + g_return_if_fail(session != NULL); + + soapconn->gsc = gsc; + + msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED); + + /*connection callback*/ + if (soapconn->connect_cb != NULL) { + soapconn_is_valid = soapconn->connect_cb(soapconn, gsc); + } + + if (!soapconn_is_valid) { + return; + } + + /*we do the SOAP request here*/ + msn_soap_post_head_request(soapconn); +} + +/*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); + + purple_debug_warning("MSN SOAP","Soap connection error!\n"); + + msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); + + /*error callback*/ + if (soapconn->error_cb != NULL) { + soapconn->error_cb(soapconn, gsc, error); + } else { + msn_soap_post(soapconn, NULL); + } +} + +/*init the soap connection*/ +void +msn_soap_init(MsnSoapConn *soapconn,char * host,int ssl, + MsnSoapSslConnectCbFunction connect_cb, + MsnSoapSslErrorCbFunction error_cb) +{ + purple_debug_misc("MSN SOAP","Initializing SOAP connection\n"); + soapconn->login_host = g_strdup(host); + soapconn->ssl_conn = ssl; + soapconn->connect_cb = connect_cb; + soapconn->error_cb = error_cb; +} + +/*connect the soap connection*/ +void +msn_soap_connect(MsnSoapConn *soapconn) +{ + if (soapconn->ssl_conn) { + purple_ssl_connect(soapconn->session->account, soapconn->login_host, + PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, msn_soap_error_cb, + soapconn); + } else { + } + + msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTING); +} + + +static void +msn_soap_close_handler(guint *handler) +{ + if (*handler > 0) { + purple_input_remove(*handler); + *handler = 0; + } +#ifdef MSN_SOAP_DEBUG + else { + purple_debug_misc("MSN SOAP", "Handler inactive, not removing\n"); + } +#endif + +} + + +/*close the soap connection*/ +void +msn_soap_close(MsnSoapConn *soapconn) +{ + if (soapconn->ssl_conn) { + if (soapconn->gsc != NULL) { + purple_ssl_close(soapconn->gsc); + soapconn->gsc = NULL; + } + } else { + } + msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); +} + +/*clean the unhandled SOAP request*/ +void +msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn) +{ + MsnSoapReq *request; + + g_return_if_fail(soapconn != NULL); + + soapconn->body = NULL; + + while ((request = g_queue_pop_head(soapconn->soap_queue)) != NULL){ + if (soapconn->read_cb) { + soapconn->read_cb(soapconn); + } + msn_soap_request_free(request); + } +} + +/*destroy the soap connection*/ +void +msn_soap_destroy(MsnSoapConn *soapconn) +{ + if(soapconn->login_host) + g_free(soapconn->login_host); + + if(soapconn->login_path) + g_free(soapconn->login_path); + + /*remove the write handler*/ + if (soapconn->output_handler > 0){ + purple_input_remove(soapconn->output_handler); + soapconn->output_handler = 0; + } + /*remove the read handler*/ + if (soapconn->input_handler > 0){ + purple_input_remove(soapconn->input_handler); + soapconn->input_handler = 0; + } + msn_soap_free_read_buf(soapconn); + msn_soap_free_write_buf(soapconn); + + /*close ssl connection*/ + msn_soap_close(soapconn); + + /*process the unhandled soap request*/ + msn_soap_clean_unhandled_requests(soapconn); + + g_queue_free(soapconn->soap_queue); + g_free(soapconn); +} + +/*check the soap is connected? + * if connected return 1 + */ +int +msn_soap_connected(MsnSoapConn *soapconn) +{ + if (soapconn->ssl_conn) { + return (soapconn->gsc == NULL ? 0 : 1); + } + return (soapconn->fd > 0 ? 1 : 0); +} + +/*read and append the content to the buffer*/ +static gssize +msn_soap_read(MsnSoapConn *soapconn) +{ + 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; + } + else { + requested_len = soapconn->need_to_read; + } + + if ( soapconn->ssl_conn ) { + len = purple_ssl_read(soapconn->gsc, temp_buf, requested_len); + } else { + len = read(soapconn->fd, temp_buf, requested_len); + } + + + if ( len <= 0 ) { + switch (errno) { + + case 0: + case EBADF: /* we are sometimes getting this in Windows */ + case EAGAIN: return len; + + default : purple_debug_error("MSN SOAP", "Read error!" + "read len: %d, error = %s\n", + len, strerror(errno)); + purple_input_remove(soapconn->input_handler); + //soapconn->input_handler = 0; + g_free(soapconn->read_buf); + soapconn->read_buf = NULL; + soapconn->read_len = 0; + /* TODO: error handling */ + return len; + } + } + else { + soapconn->read_buf = g_realloc(soapconn->read_buf, + soapconn->read_len + len + 1); + if ( soapconn->read_buf != NULL ) { + memcpy(soapconn->read_buf + soapconn->read_len, temp_buf, len); + soapconn->read_len += len; + soapconn->read_buf[soapconn->read_len] = '\0'; + } + else { + purple_debug_error("MSN SOAP", "Failure re-allocating %d bytes of memory!\n", soapconn->read_len + len + 1); + exit(EXIT_FAILURE); + } + + } + +#if defined(MSN_SOAP_DEBUG) + if (len > 0) + purple_debug_info("MSN SOAP","Read %d bytes from SOAP server:\n%s\n", len, soapconn->read_buf + soapconn->read_len - len); +#endif + + return len; +} + +/*read the whole SOAP server response*/ +void +msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnSession *session; + int len; + char * body_start,*body_len; + char *length_start,*length_end; +#ifdef MSN_SOAP_DEBUG +#if !defined(_WIN32) + gchar * formattedxml = NULL; + gchar * http_headers = NULL; + xmlnode * node = NULL; +#endif + purple_debug_misc("MSN SOAP", "msn_soap_read_cb()\n"); +#endif + session = soapconn->session; + g_return_if_fail(session != NULL); + + + /*read the request header*/ + len = msn_soap_read(soapconn); + + if ( len < 0 ) + return; + + if (soapconn->read_buf == NULL) { + return; + } + + if ( (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) + || ( strstr(soapconn->read_buf, "HTTP/1.1 301") != NULL ) ) + { + /* Redirect. */ + char *location, *c; + + purple_debug_info("MSN SOAP", "HTTP Redirect\n"); + location = strstr(soapconn->read_buf, "Location: "); + if (location == NULL) + { + c = (char *) g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n"); + if (c != NULL) { + /* we have read the whole HTTP headers and found no Location: */ + msn_soap_free_read_buf(soapconn); + msn_soap_post(soapconn, NULL); + } + + return; + } + location = strchr(location, ' ') + 1; + + if ((c = strchr(location, '\r')) != NULL) + *c = '\0'; + else + return; + + /* Skip the http:// */ + if ((c = strchr(location, '/')) != NULL) + location = c + 2; + + if ((c = strchr(location, '/')) != NULL) + { + g_free(soapconn->login_path); + soapconn->login_path = g_strdup(c); + + *c = '\0'; + } + + 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); + } + } + /* Another case of redirection, active on May, 2007 + See http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener#Redirect + */ + else if (strstr(soapconn->read_buf, + "<faultcode>psf:Redirect</faultcode>") != NULL) + { + char *location, *c; + + if ( (location = strstr(soapconn->read_buf, "<psf:redirectUrl>") ) == NULL) + return; + + /* Omit the tag preceding the URL */ + location += strlen("<psf:redirectUrl>"); + if (location > soapconn->read_buf + soapconn->read_len) + return; + if ( (location = strstr(location, "://")) == NULL) + return; + + location += strlen("://"); /* Skip http:// or https:// */ + + if ( (c = strstr(location, "</psf:redirectUrl>")) != NULL ) + *c = '\0'; + else + return; + + if ( (c = strstr(location, "/")) != NULL ) + { + g_free(soapconn->login_path); + soapconn->login_path = g_strdup(c); + *c = '\0'; + } + + 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); + } + } + else if (strstr(soapconn->read_buf, "HTTP/1.1 401 Unauthorized") != NULL) + { + const char *error; + + purple_debug_error("MSN SOAP", "Received HTTP error 401 Unauthorized\n"); + if ((error = strstr(soapconn->read_buf, "WWW-Authenticate")) != NULL) + { + if ((error = strstr(error, "cbtxt=")) != NULL) + { + const char *c; + char *temp; + + error += strlen("cbtxt="); + + if ((c = strchr(error, '\n')) == NULL) + c = error + strlen(error); + + temp = g_strndup(error, c - error); + error = purple_url_decode(temp); + g_free(temp); + } + } + + msn_session_set_error(session, MSN_ERROR_AUTH, error); + } + /* Handle Passport 3.0 authentication failures. + * Further info: http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener + */ + else if (strstr(soapconn->read_buf, + "<faultcode>wsse:FailedAuthentication</faultcode>") != NULL) + { + gchar *faultstring; + + faultstring = strstr(soapconn->read_buf, "<faultstring>"); + + if (faultstring != NULL) + { + gchar *c; + faultstring += strlen("<faultstring>"); + if (faultstring < soapconn->read_buf + soapconn->read_len) { + c = strstr(soapconn->read_buf, "</faultstring>"); + if (c != NULL) { + *c = '\0'; + msn_session_set_error(session, MSN_ERROR_AUTH, faultstring); + } + } + } + + } + else if (strstr(soapconn->read_buf, "HTTP/1.1 503 Service Unavailable")) + { + msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL); + } + else if ((strstr(soapconn->read_buf, "HTTP/1.1 200 OK")) + ||(strstr(soapconn->read_buf, "HTTP/1.1 500"))) + { + gboolean soapconn_is_valid = FALSE; + + /*OK! process the SOAP body*/ + body_start = (char *)g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n"); + if (!body_start) { + return; + } + body_start += 4; + + if (body_start > soapconn->read_buf + soapconn->read_len) + return; + + /* we read the content-length*/ + if ( (length_start = g_strstr_len(soapconn->read_buf, soapconn->read_len, "Content-Length: ")) != NULL) + length_start += strlen("Content-Length: "); + + if (length_start > soapconn->read_buf + soapconn->read_len) + return; + + if ( (length_end = strstr(length_start, "\r\n")) == NULL ) + return; + + body_len = g_strndup(length_start, length_end - length_start); + + /*setup the conn body */ + soapconn->body = body_start; + soapconn->body_len = atoi(body_len); + g_free(body_len); +#ifdef MSN_SOAP_DEBUG + purple_debug_misc("MSN SOAP","SOAP bytes read so far: %d, Content-Length: %d\n", soapconn->read_len, soapconn->body_len); +#endif + soapconn->need_to_read = (body_start - soapconn->read_buf + soapconn->body_len) - soapconn->read_len; + if ( soapconn->need_to_read > 0 ) { + return; + } + +#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); + xmlnode_free(node); + } + else + purple_debug_info("MSN SOAP","Data received from the SOAP server:\n%s\n", soapconn->read_buf); +#endif + + /*remove the read handler*/ + msn_soap_close_handler( &(soapconn->input_handler) ); +// purple_input_remove(soapconn->input_handler); +// soapconn->input_handler = 0; + /* + * close the soap connection,if more soap request came, + * Just reconnect to do it, + * + * To solve the problem described below: + * When I post the soap request in one socket one after the other, + * The first read is ok, But the second soap read always got 0 bytes, + * Weird! + * */ + msn_soap_close(soapconn); + + /*call the read callback*/ + 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 +msn_soap_free_read_buf(MsnSoapConn *soapconn) +{ + g_return_if_fail(soapconn != NULL); + + if (soapconn->read_buf) { + g_free(soapconn->read_buf); + } + soapconn->read_buf = NULL; + soapconn->read_len = 0; + soapconn->need_to_read = 0; +} + +void +msn_soap_free_write_buf(MsnSoapConn *soapconn) +{ + g_return_if_fail(soapconn != NULL); + + if (soapconn->write_buf) { + g_free(soapconn->write_buf); + } + soapconn->write_buf = NULL; + soapconn->written_len = 0; +} + +/*Soap write process func*/ +static void +msn_soap_write_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + int len, total_len; + + g_return_if_fail(soapconn != NULL); + if ( soapconn->write_buf == NULL ) { + purple_debug_error("MSN SOAP","SOAP write buffer is NULL\n"); + // msn_soap_check_conn_errors(soapconn); + // purple_input_remove(soapconn->output_handler); + // soapconn->output_handler = 0; + msn_soap_close_handler( &(soapconn->output_handler) ); + return; + } + total_len = strlen(soapconn->write_buf); + + /* + * write the content to SSL server, + */ + len = purple_ssl_write(soapconn->gsc, + soapconn->write_buf + soapconn->written_len, + total_len - soapconn->written_len); + + if (len < 0 && errno == EAGAIN) + return; + else if (len <= 0){ + /*SSL write error!*/ +// msn_soap_check_conn_errors(soapconn); + + msn_soap_close_handler( &(soapconn->output_handler) ); +// purple_input_remove(soapconn->output_handler); +// soapconn->output_handler = 0; + + msn_soap_close(soapconn); + + /* TODO: notify of the error */ + purple_debug_error("MSN SOAP", "Error writing to SSL connection!\n"); + msn_soap_post(soapconn, NULL); + return; + } + soapconn->written_len += len; + + if (soapconn->written_len < total_len) + return; + + msn_soap_close_handler( &(soapconn->output_handler) ); +// purple_input_remove(soapconn->output_handler); +// soapconn->output_handler = 0; + + /*clear the write buff*/ + msn_soap_free_write_buf(soapconn); + + /* Write finish! + * callback for write done + */ + if(soapconn->written_cb != NULL){ + soapconn->written_cb(soapconn); + } + /*maybe we need to read the input?*/ + if ( soapconn->input_handler == 0 ) { + soapconn->input_handler = purple_input_add(soapconn->gsc->fd, + PURPLE_INPUT_READ, msn_soap_read_cb, soapconn); + } +} + +/*write the buffer to SOAP connection*/ +void +msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb) +{ + if (soapconn == NULL) { + return; + } + + msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); + + 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*/ + /*start the write*/ + soapconn->output_handler = purple_input_add(soapconn->gsc->fd, PURPLE_INPUT_WRITE, + msn_soap_write_cb, soapconn); + msn_soap_write_cb(soapconn, soapconn->gsc->fd, PURPLE_INPUT_WRITE); +} + +/* New a soap request*/ +MsnSoapReq * +msn_soap_request_new(const char *host,const char *post_url,const char *soap_action, + const char *body, const gpointer data_cb, + MsnSoapReadCbFunction read_cb, + MsnSoapWrittenCbFunction written_cb, + MsnSoapConnectInitFunction connect_init) +{ + MsnSoapReq *request; + + request = g_new0(MsnSoapReq, 1); + request->id = 0; + + request->login_host = g_strdup(host); + request->login_path = g_strdup(post_url); + request->soap_action = g_strdup(soap_action); + request->body = g_strdup(body); + request->data_cb = data_cb; + request->read_cb = read_cb; + request->written_cb = written_cb; + request->connect_init = connect_init; + + return request; +} + +/*free a soap request*/ +void +msn_soap_request_free(MsnSoapReq *request) +{ + g_return_if_fail(request != NULL); + + g_free(request->login_host); + g_free(request->login_path); + g_free(request->soap_action); + g_free(request->body); + request->read_cb = NULL; + request->written_cb = NULL; + request->connect_init = NULL; + + g_free(request); +} + +/*post the soap request queue's head request*/ +void +msn_soap_post_head_request(MsnSoapConn *soapconn) +{ + 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) { + + purple_debug_info("MSN SOAP", "Posting new request from head of the queue\n"); + + if ( !g_queue_is_empty(soapconn->soap_queue) ) { + MsnSoapReq *request; + + if ( (request = g_queue_pop_head(soapconn->soap_queue)) != NULL ) { + msn_soap_post_request(soapconn,request); + } + } else { + purple_debug_info("MSN SOAP", "No requests to process found.\n"); + msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED_IDLE); + } + } +} + +/*post the soap request , + * if not connected, Connected first. + */ +void +msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request) +{ + MsnSoapReq *head_request; + + if (soapconn == NULL) + return; + + if (request != NULL) { +#ifdef MSN_SOAP_DEBUG + purple_debug_misc("MSN SOAP", "Request added to the queue\n"); +#endif + g_queue_push_tail(soapconn->soap_queue, request); + } + + if ( !g_queue_is_empty(soapconn->soap_queue)) { + + /* we may have to reinitialize the soap connection, so avoid + * reusing the connection for now */ + + if (soapconn->step == MSN_SOAP_CONNECTED_IDLE) { + purple_debug_misc("MSN SOAP","Already connected to SOAP server, re-initializing\n"); + msn_soap_close_handler( &(soapconn->input_handler) ); + msn_soap_close_handler( &(soapconn->output_handler) ); + msn_soap_close(soapconn); + } + + if (!msn_soap_connected(soapconn) && (soapconn->step == MSN_SOAP_UNCONNECTED)) { + + /*not connected?and we have something to process connect it first*/ + purple_debug_misc("MSN SOAP","No connection to SOAP server. Connecting...\n"); + head_request = g_queue_peek_head(soapconn->soap_queue); + + if (head_request == NULL) { + purple_debug_error("MSN SOAP", "Queue is not empty, but failed to peek the head request!\n"); + return; + } + + if (head_request->connect_init != NULL) { + head_request->connect_init(soapconn); + } + msn_soap_connect(soapconn); + return; + } + + purple_debug_info("MSN SOAP", "Currently processing another SOAP request\n"); + } else { + purple_debug_info("MSN SOAP", "No requests left to dispatch\n"); + } +} + +/*Post the soap request action*/ +void +msn_soap_post_request(MsnSoapConn *soapconn, MsnSoapReq *request) +{ + char * soap_head = NULL; + char * request_str = NULL; +#ifdef MSN_SOAP_DEBUG +#if !defined(_WIN32) + xmlnode * node; +#endif + purple_debug_misc("MSN SOAP","msn_soap_post_request()\n"); +#endif + + msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); + soap_head = g_strdup_printf( + "POST %s HTTP/1.1\r\n" + "SOAPAction: %s\r\n" + "Content-Type:text/xml; charset=utf-8\r\n" + "Cookie: MSPAuth=%s\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" + "Accept: */*\r\n" + "Host: %s\r\n" + "Content-Length: %" G_GSIZE_FORMAT "\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n\r\n", + request->login_path, + request->soap_action, + soapconn->session->passport_info.mspauth, + request->login_host, + strlen(request->body) + ); + request_str = g_strdup_printf("%s%s", soap_head, request->body); + +#if defined(MSN_SOAP_DEBUG) && !defined(_WIN32) + node = xmlnode_from_str(request->body, -1); + if (node != NULL) { + char *formattedstr = xmlnode_to_formatted_str(node, NULL); + purple_debug_info("MSN SOAP","Posting request to SOAP server:\n%s%s\n",soap_head, formattedstr); + g_free(formattedstr); + xmlnode_free(node); + } + else + purple_debug_info("MSN SOAP","Failed to parse SOAP request being sent:\n%s\n", request_str); +#endif + + g_free(soap_head); + /*free read buffer*/ + // msn_soap_free_read_buf(soapconn); + /*post it to server*/ + soapconn->data_cb = request->data_cb; + msn_soap_write(soapconn, request_str, request->written_cb); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.h Mon Oct 01 17:51:20 2007 +0000 @@ -0,0 +1,167 @@ +/** + * @file soap.h + * header file for SOAP connection related process + * Author + * MaYuan<mayuan2006@gmail.com> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SOAP_H_ +#define _MSN_SOAP_H_ + +#define MSN_SOAP_READ_BUFF_SIZE 8192 + +/* define this to debug the communications with the SOAP server */ +/* #define MSN_SOAP_DEBUG */ + +#define MSN_SOAP_READ 1 +#define MSN_SOAP_WRITE 2 + +typedef enum +{ + MSN_SOAP_UNCONNECTED, + MSN_SOAP_CONNECTING, + MSN_SOAP_CONNECTED, + MSN_SOAP_PROCESSING, + MSN_SOAP_CONNECTED_IDLE +}MsnSoapStep; + +/* MSN SoapRequest structure*/ +typedef struct _MsnSoapReq MsnSoapReq; + +/* MSN Https connection structure*/ +typedef struct _MsnSoapConn MsnSoapConn; + +typedef void (*MsnSoapConnectInitFunction)(MsnSoapConn *); +typedef gboolean (*MsnSoapReadCbFunction)(MsnSoapConn *); +typedef void (*MsnSoapWrittenCbFunction)(MsnSoapConn *); + +typedef gboolean (*MsnSoapSslConnectCbFunction)(MsnSoapConn *, PurpleSslConnection *); +typedef void (*MsnSoapSslErrorCbFunction)(MsnSoapConn *, PurpleSslConnection *, PurpleSslErrorType); + + +struct _MsnSoapReq{ + /*request sequence*/ + int id; + + char *login_host; + char *login_path; + char *soap_action; + + char *body; + + gpointer data_cb; + MsnSoapReadCbFunction read_cb; + MsnSoapWrittenCbFunction written_cb; + MsnSoapConnectInitFunction connect_init; +}; + +struct _MsnSoapConn{ + MsnSession *session; + gpointer parent; + + char *login_host; + char *login_path; + char *soap_action; + + MsnSoapStep step; + /*ssl connection?*/ + guint ssl_conn; + /*normal connection*/ + guint fd; + /*SSL connection*/ + PurpleSslConnection *gsc; + /*ssl connection callback*/ + MsnSoapSslConnectCbFunction connect_cb; + /*ssl error callback*/ + MsnSoapSslErrorCbFunction error_cb; + + /*read handler*/ + guint input_handler; + /*write handler*/ + guint output_handler; + + /*Queue of SOAP request to send*/ + int soap_id; + GQueue *soap_queue; + + /*write buffer*/ + char *write_buf; + gsize written_len; + MsnSoapWrittenCbFunction written_cb; + + /*read buffer*/ + char *read_buf; + gsize read_len; + gsize need_to_read; + MsnSoapReadCbFunction read_cb; + + gpointer data_cb; + + /*HTTP reply body part*/ + char *body; + int body_len; +}; + + +/*Function Prototype*/ +/*Soap Request Function */ +MsnSoapReq *msn_soap_request_new(const char *host, const char *post_url, + const char *soap_action, const char *body, + const gpointer data_cb, + MsnSoapReadCbFunction read_cb, + MsnSoapWrittenCbFunction written_cb, + MsnSoapConnectInitFunction connect_init); + +void msn_soap_request_free(MsnSoapReq *request); +void msn_soap_post_request(MsnSoapConn *soapconn,MsnSoapReq *request); +void msn_soap_post_head_request(MsnSoapConn *soapconn); + +/*new a soap conneciton */ +MsnSoapConn *msn_soap_new(MsnSession *session,gpointer data,int sslconn); + +/*destroy */ +void msn_soap_destroy(MsnSoapConn *soapconn); + +/*init a soap conneciton */ +void msn_soap_init(MsnSoapConn *soapconn, char * host, int ssl, + MsnSoapSslConnectCbFunction connect_cb, + MsnSoapSslErrorCbFunction error_cb); +void msn_soap_connect(MsnSoapConn *soapconn); +void msn_soap_close(MsnSoapConn *soapconn); + +/*write to soap*/ +void msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb); +void msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request); + +void msn_soap_free_read_buf(MsnSoapConn *soapconn); +void msn_soap_free_write_buf(MsnSoapConn *soapconn); +void msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond); +void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond); + +/*clean the unhandled requests*/ +void msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn); + +/*check if the soap connection is connected*/ +int msn_soap_connected(MsnSoapConn *soapconn); +void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step); + +#endif/*_MSN_SOAP_H_*/ +
--- a/libpurple/protocols/msn/state.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/state.c Mon Oct 01 17:51:20 2007 +0000 @@ -38,6 +38,197 @@ N_("Available") }; +/* Local Function Prototype*/ +static char *msn_build_psm(const char *psmstr,const char *mediastr, + const char *guidstr); + +/* + * WLM media PSM info build prcedure + * + * Result can like: + * <CurrentMedia>\0Music\01\0{0} - {1}\0Song Title\0Song Artist\0Song Album\0\0</CurrentMedia>\ + * <CurrentMedia>\0Games\01\0Playing {0}\0Game Name\0</CurrentMedia>\ + * <CurrentMedia>\0Office\01\0Office Message\0Office App Name\0</CurrentMedia>" + */ +static char * +msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr) +{ + xmlnode *dataNode,*psmNode,*mediaNode,*guidNode; + char *result; + int length; + + dataNode = xmlnode_new("Data"); + + psmNode = xmlnode_new("PSM"); + if(psmstr != NULL){ + xmlnode_insert_data(psmNode,psmstr,strlen(psmstr)); + } + xmlnode_insert_child(dataNode,psmNode); + + mediaNode = xmlnode_new("CurrentMedia"); + if(mediastr != NULL){ + xmlnode_insert_data(mediaNode,mediastr,strlen(mediastr)); + } + xmlnode_insert_child(dataNode,mediaNode); + + guidNode = xmlnode_new("MachineGuid"); + if(guidstr != NULL){ + xmlnode_insert_data(guidNode,guidstr,strlen(guidstr)); + } + xmlnode_insert_child(dataNode,guidNode); + + result = xmlnode_to_str(dataNode,&length); + xmlnode_free(dataNode); + return result; +} + +/* parse CurrentMedia string */ +char * +msn_parse_currentmedia(const char *cmedia) +{ + char **cmedia_array; + GString *buffer = NULL; + int strings; + + if ((cmedia == NULL) || (*cmedia == '\0')) { + purple_debug_info("msn", "No currentmedia string\n"); + return NULL; + } + + purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia); + + cmedia_array = g_strsplit(cmedia, "\\0", 0); + + strings = 0; + /* Yes, we want to skip the first element here, as it is empty due to + * the cmedia string starting with \0 -- see the examples below. */ + while (cmedia_array[++strings] != NULL); + + /* The cmedia_array[2] field contains a 1 if enabled. */ + if ((strings > 3) && (!strcmp(cmedia_array[2], "1"))) { + char *inptr = cmedia_array[3]; + + buffer = g_string_new(NULL); + + while (*inptr != '\0') { + if ((*inptr == '{') && ((*(inptr + 1) != '\0') && (*(inptr+2) == '}'))) { + char *tmpptr; + int tmp; + + errno = 0; + tmp = strtol(inptr + 1, &tmpptr, 10); + + if (errno == 0 && tmpptr != inptr + 1 && + tmp + 4 < strings) { + /* Replace {?} tag with appropriate text only when successful. + * Skip otherwise. */ + buffer = g_string_append(buffer, cmedia_array[tmp + 4]); + } + inptr += 3; /* Skip to the next char after '}' */ + } else { + buffer = g_string_append_c(buffer, *inptr++); + } + } + purple_debug_info("msn", "Parsed currentmedia string, result: \"%s\"\n", + buffer->str); + } else { + purple_debug_info("msn", "Current media marked disabled, not parsing.\n"); + } + + g_strfreev(cmedia_array); + return buffer ? g_string_free(buffer, FALSE) : NULL; +} + +/* get the CurrentMedia info from the XML string */ +char * +msn_get_currentmedia(char *xml_str, gsize len) +{ + xmlnode *payloadNode, *currentmediaNode; + char *currentmedia; + + purple_debug_info("msn","msn get CurrentMedia\n"); + payloadNode = xmlnode_from_str(xml_str, len); + if (!payloadNode){ + purple_debug_error("msn","PSM XML parse Error!\n"); + return NULL; + } + currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia"); + if (currentmediaNode == NULL){ + purple_debug_info("msn","No CurrentMedia Node"); + xmlnode_free(payloadNode); + return NULL; + } + currentmedia = xmlnode_get_data(currentmediaNode); + + xmlnode_free(payloadNode); + + return currentmedia; +} + +/*get the PSM info from the XML string*/ +char * +msn_get_psm(char *xml_str, gsize len) +{ + xmlnode *payloadNode, *psmNode; + char *psm; + + purple_debug_info("MSNP14","msn get PSM\n"); + payloadNode = xmlnode_from_str(xml_str, len); + if (!payloadNode){ + purple_debug_error("MSNP14","PSM XML parse Error!\n"); + return NULL; + } + psmNode = xmlnode_get_child(payloadNode, "PSM"); + if (psmNode == NULL){ + purple_debug_info("MSNP14","No PSM status Node"); + xmlnode_free(payloadNode); + return NULL; + } + psm = xmlnode_get_data(psmNode); + + xmlnode_free(payloadNode); + + return psm; +} + +/* set the MSN's PSM info,Currently Read from the status Line + * Thanks for Cris Code + */ +void +msn_set_psm(MsnSession *session) +{ + PurpleAccount *account = session->account; + PurplePresence *presence; + PurpleStatus *status; + MsnCmdProc *cmdproc; + MsnTransaction *trans; + char *payload; + const char *statusline; + gchar *unescapedstatusline; + + g_return_if_fail(session != NULL); + g_return_if_fail(session->notification != NULL); + + cmdproc = session->notification->cmdproc; + /*prepare PSM info*/ + if(session->psm){ + g_free(session->psm); + } + /*Get the PSM string from Purple's Status Line*/ + presence = purple_account_get_presence(account); + status = purple_presence_get_active_status(presence); + statusline = purple_status_get_attr_string(status, "message"); + unescapedstatusline = purple_unescape_html(statusline); + session->psm = msn_build_psm(unescapedstatusline, NULL, NULL); + g_free(unescapedstatusline); + payload = session->psm; + + purple_debug_misc("MSNP14","Sending UUX command with payload: %s\n",payload); + trans = msn_transaction_new(cmdproc, "UUX","%d",strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + void msn_change_status(MsnSession *session) { @@ -79,6 +270,7 @@ g_free(msnobj_str); } + msn_set_psm(session); } const char *
--- a/libpurple/protocols/msn/state.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/state.h Mon Oct 01 17:51:20 2007 +0000 @@ -59,6 +59,17 @@ const char *msn_state_get_text(MsnAwayType state); +void msn_set_psm(MsnSession *session); + +/* Parse CurrentMedia string */ +char * msn_parse_currentmedia(const char *cmedia); + +/* Get the CurrentMedia info from the XML string */ +char * msn_get_currentmedia(char *xml_str,gsize len); + +/*get the PSM info from the XML string*/ +char * msn_get_psm(char *xml_str,gsize len); + MsnAwayType msn_state_from_account(PurpleAccount *account); #endif /* _MSN_STATE_H_ */
--- a/libpurple/protocols/msn/switchboard.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Mon Oct 01 17:51:20 2007 +0000 @@ -25,7 +25,7 @@ #include "prefs.h" #include "switchboard.h" #include "notification.h" -#include "msn-utils.h" +#include "msnutils.h" #include "error.h" @@ -534,6 +534,7 @@ payload = msn_message_gen_payload(msg, &payload_len); #ifdef MSN_DEBUG_SB + purple_debug_info("MSNP14","SB length:{%d}",payload_len); msn_message_show_readable(msg, "SB SEND", FALSE); #endif @@ -621,6 +622,7 @@ g_return_if_fail(swboard != NULL); g_return_if_fail(msg != NULL); + purple_debug_info("MSNP14","switchboard send msg..\n"); if (msn_switchboard_can_send(swboard)) release_msg(swboard, msg); else if (queue) @@ -727,7 +729,8 @@ msg = msn_message_new_from_cmd(cmdproc->session, cmd); - msn_message_parse_payload(msg, payload, len); + msn_message_parse_payload(msg, payload, len, + MSG_LINE_DEM,MSG_BODY_DEM); #ifdef MSN_DEBUG_SB msn_message_show_readable(msg, "SB RECV", FALSE); #endif @@ -749,6 +752,14 @@ } static void +ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_misc("MSNP14","get UBM...\n"); + cmdproc->servconn->payload_len = atoi(cmd->params[4]); + cmdproc->last_cmd->payload_cb = msg_cmd_post; +} + +static void nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnMessage *msg; @@ -1084,6 +1095,8 @@ cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { int reason = MSN_SB_ERROR_UNKNOWN; + MsnMessage *msg; + MsnSwitchBoard *swboard = trans->data; if (error == 215) { @@ -1096,7 +1109,19 @@ } purple_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); + purple_debug_warning("msn", "Will Use Offline Message to sendit\n"); +// cal_error_helper(trans, reason); + /*offline Message send Process*/ + + while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL){ + purple_debug_warning("MSNP14","offline msg to send:{%s}\n",msg->body); + /* The messages could not be sent due to a switchboard error */ + swboard->error = MSN_SB_ERROR_USER_OFFLINE; + msg_error_helper(swboard->cmdproc, msg, + MSN_MSG_ERROR_SB); + msn_message_unref(msg); + } cal_error_helper(trans, reason); } @@ -1140,6 +1165,7 @@ /* The conversation window was closed. */ return; + purple_debug_info("MSNP14","Switchboard:auth:{%s} socket:{%s}\n",cmd->params[4],cmd->params[2]); msn_switchboard_set_auth_key(swboard, cmd->params[4]); msn_parse_socket(cmd->params[2], &host, &port); @@ -1252,6 +1278,7 @@ msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd); msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd); msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd); msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
--- a/libpurple/protocols/msn/sync.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/sync.c Mon Oct 01 17:51:20 2007 +0000 @@ -90,9 +90,9 @@ { MsnSession *session = cmdproc->session; const char *name; - int group_id; + const char *group_id; - group_id = atoi(cmd->params[0]); + group_id = cmd->params[0]; name = purple_url_decode(cmd->params[1]); msn_group_new(session->userlist, group_id, name); @@ -156,10 +156,10 @@ for (c = tokens; *c != NULL; c++) { - int id; + char *id; - id = atoi(*c); - group_ids = g_slist_append(group_ids, GINT_TO_POINTER(id)); + id = *c; + group_ids = g_slist_append(group_ids, g_strdup(id)); } g_strfreev(tokens);
--- a/libpurple/protocols/msn/user.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/user.c Mon Oct 01 17:51:20 2007 +0000 @@ -25,6 +25,7 @@ #include "user.h" #include "slp.h" +/*new a user object*/ MsnUser * msn_user_new(MsnUserList *userlist, const char *passport, const char *store_name) @@ -50,6 +51,7 @@ return user; } +/*destroy a user object*/ void msn_user_destroy(MsnUser *user) { @@ -59,7 +61,14 @@ g_hash_table_destroy(user->clientcaps); if (user->group_ids != NULL) + { + GList *l; + for (l = user->group_ids; l != NULL; l = l->next) + { + g_free(l->data); + } g_list_free(user->group_ids); + } if (user->msnobj != NULL) msn_object_destroy(user->msnobj); @@ -67,6 +76,7 @@ g_free(user->passport); g_free(user->friendly_name); g_free(user->store_name); + g_free(user->uid); g_free(user->phone.home); g_free(user->phone.work); g_free(user->phone.mobile); @@ -81,7 +91,18 @@ account = user->userlist->session->account; - if (user->status != NULL) { + if (user->statusline != NULL && user->currentmedia != NULL) { + purple_prpl_got_user_status(account, user->passport, user->status, + "message", user->statusline, + "currentmedia", user->currentmedia, NULL); + } else if (user->currentmedia != NULL) { + purple_prpl_got_user_status(account, user->passport, user->status, "currentmedia", + user->currentmedia, NULL); + } else if (user->statusline != NULL) { + //char *status = g_strdup_printf("%s - %s", user->status, user->statusline); + purple_prpl_got_user_status(account, user->passport, user->status, + "message", user->statusline, NULL); + } else if (user->status != NULL) { if (!strcmp(user->status, "offline") && user->mobile) { purple_prpl_got_user_status(account, user->passport, "offline", NULL); purple_prpl_got_user_status(account, user->passport, "mobile", NULL); @@ -142,12 +163,66 @@ } void +msn_user_set_statusline(MsnUser *user, const char *statusline) +{ + g_return_if_fail(user != NULL); + + g_free(user->statusline); + user->statusline = g_strdup(statusline); +} + +void +msn_user_set_currentmedia(MsnUser *user, const char *currentmedia) +{ + g_return_if_fail(user != NULL); + + g_free(user->currentmedia); + user->currentmedia = g_strdup(currentmedia); +} + +void msn_user_set_store_name(MsnUser *user, const char *name) { g_return_if_fail(user != NULL); - g_free(user->store_name); - user->store_name = g_strdup(name); + if (name != NULL) + { + g_free(user->store_name); + user->store_name = g_strdup(name); + } +} + +void +msn_user_set_uid(MsnUser *user, const char *uid) +{ + g_return_if_fail(user != NULL); + + g_free(user->uid); + user->uid = g_strdup(uid); +} + +void +msn_user_set_type(MsnUser *user, MsnUserType type) +{ + g_return_if_fail(user != NULL); + + user->type = type; +} + +void +msn_user_set_op(MsnUser *user, int list_op) +{ + g_return_if_fail(user != NULL); + + user->list_op |= list_op; +} + +void +msn_user_unset_op(MsnUser *user, int list_op) +{ + g_return_if_fail(user != NULL); + + user->list_op &= ~list_op; } void @@ -218,54 +293,97 @@ } } +/*add group id to User object*/ void -msn_user_add_group_id(MsnUser *user, int id) +msn_user_add_group_id(MsnUser *user, const char* id) { MsnUserList *userlist; PurpleAccount *account; PurpleBuddy *b; PurpleGroup *g; const char *passport; + char *group_id; const char *group_name; g_return_if_fail(user != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); - user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id)); + group_id = g_strdup(id); + user->group_ids = g_list_append(user->group_ids, group_id); userlist = user->userlist; account = userlist->session->account; passport = msn_user_get_passport(user); - group_name = msn_userlist_find_group_name(userlist, id); + group_name = msn_userlist_find_group_name(userlist, group_id); + + purple_debug_info("User","group id:%s,name:%s,user:%s\n", group_id, group_name, passport); g = purple_find_group(group_name); - if ((id == 0) && (g == NULL)) + if ((id == NULL) && (g == NULL)) { g = purple_group_new(group_name); purple_blist_add_group(g, NULL); } b = purple_find_buddy_in_group(account, passport, g); - if (b == NULL) { b = purple_buddy_new(account, passport, NULL); - purple_blist_add_buddy(b, NULL, g, NULL); } + b->proto_data = user; + /*Update the blist Node info*/ +// purple_blist_node_set_string(&(b->node), "", ""); +} - b->proto_data = user; +/*check if the msn user is online*/ +gboolean +msn_user_is_online(PurpleAccount *account, const char *name) +{ + PurpleBuddy *buddy; + + buddy =purple_find_buddy(account,name); + return PURPLE_BUDDY_IS_ONLINE(buddy); +} + +gboolean +msn_user_is_yahoo(PurpleAccount *account, const char *name) +{ + MsnSession *session = NULL; + MsnUser *user; + PurpleConnection *gc; + + gc = purple_account_get_connection(account); + if (gc != NULL) + session = gc->proto_data; + + if ((session != NULL) && (session->protocol_ver == WLM_PROT_VER)) + return FALSE; + + if ((session != NULL) && (user = msn_userlist_find_user(session->userlist, name)) != NULL) + { + return (user->type == MSN_USER_TYPE_YAHOO); + } + return (strstr(name,"@yahoo.") != NULL); } void -msn_user_remove_group_id(MsnUser *user, int id) +msn_user_remove_group_id(MsnUser *user, const char *id) { + GList *l; + g_return_if_fail(user != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); + + l = g_list_find_custom(user->group_ids, id, (GCompareFunc)strcmp); - user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id)); + if (l == NULL) + return; + + g_free(l->data); + user->group_ids = g_list_remove_link(user->group_ids, l); } void
--- a/libpurple/protocols/msn/user.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/user.h Mon Oct 01 17:51:20 2007 +0000 @@ -31,6 +31,17 @@ #include "userlist.h" +typedef enum +{ + MSN_USER_TYPE_UNKNOWN = 0x00, + MSN_USER_TYPE_PASSPORT = 0x01, + MSN_USER_TYPE_UNKNOWN1 = 0x02, + MSN_USER_TYPE_MOBILE = 0x04, + MSN_USER_TYPE_UNKNOWN2 = 0x08, + MSN_USER_TYPE_UNKNOWN3 = 0x10, + MSN_USER_TYPE_YAHOO = 0x20 +} MsnUserType; + /** * A user. */ @@ -45,7 +56,12 @@ char *store_name; /**< The name stored in the server. */ char *friendly_name; /**< The friendly name. */ + char * uid; /*< User Id */ + const char *status; /**< The state of the user. */ + char *statusline; /**< The state of the user. */ + char *currentmedia; /**< The current media of the user. */ + gboolean idle; /**< The idle state of the user. */ struct @@ -65,7 +81,12 @@ GHashTable *clientcaps; /**< The client's capabilities. */ - int list_op; + MsnUserType type; /**< The user type */ + + int list_op; /**< Which lists the user is in */ + + guint membership_id[5]; /**< The membershipId sent by the contacts server, + indexed by the list it belongs to */ }; /**************************************************************************/ @@ -102,6 +123,22 @@ */ void msn_user_update(MsnUser *user); + /** + * Sets the new statusline of user. + * + * @param user The user. + * @param state The statusline string. + */ +void msn_user_set_statusline(MsnUser *user, const char *statusline); + + /** + * Sets the current media of user. + * + * @param user The user. + * @param state The statusline string. + */ +void msn_user_set_currentmedia(MsnUser *user, const char *currentmedia); + /** * Sets the new state of user. * @@ -156,7 +193,7 @@ * @param user The user. * @param id The group ID. */ -void msn_user_add_group_id(MsnUser *user, int id); +void msn_user_add_group_id(MsnUser *user, const char * id); /** * Removes the group ID from a user. @@ -164,7 +201,7 @@ * @param user The user. * @param id The group ID. */ -void msn_user_remove_group_id(MsnUser *user, int id); +void msn_user_remove_group_id(MsnUser *user, const char * id); /** * Sets the home phone number for a user. @@ -182,6 +219,9 @@ */ void msn_user_set_work_phone(MsnUser *user, const char *number); +void msn_user_set_uid(MsnUser *user, const char *uid); +void msn_user_set_type(MsnUser *user, MsnUserType type); + /** * Sets the mobile phone number for a user. * @@ -279,6 +319,22 @@ */ GHashTable *msn_user_get_client_caps(const MsnUser *user); +/** + * check to see if user is online + */ +gboolean +msn_user_is_online(PurpleAccount *account, const char *name); + +/** + * check to see if user is Yahoo User + */ +gboolean +msn_user_is_yahoo(PurpleAccount *account ,const char *name); + +void msn_user_set_op(MsnUser *user, int list_op); +void msn_user_unset_op(MsnUser *user, int list_op); + /*@}*/ + #endif /* _MSN_USER_H_ */
--- a/libpurple/protocols/msn/userlist.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Mon Oct 01 17:51:20 2007 +0000 @@ -41,10 +41,21 @@ msn_accept_add_cb(gpointer data) { MsnPermitAdd *pa = data; - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; + + purple_debug_misc("MSN Userlist", "Accepted the new buddy: %s\n", pa->who); - msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL); + if (PURPLE_CONNECTION_IS_VALID(pa->gc)) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; + MsnUser *user = msn_userlist_find_add_user(userlist, pa->who, pa->who); + + + msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_FL)) + msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL); + } g_free(pa->who); g_free(pa->friendly); @@ -55,10 +66,20 @@ msn_cancel_add_cb(gpointer data) { MsnPermitAdd *pa = data; - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; + + purple_debug_misc("MSN Userlist", "Denied the new buddy: %s\n", pa->who); - msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL); + if (PURPLE_CONNECTION_IS_VALID(pa->gc)) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; + MsnCallbackState *state = msn_callback_state_new(); + + msn_callback_state_set_action(state, MSN_DENIED_BUDDY); + + msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_BL); + msn_del_contact_from_list(session->contact, state, pa->who, MSN_LIST_PL); + } g_free(pa->who); g_free(pa->friendly); @@ -68,59 +89,57 @@ static void got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly) { + PurpleAccount *acct; MsnPermitAdd *pa; pa = g_new0(MsnPermitAdd, 1); pa->who = g_strdup(passport); pa->friendly = g_strdup(friendly); pa->gc = gc; - - purple_account_request_authorization(purple_connection_get_account(gc), passport, NULL, friendly, NULL, - purple_find_buddy(purple_connection_get_account(gc), passport) != NULL, - msn_accept_add_cb, msn_cancel_add_cb, pa); + + acct = purple_connection_get_account(gc); + purple_account_request_authorization(acct, passport, NULL, friendly, NULL, + purple_find_buddy(acct, passport) != NULL, + msn_accept_add_cb, msn_cancel_add_cb, pa); + } /************************************************************************** * Utility functions **************************************************************************/ -static gboolean -user_is_in_group(MsnUser *user, int group_id) +gboolean +msn_userlist_user_is_in_group(MsnUser *user, const char * group_id) { if (user == NULL) return FALSE; - if (group_id < 0) + if (group_id == NULL) return FALSE; - if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id))) + if (g_list_find_custom(user->group_ids, group_id, (GCompareFunc)strcmp)) return TRUE; return FALSE; } -static gboolean -user_is_there(MsnUser *user, int list_id, int group_id) +gboolean +msn_userlist_user_is_in_list(MsnUser *user, MsnListId list_id) { int list_op; if (user == NULL) return FALSE; - + list_op = 1 << list_id; - if (!(user->list_op & list_op)) + if (user->list_op & list_op) + return TRUE; + else return FALSE; - - if (list_id == MSN_LIST_FL) - { - if (group_id >= 0) - return user_is_in_group(user, group_id); - } - - return TRUE; } +#if 0 static const char* get_store_name(MsnUser *user) { @@ -148,31 +167,7 @@ return store_name; } - -static void -msn_request_add_group(MsnUserList *userlist, const char *who, - const char *old_group_name, const char *new_group_name) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - MsnMoveBuddy *data; - - cmdproc = userlist->session->notification->cmdproc; - data = g_new0(MsnMoveBuddy, 1); - - data->who = g_strdup(who); - - if (old_group_name) - data->old_group_name = g_strdup(old_group_name); - - trans = msn_transaction_new(cmdproc, "ADG", "%s %d", - purple_url_encode(new_group_name), - 0); - - msn_transaction_set_data(trans, data); - - msn_cmdproc_send_trans(cmdproc, trans); -} +#endif /************************************************************************** * Server functions @@ -193,14 +188,16 @@ return -1; } +/* this function msn_got_add_user isn't called anywhere */ void msn_got_add_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id) + MsnListId list_id, const char * group_id) { PurpleAccount *account; const char *passport; const char *friendly; + purple_debug_info("MSNP14","got add user...\n"); account = session->account; passport = msn_user_get_passport(user); @@ -214,7 +211,7 @@ serv_got_alias(gc, passport, friendly); - if (group_id >= 0) + if (group_id != NULL) { msn_user_add_group_id(user, group_id); } @@ -263,7 +260,7 @@ * looked at this. Maybe we should use the store * name instead? --KingAnt */ - got_new_entry(gc, passport, friendly); +// got_new_entry(gc, passport, friendly); } } @@ -273,7 +270,7 @@ void msn_got_rem_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id) + MsnListId list_id, const char * group_id) { PurpleAccount *account; const char *passport; @@ -285,7 +282,7 @@ if (list_id == MSN_LIST_FL) { /* TODO: When is the user totally removed? */ - if (group_id >= 0) + if (group_id != NULL) { msn_user_remove_group_id(user, group_id); return; @@ -333,7 +330,6 @@ { purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n", passport); - } } @@ -351,14 +347,16 @@ 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) { GSList *c; for (c = group_ids; c != NULL; c = g_slist_next(c)) { - int group_id; - group_id = GPOINTER_TO_INT(c->data); + char *group_id; + group_id = c->data; msn_user_add_group_id(user, group_id); } @@ -393,11 +391,14 @@ if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) { - got_new_entry(gc, passport, store); +// got_new_entry(gc, passport, store); } } - user->list_op = list_op; + if (list_op & MSN_LIST_PL_OP) + { + got_new_entry(gc, passport, store); + } } /************************************************************************** @@ -427,18 +428,18 @@ { GList *l; + /*destroy userlist*/ for (l = userlist->users; l != NULL; l = l->next) { msn_user_destroy(l->data); } - g_list_free(userlist->users); + /*destroy group list*/ for (l = userlist->groups; l != NULL; l = l->next) { msn_group_destroy(l->data); } - g_list_free(userlist->groups); g_queue_free(userlist->buddy_icon_requests); @@ -449,6 +450,22 @@ g_free(userlist); } +MsnUser * +msn_userlist_find_add_user(MsnUserList *userlist,const char *passport,const char *userName) +{ + MsnUser *user; + + user = msn_userlist_find_user(userlist, passport); + if (user == NULL) + { + user = msn_user_new(userlist, passport, userName); + msn_userlist_add_user(userlist, user); + } else { + msn_user_set_store_name(user, userName); + } + return user; +} + void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user) { @@ -472,10 +489,36 @@ { MsnUser *user = (MsnUser *)l->data; +// purple_debug_info("MsnUserList","user passport:%s,passport:%s\n",user->passport,passport); g_return_val_if_fail(user->passport != NULL, NULL); - if (!strcmp(passport, user->passport)) + if (!g_strcasecmp(passport, user->passport)){ +// purple_debug_info("MsnUserList","return:%p\n",user); return user; + } + } + + return NULL; +} + +MsnUser * +msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid) +{ + GList *l; + + g_return_val_if_fail(uid != NULL, NULL); + + for (l = userlist->users; l != NULL; l = l->next) + { + MsnUser *user = (MsnUser *)l->data; + + if (user->uid == NULL) { + continue; + } + + if ( !g_strcasecmp(uid, user->uid) ) { + return user; + } } return NULL; @@ -494,18 +537,18 @@ } MsnGroup * -msn_userlist_find_group_with_id(MsnUserList *userlist, int id) +msn_userlist_find_group_with_id(MsnUserList *userlist, const char * id) { GList *l; g_return_val_if_fail(userlist != NULL, NULL); - g_return_val_if_fail(id >= 0, NULL); + g_return_val_if_fail(id != NULL, NULL); for (l = userlist->groups; l != NULL; l = l->next) { MsnGroup *group = l->data; - if (group->id == id) + if (!g_strcasecmp(group->id,id)) return group; } @@ -524,14 +567,14 @@ { MsnGroup *group = l->data; - if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name)) + if ((group->name != NULL) && !g_strcasecmp(name, group->name)) return group; } return NULL; } -int +const char * msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name) { MsnGroup *group; @@ -541,11 +584,11 @@ if (group != NULL) return msn_group_get_id(group); else - return -1; + return NULL; } const char * -msn_userlist_find_group_name(MsnUserList *userlist, int group_id) +msn_userlist_find_group_name(MsnUserList *userlist, const char * group_id) { MsnGroup *group; @@ -558,7 +601,7 @@ } void -msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, +msn_userlist_rename_group_id(MsnUserList *userlist, const char * group_id, const char *new_name) { MsnGroup *group; @@ -570,7 +613,7 @@ } void -msn_userlist_remove_group_id(MsnUserList *userlist, int group_id) +msn_userlist_remove_group_id(MsnUserList *userlist, const char * group_id) { MsnGroup *group; @@ -584,116 +627,293 @@ } void -msn_userlist_rem_buddy(MsnUserList *userlist, - const char *who, int list_id, const char *group_name) +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); + + /* delete the contact from address book via soap action */ + if (user != NULL) { + msn_delete_contact(userlist->session->contact, user->uid); + } +} + +void +msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who, + MsnListId list_id) { MsnUser *user; - int group_id; - const char *list; + const gchar *list; + MsnListOp list_op = 1 << list_id; user = msn_userlist_find_user(userlist, who); - group_id = -1; - - if (group_name != NULL) - { - group_id = msn_userlist_find_group_id(userlist, group_name); - - if (group_id < 0) - { - /* Whoa, there is no such group. */ - purple_debug_error("msn", "Group doesn't exist: %s\n", group_name); - return; - } - } - - /* First we're going to check if not there. */ - if (!(user_is_there(user, list_id, group_id))) - { + + g_return_if_fail(user != NULL); + + if ( !msn_userlist_user_is_in_list(user, list_id)) { list = lists[list_id]; - purple_debug_error("msn", "User '%s' is not there: %s\n", - who, list); + purple_debug_info("MSN Userlist", "User %s is not in list %s, not removing.\n", who, list); return; } - /* Then request the rem to the server. */ - list = lists[list_id]; + msn_user_unset_op(user, list_op); - msn_notification_rem_buddy(userlist->session->notification, list, who, group_id); + msn_notification_rem_buddy_from_list(userlist->session->notification, list_id, who); } +/*add buddy*/ void -msn_userlist_add_buddy(MsnUserList *userlist, - const char *who, int list_id, - const char *group_name) +msn_userlist_add_buddy(MsnUserList *userlist, const char *who, const char *group_name) { MsnUser *user; - int group_id; - const char *list; - const char *store_name; + MsnCallbackState *state = NULL; + const char *group_id = NULL, *new_group_name; + + new_group_name = group_name == NULL ? MSN_INDIVIDUALS_GROUP_NAME : group_name; - group_id = -1; + + 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(); + msn_callback_state_set_who(state, who); + msn_callback_state_set_new_group_name(state, new_group_name); if (!purple_email_is_valid(who)) { /* 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 */ - if (list_id == MSN_LIST_FL) - { - char *str = g_strdup_printf(_("Unable to add \"%s\"."), who); - purple_notify_error(NULL, NULL, str, - _("The screen name specified is invalid.")); - g_free(str); - } + + char *str = g_strdup_printf(_("Unable to add \"%s\"."), who); + + purple_notify_error(NULL, NULL, str, + _("The screen name specified is invalid.")); + g_free(str); return; } - if (group_name != NULL) + group_id = msn_userlist_find_group_id(userlist, new_group_name); + + if (group_id == NULL) { - group_id = msn_userlist_find_group_id(userlist, group_name); + /* 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); - if (group_id < 0) - { - /* Whoa, we must add that group first. */ - msn_request_add_group(userlist, who, NULL, group_name); + msn_add_group(userlist->session, state, new_group_name); + return; + } 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 + * early enough that the ILN command doesn't screw us up */ + + user = msn_userlist_find_add_user(userlist, who, who); + + if ( msn_userlist_user_is_in_list(user, MSN_LIST_FL) ) { + + purple_debug_info("MSN Userlist", "User %s already exists\n", who); + + msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); + + if (msn_userlist_user_is_in_group(user, group_id)) { + purple_debug_info("MSN Userlist", "User %s is already in group %s, returning\n", who, new_group_name); return; } } + + purple_debug_info("MSN Userlist", "Adding user: %s to group id: %s\n", who, group_id); - user = msn_userlist_find_user(userlist, who); + msn_callback_state_set_action(state, MSN_ADD_BUDDY); + + /* Add contact in the Contact server with a SOAP request and if + successful, send ADL with MSN_LIST_AL and MSN_LIST_FL and a FQY */ + msn_add_contact_to_group(userlist->session->contact, state, who, group_id); +} +void +msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, + MsnListId list_id) +{ + MsnUser *user = NULL; + const gchar *list; + 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 (user_is_there(user, list_id, group_id)) + if (msn_userlist_user_is_in_list(user, list_id)) { list = lists[list_id]; - purple_debug_error("msn", "User '%s' is already there: %s\n", who, list); + 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); +} + +gboolean +msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who, + const char *group_name) +{ + 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); + + purple_debug_info("MSN Userlist","Adding buddy with passport %s to group %s\n", who, group_name); + + if ( (group_id = (gchar *)msn_userlist_find_group_id(userlist, group_name)) == NULL) { + purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name); + return FALSE; + } - store_name = (user != NULL) ? get_store_name(user) : who; + if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { + purple_debug_error("MSN Userlist", "User %s not found!", who); + return FALSE; + } + + msn_user_add_group_id(user, group_id); + + return TRUE; +} + + +gboolean +msn_userlist_rem_buddy_from_group(MsnUserList *userlist, const char *who, + const char *group_name) +{ + const gchar * group_id; + MsnUser *user; - /* Then request the add to the server. */ - list = lists[list_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); + + purple_debug_info("MSN Userlist","Removing buddy with passport %s from group %s\n", who, group_name); - msn_notification_add_buddy(userlist->session->notification, list, who, - store_name, group_id); + if ( (group_id = msn_userlist_find_group_id(userlist, group_name)) == NULL) { + purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name); + return FALSE; + } + + if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { + purple_debug_error("MSN Userlist", "User %s not found!", who); + return FALSE; + } + + msn_user_remove_group_id(user, group_id); + + return TRUE; } void msn_userlist_move_buddy(MsnUserList *userlist, const char *who, - const char *old_group_name, const char *new_group_name) + const char *old_group_name, const char *new_group_name) { - int new_group_id; + 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); + + state = msn_callback_state_new(); + msn_callback_state_set_who(state, who); + msn_callback_state_set_action(state, MSN_MOVE_BUDDY); + msn_callback_state_set_old_group_name(state, old_group_name); + msn_callback_state_set_new_group_name(state, new_group_name); new_group_id = msn_userlist_find_group_id(userlist, new_group_name); - if (new_group_id < 0) - { - msn_request_add_group(userlist, who, old_group_name, 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 + */ + msn_add_contact_to_group(userlist->session->contact, state, who, new_group_id); +} - msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name); - msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name); +/*load userlist from the Blist file cache*/ +void +msn_userlist_load(MsnSession *session) +{ + PurpleBlistNode *gnode, *cnode, *bnode; + PurpleConnection *gc = purple_account_get_connection(session->account); + GSList *l; + MsnUser * user; + + g_return_if_fail(gc != NULL); + + for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) + { + if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) + continue; + for (cnode = gnode->child; cnode; cnode = cnode->next) + { + if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) + continue; + for (bnode = cnode->child; bnode; bnode = bnode->next) + { + PurpleBuddy *b; + if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) + continue; + b = (PurpleBuddy *)bnode; + if (b->account == gc->account) + { + user = msn_userlist_find_add_user(session->userlist, + b->name,NULL); + b->proto_data = user; + msn_user_set_op(user, MSN_LIST_FL_OP); + } + } + } + } + for (l = session->account->permit; l != NULL; l = l->next) + { + user = msn_userlist_find_add_user(session->userlist, + (char *)l->data,NULL); + msn_user_set_op(user, MSN_LIST_AL_OP); + } + for (l = session->account->deny; l != NULL; l = l->next) + { + user = msn_userlist_find_add_user(session->userlist, + (char *)l->data,NULL); + msn_user_set_op(user, MSN_LIST_BL_OP); + } + } +
--- a/libpurple/protocols/msn/userlist.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/msn/userlist.h Mon Oct 01 17:51:20 2007 +0000 @@ -35,16 +35,11 @@ MSN_LIST_FL, MSN_LIST_AL, MSN_LIST_BL, - MSN_LIST_RL + MSN_LIST_RL, + MSN_LIST_PL } MsnListId; -typedef struct -{ - char *who; - char *old_group_name; - -} MsnMoveBuddy; struct _MsnUserList { @@ -64,40 +59,57 @@ }; +gboolean msn_userlist_user_is_in_group(MsnUser *user, const char * group_id); +gboolean msn_userlist_user_is_in_list(MsnUser *user, MsnListId list_id); MsnListId msn_get_list_id(const char *list); void msn_got_add_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id); + MsnListId list_id, const char *group_id); void msn_got_rem_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id); + MsnListId list_id, const char *group_id); void msn_got_lst_user(MsnSession *session, MsnUser *user, int list_op, GSList *group_ids); MsnUserList *msn_userlist_new(MsnSession *session); void msn_userlist_destroy(MsnUserList *userlist); + void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user); void msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user); -MsnUser *msn_userlist_find_user(MsnUserList *userlist, - const char *passport); + +MsnUser * msn_userlist_find_user(MsnUserList *userlist, const char *passport); +MsnUser * msn_userlist_find_add_user(MsnUserList *userlist, + const char *passport, const char *userName); +MsnUser * msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid); + void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group); void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group); -MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, int id); -MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, - const char *name); -int msn_userlist_find_group_id(MsnUserList *userlist, - const char *group_name); -const char *msn_userlist_find_group_name(MsnUserList *userlist, - int group_id); -void msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, - const char *new_name); -void msn_userlist_remove_group_id(MsnUserList *userlist, int group_id); +MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id); +MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name); +const char * msn_userlist_find_group_id(MsnUserList *userlist, + const char *group_name); +const char *msn_userlist_find_group_name(MsnUserList *userlist, const char *group_id); +void msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id, + const char *new_name); +void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id); -void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who, - int list_id, const char *group_name); -void msn_userlist_add_buddy(MsnUserList *userlist, const char *who, - int list_id, const char *group_name); +void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who); +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, - const char *new_group_name); + const char *old_group_name, + const char *new_group_name); + +gboolean msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who, + const char *group_name); +gboolean msn_userlist_rem_buddy_from_group(MsnUserList *userlist, + const char *who, + const char *group_name); + +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); + +void msn_userlist_load(MsnSession *session); #endif /* _MSN_USERLIST_H_ */
--- a/libpurple/protocols/myspace/Makefile.am Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/myspace/Makefile.am Mon Oct 01 17:51:20 2007 +0000 @@ -2,7 +2,7 @@ pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) -SOURCES = markup.c \ +MSIMSOURCES = markup.c \ markup.h \ message.c \ message.h \ @@ -24,14 +24,14 @@ st = -DPURPLE_STATIC_PRPL noinst_LIBRARIES = libmyspace.a -libmyspace_a_SOURCES = $(SOURCES) +libmyspace_a_SOURCES = $(MSIMSOURCES) libmyspace_a_CFLAGS = $(AM_CFLAGS) else st = pkg_LTLIBRARIES = libmyspace.la -libmyspace_la_SOURCES = $(SOURCES) +libmyspace_la_SOURCES = $(MSIMSOURCES) libmyspace_la_LIBADD = $(GLIB_LIBS) endif
--- a/libpurple/protocols/myspace/markup.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/myspace/markup.c Mon Oct 01 17:51:20 2007 +0000 @@ -1,704 +1,705 @@ -/* MySpaceIM Protocol Plugin - markup - * - * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im> - * - * 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 "myspace.h" - -typedef void (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **); - -/* Internal functions */ - -static guint msim_point_to_purple_size(MsimSession *session, guint point); -static guint msim_purple_size_to_point(MsimSession *session, guint size); -static guint msim_height_to_point(MsimSession *session, guint height); -static guint msim_point_to_height(MsimSession *session, guint point); - -static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end); -static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end); -static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f); -static gchar *msim_convert_smileys_to_markup(gchar *before); -static double msim_round(double round); - - -/* Globals */ - -/* The names in in emoticon_names (for <i n=whatever>) map to corresponding - * entries in emoticon_symbols (for the ASCII representation of the emoticon). - * - * Multiple emoticon symbols in Pidgin can map to one name. List the - * canonical form, as inserted by the "Smile!" dialog, first. For example, - * :) comes before :-), because although both are recognized as 'happy', - * the first is inserted by the smiley button (first symbol in theme). - * - * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */ -static struct MSIM_EMOTICON -{ - gchar *name; - gchar *symbol; -} msim_emoticons[] = { - /* Unfortunately, this list duplicates much of the file - * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because - * that file is part of Pidgin, but we're part of libpurple. - */ - { "bigsmile", ":D" }, - { "bigsmile", ":-D" }, - { "devil", "}:)" }, - { "frazzled", ":Z" }, - { "geek", "B)" }, - { "googles", "%)" }, - { "growl", ":E" }, - { "laugh", ":))" }, /* Must be before ':)' */ - { "happy", ":)" }, - { "happy", ":-)" }, - { "happi", ":)" }, - { "heart", ":X" }, - { "mohawk", "-:" }, - { "mad", "X(" }, - { "messed", "X)" }, - { "nerd", "Q)" }, - { "oops", ":G" }, - { "pirate", "P)" }, - { "scared", ":O" }, - { "sidefrown", ":{" }, - { "sinister", ":B" }, - { "smirk", ":," }, - { "straight", ":|" }, - { "tongue", ":P" }, - { "tongue", ":p" }, - { "tongy", ":P" }, - { "upset", "B|" }, - { "wink", ";-)" }, - { "wink", ";)" }, - { "winc", ";)" }, - { "worried", ":[" }, - { "kiss", ":x" }, - { NULL, NULL } -}; - - - -/* Indexes of this array + 1 map HTML font size to scale of normal font size. * - * Based on _point_sizes from libpurple/gtkimhtml.c - * 1 2 3 4 5 6 7 */ -static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 }; - -#define MAX_FONT_SIZE 7 /* Purple maximum font size */ -#define POINTS_PER_INCH 72 /* How many pt's in an inch */ - -/* Text formatting bits for <f s=#> */ -#define MSIM_TEXT_BOLD 1 -#define MSIM_TEXT_ITALIC 2 -#define MSIM_TEXT_UNDERLINE 4 - -/* Default baseline size of purple's fonts, in points. What is size 3 in points. - * _font_scale specifies scaling factor relative to this point size. Note this - * is only the default; it is configurable in account options. */ -#define MSIM_BASE_FONT_POINT_SIZE 8 - -/* Default display's DPI. 96 is common but it can differ. Also configurable - * in account options. */ -#define MSIM_DEFAULT_DPI 96 - - -/* round is part of C99, but sometimes is unavailable before then. - * Based on http://forums.belution.com/en/cpp/000/050/13.shtml - */ -double msim_round(double value) -{ - if (value < 0) { - return -(floor(-value + 0.5)); - } else { - return floor( value + 0.5); - } -} - - -/** Convert typographical font point size to HTML font size. - * Based on libpurple/gtkimhtml.c */ -static guint -msim_point_to_purple_size(MsimSession *session, guint point) -{ - guint size, this_point, base; - gdouble scale; - - base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); - - for (size = 0; - size < sizeof(_font_scale) / sizeof(_font_scale[0]); - ++size) { - scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; - this_point = (guint)msim_round(scale * base); - - if (this_point >= point) { - purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n", - point, size); - return size; - } - } - - /* No HTML font size was this big; return largest possible. */ - return this_point; -} - -/** Convert HTML font size to point size. */ -static guint -msim_purple_size_to_point(MsimSession *session, guint size) -{ - gdouble scale; - guint point; - guint base; - - scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; - - base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); - - point = (guint)msim_round(scale * base); - - purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n", - size, point); - - return point; -} - -/** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */ -static guint -msim_height_to_point(MsimSession *session, guint height) -{ - guint dpi; - - dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); - - return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height); - - /* See also: libpurple/protocols/bonjour/jabber.c - * _font_size_ichat_to_purple */ -} - -/** Convert point size to msim pixel height font size specification, for outgoing messages. */ -static guint -msim_point_to_height(MsimSession *session, guint point) -{ - guint dpi; - - dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); - - return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point); -} - -/** Convert the msim markup <f> (font) tag into HTML. */ -static void -msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - const gchar *face, *height_str, *decor_str; - GString *gs_end, *gs_begin; - guint decor, height; - - face = xmlnode_get_attrib(root, "f"); - height_str = xmlnode_get_attrib(root, "h"); - decor_str = xmlnode_get_attrib(root, "s"); - - if (height_str) { - height = atol(height_str); - } else { - height = 12; - } - - if (decor_str) { - decor = atol(decor_str); - } else { - decor = 0; - } - - gs_begin = g_string_new(""); - /* TODO: get font size working */ - if (height && !face) { - g_string_printf(gs_begin, "<font size='%d'>", - msim_point_to_purple_size(session, msim_height_to_point(session, height))); - } else if (height && face) { - g_string_printf(gs_begin, "<font face='%s' size='%d'>", face, - msim_point_to_purple_size(session, msim_height_to_point(session, height))); - } else { - g_string_printf(gs_begin, "<font>"); - } - - /* No support for font-size CSS? */ - /* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face, - msim_height_to_point(height)); */ - - gs_end = g_string_new("</font>"); - - if (decor & MSIM_TEXT_BOLD) { - g_string_append(gs_begin, "<b>"); - g_string_prepend(gs_end, "</b>"); - } - - if (decor & MSIM_TEXT_ITALIC) { - g_string_append(gs_begin, "<i>"); - g_string_append(gs_end, "</i>"); - } - - if (decor & MSIM_TEXT_UNDERLINE) { - g_string_append(gs_begin, "<u>"); - g_string_append(gs_end, "</u>"); - } - - - *begin = g_string_free(gs_begin,FALSE); - *end = g_string_free(gs_end, FALSE); -} - -/** Convert a msim markup color to a color suitable for libpurple. - * - * @param msim Either a color name, or an rgb(x,y,z) code. - * - * @return A new string, either a color name or #rrggbb code. Must g_free(). - */ -static char * -msim_color_to_purple(const char *msim) -{ - guint red, green, blue; - - if (!msim) { - return g_strdup("black"); - } - - if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) { - /* Color name. */ - return g_strdup(msim); - } - /* TODO: rgba (alpha). */ - - return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue); -} - -/** Convert the msim markup <a> (anchor) tag into HTML. */ -static void -msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - const gchar *href; - - href = xmlnode_get_attrib(root, "h"); - if (!href) { - href = ""; - } - - *begin = g_strdup_printf("<a href=\"%s\">%s", href, href); - *end = g_strdup("</a>"); -} - -/** Convert the msim markup <p> (paragraph) tag into HTML. */ -static void -msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - /* Just pass through unchanged. - * - * Note: attributes currently aren't passed, if there are any. */ - *begin = g_strdup("<p>"); - *end = g_strdup("</p>"); -} - -/** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */ -static void -msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - const gchar *color; - gchar *purple_color; - - color = xmlnode_get_attrib(root, "v"); - if (!color) { - purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr\n"); - *begin = g_strdup(""); - *end = g_strdup(""); - /* TODO: log as unrecognized */ - return; - } - - purple_color = msim_color_to_purple(color); - - *begin = g_strdup_printf("<font color='%s'>", purple_color); - - g_free(purple_color); - - /* *begin = g_strdup_printf("<span style='color: %s'>", color); */ - *end = g_strdup("</font>"); -} - -/** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */ -static void -msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - const gchar *color; - gchar *purple_color; - - color = xmlnode_get_attrib(root, "v"); - if (!color) { - *begin = g_strdup(""); - *end = g_strdup(""); - purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr\n"); - /* TODO: log as unrecognized. */ - return; - } - - purple_color = msim_color_to_purple(color); - - /* TODO: find out how to set background color. */ - *begin = g_strdup_printf("<span style='background-color: %s'>", - purple_color); - g_free(purple_color); - - *end = g_strdup("</p>"); -} - -/** Convert the msim markup <i> tag (emoticon image) into HTML. */ -static void -msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) -{ - const gchar *name; - guint i; - struct MSIM_EMOTICON *emote; - - name = xmlnode_get_attrib(root, "n"); - if (!name) { - purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n\n"); - *begin = g_strdup(""); - *end = g_strdup(""); - /* TODO: log as unrecognized */ - return; - } - - /* Find and use canonical form of smiley symbol. */ - for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { - if (g_str_equal(name, emote->name)) { - *begin = g_strdup(emote->symbol); - *end = g_strdup(""); - return; - } - } - - /* Couldn't find it, sorry. Try to degrade gracefully. */ - *begin = g_strdup_printf("**%s**", name); - *end = g_strdup(""); -} - -/** Convert an individual msim markup tag to HTML. */ -static void -msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, - gchar **end) -{ - if (g_str_equal(root->name, "f")) { - msim_markup_f_to_html(session, root, begin, end); - } else if (g_str_equal(root->name, "a")) { - msim_markup_a_to_html(session, root, begin, end); - } else if (g_str_equal(root->name, "p")) { - msim_markup_p_to_html(session, root, begin, end); - } else if (g_str_equal(root->name, "c")) { - msim_markup_c_to_html(session, root, begin, end); - } else if (g_str_equal(root->name, "b")) { - msim_markup_b_to_html(session, root, begin, end); - } else if (g_str_equal(root->name, "i")) { - msim_markup_i_to_html(session, root, begin, end); - } else { - purple_debug_info("msim", "msim_markup_tag_to_html: " - "unknown tag name=%s, ignoring", - (root && root->name) ? root->name : "(NULL)"); - *begin = g_strdup(""); - *end = g_strdup(""); - } -} - -/** Convert an individual HTML tag to msim markup. */ -static void -html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, - gchar **end) -{ - if (!purple_utf8_strcasecmp(root->name, "root") || - !purple_utf8_strcasecmp(root->name, "html")) { - *begin = g_strdup(""); - *end = g_strdup(""); - /* TODO: Coalesce nested tags into one <f> tag! - * Currently, the 's' value will be overwritten when b/i/u is nested - * within another one, and only the inner-most formatting will be - * applied to the text. */ - } else if (!purple_utf8_strcasecmp(root->name, "b")) { - *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD); - *end = g_strdup("</f>"); - } else if (!purple_utf8_strcasecmp(root->name, "i")) { - *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC); - *end = g_strdup("</f>"); - } else if (!purple_utf8_strcasecmp(root->name, "u")) { - *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE); - *end = g_strdup("</f>"); - } else if (!purple_utf8_strcasecmp(root->name, "a")) { - const gchar *href, *link_text; - - href = xmlnode_get_attrib(root, "href"); - - if (!href) { - href = xmlnode_get_attrib(root, "HREF"); - } - - link_text = xmlnode_get_data(root); - - if (href) { - if (g_str_equal(link_text, href)) { - /* Purple gives us: <a href="URL">URL</a> - * Translate to <a h='URL' /> - * Displayed as text of URL with link to URL - */ - *begin = g_strdup_printf("<a h='%s' />", href); - } else { - /* But if we get: <a href="URL">text</a> - * Translate to: text: <a h='URL' /> - * - * Because official client only supports self-closed <a> - * tags; you can't change the link text. - */ - *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href); - } - } else { - *begin = g_strdup("<a />"); - } - - /* Sorry, kid. MySpace doesn't support you within <a> tags. */ - xmlnode_free(root->child); - root->child = NULL; - - *end = g_strdup(""); - } else if (!purple_utf8_strcasecmp(root->name, "font")) { - const gchar *size; - const gchar *face; - - size = xmlnode_get_attrib(root, "size"); - face = xmlnode_get_attrib(root, "face"); - - if (face && size) { - *begin = g_strdup_printf("<f f='%s' h='%d'>", face, - msim_point_to_height(session, - msim_purple_size_to_point(session, atoi(size)))); - } else if (face) { - *begin = g_strdup_printf("<f f='%s'>", face); - } else if (size) { - *begin = g_strdup_printf("<f h='%d'>", - msim_point_to_height(session, - msim_purple_size_to_point(session, atoi(size)))); - } else { - *begin = g_strdup("<f>"); - } - - *end = g_strdup("</f>"); - - /* TODO: color (bg uses <body>), emoticons */ - } else { - gchar *err; - -#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS - *begin = g_strdup_printf("[%s]", root->name); - *end = g_strdup_printf("[/%s]", root->name); -#else - *begin = g_strdup(""); - *end = g_strdup(""); -#endif - - err = g_strdup_printf("html_tag_to_msim_markup: unrecognized " - "HTML tag %s was sent by the IM client; ignoring", (root->name ? root->name : "(NULL)")); - msim_unrecognized(NULL, NULL, err); - g_free(err); - } -} - -/** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup. - * - * @param f Function to convert tags. - * - * @return An HTML string. Caller frees. - */ -static gchar * -msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f) -{ - xmlnode *node; - gchar *begin, *inner, *end; - GString *final; - - if (!root || !root->name) { - return g_strdup(""); - } - - purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n", - root->name); - - begin = inner = end = NULL; - - final = g_string_new(""); - - f(session, root, &begin, &end); - - g_string_append(final, begin); - - /* Loop over all child nodes. */ - for (node = root->child; node != NULL; node = node->next) { - switch (node->type) { - case XMLNODE_TYPE_ATTRIB: - /* Attributes handled above. */ - break; - - case XMLNODE_TYPE_TAG: - /* A tag or tag with attributes. Recursively descend. */ - inner = msim_convert_xmlnode(session, node, f); - g_return_val_if_fail(inner != NULL, NULL); - - purple_debug_info("msim", " ** node name=%s\n", - (node && node->name) ? node->name : "(NULL)"); - break; - - case XMLNODE_TYPE_DATA: - /* Literal text. */ - inner = g_new0(char, node->data_sz + 1); - strncpy(inner, node->data, node->data_sz); - inner[node->data_sz] = 0; - - purple_debug_info("msim", " ** node data=%s\n", - inner ? inner : "(NULL)"); - break; - - default: - purple_debug_info("msim", - "msim_convert_xmlnode: strange node\n"); - inner = g_strdup(""); - } - - if (inner) { - g_string_append(final, inner); - } - } - - /* TODO: Note that msim counts each piece of text enclosed by <f> as - * a paragraph and will display each on its own line. You actually have - * to _nest_ <f> tags to intersperse different text in one paragraph! - * Comment out this line below to see. */ - g_string_append(final, end); - - purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n", - (final && final->str) ? final->str : "(NULL)"); - - return g_string_free(final, FALSE); -} - -/** Convert XML to something based on MSIM_XMLNODE_CONVERT. */ -static gchar * -msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f) -{ - xmlnode *root; - gchar *str; - gchar *enclosed_raw; - - g_return_val_if_fail(raw != NULL, NULL); - - /* Enclose text in one root tag, to try to make it valid XML for parsing. */ - enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL); - - root = xmlnode_from_str(enclosed_raw, -1); - - if (!root) { - purple_debug_info("msim", "msim_markup_to_html: couldn't parse " - "%s as XML, returning raw: %s\n", enclosed_raw, raw); - /* TODO: msim_unrecognized */ - g_free(enclosed_raw); - return g_strdup(raw); - } - - g_free(enclosed_raw); - - str = msim_convert_xmlnode(session, root, f); - g_return_val_if_fail(str != NULL, NULL); - purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str); - - xmlnode_free(root); - - return str; -} - -/** Convert plaintext smileys to <i> markup tags. - * - * @param before Original text with ASCII smileys. Will be freed. - * @return A new string with <i> tags, if applicable. Must be g_free()'d. - */ -static gchar * -msim_convert_smileys_to_markup(gchar *before) -{ - gchar *old, *new, *replacement; - guint i; - struct MSIM_EMOTICON *emote; - - old = before; - new = NULL; - - for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { - gchar *name, *symbol; - - name = emote->name; - symbol = emote->symbol; - - replacement = g_strdup_printf("<i n=\"%s\"/>", name); - - purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n", - symbol ? symbol : "(NULL)", - replacement ? replacement : "(NULL)"); - new = purple_strreplace(old, symbol, replacement); - - g_free(replacement); - g_free(old); - - old = new; - } - - return new; -} - - -/** High-level function to convert MySpaceIM markup to Purple (HTML) markup. - * - * @return Purple markup string, must be g_free()'d. */ -gchar * -msim_markup_to_html(MsimSession *session, const gchar *raw) -{ - return msim_convert_xml(session, raw, - (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html)); -} - -/** High-level function to convert Purple (HTML) to MySpaceIM markup. - * - * TODO: consider using purple_markup_html_to_xhtml() to make valid XML. - * - * @return HTML markup string, must be g_free()'d. */ -gchar * -html_to_msim_markup(MsimSession *session, const gchar *raw) -{ - gchar *markup; - - markup = msim_convert_xml(session, raw, - (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup)); - - if (purple_account_get_bool(session->account, "emoticons", TRUE)) { - /* Frees markup and allocates a new one. */ - markup = msim_convert_smileys_to_markup(markup); - } - - return markup; -} - - +/* MySpaceIM Protocol Plugin - markup + * + * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im> + * + * 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 "myspace.h" + +typedef void (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **); + +/* Internal functions */ + +static guint msim_point_to_purple_size(MsimSession *session, guint point); +static guint msim_purple_size_to_point(MsimSession *session, guint size); +static guint msim_height_to_point(MsimSession *session, guint height); +static guint msim_point_to_height(MsimSession *session, guint point); + +static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end); +static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end); +static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f); +static gchar *msim_convert_smileys_to_markup(gchar *before); +static double msim_round(double round); + + +/* Globals */ + +/* The names in in emoticon_names (for <i n=whatever>) map to corresponding + * entries in emoticon_symbols (for the ASCII representation of the emoticon). + * + * Multiple emoticon symbols in Pidgin can map to one name. List the + * canonical form, as inserted by the "Smile!" dialog, first. For example, + * :) comes before :-), because although both are recognized as 'happy', + * the first is inserted by the smiley button (first symbol in theme). + * + * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */ +static struct MSIM_EMOTICON +{ + gchar *name; + gchar *symbol; +} msim_emoticons[] = { + /* Unfortunately, this list duplicates much of the file + * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because + * that file is part of Pidgin, but we're part of libpurple. + */ + { "bigsmile", ":D" }, + { "bigsmile", ":-D" }, + { "devil", "}:)" }, + { "frazzled", ":Z" }, + { "geek", "B)" }, + { "googles", "%)" }, + { "growl", ":E" }, + { "laugh", ":))" }, /* Must be before ':)' */ + { "happy", ":)" }, + { "happy", ":-)" }, + { "happi", ":)" }, + { "heart", ":X" }, + { "mohawk", "-:" }, + { "mad", "X(" }, + { "messed", "X)" }, + { "nerd", "Q)" }, + { "oops", ":G" }, + { "pirate", "P)" }, + { "scared", ":O" }, + { "sidefrown", ":{" }, + { "sinister", ":B" }, + { "smirk", ":," }, + { "straight", ":|" }, + { "tongue", ":P" }, + { "tongue", ":p" }, + { "tongy", ":P" }, + { "upset", "B|" }, + { "wink", ";-)" }, + { "wink", ";)" }, + { "winc", ";)" }, + { "worried", ":[" }, + { "kiss", ":x" }, + { NULL, NULL } +}; + + + +/* Indexes of this array + 1 map HTML font size to scale of normal font size. * + * Based on _point_sizes from libpurple/gtkimhtml.c + * 1 2 3 4 5 6 7 */ +static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 }; + +#define MAX_FONT_SIZE 7 /* Purple maximum font size */ +#define POINTS_PER_INCH 72 /* How many pt's in an inch */ + +/* Text formatting bits for <f s=#> */ +#define MSIM_TEXT_BOLD 1 +#define MSIM_TEXT_ITALIC 2 +#define MSIM_TEXT_UNDERLINE 4 + +/* Default baseline size of purple's fonts, in points. What is size 3 in points. + * _font_scale specifies scaling factor relative to this point size. Note this + * is only the default; it is configurable in account options. */ +#define MSIM_BASE_FONT_POINT_SIZE 8 + +/* Default display's DPI. 96 is common but it can differ. Also configurable + * in account options. */ +#define MSIM_DEFAULT_DPI 96 + + +/* round is part of C99, but sometimes is unavailable before then. + * Based on http://forums.belution.com/en/cpp/000/050/13.shtml + */ +double msim_round(double value) +{ + if (value < 0) { + return -(floor(-value + 0.5)); + } else { + return floor( value + 0.5); + } +} + + +/** Convert typographical font point size to HTML font size. + * Based on libpurple/gtkimhtml.c */ +static guint +msim_point_to_purple_size(MsimSession *session, guint point) +{ + guint size, this_point, base; + gdouble scale; + + base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); + + for (size = 0; + size < sizeof(_font_scale) / sizeof(_font_scale[0]); + ++size) { + scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; + this_point = (guint)msim_round(scale * base); + + if (this_point >= point) { + purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n", + point, size); + return size; + } + } + + /* No HTML font size was this big; return largest possible. */ + return this_point; +} + +/** Convert HTML font size to point size. */ +static guint +msim_purple_size_to_point(MsimSession *session, guint size) +{ + gdouble scale; + guint point; + guint base; + + scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; + + base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); + + point = (guint)msim_round(scale * base); + + purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n", + size, point); + + return point; +} + +/** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */ +static guint +msim_height_to_point(MsimSession *session, guint height) +{ + guint dpi; + + dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); + + return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height); + + /* See also: libpurple/protocols/bonjour/jabber.c + * _font_size_ichat_to_purple */ +} + +/** Convert point size to msim pixel height font size specification, for outgoing messages. */ +static guint +msim_point_to_height(MsimSession *session, guint point) +{ + guint dpi; + + dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); + + return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point); +} + +/** Convert the msim markup <f> (font) tag into HTML. */ +static void +msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + const gchar *face, *height_str, *decor_str; + GString *gs_end, *gs_begin; + guint decor, height; + + face = xmlnode_get_attrib(root, "f"); + height_str = xmlnode_get_attrib(root, "h"); + decor_str = xmlnode_get_attrib(root, "s"); + + if (height_str) { + height = atol(height_str); + } else { + height = 12; + } + + if (decor_str) { + decor = atol(decor_str); + } else { + decor = 0; + } + + gs_begin = g_string_new(""); + /* TODO: get font size working */ + if (height && !face) { + g_string_printf(gs_begin, "<font size='%d'>", + msim_point_to_purple_size(session, msim_height_to_point(session, height))); + } else if (height && face) { + g_string_printf(gs_begin, "<font face='%s' size='%d'>", face, + msim_point_to_purple_size(session, msim_height_to_point(session, height))); + } else { + g_string_printf(gs_begin, "<font>"); + } + + /* No support for font-size CSS? */ + /* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face, + msim_height_to_point(height)); */ + + gs_end = g_string_new("</font>"); + + if (decor & MSIM_TEXT_BOLD) { + g_string_append(gs_begin, "<b>"); + g_string_prepend(gs_end, "</b>"); + } + + if (decor & MSIM_TEXT_ITALIC) { + g_string_append(gs_begin, "<i>"); + g_string_append(gs_end, "</i>"); + } + + if (decor & MSIM_TEXT_UNDERLINE) { + g_string_append(gs_begin, "<u>"); + g_string_append(gs_end, "</u>"); + } + + + *begin = g_string_free(gs_begin, FALSE); + *end = g_string_free(gs_end, FALSE); +} + +/** Convert a msim markup color to a color suitable for libpurple. + * + * @param msim Either a color name, or an rgb(x,y,z) code. + * + * @return A new string, either a color name or #rrggbb code. Must g_free(). + */ +static char * +msim_color_to_purple(const char *msim) +{ + guint red, green, blue; + + if (!msim) { + return g_strdup("black"); + } + + if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) { + /* Color name. */ + return g_strdup(msim); + } + /* TODO: rgba (alpha). */ + + return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue); +} + +/** Convert the msim markup <a> (anchor) tag into HTML. */ +static void +msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + const gchar *href; + + href = xmlnode_get_attrib(root, "h"); + if (!href) { + href = ""; + } + + *begin = g_strdup_printf("<a href=\"%s\">%s", href, href); + *end = g_strdup("</a>"); +} + +/** Convert the msim markup <p> (paragraph) tag into HTML. */ +static void +msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + /* Just pass through unchanged. + * + * Note: attributes currently aren't passed, if there are any. */ + *begin = g_strdup("<p>"); + *end = g_strdup("</p>"); +} + +/** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */ +static void +msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + const gchar *color; + gchar *purple_color; + + color = xmlnode_get_attrib(root, "v"); + if (!color) { + purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr\n"); + *begin = g_strdup(""); + *end = g_strdup(""); + /* TODO: log as unrecognized */ + return; + } + + purple_color = msim_color_to_purple(color); + + *begin = g_strdup_printf("<font color='%s'>", purple_color); + + g_free(purple_color); + + /* *begin = g_strdup_printf("<span style='color: %s'>", color); */ + *end = g_strdup("</font>"); +} + +/** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */ +static void +msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + const gchar *color; + gchar *purple_color; + + color = xmlnode_get_attrib(root, "v"); + if (!color) { + *begin = g_strdup(""); + *end = g_strdup(""); + purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr\n"); + /* TODO: log as unrecognized. */ + return; + } + + purple_color = msim_color_to_purple(color); + + /* TODO: find out how to set background color. */ + *begin = g_strdup_printf("<span style='background-color: %s'>", + purple_color); + g_free(purple_color); + + *end = g_strdup("</p>"); +} + +/** Convert the msim markup <i> tag (emoticon image) into HTML. */ +static void +msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) +{ + const gchar *name; + guint i; + struct MSIM_EMOTICON *emote; + + name = xmlnode_get_attrib(root, "n"); + if (!name) { + purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n\n"); + *begin = g_strdup(""); + *end = g_strdup(""); + /* TODO: log as unrecognized */ + return; + } + + /* Find and use canonical form of smiley symbol. */ + for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { + if (g_str_equal(name, emote->name)) { + *begin = g_strdup(emote->symbol); + *end = g_strdup(""); + return; + } + } + + /* Couldn't find it, sorry. Try to degrade gracefully. */ + *begin = g_strdup_printf("**%s**", name); + *end = g_strdup(""); +} + +/** Convert an individual msim markup tag to HTML. */ +static void +msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, + gchar **end) +{ + if (g_str_equal(root->name, "f")) { + msim_markup_f_to_html(session, root, begin, end); + } else if (g_str_equal(root->name, "a")) { + msim_markup_a_to_html(session, root, begin, end); + } else if (g_str_equal(root->name, "p")) { + msim_markup_p_to_html(session, root, begin, end); + } else if (g_str_equal(root->name, "c")) { + msim_markup_c_to_html(session, root, begin, end); + } else if (g_str_equal(root->name, "b")) { + msim_markup_b_to_html(session, root, begin, end); + } else if (g_str_equal(root->name, "i")) { + msim_markup_i_to_html(session, root, begin, end); + } else { + purple_debug_info("msim", "msim_markup_tag_to_html: " + "unknown tag name=%s, ignoring", + (root && root->name) ? root->name : "(NULL)"); + *begin = g_strdup(""); + *end = g_strdup(""); + } +} + +/** Convert an individual HTML tag to msim markup. */ +static void +html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, + gchar **end) +{ + if (!purple_utf8_strcasecmp(root->name, "root") || + !purple_utf8_strcasecmp(root->name, "html")) { + *begin = g_strdup(""); + *end = g_strdup(""); + /* TODO: Coalesce nested tags into one <f> tag! + * Currently, the 's' value will be overwritten when b/i/u is nested + * within another one, and only the inner-most formatting will be + * applied to the text. */ + } else if (!purple_utf8_strcasecmp(root->name, "b")) { + *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD); + *end = g_strdup("</f>"); + } else if (!purple_utf8_strcasecmp(root->name, "i")) { + *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC); + *end = g_strdup("</f>"); + } else if (!purple_utf8_strcasecmp(root->name, "u")) { + *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE); + *end = g_strdup("</f>"); + } else if (!purple_utf8_strcasecmp(root->name, "a")) { + const gchar *href, *link_text; + + href = xmlnode_get_attrib(root, "href"); + + if (!href) { + href = xmlnode_get_attrib(root, "HREF"); + } + + link_text = xmlnode_get_data(root); + + if (href) { + if (g_str_equal(link_text, href)) { + /* Purple gives us: <a href="URL">URL</a> + * Translate to <a h='URL' /> + * Displayed as text of URL with link to URL + */ + *begin = g_strdup_printf("<a h='%s' />", href); + } else { + /* But if we get: <a href="URL">text</a> + * Translate to: text: <a h='URL' /> + * + * Because official client only supports self-closed <a> + * tags; you can't change the link text. + */ + *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href); + } + } else { + *begin = g_strdup("<a />"); + } + + /* Sorry, kid. MySpace doesn't support you within <a> tags. */ + xmlnode_free(root->child); + root->child = NULL; + + *end = g_strdup(""); + } else if (!purple_utf8_strcasecmp(root->name, "font")) { + const gchar *size; + const gchar *face; + + size = xmlnode_get_attrib(root, "size"); + face = xmlnode_get_attrib(root, "face"); + + if (face && size) { + *begin = g_strdup_printf("<f f='%s' h='%d'>", face, + msim_point_to_height(session, + msim_purple_size_to_point(session, atoi(size)))); + } else if (face) { + *begin = g_strdup_printf("<f f='%s'>", face); + } else if (size) { + *begin = g_strdup_printf("<f h='%d'>", + msim_point_to_height(session, + msim_purple_size_to_point(session, atoi(size)))); + } else { + *begin = g_strdup("<f>"); + } + + *end = g_strdup("</f>"); + + /* TODO: color (bg uses <body>), emoticons */ + } else { + gchar *err; + +#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS + *begin = g_strdup_printf("[%s]", root->name); + *end = g_strdup_printf("[/%s]", root->name); +#else + *begin = g_strdup(""); + *end = g_strdup(""); +#endif + + err = g_strdup_printf("html_tag_to_msim_markup: unrecognized " + "HTML tag %s was sent by the IM client; ignoring", + root->name ? root->name : "(NULL)"); + msim_unrecognized(NULL, NULL, err); + g_free(err); + } +} + +/** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup. + * + * @param f Function to convert tags. + * + * @return An HTML string. Caller frees. + */ +static gchar * +msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f) +{ + xmlnode *node; + gchar *begin, *inner, *end; + GString *final; + + if (!root || !root->name) { + return g_strdup(""); + } + + purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n", + root->name); + + begin = inner = end = NULL; + + final = g_string_new(""); + + f(session, root, &begin, &end); + + g_string_append(final, begin); + + /* Loop over all child nodes. */ + for (node = root->child; node != NULL; node = node->next) { + switch (node->type) { + case XMLNODE_TYPE_ATTRIB: + /* Attributes handled above. */ + break; + + case XMLNODE_TYPE_TAG: + /* A tag or tag with attributes. Recursively descend. */ + inner = msim_convert_xmlnode(session, node, f); + g_return_val_if_fail(inner != NULL, NULL); + + purple_debug_info("msim", " ** node name=%s\n", + (node && node->name) ? node->name : "(NULL)"); + break; + + case XMLNODE_TYPE_DATA: + /* Literal text. */ + inner = g_new0(char, node->data_sz + 1); + strncpy(inner, node->data, node->data_sz); + inner[node->data_sz] = 0; + + purple_debug_info("msim", " ** node data=%s\n", + inner ? inner : "(NULL)"); + break; + + default: + purple_debug_info("msim", + "msim_convert_xmlnode: strange node\n"); + inner = g_strdup(""); + } + + if (inner) { + g_string_append(final, inner); + } + } + + /* TODO: Note that msim counts each piece of text enclosed by <f> as + * a paragraph and will display each on its own line. You actually have + * to _nest_ <f> tags to intersperse different text in one paragraph! + * Comment out this line below to see. */ + g_string_append(final, end); + + purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n", + (final && final->str) ? final->str : "(NULL)"); + + return g_string_free(final, FALSE); +} + +/** Convert XML to something based on MSIM_XMLNODE_CONVERT. */ +static gchar * +msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f) +{ + xmlnode *root; + gchar *str; + gchar *enclosed_raw; + + g_return_val_if_fail(raw != NULL, NULL); + + /* Enclose text in one root tag, to try to make it valid XML for parsing. */ + enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL); + + root = xmlnode_from_str(enclosed_raw, -1); + + if (!root) { + purple_debug_info("msim", "msim_markup_to_html: couldn't parse " + "%s as XML, returning raw: %s\n", enclosed_raw, raw); + /* TODO: msim_unrecognized */ + g_free(enclosed_raw); + return g_strdup(raw); + } + + g_free(enclosed_raw); + + str = msim_convert_xmlnode(session, root, f); + g_return_val_if_fail(str != NULL, NULL); + purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str); + + xmlnode_free(root); + + return str; +} + +/** Convert plaintext smileys to <i> markup tags. + * + * @param before Original text with ASCII smileys. Will be freed. + * @return A new string with <i> tags, if applicable. Must be g_free()'d. + */ +static gchar * +msim_convert_smileys_to_markup(gchar *before) +{ + gchar *old, *new, *replacement; + guint i; + struct MSIM_EMOTICON *emote; + + old = before; + new = NULL; + + for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { + gchar *name, *symbol; + + name = emote->name; + symbol = emote->symbol; + + replacement = g_strdup_printf("<i n=\"%s\"/>", name); + + purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n", + symbol ? symbol : "(NULL)", + replacement ? replacement : "(NULL)"); + new = purple_strreplace(old, symbol, replacement); + + g_free(replacement); + g_free(old); + + old = new; + } + + return new; +} + + +/** High-level function to convert MySpaceIM markup to Purple (HTML) markup. + * + * @return Purple markup string, must be g_free()'d. */ +gchar * +msim_markup_to_html(MsimSession *session, const gchar *raw) +{ + return msim_convert_xml(session, raw, + (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html)); +} + +/** High-level function to convert Purple (HTML) to MySpaceIM markup. + * + * TODO: consider using purple_markup_html_to_xhtml() to make valid XML. + * + * @return HTML markup string, must be g_free()'d. */ +gchar * +html_to_msim_markup(MsimSession *session, const gchar *raw) +{ + gchar *markup; + + markup = msim_convert_xml(session, raw, + (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup)); + + if (purple_account_get_bool(session->account, "emoticons", TRUE)) { + /* Frees markup and allocates a new one. */ + markup = msim_convert_smileys_to_markup(markup); + } + + return markup; +} + +
--- a/libpurple/protocols/myspace/myspace.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Mon Oct 01 17:51:20 2007 +0000 @@ -291,9 +291,10 @@ /* Notify an error message also, because this is important! */ purple_notify_error(acct, g_strdup(_("MySpaceIM Error")), str, NULL); + gc->wants_to_die = TRUE; purple_connection_error(gc, str); - g_free(str); + return; } #endif @@ -1791,11 +1792,13 @@ /* Destroy session if fatal. */ if (msim_msg_get(msg, "fatal")) { purple_debug_info("msim", "fatal error, closing\n"); - if (err == 260) { - /* Incorrect password */ - session->gc->wants_to_die = TRUE; - if (!purple_account_get_remember_password(session->account)) - purple_account_set_password(session->account, NULL); + switch (err) { + case 260: /* Incorrect password */ + case 6: /* Logged in elsewhere */ + session->gc->wants_to_die = TRUE; + if (!purple_account_get_remember_password(session->account)) + purple_account_set_password(session->account, NULL); + break; } purple_connection_error(session->gc, full_errmsg); } else {
--- a/libpurple/protocols/myspace/zap.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/myspace/zap.c Mon Oct 01 17:51:20 2007 +0000 @@ -41,15 +41,52 @@ types = g_list_append(types, attn); /* TODO: icons for each zap */ + + /* Lots of comments for translators: */ + + /* Zap means "to strike suddenly and forcefully as if with a + * projectile or weapon." This term often has an electrical + * connotation, for example, "he was zapped by electricity when + * he put a fork in the toaster." */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s...")); + + /* Whack means "to hit or strike someone with a sharp blow" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s...")); + + /* Torch means "to set on fire." Don't worry, this doesn't + * make a whole lot of sense in English, either. Feel free + * to translate it literally. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s...")); + + /* Smooch means "to kiss someone, often enthusiastically" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s...")); + + /* A hug is a display of affection; wrapping your arms around someone */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s...")); + + /* Slap means "to hit someone with an open/flat hand" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s...")); + + /* Goose means "to pinch someone on their butt" */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s...")); + + /* A high-five is when two people's hands slap each other + * in the air above their heads. It is done to celebrate + * something, often a victory, or to congratulate someone. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s...")); + + /* We're not entirely sure what the MySpace people mean by + * this... but we think it's the equivalent of "prank." Or, for + * someone to perform a mischievous trick or practical joke. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s...")); + + /* Raspberry is a slang term for the vibrating sound made + * when you stick your tongue out of your mouth with your + * lips closed and blow. It is typically done when + * gloating or bragging. Nowadays it's a pretty silly + * gesture, so it does not carry a harsh negative + * connotation. It is generally used in a playful tone + * with friends. */ _MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s...")); }
--- a/libpurple/protocols/novell/novell.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/novell/novell.c Mon Oct 01 17:51:20 2007 +0000 @@ -130,6 +130,8 @@ if (ret_code == NMERR_AUTHENTICATION_FAILED || ret_code == NMERR_CREDENTIALS_MISSING || ret_code == NMERR_PASSWORD_INVALID) { + if (!purple_account_get_remember_password(gc->account)) + purple_account_set_password(gc->account, NULL); gc->wants_to_die = TRUE; } purple_connection_error(gc, err); @@ -2004,11 +2006,14 @@ _evt_user_disconnect(NMUser * user, NMEvent * event) { PurpleConnection *gc; - - gc = purple_account_get_connection((PurpleAccount *) user->client_data); + PurpleAccount *account = user->client_data; + + gc = purple_account_get_connection(account); if (gc) { gc->wants_to_die = TRUE; /* we don't want to reconnect in this case */ + if (!purple_account_get_remember_password(account)) + purple_account_set_password(account, NULL); purple_connection_error(gc, _("You have been logged out because you" " logged in at another workstation.")); } @@ -2799,7 +2804,7 @@ const char *text = NULL; if (buddy == NULL) - return; + return; gc = purple_account_get_connection(buddy->account); if (gc == NULL || (user = gc->proto_data) == NULL)
--- a/libpurple/protocols/oscar/flap_connection.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Mon Oct 01 17:51:20 2007 +0000 @@ -382,6 +382,8 @@ gchar *tmp; if (conn->disconnect_code == 0x0001) { tmp = g_strdup(_("You have signed on from another location.")); + if (!purple_account_get_remember_password(account)) + purple_account_set_password(account, NULL); od->gc->wants_to_die = TRUE; } else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED) tmp = g_strdup(_("Server closed the connection."));
--- a/libpurple/protocols/oscar/odc.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/oscar/odc.c Mon Oct 01 17:51:20 2007 +0000 @@ -27,6 +27,8 @@ #include "imgstore.h" #include "util.h" +#define DIRECTIM_MAX_FILESIZE 52428800 + /** * Free any ODC related data and print a message to the conversation * window based on conn->disconnect_reason. @@ -587,6 +589,27 @@ if (frame->payload.len > 0) { + if (frame->payload.len > DIRECTIM_MAX_FILESIZE) + { + gchar *tmp, *size1, *size2; + PurpleAccount *account; + PurpleConversation *conv; + + size1 = purple_str_size_to_units(frame->payload.len); + size2 = purple_str_size_to_units(DIRECTIM_MAX_FILESIZE); + tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM. Try using file transfer instead.\n"), conn->sn, size1, size2); + g_free(size1); + g_free(size2); + + account = purple_connection_get_account(conn->od->gc); + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + + peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL); + return; + } + /* We have payload data! Switch to the ODC watcher to read it. */ frame->payload.data = g_new(guint8, frame->payload.len); frame->payload.offset = 0;
--- a/libpurple/protocols/oscar/oscar.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Mon Oct 01 17:51:20 2007 +0000 @@ -2184,12 +2184,14 @@ { PurpleConnection *gc; OscarData *od; + PurpleAccount *account; PurpleBuddy *buddy; PurpleGroup *group; gc = data->gc; od = gc->proto_data; - buddy = purple_find_buddy(purple_connection_get_account(gc), data->name); + account = purple_connection_get_account(gc); + buddy = purple_find_buddy(account, data->name); if (buddy != NULL) group = purple_buddy_get_group(buddy); else @@ -2201,7 +2203,19 @@ buddy->name, group->name); aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); if (!aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY)) + { aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); + + /* Mobile users should always be online */ + if (buddy->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_MOBILE, NULL); + } + } } } @@ -4621,12 +4635,16 @@ void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { - OscarData *od = (OscarData *)gc->proto_data; + OscarData *od; + PurpleAccount *account; + + od = (OscarData *)gc->proto_data; + account = purple_connection_get_account(gc); if (!aim_snvalid(buddy->name)) { gchar *buf; buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid. Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name); - if (!purple_conv_present_error(buddy->name, purple_connection_get_account(gc), buf)) + if (!purple_conv_present_error(buddy->name, account, buf)) purple_notify_error(gc, NULL, _("Unable To Add"), buf); g_free(buf); @@ -4640,6 +4658,16 @@ purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", buddy->name, group->name); aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); + + /* Mobile users should always be online */ + if (buddy->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_MOBILE, NULL); + } } /* XXX - Should this be done from AIM accounts, as well? */ @@ -4955,6 +4983,17 @@ g_free(comment); } } + + /* Mobile users should always be online */ + if (b->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_MOBILE, NULL); + } + g_free(gname_utf8); g_free(alias_utf8); } @@ -5145,6 +5184,17 @@ purple_debug_info("oscar", "ssi: adding buddy %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans")); purple_blist_add_buddy(b, NULL, g, NULL); + + /* Mobile users should always be online */ + if (b->name[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(b), + OSCAR_STATUS_ID_MOBILE, NULL); + } + } g_free(gname_utf8); @@ -5523,6 +5573,8 @@ return "hiptop"; if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM) return "secure"; + if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY) + return "birthday"; } return NULL; }
--- a/libpurple/protocols/qq/login_logout.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/qq/login_logout.c Mon Oct 01 17:51:20 2007 +0000 @@ -480,6 +480,8 @@ switch (ret) { case QQ_LOGIN_REPLY_PWD_ERROR: gc->wants_to_die = TRUE; + if (!purple_account_get_remember_password(gc->account)) + purple_account_set_password(gc->account, NULL); purple_connection_error(gc, _("Incorrect password.")); break; case QQ_LOGIN_REPLY_MISC_ERROR:
--- a/libpurple/protocols/simple/simple.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/simple/simple.c Mon Oct 01 17:51:20 2007 +0000 @@ -695,7 +695,7 @@ static void do_register_exp(struct simple_account_data *sip, int expire) { char *uri, *to, *contact, *hdr; - /* Set our default expiration to 900, + /* Set our default expiration to 900, * as done in the initialization of the simple_account_data * structure. */ @@ -1042,6 +1042,8 @@ if(sip->registrar.retries > SIMPLE_REGISTER_RETRY_MAX) { purple_debug_info("simple", "Setting wants_to_die to true.\n"); sip->gc->wants_to_die = TRUE; + if (!purple_account_get_remember_password(sip->gc->account)) + purple_account_set_password(sip->gc->account, NULL); purple_connection_error(sip->gc, _("Incorrect password.")); return TRUE; }
--- a/libpurple/protocols/yahoo/yahoo.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Mon Oct 01 17:51:20 2007 +0000 @@ -202,6 +202,8 @@ if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { gc->wants_to_die = TRUE; + if (!purple_account_get_remember_password(account)) + purple_account_set_password(account, NULL); purple_connection_error(gc, _("You have signed on from another location.")); return; } @@ -4090,12 +4092,12 @@ { return TRUE; } - + gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type) { PurpleConversation *c; - c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, gc->account); g_return_val_if_fail(c != NULL, FALSE); @@ -4120,7 +4122,7 @@ attn->incoming_description = _("%s has buzzed you!"); attn->outgoing_description = _("Buzzing %s..."); list = g_list_append(list, attn); - } + } return list; }
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Mon Oct 01 17:51:20 2007 +0000 @@ -281,13 +281,9 @@ } } } else { - /* TODO: Using xfer->fd like this is probably a bad thing... */ + xfer->fd = -1; if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port, - yahoo_receivefile_connected, xfer) == NULL) - xfer->fd = -1; - else - xfer->fd = 0; - if (xfer->fd == -1) { + yahoo_receivefile_connected, xfer) == NULL) { purple_notify_error(gc, NULL, _("File Transfer Failed"), _("Unable to establish file descriptor.")); purple_xfer_cancel_remote(xfer); @@ -456,26 +452,29 @@ { struct yahoo_pair *pair = l->data; - if(pair->key == 5) /* Get who the packet is for */ + switch(pair->key) { + case 5: /* Get who the packet is for */ me = pair->value; - - if(pair->key == 4) /* Get who the packet is from */ + break; + case 4: /* Get who the packet is from */ from = pair->value; - - if(pair->key == 49) /* Get the type of service */ + break; + case 49: /* Get the type of service */ service = pair->value; - - if(pair->key == 14) /* Get the 'message' of the packet */ + break; + case 14: /* Get the 'message' of the packet */ message = pair->value; - - if(pair->key == 13) /* Get the command associated with this packet */ + break; + case 13: /* Get the command associated with this packet */ command = pair->value; - - if(pair->key == 63) /* IMVironment name and version */ + break; + case 63: /* IMVironment name and version */ imv = pair->value; - - if(pair->key == 64) /* Not sure, but it does vary with initialization of Doodle */ + break; + case 64: /* Not sure, but it does vary with initialization of Doodle */ unknown = pair->value; /* So, I'll keep it (for a little while atleast) */ + break; + } l = l->next; } @@ -485,7 +484,7 @@ { /* Check for a Doodle packet and handle it accordingly */ if(strstr(imv, "doodle;") != NULL) - yahoo_doodle_process(gc, me, from, command, message); + yahoo_doodle_process(gc, me, from, command, message, imv); /* If an IMVIRONMENT packet comes without a specific imviroment name */ if(!strcmp(imv, ";0")) @@ -517,24 +516,35 @@ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - if (pair->key == 4) + switch (pair->key) { + case 4: from = pair->value; - if (pair->key == 5) + break; + case 5: to = pair->value; - if (pair->key == 14) + break; + case 14: msg = pair->value; - if (pair->key == 20) + break; + case 20: url = pair->value; - if (pair->key == 38) + break; + case 38: expires = strtol(pair->value, NULL, 10); - if (pair->key == 27) + break; + case 27: filename = pair->value; - if (pair->key == 28) + break; + case 28: filesize = atol(pair->value); - if (pair->key == 49) + break; + case 49: service = pair->value; - if (pair->key == 63) + break; + case 63: imv = pair->value; + break; + } } /*
--- a/libpurple/proxy.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/proxy.c Mon Oct 01 17:51:20 2007 +0000 @@ -401,7 +401,7 @@ */ if (!PURPLE_PROXY_CONNECT_DATA_IS_VALID(connect_data)) return; - + purple_debug_info("proxy", "Connected to %s:%d.\n", connect_data->host, connect_data->port); @@ -1993,6 +1993,13 @@ proxy_pref_cb, NULL); purple_prefs_connect_callback(handle, "/purple/proxy/password", proxy_pref_cb, NULL); + + /* Load the initial proxy settings */ + purple_prefs_trigger_callback("/purple/proxy/type"); + purple_prefs_trigger_callback("/purple/proxy/host"); + purple_prefs_trigger_callback("/purple/proxy/port"); + purple_prefs_trigger_callback("/purple/proxy/username"); + purple_prefs_trigger_callback("/purple/proxy/password"); } void
--- a/libpurple/server.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/server.c Mon Oct 01 17:51:20 2007 +0000 @@ -543,7 +543,7 @@ PurpleMessageFlags flags, time_t mtime) { PurpleAccount *account; - PurpleConversation *cnv; + PurpleConversation *conv; char *message, *name; char *angel, *buffy; int plugin_return; @@ -562,22 +562,19 @@ * We should update the conversation window buttons and menu, * if it exists. */ - cnv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account); /* - * Plugin stuff. we pass a char ** but we don't want to pass what's - * been given us by the prpls. So we create temp holders and pass - * those instead. It's basically just to avoid segfaults. + * Make copies of the message and the sender in case plugins want + * to free these strings and replace them with a modifed version. */ - /* TODO: MAX(message, BUF_LONG) is pretty ugly. */ - buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG)); - strcpy(buffy, msg); + buffy = g_strdup(msg); angel = g_strdup(who); plugin_return = GPOINTER_TO_INT( purple_signal_emit_return_1(purple_conversations_get_handle(), "receiving-im-msg", gc->account, - &angel, &buffy, cnv, &flags)); + &angel, &buffy, conv, &flags)); if (!buffy || !angel || plugin_return) { g_free(buffy); @@ -589,21 +586,21 @@ message = buffy; purple_signal_emit(purple_conversations_get_handle(), "received-im-msg", gc->account, - name, message, cnv, flags); + name, message, conv, flags); /* search for conversation again in case it was created by received-im-msg handler */ - if (cnv == NULL) - cnv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account); + if (conv == NULL) + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account); /* * XXX: Should we be setting this here, or relying on prpls to set it? */ flags |= PURPLE_MESSAGE_RECV; - if (cnv == NULL) - cnv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); + if (conv == NULL) + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); - purple_conv_im_write(PURPLE_CONV_IM(cnv), NULL, message, flags, mtime); + purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, message, flags, mtime); g_free(message); /* @@ -670,7 +667,7 @@ { serv_send_im(gc, name, away_msg, PURPLE_MESSAGE_AUTO_RESP); - purple_conv_im_write(PURPLE_CONV_IM(cnv), NULL, away_msg, + purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, away_msg, PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_AUTO_RESP, mtime); } @@ -892,15 +889,10 @@ return; /* - * Plugin stuff. We pass a char ** but we don't want to pass what's - * been given us by the prpls. so we create temp holders and pass those - * instead. It's basically just to avoid segfaults. Of course, if the - * data is binary, plugins don't see it. Bitch all you want; i really - * don't want you to be dealing with it. + * Make copies of the message and the sender in case plugins want + * to free these strings and replace them with a modifed version. */ - /* TODO: MAX(message, BUF_LONG) is pretty ugly. */ - buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); - strcpy(buffy, message); + buffy = g_strdup(message); angel = g_strdup(who); plugin_return = GPOINTER_TO_INT( @@ -913,6 +905,7 @@ g_free(angel); return; } + who = angel; message = buffy;
--- a/libpurple/sslconn.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/sslconn.h Mon Oct 01 17:51:20 2007 +0000 @@ -31,6 +31,7 @@ #define PURPLE_SSL_DEFAULT_PORT 443 +/** Possible SSL errors. */ typedef enum { PURPLE_SSL_HANDSHAKE_FAILED = 1, @@ -86,39 +87,48 @@ typedef struct { /** Initializes the SSL system provided. - * @return TRUE if initialization succeeded - */ + * @return @a TRUE if initialization succeeded + * @see purple_ssl_init + */ gboolean (*init)(void); - /** Unloads the SSL system. Inverse of init. */ + /** Unloads the SSL system. Inverse of PurpleSslOps::init. + * @see purple_ssl_uninit + */ void (*uninit)(void); - /** Sets up the SSL connection for a PurpleSslConnection once - * the TCP connection has been established */ + /** Sets up the SSL connection for a #PurpleSslConnection once + * the TCP connection has been established + * @see purple_ssl_connect + */ void (*connectfunc)(PurpleSslConnection *gsc); /** Destroys the internal data of the SSL connection provided. * Freeing gsc itself is left to purple_ssl_close() - * + * @see purple_ssl_close */ void (*close)(PurpleSslConnection *gsc); /** Reads data from a connection (like POSIX read()) - * @param gsc Connection context - * @param data Pointer to buffer to drop data into - * @param len Maximum number of bytes to read - * @return Number of bytes actually written into the buffer, or <0 on error + * @param gsc Connection context + * @param data Pointer to buffer to drop data into + * @param len Maximum number of bytes to read + * @return Number of bytes actually written into @a data (which may be + * less than @a len), or <0 on error + * @see purple_ssl_read */ size_t (*read)(PurpleSslConnection *gsc, void *data, size_t len); /** Writes data to a connection (like POSIX send()) - * @param gsc Connection context - * @param data Data buffer to send data from - * @param len Number of bytes to send from buffer - * @return The number of bytes written (may be less than len) or <0 on error + * @param gsc Connection context + * @param data Data buffer to send data from + * @param len Number of bytes to send from buffer + * @return The number of bytes written to @a data (may be less than + * @a len) or <0 on error + * @see purple_ssl_write */ size_t (*write)(PurpleSslConnection *gsc, const void *data, size_t len); /** Obtains the certificate chain provided by the peer * * @param gsc Connection context - * @return A newly allocated list containing the certificates - * the peer provided. - * @see PurpleCertificate + * @return A newly allocated list of #PurpleCertificate containing the + * certificates the peer provided. + * @see purple_ssl_get_peer_certificates * @todo Decide whether the ordering of certificates in this * list can be guaranteed. */ @@ -141,12 +151,12 @@ /** * Returns whether or not SSL is currently supported. * - * @return TRUE if SSL is supported, or FALSE otherwise. + * @return @a TRUE if SSL is supported, or @a FALSE otherwise. */ gboolean purple_ssl_is_supported(void); /** - * Returns a human-readable string for an SSL error + * Returns a human-readable string for an SSL error. * * @param error Error code * @return Human-readable error explanation @@ -163,8 +173,8 @@ * @param port The destination port. * @param func The SSL input handler function. * @param error_func The SSL error handler function. This function - * should NOT call purple_ssl_close(). In the event - * of an error the PurpleSslConnection will be + * should <strong>NOT</strong> call purple_ssl_close(). In + * the event of an error the #PurpleSslConnection will be * destroyed for you. * @param data User-defined data. * @@ -177,7 +187,8 @@ /** * Makes a SSL connection using an already open file descriptor. - * DEPRECATED. Use purple_ssl_connect_with_host_fd instead. + * + * @deprecated Use purple_ssl_connect_with_host_fd() instead. * * @param account The account making the connection. * @param fd The file descriptor. @@ -256,7 +267,7 @@ * @param gsc The SSL connection handle * * @return The peer certificate chain, in the order of certificate, issuer, - * issuer's issuer, etc. NULL if no certificates have been provided, + * issuer's issuer, etc. @a NULL if no certificates have been provided, */ GList * purple_ssl_get_peer_certificates(PurpleSslConnection *gsc);
--- a/libpurple/status.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/status.c Mon Oct 01 17:51:20 2007 +0000 @@ -1679,6 +1679,14 @@ purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg", score_pref_changed_cb, GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE)); + + purple_prefs_trigger_callback("/purple/status/scores/offline"); + purple_prefs_trigger_callback("/purple/status/scores/available"); + purple_prefs_trigger_callback("/purple/status/scores/invisible"); + purple_prefs_trigger_callback("/purple/status/scores/away"); + purple_prefs_trigger_callback("/purple/status/scores/extended_away"); + purple_prefs_trigger_callback("/purple/status/scores/idle"); + purple_prefs_trigger_callback("/purple/status/scores/offline_msg"); } void
--- a/libpurple/upnp.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/upnp.c Mon Oct 01 17:51:20 2007 +0000 @@ -553,7 +553,7 @@ dd->inpa = 0; close(dd->fd); - dd->fd = 0; + dd->fd = -1; /* parse the response, and see if it was a success */ purple_upnp_parse_discover_response(buf, len, dd);
--- a/libpurple/util.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/util.c Mon Oct 01 17:51:20 2007 +0000 @@ -515,23 +515,6 @@ * Date/Time Functions **************************************************************************/ -#ifdef _WIN32 -static long win32_get_tz_offset() { - TIME_ZONE_INFORMATION tzi; - DWORD ret; - long off = -1; - - if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID) - { - off = -(tzi.Bias * 60); - if (ret == TIME_ZONE_ID_DAYLIGHT) - off -= tzi.DaylightBias * 60; - } - - return off; -} -#endif - const char *purple_get_tzoff_str(const struct tm *tm, gboolean iso) { static char buf[7]; @@ -546,7 +529,7 @@ g_return_val_if_reached(""); #ifdef _WIN32 - if ((off = win32_get_tz_offset()) == -1) + if ((off = wpurple_get_tz_offset()) == -1) return ""; #else # ifdef HAVE_TM_GMTOFF @@ -854,7 +837,7 @@ #endif #ifdef _WIN32 - if ((sys_tzoff = win32_get_tz_offset()) == -1) + if ((sys_tzoff = wpurple_get_tz_offset()) == -1) tzoff = PURPLE_NO_TZ_OFF; else tzoff += sys_tzoff; @@ -3871,6 +3854,7 @@ gfud->full = full; gfud->request = g_strdup(request); gfud->include_headers = include_headers; + gfud->fd = -1; purple_url_parse(url, &gfud->website.address, &gfud->website.port, &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
--- a/libpurple/win32/win32dep.c Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/win32/win32dep.c Mon Oct 01 17:51:20 2007 +0000 @@ -575,6 +575,22 @@ libpurpledll_hInstance = NULL; } +long +wpurple_get_tz_offset() { + TIME_ZONE_INFORMATION tzi; + DWORD ret; + long off = -1; + + if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID) + { + off = -(tzi.Bias * 60); + if (ret == TIME_ZONE_ID_DAYLIGHT) + off -= tzi.DaylightBias * 60; + } + + return off; +} + /* DLL initializer */ /* suppress gcc "no previous prototype" warning */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
--- a/libpurple/win32/win32dep.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/win32/win32dep.h Mon Oct 01 17:51:20 2007 +0000 @@ -60,6 +60,7 @@ void wpurple_init(void); void wpurple_cleanup(void); +long wpurple_get_tz_offset(void); /* * MACROS
--- a/libpurple/xmlnode.h Mon Oct 01 17:49:01 2007 +0000 +++ b/libpurple/xmlnode.h Mon Oct 01 17:51:20 2007 +0000 @@ -129,7 +129,7 @@ * * @param node The node to get data from. * - * @return The data from the node. This data is in raw escaped format. + * @return The data from the node or NULL. This data is in raw escaped format. * You must g_free this string when finished using it. */ char *xmlnode_get_data(xmlnode *node);
--- a/pidgin.spec.in Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin.spec.in Mon Oct 01 17:51:20 2007 +0000 @@ -44,9 +44,15 @@ BuildRequires: gnutls-devel %{?_with_dbus:BuildRequires: dbus-1-devel >= 0.35} %{!?_without_gstreamer:BuildRequires: gstreamer010-devel >= 0.10} +Requires(pre): gconf2 +Requires(post): gconf2 +Requires(preun): gconf2 %else %{?_with_dbus:BuildRequires: dbus-devel >= 0.35} %{!?_without_gstreamer:BuildRequires: gstreamer-devel >= 0.10} +Requires(pre): GConf2 +Requires(post): GConf2 +Requires(preun): GConf2 %endif # Mandrake 10.1 and lower || Mandrake 10.2 (and higher?) @@ -72,9 +78,7 @@ # For some reason perl isn't always automatically detected as a requirement :( Requires: perl -Requires(pre): GConf2 -Requires(post): GConf2 -Requires(preun): GConf2 +Requires: libpurple = %{version} Obsoletes: gaim Provides: gaim @@ -363,8 +367,6 @@ %{_bindir}/pidgin %{_datadir}/pixmaps/pidgin %{_datadir}/icons/hicolor/*/apps/pidgin.* -%dir %{_datadir}/sounds/pidgin -%{_datadir}/sounds/pidgin/* %{_datadir}/applications/* %{_sysconfdir}/gconf/schemas/purple.schemas @@ -374,6 +376,8 @@ %{_libdir}/libpurple.so.* %dir %{_libdir}/purple-2 +%{_datadir}/purple +%{_datadir}/sounds/purple %attr(755, root, root) %{perl_vendorarch}/Purple.pm %attr(755, root, root) %{perl_vendorarch}/auto/Purple @@ -427,7 +431,7 @@ %endif %if 0%{?_with_mono:1} -%files libpurple-mono +%files -n libpurple-mono %defattr(-, root, root) %{_libdir}/purple-2/mono.so @@ -457,6 +461,13 @@ %endif %changelog +* Mon Sep 17 2007 Stu Tomlinson <stu@nosnilmot.com> +- Add version dependency on libpurple for pidgin +- Support for OpenSuse lowercase package name for GConf2 + +* Fri Sep 14 2007 Stu Tomlinson <stu@nosnilmot.com> +- Fix spec file for moved sounds & new CA certificates + * Thu Jul 12 2007 Stu Tomlinson <stu@nosnilmot.com> - Don't hardcode silc header locations, rely on pkg-config for those, because I think I broke non-pkg-config detection of older silc
--- a/pidgin/gtkblist.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkblist.c Mon Oct 01 17:51:20 2007 +0000 @@ -521,7 +521,7 @@ if (i > 1) { - char *msg = g_strdup_printf(ngettext("You currently have %d contact named %s. Would you like to merge them?", "You currently have %d contacts named %s. Would you like to merge them?", i), i, alias); + char *msg = g_strdup_printf(ngettext("You have %d contact named %s. Would you like to merge them?", "You currently have %d contacts named %s. Would you like to merge them?", i), i, alias); purple_request_action(NULL, NULL, msg, _("Merging these contacts will cause them to share a single entry on the buddy list and use a single conversation window. " "You can separate them again by choosing 'Expand' from the contact's context menu"), 0, NULL, NULL, NULL, merges, 2, _("_Merge"), PURPLE_CALLBACK(gtk_blist_do_personize), _("_Cancel"), PURPLE_CALLBACK(g_list_free)); @@ -662,6 +662,26 @@ } } +static void gtk_blist_menu_showoffline_cb(GtkWidget *w, PurpleBlistNode *node) +{ + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) + { + purple_blist_node_set_bool(node, "show_offline", + !purple_blist_node_get_bool(node, "show_offline")); + } + else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) + { + PurpleBlistNode *bnode; + gboolean setting = !purple_blist_node_get_bool(node, "show_offline"); + + purple_blist_node_set_bool(node, "show_offline", setting); + for (bnode = node->child; bnode != NULL; bnode = bnode->next) { + purple_blist_node_set_bool(bnode, "show_offline", setting); + } + } + pidgin_blist_update(purple_get_blist(), node); +} + static void gtk_blist_show_systemlog_cb() { pidgin_syslog_show(); @@ -1288,13 +1308,17 @@ pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub) { PurplePluginProtocolInfo *prpl_info; PurpleContact *contact; + PurpleBlistNode *node; gboolean contact_expanded = FALSE; + gboolean show_offline = FALSE; g_return_if_fail(menu); g_return_if_fail(buddy); prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); + node = (PurpleBlistNode*)buddy; + contact = purple_buddy_get_contact(buddy); if (contact) { contact_expanded = ((struct _pidgin_blist_node *)(((PurpleBlistNode*)contact)->ui_data))->contact_expanded; @@ -1310,17 +1334,17 @@ if (!prpl_info->can_receive_file || prpl_info->can_receive_file(buddy->account->gc, buddy->name)) { - pidgin_new_item_from_stock(menu, _("_Send File"), + pidgin_new_item_from_stock(menu, _("_Send File..."), PIDGIN_STOCK_TOOLBAR_SEND_FILE, G_CALLBACK(gtk_blist_menu_send_file_cb), buddy, 0, 0, NULL); } } - pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL, + pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce..."), NULL, G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL); - if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && + if (node->parent && node->parent->child->next && !sub && !contact_expanded) { pidgin_new_item_from_stock(menu, _("View _Log"), NULL, G_CALLBACK(gtk_blist_menu_showlog_cb), @@ -1330,18 +1354,22 @@ G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL); } - - pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, - (PurpleBlistNode *)buddy); - pidgin_append_blist_node_extended_menu(menu, (PurpleBlistNode *)buddy); + if (!(purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE)) { + show_offline = purple_blist_node_get_bool(node, "show_offline"); + pidgin_new_item_from_stock(menu, show_offline ? _("Hide when offline") : _("Show when offline"), + NULL, G_CALLBACK(gtk_blist_menu_showoffline_cb), node, 0, 0, NULL); + } + + pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, node); + pidgin_append_blist_node_extended_menu(menu, node); if (!contact_expanded) pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact); - if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && + if (node->parent && node->parent->child->next && !sub && !contact_expanded) { pidgin_separator(menu); - pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); + pidgin_append_blist_node_privacy_menu(menu, node); pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, G_CALLBACK(gtk_blist_menu_alias_cb), contact, 0, 0, NULL); @@ -1350,7 +1378,7 @@ contact, 0, 0, NULL); } else if (!sub || contact_expanded) { pidgin_separator(menu); - pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); + pidgin_append_blist_node_privacy_menu(menu, node); pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL); pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, @@ -1403,10 +1431,10 @@ GtkWidget *item; menu = gtk_menu_new(); - item = pidgin_new_item_from_stock(menu, _("Add a _Buddy"), GTK_STOCK_ADD, + item = pidgin_new_item_from_stock(menu, _("Add _Buddy..."), GTK_STOCK_ADD, G_CALLBACK(pidgin_blist_add_buddy_cb), node, 0, 0, NULL); gtk_widget_set_sensitive(item, purple_connections_get_all() != NULL); - item = pidgin_new_item_from_stock(menu, _("Add a C_hat"), GTK_STOCK_ADD, + item = pidgin_new_item_from_stock(menu, _("Add C_hat..."), GTK_STOCK_ADD, G_CALLBACK(pidgin_blist_add_chat_cb), node, 0, 0, NULL); gtk_widget_set_sensitive(item, pidgin_blist_joinchat_is_showable()); pidgin_new_item_from_stock(menu, _("_Delete Group"), GTK_STOCK_REMOVE, @@ -3058,7 +3086,7 @@ /* Accounts menu */ { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, - { N_("/Accounts/Add\\/Edit"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, + { N_("/Accounts/Manage"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, /* Tools */ { N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL }, @@ -4588,7 +4616,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->Add/Edit</b>. Once you " + "<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."), PIDGIN_NAME); pretty = pidgin_make_pretty_arrows(tmp); @@ -5788,7 +5816,7 @@ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); /* Set up stuff for the account box */ - label = gtk_label_new_with_mnemonic(_("_Account:")); + label = gtk_label_new_with_mnemonic(_("A_ccount:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); @@ -6858,7 +6886,7 @@ 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/Add\\/Edit"))) + if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage"))) gtk_widget_destroy(menuitem); }
--- a/pidgin/gtkconn.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkconn.c Mon Oct 01 17:51:20 2007 +0000 @@ -141,6 +141,7 @@ { PurpleAccount *account = NULL; PidginAutoRecon *info; + GList *list; account = purple_connection_get_account(gc); info = g_hash_table_lookup(auto_reconns, account); @@ -192,6 +193,17 @@ */ purple_account_set_enabled(account, PIDGIN_UI, FALSE); } + + /* If we have any open chats, we probably want to rejoin when we get back online. */ + list = purple_get_chats(); + while (list) { + PurpleConversation *conv = list->data; + list = list->next; + if (conv->account != account || + purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv))) + continue; + purple_conversation_set_data(conv, "want-to-rejoin", GINT_TO_POINTER(TRUE)); + } } static void pidgin_connection_network_connected ()
--- a/pidgin/gtkconv.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkconv.c Mon Oct 01 17:51:20 2007 +0000 @@ -376,10 +376,13 @@ static void clear_conversation_scrollback(PurpleConversation *conv) { PidginConversation *gtkconv = NULL; + GList *iter; gtkconv = PIDGIN_CONVERSATION(conv); gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); + for (iter = gtkconv->convs; iter; iter = iter->next) + purple_conversation_clear_message_history(iter->data); } static PurpleCmdRet @@ -387,7 +390,6 @@ const char *cmd, char **args, char **error, void *data) { clear_conversation_scrollback(conv); - purple_conversation_clear_message_history(conv); return PURPLE_CMD_STATUS_OK; } @@ -1099,12 +1101,9 @@ { PidginWindow *win = data; PurpleConversation *conv; - PidginConversation *gtkconv; conv = pidgin_conv_window_get_active_conversation(win); - gtkconv = PIDGIN_CONVERSATION(conv); - - gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); + clear_conversation_scrollback(conv); } struct _search { @@ -3635,7 +3634,7 @@ gtk_widget_destroy(win->menu.send_to); /* Build the Send To menu */ - win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("_Send To")); + win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To")); gtk_widget_show(win->menu.send_to); menu = gtk_menu_new(); @@ -6836,9 +6835,7 @@ event = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event); -#if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE); -#endif gtk_widget_add_events(event, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(event), "button-press-event", @@ -7244,6 +7241,23 @@ /* if (purple_conversation_get_account(conv) == account) */ pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON | PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE); + + if (PURPLE_CONNECTION_IS_CONNECTED(gc) && + conv->type == PURPLE_CONV_TYPE_CHAT && + conv->account == gc->account && + purple_conversation_get_data(conv, "want-to-rejoin")) { + GHashTable *comps = NULL; + PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name); + if (chat == NULL) { + if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) + comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name); + } else { + comps = chat->components; + } + serv_join_chat(gc, comps); + if (chat == NULL && comps != NULL) + g_hash_table_destroy(comps); + } } } @@ -7388,6 +7402,7 @@ if (gtkconv->attach.current) return TRUE; + g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); purple_signal_emit(pidgin_conversations_get_handle(), "conversation-displayed", gtkconv); g_source_remove(gtkconv->attach.timer); @@ -7428,7 +7443,6 @@ timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer")); if (timer) purple_timeout_remove(timer); - return TRUE; } @@ -8086,7 +8100,7 @@ sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to)); if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) { - GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("_Send To")); + GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To")); if (populated) pidgin_separator(menu); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); @@ -8926,9 +8940,7 @@ /* Close button. */ gtkconv->close = gtk_event_box_new(); -#if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(gtkconv->close), FALSE); -#endif gtk_widget_set_events(gtkconv->close, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); close_image = gtk_label_new("×"); g_signal_connect(G_OBJECT(gtkconv->close), "enter-notify-event", G_CALLBACK(close_button_entered_cb), close_image);
--- a/pidgin/gtkimhtml.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkimhtml.c Mon Oct 01 17:51:20 2007 +0000 @@ -3211,24 +3211,25 @@ im_image = data; /* Update the pointer to this GdkPixbuf frame of the animation */ - g_object_unref(G_OBJECT(im_image->pixbuf)); - gdk_pixbuf_animation_iter_advance(GTK_IMHTML_ANIMATION(im_image)->iter, NULL); - im_image->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter); - g_object_ref(G_OBJECT(im_image->pixbuf)); - - /* Update the displayed GtkImage */ - width = gdk_pixbuf_get_width(gtk_image_get_pixbuf(im_image->image)); - height = gdk_pixbuf_get_height(gtk_image_get_pixbuf(im_image->image)); - if (width > 0 && height > 0) - { - /* Need to scale the new frame to the same size as the old frame */ - GdkPixbuf *tmp; - tmp = gdk_pixbuf_scale_simple(im_image->pixbuf, width, height, GDK_INTERP_BILINEAR); - gtk_image_set_from_pixbuf(im_image->image, tmp); - g_object_unref(G_OBJECT(tmp)); - } else { - /* Display at full-size */ - gtk_image_set_from_pixbuf(im_image->image, im_image->pixbuf); + if (gdk_pixbuf_animation_iter_advance(GTK_IMHTML_ANIMATION(im_image)->iter, NULL)) { + GdkPixbuf *pb = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter); + g_object_unref(G_OBJECT(im_image->pixbuf)); + im_image->pixbuf = gdk_pixbuf_copy(pb); + + /* Update the displayed GtkImage */ + width = gdk_pixbuf_get_width(gtk_image_get_pixbuf(im_image->image)); + height = gdk_pixbuf_get_height(gtk_image_get_pixbuf(im_image->image)); + if (width > 0 && height > 0) + { + /* Need to scale the new frame to the same size as the old frame */ + GdkPixbuf *tmp; + tmp = gdk_pixbuf_scale_simple(im_image->pixbuf, width, height, GDK_INTERP_BILINEAR); + gtk_image_set_from_pixbuf(im_image->image, tmp); + g_object_unref(G_OBJECT(tmp)); + } else { + /* Display at full-size */ + gtk_image_set_from_pixbuf(im_image->image, im_image->pixbuf); + } } delay = MIN(gdk_pixbuf_animation_iter_get_delay_time(GTK_IMHTML_ANIMATION(im_image)->iter), 100); @@ -3249,11 +3250,14 @@ if (gdk_pixbuf_animation_is_static_image(anim)) { GTK_IMHTML_ANIMATION(im_image)->iter = NULL; im_image->pixbuf = gdk_pixbuf_animation_get_static_image(anim); + g_object_ref(im_image->pixbuf); GTK_IMHTML_ANIMATION(im_image)->timer = 0; } else { int delay; + GdkPixbuf *pb; GTK_IMHTML_ANIMATION(im_image)->iter = gdk_pixbuf_animation_get_iter(anim, NULL); - im_image->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter); + pb = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter); + im_image->pixbuf = gdk_pixbuf_copy(pb); delay = MIN(gdk_pixbuf_animation_iter_get_delay_time(GTK_IMHTML_ANIMATION(im_image)->iter), 100); GTK_IMHTML_ANIMATION(im_image)->timer = g_timeout_add(delay, animate_image_cb, im_image); } @@ -3266,7 +3270,6 @@ im_image->filesel = NULL; g_object_ref(anim); - g_object_ref(im_image->pixbuf); return GTK_IMHTML_SCALABLE(im_image); } @@ -4606,10 +4609,15 @@ if (imhtml->num_animations == 20) { GtkImage *image = GTK_IMAGE(g_queue_pop_head(imhtml->animations)); GdkPixbufAnimation *anim = gtk_image_get_animation(image); + g_signal_handlers_disconnect_matched(G_OBJECT(image), G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, G_CALLBACK(animated_smiley_destroy_cb), NULL); if (anim) { GdkPixbuf *pb = gdk_pixbuf_animation_get_static_image(anim); - gtk_image_set_from_pixbuf(image, pb); - g_object_unref(G_OBJECT(pb)); + if (pb != NULL) { + GdkPixbuf *copy = gdk_pixbuf_copy(pb); + gtk_image_set_from_pixbuf(image, copy); + g_object_unref(G_OBJECT(copy)); + } } } else { imhtml->num_animations++;
--- a/pidgin/gtkimhtmltoolbar.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Mon Oct 01 17:51:20 2007 +0000 @@ -1302,7 +1302,7 @@ gtk_container_add(GTK_CONTAINER(smiley_button), bbox); image = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)); gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0); - label = gtk_label_new_with_mnemonic(_("_Smiley")); + label = gtk_label_new_with_mnemonic(_("_Smile!")); gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), smiley_button, FALSE, FALSE, 0); g_signal_connect_swapped(G_OBJECT(smiley_button), "clicked", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
--- a/pidgin/gtkmain.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkmain.c Mon Oct 01 17:51:20 2007 +0000 @@ -513,7 +513,7 @@ #ifndef DEBUG /* We translate this here in case the crash breaks gettext. */ segfault_message_tmp = g_strdup_printf(_( - "%s has segfaulted and attempted to dump a core file.\n" + "%s %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 developers\n" @@ -527,7 +527,7 @@ "LSchiere (via AIM). Contact information for Sean and Luke \n" "on other protocols is at\n" "%swiki/DeveloperPages\n"), - PIDGIN_NAME, PURPLE_DEVEL_WEBSITE, PURPLE_DEVEL_WEBSITE, PURPLE_DEVEL_WEBSITE + PIDGIN_NAME, VERSION, PURPLE_DEVEL_WEBSITE, PURPLE_DEVEL_WEBSITE, PURPLE_DEVEL_WEBSITE ); /* we have to convert the message (UTF-8 to console
--- a/pidgin/gtknotify.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtknotify.c Mon Oct 01 17:51:20 2007 +0000 @@ -430,12 +430,7 @@ PIDGIN_MAIL_DATA, &data, -1); if (data->account == account) { if (clear) { -#if GTK_CHECK_VERSION(2,2,0) advanced = gtk_tree_store_remove(treemodel, &iter); -#else - gtk_tree_store_remove(treemodel, &iter); - advanced = (iter.stamp == 0) ? FALSE : TRUE; -#endif purple_notify_close(PURPLE_NOTIFY_EMAILS, data); /* We're completely done if we've processed all entries */ if (!advanced) @@ -566,8 +561,8 @@ if (!GTK_WIDGET_VISIBLE(dialog)) { GdkPixbuf *pixbuf = gtk_widget_render_icon(dialog, PIDGIN_STOCK_DIALOG_MAIL, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), NULL); - char *label_text = g_strdup_printf(ngettext("<b>You have %d new e-mail.</b>", - "<b>You have %d new e-mails.</b>", + char *label_text = g_strdup_printf(ngettext("<b>%d new e-mail.</b>", + "<b>%d new e-mails.</b>", mail_dialog->total_count), mail_dialog->total_count); mail_dialog->in_use = TRUE; /* So that _set_headline doesn't accidentally remove the notifications when replacing an
--- a/pidgin/gtkprefs.c Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/gtkprefs.c Mon Oct 01 17:51:20 2007 +0000 @@ -1096,7 +1096,7 @@ const char *proxy = value; if (strcmp(proxy, "none") && strcmp(proxy, "envvar")) - gtk_widget_show_all(frame); + gtk_widget_show_all(frame); else gtk_widget_hide(frame); }
--- a/pidgin/pidgin.h Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pidgin.h Mon Oct 01 17:51:20 2007 +0000 @@ -27,12 +27,12 @@ #ifndef _PIDGIN_H_ #define _PIDGIN_H_ +#include <gtk/gtk.h> + #ifdef GDK_WINDOWING_X11 # include <gdk/gdkx.h> #endif -#include <gtk/gtk.h> - #ifdef _WIN32 # include "gtkwin32dep.h" #endif
--- a/pidgin/pixmaps/dialogs/64/scalable/cool.svg Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/cool.svg Mon Oct 01 17:51:20 2007 +0000 @@ -7,101 +7,25 @@ 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="64" - height="64" + width="48" + height="48" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.45" version="1.0" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/dialogs" + sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs" sodipodi:docname="dialog-cool.svg" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/dialogs/dialog-cool.png" + inkscape:export-filename="/home/hbons/Desktop/newstyle.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient2351"> - <stop - style="stop-color:#eeeeec;stop-opacity:1;" - offset="0" - id="stop2353" /> - <stop - style="stop-color:#eeeeec;stop-opacity:0;" - offset="1" - id="stop2355" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2351" - id="linearGradient2357" - x1="12.488563" - y1="5.8544211" - x2="12.488563" - y2="19.066195" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(60.97357,13.05831)" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2343"> - <stop - style="stop-color:#babdb6;stop-opacity:1;" - offset="0" - id="stop2345" /> - <stop - style="stop-color:#babdb6;stop-opacity:0;" - offset="1" - id="stop2347" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2343" - id="linearGradient2349" - x1="12.515625" - y1="8.7261219" - x2="12.515625" - y2="0.68458056" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.99284,0,0,1,61.04756,13.09375)" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3121"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1;" - offset="0" - id="stop3123" /> - <stop - style="stop-color:#d3d7cf;stop-opacity:0;" - offset="1" - id="stop3125" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" id="linearGradient3104"> <stop style="stop-color:#eeeeec;stop-opacity:1;" @@ -123,15 +47,380 @@ r="9.975256" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <filter + inkscape:collect="always" + x="-0.27879593" + width="1.5575919" + y="-0.78248727" + height="2.5649745" + id="filter3405"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.5438116" + id="feGaussianBlur3407" /> + </filter> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient2247" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3263"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop3265" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop3267" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2216" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3263" + id="linearGradient3269" + x1="12.845698" + y1="16.037401" + x2="10.698112" + y2="15.449714" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient3191" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3175" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <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,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + id="radialGradient2214" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3313" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="2.5781252" + fy="11.083743" + fx="17.911736" + cy="11.083743" + cx="17.911736" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" + gradientUnits="userSpaceOnUse" + id="radialGradient2259" + xlink:href="#linearGradient2382" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2867"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2869" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2871" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2847"> + <stop + style="stop-color:#888a85;stop-opacity:1;" + offset="0" + id="stop2849" /> + <stop + style="stop-color:#888a85;stop-opacity:0;" + offset="1" + id="stop2851" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2382"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2384" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2386" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2230" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2847" + id="linearGradient2853" + x1="12.5" + y1="18.202251" + x2="12.746171" + y2="20.761486" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2867" + id="linearGradient2873" + x1="12.720216" + y1="20.952612" + x2="12.720216" + y2="17.682426" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2303" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2233" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2264" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3771" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3822" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3816" + inkscape:collect="always"> + <stop + id="stop3818" + offset="0" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + id="stop3820" + offset="1" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3121" + inkscape:collect="always"> + <stop + id="stop3123" + offset="0" + style="stop-color:#d3d7cf;stop-opacity:1;" /> + <stop + id="stop3125" + offset="1" + style="stop-color:#d3d7cf;stop-opacity:0;" /> + </linearGradient> + <linearGradient + gradientTransform="matrix(0.99284,0,0,1,61.04756,13.09375)" + gradientUnits="userSpaceOnUse" + y2="0.68458056" + x2="12.515625" + y1="8.7261219" + x1="12.515625" + id="linearGradient2349" + xlink:href="#linearGradient2343" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2343" + inkscape:collect="always"> + <stop + id="stop2345" + offset="0" + style="stop-color:#babdb6;stop-opacity:1;" /> + <stop + id="stop2347" + offset="1" + style="stop-color:#babdb6;stop-opacity:0;" /> + </linearGradient> + <linearGradient + gradientTransform="translate(60.97357,13.05831)" + gradientUnits="userSpaceOnUse" + y2="19.066195" + x2="12.488563" + y1="5.8544211" + x1="12.488563" + id="linearGradient2357" + xlink:href="#linearGradient2351" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2351" + inkscape:collect="always"> + <stop + id="stop2353" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop2355" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3794" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient3121" - id="linearGradient1551" + id="linearGradient3802" gradientUnits="userSpaceOnUse" x1="42.925175" y1="40.136646" x2="42.925175" y2="15.474488" /> + <filter + inkscape:collect="always" + x="-0.47282609" + width="1.9456522" + y="-0.47282609" + height="1.9456522" + id="filter4019"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.552286" + id="feGaussianBlur4021" /> + </filter> </defs> <sodipodi:namedview id="base" @@ -140,17 +429,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="12.003863" - inkscape:cx="43.074856" - inkscape:cy="35.626159" + inkscape:zoom="15.839192" + inkscape:cx="40.272536" + inkscape:cy="20.18158" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - fill="#555753" - inkscape:window-width="1267" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + fill="#fce94f" + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="3" + inkscape:window-y="25" + width="48px" + height="48px" /> <metadata id="metadata7"> <rdf:RDF> @@ -167,25 +458,25 @@ inkscape:groupmode="layer" id="layer1"> <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" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" sodipodi:type="arc" - transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" /> + style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)" + 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(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1307" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" /> + transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" /> <path sodipodi:type="arc" style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -195,98 +486,215 @@ sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" /> + transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" /> <path sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2184" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" /> + transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" /> + <path + style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z " + id="path3154" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2172" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494387,0,0,1.2877392,1.0769258,12.069869)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3152" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3148" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494393,0,0,1.2877392,10.076919,12.069869)" /> + <path + style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 36,31 C 35.958854,34.901861 33.103799,38.559709 28.776926,39.671439 C 24.450054,40.78317 20.070187,38.984235 18,35.624852 C 24.906148,40.499205 32.307884,37.963138 36,31 z " + id="path2186" + sodipodi:nodetypes="cscc" /> + <path + sodipodi:type="arc" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2259" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.1597185,-7.1449202)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> <path - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 32,46 C 30.709742,51.13847 26.288403,55 21.000001,55 C 15.7116,55 11.290259,51.13847 10,46 C 12.318243,49.327326 16.389775,52.419284 21.000001,52.419284 C 25.610224,52.419285 29.681757,49.327326 32,46 z " - id="path2186" + sodipodi:type="arc" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2261" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> + <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" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path4318" + style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" + sodipodi:type="arc" + transform="matrix(2.383972,0,0,1.117487,-126.51617,-6.51091)" /> + <path + sodipodi:type="arc" + style="fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3777" + sodipodi:cx="11.806158" + sodipodi:cy="10.983024" + sodipodi:rx="9.975256" + sodipodi:ry="9.975256" + d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" + transform="matrix(1.854646,0,0,1.855034,-73.894233,-16.92925)" /> + <path + sodipodi:type="arc" + style="opacity:0.79545456;fill:url(#radialGradient3794);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3779" + sodipodi:cx="11.806158" + sodipodi:cy="10.983024" + sodipodi:rx="9.975256" + sodipodi:ry="9.975256" + d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" + transform="matrix(1.704217,0,0,1.704217,-72.114719,-15.27377)" /> + <path + sodipodi:type="arc" + style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3781" + sodipodi:cx="11.806158" + sodipodi:cy="10.983024" + sodipodi:rx="9.975256" + sodipodi:ry="9.975256" + d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" + transform="matrix(1.75441,0,0,1.753957,-72.710295,-15.8184)" /> + <path + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M -40.994465,6.44368 C -42.284723,11.58215 -46.706062,15.44368 -51.994464,15.44368 C -57.282865,15.44368 -61.704206,11.58215 -62.994465,6.44368 C -60.676222,9.771006 -56.60469,12.862964 -51.994464,12.862964 C -47.384241,12.862965 -43.312708,9.771006 -40.994465,6.44368 z " + id="path3783" sodipodi:nodetypes="cscsc" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2191" sodipodi:cx="9.0598059" sodipodi:cy="8.7845774" sodipodi:rx="1.1679889" sodipodi:ry="1.4520943" d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" /> + transform="matrix(1.712345,0,0,2.754643,-71.507978,-24.75469)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2193" sodipodi:cx="9.0598059" sodipodi:cy="8.7845774" sodipodi:rx="1.1679889" sodipodi:ry="1.4520943" d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" /> + transform="matrix(1.712345,0,0,2.754643,-63.507982,-24.75469)" /> <path - style="opacity:0.78977272;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.66300178;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 6,37 C 6,41.951923 9.359998,46 13.499999,46 C 17.413598,46 20.659892,42.352213 21,37.773438 C 21.340107,42.352213 24.586402,46 28.499999,46 C 32.640004,46 36,41.951923 36,37 L 21,37 L 6,37 z " - id="path2264" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;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;stroke-dasharray:none" - d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z " + style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;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" + d="M -28.915806,-30.045106 C -38.151045,-29.672823 -45.494406,-23.578958 -45.494406,-16.150506 C -45.494406,-11.885137 -43.740879,-7.375575 -39.928265,-4.826694 C -39.119658,-1.264309 -41.449395,1.502456 -41.852958,1.937782 C -41.122621,1.734237 -35.350978,0.114212 -33.186244,-2.295759 C -31.004272,-2.388266 -29.763575,-2.255902 -27.997203,-2.255902 C -18.344516,-2.255902 -10.499998,-8.482425 -10.5,-16.150506 C -10.5,-23.818587 -18.344516,-30.045106 -27.997203,-30.045106 C -28.298849,-30.045106 -28.617895,-30.057116 -28.915806,-30.045106 z " id="path13316" sodipodi:nodetypes="cscccsssc" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.0020103" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " + inkscape:original="M -28.90625 -30.03125 C -38.141489 -29.658966 -45.5 -23.584702 -45.5 -16.15625 C -45.499998 -11.890882 -43.750114 -7.361381 -39.9375 -4.8125 C -39.128893 -1.250115 -41.440187 1.502174 -41.84375 1.9375 C -41.113412 1.733955 -35.352234 0.128721 -33.1875 -2.28125 C -31.005527 -2.373757 -29.766372 -2.25 -28 -2.25 C -18.347312 -2.2499999 -10.499998 -8.488169 -10.5 -16.15625 C -10.5 -23.824332 -18.347313 -30.03125 -28 -30.03125 C -28.301645 -30.031249 -28.608339 -30.04326 -28.90625 -30.03125 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 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " /> + d="M 44.125,10.5 C 35.308909,10.855387 28.5,16.639515 28.5,23.40625 C 28.5,27.397567 30.147439,31.550115 33.625,33.875 C 33.835747,34.023343 33.981239,34.247178 34.03125,34.5 C 34.490803,36.524599 34.051533,38.324325 33.46875,39.65625 C 33.930328,39.493414 34.045022,39.492531 34.5625,39.28125 C 36.305088,38.56977 38.200088,37.553862 39.0625,36.59375 C 39.244281,36.384758 39.504456,36.260327 39.78125,36.25 C 42.026592,36.154804 43.292249,36.3125 45,36.3125 C 54.22098,36.312499 61.500002,30.39071 61.5,23.40625 C 61.5,16.421791 54.220979,10.5 45,10.5 C 44.671757,10.5 44.368389,10.490188 44.125,10.5 z " + transform="translate(-72.994465,-39.55632)" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.0109046" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " + inkscape:original="M -28.90625 -30.03125 C -38.141489 -29.658966 -45.5 -23.584702 -45.5 -16.15625 C -45.499998 -11.890882 -43.750114 -7.361381 -39.9375 -4.8125 C -39.128893 -1.250115 -41.440187 1.502174 -41.84375 1.9375 C -41.113412 1.733955 -35.352234 0.128721 -33.1875 -2.28125 C -31.005527 -2.373757 -29.766372 -2.25 -28 -2.25 C -18.347312 -2.2499999 -10.499998 -8.488169 -10.5 -16.15625 C -10.5 -23.824332 -18.347313 -30.03125 -28 -30.03125 C -28.301645 -30.031249 -28.608339 -30.04326 -28.90625 -30.03125 z " xlink:href="#path13316" - style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;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;stroke-dasharray:none" + style="color:#000000;fill:url(#linearGradient3802);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;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="path1336" inkscape:href="#path13316" - d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " /> + d="M 44.125,10.5 C 35.31263,10.855237 28.5,16.645389 28.5,23.40625 C 28.5,27.395135 30.150413,31.552103 33.625,33.875 C 33.846858,34.018204 34.003884,34.242526 34.0625,34.5 C 34.519684,36.514161 34.077673,38.294264 33.5,39.625 C 33.948389,39.466107 34.062909,39.485228 34.5625,39.28125 C 36.304559,38.569986 38.202041,37.520438 39.0625,36.5625 C 39.25032,36.365929 39.509394,36.253288 39.78125,36.25 C 42.027154,36.154781 43.29277,36.3125 45,36.3125 C 54.217148,36.312499 61.500002,30.384642 61.5,23.40625 C 61.5,16.427859 54.217147,10.5 45,10.5 C 44.671521,10.5 44.367905,10.490207 44.125,10.5 z " + transform="translate(-72.994465,-39.55632)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1397" sodipodi:cx="9.0598059" sodipodi:cy="8.7845774" sodipodi:rx="1.1679889" sodipodi:ry="1.4520943" d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(0.856174,0,0,0.688661,33.24323,22.95041)" /> + transform="matrix(0.856174,0,0,0.688661,-39.751235,-16.60591)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1403" sodipodi:cx="9.0598059" sodipodi:cy="8.7845774" sodipodi:rx="1.1679889" sodipodi:ry="1.4520943" d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(0.856172,0,0,0.688662,37.24325,22.9504)" /> + transform="matrix(0.856172,0,0,0.688662,-35.751215,-16.60592)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1405" sodipodi:cx="9.0598059" sodipodi:cy="8.7845774" sodipodi:rx="1.1679889" sodipodi:ry="1.4520943" d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(0.856173,0,0,0.688662,41.24324,22.95039)" /> + transform="matrix(0.856173,0,0,0.688662,-31.751225,-16.60593)" /> + <path + style="opacity:0.78977272;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.66300178;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 6.9375 23 C 6.6605 23 6.4375 23.223 6.4375 23.5 C 6.4375 23.777 6.6605 24 6.9375 24 L 11.0625 24 C 11.531404 27.382552 14.351819 30 17.75 30 C 21.272241 30 24.193903 27.155019 24.5 23.59375 C 24.806096 27.15502 27.727762 30 31.25 30 C 34.648185 30 37.468596 27.382552 37.9375 24 L 42.0625 24 C 42.3395 24 42.5625 23.777 42.5625 23.5 C 42.5625 23.223 42.3395 23 42.0625 23 L 38 23 L 24.5 23 L 11.5 23 L 11 23 L 6.9375 23 z " + id="path2264" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4019)" + id="path3813" + sodipodi:cx="13.826463" + sodipodi:cy="24.19828" + sodipodi:rx="3.2829957" + sodipodi:ry="3.2829957" + d="M 17.109458 24.19828 A 3.2829957 3.2829957 0 1 1 10.543467,24.19828 A 3.2829957 3.2829957 0 1 1 17.109458 24.19828 z" + transform="matrix(0.9137996,0,0,0.9137994,-1.6346163,0.8876255)" /> </g> </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/error.svg Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/error.svg Mon Oct 01 17:51:20 2007 +0000 @@ -7,101 +7,25 @@ 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="64" - height="64" + width="48" + height="48" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.45" version="1.0" - sodipodi:docbase="/home/hbons/Desktop" - sodipodi:docname="dialog-error.svg" - inkscape:export-filename="/home/hbons/Desktop/dialog-warning.png" + sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs" + sodipodi:docname="dialog--error.svg" + inkscape:export-filename="/home/hbons/Desktop/newstyle.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient2239"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop2241" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop2243" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2239" - id="linearGradient2245" - x1="15.535398" - y1="1.8014067" - x2="15.535398" - y2="48.674999" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.667328,0,0,0.667328,34.82201,12.82201)" /> - <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="11.226587" - y1="-5.4832759" - x2="11.226587" - y2="17.697369" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.946132,0,0,0.946123,34.14115,12.15018)" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3121"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1;" - offset="0" - id="stop3123" /> - <stop - style="stop-color:#d3d7cf;stop-opacity:0;" - offset="1" - id="stop3125" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" id="linearGradient3104"> <stop style="stop-color:#eeeeec;stop-opacity:1;" @@ -123,15 +47,462 @@ r="9.975256" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <filter + inkscape:collect="always" + x="-0.27879593" + width="1.5575919" + y="-0.78248727" + height="2.5649745" + id="filter3405"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.5438116" + id="feGaussianBlur3407" /> + </filter> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient2247" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3263"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop3265" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop3267" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2216" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3263" + id="linearGradient3269" + x1="12.845698" + y1="16.037401" + x2="10.698112" + y2="15.449714" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient3191" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3175" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <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,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + id="radialGradient2214" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3313" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="2.5781252" + fy="11.083743" + fx="17.911736" + cy="11.083743" + cx="17.911736" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" + gradientUnits="userSpaceOnUse" + id="radialGradient2259" + xlink:href="#linearGradient2382" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2867"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2869" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2871" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2847"> + <stop + style="stop-color:#888a85;stop-opacity:1;" + offset="0" + id="stop2849" /> + <stop + style="stop-color:#888a85;stop-opacity:0;" + offset="1" + id="stop2851" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2382"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2384" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2386" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2230" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2847" + id="linearGradient2853" + x1="12.5" + y1="18.202251" + x2="12.746171" + y2="20.761486" + gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient3121" - id="linearGradient1551" + xlink:href="#linearGradient2867" + id="linearGradient2873" + x1="12.720216" + y1="20.952612" + x2="12.720216" + y2="17.682426" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2303" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2233" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2264" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + id="radialGradient3456" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3454" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + id="radialGradient3452" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3450" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="17.682426" + x2="12.720216" + y1="20.952612" + x1="12.720216" + id="linearGradient3448" + xlink:href="#linearGradient2867" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="20.761486" + x2="12.746171" + y1="18.202251" + x1="12.5" + id="linearGradient3446" + xlink:href="#linearGradient2847" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" gradientUnits="userSpaceOnUse" - x1="42.925175" - y1="40.136646" - x2="42.925175" - y2="15.474488" /> + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3444" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2382" + id="radialGradient3424" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" + cx="17.911736" + cy="11.083743" + fx="17.911736" + fy="11.083743" + r="2.5781252" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3422" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + id="radialGradient3420" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3418" + cx="8.7359829" + cy="18.005522" + fx="8.7359829" + fy="18.005522" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient3416" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3414" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3406" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + cx="8.7359829" + cy="18.005522" + fx="8.7359829" + fy="18.005522" + r="9.975256" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="15.449714" + x2="10.698112" + y1="16.037401" + x1="12.845698" + id="linearGradient3404" + xlink:href="#linearGradient3263" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3402" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3394" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + cx="8.7359829" + cy="18.005522" + fx="8.7359829" + fy="18.005522" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient3388" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3479" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> </defs> <sodipodi:namedview id="base" @@ -140,17 +511,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="29.556978" - inkscape:cx="52.766638" - inkscape:cy="42.047904" + inkscape:zoom="11.2" + inkscape:cx="49.816631" + inkscape:cy="24.376627" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - fill="#cc0000" - inkscape:window-width="1267" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + fill="#fce94f" + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="3" + inkscape:window-y="25" + width="48px" + height="48px" /> <metadata id="metadata7"> <rdf:RDF> @@ -167,25 +540,25 @@ inkscape:groupmode="layer" id="layer1"> <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" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" sodipodi:type="arc" - transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" /> + style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)" + 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(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1307" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" /> + transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" /> <path sodipodi:type="arc" style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -195,93 +568,55 @@ sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" /> + transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" /> <path sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2184" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;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;stroke-dasharray:none" - d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z " - id="path13316" - sodipodi:nodetypes="cscccsssc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.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 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0109046" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " - xlink:href="#path13316" - style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;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;stroke-dasharray:none" - id="path1336" - inkscape:href="#path13316" - d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " /> + transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2193" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" /> + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2259" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2191" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" /> + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2261" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> <path style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 32,55 C 30.709742,49.86153 26.288403,46 21.000001,46 C 15.7116,46 11.290259,49.86153 10,55 C 12.318243,51.672674 16.389775,48.580716 21.000001,48.580716 C 25.610224,48.580715 29.681757,51.672674 32,55 z " - id="path2186" - sodipodi:nodetypes="cscsc" /> - <path - sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;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="path1311" - sodipodi:cx="15.590227" - sodipodi:cy="16.57217" - sodipodi:rx="14.345175" - sodipodi:ry="14.345175" - 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.732268,0,0,0.732268,34.07926,11.36022)" /> + d="M 17,21 L 17,22 L 18,22 L 18,21 L 17,21 z M 18,22 L 18,23 L 19,23 L 19,22 L 18,22 z M 19,23 L 19,24 L 20,24 L 20,23 L 19,23 z M 20,23 L 21,23 L 21,22 L 20,22 L 20,23 z M 21,22 L 22,22 L 22,21 L 21,21 L 21,22 z M 20,24 L 20,25 L 21,25 L 21,24 L 20,24 z M 21,25 L 21,26 L 22,26 L 22,25 L 21,25 z M 19,24 L 18,24 L 18,25 L 19,25 L 19,24 z M 18,25 L 17,25 L 17,26 L 18,26 L 18,25 z " + id="rect3307" /> <path - sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.4342562px;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" - sodipodi:rx="14.345175" - sodipodi:ry="14.345175" - 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.697225,0,0,0.697224,34.63061,11.94498)" /> + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 27,21 L 27,22 L 28,22 L 28,21 L 27,21 z M 28,22 L 28,23 L 29,23 L 29,22 L 28,22 z M 29,23 L 29,24 L 30,24 L 30,23 L 29,23 z M 30,23 L 31,23 L 31,22 L 30,22 L 30,23 z M 31,22 L 32,22 L 32,21 L 31,21 L 31,22 z M 30,24 L 30,25 L 31,25 L 31,24 L 30,24 z M 31,25 L 31,26 L 32,26 L 32,25 L 31,25 z M 29,24 L 28,24 L 28,25 L 29,25 L 29,24 z M 28,25 L 27,25 L 27,26 L 28,26 L 28,25 z " + id="path3326" /> <path - style="opacity:0.6;color:#000000;fill:url(#linearGradient2194);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.00000024px;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 54.501284,23.499216 C 54.501284,28.468337 50.46837,32.501247 45.499243,32.501247 C 40.530116,32.501247 36.497202,28.468337 36.497202,23.499216 C 36.497202,18.530098 40.530116,14.497189 45.499243,14.497189 C 50.46837,14.497189 54.501284,18.530098 54.501284,23.499216 z " - id="path2220" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.99999881px;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 53.472399,23.373021 C 53.472399,25.828104 51.776345,25.485533 45.279112,25.485533 C 38.811218,25.485533 37.51405,25.897351 37.51405,23.485931 C 37.51405,21.235525 38.820793,21.494116 45.34652,21.494116 C 51.901652,21.494116 53.472399,20.942767 53.472399,23.373021 z " - id="path1341" - sodipodi:nodetypes="czczz" /> + style="fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 34,39 C 32.885686,35.003412 29.067255,32 24.5,32 C 19.932746,32 16.114315,35.003412 15,39 C 17.00212,36.412082 20.518441,33.850868 24.5,33.850868 C 28.481556,33.850866 31.99788,36.412082 34,39 z " + id="path3492" + sodipodi:nodetypes="cscsc" /> </g> </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/info.svg Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/info.svg Mon Oct 01 17:51:20 2007 +0000 @@ -7,147 +7,25 @@ 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="64" - height="64" + width="48" + height="48" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.45" version="1.0" sodipodi:docbase="/home/hbons/Desktop" - sodipodi:docname="dialog-info.svg" - inkscape:export-filename="/home/hbons/Desktop/dialog-info.png" + sodipodi:docname="dialog.svg" + inkscape:export-filename="/home/hbons/Desktop/newstyle.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient2226"> - <stop - style="stop-color:#729fcf;stop-opacity:1;" - offset="0" - id="stop2228" /> - <stop - style="stop-color:#729fcf;stop-opacity:0;" - offset="1" - id="stop2230" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2226" - id="radialGradient2232" - cx="6.8598728" - cy="12.836589" - fx="6.8598728" - fy="12.836589" - r="6" - gradientTransform="matrix(-1.535401,1.457479,-1.350253,-1.281728,72.86699,21.2066)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3150"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop3152" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop3154" /> - </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)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2351"> - <stop - style="stop-color:#eeeeec;stop-opacity:1;" - offset="0" - id="stop2353" /> - <stop - style="stop-color:#eeeeec;stop-opacity:0;" - offset="1" - id="stop2355" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2351" - id="linearGradient2357" - x1="12.488563" - y1="5.8544211" - x2="12.488563" - y2="19.066195" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1,0,0,1.005826,31.99641,10.9359)" /> - <linearGradient - inkscape:collect="always" - id="linearGradient2343"> - <stop - style="stop-color:#babdb6;stop-opacity:1;" - offset="0" - id="stop2345" /> - <stop - style="stop-color:#babdb6;stop-opacity:0;" - offset="1" - id="stop2347" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2343" - id="linearGradient2349" - x1="12.515625" - y1="8.7261219" - x2="12.515625" - y2="0.68458056" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.993429,0,0,1.004681,32.05868,11.024)" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3121"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1;" - offset="0" - id="stop3123" /> - <stop - style="stop-color:#d3d7cf;stop-opacity:0;" - offset="1" - id="stop3125" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" id="linearGradient3104"> <stop style="stop-color:#eeeeec;stop-opacity:1;" @@ -169,15 +47,259 @@ r="9.975256" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <filter + inkscape:collect="always" + x="-0.27879593" + width="1.5575919" + y="-0.78248727" + height="2.5649745" + id="filter3405"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.5438116" + id="feGaussianBlur3407" /> + </filter> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient2247" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3263"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop3265" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop3267" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2216" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3263" + id="linearGradient3269" + x1="12.845698" + y1="16.037401" + x2="10.698112" + y2="15.449714" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient3191" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient3121" - id="linearGradient1551" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3175" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <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,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + id="radialGradient2214" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3313" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="2.5781252" + fy="11.083743" + fx="17.911736" + cy="11.083743" + cx="17.911736" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" gradientUnits="userSpaceOnUse" - x1="42.925175" - y1="40.136646" - x2="42.925175" - y2="15.474488" /> + id="radialGradient2259" + xlink:href="#linearGradient2382" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2867"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2869" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2871" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2847"> + <stop + style="stop-color:#888a85;stop-opacity:1;" + offset="0" + id="stop2849" /> + <stop + style="stop-color:#888a85;stop-opacity:0;" + offset="1" + id="stop2851" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2382"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2384" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2386" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2230" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2847" + id="linearGradient2853" + x1="12.5" + y1="18.202251" + x2="12.746171" + y2="20.761486" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2867" + id="linearGradient2873" + x1="12.720216" + y1="20.952612" + x2="12.720216" + y2="17.682426" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2303" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2233" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2264" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> </defs> <sodipodi:namedview id="base" @@ -186,17 +308,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="6.0019314" - inkscape:cx="46.66506" - inkscape:cy="27.955978" + inkscape:zoom="11.2" + inkscape:cx="49.304407" + inkscape:cy="24.325832" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - fill="#2e3436" - inkscape:window-width="1267" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + fill="#fce94f" + inkscape:window-width="1440" + inkscape:window-height="845" + inkscape:window-x="3" + inkscape:window-y="25" + width="48px" + height="48px" /> <metadata id="metadata7"> <rdf:RDF> @@ -213,25 +337,25 @@ inkscape:groupmode="layer" id="layer1"> <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" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" sodipodi:type="arc" - transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" /> + style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)" + 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(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1307" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" /> + transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" /> <path sodipodi:type="arc" style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -241,161 +365,81 @@ sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" /> + transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" /> <path sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2184" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" /> + transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" /> + <path + style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z " + id="path3154" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2172" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494387,0,0,1.2877392,1.0769249,12.069869)" /> <path - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 32,46 C 30.709742,51.13847 26.288403,55 21.000001,55 C 15.7116,55 11.290259,51.13847 10,46 C 12.318243,49.327326 16.389775,52.419284 21.000001,52.419284 C 25.610224,52.419285 29.681757,49.327326 32,46 z " + sodipodi:type="arc" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3152" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3148" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494393,0,0,1.2877392,10.07692,12.069869)" /> + <path + style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 34,32 C 32.885686,35.996588 29.067255,39 24.5,39 C 19.932746,39 16.114315,35.996588 15,32 C 17.00212,34.587918 20.518441,37.149132 24.5,37.149132 C 28.481556,37.149134 31.99788,34.587918 34,32 z " id="path2186" sodipodi:nodetypes="cscsc" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2191" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,1.486487,14.80163)" /> + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2259" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2193" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;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;stroke-dasharray:none" - d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z " - id="path13316" - sodipodi:nodetypes="cscccsssc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.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 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0109046" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " - xlink:href="#path13316" - style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;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;stroke-dasharray:none" - id="path1336" - inkscape:href="#path13316" - d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " /> - <path - style="opacity:1;fill:url(#radialGradient2232);fill-opacity:1;stroke:#729fcf;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 44.703431,14.533668 C 40.70252,14.678436 37.503421,17.811488 37.503421,21.651365 C 37.503421,24.907582 40.201737,27.911617 43.341119,28.760108 L 43.389173,30.850471 C 43.389173,30.872875 43.386855,30.909548 43.389173,30.931354 C 43.394328,30.963552 43.421848,31.022249 43.431776,31.052677 C 43.443213,31.082437 43.458677,31.146493 43.474381,31.174002 C 43.480062,31.182896 43.510872,31.20584 43.516985,31.214444 C 43.569231,31.280841 43.655052,31.37351 43.730003,31.41665 C 43.749323,31.426587 43.794808,31.448926 43.815208,31.457092 C 43.857011,31.471566 43.940397,31.49101 43.985625,31.497533 C 44.008596,31.499735 44.047229,31.497533 44.07083,31.497533 L 46.028589,31.404055 C 46.052192,31.404055 46.090827,31.406257 46.113796,31.404055 C 46.159024,31.397531 46.242411,31.378087 46.284211,31.363613 C 46.304612,31.355448 46.350096,31.333109 46.369418,31.323172 C 46.444367,31.280031 46.53019,31.187363 46.582436,31.120966 C 46.588549,31.112362 46.619359,31.089417 46.62504,31.080523 C 46.640742,31.053014 46.656207,30.988959 46.667645,30.959199 C 46.677573,30.928771 46.705092,30.870073 46.710248,30.837876 C 46.712565,30.816069 46.710248,30.779396 46.710248,30.756993 L 46.758302,28.760108 C 49.897683,27.911617 52.499887,24.907584 52.499889,21.651365 C 52.499889,17.719331 49.13652,14.533668 45.001656,14.533668 C 44.904746,14.533668 44.799454,14.530194 44.703431,14.533668 z " - id="path1311" - sodipodi:nodetypes="csccsssssssccsssssssccssc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.98906523" - inkscape:original="M 44.71875 14.53125 C 40.71784 14.676018 37.5 17.816373 37.5 21.65625 C 37.499999 24.912467 40.204368 27.901509 43.34375 28.75 L 43.375 30.84375 C 43.375001 30.866154 43.372682 30.915694 43.375 30.9375 C 43.380156 30.969697 43.427572 31.032072 43.4375 31.0625 C 43.448939 31.09226 43.453046 31.159991 43.46875 31.1875 C 43.474432 31.196394 43.525137 31.210146 43.53125 31.21875 C 43.583494 31.285148 43.643799 31.36311 43.71875 31.40625 C 43.73807 31.416186 43.7921 31.460584 43.8125 31.46875 C 43.854303 31.483224 43.954772 31.493477 44 31.5 C 44.02297 31.502201 44.038899 31.5 44.0625 31.5 L 46.03125 31.40625 C 46.054855 31.40625 46.102031 31.408452 46.125 31.40625 C 46.170228 31.399726 46.23945 31.389474 46.28125 31.375 C 46.301652 31.366835 46.355678 31.322437 46.375 31.3125 C 46.449948 31.269359 46.541504 31.191397 46.59375 31.125 C 46.599863 31.116396 46.619319 31.102644 46.625 31.09375 C 46.640704 31.066241 46.644812 30.99851 46.65625 30.96875 C 46.666178 30.938321 46.713594 30.875947 46.71875 30.84375 C 46.721068 30.821944 46.71875 30.772403 46.71875 30.75 L 46.75 28.75 C 49.889382 27.901508 52.499998 24.912469 52.5 21.65625 C 52.5 17.724216 49.134864 14.53125 45 14.53125 C 44.90309 14.53125 44.814773 14.527776 44.71875 14.53125 z " - xlink:href="#path1311" - style="opacity:0.7;fill:#ffffff;fill-opacity:0.41960784;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2204" - inkscape:href="#path1311" - d="M 33.46875,7.46875 C 29.99276,7.595007 27.28125,10.282227 27.28125,13.5625 C 27.281251,16.268084 29.627654,18.959072 32.3125,19.6875 C 32.745246,19.795209 33.052411,20.179165 33.0625,20.625 L 33.125,22.34375 L 34.40625,22.28125 L 34.46875,20.625 C 34.478839,20.179165 34.786004,19.795209 35.21875,19.6875 C 37.89876,18.960384 40.156248,16.287128 40.15625,13.5625 C 40.15625,10.202426 37.315969,7.4687499 33.71875,7.46875 C 33.598771,7.4687498 33.517755,7.46697 33.46875,7.46875 z " - transform="translate(3.330669e-15,4.169556e-4)" /> - <rect - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#c4a000;stroke-width:1.00000107;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2188" - width="5.0002198" - height="3.994288" - x="42.497272" - y="29.502851" - rx="0.50000107" - ry="0.50000083" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0076578" - inkscape:original="M 43 29.5 C 42.722999 29.5 42.5 29.723 42.5 30 L 42.5 33 C 42.5 33.277 42.723 33.5 43 33.5 L 47 33.5 C 47.277001 33.5 47.499999 33.277 47.5 33 L 47.5 30 C 47.5 29.723 47.277002 29.5 47 29.5 L 43 29.5 z " - xlink:href="#rect2188" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000083;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1324" - inkscape:href="#rect2188" - d="M 32.21875,22.4375 L 32.21875,24.40625 L 35.1875,24.40625 L 35.1875,22.4375 L 32.21875,22.4375 z " /> - <rect - style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2238" - width="1" - height="2" - x="43" - y="24" /> - <rect - style="opacity:0.70454544;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2240" - width="1.0217247" - height="2" - x="45.978275" - y="24" /> - <rect - style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2242" - width="1" - height="2.0132751" - x="-25" - y="43.986725" - transform="matrix(0,-1,1,0,0,0)" /> - <rect - style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2244" - width="1.0000002" - height="1" - x="-24" - y="43" - transform="matrix(0,-1,1,0,0,0)" /> - <rect - style="opacity:0.7;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2246" - width="1.0000002" - height="1" - x="-24" - y="45" - transform="matrix(0,-1,1,0,0,0)" /> - <rect - style="opacity:0.5;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2250" - width="1.0000002" - height="1.0066376" - x="-23" - y="45.993362" - transform="matrix(0,-1,1,0,0,0)" /> - <rect - style="opacity:0.5;fill:#729fcf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2252" - width="1.0000002" - height="1.0066376" - x="-23" - y="43.993362" - transform="matrix(0,-1,1,0,0,0)" /> - <path - sodipodi:type="arc" - style="opacity:0.9;fill:#ffffff;fill-opacity:0.41960784;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2254" - sodipodi:cx="8.9137974" - sodipodi:cy="6.046802" - sodipodi:rx="1.3745575" - sodipodi:ry="1.3329042" - d="M 10.288355 6.046802 A 1.3745575 1.3329042 0 1 1 7.5392399,6.046802 A 1.3745575 1.3329042 0 1 1 10.288355 6.046802 z" - transform="matrix(1.455014,0,0,1.500481,30.0303,10.92689)" /> + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2261" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,41.208475,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> </g> </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/question.svg Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/question.svg Mon Oct 01 17:51:20 2007 +0000 @@ -7,57 +7,25 @@ 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="64" - height="64" + width="48" + height="48" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.45" version="1.0" - sodipodi:docbase="/home/hbons/Desktop" + sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs/scalable" sodipodi:docname="dialog-question.svg" - inkscape:export-filename="/home/hbons/Desktop/dialog-question.png" + inkscape:export-filename="/home/hbons/Desktop/newstyle.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient3121"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1;" - offset="0" - id="stop3123" /> - <stop - style="stop-color:#d3d7cf;stop-opacity:0;" - offset="1" - id="stop3125" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" id="linearGradient3104"> <stop style="stop-color:#eeeeec;stop-opacity:1;" @@ -79,15 +47,259 @@ r="9.975256" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <filter + inkscape:collect="always" + x="-0.27879593" + width="1.5575919" + y="-0.78248727" + height="2.5649745" + id="filter3405"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.5438116" + id="feGaussianBlur3407" /> + </filter> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient2247" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3263"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop3265" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop3267" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2216" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3263" + id="linearGradient3269" + x1="12.845698" + y1="16.037401" + x2="10.698112" + y2="15.449714" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient3191" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient3121" - id="linearGradient1551" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3175" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <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,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + id="radialGradient2214" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3313" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="2.5781252" + fy="11.083743" + fx="17.911736" + cy="11.083743" + cx="17.911736" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" gradientUnits="userSpaceOnUse" - x1="42.925175" - y1="40.136646" - x2="42.925175" - y2="15.474488" /> + id="radialGradient2259" + xlink:href="#linearGradient2382" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2867"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2869" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2871" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2847"> + <stop + style="stop-color:#888a85;stop-opacity:1;" + offset="0" + id="stop2849" /> + <stop + style="stop-color:#888a85;stop-opacity:0;" + offset="1" + id="stop2851" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2382"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2384" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2386" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2230" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2847" + id="linearGradient2853" + x1="12.5" + y1="18.202251" + x2="12.746171" + y2="20.761486" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2867" + id="linearGradient2873" + x1="12.720216" + y1="20.952612" + x2="12.720216" + y2="17.682426" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2303" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2233" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2264" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> </defs> <sodipodi:namedview id="base" @@ -96,17 +308,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="16.976026" - inkscape:cx="39.201403" - inkscape:cy="23.251521" + inkscape:zoom="22.4" + inkscape:cx="41.793957" + inkscape:cy="31.031721" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - fill="#204a87" - inkscape:window-width="1267" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + fill="#fce94f" + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="3" + inkscape:window-y="25" + width="48px" + height="48px" /> <metadata id="metadata7"> <rdf:RDF> @@ -123,25 +337,25 @@ inkscape:groupmode="layer" id="layer1"> <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" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" sodipodi:type="arc" - transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" /> + style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)" + 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(2.2723916,0,0,1.6905173,-4.1758193,23.510748)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1307" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" /> + transform="matrix(1.8043406,0,0,1.8043406,-0.8023303,7.6828845)" /> <path sodipodi:type="arc" style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -151,81 +365,90 @@ sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" /> + transform="matrix(1.6958412,0,0,1.6958412,0.3182737,9.0348911)" /> <path sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2184" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" /> + transform="matrix(1.7042169,0,0,1.7042169,0.3797456,8.7825452)" /> + <path + style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 19.500001,23.5 C 19.500001,26.26 17.260002,28.500001 14.500001,28.500001 C 11.740001,28.500001 9.5000001,26.26 9.5000001,23.5 C 9.5000001,20.74 11.740001,18.5 14.500001,18.5 C 17.260002,18.5 19.500001,20.74 19.500001,23.5 z " + id="path3154" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2191" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,1.486487,11.80163)" /> + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2172" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494387,0,0,1.2877392,-1.9230749,13.069869)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3152" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(4.8735976,0,0,2.5754783,-20.807694,-1.3602619)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2193" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,9.486483,11.80163)" /> + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3148" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494393,0,0,1.2877392,9.0769201,13.069869)" /> <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;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;stroke-dasharray:none" - d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z " - id="path13316" - sodipodi:nodetypes="cscccsssc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.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 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " /> + style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 30,32 C 28.885686,35.996588 25.067255,39 20.5,39 C 15.932746,39 12.114315,35.996588 11,32 C 16.460075,38.82871 24.447577,38.177252 30,32 z " + id="path2186" + sodipodi:nodetypes="cscc" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0109046" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " - xlink:href="#path13316" - style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;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;stroke-dasharray:none" - id="path1336" - inkscape:href="#path13316" - d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " /> - <flowRoot - xml:space="preserve" - id="flowRoot2649" - style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;font-family:Bitstream Charter" - transform="matrix(1.282232,0,0,1.31579,-8.49345,-11.44883)"><flowRegion - id="flowRegion2651"><rect - id="rect2653" - width="44.011906" - height="42.819229" - x="36.988094" - y="20.180773" - style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;font-family:Bitstream Charter" /></flowRegion><flowPara - id="flowPara2655">?</flowPara></flowRoot> <rect - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect2278" - width="16.246384" - height="1.4764884" - x="-2.760174" - y="54.321537" - ry="0.49634099" - rx="0.49687836" - transform="matrix(0.972407,-0.233292,0.286699,0.958021,0,0)" /> + sodipodi:type="arc" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2259" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,3.2901886,-4.1630499)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> + <path + sodipodi:type="arc" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2261" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(-3.5277688,0.705265,0.6665314,1.855957,37.208475,-4.1630499)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> + <path + transform="translate(-2.96875,2.96875)" + style="font-size:19.03945923px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1.55613649px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Century Schoolbook L" + d="M 41.5625,0.03125 C 39.882592,0.03125 38.340312,0.45633843 37.125,1.3125 C 35.909688,2.1686616 35.03125,3.5773827 35.03125,5.15625 C 35.031248,6.9581536 36.509895,8.65625 38.375,8.65625 C 39.965182,8.6562496 41.5,7.3378655 41.5,5.65625 C 41.5,5.3071726 41.34266,4.9823536 41.21875,4.65625 C 41.387991,4.6997757 41.631962,4.7250666 41.6875,4.78125 C 41.780384,4.8752143 41.90625,5.0515022 41.90625,5.59375 C 41.90625,6.1652988 41.718827,6.6932831 41.46875,7.03125 C 40.561362,8.1855326 40.145637,8.7242892 39.8125,9.21875 C 39.479363,9.7132108 39.280996,10.139806 39.125,10.53125 C 39.124907,10.541666 39.124907,10.552084 39.125,10.5625 C 39.043286,10.775751 38.25,11.848298 38.25,13.46875 L 38.25,14.21875 C 38.248868,14.683225 38.432878,15.129003 38.761313,15.457437 C 39.089747,15.785872 39.535525,15.969882 40,15.96875 L 40.59375,15.96875 C 39.296693,16.363109 38.1875,17.335329 38.1875,18.78125 C 38.187498,20.599164 39.742417,21.96875 41.46875,21.96875 C 43.193995,21.968752 44.75,20.563489 44.75,18.78125 C 44.749996,17.191313 43.501537,16.129612 42.0625,15.84375 C 42.760608,15.593328 43.224284,14.929144 43.21875,14.1875 C 43.207309,13.142551 43.280625,12.715648 43.375,12.5 C 43.469375,12.284352 43.666112,12.036543 44.375,11.46875 C 44.385548,11.458466 44.395966,11.448048 44.40625,11.4375 C 45.640264,10.416457 46.472134,9.663013 47.09375,8.75 C 47.715366,7.836987 47.96875,6.7448903 47.96875,5.75 C 47.968751,4.1061365 47.251058,2.5766205 46.0625,1.5625 C 44.873942,0.5483795 43.29027,0.03125 41.5625,0.03125 z " + id="path3346" /> + <path + id="text2395" + d="M 38.506782,17.184869 C 38.482313,14.953817 38.751472,14.339138 40.317489,13.087017 C 42.715448,11.106389 43.253768,10.332347 43.253768,8.7387398 C 43.253768,6.3710938 41.369653,4.7774818 38.580188,4.7774818 C 35.815195,4.7774818 33.808732,6.1889664 33.808732,8.1468275 C 33.808732,9.1485242 34.493866,9.8997976 35.399218,9.8997976 C 36.182227,9.8997976 36.793951,9.3534166 36.793951,8.6476754 C 36.793951,8.1923596 36.549258,7.8053395 36.08435,7.4410862 C 35.717315,7.1678961 35.692845,7.122364 35.692845,6.9402374 C 35.692845,6.3483259 36.769483,5.8019451 37.943996,5.8019451 C 39.681291,5.8019451 40.684521,6.8491761 40.684521,8.6021443 C 40.684521,9.5355437 40.390894,10.400647 39.901517,11.060855 C 38.09081,13.360205 38.090807,13.360208 37.772712,14.157012 C 37.528022,14.794454 37.034866,15.386368 37.034866,16.456362 L 37.034866,17.184869 L 38.506782,17.184869 M 38.512445,20.345536 C 37.65603,20.345536 36.970897,20.982982 36.970897,21.75702 C 36.970897,22.553823 37.65603,23.191268 38.487976,23.191268 C 39.344388,23.191268 40.029523,22.553823 40.029523,21.75702 C 40.029523,20.982982 39.344388,20.345536 38.512445,20.345536" + style="font-size:19.03945923px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeec;fill-opacity:1;stroke:#ffffff;stroke-width:1.55496371px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Century Schoolbook L" /> </g> </svg>
--- a/pidgin/pixmaps/dialogs/64/scalable/warning.svg Mon Oct 01 17:49:01 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/warning.svg Mon Oct 01 17:51:20 2007 +0000 @@ -7,55 +7,35 @@ 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="64" - height="64" + width="48" + height="48" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.45" version="1.0" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/dialogs" + sodipodi:docbase="/home/hbons/Desktop/2.1.1/dialogs" sodipodi:docname="dialog-warning.svg" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/dialogs/dialog-warning.png" + inkscape:export-filename="/home/hbons/Desktop/newstyle.png" inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-ydpi="90" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient3121"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1;" - offset="0" - id="stop3123" /> + id="linearGradient3179"> <stop - style="stop-color:#d3d7cf;stop-opacity:0;" - offset="1" - id="stop3125" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" + style="stop-color:#555753;stop-opacity:1;" offset="0" - id="stop3818" /> + id="stop3181" /> <stop - style="stop-color:#000000;stop-opacity:0;" + style="stop-color:#555753;stop-opacity:0;" offset="1" - id="stop3820" /> + id="stop3183" /> </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" id="linearGradient3104"> @@ -79,15 +59,268 @@ r="9.975256" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <filter + inkscape:collect="always" + x="-0.27879593" + width="1.5575919" + y="-0.78248727" + height="2.5649745" + id="filter3405"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.5438116" + id="feGaussianBlur3407" /> + </filter> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient2247" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3263"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop3265" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop3267" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2216" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3263" + id="linearGradient3269" + x1="12.845698" + y1="16.037401" + x2="10.698112" + y2="15.449714" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + id="radialGradient3191" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient3121" - id="linearGradient1551" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3175" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <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,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-1.3308754,1.3308124,-1.4391023,-1.4390341,45.391773,16.51952)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="18.005522" + fx="8.7359829" + cy="18.005522" + cx="8.7359829" + id="radialGradient2214" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient3313" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <radialGradient + r="2.5781252" + fy="11.083743" + fx="17.911736" + cy="11.083743" + cx="17.911736" + gradientTransform="matrix(-1.591138,1.574803,-1.783257,-1.76495,68.854751,-2.8442229)" gradientUnits="userSpaceOnUse" - x1="42.925175" - y1="40.136646" - x2="42.925175" - y2="15.474488" /> + id="radialGradient2259" + xlink:href="#linearGradient2382" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2867"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2869" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2871" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2847"> + <stop + style="stop-color:#888a85;stop-opacity:1;" + offset="0" + id="stop2849" /> + <stop + style="stop-color:#888a85;stop-opacity:0;" + offset="1" + id="stop2851" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2382"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2384" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2386" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2230" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2847" + id="linearGradient2853" + x1="12.5" + y1="18.202251" + x2="12.746171" + y2="20.761486" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2867" + id="linearGradient2873" + x1="12.720216" + y1="20.952612" + x2="12.720216" + y2="17.682426" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2303" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <radialGradient + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + gradientUnits="userSpaceOnUse" + r="9.975256" + fy="14.186539" + fx="8.3343515" + cy="14.186539" + cx="8.3343515" + id="radialGradient2233" + xlink:href="#linearGradient3104" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3104" + id="radialGradient2264" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.9327,0.932656,-0.947494,-0.947449,33.02126,11.96667)" + cx="8.3343515" + cy="14.186539" + fx="8.3343515" + fy="14.186539" + r="9.975256" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3179" + id="linearGradient3185" + x1="19.107143" + y1="33.892857" + x2="24.017857" + y2="33.892857" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -96,17 +329,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="12.003863" - inkscape:cx="39.201403" - inkscape:cy="23.251521" + inkscape:zoom="11.2" + inkscape:cx="48.857979" + inkscape:cy="24.415118" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - fill="#cc0000" - inkscape:window-width="1267" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + fill="#fce94f" + inkscape:window-width="1440" + inkscape:window-height="845" + inkscape:window-x="3" + inkscape:window-y="25" + width="48px" + height="48px" /> <metadata id="metadata7"> <rdf:RDF> @@ -123,25 +358,25 @@ inkscape:groupmode="layer" id="layer1"> <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" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.5;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;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" sodipodi:type="arc" - transform="matrix(2.383972,0,0,1.117487,-53.5217,33.04541)" /> + style="opacity:0.64044949;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3405)" + 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(2.2723916,0,0,1.6905173,-0.1758194,23.510748)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#f57900;stroke-width:0.53913006;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#edd400;fill-opacity:1;stroke:#cc6400;stroke-width:0.55559433;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1307" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.854646,0,0,1.855034,-0.899768,22.62707)" /> + transform="matrix(1.8043406,0,0,1.8043406,3.1976696,7.6828846)" /> <path sodipodi:type="arc" style="opacity:0.79545456;fill:url(#radialGradient3114);fill-opacity:1;stroke:none;stroke-width:1.05274069;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -151,83 +386,96 @@ sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.704217,0,0,1.704217,0.879746,24.28255)" /> + transform="matrix(1.6958412,0,0,1.6958412,4.3182736,9.0348912)" /> <path sodipodi:type="arc" - style="opacity:0.5;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.57006598;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.58677971;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path2184" sodipodi:cx="11.806158" sodipodi:cy="10.983024" sodipodi:rx="9.975256" sodipodi:ry="9.975256" d="M 21.781414 10.983024 A 9.975256 9.975256 0 1 1 1.8309021,10.983024 A 9.975256 9.975256 0 1 1 21.781414 10.983024 z" - transform="matrix(1.75441,0,0,1.753957,0.28417,23.73792)" /> + transform="matrix(1.7042169,0,0,1.7042169,4.3797455,8.7825453)" /> <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;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;stroke-dasharray:none" - d="M 44.078659,9.5112136 C 34.84342,9.8834971 27.500059,15.977362 27.500059,23.405814 C 27.500059,27.671183 29.253586,32.180745 33.0662,34.729626 C 33.874807,38.292011 31.54507,41.058776 31.141507,41.494102 C 31.871844,41.290557 37.643487,39.670532 39.808221,37.260561 C 41.990193,37.168054 43.23089,37.300418 44.997262,37.300418 C 54.649949,37.300418 62.494467,31.073895 62.494465,23.405814 C 62.494465,15.737733 54.649949,9.5112136 44.997262,9.5112136 C 44.695616,9.5112136 44.37657,9.4992035 44.078659,9.5112136 z " - id="path13316" - sodipodi:nodetypes="cscccsssc" /> + style="fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 23.500001,23.5 C 23.500001,26.26 21.260002,28.500001 18.500001,28.500001 C 15.740001,28.500001 13.5,26.26 13.5,23.5 C 13.5,20.74 15.740001,18.5 18.500001,18.5 C 21.260002,18.5 23.500001,20.74 23.500001,23.5 z " + id="path3154" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0020103" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.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 43.9375,10.5 C 35.082559,10.856667 28.28125,16.643774 28.28125,23.4375 C 28.28125,27.441186 29.946384,31.636673 33.4375,33.96875 C 33.648247,34.117093 33.793739,34.340928 33.84375,34.59375 C 34.305353,36.625753 33.873291,38.418899 33.28125,39.75 C 33.741286,39.588469 33.859625,39.584381 34.375,39.375 C 36.123726,38.664548 38.008731,37.651133 38.875,36.6875 C 39.056781,36.478508 39.316956,36.354077 39.59375,36.34375 C 41.847992,36.248256 43.128683,36.40625 44.84375,36.40625 C 54.103198,36.406251 61.406252,30.447219 61.40625,23.4375 C 61.406249,16.427779 54.105354,10.5 44.84375,10.5 C 44.5143,10.499999 44.179676,10.490245 43.9375,10.5 z " /> + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2172" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494387,0,0,1.2877392,1.0769249,12.069869)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#fea523;stroke-width:0.282258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3152" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(4.8735976,0,0,2.5754783,-16.807694,-1.3602618)" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0109046" - inkscape:original="M 44.09375 9.5 C 34.858511 9.8722838 27.5 15.977798 27.5 23.40625 C 27.5 27.67162 29.249886 32.169869 33.0625 34.71875 C 33.871107 38.281135 31.559813 41.064674 31.15625 41.5 C 31.886588 41.296455 37.647766 39.659971 39.8125 37.25 C 41.994473 37.157491 43.233628 37.3125 45 37.3125 C 54.652688 37.312499 62.500002 31.074331 62.5 23.40625 C 62.5 15.73817 54.652687 9.5 45 9.5 C 44.698355 9.5000003 44.391661 9.4879899 44.09375 9.5 z " - xlink:href="#path13316" - style="opacity:1;color:#000000;fill:url(#linearGradient1551);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;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;stroke-dasharray:none" - id="path1336" - inkscape:href="#path13316" - d="M 43.9375,10.5 C 35.086269,10.856517 28.28125,16.649624 28.28125,23.4375 C 28.28125,27.43874 29.949375,31.638672 33.4375,33.96875 C 33.659358,34.111954 33.816384,34.336276 33.875,34.59375 C 34.337119,36.628026 33.873842,38.417659 33.28125,39.75 C 33.741161,39.588512 33.859781,39.584317 34.375,39.375 C 36.123195,38.664763 38.010688,37.617706 38.875,36.65625 C 39.06282,36.459679 39.321894,36.347038 39.59375,36.34375 C 41.848554,36.248232 43.129202,36.40625 44.84375,36.40625 C 54.099359,36.406251 61.406252,30.441153 61.40625,23.4375 C 61.406249,16.433845 54.101534,10.5 44.84375,10.5 C 44.514064,10.499999 44.17917,10.490265 43.9375,10.5 z " /> - <flowRoot - xml:space="preserve" - id="flowRoot2649" - style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#cc0000;font-family:Bitstream Charter" - transform="matrix(1.41844,0,0,1.343101,-12.30498,-12.66081)"><flowRegion - id="flowRegion2651"><rect - id="rect2653" - width="44.011906" - height="42.819229" - x="36.988094" - y="20.180773" - style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#cc0000;font-family:Bitstream Charter" /></flowRegion><flowPara - id="flowPara2655">!</flowPara></flowRoot> <path + sodipodi:type="arc" + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.98640186;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3148" + sodipodi:cx="9.7069349" + sodipodi:cy="9.6526775" + sodipodi:rx="1.0259361" + sodipodi:ry="1.9413869" + d="M 10.732871 9.6526775 A 1.0259361 1.9413869 0 1 1 8.6809988,9.6526775 A 1.0259361 1.9413869 0 1 1 10.732871 9.6526775 z" + transform="matrix(1.9494393,0,0,1.2877392,10.07692,12.069869)" /> + <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2193" - sodipodi:cx="9.0598059" - sodipodi:cy="8.7845774" - sodipodi:rx="1.1679889" - sodipodi:ry="1.4520943" - d="M 10.227795 8.7845774 A 1.1679889 1.4520943 0 1 1 7.891817,8.7845774 A 1.1679889 1.4520943 0 1 1 10.227795 8.7845774 z" - transform="matrix(1.712345,0,0,2.754643,9.486483,14.80163)" /> + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2259" + sodipodi:cx="8.3258924" + sodipodi:cy="9.2232141" + sodipodi:rx="1.2276785" + sodipodi:ry="1.7410715" + d="M 7.2133909,8.4869402 A 1.2276785,1.7410715 0 0 1 9.288462,8.1425499" + transform="matrix(3.5277688,0.705265,-0.6665314,1.855957,7.2901885,-4.1630498)" + sodipodi:start="3.5782199" + sodipodi:end="5.6135639" + sodipodi:open="true" /> + <path + sodipodi:type="arc" + style="opacity:0.64044949;fill:none;fill-opacity:1;stroke:#f57900;stroke-width:0.3774938;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2261" + sodipodi:cx="8.3258924"