Mercurial > pidgin.yaz
changeset 20685:02df6998b466
propagate from branch 'im.pidgin.rlaager.merging.2_2_1_conflicts' (head 4ad1081695d083df424898e6e7091f731b401265)
to branch 'im.pidgin.pidgin' (head d33243e8f5347776c81f81a0e4ba3a76ae5505a5)
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Fri, 28 Sep 2007 16:34:43 +0000 |
parents | 509ca8ebe515 (current diff) 8d9db4584f02 (diff) |
children | fd664b4aa4f1 |
files | COPYRIGHT finch/gntconn.c finch/gntconv.c libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/message.c libpurple/protocols/msn/directconn.c libpurple/protocols/msn/msn-utils.c libpurple/protocols/msn/msn-utils.h libpurple/protocols/msn/servconn.c libpurple/protocols/msn/userlist.c libpurple/protocols/myspace/markup.c libpurple/protocols/myspace/myspace.c libpurple/protocols/oscar/oscar.c libpurple/util.c libpurple/win32/win32dep.c pidgin/gtkblist.c pidgin/gtkcellrendererexpander.c pidgin/gtkconv.c pidgin/gtkimhtmltoolbar.c pidgin/gtkmain.c pidgin/gtknotify.c pidgin/gtkprefs.c |
diffstat | 138 files changed, 12194 insertions(+), 3763 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Fri Sep 28 16:32:28 2007 +0000 +++ b/COPYRIGHT Fri Sep 28 16:34:43 2007 +0000 @@ -246,6 +246,7 @@ Kevin Miller Paul Miller Arkadiusz Miskiewicz +David Mohr Andrew Molloy Michael Monreal Benjamin Moody @@ -278,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 Fri Sep 28 16:32:28 2007 +0000 +++ b/ChangeLog Fri Sep 28 16:34:43 2007 +0000 @@ -1,5 +1,45 @@ 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 + + libpurple: + * A few build issues on Solaris were fixed. + * Cancelling the password prompt for an account will no longer leave + it in an ambiguous state. (It will be disabled.) + * Fixed an erroneous size display for MSN file transfers. (galt) + * Real usernames are now shown in the system log. + * Gmail notifications are better tracked + + Pidgin: + * If you alias a buddy to an alias that is already present within + 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. + * Fixed keyboard tab reordering to move tabs one step instead of two. + * Pidgin's display is now saved with the command line for session + restoration. (David Mohr) + * You should no longer lose proxy settings when Pidgin is restarted. + * ICQ Birthday notifications are shown as buddy list emblems + + 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
--- a/doc/funniest_home_convos.txt Fri Sep 28 16:32:28 2007 +0000 +++ b/doc/funniest_home_convos.txt Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/finch/gntblist.c Fri Sep 28 16:34:43 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/gntconn.c Fri Sep 28 16:32:28 2007 +0000 +++ b/finch/gntconn.c Fri Sep 28 16:34:43 2007 +0000 @@ -105,10 +105,11 @@ { FinchAutoRecon *info; PurpleAccount *account = purple_connection_get_account(gc); - - info = g_hash_table_lookup(hash, account); + GList *list; if (!gc->wants_to_die) { + info = g_hash_table_lookup(hash, account); + if (info == NULL) { info = g_new0(FinchAutoRecon, 1); g_hash_table_insert(hash, account, info); @@ -141,6 +142,17 @@ g_free(secondary); purple_account_set_enabled(account, FINCH_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
--- a/finch/gntconv.c Fri Sep 28 16:32:28 2007 +0000 +++ b/finch/gntconv.c Fri Sep 28 16:34:43 2007 +0000 @@ -311,13 +311,40 @@ static void account_signed_on_off(PurpleConnection *gc, gpointer null) { - GList *ims = purple_get_ims(); - while (ims) { - PurpleConversation *conv = ims->data; + GList *list = purple_get_ims(); + while (list) { + PurpleConversation *conv = list->data; PurpleConversation *cc = find_conv_with_contact(conv->account, conv->name); if (cc) generate_send_to_menu(cc->ui_data); - ims = ims->next; + list = list->next; + } + + if (PURPLE_CONNECTION_IS_CONNECTED(gc)) { + /* We just signed on. Let's see if there's any chat that we have open, + * and hadn't left before the disconnect. */ + list = purple_get_chats(); + while (list) { + PurpleConversation *conv = list->data; + PurpleChat *chat; + GHashTable *comps = NULL; + + list = list->next; + if (conv->account != gc->account || + !purple_conversation_get_data(conv, "want-to-rejoin")) + continue; + + 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); + } } } @@ -738,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;
--- a/finch/gntnotify.c Fri Sep 28 16:32:28 2007 +0000 +++ b/finch/gntnotify.c Fri Sep 28 16:34:43 2007 +0000 @@ -352,14 +352,17 @@ gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL)); - columns = purple_notify_searchresults_get_columns_count(results); + columns = g_list_length(results->columns); tree = gnt_tree_new_with_columns(columns); gnt_tree_set_show_title(GNT_TREE(tree), TRUE); gnt_box_add_widget(GNT_BOX(window), tree); - for (i = 0; i < columns; i++) - gnt_tree_set_column_title(GNT_TREE(tree), i, - purple_notify_searchresults_column_get_title(results, i)); + i = 0; + for (iter = results->columns; iter; iter = iter->next) + { + gnt_tree_set_column_title(GNT_TREE(tree), i, iter->data); + i++; + } box = gnt_hbox_new(TRUE);
--- a/finch/libgnt/gntentry.c Fri Sep 28 16:32:28 2007 +0000 +++ b/finch/libgnt/gntentry.c Fri Sep 28 16:34:43 2007 +0000 @@ -100,6 +100,15 @@ return changed; } +static int +max_common_prefix(const char *s, const char *t) +{ + const char *f = s; + while (*f && *t && *f == *t++) + f++; + return f - s; +} + static gboolean show_suggest_dropdown(GntEntry *entry) { @@ -110,6 +119,7 @@ GList *iter; const char *text = NULL; const char *sgst = NULL; + int max = -1; if (entry->word) { @@ -121,14 +131,13 @@ else suggest = g_strdup(entry->start); len = strlen(suggest); /* Don't need to use the utf8-function here */ - + if (entry->ddown == NULL) { GntWidget *box = gnt_vbox_new(FALSE); entry->ddown = gnt_tree_new(); gnt_tree_set_compare_func(GNT_TREE(entry->ddown), (GCompareFunc)g_utf8_collate); gnt_box_add_widget(GNT_BOX(box), entry->ddown); - /* XXX: Connect to the "activate" signal for the dropdown tree */ GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); @@ -151,6 +160,10 @@ gnt_tree_create_row(GNT_TREE(entry->ddown), text), NULL, NULL); count++; + if (max == -1) + max = strlen(text) - len; + else if (max) + max = MIN(max, max_common_prefix(sgst + len, text + len)); sgst = text; } } @@ -163,6 +176,17 @@ destroy_suggest(entry); return complete_suggest(entry, sgst); } else { + if (max > 0) { + GntWidget *ddown = entry->ddown; + char *match = g_strndup(sgst + len, max); + entry->ddown = NULL; + gnt_entry_key_pressed(GNT_WIDGET(entry), match); + g_free(match); + if (entry->ddown) + gnt_widget_destroy(ddown); + else + entry->ddown = ddown; + } gnt_widget_draw(entry->ddown->parent); }
--- a/libpurple/blist.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/blist.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/blist.h Fri Sep 28 16:34:43 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/cmds.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/cmds.h Fri Sep 28 16:34:43 2007 +0000 @@ -67,10 +67,20 @@ PURPLE_CMD_P_VERY_HIGH = 6000, }; +/** Flags used to set various properties of commands. Every command should + * have at least one of #PURPLE_CMD_FLAG_IM and #PURPLE_CMD_FLAG_CHAT set in + * order to be even slighly useful. + * + * @see purple_cmd_register + */ enum _PurpleCmdFlag { + /** Command is usable in IMs. */ PURPLE_CMD_FLAG_IM = 0x01, + /** Command is usable in multi-user chats. */ PURPLE_CMD_FLAG_CHAT = 0x02, + /** Command is usable only for a particular prpl. */ PURPLE_CMD_FLAG_PRPL_ONLY = 0x04, + /** Incorrect arguments to this command should be accepted anyway. */ PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08, }; @@ -92,36 +102,49 @@ * The command will only happen if commands are enabled, * which is a UI pref. UIs don't have to support commands at all. * - * @param cmd The command. This should be a UTF8 (or ASCII) string, with no spaces + * @param cmd The command. This should be a UTF-8 (or ASCII) string, with no spaces * or other white space. - * @param args This tells Purple how to parse the arguments to the command for you. - * If what the user types doesn't match, Purple will keep looking for another - * command, unless the flag @c PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed in f. - * This string contains no whitespace, and uses a single character for each argument. - * The recognized characters are: - * 'w' Matches a single word. - * 'W' Matches a single word, with formatting. - * 's' Matches the rest of the arguments after this point, as a single string. - * 'S' Same as 's' but with formatting. + * @param args A string of characters describing to libpurple how to parse this + * command's arguments. If what the user types doesn't match this + * pattern, libpurple will keep looking for another command, unless + * the flag #PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed in @a f. + * This string should contain no whitespace, and use a single + * character for each argument. The recognized characters are: + * <ul> + * <li><tt>'w'</tt>: Matches a single word.</li> + * <li><tt>'W'</tt>: Matches a single word, with formatting.</li> + * <li><tt>'s'</tt>: Matches the rest of the arguments after this + * point, as a single string.</li> + * <li><tt>'S'</tt>: Same as <tt>'s'</tt> but with formatting.</li> + * </ul> * If args is the empty string, then the command accepts no arguments. - * The args passed to callback func will be a @c NULL terminated array of null - * terminated strings, and will always match the number of arguments asked for, - * unless PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed. - * @param p This is the priority. Higher priority commands will be run first, and usually the - * first command will stop any others from being called. - * @param f These are the flags. You need to at least pass one of PURPLE_CMD_FLAG_IM or - * PURPLE_CMD_FLAG_CHAT (can may pass both) in order for the command to ever actually - * be called. - * @param prpl_id This is the prpl's id string. This is only meaningful if the proper flag is set. + * The args passed to the callback @a func will be a @c NULL + * terminated array of @c NULL terminated strings, and will always + * match the number of arguments asked for, unless + * #PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS is passed. + * @param p This is the priority. Higher priority commands will be run first, + * and usually the first command will stop any others from being + * called. + * @param f Flags specifying various options about this command, combined with + * <tt>|</tt> (bitwise OR). You need to at least pass one of + * #PURPLE_CMD_FLAG_IM or #PURPLE_CMD_FLAG_CHAT (you may pass both) in + * order for the command to ever actually be called. + * @param prpl_id If the #PURPLE_CMD_FLAG_PRPL_ONLY flag is set, this is the id + * of the prpl to which the command applies (such as + * <tt>"prpl-msn"</tt>). If the flag is not set, this parameter + * is ignored; pass @c NULL (or a humourous string of your + * choice!). * @param func This is the function to call when someone enters this command. - * @param helpstr This is a whitespace sensitive, UTF-8, HTML string describing how to use the command. - * The preferred format of this string shall be the commands name, followed by a space - * and any arguments it accepts (if it takes any arguments, otherwise no space), followed - * by a colon, two spaces, and a description of the command in sentence form. No slash - * before the command name. - * @param data User defined data to pass to the PurpleCmdFunc - * @return A PurpleCmdId. This is only used for calling purple_cmd_unregister. - * Returns 0 on failure. + * @param helpstr a whitespace sensitive, UTF-8, HTML string describing how to + * use the command. The preferred format of this string is the + * command's name, followed by a space and any arguments it + * accepts (if it takes any arguments, otherwise no space), + * followed by a colon, two spaces, and a description of the + * command in sentence form. Do not include a slash before the + * command name. + * @param data User defined data to pass to the #PurpleCmdFunc @a f. + * @return A #PurpleCmdId, which is only used for calling + * #purple_cmd_unregister, or @a 0 on failure. */ PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, PurpleCmdPriority p, PurpleCmdFlag f, const gchar *prpl_id, PurpleCmdFunc func, const gchar *helpstr, void *data); @@ -133,7 +156,7 @@ * or something else that might go away. Normally this is called when the plugin * unloads itself. * - * @param id The PurpleCmdId to unregister. + * @param id The #PurpleCmdId to unregister, as returned by #purple_cmd_register. */ void purple_cmd_unregister(PurpleCmdId id); @@ -153,7 +176,7 @@ * include both the default formatting and any extra manual formatting. * @param errormsg If the command failed errormsg is filled in with the appropriate error * message. It must be freed by the caller with g_free(). - * @return A PurpleCmdStatus indicated if the command succeeded or failed. + * @return A #PurpleCmdStatus indicated if the command succeeded or failed. */ PurpleCmdStatus purple_cmd_do_command(PurpleConversation *conv, const gchar *cmdline, const gchar *markup, gchar **errormsg); @@ -161,13 +184,15 @@ /** * List registered commands. * - * Returns a GList (which must be freed by the caller) of all commands - * that are valid in the context of conv, or all commands, if conv is - * @c NULL. Don't keep this list around past the main loop, or anything else - * that might unregister a command, as the char*'s used get freed then. + * Returns a <tt>GList</tt> (which must be freed by the caller) of all commands + * that are valid in the context of @a conv, or all commands, if @a conv is @c + * NULL. Don't keep this list around past the main loop, or anything else that + * might unregister a command, as the <tt>const char *</tt>'s used get freed + * then. * * @param conv The conversation, or @c NULL. - * @return A GList of const char*, which must be freed with g_list_free(). + * @return A @c GList of <tt>const char *</tt>, which must be freed with + * <tt>g_list_free()</tt>. */ GList *purple_cmd_list(PurpleConversation *conv); @@ -180,7 +205,7 @@ * @param conv The conversation, or @c NULL for no context. * @param cmd The command. No wildcards accepted, but returns help for all * commands if @c NULL. - * @return A GList of const char*s, which is the help string + * @return A <tt>GList</tt> of <tt>const char *</tt>s, which is the help string * for that command. */ GList *purple_cmd_help(PurpleConversation *conv, const gchar *cmd);
--- a/libpurple/conversation.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/conversation.c Fri Sep 28 16:34:43 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/internal.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/internal.h Fri Sep 28 16:34:43 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.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/notify.h Fri Sep 28 16:34:43 2007 +0000 @@ -293,7 +293,17 @@ /** * Returns a number of the rows in the search results object. - * + * + * @deprecated This function will be removed in Pidgin 3.0.0 unless + * there is sufficient demand to keep it. Using this + * function encourages looping through the results + * inefficiently. Instead of using this function you + * should iterate through the results using a loop + * similar to this: + * for (l = results->rows; l != NULL; l = l->next) + * If you really need to get the number of rows you + * can use g_list_length(results->rows). + * * @param results The search results object. * * @return Number of the result rows. @@ -303,6 +313,16 @@ /** * Returns a number of the columns in the search results object. * + * @deprecated This function will be removed in Pidgin 3.0.0 unless + * there is sufficient demand to keep it. Using this + * function encourages looping through the columns + * inefficiently. Instead of using this function you + * should iterate through the columns using a loop + * similar to this: + * for (l = results->columns; l != NULL; l = l->next) + * If you really need to get the number of columns you + * can use g_list_length(results->columns). + * * @param results The search results object. * * @return Number of the columns. @@ -312,6 +332,16 @@ /** * Returns a row of the results from the search results object. * + * @deprecated This function will be removed in Pidgin 3.0.0 unless + * there is sufficient demand to keep it. Using this + * function encourages looping through the results + * inefficiently. Instead of using this function you + * should iterate through the results using a loop + * similar to this: + * for (l = results->rows; l != NULL; l = l->next) + * If you really need to get the data for a particular + * row you can use g_list_nth_data(results->rows, row_id). + * * @param results The search results object. * @param row_id Index of the row to be returned. * @@ -322,7 +352,15 @@ /** * Returns a title of the search results object's column. - * + * + * @deprecated This function will be removed in Pidgin 3.0.0 unless + * there is sufficient demand to keep it. Using this + * function encourages looping through the columns + * inefficiently. Instead of using this function you + * should iterate through the name of a particular + * column you can use + * g_list_nth_data(results->columns, row_id). + * * @param results The search results object. * @param column_id Index of the column. *
--- a/libpurple/plugins/tcl/tcl.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/plugins/tcl/tcl.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/plugins/tcl/tcl_cmds.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/plugins/tcl/tcl_purple.h Fri Sep 28 16:34:43 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/jabber/adhoccommands.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.c Fri Sep 28 16:34:43 2007 +0000 @@ -151,8 +151,11 @@ /* display result */ xmlnode *note = xmlnode_get_child(command,"note"); - if(note) - purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), xmlnode_get_data(note), NULL); + if(note) { + char *data = xmlnode_get_data(note); + purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), data, NULL); + g_free(data); + } if(xdata) jabber_x_data_request(js, xdata, (jabber_x_data_cb)do_adhoc_ignoreme, NULL);
--- a/libpurple/protocols/jabber/buddy.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Fri Sep 28 16:34:43 2007 +0000 @@ -1455,10 +1455,13 @@ return; img = purple_base64_decode(b64data, &size); - if(!img) + if(!img) { + g_free(b64data); return; + } purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, img, size, checksum); + g_free(b64data); } void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items) {
--- a/libpurple/protocols/jabber/jabber.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Fri Sep 28 16:34:43 2007 +0000 @@ -814,7 +814,7 @@ if(account->registration_cb) (account->registration_cb)(account, FALSE, account->registration_cb_user_data); jabber_connection_schedule_close(cbdata->js); -} + } g_free(cbdata->who); g_free(cbdata); } @@ -883,12 +883,12 @@ if((href = xmlnode_get_data(url))) { purple_notify_uri(NULL, href); g_free(href); - if(js->registration) { - js->gc->wants_to_die = TRUE; - if(account->registration_cb) /* succeeded, but we have no login info */ - (account->registration_cb)(account, TRUE, account->registration_cb_user_data); - jabber_connection_schedule_close(js); - } + if(js->registration) { + js->gc->wants_to_die = TRUE; + if(account->registration_cb) /* succeeded, but we have no login info */ + (account->registration_cb)(account, TRUE, account->registration_cb_user_data); + jabber_connection_schedule_close(js); + } return; } } @@ -988,14 +988,14 @@ purple_request_field_group_add_field(group, field); } - if((y = xmlnode_get_child(query, "instructions"))) - instructions = xmlnode_get_data(y); + if((y = xmlnode_get_child(query, "instructions"))) + instructions = xmlnode_get_data(y); else if(registered) instructions = g_strdup(_("Please fill out the information below " "to change your account registration.")); - else - instructions = g_strdup(_("Please fill out the information below " - "to register your new account.")); + else + instructions = g_strdup(_("Please fill out the information below " + "to register your new account.")); cbdata = g_new0(JabberRegisterCBData, 1); cbdata->js = js; @@ -1020,8 +1020,8 @@ g_free(title); } - g_free(instructions); - } + g_free(instructions); +} void jabber_register_start(JabberStream *js) { @@ -1532,15 +1532,15 @@ "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), - "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), - "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), - "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), - "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), - "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), - "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); @@ -1555,15 +1555,15 @@ "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), - "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), - "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), - "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), - "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), - "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), - "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); @@ -1578,15 +1578,15 @@ "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), - "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), - "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), - "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), - "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), - "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), - "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); @@ -1601,15 +1601,15 @@ "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), - "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), - "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), - "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), - "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), - "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), - "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); @@ -1624,15 +1624,15 @@ "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), - "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), - "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), - "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), - "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), - "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), - "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); @@ -2240,6 +2240,44 @@ return PURPLE_CMD_RET_FAILED; } +GList *jabber_attention_types(PurpleAccount *account) +{ + static GList *types = NULL; + PurpleAttentionType *attn; + + if (!types) { + attn = g_new0(PurpleAttentionType, 1); + attn->name = _("Buzz"); + attn->incoming_description = _("%s has buzzed you!"); + attn->outgoing_description = _("Buzzing %s..."); + types = g_list_append(types, attn); + } + + return types; +} + +gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code) +{ + PurpleConversation *conv; + char *error; + char *args[1]; + PurpleCmdRet ret; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, username, gc->account); + + args[0] = (char *)username; + + ret = jabber_cmd_buzz(conv, "buzz", args, &error, NULL); + + if (ret == PURPLE_CMD_RET_FAILED) { + purple_debug_error("jabber", "jabber_send_attention: jabber_cmd_buzz failed with error: %s\n", error ? error : "(NULL)"); + return FALSE; + } else { + return TRUE; + } +} + + gboolean jabber_offline_message(const PurpleBuddy *buddy) { return TRUE;
--- a/libpurple/protocols/jabber/jabber.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.h Fri Sep 28 16:34:43 2007 +0000 @@ -66,6 +66,9 @@ #define CAPS0115_NODE "http://pidgin.im/caps" +/* Index into attention_types list */ +#define JABBER_BUZZ 0 + typedef enum { JABBER_STREAM_OFFLINE, JABBER_STREAM_CONNECTING, @@ -231,6 +234,8 @@ void jabber_register_gateway(JabberStream *js, const char *gateway); void jabber_register_account(PurpleAccount *account); void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data); +gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code); +GList *jabber_attention_types(PurpleAccount *account); void jabber_convo_closed(PurpleConnection *gc, const char *who); PurpleChat *jabber_find_blist_chat(PurpleAccount *account, const char *name); gboolean jabber_offline_message(const PurpleBuddy *buddy);
--- a/libpurple/protocols/jabber/libxmpp.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Fri Sep 28 16:34:43 2007 +0000 @@ -113,10 +113,10 @@ jabber_prpl_send_raw, /* send_raw */ jabber_roomlist_room_serialize, /* roomlist_room_serialize */ jabber_unregister_account, /* unregister_user */ + jabber_send_attention, /* send_attention */ + jabber_attention_types, /* attention_types */ /* padding */ - NULL, - NULL, NULL };
--- a/libpurple/protocols/jabber/message.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/message.c Fri Sep 28 16:34:43 2007 +0000 @@ -327,7 +327,7 @@ if(type) { if(!strcmp(type, "normal")) jm->type = JABBER_MESSAGE_NORMAL; - else if(!strcmp(type, "chat")) + else if(!strcmp(type, "chat")) jm->type = JABBER_MESSAGE_CHAT; else if(!strcmp(type, "groupchat")) jm->type = JABBER_MESSAGE_GROUPCHAT;
--- a/libpurple/protocols/jabber/presence.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/presence.c Fri Sep 28 16:34:43 2007 +0000 @@ -192,16 +192,11 @@ jabber_tune_set(js->gc, &tuneinfo); /* update old values */ - if(js->old_artist) - g_free(js->old_artist); - if(js->old_title) - g_free(js->old_title); - if(js->old_source) - g_free(js->old_source); - if(js->old_uri) - g_free(js->old_uri); - if(js->old_track) - g_free(js->old_track); + g_free(js->old_artist); + g_free(js->old_title); + g_free(js->old_source); + g_free(js->old_uri); + g_free(js->old_track); js->old_artist = g_strdup(artist); js->old_title = g_strdup(title); js->old_source = g_strdup(source);
--- a/libpurple/protocols/jabber/usernick.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/usernick.c Fri Sep 28 16:34:43 2007 +0000 @@ -33,7 +33,7 @@ xmlnode *item = xmlnode_get_child(items, "item"); JabberBuddy *buddy = jabber_buddy_find(js, from, FALSE); xmlnode *nick; - const char *nickname = NULL; + char *nickname = NULL; /* ignore the tune of people not on our buddy list */ if (!buddy || !item) @@ -43,8 +43,8 @@ if (!nick) return; nickname = xmlnode_get_data(nick); - serv_got_alias(js->gc, from, nickname); + g_free(nickname); } static void do_nick_set(JabberStream *js, const char *nick) { @@ -64,7 +64,7 @@ } static void do_nick_got_own_nick_cb(JabberStream *js, const char *from, xmlnode *items) { - const char *oldnickname = NULL; + char *oldnickname = NULL; xmlnode *item = xmlnode_get_child(items,"item"); if(item) { @@ -77,6 +77,7 @@ _("This information is visible to all contacts on your contact list, so choose something appropriate."), oldnickname, FALSE, FALSE, NULL, _("Set"), PURPLE_CALLBACK(do_nick_set), _("Cancel"), NULL, purple_connection_get_account(js->gc), NULL, NULL, js); + g_free(oldnickname); } static void do_nick_set_nick(PurplePluginAction *action) {
--- a/libpurple/protocols/jabber/usertune.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/jabber/usertune.c Fri Sep 28 16:34:43 2007 +0000 @@ -41,48 +41,61 @@ if (!buddy || !item) return; - tuneinfodata.artist = ""; - tuneinfodata.title = ""; - tuneinfodata.album = ""; - tuneinfodata.track = ""; + tuneinfodata.artist = NULL; + tuneinfodata.title = NULL; + tuneinfodata.album = NULL; + tuneinfodata.track = NULL; tuneinfodata.time = -1; - tuneinfodata.url = ""; - + tuneinfodata.url = NULL; + tune = xmlnode_get_child_with_namespace(item, "tune", "http://jabber.org/protocol/tune"); if (!tune) return; + resource = jabber_buddy_find_resource(buddy, NULL); + if(!resource) + return; /* huh? */ for (tuneinfo = tune->child; tuneinfo; tuneinfo = tuneinfo->next) { if (tuneinfo->type == XMLNODE_TYPE_TAG) { if (!strcmp(tuneinfo->name, "artist")) { - if (tuneinfodata.artist[0] == '\0') /* only pick the first one */ + if (tuneinfodata.artist == NULL) /* only pick the first one */ tuneinfodata.artist = xmlnode_get_data(tuneinfo); } else if (!strcmp(tuneinfo->name, "length")) { if (tuneinfodata.time == -1) { char *length = xmlnode_get_data(tuneinfo); if (length) tuneinfodata.time = strtol(length, NULL, 10); + g_free(length); } } else if (!strcmp(tuneinfo->name, "source")) { - if (tuneinfodata.album[0] == '\0') /* only pick the first one */ + if (tuneinfodata.album == NULL) /* only pick the first one */ tuneinfodata.album = xmlnode_get_data(tuneinfo); } else if (!strcmp(tuneinfo->name, "title")) { - if (tuneinfodata.title[0] == '\0') /* only pick the first one */ + if (tuneinfodata.title == NULL) /* only pick the first one */ tuneinfodata.title = xmlnode_get_data(tuneinfo); } else if (!strcmp(tuneinfo->name, "track")) { - if (tuneinfodata.track[0] == '\0') /* only pick the first one */ + if (tuneinfodata.track == NULL) /* only pick the first one */ tuneinfodata.track = xmlnode_get_data(tuneinfo); } else if (!strcmp(tuneinfo->name, "uri")) { - if (tuneinfodata.url[0] == '\0') /* only pick the first one */ + if (tuneinfodata.url == NULL) /* only pick the first one */ tuneinfodata.url = xmlnode_get_data(tuneinfo); } } } - resource = jabber_buddy_find_resource(buddy, NULL); - if(!resource) - return; /* huh? */ status_id = jabber_buddy_state_get_status_id(resource->state); - purple_prpl_got_user_status(js->gc->account, from, status_id, PURPLE_TUNE_ARTIST, tuneinfodata.artist, PURPLE_TUNE_TITLE, tuneinfodata.title, PURPLE_TUNE_ALBUM, tuneinfodata.album, PURPLE_TUNE_TRACK, tuneinfodata.track, PURPLE_TUNE_TIME, tuneinfodata.time, PURPLE_TUNE_URL, tuneinfodata.url, NULL); + purple_prpl_got_user_status(js->gc->account, from, status_id, + PURPLE_TUNE_ARTIST, tuneinfodata.artist, + PURPLE_TUNE_TITLE, tuneinfodata.title, + PURPLE_TUNE_ALBUM, tuneinfodata.album, + PURPLE_TUNE_TRACK, tuneinfodata.track, + PURPLE_TUNE_TIME, tuneinfodata.time, + PURPLE_TUNE_URL, tuneinfodata.url, NULL); + + g_free(tuneinfodata.artist); + g_free(tuneinfodata.title); + g_free(tuneinfodata.album); + g_free(tuneinfodata.track); + g_free(tuneinfodata.url); } void jabber_tune_init(void) {
--- a/libpurple/protocols/msn/Makefile.am Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/command.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 2007 +0000 @@ -0,0 +1,1893 @@ +/** + * @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"); + + purple_debug_info("MSNCL","Member type: %s\n", member_type ? member_type : "(null)"); + + if (!member_type) + 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")) { + } + 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); + } + } + } + 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 = NULL; + gchar * update_str; + 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); + } else { + update_str = g_strdup(""); + } + + body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_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, *group_name; + + groupId = xmlnode_get_child(group,"groupId"); + group_id = xmlnode_get_data(groupId); + groupInfo = xmlnode_get_child(group,"groupInfo"); + groupname = xmlnode_get_child(groupInfo,"name"); + group_name = xmlnode_get_data(groupname); + + 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); + 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); + + purple_debug_misc("MsnAB","parse guid...\n"); + 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 { + /*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->child->name,node->lastchild->name); + + 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 = NULL, *escaped_nickname; + + 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/dialog.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/directconn.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/directconn.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/group.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/group.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/history.c Fri Sep 28 16:34:43 2007 +0000 @@ -84,3 +84,4 @@ msn_transaction_destroy(trans); } } +
--- a/libpurple/protocols/msn/msg.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/msg.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/msg.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 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 Fri Sep 28 16:32:28 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/msn.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Fri Sep 28 16:34:43 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 **************************************************************************/ @@ -102,9 +111,11 @@ account = session->account; /* Allocate an array for CVR0, NULL, and all the versions */ - a = c = g_new0(char *, session->protocol_ver - 8 + 3); +// a = c = g_new0(char *, session->protocol_ver - WLM_MIN_PROTOCOL + 3); + a = c = g_new0(char *, WLM_MAX_PROTOCOL - WLM_MIN_PROTOCOL + 3); - for (i = session->protocol_ver; i >= 8; i--) +// for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) + for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) *c++ = g_strdup_printf("MSNP%d", i); *c++ = g_strdup("CVR0"); @@ -112,9 +123,13 @@ vers = g_strjoinv(" ", a); 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); @@ -153,7 +168,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,9 +187,7 @@ 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); } @@ -214,7 +227,6 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", purple_account_get_username(account)); } @@ -232,14 +244,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 +264,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 +342,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 +393,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 +406,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 +421,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 +567,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 +584,301 @@ /************************************************************************** * 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; + char *email,*domain; + char *list_op_str,*type_str; + + purple_debug_info("MSNP14","Passport: %s, type: %d\n", passport, type); + tokens = g_strsplit(passport, "@", 2); + email = tokens[0]; + domain = tokens[1]; + + /*find a domain Node*/ + for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node)) + { + const char * attr = NULL; + purple_debug_info("MSNP14","d_node: %s\n",d_node->name); + attr = xmlnode_get_attrib(d_node,"n"); + if(attr == NULL){ + continue; + } + if(!strcmp(attr,domain)){ + break; + } + } + if(d_node == NULL) + { + /*domain not found, create a new domain Node*/ + purple_debug_info("MSNP14","get No d_node\n"); + 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); + + list_op_str = g_strdup_printf("%d",list_op); + purple_debug_info("MSNP14","list_op: %d\n",list_op); + xmlnode_set_attrib(c_node,"l",list_op_str); + g_free(list_op_str); + + if (type != MSN_USER_TYPE_UNKNOWN) { + type_str = g_strdup_printf("%d", type); + } else { + if (msn_user_is_yahoo(session->account, passport)) + type_str = g_strdup_printf("%d", MSN_USER_TYPE_YAHOO); + else + type_str = g_strdup_printf("%d", MSN_USER_TYPE_PASSPORT); + } + /*mobile*/ + //type_str = g_strdup_printf("4"); + xmlnode_set_attrib(c_node,"t",type_str); + g_free(type_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 +973,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 +1046,7 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; + int wlmclient; const char *state, *passport, *friendly; session = cmdproc->session; @@ -650,7 +1055,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 +1065,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 +1099,7 @@ MsnUser *user; MsnObject *msnobj; int clientid; + int wlmclient; const char *state, *passport, *friendly, *old_friendly; session = cmdproc->session; @@ -700,7 +1108,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 +1122,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 +1133,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 +1205,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 +1231,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 +1250,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 +1262,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 +1293,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 +1317,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 +1360,7 @@ session->sync = sync; cmdproc->cbs_table = sync->cbs_table; } +#endif /************************************************************************** * Misc commands @@ -1146,6 +1569,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 +1675,7 @@ { MsnSession *session; const char *value; + const char *clLastChange; session = cmdproc->session; @@ -1187,10 +1708,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 +1784,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 +1965,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 +2031,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 +2051,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 +2069,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 +2086,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 +2114,4 @@ { msn_table_destroy(cbs_table); } +
--- a/libpurple/protocols/msn/notification.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/notification.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/session.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/session.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/slpcall.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/state.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/state.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Fri Sep 28 16:34:43 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; @@ -1095,6 +1106,8 @@ cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { int reason = MSN_SB_ERROR_UNKNOWN; + MsnMessage *msg; + MsnSwitchBoard *swboard = trans->data; if (error == 215) { @@ -1107,7 +1120,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); } @@ -1151,6 +1176,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); @@ -1263,6 +1289,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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/sync.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/user.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/user.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Fri Sep 28 16:34:43 2007 +0000 @@ -43,8 +43,15 @@ MsnPermitAdd *pa = data; MsnSession *session = pa->gc->proto_data; MsnUserList *userlist = session->userlist; + MsnUser *user = msn_userlist_find_add_user(userlist, pa->who, pa->who); + + purple_debug_misc("MSN Userlist", "Accepted the new buddy: %s\n", pa->who); - msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_AL, NULL); + 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 +62,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", "Deniedthe new buddy: %s\n", pa->who); - msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL); + if (g_list_find(purple_connections_get_all(), pa->gc) != NULL) + { + 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); @@ -78,49 +95,45 @@ 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); + } /************************************************************************** * 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 +161,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 +182,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 +205,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 +254,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 +264,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 +276,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 +324,6 @@ { purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n", passport); - } } @@ -351,14 +341,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 +385,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 +422,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 +444,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 +483,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 +531,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 +561,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 +578,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 +595,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 +607,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 +621,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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/msn/userlist.h Fri Sep 28 16:34:43 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/markup.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/markup.c Fri Sep 28 16:34:43 2007 +0000 @@ -426,13 +426,14 @@ 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. */ - if (!purple_utf8_strcasecmp(root->name, "root")) { - *begin = g_strdup(""); - *end = g_strdup(""); } else if (!purple_utf8_strcasecmp(root->name, "b")) { *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD); *end = g_strdup("</f>"); @@ -503,8 +504,21 @@ /* 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); } }
--- a/libpurple/protocols/myspace/markup.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/markup.h Fri Sep 28 16:34:43 2007 +0000 @@ -1,27 +1,27 @@ -/* 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 - */ - -#ifndef _MYSPACE_MARKUP_H -#define _MYSPACE_MARKUP_H - -/* High-level msim markup <=> Purple html conversion functions. */ -gchar *msim_markup_to_html(MsimSession *, const gchar *raw); -gchar *html_to_msim_markup(MsimSession *, const gchar *raw); - -#endif /* !_MYSPACE_MARKUP_H */ +/* 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 + */ + +#ifndef _MYSPACE_MARKUP_H +#define _MYSPACE_MARKUP_H + +/* High-level msim markup <=> Purple html conversion functions. */ +gchar *msim_markup_to_html(MsimSession *, const gchar *raw); +gchar *html_to_msim_markup(MsimSession *, const gchar *raw); + +#endif /* !_MYSPACE_MARKUP_H */
--- a/libpurple/protocols/myspace/myspace.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.c Fri Sep 28 16:34:43 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 @@ -458,6 +459,7 @@ purple_cipher_context_append(key_context, hash_pw, HASH_SIZE); purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE); purple_cipher_context_digest(key_context, sizeof(key), key, NULL); + purple_cipher_context_destroy(key_context); #ifdef MSIM_DEBUG_LOGIN_CHALLENGE purple_debug_info("msim", "key = "); @@ -1039,7 +1041,7 @@ PurpleStatusType *type; MsimSession *session; guint status_code; - const gchar *statstring; + gchar *statstring; session = (MsimSession *)account->gc->proto_data; @@ -1073,7 +1075,7 @@ break; } - statstring = purple_status_get_attr_string(status, "message"); + statstring = (gchar *)purple_status_get_attr_string(status, "message"); if (!statstring) { statstring = ""; @@ -1082,7 +1084,7 @@ /* Status strings are plain text. */ statstring = purple_markup_strip_html(statstring); - msim_set_status_code(session, status_code, g_strdup(statstring)); + msim_set_status_code(session, status_code, statstring); } /** Go idle. */ @@ -1213,7 +1215,7 @@ if (uid == wanted_uid) { ret = g_strdup(name); - break; + break; } } @@ -1790,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 { @@ -1867,6 +1871,7 @@ purple_blist_add_buddy(buddy, NULL, NULL, NULL); user = msim_get_user_from_buddy(buddy); + /* TODO: free user. memory leak? */ /* All buddies on list should have 'uid' integer associated with them. */ purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f")); @@ -2863,7 +2868,7 @@ } /** Callbacks called by Purple, to access this plugin. */ -PurplePluginProtocolInfo prpl_info = { +static PurplePluginProtocolInfo prpl_info = { /* options */ OPT_PROTO_USE_POINTSIZE /* specify font size in sane point size */ | OPT_PROTO_MAIL_CHECK,
--- a/libpurple/protocols/myspace/myspace.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/myspace.h Fri Sep 28 16:34:43 2007 +0000 @@ -67,6 +67,10 @@ /*#define MSIM_DEBUG_LOGIN_CHALLENGE*/ /*#define MSIM_DEBUG_RXBUF */ +/* Encode unknown HTML tags from IM clients in messages as [tag], instead of + * ignoring. Useful for debugging */ +/*#define MSIM_MARKUP_SHOW_UNKNOWN_TAGS */ + /* Define to cause init_plugin() to run some tests and print * the results to the Purple debug log, then exit. Useful to * run with 'pidgin -d' to see the output. Don't define if
--- a/libpurple/protocols/myspace/session.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/session.c Fri Sep 28 16:34:43 2007 +0000 @@ -1,95 +1,95 @@ -/* MySpaceIM Protocol Plugin, session - * - * 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" - -/* Session methods */ - -/** - * Create a new MSIM session. - * - * @param acct The account to create the session from. - * - * @return Pointer to a new session. Free with msim_session_destroy. - */ -MsimSession * -msim_session_new(PurpleAccount *acct) -{ - MsimSession *session; - - g_return_val_if_fail(acct != NULL, NULL); - - session = g_new0(MsimSession, 1); - - session->magic = MSIM_SESSION_STRUCT_MAGIC; - session->account = acct; - session->gc = purple_account_get_connection(acct); - session->sesskey = 0; - session->userid = 0; - session->username = NULL; - session->fd = -1; - - /* TODO: Remove. */ - session->user_lookup_cb = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */ - session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash, - g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are, - they could be integers inside gpointers - or strings, so I don't freed them. - Figure this out, once free cache. */ - - /* Created in msim_process_server_info() */ - session->server_info = NULL; - - session->rxoff = 0; - session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE); - session->next_rid = 1; - session->last_comm = time(NULL); - session->inbox_status = 0; - - return session; -} - -/** - * Free a session. - * - * @param session The session to destroy. - */ -void -msim_session_destroy(MsimSession *session) -{ - g_return_if_fail(MSIM_SESSION_VALID(session)); - - session->magic = -1; - - g_free(session->rxbuf); - g_free(session->username); - - /* TODO: Remove. */ - g_hash_table_destroy(session->user_lookup_cb); - g_hash_table_destroy(session->user_lookup_cb_data); - - if (session->server_info) { - msim_msg_free(session->server_info); - } - - g_free(session); -} - +/* MySpaceIM Protocol Plugin, session + * + * 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" + +/* Session methods */ + +/** + * Create a new MSIM session. + * + * @param acct The account to create the session from. + * + * @return Pointer to a new session. Free with msim_session_destroy. + */ +MsimSession * +msim_session_new(PurpleAccount *acct) +{ + MsimSession *session; + + g_return_val_if_fail(acct != NULL, NULL); + + session = g_new0(MsimSession, 1); + + session->magic = MSIM_SESSION_STRUCT_MAGIC; + session->account = acct; + session->gc = purple_account_get_connection(acct); + session->sesskey = 0; + session->userid = 0; + session->username = NULL; + session->fd = -1; + + /* TODO: Remove. */ + session->user_lookup_cb = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */ + session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are, + they could be integers inside gpointers + or strings, so I don't freed them. + Figure this out, once free cache. */ + + /* Created in msim_process_server_info() */ + session->server_info = NULL; + + session->rxoff = 0; + session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE); + session->next_rid = 1; + session->last_comm = time(NULL); + session->inbox_status = 0; + + return session; +} + +/** + * Free a session. + * + * @param session The session to destroy. + */ +void +msim_session_destroy(MsimSession *session) +{ + g_return_if_fail(MSIM_SESSION_VALID(session)); + + session->magic = -1; + + g_free(session->rxbuf); + g_free(session->username); + + /* TODO: Remove. */ + g_hash_table_destroy(session->user_lookup_cb); + g_hash_table_destroy(session->user_lookup_cb_data); + + if (session->server_info) { + msim_msg_free(session->server_info); + } + + g_free(session); +} +
--- a/libpurple/protocols/myspace/session.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/session.h Fri Sep 28 16:34:43 2007 +0000 @@ -1,57 +1,57 @@ -/* MySpaceIM Protocol Plugin, session - * - * 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 - */ - -#ifndef _MYSPACE_SESSION_H -#define _MYSPACE_SESSION_H - -/* Random number in every MsimSession, to ensure it is valid. */ -#define MSIM_SESSION_STRUCT_MAGIC 0xe4a6752b - -/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */ -typedef struct _MsimSession -{ - guint magic; /**< MSIM_SESSION_STRUCT_MAGIC */ - PurpleAccount *account; - PurpleConnection *gc; - guint sesskey; /**< Session key from server */ - guint userid; /**< This user's numeric user ID */ - gchar *username; /**< This user's unique username */ - gint fd; /**< File descriptor to/from server */ - - /* TODO: Remove. */ - GHashTable *user_lookup_cb; /**< Username -> userid lookup callback */ - GHashTable *user_lookup_cb_data; /**< Username -> userid lookup callback data */ - - MsimMessage *server_info; /**< Parameters from server */ - - gchar *rxbuf; /**< Receive buffer */ - guint rxoff; /**< Receive buffer offset */ - guint next_rid; /**< Next request/response ID */ - time_t last_comm; /**< Time received last communication */ - guint inbox_status; /**< Bit field of inbox notifications */ -} MsimSession; - -/* Check if an MsimSession is valid */ -#define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC) - - -MsimSession *msim_session_new(PurpleAccount *acct); -void msim_session_destroy(MsimSession *session); - -#endif /* !_MYSPACE_SESSION_H */ +/* MySpaceIM Protocol Plugin, session + * + * 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 + */ + +#ifndef _MYSPACE_SESSION_H +#define _MYSPACE_SESSION_H + +/* Random number in every MsimSession, to ensure it is valid. */ +#define MSIM_SESSION_STRUCT_MAGIC 0xe4a6752b + +/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */ +typedef struct _MsimSession +{ + guint magic; /**< MSIM_SESSION_STRUCT_MAGIC */ + PurpleAccount *account; + PurpleConnection *gc; + guint sesskey; /**< Session key from server */ + guint userid; /**< This user's numeric user ID */ + gchar *username; /**< This user's unique username */ + gint fd; /**< File descriptor to/from server */ + + /* TODO: Remove. */ + GHashTable *user_lookup_cb; /**< Username -> userid lookup callback */ + GHashTable *user_lookup_cb_data; /**< Username -> userid lookup callback data */ + + MsimMessage *server_info; /**< Parameters from server */ + + gchar *rxbuf; /**< Receive buffer */ + guint rxoff; /**< Receive buffer offset */ + guint next_rid; /**< Next request/response ID */ + time_t last_comm; /**< Time received last communication */ + guint inbox_status; /**< Bit field of inbox notifications */ +} MsimSession; + +/* Check if an MsimSession is valid */ +#define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC) + + +MsimSession *msim_session_new(PurpleAccount *acct); +void msim_session_destroy(MsimSession *session); + +#endif /* !_MYSPACE_SESSION_H */
--- a/libpurple/protocols/myspace/user.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/user.c Fri Sep 28 16:34:43 2007 +0000 @@ -1,437 +1,454 @@ -/* MySpaceIM Protocol Plugin, header file - * - * 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" - -static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user); -static gchar *msim_format_now_playing(gchar *band, gchar *song); -static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, - gsize len, const gchar *error_message); - -/** Format the "now playing" indicator, showing the artist and song. - * @return Return a new string (must be g_free()'d), or NULL. - */ -static gchar * -msim_format_now_playing(gchar *band, gchar *song) -{ - if ((band && strlen(band)) || (song && strlen(song))) { - return g_strdup_printf("%s - %s", - (band && strlen(band)) ? band : "Unknown Artist", - (song && strlen(song)) ? song : "Unknown Song"); - } else { - return NULL; - } -} -/** Get the MsimUser from a PurpleBuddy, creating it if needed. */ -MsimUser * -msim_get_user_from_buddy(PurpleBuddy *buddy) -{ - MsimUser *user; - - if (!buddy) { - return NULL; - } - - if (!buddy->proto_data) { - /* No MsimUser for this buddy; make one. */ - - /* TODO: where is this freed? */ - user = g_new0(MsimUser, 1); - user->buddy = buddy; - buddy->proto_data = (gpointer)user; - } - - user = (MsimUser *)(buddy->proto_data); - - return user; -} - -/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */ -MsimUser * -msim_find_user(MsimSession *session, const gchar *username) -{ - PurpleBuddy *buddy; - MsimUser *user; - - buddy = purple_find_buddy(session->account, username); - if (!buddy) { - return NULL; - } - - user = msim_get_user_from_buddy(buddy); - - return user; -} - -/** Append user information to a PurpleNotifyUserInfo, given an MsimUser. - * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile. - */ -void -msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full) -{ - gchar *str; - guint uid; - guint cv; - - /* Useful to identify the account the tooltip refers to. - * Other prpls show this. */ - if (user->username) { - purple_notify_user_info_add_pair(user_info, _("User"), user->username); - } - - uid = purple_blist_node_get_int(&user->buddy->node, "UserID"); - - if (full) { - /* TODO: link to username, if available */ - purple_notify_user_info_add_pair(user_info, _("Profile"), - g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>", - uid, uid)); - } - - - /* a/s/l...the vitals */ - if (user->age) { - purple_notify_user_info_add_pair(user_info, _("Age"), - g_strdup_printf("%d", user->age)); - } - - if (user->gender && strlen(user->gender)) { - purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender); - } - - if (user->location && strlen(user->location)) { - purple_notify_user_info_add_pair(user_info, _("Location"), user->location); - } - - /* Other information */ - if (user->headline && strlen(user->headline)) { - purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline); - } - - str = msim_format_now_playing(user->band_name, user->song_name); - if (str && strlen(str)) { - purple_notify_user_info_add_pair(user_info, _("Song"), str); - } - - /* Note: total friends only available if looked up by uid, not username. */ - if (user->total_friends) { - purple_notify_user_info_add_pair(user_info, _("Total Friends"), - g_strdup_printf("%d", user->total_friends)); - } - - if (full) { - /* Client information */ - - str = user->client_info; - cv = user->client_cv; - - if (str && cv != 0) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup_printf("%s (build %d)", str, cv)); - } else if (str) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup(str)); - } else if (cv) { - purple_notify_user_info_add_pair(user_info, _("Client Version"), - g_strdup_printf("Build %d", cv)); - } - } -} - -/** Store a field of information about a buddy. */ -void -msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user) -{ - if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) { - /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */ - if (user->buddy) - { - purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name); - purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str)); - } - /* Need to store in MsimUser, too? What if not on blist? */ - } else if (g_str_equal(key_str, "Age")) { - user->age = atol(value_str); - } else if (g_str_equal(key_str, "Gender")) { - user->gender = g_strdup(value_str); - } else if (g_str_equal(key_str, "Location")) { - user->location = g_strdup(value_str); - } else if (g_str_equal(key_str, "TotalFriends")) { - user->total_friends = atol(value_str); - } else if (g_str_equal(key_str, "DisplayName")) { - user->display_name = g_strdup(value_str); - } else if (g_str_equal(key_str, "BandName")) { - user->band_name = g_strdup(value_str); - } else if (g_str_equal(key_str, "SongName")) { - user->song_name = g_strdup(value_str); - } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) { - /* Ignore because PurpleBuddy knows this already */ - ; - } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) { - const gchar *previous_url; - - user->image_url = g_strdup(value_str); - - /* Instead of showing 'no photo' picture, show nothing. */ - if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif")) - { - purple_buddy_icons_set_for_user(user->buddy->account, - user->buddy->name, - NULL, 0, NULL); - return; - } - - /* TODO: use ETag for checksum */ - previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy); - - /* Only download if URL changed */ - if (!previous_url || !g_str_equal(previous_url, user->image_url)) { - purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user); - } - } else if (g_str_equal(key_str, "LastImageUpdated")) { - /* TODO: use somewhere */ - user->last_image_updated = atol(value_str); - } else if (g_str_equal(key_str, "Headline")) { - user->headline = g_strdup(value_str); - } else { - /* TODO: other fields in MsimUser */ - gchar *msg; - - msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s", - key_str, value_str); - - msim_unrecognized(NULL, NULL, msg); - - g_free(msg); - } -} - -/** Save buddy information to the buddy list from a user info reply message. - * - * @param session - * @param msg The user information reply, with any amount of information. - * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data. - * - * Variable information is saved to the passed MsimUser structure. Permanent - * information (UserID) is stored in the blist node of the buddy list (and - * ends up in blist.xml, persisted to disk) if it exists. - * - * If the function has no buddy information, this function - * is a no-op (and returns FALSE). - * - */ -gboolean -msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user) -{ - gchar *username; - MsimMessage *body, *body_node; - - g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); - g_return_val_if_fail(msg != NULL, FALSE); - - body = msim_msg_get_dictionary(msg, "body"); - if (!body) { - return FALSE; - } - - username = msim_msg_get_string(body, "UserName"); - - if (!username) { - purple_debug_info("msim", - "msim_process_reply: not caching body, no UserName\n"); - msim_msg_free(body); - g_free(username); - return FALSE; - } - - /* Null user = find and store in PurpleBuddy's proto_data */ - if (!user) { - user = msim_find_user(session, username); - if (!user) { - msim_msg_free(body); - g_free(username); - return FALSE; - } - } - - /* TODO: make looping over MsimMessage's easier. */ - for (body_node = body; - body_node != NULL; - body_node = msim_msg_get_next_element_node(body_node)) - { - const gchar *key_str; - gchar *value_str; - MsimMessageElement *elem; - - elem = (MsimMessageElement *)body_node->data; - key_str = elem->name; - - value_str = msim_msg_get_string_from_element(elem); - msim_store_user_info_each(key_str, value_str, user); - g_free(value_str); - } - - if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN && - msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) { - /* TODO: do something with our own IM info, if we need it for some - * specific purpose. Otherwise it is available on the buddy list, - * if the user has themselves as their own buddy. - * - * However, much of the info is already available in MsimSession, - * stored in msim_we_are_logged_on(). */ - } else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN && - msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) { - /* TODO: same as above, but for MySpace info. */ - } - - msim_msg_free(body); - - return TRUE; -} - -/** - * Asynchronously lookup user information, calling callback when receive result. - * - * @param session - * @param user The user id, email address, or username. Not freed. - * @param cb Callback, called with user information when available. - * @param data An arbitray data pointer passed to the callback. - */ -/* TODO: change to not use callbacks */ -void -msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data) -{ - MsimMessage *body; - gchar *field_name; - guint rid, cmd, dsn, lid; - - g_return_if_fail(MSIM_SESSION_VALID(session)); - g_return_if_fail(user != NULL); - /* Callback can be null to not call anything, just lookup & store information. */ - /*g_return_if_fail(cb != NULL);*/ - - purple_debug_info("msim", "msim_lookup_userid: " - "asynchronously looking up <%s>\n", user); - - msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data); - - /* Setup callback. Response will be associated with request using 'rid'. */ - rid = msim_new_reply_callback(session, cb, data); - - /* Send request */ - - cmd = MSIM_CMD_GET; - - if (msim_is_userid(user)) { - field_name = "UserID"; - dsn = MG_MYSPACE_INFO_BY_ID_DSN; - lid = MG_MYSPACE_INFO_BY_ID_LID; - } else if (msim_is_email(user)) { - field_name = "Email"; - dsn = MG_MYSPACE_INFO_BY_STRING_DSN; - lid = MG_MYSPACE_INFO_BY_STRING_LID; - } else { - field_name = "UserName"; - dsn = MG_MYSPACE_INFO_BY_STRING_DSN; - lid = MG_MYSPACE_INFO_BY_STRING_LID; - } - - body = msim_msg_new( - field_name, MSIM_TYPE_STRING, g_strdup(user), - NULL); - - g_return_if_fail(msim_send(session, - "persist", MSIM_TYPE_INTEGER, 1, - "sesskey", MSIM_TYPE_INTEGER, session->sesskey, - "cmd", MSIM_TYPE_INTEGER, 1, - "dsn", MSIM_TYPE_INTEGER, dsn, - "uid", MSIM_TYPE_INTEGER, session->userid, - "lid", MSIM_TYPE_INTEGER, lid, - "rid", MSIM_TYPE_INTEGER, rid, - "body", MSIM_TYPE_DICTIONARY, body, - NULL)); -} - - -/** - * Check if a string is a userid (all numeric). - * - * @param user The user id, email, or name. - * - * @return TRUE if is userid, FALSE if not. - */ -gboolean -msim_is_userid(const gchar *user) -{ - g_return_val_if_fail(user != NULL, FALSE); - - return strspn(user, "0123456789") == strlen(user); -} - -/** - * Check if a string is an email address (contains an @). - * - * @param user The user id, email, or name. - * - * @return TRUE if is an email, FALSE if not. - * - * This function is not intended to be used as a generic - * means of validating email addresses, but to distinguish - * between a user represented by an email address from - * other forms of identification. - */ -gboolean -msim_is_email(const gchar *user) -{ - g_return_val_if_fail(user != NULL, FALSE); - - return strchr(user, '@') != NULL; -} - - -/** Callback for when a buddy icon finished being downloaded. */ -static void -msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, - gpointer user_data, - const gchar *url_text, - gsize len, - const gchar *error_message) -{ - MsimUser *user; - - user = (MsimUser *)user_data; - - purple_debug_info("msim_downloaded_buddy_icon", - "Downloaded %d bytes\n", len); - - if (!url_text) { - purple_debug_info("msim_downloaded_buddy_icon", - "failed to download icon for %s", - user->buddy->name); - return; - } - - purple_buddy_icons_set_for_user(user->buddy->account, - user->buddy->name, - g_memdup((gchar *)url_text, len), len, - /* Use URL itself as buddy icon "checksum" (TODO: ETag) */ - user->image_url); /* checksum */ -} - - +/* MySpaceIM Protocol Plugin, header file + * + * 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" + +static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user); +static gchar *msim_format_now_playing(gchar *band, gchar *song); +static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, + gsize len, const gchar *error_message); + +/** Format the "now playing" indicator, showing the artist and song. + * @return Return a new string (must be g_free()'d), or NULL. + */ +static gchar * +msim_format_now_playing(gchar *band, gchar *song) +{ + if ((band && strlen(band)) || (song && strlen(song))) { + return g_strdup_printf("%s - %s", + (band && strlen(band)) ? band : "Unknown Artist", + (song && strlen(song)) ? song : "Unknown Song"); + } else { + return NULL; + } +} +/** Get the MsimUser from a PurpleBuddy, creating it if needed. */ +MsimUser * +msim_get_user_from_buddy(PurpleBuddy *buddy) +{ + MsimUser *user; + + if (!buddy) { + return NULL; + } + + if (!buddy->proto_data) { + /* No MsimUser for this buddy; make one. */ + + /* TODO: where is this freed? */ + user = g_new0(MsimUser, 1); + user->buddy = buddy; + buddy->proto_data = (gpointer)user; + } + + user = (MsimUser *)(buddy->proto_data); + + return user; +} + +/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */ +MsimUser * +msim_find_user(MsimSession *session, const gchar *username) +{ + PurpleBuddy *buddy; + MsimUser *user; + + buddy = purple_find_buddy(session->account, username); + if (!buddy) { + return NULL; + } + + user = msim_get_user_from_buddy(buddy); + + return user; +} + +/** Append user information to a PurpleNotifyUserInfo, given an MsimUser. + * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile. + */ +void +msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full) +{ + gchar *str; + guint uid; + guint cv; + + /* Useful to identify the account the tooltip refers to. + * Other prpls show this. */ + if (user->username) { + purple_notify_user_info_add_pair(user_info, _("User"), user->username); + } + + uid = purple_blist_node_get_int(&user->buddy->node, "UserID"); + + if (full) { + /* TODO: link to username, if available */ + purple_notify_user_info_add_pair(user_info, _("Profile"), + g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>", + uid, uid)); + } + + + /* a/s/l...the vitals */ + if (user->age) { + purple_notify_user_info_add_pair(user_info, _("Age"), + g_strdup_printf("%d", user->age)); + } + + if (user->gender && strlen(user->gender)) { + purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender); + } + + if (user->location && strlen(user->location)) { + purple_notify_user_info_add_pair(user_info, _("Location"), user->location); + } + + /* Other information */ + if (user->headline && strlen(user->headline)) { + purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline); + } + + str = msim_format_now_playing(user->band_name, user->song_name); + if (str && strlen(str)) { + purple_notify_user_info_add_pair(user_info, _("Song"), str); + } + + /* Note: total friends only available if looked up by uid, not username. */ + if (user->total_friends) { + purple_notify_user_info_add_pair(user_info, _("Total Friends"), + g_strdup_printf("%d", user->total_friends)); + } + + if (full) { + /* Client information */ + + str = user->client_info; + cv = user->client_cv; + + if (str && cv != 0) { + purple_notify_user_info_add_pair(user_info, _("Client Version"), + g_strdup_printf("%s (build %d)", str, cv)); + } else if (str) { + purple_notify_user_info_add_pair(user_info, _("Client Version"), + g_strdup(str)); + } else if (cv) { + purple_notify_user_info_add_pair(user_info, _("Client Version"), + g_strdup_printf("Build %d", cv)); + } + } +} + +/** Store a field of information about a buddy. + * + * @param key_str Key to store. + * @param value_str Value string, either user takes ownership of this string + * or it is freed if MsimUser doesn't store the string. + * @param user User to store data in. Existing data will be replaced. + * */ +void +msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user) +{ + if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) { + /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */ + if (user->buddy) + { + purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name); + purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str)); + } + /* Need to store in MsimUser, too? What if not on blist? */ + } else if (g_str_equal(key_str, "Age")) { + user->age = atol(value_str); + g_free(value_str); + } else if (g_str_equal(key_str, "Gender")) { + g_free(user->gender); + user->gender = value_str; + } else if (g_str_equal(key_str, "Location")) { + g_free(user->location); + user->location = value_str; + } else if (g_str_equal(key_str, "TotalFriends")) { + user->total_friends = atol(value_str); + } else if (g_str_equal(key_str, "DisplayName")) { + g_free(user->display_name); + user->display_name = value_str; + } else if (g_str_equal(key_str, "BandName")) { + g_free(user->band_name); + user->band_name = value_str; + } else if (g_str_equal(key_str, "SongName")) { + g_free(user->song_name); + user->song_name = value_str; + } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) { + /* Ignore because PurpleBuddy knows this already */ + g_free(value_str); + } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) { + const gchar *previous_url; + + g_free(user->image_url); + + user->image_url = value_str; + + /* Instead of showing 'no photo' picture, show nothing. */ + if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif")) + { + purple_buddy_icons_set_for_user(user->buddy->account, + user->buddy->name, + NULL, 0, NULL); + return; + } + + /* TODO: use ETag for checksum */ + previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy); + + /* Only download if URL changed */ + if (!previous_url || !g_str_equal(previous_url, user->image_url)) { + purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user); + } + } else if (g_str_equal(key_str, "LastImageUpdated")) { + /* TODO: use somewhere */ + user->last_image_updated = atol(value_str); + g_free(value_str); + } else if (g_str_equal(key_str, "Headline")) { + g_free(user->headline); + user->headline = value_str; + } else { + /* TODO: other fields in MsimUser */ + gchar *msg; + + msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s", + key_str, value_str); + g_free(value_str); + + msim_unrecognized(NULL, NULL, msg); + + g_free(msg); + } +} + +/** Save buddy information to the buddy list from a user info reply message. + * + * @param session + * @param msg The user information reply, with any amount of information. + * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data. + * + * Variable information is saved to the passed MsimUser structure. Permanent + * information (UserID) is stored in the blist node of the buddy list (and + * ends up in blist.xml, persisted to disk) if it exists. + * + * If the function has no buddy information, this function + * is a no-op (and returns FALSE). + * + */ +gboolean +msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user) +{ + gchar *username; + MsimMessage *body, *body_node; + + g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); + g_return_val_if_fail(msg != NULL, FALSE); + + body = msim_msg_get_dictionary(msg, "body"); + if (!body) { + return FALSE; + } + + username = msim_msg_get_string(body, "UserName"); + + if (!username) { + purple_debug_info("msim", + "msim_process_reply: not caching body, no UserName\n"); + msim_msg_free(body); + g_free(username); + return FALSE; + } + + /* Null user = find and store in PurpleBuddy's proto_data */ + if (!user) { + user = msim_find_user(session, username); + if (!user) { + msim_msg_free(body); + g_free(username); + return FALSE; + } + } + + /* TODO: make looping over MsimMessage's easier. */ + for (body_node = body; + body_node != NULL; + body_node = msim_msg_get_next_element_node(body_node)) + { + const gchar *key_str; + gchar *value_str; + MsimMessageElement *elem; + + elem = (MsimMessageElement *)body_node->data; + key_str = elem->name; + + value_str = msim_msg_get_string_from_element(elem); + msim_store_user_info_each(key_str, value_str, user); + } + + if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN && + msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) { + /* TODO: do something with our own IM info, if we need it for some + * specific purpose. Otherwise it is available on the buddy list, + * if the user has themselves as their own buddy. + * + * However, much of the info is already available in MsimSession, + * stored in msim_we_are_logged_on(). */ + } else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN && + msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) { + /* TODO: same as above, but for MySpace info. */ + } + + msim_msg_free(body); + g_free(username); + + return TRUE; +} + +/** + * Asynchronously lookup user information, calling callback when receive result. + * + * @param session + * @param user The user id, email address, or username. Not freed. + * @param cb Callback, called with user information when available. + * @param data An arbitray data pointer passed to the callback. + */ +/* TODO: change to not use callbacks */ +void +msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data) +{ + MsimMessage *body; + gchar *field_name; + guint rid, cmd, dsn, lid; + + g_return_if_fail(MSIM_SESSION_VALID(session)); + g_return_if_fail(user != NULL); + /* Callback can be null to not call anything, just lookup & store information. */ + /*g_return_if_fail(cb != NULL);*/ + + purple_debug_info("msim", "msim_lookup_userid: " + "asynchronously looking up <%s>\n", user); + + msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data); + + /* Setup callback. Response will be associated with request using 'rid'. */ + rid = msim_new_reply_callback(session, cb, data); + + /* Send request */ + + cmd = MSIM_CMD_GET; + + if (msim_is_userid(user)) { + field_name = "UserID"; + dsn = MG_MYSPACE_INFO_BY_ID_DSN; + lid = MG_MYSPACE_INFO_BY_ID_LID; + } else if (msim_is_email(user)) { + field_name = "Email"; + dsn = MG_MYSPACE_INFO_BY_STRING_DSN; + lid = MG_MYSPACE_INFO_BY_STRING_LID; + } else { + field_name = "UserName"; + dsn = MG_MYSPACE_INFO_BY_STRING_DSN; + lid = MG_MYSPACE_INFO_BY_STRING_LID; + } + + body = msim_msg_new( + field_name, MSIM_TYPE_STRING, g_strdup(user), + NULL); + + g_return_if_fail(msim_send(session, + "persist", MSIM_TYPE_INTEGER, 1, + "sesskey", MSIM_TYPE_INTEGER, session->sesskey, + "cmd", MSIM_TYPE_INTEGER, 1, + "dsn", MSIM_TYPE_INTEGER, dsn, + "uid", MSIM_TYPE_INTEGER, session->userid, + "lid", MSIM_TYPE_INTEGER, lid, + "rid", MSIM_TYPE_INTEGER, rid, + "body", MSIM_TYPE_DICTIONARY, body, + NULL)); +} + + +/** + * Check if a string is a userid (all numeric). + * + * @param user The user id, email, or name. + * + * @return TRUE if is userid, FALSE if not. + */ +gboolean +msim_is_userid(const gchar *user) +{ + g_return_val_if_fail(user != NULL, FALSE); + + return strspn(user, "0123456789") == strlen(user); +} + +/** + * Check if a string is an email address (contains an @). + * + * @param user The user id, email, or name. + * + * @return TRUE if is an email, FALSE if not. + * + * This function is not intended to be used as a generic + * means of validating email addresses, but to distinguish + * between a user represented by an email address from + * other forms of identification. + */ +gboolean +msim_is_email(const gchar *user) +{ + g_return_val_if_fail(user != NULL, FALSE); + + return strchr(user, '@') != NULL; +} + + +/** Callback for when a buddy icon finished being downloaded. */ +static void +msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, + gpointer user_data, + const gchar *url_text, + gsize len, + const gchar *error_message) +{ + MsimUser *user; + + user = (MsimUser *)user_data; + + purple_debug_info("msim_downloaded_buddy_icon", + "Downloaded %d bytes\n", len); + + if (!url_text) { + purple_debug_info("msim_downloaded_buddy_icon", + "failed to download icon for %s", + user->buddy->name); + return; + } + + purple_buddy_icons_set_for_user(user->buddy->account, + user->buddy->name, + g_memdup((gchar *)url_text, len), len, + /* Use URL itself as buddy icon "checksum" (TODO: ETag) */ + user->image_url); /* checksum */ +} + +
--- a/libpurple/protocols/myspace/user.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/user.h Fri Sep 28 16:34:43 2007 +0000 @@ -1,55 +1,55 @@ -/* MySpaceIM Protocol Plugin, header file - * - * 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 - */ - -#ifndef _MYSPACE_USER_H -#define _MYSPACE_USER_H - -/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */ -/* GHashTable? */ -typedef struct _MsimUser -{ - PurpleBuddy *buddy; - guint client_cv; - gchar *client_info; - guint age; - gchar *gender; - gchar *location; - guint total_friends; - gchar *headline; - gchar *display_name; - /* Note: uid is in &buddy->node (set_blist_node_int), since it never changes */ - gchar *username; - gchar *band_name, *song_name; - gchar *image_url; - guint last_image_updated; -} MsimUser; - -/* Callback function pointer type for when a user's information is received, - * initiated from a user lookup. */ -typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, MsimMessage *userinfo, gpointer data); - -MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy); -MsimUser *msim_find_user(MsimSession *session, const gchar *username); -void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full); -gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user); -gboolean msim_is_userid(const gchar *user); -gboolean msim_is_email(const gchar *user); -void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data); - -#endif /* !_MYSPACE_USER_H */ +/* MySpaceIM Protocol Plugin, header file + * + * 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 + */ + +#ifndef _MYSPACE_USER_H +#define _MYSPACE_USER_H + +/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */ +/* GHashTable? */ +typedef struct _MsimUser +{ + PurpleBuddy *buddy; + guint client_cv; + gchar *client_info; + guint age; + gchar *gender; + gchar *location; + guint total_friends; + gchar *headline; + gchar *display_name; + /* Note: uid is in &buddy->node (set_blist_node_int), since it never changes */ + gchar *username; + gchar *band_name, *song_name; + gchar *image_url; + guint last_image_updated; +} MsimUser; + +/* Callback function pointer type for when a user's information is received, + * initiated from a user lookup. */ +typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, MsimMessage *userinfo, gpointer data); + +MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy); +MsimUser *msim_find_user(MsimSession *session, const gchar *username); +void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full); +gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user); +gboolean msim_is_userid(const gchar *user); +gboolean msim_is_email(const gchar *user); +void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data); + +#endif /* !_MYSPACE_USER_H */
--- a/libpurple/protocols/myspace/zap.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/zap.c Fri Sep 28 16:34:43 2007 +0000 @@ -1,208 +1,208 @@ -/* MySpaceIM Protocol Plugin - zap support - * - * 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" -#include "zap.h" - -static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code); -static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr); - - -/** Get zap types. */ -GList * -msim_attention_types(PurpleAccount *acct) -{ - static GList *types = NULL; - MsimAttentionType* attn; - - if (!types) { -#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing) \ - attn = g_new0(MsimAttentionType, 1); \ - attn->icon_name = icn; \ - attn->name = nme; \ - attn->incoming_description = incoming; \ - attn->outgoing_description = outgoing; \ - types = g_list_append(types, attn); - - /* TODO: icons for each zap */ - _MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s...")); - _MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s...")); - } - - return types; -} - -/** Send a zap */ -gboolean -msim_send_attention(PurpleConnection *gc, const gchar *username, guint code) -{ - GList *types; - MsimSession *session; - MsimAttentionType *attn; - PurpleBuddy *buddy; - - session = (MsimSession *)gc->proto_data; - - /* Look for this attention type, by the code index given. */ - types = msim_attention_types(gc->account); - attn = (MsimAttentionType *)g_list_nth_data(types, code); - - if (!attn) { - purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code); - return FALSE; - } - - buddy = purple_find_buddy(session->account, username); - if (!buddy) { - return FALSE; - } - - msim_send_zap(session, username, code); - - return TRUE; -} - -/** Send a zap to a user. */ -static gboolean -msim_send_zap(MsimSession *session, const gchar *username, guint code) -{ - gchar *zap_string; - gboolean rc; - - g_return_val_if_fail(session != NULL, FALSE); - g_return_val_if_fail(username != NULL, FALSE); - - /* Construct and send the actual zap command. */ - zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code); - - if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) { - purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s\n", - username, zap_string); - rc = FALSE; - } else { - rc = TRUE; - } - - g_free(zap_string); - - return rc; - -} - -/** Zap someone. Callback from msim_blist_node_menu zap menu. */ -static void -msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr) -{ - PurpleBuddy *buddy; - PurpleAccount *account; - PurpleConnection *gc; - MsimSession *session; - guint zap; - - if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) { - /* Only know about buddies for now. */ - return; - } - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *)node; - - /* Find the session */ - account = buddy->account; - gc = purple_account_get_connection(account); - session = (MsimSession *)gc->proto_data; - - zap = GPOINTER_TO_INT(zap_num_ptr); - - serv_send_attention(session->gc, buddy->name, zap); -} - -/** Return menu, if any, for a buddy list node. */ -GList * -msim_blist_node_menu(PurpleBlistNode *node) -{ - GList *menu, *zap_menu; - GList *types; - PurpleMenuAction *act; - guint i; - - if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) { - /* Only know about buddies for now. */ - return NULL; - } - - zap_menu = NULL; - - /* TODO: get rid of once is accessible directly in GUI */ - types = msim_attention_types(NULL); - i = 0; - do - { - MsimAttentionType *attn; - - attn = (MsimAttentionType *)types->data; - - act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu), - GUINT_TO_POINTER(i), NULL); - zap_menu = g_list_append(zap_menu, act); - - ++i; - } while ((types = g_list_next(types))); - - act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu); - menu = g_list_append(NULL, act); - - return menu; -} - -/** Process an incoming zap. */ -gboolean -msim_incoming_zap(MsimSession *session, MsimMessage *msg) -{ - gchar *msg_text, *username; - gint zap; - - msg_text = msim_msg_get_string(msg, "msg"); - username = msim_msg_get_string(msg, "_username"); - - g_return_val_if_fail(msg_text != NULL, FALSE); - g_return_val_if_fail(username != NULL, FALSE); - - g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE); - - zap = CLAMP(zap, 0, 9); - - serv_got_attention(session->gc, username, zap); - - g_free(msg_text); - g_free(username); - - return TRUE; -} - - +/* MySpaceIM Protocol Plugin - zap support + * + * 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" +#include "zap.h" + +static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code); +static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr); + + +/** Get zap types. */ +GList * +msim_attention_types(PurpleAccount *acct) +{ + static GList *types = NULL; + MsimAttentionType* attn; + + if (!types) { +#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing) \ + attn = g_new0(MsimAttentionType, 1); \ + attn->icon_name = icn; \ + attn->name = nme; \ + attn->incoming_description = incoming; \ + attn->outgoing_description = outgoing; \ + types = g_list_append(types, attn); + + /* TODO: icons for each zap */ + _MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s...")); + _MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s...")); + } + + return types; +} + +/** Send a zap */ +gboolean +msim_send_attention(PurpleConnection *gc, const gchar *username, guint code) +{ + GList *types; + MsimSession *session; + MsimAttentionType *attn; + PurpleBuddy *buddy; + + session = (MsimSession *)gc->proto_data; + + /* Look for this attention type, by the code index given. */ + types = msim_attention_types(gc->account); + attn = (MsimAttentionType *)g_list_nth_data(types, code); + + if (!attn) { + purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code); + return FALSE; + } + + buddy = purple_find_buddy(session->account, username); + if (!buddy) { + return FALSE; + } + + msim_send_zap(session, username, code); + + return TRUE; +} + +/** Send a zap to a user. */ +static gboolean +msim_send_zap(MsimSession *session, const gchar *username, guint code) +{ + gchar *zap_string; + gboolean rc; + + g_return_val_if_fail(session != NULL, FALSE); + g_return_val_if_fail(username != NULL, FALSE); + + /* Construct and send the actual zap command. */ + zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code); + + if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) { + purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s\n", + username, zap_string); + rc = FALSE; + } else { + rc = TRUE; + } + + g_free(zap_string); + + return rc; + +} + +/** Zap someone. Callback from msim_blist_node_menu zap menu. */ +static void +msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr) +{ + PurpleBuddy *buddy; + PurpleAccount *account; + PurpleConnection *gc; + MsimSession *session; + guint zap; + + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) { + /* Only know about buddies for now. */ + return; + } + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *)node; + + /* Find the session */ + account = buddy->account; + gc = purple_account_get_connection(account); + session = (MsimSession *)gc->proto_data; + + zap = GPOINTER_TO_INT(zap_num_ptr); + + serv_send_attention(session->gc, buddy->name, zap); +} + +/** Return menu, if any, for a buddy list node. */ +GList * +msim_blist_node_menu(PurpleBlistNode *node) +{ + GList *menu, *zap_menu; + GList *types; + PurpleMenuAction *act; + guint i; + + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) { + /* Only know about buddies for now. */ + return NULL; + } + + zap_menu = NULL; + + /* TODO: get rid of once is accessible directly in GUI */ + types = msim_attention_types(NULL); + i = 0; + do + { + MsimAttentionType *attn; + + attn = (MsimAttentionType *)types->data; + + act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu), + GUINT_TO_POINTER(i), NULL); + zap_menu = g_list_append(zap_menu, act); + + ++i; + } while ((types = g_list_next(types))); + + act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu); + menu = g_list_append(NULL, act); + + return menu; +} + +/** Process an incoming zap. */ +gboolean +msim_incoming_zap(MsimSession *session, MsimMessage *msg) +{ + gchar *msg_text, *username; + gint zap; + + msg_text = msim_msg_get_string(msg, "msg"); + username = msim_msg_get_string(msg, "_username"); + + g_return_val_if_fail(msg_text != NULL, FALSE); + g_return_val_if_fail(username != NULL, FALSE); + + g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE); + + zap = CLAMP(zap, 0, 9); + + serv_got_attention(session->gc, username, zap); + + g_free(msg_text); + g_free(username); + + return TRUE; +} + +
--- a/libpurple/protocols/myspace/zap.h Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/myspace/zap.h Fri Sep 28 16:34:43 2007 +0000 @@ -1,28 +1,28 @@ -/* MySpaceIM Protocol Plugin - zap support - * - * 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 - */ - -#ifndef _MYSPACE_ZAP_H -#define _MYSPACE_ZAP_H - -GList *msim_attention_types(PurpleAccount *acct); -gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code); -GList *msim_blist_node_menu(PurpleBlistNode *node); -gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg); - -#endif /* !_MYSPACE_ZAP_H */ +/* MySpaceIM Protocol Plugin - zap support + * + * 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 + */ + +#ifndef _MYSPACE_ZAP_H +#define _MYSPACE_ZAP_H + +GList *msim_attention_types(PurpleAccount *acct); +gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code); +GList *msim_blist_node_menu(PurpleBlistNode *node); +gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg); + +#endif /* !_MYSPACE_ZAP_H */
--- a/libpurple/protocols/novell/novell.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/novell/novell.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Fri Sep 28 16:34:43 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/oscar.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Fri Sep 28 16:34:43 2007 +0000 @@ -5523,6 +5523,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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/qq/login_logout.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/simple/simple.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Fri Sep 28 16:34:43 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; } @@ -4087,12 +4089,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); @@ -4117,7 +4119,7 @@ attn->incoming_description = _("%s has buzzed you!"); attn->outgoing_description = _("Buzzing %s..."); list = g_list_append(list, attn); - } + } return list; }
--- a/libpurple/server.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/server.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/sslconn.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/status.c Fri Sep 28 16:34:43 2007 +0000 @@ -601,7 +601,7 @@ { time_t current_time = time(NULL); const char *buddy_alias = purple_buddy_get_alias(buddy); - char *tmp; + char *tmp, *logtmp; PurpleLog *log; if (old_status != NULL) @@ -609,6 +609,10 @@ tmp = g_strdup_printf(_("%s changed status from %s to %s"), buddy_alias, purple_status_get_name(old_status), purple_status_get_name(new_status)); + logtmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias, buddy->name, + purple_status_get_name(old_status), + purple_status_get_name(new_status)); + } else { @@ -618,11 +622,16 @@ { tmp = g_strdup_printf(_("%s is now %s"), buddy_alias, purple_status_get_name(new_status)); + logtmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias, buddy->name, + purple_status_get_name(new_status)); + } else { tmp = g_strdup_printf(_("%s is no longer %s"), buddy_alias, purple_status_get_name(new_status)); + logtmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias, buddy->name, + purple_status_get_name(new_status)); } } @@ -630,10 +639,11 @@ if (log != NULL) { purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias, - current_time, tmp); + current_time, logtmp); } g_free(tmp); + g_free(logtmp); } }
--- a/libpurple/util.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/util.c Fri Sep 28 16:34:43 2007 +0000 @@ -68,7 +68,7 @@ }; static char *custom_user_dir = NULL; -static char *home_dir = NULL; +static char *user_dir = NULL; PurpleMenuAction * purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data, @@ -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; @@ -2465,10 +2448,10 @@ { if (custom_user_dir != NULL) return custom_user_dir; - else if (!home_dir) - home_dir = g_build_filename(purple_home_dir(), ".purple", NULL); - - return home_dir; + else if (!user_dir) + user_dir = g_build_filename(purple_home_dir(), ".purple", NULL); + + return user_dir; } void purple_util_set_user_dir(const char *dir)
--- a/libpurple/win32/win32dep.c Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/win32/win32dep.c Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/win32/win32dep.h Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/libpurple/xmlnode.h Fri Sep 28 16:34:43 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/gtkblist.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkblist.c Fri Sep 28 16:34:43 2007 +0000 @@ -88,6 +88,8 @@ GtkWidget *group_combo; GtkWidget *entries_box; GtkSizeGroup *sg; + GtkWidget *autojoin; + GtkWidget *persistent; GList *entries; @@ -138,13 +140,23 @@ static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender); static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); - -struct _pidgin_blist_node { +static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node); + +typedef enum { + PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE = 1 << 0, /* Whether there's pending message in a conversation */ +} PidginBlistNodeFlags; + +typedef struct _pidgin_blist_node { GtkTreeRowReference *row; gboolean contact_expanded; gboolean recent_signonoff; gint recent_signonoff_timer; -}; + struct { + PurpleConversation *conv; + time_t last_message; /* timestamp for last displayed message */ + PidginBlistNodeFlags flags; + } conv; +} PidginBlistNode; static char dim_grey_string[8] = ""; static char *dim_grey() @@ -306,12 +318,36 @@ serv_send_file(b->account->gc, b->name, NULL); } +static void gtk_blist_menu_move_to_cb(GtkWidget *w, PurpleBlistNode *node) +{ + PurpleGroup *group = g_object_get_data(G_OBJECT(w), "groupnode"); + purple_blist_add_contact((PurpleContact *)node, group, NULL); + +} + static void gtk_blist_menu_autojoin_cb(GtkWidget *w, PurpleChat *chat) { purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin", gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); } +static void gtk_blist_menu_persistent_cb(GtkWidget *w, PurpleChat *chat) +{ + purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent", + gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); +} + +static PurpleConversation * +find_conversation_with_buddy(PurpleBuddy *buddy) +{ + PidginBlistNode *ui = buddy->node.ui_data; + if (ui) + return ui->conv.conv; + return purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + purple_buddy_get_name(buddy), + purple_buddy_get_account(buddy)); +} + static void gtk_blist_join_chat(PurpleChat *chat) { PurpleConversation *conv; @@ -395,6 +431,105 @@ } #endif +static void +gtk_blist_do_personize(GList *merges) +{ + PurpleBlistNode *contact = NULL; + int max = 0; + GList *tmp; + + /* First, we find the contact to merge the rest of the buddies into. + * This will be the contact with the most buddies in it; ties are broken + * by which contact is higher in the list + */ + for (tmp = merges; tmp; tmp = tmp->next) { + PurpleBlistNode *node = tmp->data; + PurpleBlistNode *b; + int i = 0; + + if (node->type == PURPLE_BLIST_BUDDY_NODE) + node = node->parent; + + if (node->type != PURPLE_BLIST_CONTACT_NODE) + continue; + + + for (b = node->child; b; b = b->next) + i++; + if (i > max) { + contact = node; + max = i; + } + } + + if (contact == NULL) + return; + + /* Merge all those buddies into this contact */ + for (tmp = merges; tmp; tmp = tmp->next) { + PurpleBlistNode *node = tmp->data; + if (node->type == PURPLE_BLIST_BUDDY_NODE) + node = node->parent; + + if (node == contact) + continue; + + purple_blist_merge_contact((PurpleContact *)node, contact); + } + + /* And show the expanded contact, so the people know what's going on */ + pidgin_blist_expand_contact_cb(NULL, contact); + g_list_free(merges); +} + +static void +gtk_blist_auto_personize(PurpleBlistNode *group, const char *alias) +{ + PurpleBlistNode *contact; + PurpleBlistNode *buddy; + GList *merges = NULL; + int i = 0; + char *a = g_utf8_casefold(alias, -1); + + for (contact = group->child; contact; contact = contact->next) { + char *node_alias; + if (contact->type != PURPLE_BLIST_CONTACT_NODE) + continue; + + node_alias = g_utf8_casefold(purple_contact_get_alias((PurpleContact *)contact), -1); + if (node_alias && !g_utf8_collate(node_alias, a)) { + merges = g_list_append(merges, contact); + i++; + g_free(node_alias); + continue; + } + g_free(node_alias); + + for (buddy = contact->child; buddy; buddy = buddy->next) { + if (buddy->type != PURPLE_BLIST_BUDDY_NODE) + continue; + + node_alias = g_utf8_casefold(purple_buddy_get_alias((PurpleBuddy *)buddy), -1); + if (node_alias && !g_utf8_collate(node_alias, a)) { + merges = g_list_append(merges, buddy); + i++; + } + g_free(node_alias); + } + } + g_free(a); + + if (i > 1) + { + 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)); + g_free(msg); + } else + g_list_free(merges); +} + static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1, char *arg2, PurpleBuddyList *list) { @@ -421,13 +556,14 @@ PurpleContact *contact = (PurpleContact *)node; struct _pidgin_blist_node *gtknode = (struct _pidgin_blist_node *)node->ui_data; - if (contact->alias || gtknode->contact_expanded) + if (contact->alias || gtknode->contact_expanded) { purple_blist_alias_contact(contact, arg2); - else - { + gtk_blist_auto_personize(node->parent, arg2); + } else { PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact); purple_blist_alias_buddy(buddy, arg2); serv_alias_buddy(buddy); + gtk_blist_auto_personize(node->parent, arg2); } } break; @@ -435,6 +571,7 @@ case PURPLE_BLIST_BUDDY_NODE: purple_blist_alias_buddy((PurpleBuddy*)node, arg2); serv_alias_buddy((PurpleBuddy *)node); + gtk_blist_auto_personize(node->parent->parent, arg2); break; case PURPLE_BLIST_GROUP_NODE: dest = purple_find_group(arg2); @@ -525,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(); @@ -1119,17 +1276,49 @@ g_list_free(ll); } + + +static void +pidgin_append_blist_node_move_to_menu(GtkWidget *menu, PurpleBlistNode *node) +{ + GtkWidget *submenu; + GtkWidget *menuitem; + PurpleBlistNode *group; + + menuitem = gtk_menu_item_new_with_label(_("Move to")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + gtk_widget_show(menuitem); + + submenu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); + + for (group = purple_blist_get_root(); group; group = group->next) { + if (group->type != PURPLE_BLIST_GROUP_NODE) + continue; + if (group == node->parent) + continue; + menuitem = pidgin_new_item_from_stock(submenu, purple_group_get_name((PurpleGroup *)group), NULL, + G_CALLBACK(gtk_blist_menu_move_to_cb), node, 0, 0, NULL); + g_object_set_data(G_OBJECT(menuitem), "groupnode", group); + } + gtk_widget_show_all(submenu); +} + void 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; @@ -1145,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), @@ -1165,15 +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 (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && + 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 (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); @@ -1182,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, @@ -1235,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, @@ -1256,16 +1452,19 @@ create_chat_menu(PurpleBlistNode *node, PurpleChat *c) { GtkWidget *menu; - gboolean autojoin; + gboolean autojoin, persistent; menu = gtk_menu_new(); autojoin = (purple_blist_node_get_bool(node, "gtk-autojoin") || (purple_blist_node_get_string(node, "gtk-autojoin") != NULL)); + persistent = purple_blist_node_get_bool(node, "gtk-persistent"); pidgin_new_item_from_stock(menu, _("_Join"), PIDGIN_STOCK_CHAT, G_CALLBACK(gtk_blist_menu_join_cb), node, 0, 0, NULL); pidgin_new_check_item(menu, _("Auto-Join"), G_CALLBACK(gtk_blist_menu_autojoin_cb), node, autojoin); + pidgin_new_check_item(menu, _("Persistent"), + G_CALLBACK(gtk_blist_menu_persistent_cb), node, persistent); pidgin_new_item_from_stock(menu, _("View _Log"), NULL, G_CALLBACK(gtk_blist_menu_showlog_cb), node, 0, 0, NULL); @@ -1307,7 +1506,6 @@ node, 0, 0, NULL); pidgin_append_blist_node_extended_menu(menu, node); - return menu; } @@ -2888,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 }, @@ -3145,8 +3343,6 @@ GdkPixbuf *ret; PurplePresence *p; - - if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { if(!gtknode->contact_expanded) { buddy = purple_contact_get_priority_buddy((PurpleContact*)node); @@ -3188,6 +3384,13 @@ return ret; } + if (purple_status_get_attr_string(purple_presence_get_active_status(p), PURPLE_TUNE_TITLE)) { + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL); + ret = gdk_pixbuf_new_from_file(path, NULL); + g_free(path); + return ret; + } + prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account)); if (!prpl) return NULL; @@ -3261,17 +3464,17 @@ } if(buddy) { - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - purple_buddy_get_name(buddy), - purple_buddy_get_account(buddy)); + PurpleConversation *conv = find_conversation_with_buddy(buddy); PurplePresence *p; gboolean trans; if(conv != NULL) { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); - if((gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) && size == PIDGIN_STATUS_ICON_SMALL) { - return gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_MESSAGE, - icon_size, "GtkTreeView"); + if (gtkconv == NULL && size == PIDGIN_STATUS_ICON_SMALL) { + PidginBlistNode *ui = buddy->node.ui_data; + if (ui == NULL || (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE)) + return gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), + PIDGIN_STOCK_STATUS_MESSAGE, icon_size, "GtkTreeView"); } } @@ -3327,16 +3530,17 @@ struct _pidgin_blist_node *gtkcontactnode = NULL; char *idletime = NULL, *statustext = NULL; time_t t; - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - purple_buddy_get_name(b), - purple_buddy_get_account(b)); - PidginConversation *gtkconv; + PurpleConversation *conv = find_conversation_with_buddy(b); gboolean hidden_conv = FALSE; - if(conv != NULL) { - gtkconv = PIDGIN_CONVERSATION(conv); - if(gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) { - hidden_conv = TRUE; + if (conv != NULL) { + PidginBlistNode *ui = b->node.ui_data; + if (ui) { + if (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE) + hidden_conv = TRUE; + } else { + if (PIDGIN_CONVERSATION(conv) == NULL) + hidden_conv = TRUE; } } @@ -3671,7 +3875,7 @@ menu = NULL; } - convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM, PIDGIN_UNSEEN_TEXT, TRUE, 0); + convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_ANY, PIDGIN_UNSEEN_TEXT, TRUE, 0); if (!convs) /* no conversations added, don't show the menu */ return; @@ -3727,7 +3931,7 @@ gtkblist->menutrayicon = NULL; } - convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM, PIDGIN_UNSEEN_TEXT, TRUE, 0); + convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_ANY, PIDGIN_UNSEEN_TEXT, TRUE, 0); if (convs) { GtkWidget *img = NULL; GString *tooltip_text = NULL; @@ -3735,14 +3939,10 @@ tooltip_text = g_string_new(""); l = convs; while (l != NULL) { - if (PIDGIN_IS_PIDGIN_CONVERSATION(l->data)) { - PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)l->data); - - g_string_append_printf(tooltip_text, - ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count), - gtkconv->unseen_count, - gtk_label_get_text(GTK_LABEL(gtkconv->tab_label))); - } + int count = GPOINTER_TO_INT(purple_conversation_get_data(l->data, "unseen-count")); + g_string_append_printf(tooltip_text, + ngettext("%d unread message from %s\n", "%d unread messages from %s\n", count), + count, purple_conversation_get_name(l->data)); l = l->next; } if(tooltip_text->len > 0) { @@ -3770,6 +3970,88 @@ conversation_updated_cb(conv, PURPLE_CONV_UPDATE_UNSEEN, gtkblist); } +static void +conversation_deleted_update_ui_cb(PurpleConversation *conv, struct _pidgin_blist_node *ui) +{ + if (ui->conv.conv != conv) + return; + ui->conv.conv = NULL; + ui->conv.flags = 0; + ui->conv.last_message = 0; +} + +static void +written_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message, + PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node) +{ + PidginBlistNode *ui = node->ui_data; + if (ui->conv.conv != conv || PIDGIN_CONVERSATION(conv) || + !(flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV))) + return; + ui->conv.flags |= PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE; + ui->conv.last_message = time(NULL); /* XXX: for lack of better data */ + pidgin_blist_update(purple_get_blist(), node); +} + +static void +displayed_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message, + PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node) +{ + PidginBlistNode *ui = node->ui_data; + if (ui->conv.conv != conv) + return; + ui->conv.flags &= ~PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE; + pidgin_blist_update(purple_get_blist(), node); +} + +static void +conversation_created_cb(PurpleConversation *conv, PidginBuddyList *gtkblist) +{ + switch (conv->type) { + case PURPLE_CONV_TYPE_IM: + { + GSList *buddies = purple_find_buddies(conv->account, conv->name); + while (buddies) { + PurpleBlistNode *buddy = buddies->data; + struct _pidgin_blist_node *ui = buddy->ui_data; + buddies = g_slist_delete_link(buddies, buddies); + if (!ui) + continue; + ui->conv.conv = conv; + ui->conv.flags = 0; + ui->conv.last_message = 0; + purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", + ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui); + purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", + ui, PURPLE_CALLBACK(written_msg_update_ui_cb), buddy); + purple_signal_connect(pidgin_conversations_get_handle(), "displayed-im-msg", + ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), buddy); + } + } + case PURPLE_CONV_TYPE_CHAT: + { + PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name); + struct _pidgin_blist_node *ui; + if (!chat) + break; + ui = chat->node.ui_data; + if (!ui) + break; + ui->conv.conv = conv; + ui->conv.flags = 0; + ui->conv.last_message = 0; + purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", + ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui); + purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", + ui, PURPLE_CALLBACK(written_msg_update_ui_cb), chat); + purple_signal_connect(pidgin_conversations_get_handle(), "displayed-chat-msg", + ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), chat); + } + default: + break; + } +} + /********************************************************************************** * Public API Functions * **********************************************************************************/ @@ -4334,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); @@ -4683,6 +4965,9 @@ purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", gtkblist, PURPLE_CALLBACK(conversation_deleting_cb), gtkblist); + purple_signal_connect(purple_conversations_get_handle(), "conversation-created", + gtkblist, PURPLE_CALLBACK(conversation_created_cb), + gtkblist); gtk_widget_hide(gtkblist->headline_hbox); gtk_widget_hide(gtkblist->error_buttons); @@ -4789,6 +5074,7 @@ if(gtknode->recent_signonoff_timer > 0) purple_timeout_remove(gtknode->recent_signonoff_timer); + purple_signals_disconnect_by_handle(node->ui_data); g_free(node->ui_data); node->ui_data = NULL; } @@ -4953,7 +5239,7 @@ STATUS_ICON_COLUMN, NULL, NAME_COLUMN, title, NODE_COLUMN, gnode, - BGCOLOR_COLUMN, &bgcolor, + /* BGCOLOR_COLUMN, &bgcolor, */ GROUP_EXPANDER_COLUMN, TRUE, GROUP_EXPANDER_VISIBLE_COLUMN, TRUE, CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE, @@ -5213,14 +5499,17 @@ GdkPixbuf *emblem; char *mark; gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); - const char *name = purple_chat_get_name(chat); - PurpleConversation *conv = - purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, name, chat->account); - gboolean hidden = (conv && !PIDGIN_CONVERSATION(conv)); - - if(!insert_node(list, node, &iter)) + PidginBlistNode *ui; + PurpleConversation *conv; + gboolean hidden; + + if (!insert_node(list, node, &iter)) return; + ui = node->ui_data; + conv = ui->conv.conv; + hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE)); + status = pidgin_blist_get_status_icon(node, PIDGIN_STATUS_ICON_SMALL); emblem = pidgin_blist_get_emblem(node); @@ -5527,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); @@ -5644,6 +5933,12 @@ purple_blist_add_chat(chat, group, NULL); } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->autojoin))) + purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin", TRUE); + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->persistent))) + purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent", TRUE); + gtk_widget_destroy(data->window); g_free(data->default_chat_name); g_list_free(data->entries); @@ -5938,6 +6233,11 @@ gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_BIN(data->group_combo)->child); pidgin_set_accessible_label (data->group_combo, label); gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0); + + data->autojoin = gtk_check_button_new_with_mnemonic(_("Autojoin when account becomes online.")); + data->persistent = gtk_check_button_new_with_mnemonic(_("Hide chat when the window is closed.")); + gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), data->persistent, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(data->window), "response", G_CALLBACK(add_chat_resp_cb), data); @@ -6586,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/gtkcellrendererexpander.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkcellrendererexpander.c Fri Sep 28 16:34:43 2007 +0000 @@ -270,6 +270,9 @@ cell_area->x + cell->xpad + (width / 2), cell_area->y + cell->ypad + (height / 2), cell->is_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED); + if (cell->is_expanded) + gtk_paint_hline (widget->style, window, state, NULL, widget, NULL, 0, + widget->allocation.width, cell_area->y + cell_area->height); } static gboolean pidgin_cell_renderer_expander_activate(GtkCellRenderer *r,
--- a/pidgin/gtkconn.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkconn.c Fri Sep 28 16:34:43 2007 +0000 @@ -53,7 +53,7 @@ * The key is a pointer to the PurpleAccount and the * value is a pointer to a PidginAutoRecon. */ -static GHashTable *hash = NULL; +static GHashTable *auto_reconns = NULL; static void pidgin_connection_connect_progress(PurpleConnection *gc, @@ -80,7 +80,7 @@ pidgin_status_box_set_connecting(PIDGIN_STATUS_BOX(gtkblist->statusbox), (purple_connections_get_connecting() != NULL)); - g_hash_table_remove(hash, account); + g_hash_table_remove(auto_reconns, account); pidgin_blist_update_account_error_state(account, NULL); } @@ -120,7 +120,7 @@ purple_debug_info("autorecon", "do_signon called\n"); g_return_val_if_fail(account != NULL, FALSE); - info = g_hash_table_lookup(hash, account); + info = g_hash_table_lookup(auto_reconns, account); if (info) info->timeout = 0; @@ -141,15 +141,16 @@ { PurpleAccount *account = NULL; PidginAutoRecon *info; + GList *list; account = purple_connection_get_account(gc); - info = g_hash_table_lookup(hash, account); + info = g_hash_table_lookup(auto_reconns, account); pidgin_blist_update_account_error_state(account, text); if (!gc->wants_to_die) { if (info == NULL) { info = g_new0(PidginAutoRecon, 1); - g_hash_table_insert(hash, account, info); + g_hash_table_insert(auto_reconns, account, info); info->delay = g_random_int_range(INITIAL_RECON_DELAY_MIN, INITIAL_RECON_DELAY_MAX); } else { info->delay = MIN(2 * info->delay, MAX_RECON_DELAY); @@ -160,7 +161,7 @@ } else { char *p, *s, *n=NULL ; if (info != NULL) - g_hash_table_remove(hash, account); + g_hash_table_remove(auto_reconns, account); if (purple_account_get_alias(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 () @@ -204,7 +216,7 @@ while (list) { PurpleAccount *account = (PurpleAccount*)list->data; - g_hash_table_remove(hash, account); + g_hash_table_remove(auto_reconns, account); if (purple_account_is_disconnected(account)) do_signon(account); list = list->next; @@ -265,7 +277,7 @@ static void account_removed_cb(PurpleAccount *account, gpointer user_data) { - g_hash_table_remove(hash, account); + g_hash_table_remove(auto_reconns, account); pidgin_blist_update_account_error_state(account, NULL); } @@ -286,7 +298,7 @@ void pidgin_connection_init(void) { - hash = g_hash_table_new_full( + auto_reconns = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, free_auto_recon); @@ -300,5 +312,5 @@ { purple_signals_disconnect_by_handle(pidgin_connection_get_handle()); - g_hash_table_destroy(hash); + g_hash_table_destroy(auto_reconns); }
--- a/pidgin/gtkconv.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkconv.c Fri Sep 28 16:34:43 2007 +0000 @@ -70,6 +70,8 @@ #include "gtknickcolors.h" +#define CLOSE_CONV_TIMEOUT_SECS (10 * 60) + #define AUTO_RESPONSE "<AUTO-REPLY> : " typedef enum @@ -123,7 +125,6 @@ static GtkWidget *invite_dialog = NULL; static GtkWidget *warn_close_dialog = NULL; -static PidginWindow *hidden_convwin = NULL; static GList *window_list = NULL; /* Lists of status icons at all available sizes for use as window icons */ @@ -161,6 +162,7 @@ static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv); static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv); +static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, int width, int height); @@ -208,12 +210,49 @@ **************************************************************************/ static gboolean -close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv) -{ +close_this_sucker(gpointer data) +{ + PidginConversation *gtkconv = data; GList *list = g_list_copy(gtkconv->convs); - g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL); g_list_free(list); + return FALSE; +} + +static gboolean +close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv) +{ + /* We are going to destroy the conversations immediately only if the 'close immediately' + * preference is selected. Otherwise, close the conversation after a reasonable timeout + * (I am going to consider 10 minutes as a 'reasonable timeout' here. + * For chats, close immediately if the chat is not in the buddylist, or if the chat is + * not marked 'Persistent' */ + PurpleConversation *conv = gtkconv->active_conv; + PurpleAccount *account = purple_conversation_get_account(conv); + const char *name = purple_conversation_get_name(conv); + + switch (purple_conversation_get_type(conv)) { + case PURPLE_CONV_TYPE_IM: + { + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately")) + close_this_sucker(gtkconv); + else + hide_conv(gtkconv, TRUE); + break; + } + case PURPLE_CONV_TYPE_CHAT: + { + PurpleChat *chat = purple_blist_find_chat(account, name); + if (!chat || + !purple_blist_node_get_bool(&chat->node, "gtk-persistent")) + close_this_sucker(gtkconv); + else + hide_conv(gtkconv, FALSE); + break; + } + default: + ; + } return TRUE; } @@ -337,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 @@ -348,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; } @@ -1060,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 { @@ -1315,18 +1353,33 @@ add_remove_cb(NULL, PIDGIN_CONVERSATION(conv)); } -#if 0 -static void -menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget) -{ - PidginWindow *win = data; - PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); - PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win); +static gboolean +close_already(gpointer data) +{ + purple_conversation_destroy(data); + return FALSE; +} + +static void +hide_conv(PidginConversation *gtkconv, gboolean closetimer) +{ + GList *list; + purple_signal_emit(pidgin_conversations_get_handle(), "conversation-hiding", gtkconv); - purple_conversation_set_ui_ops(conv, NULL); -} -#endif + + for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) { + PurpleConversation *conv = list->data; + if (closetimer) { + guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer")); + if (timer) + purple_timeout_remove(timer); + timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv); + purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer)); + } + purple_conversation_set_ui_ops(conv, NULL); + } +} static void menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) @@ -2343,63 +2396,69 @@ return get_prpl_icon_list(account); } -GdkPixbuf * -pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon) -{ - PurpleAccount *account = NULL; - const char *name = NULL; - GdkPixbuf *status = NULL; - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL; - g_return_val_if_fail(conv != NULL, NULL); - - account = purple_conversation_get_account(conv); - name = purple_conversation_get_name(conv); - - g_return_val_if_fail(account != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - /* Use the buddy icon, if possible */ - if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { - PurpleBuddy *b = purple_find_buddy(account, name); - if (b != NULL) { +static GdkPixbuf * +pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size) +{ + PurpleAccount *account = NULL; + const char *name = NULL; + GdkPixbuf *status = NULL; + PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + g_return_val_if_fail(conv != NULL, NULL); + + account = purple_conversation_get_account(conv); + name = purple_conversation_get_name(conv); + + g_return_val_if_fail(account != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + /* Use the buddy icon, if possible */ + if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { + PurpleBuddy *b = purple_find_buddy(account, name); + if (b != NULL) { PurplePresence *p = purple_buddy_get_presence(b); - /* I hate this hack. It fixes a bug where the pending message icon - * displays in the conv tab even though it shouldn't. - * A better solution would be great. */ - if (ops && ops->update) - ops->update(NULL, (PurpleBlistNode*)b); + /* I hate this hack. It fixes a bug where the pending message icon + * displays in the conv tab even though it shouldn't. + * A better solution would be great. */ + if (ops && ops->update) + ops->update(NULL, (PurpleBlistNode*)b); /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */ if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY)) - status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); + status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size); else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY)) - status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); - else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE)) - status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, PIDGIN_CONVERSATION(conv)->icon, icon_size); - else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE)) - status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); - else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) - status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); - else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) - status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); - } - } - - /* If they don't have a buddy icon, then use the PRPL icon */ - if (status == NULL) { + status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, parent, icon_size); + else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE)) + status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size); + else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE)) + status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size); + else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) + status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size); + else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) + status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size); + } + } + + /* If they don't have a buddy icon, then use the PRPL icon */ + if (status == NULL) { GtkIconSize size = gtk_icon_size_from_name(icon_size); if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { - status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON, - size, "GtkWidget"); + status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON, + size, "GtkWidget"); } else { - status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT, - size, "GtkWidget"); + status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT, + size, "GtkWidget"); } } return status; } +GdkPixbuf * +pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon) +{ + const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL; + return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size); +} + static void update_tab_icon(PurpleConversation *conv) @@ -2751,9 +2810,9 @@ PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); GdkModifierType state; - if(gtkconv->win==hidden_convwin) { - pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); - pidgin_conv_placement_place(gtkconv); + if (gtkconv == NULL) { + pidgin_conv_attach_to_conversation(conv); + gtkconv = PIDGIN_CONVERSATION(conv); } pidgin_conv_switch_active_conversation(conv); @@ -2786,15 +2845,19 @@ PurpleConversation *conv = (PurpleConversation*)l->data; PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); - if(gtkconv == NULL || gtkconv->active_conv != conv) + if (gtkconv != NULL && gtkconv->active_conv != conv) continue; - - if (gtkconv->unseen_state >= min_state - && (!hidden_only || - (hidden_only && gtkconv->win == hidden_convwin))) { - + if (gtkconv == NULL) { + if (!hidden_only || + !purple_conversation_get_data(conv, "unseen-count")) + continue; r = g_list_prepend(r, conv); c++; + } else { + if (gtkconv->unseen_state >= min_state && !hidden_only) { + r = g_list_prepend(r, conv); + c++; + } } } @@ -2834,11 +2897,11 @@ PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); GtkWidget *icon = gtk_image_new(); - GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE); + GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC); GtkWidget *item; gchar *text = g_strdup_printf("%s (%d)", - gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)), - gtkconv->unseen_count); + gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv), + gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"))); gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf); g_object_unref(pbuf); @@ -3096,7 +3159,7 @@ PurpleConversation *conv; GtkWidget *item; - if (win->window == NULL || win == hidden_convwin) + if (win->window == NULL) return; gtkconv = pidgin_conv_window_get_active_gtkconv(win); @@ -3571,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(); @@ -4943,6 +5006,9 @@ GtkWidget *tab_cont; PurpleBlistNode *convnode; + if (hidden) + return; + if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) { conv->ui_data = gtkconv; if (!g_list_find(gtkconv->convs, conv)) @@ -5042,10 +5108,7 @@ G_CALLBACK(gtk_widget_grab_focus), gtkconv->entry); - if (hidden) - pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv); - else - pidgin_conv_placement_place(gtkconv); + pidgin_conv_placement_place(gtkconv); if (nick_colors == NULL) { nbr_nick_colors = NUM_NICK_COLORS; @@ -5053,11 +5116,13 @@ } } +#if 0 static void pidgin_conv_new_hidden(PurpleConversation *conv) { private_gtkconv_new(conv, TRUE); } +#endif void pidgin_conv_new(PurpleConversation *conv) @@ -5070,26 +5135,22 @@ PurpleConversation *conv, PurpleMessageFlags flags) { PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops(); - if (conv != NULL) - return; /* create hidden conv if hide_new pref is always */ - if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) - { - ui_ops->create_conversation = pidgin_conv_new_hidden; - purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender); - ui_ops->create_conversation = pidgin_conv_new; - return; - } - - /* create hidden conv if hide_new pref is away and account is away */ - if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 && - !purple_status_is_available(purple_account_get_active_status(account))) - { - ui_ops->create_conversation = pidgin_conv_new_hidden; - purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender); - ui_ops->create_conversation = pidgin_conv_new; - return; + /* or if hide_new pref is away and account is away */ + if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) || + (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 && + !purple_status_is_available(purple_account_get_active_status(account)))) { + if (!conv) { + ui_ops->create_conversation = NULL; + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender); + purple_conversation_set_ui_ops(conv, NULL); + ui_ops->create_conversation = pidgin_conv_new; + } + } else { + /* new message for an IM */ + if (conv && conv->type == PURPLE_CONV_TYPE_IM) + pidgin_conv_attach_to_conversation(conv); } } @@ -5098,6 +5159,9 @@ { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); + if (!gtkconv) + return; + gtkconv->convs = g_list_remove(gtkconv->convs, conv); /* Don't destroy ourselves until all our convos are gone */ if (gtkconv->convs) { @@ -6575,6 +6639,19 @@ pidgin_conv_update_fields(conv, flags); } +static void +wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message, + PurpleConversation *conv, PurpleMessageFlags flag, gpointer null) +{ + if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv)) + return; + if (flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) { + purple_conversation_set_data(conv, "unseen-count", + GINT_TO_POINTER(GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")) + 1)); + purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN); + } +} + static PurpleConversationUiOps conversation_ui_ops = { pidgin_conv_new, @@ -7072,6 +7149,7 @@ account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus, PurpleStatus *newstatus) { +#if 0 GList *l; PurpleConversation *conv = NULL; PidginConversation *gtkconv; @@ -7081,27 +7159,7 @@ if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus)) return; - - while ((l = hidden_convwin->gtkconvs) != NULL) - { - gtkconv = l->data; - - conv = gtkconv->active_conv; - - while(l && !purple_status_is_available( - purple_account_get_active_status( - purple_conversation_get_account(conv)))) - l = l->next; - if (!l) - break; - - pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); - pidgin_conv_placement_place(gtkconv); - - /* TODO: do we need to do anything for any other conversations that are in the same gtkconv here? - * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/ - purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN); - } +#endif } static void @@ -7109,32 +7167,25 @@ gconstpointer value, gpointer data) { GList *l; - PurpleConversation *conv = NULL; - PidginConversation *gtkconv; gboolean when_away = FALSE; - if(!hidden_convwin) - return; - if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0) return; if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0) when_away = TRUE; - while ((l = hidden_convwin->gtkconvs) != NULL) + for (l = purple_get_conversations(); l; l = l->next) { - gtkconv = l->data; - - conv = gtkconv->active_conv; - + PurpleConversation *conv = l->data; + PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); + if (gtkconv) + continue; if(when_away && !purple_status_is_available( purple_account_get_active_status( purple_conversation_get_account(conv)))) continue; - - pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); - pidgin_conv_placement_place(gtkconv); + pidgin_conv_attach_to_conversation(conv); } } @@ -7190,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); + } } } @@ -7317,9 +7385,15 @@ PidginConversation *gtkconv = data; int count = 0; int timer = gtkconv->attach.timer; + time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time")); + gtkconv->attach.timer = 0; while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ PurpleConvMessage *msg = gtkconv->attach.current->data; + if (when && when < msg->when) { + gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); + g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); + } pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when); gtkconv->attach.current = gtkconv->attach.current->prev; count++; @@ -7328,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); @@ -7339,18 +7414,21 @@ { GList *list; PidginConversation *gtkconv; + int timer; if (PIDGIN_IS_PIDGIN_CONVERSATION(conv)) return FALSE; + purple_conversation_set_data(conv, "unseen-count", NULL); purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops()); private_gtkconv_new(conv, FALSE); gtkconv = PIDGIN_CONVERSATION(conv); list = purple_conversation_get_message_history(conv); if (list) { - list = g_list_last(list); - gtkconv->attach.current = list; + g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", + GINT_TO_POINTER(((PurpleConvMessage*)(list->data))->when)); + gtkconv->attach.current = g_list_last(list); gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv); } else { purple_signal_emit(pidgin_conversations_get_handle(), @@ -7362,6 +7440,9 @@ pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE); } + timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer")); + if (timer) + purple_timeout_remove(timer); return TRUE; } @@ -7427,6 +7508,7 @@ purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE); purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never"); + purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", FALSE); #ifdef _WIN32 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE); @@ -7590,9 +7672,6 @@ purple_conversations_set_ui_ops(&conversation_ui_ops); - hidden_convwin = pidgin_conv_window_new(); - window_list = g_list_remove(window_list, hidden_convwin); - purple_signal_connect(purple_accounts_get_handle(), "account-status-changed", handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); @@ -7628,6 +7707,10 @@ purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle, PURPLE_CALLBACK(pidgin_conv_updated), NULL, PURPLE_SIGNAL_PRIORITY_LOWEST); + purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", handle, + PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL); + purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle, + PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL); } void @@ -7636,8 +7719,6 @@ purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle()); purple_signals_disconnect_by_handle(pidgin_conversations_get_handle()); purple_signals_unregister_by_instance(pidgin_conversations_get_handle()); - pidgin_conv_window_destroy(hidden_convwin); - hidden_convwin=NULL; } @@ -8019,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); @@ -8769,15 +8850,10 @@ if (win->gtkconvs) { while (win->gtkconvs) { - GList *nextgtk = win->gtkconvs->next; - PidginConversation *gtkconv = win->gtkconvs->data; - GList *nextcore = gtkconv->convs->next; - PurpleConversation *conv = gtkconv->convs->data; - purple_conversation_destroy(conv); - if (!nextgtk && !nextcore) - /* we'll end up invoking ourselves when we destroy our last child */ - /* so don't destroy ourselves right now */ - return; + gboolean last = (win->gtkconvs->next == NULL); + close_conv_cb(NULL, NULL, win->gtkconvs->data); + if (last) + break; } return; } @@ -9054,7 +9130,7 @@ if (win->gtkconvs && win->gtkconvs->next == NULL) pidgin_conv_tab_pack(win, win->gtkconvs->data); - if (!win->gtkconvs && win != hidden_convwin) + if (!win->gtkconvs) pidgin_conv_window_destroy(win); } @@ -9593,9 +9669,7 @@ gboolean pidgin_conv_is_hidden(PidginConversation *gtkconv) { - g_return_val_if_fail(gtkconv != NULL, FALSE); - - return (gtkconv->win == hidden_convwin); + return (gtkconv == NULL); } @@ -9696,3 +9770,4 @@ return colors; } +
--- a/pidgin/gtkdocklet.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkdocklet.c Fri Sep 28 16:34:43 2007 +0000 @@ -532,7 +532,7 @@ g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_mute), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = gtk_check_menu_item_new_with_label(_("Blink on new message")); + menuitem = gtk_check_menu_item_new_with_label(_("Blink on New Message")); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink")); g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blink), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
--- a/pidgin/gtkimhtmltoolbar.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Fri Sep 28 16:34:43 2007 +0000 @@ -1166,6 +1166,7 @@ GtkWidget *label; GtkWidget *insert_button; GtkWidget *font_button; + GtkWidget *smiley_button; GtkWidget *font_menu; GtkWidget *insert_menu; GtkWidget *menuitem; @@ -1267,12 +1268,6 @@ insert_menu = gtk_menu_new(); g_object_set_data(G_OBJECT(toolbar), "insert_menu", insert_menu); - menuitem = gtk_menu_item_new_with_mnemonic(_("_Smiley")); - g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_button_clicked), toolbar->smiley); - gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), menuitem); - g_signal_connect(G_OBJECT(toolbar->smiley), "notify::sensitive", - G_CALLBACK(button_sensitiveness_changed), menuitem); - menuitem = gtk_menu_item_new_with_mnemonic(_("_Image")); g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(gtk_button_clicked), toolbar->image); gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), menuitem); @@ -1294,6 +1289,24 @@ g_signal_connect(G_OBJECT(insert_button), "activate", G_CALLBACK(pidgin_menu_clicked), insert_menu); g_signal_connect(G_OBJECT(insert_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), insert_button); toolbar->sml = NULL; + + /* Sep */ + sep = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 0); + gtk_widget_show_all(sep); + + /* Smiley */ + smiley_button = gtk_button_new(); + gtk_button_set_relief(GTK_BUTTON(smiley_button), GTK_RELIEF_NONE); + bbox = gtk_hbox_new(FALSE, 3); + 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(_("_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); + gtk_widget_show_all(smiley_button); gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(hbox), "lean-view", box);
--- a/pidgin/gtkmain.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkmain.c Fri Sep 28 16:34:43 2007 +0000 @@ -394,6 +394,9 @@ " -n, --nologin don't automatically login\n" " -l, --login[=NAME] automatically login (optional argument NAME specifies\n" " account(s) to use, separated by commas)\n" +#ifndef WIN32 + " --display=DISPLAY X display to use\n" +#endif " -v, --version display the current version and exit\n"), PIDGIN_NAME, VERSION, name); } @@ -481,6 +484,7 @@ {"nologin", no_argument, NULL, 'n'}, {"session", required_argument, NULL, 's'}, {"version", no_argument, NULL, 'v'}, + {"display", required_argument, NULL, 'D'}, {0, 0, 0, 0} }; @@ -626,6 +630,9 @@ case 'm': /* do not ensure single instance. */ opt_si = FALSE; break; + case 'D': /* --display */ + /* handled by gtk_init_check below */ + break; case '?': /* show terse help */ default: show_usage(argv[0], TRUE);
--- a/pidgin/gtknotify.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtknotify.c Fri Sep 28 16:34:43 2007 +0000 @@ -559,8 +559,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 @@ -690,30 +690,30 @@ GtkTreeIter iter; GdkPixbuf *pixbuf; guint col_num; - guint i; - guint j; + GList *row, *column; + guint n; gtk_list_store_clear(data->model); pixbuf = pidgin_create_prpl_icon(purple_connection_get_account(gc), 0.5); /* +1 is for the automagically created Status column. */ - col_num = purple_notify_searchresults_get_columns_count(results) + 1; + col_num = g_list_length(results->columns) + 1; - for (i = 0; i < purple_notify_searchresults_get_rows_count(results); i++) { - GList *row = purple_notify_searchresults_row_get(results, i); + for (row = results->rows; row != NULL; row = row->next) { gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, pixbuf, -1); - for (j = 1; j < col_num; j++) { + n = 1; + for (column = row->data; column != NULL; column = column->next) { GValue v; - char *data = g_list_nth_data(row, j - 1); v.g_type = 0; g_value_init(&v, G_TYPE_STRING); - g_value_set_string(&v, data); - gtk_list_store_set_value(model, &iter, j, &v); + g_value_set_string(&v, column->data); + gtk_list_store_set_value(model, &iter, n, &v); + n++; } } @@ -733,6 +733,7 @@ GtkListStore *model; GtkCellRenderer *renderer; guint col_num; + GList *column; guint i; GtkWidget *vbox; @@ -780,7 +781,7 @@ g_free(label_text); /* +1 is for the automagically created Status column. */ - col_num = purple_notify_searchresults_get_columns_count(results) + 1; + col_num = g_list_length(results->columns) + 1; /* Setup the list model */ col_types = g_new0(GType, col_num); @@ -815,12 +816,13 @@ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, "", renderer, "pixbuf", 0, NULL); - for (i = 1; i < col_num; i++) { + i = 1; + for (column = results->columns; column != NULL; column = column->next) { renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, - purple_notify_searchresults_column_get_title(results, i-1), - renderer, "text", i, NULL); + column->data, renderer, "text", i, NULL); + i++; } for (i = 0; i < g_list_length(results->buttons); i++) {
--- a/pidgin/gtkprefs.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtkprefs.c Fri Sep 28 16:34:43 2007 +0000 @@ -994,6 +994,8 @@ pidgin_prefs_checkbox(_("Show _formatting on incoming messages"), PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox); + pidgin_prefs_checkbox(_("Close IMs immediately when the tab is closed"), + PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", vbox); iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"), PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox);
--- a/pidgin/gtksession.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/gtksession.c Fri Sep 28 16:34:43 2007 +0000 @@ -36,6 +36,7 @@ #include <gdk/gdkx.h> #include <unistd.h> #include <fcntl.h> +#include <gdk/gdk.h> #define ERROR_LENGTH 512 @@ -141,7 +142,7 @@ /* my magic utility function */ static gchar **session_make_command(gchar *client_id, gchar *config_dir) { - gint i = 2; + gint i = 4; gint j = 0; gchar **ret; @@ -161,6 +162,9 @@ ret[j++] = g_strdup(config_dir); } + ret[j++] = g_strdup("--display"); + ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default())); + ret[j++] = NULL; return ret;
--- a/pidgin/pixmaps/dialogs/64/scalable/cool.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/cool.svg Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/error.svg Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/info.svg Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/question.svg Fri Sep 28 16:34:43 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 Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/dialogs/64/scalable/warning.svg Fri Sep 28 16:34:43 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" + 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 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)" /> + id="path3228" + sodipodi:cx="21.5625" + sodipodi:cy="33.892857" + sodipodi:rx="2.4553571" + sodipodi:ry="1.9642857" + d="M 24.017857 33.892857 A 2.4553571 1.9642857 0 1 1 19.107143,33.892857 A 2.4553571 1.9642857 0 1 1 24.017857 33.892857 z" + transform="matrix(3.0545454,0,0,2.2909093,-41.363636,-42.145461)" /> <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="path2251" - sodipodi:cx="9.3754778" - sodipodi:cy="13.4881" - sodipodi:rx="6.1556172" - sodipodi:ry="6.1556172" - d="M 15.531095 13.4881 A 6.1556172 6.1556172 0 1 1 3.2198606,13.4881 A 6.1556172 6.1556172 0 1 1 15.531095 13.4881 z" - transform="matrix(0.97472,0,0,0.812266,11.86154,41.04407)" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> + style="opacity:1;fill:url(#linearGradient3185);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2206" + sodipodi:cx="21.5625" + sodipodi:cy="33.892857" + sodipodi:rx="2.4553571" + sodipodi:ry="1.9642857" + d="M 24.017857 33.892857 A 2.4553571 1.9642857 0 1 1 19.107143,33.892857 A 2.4553571 1.9642857 0 1 1 24.017857 33.892857 z" + transform="matrix(-3.0545454,0,0,2.2909093,90.363634,-42.145461)" /> </g> </svg>
--- a/pidgin/pixmaps/emblems/16/Makefile.am Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/emblems/16/Makefile.am Fri Sep 28 16:34:43 2007 +0000 @@ -1,6 +1,7 @@ SUBDIRS = scalable EXTRA_DIST = aol-client.png \ + birthday.png \ blocked.png \ bot.png \ external.png \ @@ -12,6 +13,7 @@ hiptop.png \ male.png \ mobile.png \ + music.png \ not-authorized.png \ operator.png \ qq-member.png \
--- a/pidgin/pixmaps/emblems/16/scalable/Makefile.am Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/emblems/16/scalable/Makefile.am Fri Sep 28 16:34:43 2007 +0000 @@ -7,6 +7,7 @@ game.svg \ male.svg \ mobile.svg \ + music.svg \ not-authorized.svg \ qq-member.svg \ secure.svg \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/emblems/16/scalable/music.svg Fri Sep 28 16:34:43 2007 +0000 @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.45" + sodipodi:modified="true" + version="1.0"> + <defs + id="defs4"> + <linearGradient + inkscape:collect="always" + id="linearGradient3185"> + <stop + style="stop-color:#4e9a06;stop-opacity:1;" + offset="0" + id="stop3187" /> + <stop + style="stop-color:#4e9a06;stop-opacity:0" + offset="1" + id="stop3189" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3177"> + <stop + style="stop-color:#4e9a06;stop-opacity:1;" + offset="0" + id="stop3179" /> + <stop + style="stop-color:#4e9a06;stop-opacity:0;" + offset="1" + id="stop3181" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3153"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3155" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3157" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3153" + id="linearGradient3159" + x1="2.5409546" + y1="10.048674" + x2="10.378205" + y2="15.928688" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3177" + id="radialGradient3183" + cx="5.2116022" + cy="8.4051199" + fx="5.2116022" + fy="8.4051199" + r="2.9404981" + gradientTransform="matrix(2.6050387,0,0,2.2888674,-8.415579,-10.767812)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3185" + id="radialGradient3191" + cx="5.1978397" + cy="8.4135866" + fx="5.1978397" + fy="8.4135866" + r="3.1428281" + gradientTransform="matrix(2.8202152,0,0,2.4999643,-9.461187,-12.455954)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="22.4" + inkscape:cx="19.784002" + inkscape:cy="11.848" + inkscape:document-units="px" + inkscape:current-layer="layer1" + width="16px" + height="16px" + showgrid="true" + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + sodipodi:type="arc" + style="opacity:1;fill:#555753;fill-opacity:1;stroke:#222728;stroke-width:1.14297926;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2160" + sodipodi:cx="6.4712896" + sodipodi:cy="14.484771" + sodipodi:rx="3.5986683" + sodipodi:ry="2.1781414" + d="M 10.069958 14.484771 A 3.5986683 2.1781414 0 1 1 2.8726213,14.484771 A 3.5986683 2.1781414 0 1 1 10.069958 14.484771 z" + transform="matrix(0.8336417,0,0,0.918214,4.1052631,-0.8001194)" /> + <rect + style="opacity:1;fill:#222728;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3143" + width="1" + height="12" + x="12" + y="1" + rx="0.18940361" + ry="0.20662212" /> + <path + style="fill:#222728;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 12.006464,3.0203051 L 11.981638,1 C 13.945163,1 17.837365,1.1548232 14.996311,7.9684328 C 15.596089,2.2547574 13.743811,3.0203051 12.006464,3.0203051 z " + id="rect3146" + sodipodi:nodetypes="cccc" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#555753;fill-opacity:1;stroke:url(#linearGradient3159);stroke-width:1.97969818;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3151" + sodipodi:cx="6.4712896" + sodipodi:cy="14.484771" + sodipodi:rx="3.5986683" + sodipodi:ry="2.1781414" + d="M 10.069958 14.484771 A 3.5986683 2.1781414 0 1 1 2.8726213,14.484771 A 3.5986683 2.1781414 0 1 1 10.069958 14.484771 z" + transform="matrix(0.5557611,0,0,0.4591071,5.903509,5.8499391)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:none;fill-opacity:1;stroke:url(#radialGradient3191);stroke-width:0.98568761;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3173" + sodipodi:cx="8.0970039" + sodipodi:cy="11.122857" + sodipodi:rx="4.3089318" + sodipodi:ry="3.5513175" + d="M 3.9729753,12.152015 A 4.3089318,3.5513175 0 0 1 9.0871283,7.6665672" + transform="matrix(1.0443424,0,0,0.9855497,-0.4560443,3.7870959e-2)" + sodipodi:start="2.8475788" + sodipodi:end="4.9442449" + sodipodi:open="true" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:none;fill-opacity:1;stroke:url(#radialGradient3183);stroke-width:0.58102763;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3175" + sodipodi:cx="8.0970039" + sodipodi:cy="11.122857" + sodipodi:rx="4.3089318" + sodipodi:ry="3.5513175" + d="M 3.9729753,12.152015 A 4.3089318,3.5513175 0 0 1 9.0871283,7.6665672" + transform="matrix(1.6981233,0,0,1.7443645,-5.9310642,-8.697544)" + sodipodi:start="2.8475788" + sodipodi:end="4.9442449" + sodipodi:open="true" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/protocols/22/scalable/myspace.svg Fri Sep 28 16:34:43 2007 +0000 @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="24" + height="24" + id="svg2160" + sodipodi:version="0.32" + inkscape:version="0.45" + sodipodi:docname="myspace48.svg" + sodipodi:docbase="/home/hbons/Desktop" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true" + version="1.0"> + <defs + id="defs2162"> + <linearGradient + inkscape:collect="always" + id="linearGradient3147"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3149" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3151" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3172"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3174" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3176" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3172" + id="linearGradient3178" + x1="10.549266" + y1="5.125" + x2="52.810349" + y2="49.864979" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3147" + id="linearGradient3153" + x1="6.0203052" + y1="1.0398448" + x2="26.101271" + y2="25.83909" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="9.8994949" + inkscape:cx="31.349135" + inkscape:cy="11.3794" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="3" + inkscape:window-y="25" + width="24px" + height="24px" /> + <metadata + id="metadata2165"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:#888a85;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 17 1.5 C 15.068 1.5 13.5 3.0680001 13.5 5 C 13.5 6.932 15.068 8.5 17 8.5 C 18.932 8.5 20.499999 6.932 20.5 5 C 20.5 3.068 18.931999 1.4999999 17 1.5 z M 10.5 2.5 C 8.8439999 2.5 7.5000001 3.8439999 7.5 5.5 C 7.5 7.1559999 8.8439997 8.4999996 10.5 8.5 C 9.395701 8.5527352 8.4448563 9.5454035 7.875 10.4375 C 7.830859 8.7148111 7.161553 7.5791344 5.6875 7.5 C 6.7035586 7.4052513 7.5 6.5406823 7.5 5.5 C 7.5 4.396 6.604 3.5 5.5 3.5 C 4.396 3.5 3.4999999 4.396 3.5 5.5 C 3.5 6.5828941 4.3626534 7.4666427 5.4375 7.5 C 4.352857 7.6401732 3.5000005 8.6243123 3.5 9.875 L 3.5 14.53125 L 7.5625 14.53125 L 7.5625 18.53125 L 12.5 18.53125 L 12.5 22.5 L 21.5 22.5 C 21.499867 19.408873 21.5 16.303843 21.5 13.21875 C 21.5 10.634939 19.434134 8.53125 16.875 8.53125 C 15.587036 8.5312503 14.40291 9.424387 13.5625 10.28125 C 13.046577 9.1148819 11.916283 8.5 10.59375 8.5 C 12.205095 8.4489386 13.5 7.1236737 13.5 5.5 C 13.5 3.8440001 12.156 2.5 10.5 2.5 z " + id="path3149" /> + <path + sodipodi:type="inkscape:offset" + inkscape:radius="-1.00878" + inkscape:original="M 17 1.5 C 15.068 1.5 13.5 3.0680001 13.5 5 C 13.5 6.932 15.068 8.5 17 8.5 C 18.932 8.5 20.499999 6.932 20.5 5 C 20.5 3.068 18.931999 1.4999999 17 1.5 z M 10.5 2.5 C 8.8439999 2.5 7.5000001 3.8439999 7.5 5.5 C 7.5 7.1559999 8.8439997 8.4999996 10.5 8.5 C 9.395701 8.5527352 8.4448563 9.5454035 7.875 10.4375 C 7.830859 8.7148111 7.161553 7.5791344 5.6875 7.5 C 6.7035586 7.4052513 7.5 6.5406823 7.5 5.5 C 7.5 4.396 6.604 3.5 5.5 3.5 C 4.396 3.5 3.4999999 4.396 3.5 5.5 C 3.5 6.5828941 4.3626534 7.4666427 5.4375 7.5 C 4.352857 7.6401732 3.5000005 8.6243123 3.5 9.875 L 3.5 14.53125 L 7.5625 14.53125 L 7.5625 18.53125 L 12.5 18.53125 L 12.5 22.5 L 21.5 22.5 C 21.499867 19.408873 21.5 16.303843 21.5 13.21875 C 21.5 10.634939 19.434134 8.53125 16.875 8.53125 C 15.587036 8.5312503 14.40291 9.424387 13.5625 10.28125 C 13.046577 9.1148819 11.916283 8.5 10.59375 8.5 C 12.205095 8.4489386 13.5 7.1236737 13.5 5.5 C 13.5 3.8440001 12.156 2.5 10.5 2.5 z " + style="opacity:1;fill:url(#linearGradient3153);fill-opacity:1.0;stroke:#ffffff;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2174" + d="M 17,2.5 C 15.613813,2.5 14.5,3.6138135 14.5,5 C 14.5,6.3861867 15.613813,7.5 17,7.5 C 18.386187,7.5 19.499999,6.3861873 19.5,5 C 19.5,3.6138137 18.386185,2.4999999 17,2.5 z M 10.5,3.5 C 9.3898132,3.5 8.5000001,4.3898131 8.5,5.5 C 8.5,6.5997176 9.3733703,7.4835976 10.46875,7.5 C 10.499983,7.4985473 10.531267,7.4985473 10.5625,7.5 C 10.572807,7.4996734 10.583484,7.5004795 10.59375,7.5 C 11.655314,7.4504166 12.5,6.5769144 12.5,5.5 C 12.5,4.3898135 11.610187,3.5 10.5,3.5 z M 5.5,4.5 C 4.9418133,4.5 4.4999999,4.9418134 4.5,5.5 C 4.5,6.0471523 4.9293308,6.4832594 5.46875,6.5 C 5.4999831,6.4985473 5.5312669,6.4985473 5.5625,6.5 C 5.572916,6.4998387 5.583334,6.4998387 5.59375,6.5 C 6.0934659,6.4534009 6.5,6.0259981 6.5,5.5 C 6.5,4.9418133 6.0581867,4.5 5.5,4.5 z M 5.53125,8.5 C 4.98621,8.5848564 4.5000003,9.0959604 4.5,9.875 L 4.5,13.53125 L 7.5625,13.53125 C 8.1127746,13.536073 8.557677,13.980975 8.5625,14.53125 L 8.5625,17.53125 L 12.5,17.53125 C 13.050275,17.536073 13.495177,17.980975 13.5,18.53125 L 13.5,21.5 L 20.5,21.5 C 20.499928,18.739558 20.5,15.971417 20.5,13.21875 C 20.5,11.172647 18.881301,9.53125 16.875,9.53125 C 16.053394,9.5312502 15.035346,10.231141 14.28125,11 C 14.045303,11.244024 13.70246,11.353041 13.368907,11.290106 C 13.035354,11.227172 12.755806,11.000722 12.625,10.6875 C 12.280526,9.9087333 11.615906,9.5089368 10.625,9.5 C 10.614584,9.5001613 10.604166,9.5001613 10.59375,9.5 C 10.583334,9.5001613 10.572916,9.5001613 10.5625,9.5 C 10.033117,9.5252804 9.1973144,10.219569 8.71875,10.96875 C 8.4774641,11.327111 8.0347855,11.49207 7.6178253,11.378996 C 7.2008651,11.265922 6.9021772,10.899915 6.875,10.46875 C 6.8561284,9.7322475 6.6929787,9.2126452 6.5,8.9375 C 6.312535,8.6702161 6.1126513,8.5308317 5.65625,8.5 C 5.645834,8.5001613 5.635416,8.5001613 5.625,8.5 C 5.5937669,8.5014527 5.5624831,8.5014527 5.53125,8.5 L 5.53125,8.5 z " /> + </g> +</svg>
--- a/pidgin/pixmaps/status/16/scalable/available.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/available.svg Fri Sep 28 16:34:43 2007 +0000 @@ -13,13 +13,15 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.44.1" + inkscape:version="0.45" version="1.0" inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/available.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" - sodipodi:docname="available.svg"> + sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" + sodipodi:docname="available.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient @@ -246,7 +248,7 @@ inkscape:window-width="1274" inkscape:window-height="844" inkscape:window-x="3" - inkscape:window-y="0" /> + inkscape:window-y="25" /> <metadata id="metadata7"> <rdf:RDF> @@ -263,16 +265,6 @@ 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="path2969" - style="color:black;fill:url(#radialGradient3025);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(0.923568,0,0,0.173169,-20.73469,11.2083)" /> - <path transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)" style="fill:url(#linearGradient4738);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:1.85770929;stroke-miterlimit:4;stroke-opacity:1" d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z "
--- a/pidgin/pixmaps/status/16/scalable/away.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/away.svg Fri Sep 28 16:34:43 2007 +0000 @@ -13,13 +13,15 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.44.1" + inkscape:version="0.45" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/status/16/scalable" - sodipodi:docname="away.svg"> + sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" + sodipodi:docname="away.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient @@ -123,8 +125,8 @@ fill="#eeeeec" inkscape:window-width="1434" inkscape:window-height="840" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-x="3" + inkscape:window-y="25" inkscape:object-paths="false" inkscape:grid-bbox="true" inkscape:guide-bbox="false" @@ -145,16 +147,6 @@ 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:1;color:black;fill:url(#radialGradient2818);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(0.923568,0,0,0.173169,-20.73469,11.2083)" /> - <path sodipodi:type="arc" style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.91314828px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1339"
--- a/pidgin/pixmaps/status/16/scalable/busy.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/busy.svg Fri Sep 28 16:34:43 2007 +0000 @@ -13,13 +13,15 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.44.1" + inkscape:version="0.45" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" - sodipodi:docname="busy.svg"> + sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" + sodipodi:docname="busy.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient @@ -192,8 +194,8 @@ fill="#eeeeec" inkscape:window-width="1268" inkscape:window-height="844" - inkscape:window-x="6" - inkscape:window-y="0" /> + inkscape:window-x="3" + inkscape:window-y="25" /> <metadata id="metadata7"> <rdf:RDF> @@ -210,16 +212,6 @@ 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="path2969" - style="color:black;fill:url(#radialGradient3025);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(0.923568,0,0,0.173169,-20.73469,11.2083)" /> - <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"
--- a/pidgin/pixmaps/status/16/scalable/extended-away.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/extended-away.svg Fri Sep 28 16:34:43 2007 +0000 @@ -13,12 +13,14 @@ height="16px" id="svg4245" sodipodi:version="0.32" - inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/status/16/scalable" + inkscape:version="0.45" + sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" sodipodi:docname="extended-away.svg" inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/extended-away.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="defs4247"> <linearGradient @@ -53,16 +55,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="22.197802" - inkscape:cx="8" - inkscape:cy="9.6246122" + inkscape:cx="14.39703" + inkscape:cy="8.273127" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="872" - inkscape:window-height="626" - inkscape:window-x="129" - inkscape:window-y="124" /> + inkscape:window-width="1440" + inkscape:window-height="847" + inkscape:window-x="0" + inkscape:window-y="22" /> <metadata id="metadata4250"> <rdf:RDF> @@ -79,27 +81,17 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> <path - sodipodi:type="arc" - style="fill:url(#radialGradient5300);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81530744;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5131" - sodipodi:cx="11.756953" - sodipodi:cy="17.588654" - sodipodi:rx="6.3436799" - sodipodi:ry="3.9753728" - d="M 18.100633 17.588654 A 6.3436799 3.9753728 0 1 1 5.4132733,17.588654 A 6.3436799 3.9753728 0 1 1 18.100633 17.588654 z" - transform="matrix(-1.024642,0,0,0.754646,19.54667,-0.273206)" /> - <path - transform="matrix(-1.708738,0,0,1.647118,-1.878642,-0.867731)" style="fill:#fce94f;fill-opacity:1;stroke:#ce5c00;stroke-width:0.59607363;stroke-miterlimit:4;stroke-opacity:1" d="M -9,3.2233667 L -7.134588,1.4374993 L -2.89508,1.4374993 C -2.3096744,1.4374993 -1.9824877,1.8329068 -1.9824877,2.3263196 L -1.9824877,9.3300741 L -9,9.3300741 L -9,3.2233667 z " id="rect5097" - sodipodi:nodetypes="ccccccc" /> + sodipodi:nodetypes="ccccccc" + transform="matrix(-1.708738,0,0,1.647118,-1.878642,-0.867731)" /> <path - transform="matrix(-1.398059,0,0,1.342047,-8.253506e-2,0.574281)" style="opacity:0.5625;fill:none;fill-opacity:1;stroke:#eeeeec;stroke-width:0.7300511;stroke-miterlimit:4;stroke-opacity:1" d="M -8.9656284,3.1521999 L -7.1361003,1.4267646 L -1.8535964,1.4374993 L -1.8535964,9.6313422 L -9,9.6313422 L -8.9656284,3.1521999 z " id="rect5099" - sodipodi:nodetypes="cccccc" /> + sodipodi:nodetypes="cccccc" + transform="matrix(-1.398059,0,0,1.342047,-8.253506e-2,0.574281)" /> <rect style="opacity:0.4;fill:#ce5c00;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect5988"
--- a/pidgin/pixmaps/status/16/scalable/offline.svg Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/offline.svg Fri Sep 28 16:34:43 2007 +0000 @@ -13,13 +13,15 @@ height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.44.1" + inkscape:version="0.45" version="1.0" inkscape:export-filename="/home/hbons/Desktop/offline.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" - sodipodi:docname="offline.svg"> + sodipodi:docbase="/home/hbons/Desktop/2.1.1/status/16/scalable" + sodipodi:docname="offline.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:modified="true"> <defs id="defs4"> <linearGradient @@ -168,8 +170,8 @@ fill="#eeeeec" inkscape:window-width="1434" inkscape:window-height="844" - inkscape:window-x="0" - inkscape:window-y="0" /> + inkscape:window-x="3" + inkscape:window-y="25" /> <metadata id="metadata7"> <rdf:RDF> @@ -186,16 +188,6 @@ 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.7;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(0.923568,0,0,0.288615,-20.73469,8.013827)" /> - <path style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999827;stroke-miterlimit:4;stroke-opacity:1" d="M 13.307074,13.307079 C 10.376958,16.237198 5.6213214,16.237693 2.6918157,13.308187 C -0.23769028,10.378679 -0.23719421,5.623042 2.692923,2.6929237 C 5.62304,-0.23719442 10.378675,-0.23769056 13.308181,2.6918165 C 16.237687,5.6213234 16.237192,10.376962 13.307074,13.307079 z " id="path2187" />
--- a/pidgin/plugins/history.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/plugins/history.c Fri Sep 28 16:34:43 2007 +0000 @@ -45,6 +45,9 @@ convtype = purple_conversation_get_type(c); gtkconv = PIDGIN_CONVERSATION(c); + if (gtkconv == NULL) + return; + if (convtype == PURPLE_CONV_TYPE_IM && g_list_length(gtkconv->convs) < 2) { GSList *buddies; @@ -163,6 +166,7 @@ purple_signal_connect(purple_conversations_get_handle(), "conversation-created", plugin, PURPLE_CALLBACK(historize), NULL); + /* XXX: Do we want to listen to pidgin's "conversation-displayed" signal? */ purple_prefs_connect_callback(plugin, "/purple/logging/log_ims", history_prefs_cb, plugin);
--- a/pidgin/plugins/pidginrc.c Fri Sep 28 16:32:28 2007 +0000 +++ b/pidgin/plugins/pidginrc.c Fri Sep 28 16:34:43 2007 +0000 @@ -57,22 +57,16 @@ static const gchar *font_prefs[] = { "/plugins/gtk/purplerc/font/*pidgin_conv_entry", - "/plugins/gtk/purplerc/font/*pidgin_conv_imhtml", - "/plugins/gtk/purplerc/font/*pidgin_log_imhtml", "/plugins/gtk/purplerc/font/*pidgin_request_imhtml", "/plugins/gtk/purplerc/font/*pidgin_notify_imhtml", }; static const gchar *font_prefs_set[] = { "/plugins/gtk/purplerc/set/font/*pidgin_conv_entry", - "/plugins/gtk/purplerc/set/font/*pidgin_conv_imhtml", - "/plugins/gtk/purplerc/set/font/*pidgin_log_imhtml", "/plugins/gtk/purplerc/set/font/*pidgin_request_imhtml", "/plugins/gtk/purplerc/set/font/*pidgin_notify_imhtml", }; static const gchar *font_names[] = { N_("Conversation Entry"), - N_("Conversation History"), - N_("Log Viewer"), N_("Request Dialog"), N_("Notify Dialog") };
--- a/po/POTFILES.in Fri Sep 28 16:32:28 2007 +0000 +++ b/po/POTFILES.in Fri Sep 28 16:34:43 2007 +0000 @@ -91,11 +91,13 @@ libpurple/protocols/jabber/usermood.c libpurple/protocols/jabber/usernick.c libpurple/protocols/jabber/xdata.c +libpurple/protocols/msn/contact.c libpurple/protocols/msn/dialog.c libpurple/protocols/msn/error.c libpurple/protocols/msn/msn.c libpurple/protocols/msn/nexus.c libpurple/protocols/msn/notification.c +libpurple/protocols/msn/oim.c libpurple/protocols/msn/servconn.c libpurple/protocols/msn/session.c libpurple/protocols/msn/state.c