Mercurial > pidgin.yaz
changeset 22195:6419554aadd9
merge of '7a2d6f31a70791d5e6e8af6fae041e30d5a1c48f'
and 'a0479b7ebd8713b6442fb2ecb8238b7e71be61b5'
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Fri, 25 Jan 2008 00:51:06 +0000 |
parents | 17e21fa1db57 (diff) 252b96b6a32c (current diff) |
children | 6c7cf4654d10 |
files | ChangeLog.API libpurple/protocols/myspace/myspace.c libpurple/protocols/oscar/flap_connection.c |
diffstat | 24 files changed, 1090 insertions(+), 322 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Jan 23 23:28:38 2008 +0000 +++ b/ChangeLog Fri Jan 25 00:51:06 2008 +0000 @@ -35,6 +35,9 @@ * Recently signed on (or off) buddies blink in the buddy list. * New action 'Room List' in the action list can be used to get the list of available chat rooms for an online account. + * The 'Grouping' plugin can be used for alternate grouping in the + buddylist. The current options are 'Group Online/Offline' and 'No + Group'. version 2.3.1 (12/7/2007): http://developer.pidgin.im/query?status=closed&milestone=2.3.1
--- a/ChangeLog.API Wed Jan 23 23:28:38 2008 +0000 +++ b/ChangeLog.API Fri Jan 25 00:51:06 2008 +0000 @@ -30,8 +30,11 @@ * purple_attention_type_get_outgoing_desc * purple_attention_type_get_icon_name * purple_attention_type_get_unlocalized_name - * last_received to PurpleAccount, the time_t of the last - received packet + * Add some PurpleBuddyListNode accessor functions: + * purple_blist_node_get_parent + * purple_blist_node_get_first_child + * purple_blist_node_get_sibling_next + * purple_chat_get_account Pidgin: Added: @@ -67,6 +70,7 @@ string. * Added gnt_style_get_color to get a color pair from an entry in ~/.gntrc + * Added gnt_tree_get_parent_key to get the key for the parent row. version 2.3.0 (11/24/2007): libpurple:
--- a/finch/gntblist.c Wed Jan 23 23:28:38 2008 +0000 +++ b/finch/gntblist.c Fri Jan 25 00:51:06 2008 +0000 @@ -81,6 +81,9 @@ /* These are the menuitems that get regenerated */ GntMenuItem *accounts; GntMenuItem *plugins; + GntMenuItem *grouping; + + FinchBlistManager *manager; } FinchBlist; typedef struct @@ -115,7 +118,12 @@ static void add_chat(PurpleChat *chat, FinchBlist *ggblist); static void add_node(PurpleBlistNode *node, FinchBlist *ggblist); static void node_update(PurpleBuddyList *list, PurpleBlistNode *node); +#if 0 +static gboolean is_contact_online(PurpleContact *contact); +static gboolean is_group_online(PurpleGroup *group); +#endif static void draw_tooltip(FinchBlist *ggblist); +static void tooltip_for_buddy(PurpleBuddy *buddy, GString *str, gboolean full); static gboolean remove_typing_cb(gpointer null); static void remove_peripherals(FinchBlist *ggblist); static const char * get_display_name(PurpleBlistNode *node); @@ -125,6 +133,7 @@ static void update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist); static void account_signed_on_cb(PurpleConnection *pc, gpointer null); static void finch_request_add_buddy(PurpleAccount *account, const char *username, const char *grp, const char *alias); +static void menu_group_set_cb(GntMenuItem *item, gpointer null); /* Sort functions */ static int blist_node_compare_position(PurpleBlistNode *n1, PurpleBlistNode *n2); @@ -137,6 +146,168 @@ static int color_offline; static int color_idle; +/** + * Buddy List Manager functions. + */ + +static gboolean default_can_add_node(PurpleBlistNode *node) +{ + gboolean offline = purple_prefs_get_bool(PREF_ROOT "/showoffline"); + + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { + PurpleBuddy *buddy = (PurpleBuddy*)node; + FinchBlistNode *fnode = node->ui_data; + if (!purple_buddy_get_contact(buddy)) + return FALSE; /* When a new buddy is added and show-offline is set */ + if (PURPLE_BUDDY_IS_ONLINE(buddy)) + return TRUE; /* The buddy is online */ + if (!purple_account_is_connected(purple_buddy_get_account(buddy))) + return FALSE; /* The account is disconnected. Do not show */ + if (offline) + return TRUE; /* We want to see offline buddies too */ + if (fnode && fnode->signed_timer) + return TRUE; /* Show if the buddy just signed off */ + } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { + PurpleBlistNode *nd; + for (nd = purple_blist_node_get_first_child(node); + nd; nd = purple_blist_node_get_sibling_next(nd)) { + if (default_can_add_node(nd)) + return TRUE; + } + } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { + PurpleChat *chat = (PurpleChat*)node; + if (purple_account_is_connected(purple_chat_get_account(chat))) + return TRUE; /* Show whenever the account is online */ + } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { + PurpleBlistNode *nd; + gboolean empty = purple_prefs_get_bool(PREF_ROOT "/emptygroups"); + if (empty) + return TRUE; /* If we want to see empty groups, we can show any group */ + + for (nd = purple_blist_node_get_first_child(node); + nd; nd = purple_blist_node_get_sibling_next(nd)) { + if (default_can_add_node(nd)) + return TRUE; + } + } + + return FALSE; +} + +static gpointer default_find_parent(PurpleBlistNode *node) +{ + gpointer ret = NULL; + switch (purple_blist_node_get_type(node)) { + case PURPLE_BLIST_BUDDY_NODE: + case PURPLE_BLIST_CONTACT_NODE: + case PURPLE_BLIST_CHAT_NODE: + ret = purple_blist_node_get_parent(node); + break; + default: + break; + } + if (ret) + add_node(ret, ggblist); + return ret; +} + +static gboolean default_create_tooltip(gpointer selected_row, GString **body, char **tool_title) +{ + GString *str; + PurpleBlistNode *node = selected_row; + int lastseen = 0; + char *title; + + if (!node || + purple_blist_node_get_type(node) == PURPLE_BLIST_OTHER_NODE) + return FALSE; + + str = g_string_new(""); + + if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { + PurpleBuddy *pr = purple_contact_get_priority_buddy((PurpleContact*)node); + gboolean offline = !PURPLE_BUDDY_IS_ONLINE(pr); + gboolean showoffline = purple_prefs_get_bool(PREF_ROOT "/showoffline"); + const char *name = purple_buddy_get_name(pr); + + title = g_strdup(name); + tooltip_for_buddy(pr, str, TRUE); + for (node = purple_blist_node_get_first_child(node); node; node = purple_blist_node_get_sibling_next(node)) { + PurpleBuddy *buddy = (PurpleBuddy*)node; + if (offline) { + int value = purple_blist_node_get_int(node, "last_seen"); + if (value > lastseen) + lastseen = value; + } + if (node == (PurpleBlistNode*)pr) + continue; + if (!purple_account_is_connected(buddy->account)) + continue; + if (!showoffline && !PURPLE_BUDDY_IS_ONLINE(buddy)) + continue; + str = g_string_append(str, "\n----------\n"); + tooltip_for_buddy(buddy, str, FALSE); + } + } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { + PurpleBuddy *buddy = (PurpleBuddy *)node; + tooltip_for_buddy(buddy, str, TRUE); + title = g_strdup(purple_buddy_get_name(buddy)); + if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node)) + lastseen = purple_blist_node_get_int(node, "last_seen"); + } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { + PurpleGroup *group = (PurpleGroup *)node; + + g_string_append_printf(str, _("Online: %d\nTotal: %d"), + purple_blist_get_group_online_count(group), + purple_blist_get_group_size(group, FALSE)); + + title = g_strdup(group->name); + } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { + PurpleChat *chat = (PurpleChat *)node; + PurpleAccount *account = chat->account; + + g_string_append_printf(str, _("Account: %s (%s)"), + purple_account_get_username(account), + purple_account_get_protocol_name(account)); + + title = g_strdup(purple_chat_get_name(chat)); + } else { + g_string_free(str, TRUE); + return FALSE; + } + + if (lastseen > 0) { + char *tmp = purple_str_seconds_to_string(time(NULL) - lastseen); + g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp); + g_free(tmp); + } + + if (tool_title) + *tool_title = title; + else + g_free(title); + + if (body) + *body = str; + else + g_string_free(str, TRUE); + + return TRUE; +} + +static FinchBlistManager default_manager = +{ + "default", + N_("Default"), + NULL, + NULL, + default_can_add_node, + default_find_parent, + default_create_tooltip, + {NULL, NULL, NULL, NULL} +}; +static GList *managers; + static FinchBlistNode * create_finch_blist_node(PurpleBlistNode *node, gpointer row) { @@ -216,12 +387,16 @@ gnt_tree_set_row_color(GNT_TREE(ggblist->tree), node, get_display_color(node)); } +#if 0 static gboolean is_contact_online(PurpleContact *contact) { PurpleBlistNode *node; - for (node = ((PurpleBlistNode*)contact)->child; node; node = node->next) { - if (PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node)) + for (node = purple_blist_node_get_first_child(((PurpleBlistNode*)contact)); node; + node = purple_blist_node_get_sibling_next(node)) { + FinchBlistNode *fnode = node->ui_data; + if (PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node) || + (fnode && fnode->signed_timer)) return TRUE; } return FALSE; @@ -231,7 +406,8 @@ is_group_online(PurpleGroup *group) { PurpleBlistNode *node; - for (node = ((PurpleBlistNode*)group)->child; node; node = node->next) { + for (node = purple_blist_node_get_first_child(((PurpleBlistNode*)group)); node; + node = purple_blist_node_get_sibling_next(node)) { if (PURPLE_BLIST_NODE_IS_CHAT(node) && purple_account_is_connected(((PurpleChat *)node)->account)) return TRUE; @@ -240,14 +416,22 @@ } return FALSE; } +#endif static void new_node(PurpleBlistNode *node) { } -static void add_node(PurpleBlistNode *node, FinchBlist *ggblist) +static void +add_node(PurpleBlistNode *node, FinchBlist *ggblist) { + if (node->ui_data) + return; + + if (!ggblist->manager->can_add_node(node)) + return; + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) add_buddy((PurpleBuddy*)node, ggblist); else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) @@ -256,9 +440,15 @@ add_group((PurpleGroup*)node, ggblist); else if (PURPLE_BLIST_NODE_IS_CHAT(node)) add_chat((PurpleChat *)node, ggblist); + draw_tooltip(ggblist); } +void finch_blist_manager_add_node(PurpleBlistNode *node) +{ + add_node(node, ggblist); +} + static void remove_tooltip(FinchBlist *ggblist) { @@ -271,6 +461,7 @@ node_remove(PurpleBuddyList *list, PurpleBlistNode *node) { FinchBlist *ggblist = list->ui_data; + PurpleBlistNode *parent; if (ggblist == NULL || node->ui_data == NULL) return; @@ -280,23 +471,16 @@ if (ggblist->tagged) ggblist->tagged = g_list_remove(ggblist->tagged, node); - if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { - PurpleContact *contact = (PurpleContact*)node->parent; - if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || - contact->currentsize < 1) - node_remove(list, (PurpleBlistNode*)contact); + parent = purple_blist_node_get_parent(node); + for (node = purple_blist_node_get_first_child(node); node; + node = purple_blist_node_get_sibling_next(node)) + node_remove(list, node); + + if (parent) { + if (!ggblist->manager->can_add_node(parent)) + node_remove(list, parent); else - node_update(list, (PurpleBlistNode*)contact); - } else if (!PURPLE_BLIST_NODE_IS_GROUP(node)) { - PurpleGroup *group = (PurpleGroup*)node->parent; - if ((group->currentsize < 1 && !purple_prefs_get_bool(PREF_ROOT "/emptygroups")) || - (!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group))) - node_remove(list, node->parent); - for (node = node->child; node; node = node->next) - reset_blist_node_ui_data(node); - } else { - for (node = node->child; node; node = node->next) - node_remove(list, node); + node_update(list, parent); } draw_tooltip(ggblist); @@ -321,34 +505,25 @@ 0, get_display_name(node)); gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); blist_update_row_flags(node); + if (gnt_tree_get_parent_key(GNT_TREE(ggblist->tree), node) != + ggblist->manager->find_parent(node)) + node_remove(list, node); } if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { PurpleBuddy *buddy = (PurpleBuddy*)node; - if (purple_account_is_connected(buddy->account) && - (PURPLE_BUDDY_IS_ONLINE(buddy) || purple_prefs_get_bool(PREF_ROOT "/showoffline"))) - add_node((PurpleBlistNode*)buddy, list->ui_data); - - node_update(list, node->parent); + add_node((PurpleBlistNode*)buddy, list->ui_data); + node_update(list, purple_blist_node_get_parent(node)); } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { - add_chat((PurpleChat *)node, list->ui_data); + add_node(node, list->ui_data); } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { - PurpleContact *contact = (PurpleContact*)node; - if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || - contact->currentsize < 1) - /* nothing */; - else { - if (node->ui_data == NULL) { - /* The core seems to expect the UI to add the buddies. */ - for (node = node->child; node; node = node->next) - add_node(node, list->ui_data); - } + if (node->ui_data == NULL) { + /* The core seems to expect the UI to add the buddies. */ + for (node = purple_blist_node_get_first_child(node); node; node = purple_blist_node_get_sibling_next(node)) + add_node(node, list->ui_data); } } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { - PurpleGroup *group = (PurpleGroup*)node; - if (!purple_prefs_get_bool(PREF_ROOT "/emptygroups") && - ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || - group->currentsize < 1)) + if (!ggblist->manager->can_add_node(node)) node_remove(list, node); else add_node(node, list->ui_data); @@ -363,6 +538,9 @@ ggblist = g_new0(FinchBlist, 1); list->ui_data = ggblist; + ggblist->manager = finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT "/grouping")); + if (!ggblist->manager) + ggblist->manager = &default_manager; } static void @@ -399,6 +577,8 @@ purple_blist_add_group(grp, NULL); } + /* XXX: Ask if there's already the same buddy in the same group (#4553) */ + buddy = purple_buddy_new(account, username, alias); purple_blist_add_buddy(buddy, NULL, grp, NULL); purple_account_add_buddy(account, buddy); @@ -578,11 +758,14 @@ static void add_group(PurpleGroup *group, FinchBlist *ggblist) { + gpointer parent; PurpleBlistNode *node = (PurpleBlistNode *)group; if (node->ui_data) return; + parent = ggblist->manager->find_parent((PurpleBlistNode*)group); create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group, - gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), NULL, NULL)); + gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), + parent, NULL)); gnt_tree_set_expanded(GNT_TREE(ggblist->tree), node, !purple_blist_node_get_bool(node, "collapsed")); } @@ -648,25 +831,24 @@ static void add_chat(PurpleChat *chat, FinchBlist *ggblist) { - PurpleGroup *group; + gpointer parent; PurpleBlistNode *node = (PurpleBlistNode *)chat; if (node->ui_data) return; if (!purple_account_is_connected(chat->account)) return; - group = purple_chat_get_group(chat); - add_node((PurpleBlistNode*)group, ggblist); + parent = ggblist->manager->find_parent((PurpleBlistNode*)chat); create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), chat, gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), - group, NULL)); + parent, NULL)); } static void add_contact(PurpleContact *contact, FinchBlist *ggblist) { - PurpleGroup *group; + gpointer parent; PurpleBlistNode *node = (PurpleBlistNode*)contact; const char *name; @@ -677,12 +859,11 @@ if (name == NULL) return; - group = (PurpleGroup*)node->parent; - add_node((PurpleBlistNode*)group, ggblist); + parent = ggblist->manager->find_parent((PurpleBlistNode*)contact); create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), contact, gnt_tree_create_row(GNT_TREE(ggblist->tree), name), - group, NULL)); + parent, NULL)); gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE); } @@ -690,23 +871,19 @@ static void add_buddy(PurpleBuddy *buddy, FinchBlist *ggblist) { + gpointer parent; + PurpleBlistNode *node = (PurpleBlistNode *)buddy; PurpleContact *contact; - PurpleBlistNode *node = (PurpleBlistNode *)buddy; if (node->ui_data) return; - if (!purple_account_is_connected(buddy->account)) - return; - - contact = (PurpleContact*)node->parent; - if (!contact) /* When a new buddy is added and show-offline is set */ - return; - add_node((PurpleBlistNode*)contact, ggblist); + contact = purple_buddy_get_contact(buddy); + parent = ggblist->manager->find_parent((PurpleBlistNode*)buddy); create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), buddy, gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), - contact, NULL)); + parent, NULL)); blist_update_row_flags((PurpleBlistNode*)buddy); if (buddy == purple_contact_get_priority_buddy(contact)) @@ -1035,8 +1212,8 @@ PurpleGroup *group; cnode = (PurpleBlistNode *)contact; - group = (PurpleGroup*)cnode->parent; - for (bnode = cnode->child; bnode; bnode = bnode->next) { + group = (PurpleGroup*)purple_blist_node_get_parent(cnode); + for (bnode = purple_blist_node_get_first_child(cnode); bnode; bnode = purple_blist_node_get_sibling_next(bnode)) { PurpleBuddy *buddy = (PurpleBuddy*)bnode; if (purple_account_is_connected(buddy->account)) purple_account_remove_buddy(buddy->account, buddy, group); @@ -1104,32 +1281,32 @@ { PurpleBlistNode *cnode, *bnode; - cnode = ((PurpleBlistNode*)group)->child; + cnode = purple_blist_node_get_first_child(((PurpleBlistNode*)group)); while (cnode) { if (PURPLE_BLIST_NODE_IS_CONTACT(cnode)) { - bnode = cnode->child; - cnode = cnode->next; + bnode = purple_blist_node_get_first_child(cnode); + cnode = purple_blist_node_get_sibling_next(cnode); while (bnode) { PurpleBuddy *buddy; if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) { buddy = (PurpleBuddy*)bnode; - bnode = bnode->next; + bnode = purple_blist_node_get_sibling_next(bnode); if (purple_account_is_connected(buddy->account)) { purple_account_remove_buddy(buddy->account, buddy, group); purple_blist_remove_buddy(buddy); } } else { - bnode = bnode->next; + bnode = purple_blist_node_get_sibling_next(bnode); } } } else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) { PurpleChat *chat = (PurpleChat *)cnode; - cnode = cnode->next; + cnode = purple_blist_node_get_sibling_next(cnode); if (purple_account_is_connected(chat->account)) purple_blist_remove_chat(chat); } else { - cnode = cnode->next; + cnode = purple_blist_node_get_sibling_next(cnode); } } @@ -1216,18 +1393,19 @@ PurpleGroup *tg = NULL; PurpleContact *tc = NULL; - if (target == NULL) + if (target == NULL || + purple_blist_node_get_type(target) == PURPLE_BLIST_OTHER_NODE) return; if (PURPLE_BLIST_NODE_IS_GROUP(target)) tg = (PurpleGroup*)target; else if (PURPLE_BLIST_NODE_IS_BUDDY(target)) { - tc = (PurpleContact*)target->parent; - tg = (PurpleGroup*)target->parent->parent; + tc = (PurpleContact*)purple_blist_node_get_parent(target); + tg = (PurpleGroup*)purple_blist_node_get_parent((PurpleBlistNode*)tc); } else { if (PURPLE_BLIST_NODE_IS_CONTACT(target)) tc = (PurpleContact*)target; - tg = (PurpleGroup*)target->parent; + tg = (PurpleGroup*)purple_blist_node_get_parent(target); } if (ggblist->tagged) { @@ -1300,6 +1478,8 @@ tree = GNT_TREE(ggblist->tree); node = gnt_tree_get_selection_data(tree); + if (node && purple_blist_node_get_type(node) == PURPLE_BLIST_OTHER_NODE) + return; if (ggblist->tooltip) remove_tooltip(ggblist); @@ -1393,7 +1573,7 @@ purple_account_get_protocol_name(account)); purple_notify_user_info_add_pair(user_info, _("Account"), tmp); g_free(tmp); - + prpl = purple_find_prpl(purple_account_get_protocol_id(account)); prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); if (prpl_info && prpl_info->tooltip_text) { @@ -1442,16 +1622,15 @@ { PurpleBlistNode *node; int x, y, top, width, w, h; - GString *str; + GString *str = NULL; GntTree *tree; GntWidget *widget, *box, *tv; char *title = NULL; - int lastseen = 0; widget = ggblist->tree; tree = GNT_TREE(widget); - if (!gnt_widget_has_focus(ggblist->tree) || + if (!gnt_widget_has_focus(ggblist->tree) || (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE))) return FALSE; @@ -1466,65 +1645,8 @@ if (!node) return FALSE; - str = g_string_new(""); - - if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { - PurpleBuddy *pr = purple_contact_get_priority_buddy((PurpleContact*)node); - gboolean offline = !PURPLE_BUDDY_IS_ONLINE(pr); - gboolean showoffline = purple_prefs_get_bool(PREF_ROOT "/showoffline"); - const char *name = purple_buddy_get_name(pr); - - title = g_strdup(name); - tooltip_for_buddy(pr, str, TRUE); - for (node = node->child; node; node = node->next) { - PurpleBuddy *buddy = (PurpleBuddy*)node; - if (offline) { - int value = purple_blist_node_get_int(node, "last_seen"); - if (value > lastseen) - lastseen = value; - } - if (node == (PurpleBlistNode*)pr) - continue; - if (!purple_account_is_connected(buddy->account)) - continue; - if (!showoffline && !PURPLE_BUDDY_IS_ONLINE(buddy)) - continue; - str = g_string_append(str, "\n----------\n"); - tooltip_for_buddy(buddy, str, FALSE); - } - } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { - PurpleBuddy *buddy = (PurpleBuddy *)node; - tooltip_for_buddy(buddy, str, TRUE); - title = g_strdup(purple_buddy_get_name(buddy)); - if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node)) - lastseen = purple_blist_node_get_int(node, "last_seen"); - } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { - PurpleGroup *group = (PurpleGroup *)node; - - g_string_append_printf(str, _("Online: %d\nTotal: %d"), - purple_blist_get_group_online_count(group), - purple_blist_get_group_size(group, FALSE)); - - title = g_strdup(group->name); - } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { - PurpleChat *chat = (PurpleChat *)node; - PurpleAccount *account = chat->account; - - g_string_append_printf(str, _("Account: %s (%s)"), - purple_account_get_username(account), - purple_account_get_protocol_name(account)); - - title = g_strdup(purple_chat_get_name(chat)); - } else { - g_string_free(str, TRUE); + if (!ggblist->manager->create_tooltip(node, &str, &title)) return FALSE; - } - - if (lastseen > 0) { - char *tmp = purple_str_seconds_to_string(time(NULL) - lastseen); - g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp); - g_free(tmp); - } gnt_widget_get_position(widget, &x, &y); gnt_widget_get_size(widget, &width, NULL); @@ -1707,6 +1829,9 @@ PurpleBlistNode *node; PurpleBuddyList *list; + if (ggblist->manager->init) + ggblist->manager->init(); + if (strcmp(purple_prefs_get_string(PREF_ROOT "/sort_type"), "text") == 0) { gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), (GCompareFunc)blist_node_compare_text); @@ -1794,11 +1919,33 @@ redraw_blist(const char *name, PurplePrefType type, gconstpointer val, gpointer data) { PurpleBlistNode *node, *sel; - if (ggblist == NULL || ggblist->window == NULL) + FinchBlistManager *manager; + + if (ggblist == NULL) + return; + + manager = finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT "/grouping")); + if (manager == NULL) + manager = &default_manager; + if (ggblist->manager != manager) { + if (ggblist->manager->uninit) + ggblist->manager->uninit(); + + ggblist->manager = manager; + if (manager->can_add_node == NULL) + manager->can_add_node = default_can_add_node; + if (manager->find_parent == NULL) + manager->find_parent = default_find_parent; + if (manager->create_tooltip == NULL) + manager->create_tooltip = default_create_tooltip; + } + + if (ggblist->window == NULL) return; sel = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)); gnt_tree_remove_all(GNT_TREE(ggblist->tree)); + node = purple_blist_get_root(); for (; node; node = purple_blist_node_next(node, TRUE)) reset_blist_node_ui_data(node); @@ -1833,6 +1980,7 @@ purple_prefs_add_bool(PREF_ROOT "/showoffline", FALSE); purple_prefs_add_bool(PREF_ROOT "/emptygroups", FALSE); purple_prefs_add_string(PREF_ROOT "/sort_type", "text"); + purple_prefs_add_string(PREF_ROOT "/grouping", "default"); purple_prefs_connect_callback(finch_blist_get_handle(), PREF_ROOT "/emptygroups", redraw_blist, NULL); @@ -1840,9 +1988,14 @@ PREF_ROOT "/showoffline", redraw_blist, NULL); purple_prefs_connect_callback(finch_blist_get_handle(), PREF_ROOT "/sort_type", redraw_blist, NULL); + purple_prefs_connect_callback(finch_blist_get_handle(), + PREF_ROOT "/grouping", redraw_blist, NULL); purple_signal_connect(purple_connections_get_handle(), "signed-on", purple_blist_get_handle(), G_CALLBACK(account_signed_on_cb), NULL); + + finch_blist_install_manager(&default_manager); + return; } @@ -2082,7 +2235,7 @@ int log = 0; PurpleBlistNode *node; - for (node = c->child; node; node = node->next) { + for (node = purple_blist_node_get_first_child(c); node; node = purple_blist_node_get_sibling_next(node)) { PurpleBuddy *b = (PurpleBuddy*)node; log += purple_log_get_total_size(PURPLE_LOG_IM, b->name, b->account); } @@ -2166,18 +2319,16 @@ { PurpleBlistNode *node = data; FinchBlistNode *fnode = node->ui_data; - PurpleBuddy *buddy = (PurpleBuddy*)node; purple_timeout_remove(fnode->signed_timer); fnode->signed_timer = 0; - if (!purple_account_is_connected(buddy->account) || - (!PURPLE_BUDDY_IS_ONLINE(buddy) && !purple_prefs_get_bool(PREF_ROOT "/showoffline"))) { + if (!ggblist->manager->can_add_node(node)) { node_remove(purple_get_blist(), node); } else { update_node_display(node, ggblist); - if (node->parent && PURPLE_BLIST_NODE_IS_CONTACT(node->parent)) - update_node_display(node->parent, ggblist); + if (purple_blist_node_get_parent(node) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node))) + update_node_display(purple_blist_node_get_parent(node), ggblist); } return FALSE; @@ -2195,8 +2346,8 @@ purple_timeout_remove(fnode->signed_timer); fnode->signed_timer = purple_timeout_add_seconds(6, (GSourceFunc)buddy_recent_signed_on_off, data); update_node_display(node, ggblist); - if (node->parent && PURPLE_BLIST_NODE_IS_CONTACT(node->parent)) - update_node_display(node->parent, ggblist); + if (purple_blist_node_get_parent(node) && PURPLE_BLIST_NODE_IS_CONTACT(purple_blist_node_get_parent(node))) + update_node_display(purple_blist_node_get_parent(node), ggblist); return FALSE; } @@ -2260,7 +2411,7 @@ PurpleAccount *account = iter->data; PurpleConnection *gc = purple_account_get_connection(account); PurplePlugin *prpl; - + if (!gc || !PURPLE_CONNECTION_IS_CONNECTED(gc)) continue; prpl = gc->prpl; @@ -2273,6 +2424,30 @@ } } +static void +reconstruct_grouping_menu(void) +{ + GList *iter; + GntWidget *subsub; + + if (!ggblist || !ggblist->grouping) + return; + + subsub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(ggblist->grouping, GNT_MENU(subsub)); + + for (iter = managers; iter; iter = iter->next) { + char menuid[128]; + FinchBlistManager *manager = iter->data; + GntMenuItem *item = gnt_menuitem_new(_(manager->name)); + snprintf(menuid, sizeof(menuid), "grouping-%s", manager->id); + gnt_menuitem_set_id(GNT_MENU_ITEM(item), menuid); + gnt_menu_add_item(GNT_MENU(subsub), item); + g_object_set_data_full(G_OBJECT(item), "grouping-id", g_strdup(manager->id), g_free); + gnt_menuitem_set_callback(item, menu_group_set_cb, NULL); + } +} + static gboolean auto_join_chats(gpointer data) { @@ -2439,6 +2614,13 @@ } static void +menu_group_set_cb(GntMenuItem *item, gpointer null) +{ + const char *id = g_object_get_data(G_OBJECT(item), "grouping-id"); + purple_prefs_set_string(PREF_ROOT "/grouping", id); +} + +static void create_menu(void) { GntWidget *menu, *sub, *subsub; @@ -2479,7 +2661,7 @@ purple_prefs_get_bool(PREF_ROOT "/emptygroups")); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/emptygroups"); - + item = gnt_menuitem_check_new(_("Offline buddies")); gnt_menuitem_set_id(GNT_MENU_ITEM(item), "show-offline-buddies"); gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), @@ -2513,21 +2695,25 @@ subsub = gnt_menu_new(GNT_MENU_POPUP); gnt_menuitem_set_submenu(item, GNT_MENU(subsub)); - item = gnt_menuitem_new("Buddy"); + item = gnt_menuitem_new(_("Buddy")); gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-buddy"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_buddy_cb, NULL); - item = gnt_menuitem_new("Chat"); + item = gnt_menuitem_new(_("Chat")); gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-chat"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_chat_cb, NULL); - item = gnt_menuitem_new("Group"); + item = gnt_menuitem_new(_("Group")); gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-group"); gnt_menu_add_item(GNT_MENU(subsub), item); gnt_menuitem_set_callback(item, menu_add_group_cb, NULL); + ggblist->grouping = item = gnt_menuitem_new(_("Grouping")); + gnt_menu_add_item(GNT_MENU(sub), item); + reconstruct_grouping_menu(); + reconstruct_accounts_menu(); gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts); @@ -2679,3 +2865,43 @@ { gnt_widget_set_size(ggblist->window, width, height); } + +void finch_blist_install_manager(const FinchBlistManager *manager) +{ + if (!g_list_find(managers, manager)) { + managers = g_list_append(managers, (gpointer)manager); + reconstruct_grouping_menu(); + if (strcmp(manager->id, purple_prefs_get_string(PREF_ROOT "/grouping")) == 0) + purple_prefs_trigger_callback(PREF_ROOT "/grouping"); + } +} + +void finch_blist_uninstall_manager(const FinchBlistManager *manager) +{ + if (g_list_find(managers, manager)) { + managers = g_list_remove(managers, manager); + reconstruct_grouping_menu(); + if (strcmp(manager->id, purple_prefs_get_string(PREF_ROOT "/grouping")) == 0) + purple_prefs_trigger_callback(PREF_ROOT "/grouping"); + } +} + +FinchBlistManager * finch_blist_manager_find(const char *id) +{ + GList *iter = managers; + if (!id) + return NULL; + + for (; iter; iter = iter->next) { + FinchBlistManager *m = iter->data; + if (strcmp(id, m->id) == 0) + return m; + } + return NULL; +} + +GntTree * finch_blist_get_tree(void) +{ + return ggblist ? GNT_TREE(ggblist->tree) : NULL; +} +
--- a/finch/gntblist.h Wed Jan 23 23:28:38 2008 +0000 +++ b/finch/gntblist.h Fri Jan 25 00:51:06 2008 +0000 @@ -27,12 +27,25 @@ #define _GNT_BLIST_H #include "blist.h" +#include "gnttree.h" /********************************************************************** * @name GNT BuddyList API **********************************************************************/ /*@{*/ +typedef struct +{ + const char *id; /**< An identifier for the manager. */ + const char *name; /**< Displayable name for the manager. */ + gboolean (*init)(void); /**< Called right before it's being used. */ + gboolean (*uninit)(void); /**< Called right after it's not being used any more. */ + gboolean (*can_add_node)(PurpleBlistNode *node); /**< Whether a node should be added to the view. */ + gpointer (*find_parent)(PurpleBlistNode *node); /**< Find the parent row for a node. */ + gboolean (*create_tooltip)(gpointer selected_row, GString **body, char **title); /**< Create tooltip for a selected row. */ + gpointer reserved[4]; +} FinchBlistManager; + /** * Get the ui-functions. * @@ -103,6 +116,47 @@ */ gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name); +/** + * Get the tree list of the buddy list. + * @return The GntTree widget. + * @since 2.4.0 + */ +GntTree * finch_blist_get_tree(void); + +/** + * Add an alternate buddy list manager. + * + * @param manager The alternate buddylist manager. + * @since 2.4.0 + */ +void finch_blist_install_manager(const FinchBlistManager *manager); + +/** + * Remove an alternate buddy list manager. + * + * @param manager The buddy list manager to remove. + * @since 2.4.0 + */ +void finch_blist_uninstall_manager(const FinchBlistManager *manager); + +/** + * Find a buddy list manager. + * + * @param id The identifier for the desired buddy list manager. + * + * @return The manager with the requested identifier, if available. @c NULL otherwise. + * @since 2.4.0 + */ +FinchBlistManager * finch_blist_manager_find(const char *id); + +/** + * Request the active buddy list manager to add a node. + * + * @param node The node to add + * @since 2.4.0 + */ +void finch_blist_manager_add_node(PurpleBlistNode *node); + /*@}*/ #endif
--- a/finch/libgnt/gnttree.c Wed Jan 23 23:28:38 2008 +0000 +++ b/finch/libgnt/gnttree.c Fri Jan 25 00:51:06 2008 +0000 @@ -39,6 +39,7 @@ { PROP_0, PROP_COLUMNS, + PROP_EXPANDER, }; enum @@ -59,6 +60,7 @@ GCompareFunc compare; int lastvisible; + int expander_level; }; #define TAB_SIZE 3 @@ -338,7 +340,7 @@ row->isselected ? 'X' : ' '); fl = 4; } - else if (row->parent == NULL && row->child) + else if (find_depth(row) < tree->priv->expander_level && row->child) { if (row->collapsed) { @@ -951,6 +953,11 @@ case PROP_COLUMNS: _gnt_tree_init_internals(tree, g_value_get_int(value)); break; + case PROP_EXPANDER: + if (tree->priv->expander_level == g_value_get_int(value)) + break; + tree->priv->expander_level = g_value_get_int(value); + g_object_notify(obj, "expander-level"); default: break; } @@ -965,6 +972,9 @@ case PROP_COLUMNS: g_value_set_int(value, tree->ncol); break; + case PROP_EXPANDER: + g_value_set_int(value, tree->priv->expander_level); + break; default: break; } @@ -995,6 +1005,14 @@ G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB ) ); + g_object_class_install_property(gclass, + PROP_EXPANDER, + g_param_spec_int("expander-level", "Expander level", + "Number of levels to show expander in the tree.", + 0, G_MAXINT, 1, + G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB + ) + ); signals[SIG_SELECTION_CHANGED] = g_signal_new("selection-changed", @@ -1618,6 +1636,7 @@ { GntWidget *widget = g_object_new(GNT_TYPE_TREE, "columns", col, + "expander-level", 1, NULL); return widget; @@ -1841,3 +1860,9 @@ tree->priv->search_func = func; } +gpointer gnt_tree_get_parent_key(GntTree *tree, gpointer key) +{ + GntTreeRow *row = g_hash_table_lookup(tree->hash, key); + return (row && row->parent) ? row->parent->key : NULL; +} +
--- a/finch/libgnt/gnttree.h Wed Jan 23 23:28:38 2008 +0000 +++ b/finch/libgnt/gnttree.h Fri Jan 25 00:51:06 2008 +0000 @@ -575,6 +575,17 @@ void gnt_tree_set_search_function(GntTree *tree, gboolean (*func)(GntTree *tree, gpointer key, const char *search, const char *current)); +/** + * Get the parent key for a row. + * + * @param tree The tree + * @param key The key for the row. + * + * @return The key of the parent row. + * @since 2.4.0 + */ +gpointer gnt_tree_get_parent_key(GntTree *tree, gpointer key); + G_END_DECLS #endif /* GNT_TREE_H */
--- a/finch/plugins/Makefile.am Wed Jan 23 23:28:38 2008 +0000 +++ b/finch/plugins/Makefile.am Fri Jan 25 00:51:06 2008 +0000 @@ -1,7 +1,8 @@ gntclipboard_la_LDFLAGS = -module -avoid-version gntgf_la_LDFLAGS = -module -avoid-version gnthistory_la_LDFLAGS = -module -avoid-version -gntlastlog_la_LDFLAGS = -module -avoid-version +gntlastlog_la_LDFLAGS = -module -avoid-version +grouping_la_LDFLAGS = -module -avoid-version if PLUGINS @@ -9,7 +10,8 @@ gntclipboard.la \ gntgf.la \ gnthistory.la \ - gntlastlog.la + gntlastlog.la \ + grouping.la plugindir = $(libdir)/finch @@ -17,6 +19,7 @@ gntgf_la_SOURCES = gntgf.c gnthistory_la_SOURCES = gnthistory.c gntlastlog_la_SOURCES = lastlog.c +grouping_la_SOURCES = grouping.c gntclipboard_la_CFLAGS = $(X11_CFLAGS) gntgf_la_CFLAGS = $(X11_CFLAGS) @@ -25,6 +28,7 @@ gntgf_la_LIBADD = $(GLIB_LIBS) $(X11_LIBS) $(top_builddir)/finch/libgnt/libgnt.la gnthistory_la_LIBADD = $(GLIB_LIBS) gntlastlog_la_LIBADD = $(GLIB_LIBS) +grouping_la_LIBADD = $(GLIB_LIBS) $(top_builddir)/finch/libgnt/libgnt.la endif # PLUGINS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/finch/plugins/grouping.c Fri Jan 25 00:51:06 2008 +0000 @@ -0,0 +1,278 @@ +/** + * @file grouping.c Provides different grouping options. + * + * Copyright (C) 2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net> + * + * 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 + */ + +#define PURPLE_PLUGIN + +#include "internal.h" +#include "purple.h" + +#include "gntblist.h" +#include "gntplugin.h" + +#include "gnttree.h" + +/** + * Online/Offline + */ +static PurpleBlistNode online = {.type = PURPLE_BLIST_OTHER_NODE}, + offline = {.type = PURPLE_BLIST_OTHER_NODE}; + +static gboolean on_offline_init() +{ + GntTree *tree = finch_blist_get_tree(); + + gnt_tree_add_row_after(tree, &online, + gnt_tree_create_row(tree, _("Online")), NULL, NULL); + gnt_tree_add_row_after(tree, &offline, + gnt_tree_create_row(tree, _("Offline")), NULL, &online); + + return TRUE; +} + +static gboolean on_offline_can_add_node(PurpleBlistNode *node) +{ + switch (purple_blist_node_get_type(node)) { + case PURPLE_BLIST_CONTACT_NODE: + { + PurpleContact *contact = (PurpleContact*)node; + if (contact->currentsize > 0) + return TRUE; + return FALSE; + } + break; + case PURPLE_BLIST_BUDDY_NODE: + { + PurpleBuddy *buddy = (PurpleBuddy*)node; + if (PURPLE_BUDDY_IS_ONLINE(buddy)) + return TRUE; + if (purple_prefs_get_bool("/finch/blist/showoffline") && + purple_account_is_connected(purple_buddy_get_account(buddy))) + return TRUE; + return FALSE; + } + break; + case PURPLE_BLIST_CHAT_NODE: + { + PurpleChat *chat = (PurpleChat*)node; + return purple_account_is_connected(purple_chat_get_account(chat)); + } + break; + default: + return FALSE; + } +} + +static gpointer on_offline_find_parent(PurpleBlistNode *node) +{ + gpointer ret = NULL; + + switch (purple_blist_node_get_type(node)) { + case PURPLE_BLIST_CONTACT_NODE: + node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node); + ret = PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node) ? &online : &offline; + break; + case PURPLE_BLIST_BUDDY_NODE: + ret = purple_blist_node_get_parent(node); + finch_blist_manager_add_node(ret); + break; + case PURPLE_BLIST_CHAT_NODE: + ret = &online; + break; + default: + break; + } + return ret; +} + +static gboolean on_offline_create_tooltip(gpointer selected_row, GString **body, char **tool_title) +{ + static FinchBlistManager *def = NULL; + PurpleBlistNode *node = selected_row; + + if (def == NULL) + def = finch_blist_manager_find("default"); + + if (purple_blist_node_get_type(node) == PURPLE_BLIST_OTHER_NODE) { + /* There should be some easy way of getting the total online count, + * or total number of chats. Doing a loop here will probably be pretty + * expensive. */ + if (body) + *body = g_string_new(node == &online ? _("Online Buddies") : _("Offline Buddies")); + return TRUE; + } else { + return def ? def->create_tooltip(selected_row, body, tool_title) : FALSE; + } +} + +static FinchBlistManager on_offline = +{ + "on-offline", + N_("Online/Offline"), + on_offline_init, + NULL, + on_offline_can_add_node, + on_offline_find_parent, + on_offline_create_tooltip, + {NULL, NULL, NULL, NULL} +}; + +/** + * Meebo-like Grouping. + */ +static PurpleBlistNode meebo = {.type = PURPLE_BLIST_OTHER_NODE}; +static gboolean meebo_init() +{ + GntTree *tree = finch_blist_get_tree(); + if (!g_list_find(gnt_tree_get_rows(tree), &meebo)) { + gnt_tree_add_row_last(tree, &meebo, + gnt_tree_create_row(tree, _("Offline")), NULL); + } + return TRUE; +} + +static gpointer meebo_find_parent(PurpleBlistNode *node) +{ + static FinchBlistManager *def = NULL; + if (def == NULL) + def = finch_blist_manager_find("default"); + + if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { + PurpleBuddy *buddy = purple_contact_get_priority_buddy((PurpleContact*)node); + if (buddy && !PURPLE_BUDDY_IS_ONLINE(buddy)) { + return &meebo; + } + } + return def->find_parent(node); +} + +static FinchBlistManager meebo_group = +{ + "meebo", + N_("Meebo"), + meebo_init, + NULL, + NULL, + meebo_find_parent, + NULL, + {NULL, NULL, NULL, NULL} +}; + +/** + * No Grouping. + */ +static gboolean no_group_init() +{ + GntTree *tree = finch_blist_get_tree(); + g_object_set(G_OBJECT(tree), "expander-level", 0, NULL); + return TRUE; +} + +static gboolean no_group_uninit() +{ + GntTree *tree = finch_blist_get_tree(); + g_object_set(G_OBJECT(tree), "expander-level", 1, NULL); + return TRUE; +} + +static gboolean no_group_can_add_node(PurpleBlistNode *node) +{ + return on_offline_can_add_node(node); /* These happen to be the same */ +} + +static gpointer no_group_find_parent(PurpleBlistNode *node) +{ + gpointer ret = NULL; + + switch (purple_blist_node_get_type(node)) { + case PURPLE_BLIST_BUDDY_NODE: + ret = purple_blist_node_get_parent(node); + finch_blist_manager_add_node(ret); + break; + default: + break; + } + return ret; +} + +static FinchBlistManager no_group = +{ + "no-group", + N_("No Grouping"), + no_group_init, + no_group_uninit, + no_group_can_add_node, + no_group_find_parent, + NULL, + {NULL, NULL, NULL, NULL} +}; + +static gboolean +plugin_load(PurplePlugin *plugin) +{ + finch_blist_install_manager(&on_offline); + finch_blist_install_manager(&meebo_group); + finch_blist_install_manager(&no_group); + return TRUE; +} + +static gboolean +plugin_unload(PurplePlugin *plugin) +{ + finch_blist_uninstall_manager(&on_offline); + finch_blist_uninstall_manager(&meebo_group); + finch_blist_uninstall_manager(&no_group); + return TRUE; +} + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, + PURPLE_MINOR_VERSION, + PURPLE_PLUGIN_STANDARD, + FINCH_PLUGIN_TYPE, + 0, + NULL, + PURPLE_PRIORITY_DEFAULT, + "grouping", + N_("Grouping"), + VERSION, + N_("Provides alternate buddylist grouping options."), + N_("Provides alternate buddylist grouping options."), + "Sadrul H Chowdhury <sadrul@users.sourceforge.net>", + PURPLE_WEBSITE, + plugin_load, + plugin_unload, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL,NULL,NULL,NULL +}; + +static void +init_plugin(PurplePlugin *plugin) +{ +} + +PURPLE_INIT_PLUGIN(ignore, init_plugin, info) + +
--- a/libpurple/accountopt.h Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/accountopt.h Fri Jan 25 00:51:06 2008 +0000 @@ -83,7 +83,10 @@ /*@{*/ /** - * Creates a new account option. + * Creates a new account option. If you know what @a type will be in advance, + * consider using purple_account_option_bool_new(), + * purple_account_option_int_new(), purple_account_option_string_new() or + * purple_account_option_list_new() (as appropriate) instead. * * @param type The type of option. * @param text The text of the option. @@ -91,8 +94,8 @@ * * @return The account option. */ -PurpleAccountOption *purple_account_option_new(PurplePrefType type, const char *text, - const char *pref_name); +PurpleAccountOption *purple_account_option_new(PurplePrefType type, + const char *text, const char *pref_name); /** * Creates a new boolean account option. @@ -104,8 +107,7 @@ * @return The account option. */ PurpleAccountOption *purple_account_option_bool_new(const char *text, - const char *pref_name, - gboolean default_value); + const char *pref_name, gboolean default_value); /** * Creates a new integer account option. @@ -117,8 +119,7 @@ * @return The account option. */ PurpleAccountOption *purple_account_option_int_new(const char *text, - const char *pref_name, - int default_value); + const char *pref_name, int default_value); /** * Creates a new string account option. @@ -130,8 +131,7 @@ * @return The account option. */ PurpleAccountOption *purple_account_option_string_new(const char *text, - const char *pref_name, - const char *default_value); + const char *pref_name, const char *default_value); /** * Creates a new list account option. @@ -140,7 +140,7 @@ * strings inside will be freed automatically. * * The list is a list of PurpleKeyValuePair items. The key is the ID stored and - * used internally, and the value is the label displayed. + * used internally, and the <tt>(const char *)</tt> value is the label displayed. * * @param text The text of the option. * @param pref_name The account preference name for the option. @@ -149,8 +149,7 @@ * @return The account option. */ PurpleAccountOption *purple_account_option_list_new(const char *text, - const char *pref_name, - GList *list); + const char *pref_name, GList *list); /** * Destroys an account option. @@ -240,11 +239,13 @@ const char *purple_account_option_get_text(const PurpleAccountOption *option); /** - * Returns the account setting for an account option. + * Returns the name of an account option. This corresponds to the @c pref_name + * parameter supplied to purple_account_option_new() or one of the + * type-specific constructors. * * @param option The account option. * - * @return The account setting. + * @return The option's name. */ const char *purple_account_option_get_setting(const PurpleAccountOption *option);
--- a/libpurple/blist.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/blist.c Fri Jan 25 00:51:06 2008 +0000 @@ -640,10 +640,10 @@ if (purple_account_is_connected(buddy->account)) { - int cmp; - - cmp = purple_presence_compare(purple_buddy_get_presence(new_priority), - purple_buddy_get_presence(buddy)); + int cmp = 1; + if (purple_account_is_connected(new_priority->account)) + cmp = purple_presence_compare(purple_buddy_get_presence(new_priority), + purple_buddy_get_presence(buddy)); if (cmp > 0 || (cmp == 0 && purple_prefs_get_bool("/purple/contact/last_match"))) @@ -753,6 +753,21 @@ return ret; } +PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node) +{ + return node ? node->parent : NULL; +} + +PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node) +{ + return node ? node->child : NULL; +} + +PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node) +{ + return node? node->next : NULL; +} + void purple_blist_update_buddy_status(PurpleBuddy *buddy, PurpleStatus *old_status) { @@ -2232,6 +2247,14 @@ return (PurpleGroup *)(((PurpleBlistNode *)chat)->parent); } +PurpleAccount * +purple_chat_get_account(PurpleChat *chat) +{ + g_return_val_if_fail(chat != NULL, NULL); + + return chat->account; +} + PurpleContact *purple_buddy_get_contact(PurpleBuddy *buddy) { g_return_val_if_fail(buddy != NULL, NULL);
--- a/libpurple/blist.h Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/blist.h Fri Jan 25 00:51:06 2008 +0000 @@ -231,10 +231,49 @@ * @param node A node. * @param offline Whether to include nodes for offline accounts * @return The next node + * @see purple_blist_node_get_parent + * @see purple_blist_node_get_first_child + * @see purple_blist_node_get_sibling_next */ PurpleBlistNode *purple_blist_node_next(PurpleBlistNode *node, gboolean offline); /** + * Returns the parent node of a given node. + * + * @param node A node. + * @return The parent node. + * @since 2.4.0 + * @see purple_blist_node_get_first_child + * @see purple_blist_node_get_sibling_next + * @see purple_blist_node_next + */ +PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node); + +/** + * Returns the the first child node of a given node. + * + * @param node A node. + * @return The child node. + * @since 2.4.0 + * @see purple_blist_node_get_parent + * @see purple_blist_node_get_sibling_next + * @see purple_blist_node_next + */ +PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node); + +/** + * Returns the sibling node of a given node. + * + * @param node A node. + * @return The sibling node. + * @since 2.4.0 + * @see purple_blist_node_get_parent + * @see purple_blist_node_get_first_child + * @see purple_blist_node_next + */ +PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node); + +/** * Shows the buddy list, creating a new one if necessary. */ void purple_blist_show(void); @@ -667,6 +706,16 @@ PurpleGroup *purple_chat_get_group(PurpleChat *chat); /** + * Returns the account the chat belongs to. + * + * @param chat The chat. + * + * @return The account the chat belongs to. + * @since 2.4.0 + */ +PurpleAccount *purple_chat_get_account(PurpleChat *chat); + +/** * Returns the group of which the buddy is a member. * * @param buddy The buddy
--- a/libpurple/buddyicon.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/buddyicon.c Fri Jan 25 00:51:06 2008 +0000 @@ -701,11 +701,6 @@ } unref_filename(old_icon); - if (img) - g_hash_table_insert(pointer_icon_cache, account, img); - else - g_hash_table_remove(pointer_icon_cache, account); - if (purple_account_is_connected(account)) { PurpleConnection *gc; @@ -729,6 +724,11 @@ } g_free(old_icon); + if (img) + g_hash_table_insert(pointer_icon_cache, account, img); + else + g_hash_table_remove(pointer_icon_cache, account); + return img; }
--- a/libpurple/example/Makefile.am Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/example/Makefile.am Fri Jan 25 00:51:06 2008 +0000 @@ -17,7 +17,8 @@ -DLIBDIR=\"$(libdir)/purple-$(PURPLE_MAJOR_VERSION)/\" \ -DLOCALEDIR=\"$(datadir)/locale\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ - -I$(top_srcdir)/libpurple/ \ + -I$(top_builddir)/libpurple \ + -I$(top_srcdir)/libpurple \ -I$(top_srcdir) \ $(DEBUG_CFLAGS) \ $(GLIB_CFLAGS) \
--- a/libpurple/example/nullclient.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/example/nullclient.c Fri Jan 25 00:51:06 2008 +0000 @@ -21,28 +21,11 @@ * */ -/* XXX: we probably shouldn't include internal.h in examples */ -#include "internal.h" - -#include "account.h" -#include "conversation.h" -#include "core.h" -#include "debug.h" -#include "eventloop.h" -#include "ft.h" -#include "log.h" -#include "notify.h" -#include "prefs.h" -#include "prpl.h" -#include "pounce.h" -#include "savedstatuses.h" -#include "sound.h" -#include "status.h" -#include "util.h" -#include "whiteboard.h" +#include "purple.h" #include <glib.h> +#include <signal.h> #include <string.h> #include <unistd.h>
--- a/libpurple/protocols/myspace/myspace.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/protocols/myspace/myspace.c Fri Jan 25 00:51:06 2008 +0000 @@ -117,7 +117,7 @@ } return TRUE; } - + /** * Get possible user status types. Based on mockprpl. * @@ -552,10 +552,8 @@ * return 1 even if the message could not be sent, since I don't know if * it has failed yet--because the IM is only sent after the userid is * retrieved from the server (which happens after this function returns). + * If an error does occur, it should be logged to the IM window. */ - /* TODO: maybe if message is delayed, don't echo to conv window, - * but do echo it to conv window manually once it is actually - * sent? Would be complicated. */ rc = 1; } else { rc = -1; @@ -563,19 +561,6 @@ g_free(message_msim); - /* - * In MySpace, you login with your email address, but don't talk to other - * users using their email address. So there is currently an asymmetry in the - * IM windows when using this plugin: - * - * you@example.com: hello - * some_other_user: what's going on? - * you@example.com: just coding a prpl - * - * TODO: Make the sent IM's appear as from the user's username, instead of - * their email address. Purple uses the login (in MSIM, the email)--change this. - */ - return rc; } @@ -745,7 +730,10 @@ /* TODO: dump unknown msgs to file, so user can send them to me * if they wish, to help add support for new messages (inspired - * by Alexandr Shutko, who maintains OSCAR protocol documentation). */ + * by Alexandr Shutko, who maintains OSCAR protocol documentation). + * + * Filed enhancement ticket for libpurple as #4688. + */ purple_debug_info("msim", "Unrecognized data on account for %s\n", (session && session->account && session->account->username) ? @@ -787,9 +775,6 @@ msg_text, username); if (g_str_equal(msg_text, "%typing%")) { - /* TODO: find out if msim repeatedly sends typing messages, so we can - * give it a timeout. Right now, there does seem to be an inordinately - * amount of time between typing stopped-typing notifications. */ serv_got_typing(session->gc, username, 0, PURPLE_TYPING); rc = TRUE; } else if (g_str_equal(msg_text, "%stoptyping%")) { @@ -959,6 +944,7 @@ if (!user) { /* User isn't on blist, create a temporary user to store info. */ + /* TODO: is this legit, or is it somehow responsible for #3444? */ PurpleBuddy *buddy; user = g_new0(MsimUser, 1); @@ -1052,6 +1038,7 @@ guint status_code; const gchar *message; gchar *stripped; + gchar *unrecognized_msg; session = (MsimSession *)account->gc->proto_data; @@ -1083,6 +1070,12 @@ purple_debug_info("msim", "msim_set_status: unknown " "status interpreting as online"); status_code = MSIM_STATUS_CODE_ONLINE; + + unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n", + purple_status_type_get_primitive(type)); + msim_unrecognized(session, NULL, unrecognized_msg); + g_free(unrecognized_msg); + break; } @@ -1203,7 +1196,7 @@ msim_process(session, msg); /* TODO: Free copy cloned from msim_preprocess_incoming(). */ - //XXX msim_msg_free(msg); + /* msim_msg_free(msg); */ msim_msg_free(body); } @@ -1211,7 +1204,9 @@ * * @param wanted_uid * - * @return Username of wanted_uid, if on blist, or NULL. Static string. + * @return Username of wanted_uid, if on blist, or NULL. Static string. + * TODO: The username string here is a new string from g_strdup(), not + * a static string that doesn't need to be fixed. Probably leaks. TODO: fix. * */ static const gchar * @@ -1313,13 +1308,13 @@ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); delta = time(NULL) - session->last_comm; - //purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); + /* purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); */ if (delta >= MSIM_KEEPALIVE_INTERVAL) { errmsg = g_strdup_printf(_("Connection to server lost (no data received within %d seconds)"), (int)delta); purple_debug_info("msim", "msim_check_alive: %s > interval of %d, presumed dead\n", errmsg, MSIM_KEEPALIVE_INTERVAL); - purple_connection_error_reason (session->gc, + purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, errmsg); purple_notify_error(session->gc, NULL, errmsg, NULL); @@ -1741,7 +1736,7 @@ static gboolean msim_web_challenge(MsimSession *session, MsimMessage *msg) { - /* TODO: web challenge, store token */ + /* TODO: web challenge, store token. #2659. */ return FALSE; } @@ -1832,13 +1827,14 @@ if (msim_msg_get(msg, "fatal")) { PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; purple_debug_info("msim", "fatal error, closing\n"); + switch (err) { - case 260: /* Incorrect password */ + case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */ reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; if (!purple_account_get_remember_password(session->account)) purple_account_set_password(session->account, NULL); break; - case 6: /* Logged in elsewhere */ + case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */ reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE; if (!purple_account_get_remember_password(session->account)) purple_account_set_password(session->account, NULL); @@ -1871,6 +1867,7 @@ gchar *status_headline, *status_headline_escaped; gint status_code, purple_status_code; gchar *username; + gchar *unrecognized_msg; g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); g_return_val_if_fail(msg != NULL, FALSE); @@ -1903,7 +1900,8 @@ blist = purple_get_blist(); - /* Add buddy if not found */ + /* Add buddy if not found. + * TODO: Could this be responsible for #3444? */ user = msim_find_user(session, username); if (!user) { PurpleBuddy *buddy; @@ -1915,7 +1913,7 @@ user = msim_get_user_from_buddy(buddy); - /* All buddies on list should have 'uid' integer associated with them. */ + /* All buddies on list should have a UserID integer associated with them. */ purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f")); msim_store_user_info(session, msg, NULL); @@ -1959,9 +1957,15 @@ break; default: - purple_debug_info("msim", "msim_status for %s, unknown status code %d, treating as available\n", + purple_debug_info("msim", "msim_incoming_status for %s, unknown status code %d, treating as available\n", username, status_code); purple_status_code = PURPLE_STATUS_AVAILABLE; + + unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n", + status_code); + msim_unrecognized(session, NULL, unrecognized_msg); + g_free(unrecognized_msg); + } purple_prpl_got_user_status(session->account, username, purple_primitive_get_id_from_type(purple_status_code), NULL); @@ -2156,10 +2160,15 @@ gchar *msg; msg = g_strdup_printf(_("No such user: %s"), username); - purple_notify_error(NULL, NULL, _("User lookup"), msg); + if (!purple_conv_present_error(username, session->account, msg)) { + purple_notify_error(NULL, NULL, _("User lookup"), msg); + } + g_free(msg); g_free(username); - //msim_msg_free(msg); + /* TODO: free + * msim_msg_free(msg); + */ return; } @@ -2180,7 +2189,9 @@ g_free(uid_field_name); g_free(uid_before); g_free(username); - //msim_msg_free(msg); + /* TODO: free + * msim_msg_free(msg); + */ } /** Postprocess and send a message. @@ -2222,8 +2233,7 @@ uid = 0; } - if (!buddy || !uid) - { + if (!buddy || !uid) { /* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */ purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n", username ? username : "(NULL)"); @@ -2244,7 +2254,9 @@ rc = msim_msg_send(session, msg); - //msim_msg_free(msg); + /* TODO: free + * msim_msg_free(msg); + */ return rc; } @@ -2304,7 +2316,7 @@ "blocklist", MSIM_TYPE_BOOLEAN, TRUE, "sesskey", MSIM_TYPE_INTEGER, session->sesskey, /* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */ - //"idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), + /* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */ "idlist", MSIM_TYPE_LIST, blocklist_updates, NULL); @@ -2317,9 +2329,12 @@ } /** - * Borrowed this code from oscar_normalize. Added checking for "if userid, get name before normalizing" + * Returns a string of a username in canonical form. Basically removes all the + * spaces, lowercases the string, and looks up user IDs to usernames. + * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'. * - * Basically... Returns a string that has been formated with all the spaces and caps removed. + * Borrowed this code from oscar_normalize. Added checking for + * "if userid, get name before normalizing" */ const char *msim_normalize(const PurpleAccount *account, const char *str) { static char normalized[BUF_LEN]; @@ -2345,7 +2360,7 @@ id = atol(str); username = msim_uid2username_from_blist(session, id); if (!username) { - /* Not in buddy list... scheisse... TODO: Manual Lookup! */ + /* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */ /* Note: manual lookup using msim_lookup_user() is a problem inside * msim_normalize(), because msim_lookup_user() calls a callback function * when the user information has been looked up, but msim_normalize() expects @@ -2376,6 +2391,13 @@ g_free(tmp2); g_free(tmp1); + /* TODO: re-add caps and spacing back to what the user wanted. + * User can format their own names, for example 'msimprpl' is shown + * as 'MsIm PrPl' in the official client. + * + * TODO: file a ticket to add this enhancement. + */ + return normalized; } @@ -2427,16 +2449,17 @@ g_return_if_fail(cond == PURPLE_INPUT_READ); g_return_if_fail(MSIM_SESSION_VALID(session)); - /* Mark down that we got data, so don't timeout. */ + /* Mark down that we got data, so we don't timeout. */ session->last_comm = time(NULL); /* Only can handle so much data at once... - * If this happens, try recompiling with a higher MSIM_READ_BUF_SIZE. * Should be large enough to hold the largest protocol message. */ if (session->rxoff >= MSIM_READ_BUF_SIZE) { purple_debug_error("msim", - "msim_input_cb: %d-byte read buffer full! rxoff=%d\n", + "msim_input_cb: %d-byte read buffer full! rxoff=%d. " + "If this happens, try recompiling with a higher " + "MSIM_READ_BUF_SIZE.", MSIM_READ_BUF_SIZE, session->rxoff); purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -2535,8 +2558,9 @@ memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING), MSIM_READ_BUF_SIZE - (end + strlen(MSIM_FINAL_STRING) - session->rxbuf)); - /* Clear end of buffer */ - //memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf)); + /* Clear end of buffer + * memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf)); + */ } }
--- a/libpurple/protocols/myspace/myspace.h Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/protocols/myspace/myspace.h Fri Jan 25 00:51:06 2008 +0000 @@ -180,6 +180,10 @@ #define MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS 1 #define MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS 2 +/* Error codes */ +#define MSIM_ERROR_INCORRECT_PASSWORD 260 +#define MSIM_ERROR_LOGGED_IN_ELSEWHERE 6 + /* Functions */ gboolean msim_load(PurplePlugin *plugin); GList *msim_status_types(PurpleAccount *acct);
--- a/libpurple/protocols/oscar/flap_connection.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Fri Jan 25 00:51:06 2008 +0000 @@ -360,7 +360,7 @@ conn = data; od = conn->od; - account = (PURPLE_CONNECTION_IS_VALID(od->gc) ? purple_connection_get_account(od->gc) : NULL); + account = purple_connection_get_account(od->gc); purple_debug_info("oscar", "Destroying oscar connection of " "type 0x%04hx. Disconnect reason is %d\n", @@ -375,8 +375,8 @@ * TODO: If we don't have a SNAC_FAMILY_LOCATE connection then * we should try to request one instead of disconnecting. */ - if (account && !account->disconnecting && - ((od->oscar_connections == NULL) || (!flap_connection_getbytype(od, SNAC_FAMILY_LOCATE)))) + if (!account->disconnecting && ((od->oscar_connections == NULL) + || (!flap_connection_getbytype(od, SNAC_FAMILY_LOCATE)))) { /* No more FLAP connections! Sign off this PurpleConnection! */ gchar *tmp;
--- a/libpurple/protocols/yahoo/util.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/protocols/yahoo/util.c Fri Jan 25 00:51:06 2008 +0000 @@ -168,11 +168,11 @@ { GString *gstr = NULL; char *retstr; - const char *p; + const unsigned char *p; gstr = g_string_sized_new(strlen(str) * 6 + 1); - for (p = str; *p; p++) { + for (p = (unsigned char *)str; *p; p++) { g_string_append_printf(gstr, "&#%u;", *p); }
--- a/libpurple/util.c Wed Jan 23 23:28:38 2008 +0000 +++ b/libpurple/util.c Fri Jan 25 00:51:06 2008 +0000 @@ -1445,7 +1445,6 @@ ALLOW_TAG("pre"); ALLOW_TAG("q"); ALLOW_TAG("span"); - ALLOW_TAG("strong"); ALLOW_TAG("ul"); @@ -1465,9 +1464,14 @@ plain = g_string_append_c(plain, '\n'); continue; } - if(!g_ascii_strncasecmp(c, "<b>", 3) || !g_ascii_strncasecmp(c, "<bold>", strlen("<bold>"))) { + if(!g_ascii_strncasecmp(c, "<b>", 3) || !g_ascii_strncasecmp(c, "<bold>", strlen("<bold>")) || !g_ascii_strncasecmp(c, "<strong>", strlen("<strong>"))) { struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1); - pt->src_tag = *(c+2) == '>' ? "b" : "bold"; + if (*(c+2) == '>') + pt->src_tag = "b"; + else if (*(c+2) == 'o') + pt->src_tag = "bold"; + else + pt->src_tag = "strong"; pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1;
--- a/pidgin/gtkconv.c Wed Jan 23 23:28:38 2008 +0000 +++ b/pidgin/gtkconv.c Fri Jan 25 00:51:06 2008 +0000 @@ -169,6 +169,7 @@ static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, int width, int height); +static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y); static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { static GdkColor col; @@ -3428,9 +3429,14 @@ gtk_text_buffer_delete_mark(buffer, stmark); gtk_text_buffer_delete_mark(buffer, enmark); gtk_text_buffer_delete(buffer, &start, &end); - } else if (message && *message == '\n' && !*(message + 1)) + } else if (message && *message == '\n' && message[1] == ' ' && message[2] == '\0') message = NULL; +#ifdef RESERVE_LINE + if (!message) + message = "\n "; /* The blank space is required to avoid a GTK+/Pango bug */ +#endif + if (message) { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); @@ -3458,7 +3464,11 @@ return; if (purple_conv_im_get_typing_state(im) == PURPLE_NOT_TYPING) { - update_typing_message(gtkconv, "\n"); +#ifdef RESERVE_LINE + update_typing_message(gtkconv, NULL); +#else + update_typing_message(gtkconv, "\n "); +#endif return; } @@ -4980,7 +4990,7 @@ gtk_text_buffer_create_tag(GTK_IMHTML(gtkconv->imhtml)->text_buffer, "TYPING-NOTIFICATION", "foreground", "#888888", "justification", GTK_JUSTIFY_LEFT, /* XXX: RTL'ify */ - "weight", PANGO_WEIGHT_BOLD, + "weight", PANGO_WEIGHT_LIGHT, "scale", PANGO_SCALE_SMALL, NULL); @@ -6876,6 +6886,18 @@ gray_stuff_out(PIDGIN_CONVERSATION(conv)); } +static gboolean +pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y) +{ + gint pane_x, pane_y, x_rel; + PidginConversation *gtkconv; + + gdk_window_get_origin(win->notebook->window, &pane_x, &pane_y); + x_rel = x - pane_x; + gtkconv = pidgin_conv_window_get_active_gtkconv(win); + return (x_rel > gtkconv->infopane->allocation.x + gtkconv->infopane->allocation.width / 2); +} + int pidgin_conv_get_tab_at_xy(PidginWindow *win, int x, int y, gboolean *to_right) { @@ -6911,7 +6933,7 @@ tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook), page); /* Make sure the tab is not hidden beyond an arrow */ - if (!GTK_WIDGET_DRAWABLE(tab)) + if (!GTK_WIDGET_DRAWABLE(tab) && gtk_notebook_get_show_tabs(notebook)) continue; if (horiz) { @@ -8170,7 +8192,6 @@ GtkWidget *tab; gint page_num; gboolean horiz_tabs = FALSE; - PidginConversation *gtkconv; gboolean to_right = FALSE; /* Get the window that the cursor is over. */ @@ -8184,20 +8205,27 @@ dest_notebook = GTK_NOTEBOOK(dest_win->notebook); - page_num = pidgin_conv_get_tab_at_xy(dest_win, - e->x_root, e->y_root, &to_right); - to_right = to_right && (win != dest_win); + if (gtk_notebook_get_show_tabs(dest_notebook)) { + page_num = pidgin_conv_get_tab_at_xy(dest_win, + e->x_root, e->y_root, &to_right); + to_right = to_right && (win != dest_win); + tab = pidgin_conv_window_get_gtkconv_at_index(dest_win, page_num)->tabby; + } else { + page_num = 0; + to_right = pidgin_conv_xy_to_right_infopane(dest_win, e->x_root, e->y_root); + tab = pidgin_conv_window_get_gtkconv_at_index(dest_win, page_num)->infopane; + } if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP || gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) { horiz_tabs = TRUE; } - gtkconv = pidgin_conv_window_get_gtkconv_at_index(dest_win, page_num); - tab = gtkconv->tabby; - if (gtk_notebook_get_show_tabs(dest_notebook) == FALSE) { - dnd_hints_show_relative(HINT_ARROW_DOWN, gtkconv->infopane, HINT_POSITION_CENTER, HINT_POSITION_TOP); - dnd_hints_show_relative(HINT_ARROW_UP, gtkconv->infopane, HINT_POSITION_CENTER, HINT_POSITION_BOTTOM); + if (gtk_notebook_get_show_tabs(dest_notebook) == FALSE && win == dest_win) + { + /* dragging a tab from a single-tabbed window over its own window */ + dnd_hints_hide_all(); + return TRUE; } else if (horiz_tabs) { if (((gpointer)win == (gpointer)dest_win && win->drag_tab < page_num) || to_right) { dnd_hints_show_relative(HINT_ARROW_DOWN, tab, HINT_POSITION_RIGHT, HINT_POSITION_TOP); @@ -8394,6 +8422,7 @@ notebook_release_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win) { PidginWindow *dest_win; + GtkNotebook *dest_notebook; PurpleConversation *conv; PidginConversation *gtkconv; gint dest_page_num = 0; @@ -8469,9 +8498,16 @@ "conversation-dragging", win, dest_win); /* Get the destination page number. */ - if (!new_window) - dest_page_num = pidgin_conv_get_tab_at_xy(dest_win, - e->x_root, e->y_root, &to_right); + if (!new_window) { + dest_notebook = GTK_NOTEBOOK(dest_win->notebook); + if (gtk_notebook_get_show_tabs(dest_notebook)) { + dest_page_num = pidgin_conv_get_tab_at_xy(dest_win, + e->x_root, e->y_root, &to_right); + } else { + dest_page_num = 0; + to_right = pidgin_conv_xy_to_right_infopane(dest_win, e->x_root, e->y_root); + } + } gtkconv = pidgin_conv_window_get_gtkconv_at_index(win, win->drag_tab);
--- a/pidgin/gtkstatusbox.c Wed Jan 23 23:28:38 2008 +0000 +++ b/pidgin/gtkstatusbox.c Fri Jan 25 00:51:06 2008 +0000 @@ -511,12 +511,26 @@ pidgin_status_box_finalize(GObject *obj) { PidginStatusBox *statusbox = PIDGIN_STATUS_BOX(obj); + int i; purple_signals_disconnect_by_handle(statusbox); purple_prefs_disconnect_by_handle(statusbox); destroy_icon_box(statusbox); + if (statusbox->active_row) + gtk_tree_row_reference_free(statusbox->active_row); + + for (i = 0; i < G_N_ELEMENTS(statusbox->connecting_pixbufs); i++) { + if (statusbox->connecting_pixbufs[i] != NULL) + gdk_pixbuf_unref(statusbox->connecting_pixbufs[i]); + } + + for (i = 0; i < G_N_ELEMENTS(statusbox->typing_pixbufs); i++) { + if (statusbox->typing_pixbufs[i] != NULL) + gdk_pixbuf_unref(statusbox->typing_pixbufs[i]); + } + g_object_unref(G_OBJECT(statusbox->store)); g_object_unref(G_OBJECT(statusbox->dropdown_store)); G_OBJECT_CLASS(parent_class)->finalize(obj); @@ -1166,18 +1180,15 @@ cache_pixbufs(PidginStatusBox *status_box) { GtkIconSize icon_size; + int i; g_object_set(G_OBJECT(status_box->icon_rend), "xpad", 3, NULL); icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); - if (status_box->connecting_pixbufs[0] != NULL) - gdk_pixbuf_unref(status_box->connecting_pixbufs[0]); - if (status_box->connecting_pixbufs[1] != NULL) - gdk_pixbuf_unref(status_box->connecting_pixbufs[1]); - if (status_box->connecting_pixbufs[2] != NULL) - gdk_pixbuf_unref(status_box->connecting_pixbufs[2]); - if (status_box->connecting_pixbufs[3] != NULL) - gdk_pixbuf_unref(status_box->connecting_pixbufs[3]); + for (i = 0; i < G_N_ELEMENTS(status_box->connecting_pixbufs); i++) { + if (status_box->connecting_pixbufs[i] != NULL) + gdk_pixbuf_unref(status_box->connecting_pixbufs[i]); + } status_box->connecting_index = 0; status_box->connecting_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_ANIMATION_CONNECT0, @@ -1199,14 +1210,10 @@ status_box->connecting_pixbufs[8] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_ANIMATION_CONNECT8, icon_size, "PidginStatusBox"); - if (status_box->typing_pixbufs[0] != NULL) - gdk_pixbuf_unref(status_box->typing_pixbufs[0]); - if (status_box->typing_pixbufs[1] != NULL) - gdk_pixbuf_unref(status_box->typing_pixbufs[1]); - if (status_box->typing_pixbufs[2] != NULL) - gdk_pixbuf_unref(status_box->typing_pixbufs[2]); - if (status_box->typing_pixbufs[3] != NULL) - gdk_pixbuf_unref(status_box->typing_pixbufs[3]); + for (i = 0; i < G_N_ELEMENTS(status_box->typing_pixbufs); i++) { + if (status_box->typing_pixbufs[i] != NULL) + gdk_pixbuf_unref(status_box->typing_pixbufs[i]); + } status_box->typing_index = 0; status_box->typing_pixbufs[0] = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_ANIMATION_TYPING0,
--- a/pidgin/gtkutils.h Wed Jan 23 23:28:38 2008 +0000 +++ b/pidgin/gtkutils.h Fri Jan 25 00:51:06 2008 +0000 @@ -798,11 +798,11 @@ * Add a labelled widget to a GtkVBox * * @param vbox The GtkVBox to add the widget to. - * @param widget_label The label to give the widget. - * @param sg The GtkSizeGroup to add the label to. - * @param widget The GtkWidget to add + * @param widget_label The label to give the widget, can be @c NULL. + * @param sg The GtkSizeGroup to add the label to, can be @c NULL. + * @param widget The GtkWidget to add. * @param expand Whether to expand the widget horizontally. - * @param p_label Place to store a pointer to the GtkLabel, or NULL if you don't care. + * @param p_label Place to store a pointer to the GtkLabel, or @c NULL if you don't care. * * @return A GtkHBox already added to the GtkVBox containing the GtkLabel and the GtkWidget. * @since 2.4.0
--- a/po/POTFILES.in Wed Jan 23 23:28:38 2008 +0000 +++ b/po/POTFILES.in Fri Jan 25 00:51:06 2008 +0000 @@ -33,6 +33,7 @@ finch/plugins/gntclipboard.c finch/plugins/gntgf.c finch/plugins/gnthistory.c +finch/plugins/grouping.c finch/plugins/lastlog.c libpurple/account.c libpurple/blist.c
--- a/po/de.po Wed Jan 23 23:28:38 2008 +0000 +++ b/po/de.po Fri Jan 25 00:51:06 2008 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-01-08 11:16+0100\n" -"PO-Revision-Date: 2008-01-08 11:15+0100\n" +"POT-Creation-Date: 2008-01-23 10:20+0100\n" +"PO-Revision-Date: 2008-01-23 10:19+0100\n" "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n" "Language-Team: Deutsch <de@li.org>\n" "MIME-Version: 1.0\n" @@ -155,6 +155,29 @@ msgid "Deny" msgstr "Ablehnen" +#, c-format +msgid "" +"Online: %d\n" +"Total: %d" +msgstr "" +"Online: %d\n" +"Gesamt: %d" + +#, c-format +msgid "Account: %s (%s)" +msgstr "Konto: %s (%s)" + +#, c-format +msgid "" +"\n" +"Last Seen: %s ago" +msgstr "" +"\n" +"Zuletzt gesehen: vor %s" + +msgid "Default" +msgstr "Standard" + msgid "You must provide a screename for the buddy." msgstr "Sie müssen einen Benutzernamen für den Buddy angeben." @@ -303,26 +326,6 @@ msgid "On Mobile" msgstr "Am Handy" -#, c-format -msgid "" -"Online: %d\n" -"Total: %d" -msgstr "" -"Online: %d\n" -"Gesamt: %d" - -#, c-format -msgid "Account: %s (%s)" -msgstr "Konto: %s (%s)" - -#, c-format -msgid "" -"\n" -"Last Seen: %s ago" -msgstr "" -"\n" -"Zuletzt gesehen: vor %s" - msgid "New..." msgstr "Neu..." @@ -389,6 +392,15 @@ msgid "By Log Size" msgstr "Nach Größe der Logs" +msgid "Buddy" +msgstr "Buddy" + +msgid "Chat" +msgstr "Chat" + +msgid "Grouping" +msgstr "Gruppierung" + msgid "Certificate Import" msgstr "Zertifikat-Import" @@ -1321,6 +1333,27 @@ "Wenn eine neue Unterhaltung eröffnet wird, fügt dieses Plugin die letzte " "Unterhaltung in die aktuelle Unterhaltung ein." +msgid "Online" +msgstr "Online" + +msgid "Offline" +msgstr "Offline" + +msgid "Online Buddies" +msgstr "Online-Buddys" + +msgid "Offline Buddies" +msgstr "Offline-Buddys" + +msgid "Online/Offline" +msgstr "Online/Offline" + +msgid "No Grouping" +msgstr "Keine Gruppierung" + +msgid "Provides alternate buddylist grouping options." +msgstr "Bietet alternative Einstellungen für die Kontaktlisten-Gruppierung." + msgid "Lastlog" msgstr "Verlauf" @@ -2688,6 +2721,9 @@ msgid "Could not listen on socket" msgstr "Kann nicht an der Socket hören" +msgid "Error communicating with local mDNSResponder." +msgstr "Fehler bei der Kommunikation mit lokalem mDNSResponder." + msgid "Invalid proxy settings" msgstr "Falsche Proxy-Einstellungen" @@ -2819,9 +2855,6 @@ msgid "Add to chat..." msgstr "Zum Chat hinzufügen..." -msgid "Offline" -msgstr "Offline" - msgid "Available" msgstr "Verfügbar" @@ -4237,6 +4270,8 @@ msgid "Unable to buzz, because the user %s does not support it." msgstr "Kann nicht anklopfen, da der Benutzer %s dies nicht unterstützt." +#. Yahoo only supports one attention command: the 'buzz'. +#. This is index number YAHOO_BUZZ. msgid "Buzz" msgstr "Anklopfen" @@ -5971,9 +6006,6 @@ msgid "AIM Direct IM" msgstr "AIM direkte Nachricht" -msgid "Chat" -msgstr "Chat" - msgid "Get File" msgstr "Datei abrufen" @@ -6043,9 +6075,6 @@ msgid "Invisible" msgstr "Unsichtbar" -msgid "Online" -msgstr "Online" - msgid "IP Address" msgstr "IP-Adresse" @@ -9151,6 +9180,10 @@ msgid "Unable to establish file descriptor." msgstr "Konnte Dateibeschreibung nicht erstellen." +#, c-format +msgid "%s is trying to send you a group of %d files.\n" +msgstr "%s versucht, Ihnen eine Gruppe von %d Dateien zu senden.\n" + msgid "Write Error" msgstr "Schreibfehler" @@ -10072,9 +10105,6 @@ msgid "Total Buddies" msgstr "Buddy-Anzahl" -msgid "Online Buddies" -msgstr "Online-Buddys" - #, c-format msgid "Idle %dd %dh %02dm" msgstr "Untätig %dd %dh %02dm" @@ -11682,9 +11712,6 @@ msgid "Pounce Target" msgstr "Alarm-Ziel" -msgid "Default" -msgstr "Standard" - msgid "Smiley theme failed to unpack." msgstr "Smiley-Thema konnte nicht entpackt werden." @@ -12295,6 +12322,9 @@ msgid "_Open Mail" msgstr "Mail ö_ffnen" +msgid "Pidgin Tooltip" +msgstr "Pidgin-Tooltip" + msgid "Pidgin smileys" msgstr "Pidgin-Smileys"