Mercurial > pidgin
changeset 22012:0503cd74cb56
merge of '418bc7dd4e063c50039bba0d51b489b568f9aaaa'
and '4df361b4c7c545ea522212487ebfd8e4bda0345f'
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sat, 05 Jan 2008 18:07:16 +0000 |
parents | 485383451769 (diff) 76e0463db3aa (current diff) |
children | fefe61275687 |
files | COPYRIGHT ChangeLog configure.ac finch/gntblist.c finch/libgnt/gntwm.c pidgin/gtkblist.c pidgin/gtkconv.c pidgin/gtkprefs.c pidgin/gtkutils.c pidgin/plugins/spellchk.c |
diffstat | 34 files changed, 1242 insertions(+), 790 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Sat Jan 05 18:01:12 2008 +0000 +++ b/COPYRIGHT Sat Jan 05 18:07:16 2008 +0000 @@ -151,6 +151,7 @@ Michael Golden Charlie Gordon Ryan C. Gordon +Konrad Gräfe Miah Gregory David Grohmann Christian Hammond
--- a/ChangeLog Sat Jan 05 18:01:12 2008 +0000 +++ b/ChangeLog Sat Jan 05 18:07:16 2008 +0000 @@ -7,6 +7,8 @@ * Eliminated unmaintained Howl backend implementation for the Bonjour protocol. Avahi (or Apple's Bonjour runtime on win32) is now required to use Bonjour. + * Partial support for viewing ICQ status notes (Collin from + ComBOTS GmbH). Pidgin: * Added the ability to theme conversation name colors (red and blue)
--- a/ChangeLog.API Sat Jan 05 18:01:12 2008 +0000 +++ b/ChangeLog.API Sat Jan 05 18:07:16 2008 +0000 @@ -8,6 +8,7 @@ * purple_major_version, purple_minor_version, purple_micro_version variables are exported by version.h, giving the version of libpurple in use at runtime. + * purple_util_set_current_song, purple_util_format_song_info Pidgin: Added: @@ -24,9 +25,11 @@ * pidgin_tooltip_setup_for_treeview, pidgin_tooltip_destroy, pidgin_tooltip_show and pidgin_tooltip_setup_for_widget to simplify the process of drawing tooltips. + * pidgin_add_widget_to_vbox to simplify adding a labeled widget to a + window. - Deprecated: - * PIDGIN_DIALOG + Deprecated: + * PIDGIN_DIALOG Finch: libgnt:
--- a/configure.ac Sat Jan 05 18:01:12 2008 +0000 +++ b/configure.ac Sat Jan 05 18:07:16 2008 +0000 @@ -142,7 +142,7 @@ dnl If we don't have msgfmt, then po/ is going to fail -- ensure that dnl AM_GLIB_GNU_GETTEXT found it. -if test x$MSGFMT = xno -o x$MSGFMT$GMSGFMT = x +if test x$MSGFMT = xno -o x$MSGFMT$GMSGFMT$INTLTOOL_MSGFMT = x then AC_ERROR([
--- a/doc/finch.1.in Sat Jan 05 18:01:12 2008 +0000 +++ b/doc/finch.1.in Sat Jan 05 18:07:16 2008 +0000 @@ -105,6 +105,12 @@ .B Alt \+ 1 2 ... 0 Jump to the 1st, 2nd ... 10th window. .TP +.B Alt \+ Tab +Jump to the next URGENT (highlighted) window. +.TP +.B Alt \+ Shift \+ Tab +Jump to the previous URGENT (highlighted) window. +.TP .B Ctrl \+ o Bring up the menu (if there is one) for a window. .TP @@ -460,6 +466,7 @@ .br # switch-window-n .br +# Other actions: window-next-urgent, window-prev-urgent # For the sample custom window manager .br
--- a/finch/gntblist.c Sat Jan 05 18:01:12 2008 +0000 +++ b/finch/gntblist.c Sat Jan 05 18:07:16 2008 +0000 @@ -83,6 +83,12 @@ GntMenuItem *plugins; } FinchBlist; +typedef struct +{ + gpointer row; /* the row in the GntTree */ + guint signed_timer; /* used when 'recently' signed on/off */ +} FinchBlistNode; + typedef enum { STATUS_PRIMITIVE = 0, @@ -131,6 +137,31 @@ static int color_offline; static int color_idle; +static FinchBlistNode * +create_finch_blist_node(PurpleBlistNode *node, gpointer row) +{ + FinchBlistNode *fnode = node->ui_data; + if (!fnode) { + fnode = g_new0(FinchBlistNode, 1); + fnode->signed_timer = 0; + node->ui_data = fnode; + } + fnode->row = row; + return fnode; +} + +static void +reset_blist_node_ui_data(PurpleBlistNode *node) +{ + FinchBlistNode *fnode = node->ui_data; + if (fnode == NULL) + return; + if (fnode->signed_timer) + purple_timeout_remove(fnode->signed_timer); + g_free(fnode); + node->ui_data = NULL; +} + static int get_display_color(PurpleBlistNode *node) { @@ -157,6 +188,34 @@ return color; } +static GntTextFormatFlags +get_blist_node_flag(PurpleBlistNode *node) +{ + GntTextFormatFlags flag = 0; + FinchBlistNode *fnode = node->ui_data; + + if (ggblist->tagged && g_list_find(ggblist->tagged, node)) + flag |= GNT_TEXT_FLAG_BOLD; + + if (fnode && fnode->signed_timer) + flag |= GNT_TEXT_FLAG_BLINK; + else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { + node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact *)node); + fnode = node->ui_data; + if (fnode && fnode->signed_timer) + flag |= GNT_TEXT_FLAG_BLINK; + } + + return flag; +} + +static void +blist_update_row_flags(PurpleBlistNode *node) +{ + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, get_blist_node_flag(node)); + gnt_tree_set_row_color(GNT_TREE(ggblist->tree), node, get_display_color(node)); +} + static gboolean is_contact_online(PurpleContact *contact) { @@ -217,7 +276,7 @@ return; gnt_tree_remove(GNT_TREE(ggblist->tree), node); - node->ui_data = NULL; + reset_blist_node_ui_data(node); if (ggblist->tagged) ggblist->tagged = g_list_remove(ggblist->tagged, node); @@ -234,7 +293,7 @@ (!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group))) node_remove(list, node->parent); for (node = node->child; node; node = node->next) - node->ui_data = NULL; + reset_blist_node_ui_data(node); } else { for (node = node->child; node; node = node->next) node_remove(list, node); @@ -261,7 +320,7 @@ gnt_tree_change_text(GNT_TREE(ggblist->tree), node, 0, get_display_name(node)); gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); - gnt_tree_set_row_color(GNT_TREE(ggblist->tree), node, get_display_color(node)); + blist_update_row_flags(node); } if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { @@ -269,8 +328,6 @@ 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); - else - node_remove(purple_get_blist(), node); node_update(list, node->parent); } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { @@ -279,7 +336,7 @@ PurpleContact *contact = (PurpleContact*)node; if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) || contact->currentsize < 1) - node_remove(purple_get_blist(), node); + /* nothing */; else { if (node->ui_data == NULL) { /* The core seems to expect the UI to add the buddies. */ @@ -524,8 +581,8 @@ PurpleBlistNode *node = (PurpleBlistNode *)group; if (node->ui_data) return; - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group, - gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), NULL, NULL); + 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_set_expanded(GNT_TREE(ggblist->tree), node, !purple_blist_node_get_bool(node, "collapsed")); } @@ -539,7 +596,7 @@ if (PURPLE_BLIST_NODE_IS_CONTACT(node)) node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node); /* XXX: this can return NULL?! */ - + if (node == NULL) return NULL; @@ -550,7 +607,7 @@ PurplePresence *presence; PurpleStatus *now; gboolean ascii = gnt_ascii_only(); - + presence = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE)) strncpy(status, ascii ? ":" : "☎", sizeof(status) - 1); @@ -601,9 +658,9 @@ group = purple_chat_get_group(chat); add_node((PurpleBlistNode*)group, ggblist); - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), 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); + group, NULL)); } static void @@ -623,9 +680,9 @@ group = (PurpleGroup*)node->parent; add_node((PurpleBlistNode*)group, ggblist); - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), 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); + group, NULL)); gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE); } @@ -635,7 +692,7 @@ { PurpleContact *contact; PurpleBlistNode *node = (PurpleBlistNode *)buddy; - int color = 0; + if (node->ui_data) return; @@ -647,14 +704,13 @@ return; add_node((PurpleBlistNode*)contact, ggblist); - node->ui_data = gnt_tree_add_row_after(GNT_TREE(ggblist->tree), 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); - - color = get_display_color((PurpleBlistNode*)buddy); - gnt_tree_set_row_color(GNT_TREE(ggblist->tree), buddy, color); + contact, NULL)); + + blist_update_row_flags((PurpleBlistNode*)buddy); if (buddy == purple_contact_get_priority_buddy(contact)) - gnt_tree_set_row_color(GNT_TREE(ggblist->tree), contact, color); + blist_update_row_flags((PurpleBlistNode*)contact); } #if 0 @@ -1564,9 +1620,7 @@ static void update_node_display(PurpleBlistNode *node, FinchBlist *ggblist) { - GntTextFormatFlags flag = 0; - if (ggblist->tagged && g_list_find(ggblist->tagged, node)) - flag |= GNT_TEXT_FLAG_BOLD; + GntTextFormatFlags flag = get_blist_node_flag(node); gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, flag); } @@ -1574,33 +1628,18 @@ update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist) { PurpleContact *contact; - GntTextFormatFlags bflag = 0, cflag = 0; - int color = 0; contact = purple_buddy_get_contact(buddy); gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((PurpleBlistNode*)buddy)); gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((PurpleBlistNode*)contact)); - if (ggblist->tagged && g_list_find(ggblist->tagged, buddy)) - bflag |= GNT_TEXT_FLAG_BOLD; - if (ggblist->tagged && g_list_find(ggblist->tagged, contact)) - cflag |= GNT_TEXT_FLAG_BOLD; + blist_update_row_flags((PurpleBlistNode *)buddy); + if (buddy == purple_contact_get_priority_buddy(contact)) + blist_update_row_flags((PurpleBlistNode *)contact); if (ggblist->tnode == (PurpleBlistNode*)buddy) draw_tooltip(ggblist); - - color = get_display_color((PurpleBlistNode*)buddy); - gnt_tree_set_row_color(GNT_TREE(ggblist->tree), buddy, color); - if (buddy == purple_contact_get_priority_buddy(contact)) - gnt_tree_set_row_color(GNT_TREE(ggblist->tree), contact, color); - - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), buddy, bflag); - if (buddy == purple_contact_get_priority_buddy(contact)) - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), contact, cflag); - - if (buddy != purple_contact_get_priority_buddy(contact)) - update_buddy_display(purple_contact_get_priority_buddy(contact), ggblist); } static void @@ -1649,7 +1688,7 @@ node = purple_blist_get_root(); while (node) { - node->ui_data = NULL; + reset_blist_node_ui_data(node); node = purple_blist_node_next(node, TRUE); } @@ -1762,7 +1801,7 @@ gnt_tree_remove_all(GNT_TREE(ggblist->tree)); node = purple_blist_get_root(); for (; node; node = purple_blist_node_next(node, TRUE)) - node->ui_data = NULL; + reset_blist_node_ui_data(node); populate_buddylist(); gnt_tree_set_selected(GNT_TREE(ggblist->tree), sel); draw_tooltip(ggblist); @@ -2122,6 +2161,51 @@ } } +static gboolean +buddy_recent_signed_on_off(gpointer data) +{ + 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"))) { + 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); + } + + return FALSE; +} + +static gboolean +buddy_signed_on_off_cb(gpointer data) +{ + PurpleBlistNode *node = data; + FinchBlistNode *fnode = node->ui_data; + if (!ggblist || !fnode) + return FALSE; + + if (fnode->signed_timer) + 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); + return FALSE; +} + +static void +buddy_signed_on_off(PurpleBuddy* buddy, gpointer null) +{ + g_idle_add(buddy_signed_on_off_cb, buddy); +} + static void reconstruct_plugins_menu(void) { @@ -2513,12 +2597,12 @@ purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", finch_blist_get_handle(), PURPLE_CALLBACK(reconstruct_plugins_menu), NULL); + purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(), + PURPLE_CALLBACK(buddy_signed_on_off), ggblist); + purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(), + PURPLE_CALLBACK(buddy_signed_on_off), ggblist); + #if 0 - purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(), - PURPLE_CALLBACK(buddy_signed_on), ggblist); - purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(), - PURPLE_CALLBACK(buddy_signed_off), ggblist); - /* These I plan to use to indicate unread-messages etc. */ purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", finch_blist_get_handle(), PURPLE_CALLBACK(received_im_msg), list);
--- a/finch/libgnt/gntwm.c Sat Jan 05 18:01:12 2008 +0000 +++ b/finch/libgnt/gntwm.c Sat Jan 05 18:07:16 2008 +0000 @@ -388,10 +388,10 @@ } static void -switch_window(GntWM *wm, int direction) +switch_window(GntWM *wm, int direction, gboolean urgent) { GntWidget *w = NULL, *wid = NULL; - int pos; + int pos, orgpos; if (wm->_list.window || wm->menu) return; @@ -404,15 +404,20 @@ } w = wm->cws->ordered->data; - pos = g_list_index(wm->cws->list, w); - pos += direction; + orgpos = pos = g_list_index(wm->cws->list, w); + + do { + pos += direction; - if (pos < 0) - wid = g_list_last(wm->cws->list)->data; - else if (pos >= g_list_length(wm->cws->list)) - wid = wm->cws->list->data; - else if (pos >= 0) - wid = g_list_nth_data(wm->cws->list, pos); + if (pos < 0) { + wid = g_list_last(wm->cws->list)->data; + pos = g_list_length(wm->cws->list) - 1; + } else if (pos >= g_list_length(wm->cws->list)) { + wid = wm->cws->list->data; + pos = 0; + } else + wid = g_list_nth_data(wm->cws->list, pos); + } while (urgent && !GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT) && pos != orgpos); gnt_wm_raise_window(wm, wid); } @@ -421,7 +426,7 @@ window_next(GntBindable *bindable, GList *null) { GntWM *wm = GNT_WM(bindable); - switch_window(wm, 1); + switch_window(wm, 1, FALSE); return TRUE; } @@ -429,7 +434,7 @@ window_prev(GntBindable *bindable, GList *null) { GntWM *wm = GNT_WM(bindable); - switch_window(wm, -1); + switch_window(wm, -1, FALSE); return TRUE; } @@ -1202,6 +1207,22 @@ return ignore_keys ? !(ignore_keys = FALSE) : FALSE; } +static gboolean +window_next_urgent(GntBindable *bindable, GList *n) +{ + GntWM *wm = GNT_WM(bindable); + switch_window(wm, 1, TRUE); + return TRUE; +} + +static gboolean +window_prev_urgent(GntBindable *bindable, GList *n) +{ + GntWM *wm = GNT_WM(bindable); + switch_window(wm, -1, TRUE); + return TRUE; +} + #ifdef USE_PYTHON static void python_script_selected(GntFileSel *fs, const char *path, const char *f, gpointer n) @@ -1323,6 +1344,7 @@ { int i; GObjectClass *gclass = G_OBJECT_CLASS(klass); + char key[32]; gclass->dispose = gnt_wm_destroy; @@ -1482,10 +1504,15 @@ "\033" "\\", NULL); gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "help-for-window", help_for_window, "\033" "|", NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-start", ignore_keys_start, + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-start", ignore_keys_start, GNT_KEY_CTRL_G, NULL); - gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-end", ignore_keys_end, + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "ignore-keys-end", ignore_keys_end, "\033" GNT_KEY_CTRL_G, NULL); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next-urgent", window_next_urgent, + "\033" "\t", NULL); + snprintf(key, sizeof(key), "\033%s", GNT_KEY_BACK_TAB); + gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-prev-urgent", window_prev_urgent, + key[1] ? key : NULL, NULL); #ifdef USE_PYTHON gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "run-python", run_python, GNT_KEY_F3, NULL);
--- a/libpurple/buddyicon.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/buddyicon.c Sat Jan 05 18:07:16 2008 +0000 @@ -124,7 +124,7 @@ purple_imgstore_get_size(img)); } else { purple_debug_error("buddyicon", "Unable to create file %s: %s\n", - path, g_strerror(errno)); + path, "File already exists."); } g_free(path); }
--- a/libpurple/protocols/bonjour/mdns_win32.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Sat Jan 05 18:07:16 2008 +0000 @@ -30,19 +30,21 @@ static GSList *pending_buddies = NULL; +typedef struct _dnssd_service_ref_handler { + DNSServiceRef sdRef; + PurpleAccount *account; + guint input_handler; +} DnsSDServiceRefHandlerData; + /* data used by win32 bonjour implementation */ typedef struct _win32_session_impl_data { - DNSServiceRef presence_svc; - DNSServiceRef browser_svc; + DnsSDServiceRefHandlerData *presence_query; + DnsSDServiceRefHandlerData *browser_query; DNSRecordRef buddy_icon_rec; - - guint presence_handler; - guint browser_handler; } Win32SessionImplData; typedef struct _win32_buddy_service_resolver_data { - DNSServiceRef txt_query; - guint txt_query_handler; + DnsSDServiceRefHandlerData *txt_query; uint32_t if_idx; gchar *name; gchar *type; @@ -53,21 +55,20 @@ typedef struct _win32_buddy_impl_data { GSList *resolvers; - DNSServiceRef null_query; - guint null_query_handler; + DnsSDServiceRefHandlerData *null_query; } Win32BuddyImplData; /* data structure for the resolve callback */ typedef struct _ResolveCallbackArgs { - DNSServiceRef resolver; - guint resolver_handler; + DnsSDServiceRefHandlerData *resolver_query; PurpleAccount *account; BonjourBuddy *bb; Win32SvcResolverData *res_data; gchar *full_service_name; - PurpleDnsQueryData *query; + PurpleDnsQueryData *dns_query; } ResolveCallbackArgs; + static gint _find_resolver_data(gconstpointer a, gconstpointer b) { const Win32SvcResolverData *rd_a = a; @@ -87,8 +88,9 @@ static void _cleanup_resolver_data(Win32SvcResolverData *rd) { if (rd->txt_query != NULL) { - purple_input_remove(rd->txt_query_handler); - DNSServiceRefDeallocate(rd->txt_query); + purple_input_remove(rd->txt_query->input_handler); + DNSServiceRefDeallocate(rd->txt_query->sdRef); + g_free(rd->txt_query); } g_free(rd->name); g_free(rd->type); @@ -98,7 +100,16 @@ static void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) { - DNSServiceProcessResult((DNSServiceRef) data); + DnsSDServiceRefHandlerData *srh = data; + DNSServiceErrorType errorCode = DNSServiceProcessResult(srh->sdRef); + if (errorCode != kDNSServiceErr_NoError) { + purple_debug_error("bonjour", "Error (%d) handling mDNS response.\n", errorCode); + /* This happens when the mDNSResponder goes down, I haven't seen it happen any other time (in my limited testing) */ + if (errorCode == kDNSServiceErr_Unknown) { + purple_connection_error_reason(srh->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Error communicating with local mDNSResponder.")); + } + } } static void @@ -123,7 +134,7 @@ uint32_t ttl, void *context) { - if (kDNSServiceErr_NoError != errorCode) { + if (errorCode != kDNSServiceErr_NoError) { purple_debug_error("bonjour", "record query - callback error.\n"); /* TODO: Probably should remove the buddy when this happens */ } else if (flags & kDNSServiceFlagsAdd) { @@ -142,9 +153,9 @@ bonjour_buddy_got_buddy_icon(bb, rdata, rdlen); /* We've got what we need; stop listening */ - purple_input_remove(idata->null_query_handler); - idata->null_query_handler = 0; - DNSServiceRefDeallocate(idata->null_query); + purple_input_remove(idata->null_query->input_handler); + DNSServiceRefDeallocate(idata->null_query->sdRef); + g_free(idata->null_query); idata->null_query = NULL; } } @@ -153,7 +164,7 @@ static void _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) { - ResolveCallbackArgs* args = (ResolveCallbackArgs*) data; + ResolveCallbackArgs *args = (ResolveCallbackArgs*) data; Win32BuddyImplData *idata = args->bb->mdns_impl_data; gboolean delete_buddy = FALSE; PurpleBuddy *pb; @@ -168,27 +179,31 @@ delete_buddy = TRUE; } else { struct sockaddr_in *addr = g_slist_nth_data(hosts, 1); + DNSServiceErrorType errorCode; + DNSServiceRef txt_query_sr; /* finally, set up the continuous txt record watcher, and add the buddy to purple */ - - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&args->res_data->txt_query, kDNSServiceFlagsLongLivedQuery, + errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery, kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT, - kDNSServiceClass_IN, _mdns_record_query_callback, args->bb)) { - + kDNSServiceClass_IN, _mdns_record_query_callback, args->bb); + if (errorCode == kDNSServiceErr_NoError) { const char *ip = inet_ntoa(addr->sin_addr); purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj); - args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip)); args->res_data->ip = args->bb->ips->data; - args->res_data->txt_query_handler = purple_input_add(DNSServiceRefSockFD(args->res_data->txt_query), + args->res_data->txt_query = g_new(DnsSDServiceRefHandlerData, 1); + args->res_data->txt_query->sdRef = txt_query_sr; + args->res_data->txt_query->account = args->account; + + args->res_data->txt_query->input_handler = purple_input_add(DNSServiceRefSockFD(txt_query_sr), PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query); bonjour_buddy_add_to_purple(args->bb, NULL); } else { - purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s\n", args->bb->name); + purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode); delete_buddy = TRUE; } @@ -230,21 +245,21 @@ _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context) { - ResolveCallbackArgs *args = (ResolveCallbackArgs*)context; + ResolveCallbackArgs *args = (ResolveCallbackArgs*) context; Win32BuddyImplData *idata = args->bb->mdns_impl_data; /* remove the input fd and destroy the service ref */ - purple_input_remove(args->resolver_handler); - args->resolver_handler = 0; - DNSServiceRefDeallocate(args->resolver); - args->resolver = NULL; + purple_input_remove(args->resolver_query->input_handler); + DNSServiceRefDeallocate(args->resolver_query->sdRef); + g_free(args->resolver_query); + args->resolver_query = NULL; - if (kDNSServiceErr_NoError != errorCode) + if (errorCode != kDNSServiceErr_NoError) purple_debug_error("bonjour", "service resolver - callback error.\n"); else { /* set more arguments, and start the host resolver */ - if ((args->query = + if ((args->dns_query = purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args)) != NULL) { args->full_service_name = g_strdup(fullname); @@ -286,7 +301,7 @@ const char *name, const char *regtype, const char *domain, void *context) { /* TODO: deal with collision */ - if (kDNSServiceErr_NoError != errorCode) + if (errorCode != kDNSServiceErr_NoError) purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode); else purple_debug_info("bonjour", "service advertisement - callback.\n"); @@ -298,26 +313,28 @@ { PurpleAccount *account = (PurpleAccount*)context; - if (kDNSServiceErr_NoError != errorCode) - purple_debug_error("bonjour", "service browser - callback error\n"); + if (errorCode != kDNSServiceErr_NoError) + purple_debug_error("bonjour", "service browser - callback error (%d)\n", errorCode); else if (flags & kDNSServiceFlagsAdd) { /* A presence service instance has been discovered... check it isn't us! */ if (purple_utf8_strcasecmp(serviceName, account->username) != 0) { + DNSServiceErrorType resErrorCode; /* OK, lets go ahead and resolve it to add to the buddy list */ ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1); + DNSServiceRef resolver_sr; purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n", serviceName, interfaceIndex, regtype ? regtype : "", replyDomain ? replyDomain : ""); - if (kDNSServiceErr_NoError == DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, - replyDomain, _mdns_service_resolve_callback, args)) { + resErrorCode = DNSServiceResolve(&resolver_sr, 0, 0, serviceName, regtype, + replyDomain, _mdns_service_resolve_callback, args); + if (resErrorCode == kDNSServiceErr_NoError) { GSList *tmp = pending_buddies; PurpleBuddy *pb; BonjourBuddy* bb = NULL; Win32SvcResolverData *rd; Win32BuddyImplData *idata; - gint fd; /* Is there an existing buddy? */ if ((pb = purple_find_buddy(account, serviceName))) @@ -344,7 +361,6 @@ pb->proto_data = bb; } - rd = g_new0(Win32SvcResolverData, 1); rd->if_idx = interfaceIndex; rd->name = g_strdup(serviceName); @@ -358,11 +374,14 @@ args->res_data = rd; args->account = account; + args->resolver_query = g_new(DnsSDServiceRefHandlerData, 1); + args->resolver_query->sdRef = resolver_sr; + args->resolver_query->account = account; /* get a file descriptor for this service ref, and add it to the input list */ - fd = DNSServiceRefSockFD(args->resolver); - args->resolver_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver); + args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(resolver_sr), + PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query); } else { - purple_debug_error("bonjour", "service browser - failed to resolve service.\n"); + purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode); g_free(args); } } @@ -432,7 +451,7 @@ gboolean _mdns_publish(BonjourDnsSd *data, PublishType type, GSList *records) { TXTRecordRef dns_data; gboolean ret = TRUE; - DNSServiceErrorType set_ret = kDNSServiceErr_NoError; + DNSServiceErrorType errorCode = kDNSServiceErr_NoError; Win32SessionImplData *idata = data->mdns_impl_data; g_return_val_if_fail(idata != NULL, FALSE); @@ -441,44 +460,46 @@ while (records) { PurpleKeyValuePair *kvp = records->data; - set_ret = TXTRecordSetValue(&dns_data, kvp->key, strlen(kvp->value), kvp->value); - if (set_ret != kDNSServiceErr_NoError) + errorCode = TXTRecordSetValue(&dns_data, kvp->key, strlen(kvp->value), kvp->value); + if (errorCode != kDNSServiceErr_NoError) break; records = records->next; } - if (set_ret != kDNSServiceErr_NoError) { - purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + if (errorCode != kDNSServiceErr_NoError) { + purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode); ret = FALSE; } else { - DNSServiceErrorType err = kDNSServiceErr_NoError; - /* OK, we're done constructing the text record, (re)publish the service */ + DNSServiceRef presence_sr; switch (type) { case PUBLISH_START: purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj); - err = DNSServiceRegister(&idata->presence_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, + errorCode = DNSServiceRegister(&presence_sr, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), _mdns_service_register_callback, NULL); break; case PUBLISH_UPDATE: purple_debug_info("bonjour", "Updating presence.\n"); - err = DNSServiceUpdateRecord(idata->presence_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); + errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); break; } - if (err != kDNSServiceErr_NoError) { - purple_debug_error("bonjour", "Failed to publish presence service.\n"); + if (errorCode != kDNSServiceErr_NoError) { + purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode); ret = FALSE; } else if (type == PUBLISH_START) { /* We need to do this because according to the Apple docs: * "the client is responsible for ensuring that DNSServiceProcessResult() is called * whenever there is a reply from the daemon - the daemon may terminate its connection * with a client that does not process the daemon's responses */ - idata->presence_handler = purple_input_add(DNSServiceRefSockFD(idata->presence_svc), - PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_svc); + idata->presence_query = g_new(DnsSDServiceRefHandlerData, 1); + idata->presence_query->sdRef = presence_sr; + idata->presence_query->account = data->account; + idata->presence_query->input_handler = purple_input_add(DNSServiceRefSockFD(presence_sr), + PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_query); } } @@ -488,17 +509,24 @@ } gboolean _mdns_browse(BonjourDnsSd *data) { + DNSServiceErrorType errorCode; Win32SessionImplData *idata = data->mdns_impl_data; + DNSServiceRef browser_sr; g_return_val_if_fail(idata != NULL, FALSE); - if (DNSServiceBrowse(&idata->browser_svc, 0, 0, ICHAT_SERVICE, NULL, - _mdns_service_browse_callback, data->account) - == kDNSServiceErr_NoError) { - idata->browser_handler = purple_input_add(DNSServiceRefSockFD(idata->browser_svc), - PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_svc); + errorCode = DNSServiceBrowse(&browser_sr, 0, 0, ICHAT_SERVICE, NULL, + _mdns_service_browse_callback, data->account); + if (errorCode == kDNSServiceErr_NoError) { + idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1); + idata->browser_query->sdRef = browser_sr; + idata->browser_query->account = data->account; + idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr), + PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_query); return TRUE; - } + } else + purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode); + return FALSE; } @@ -509,14 +537,16 @@ if (idata == NULL) return; - if (idata->presence_svc != NULL) { - purple_input_remove(idata->presence_handler); - DNSServiceRefDeallocate(idata->presence_svc); + if (idata->presence_query != NULL) { + purple_input_remove(idata->presence_query->input_handler); + DNSServiceRefDeallocate(idata->presence_query->sdRef); + g_free(idata->presence_query); } - if (idata->browser_svc != NULL) { - purple_input_remove(idata->browser_handler); - DNSServiceRefDeallocate(idata->browser_svc); + if (idata->browser_query != NULL) { + purple_input_remove(idata->browser_query->input_handler); + DNSServiceRefDeallocate(idata->browser_query->sdRef); + g_free(idata->browser_query); } g_free(idata); @@ -526,28 +556,30 @@ gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { Win32SessionImplData *idata = data->mdns_impl_data; - DNSServiceErrorType err = kDNSServiceErr_NoError; + DNSServiceErrorType errorCode = kDNSServiceErr_NoError; g_return_val_if_fail(idata != NULL, FALSE); if (avatar_data != NULL && idata->buddy_icon_rec == NULL) { purple_debug_info("bonjour", "Setting new buddy icon.\n"); - err = DNSServiceAddRecord(idata->presence_svc, &idata->buddy_icon_rec, + errorCode = DNSServiceAddRecord(idata->presence_query->sdRef, &idata->buddy_icon_rec, 0, kDNSServiceType_NULL, avatar_len, avatar_data, 0); } else if (avatar_data != NULL) { purple_debug_info("bonjour", "Updating existing buddy icon.\n"); - err = DNSServiceUpdateRecord(idata->presence_svc, idata->buddy_icon_rec, + errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, idata->buddy_icon_rec, 0, avatar_len, avatar_data, 0); } else if (idata->buddy_icon_rec != NULL) { purple_debug_info("bonjour", "Removing existing buddy icon.\n"); - DNSServiceRemoveRecord(idata->presence_svc, idata->buddy_icon_rec, 0); + errorCode = DNSServiceRemoveRecord(idata->presence_query->sdRef, idata->buddy_icon_rec, 0); idata->buddy_icon_rec = NULL; } - if (err != kDNSServiceErr_NoError) - purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", err); + if (errorCode != kDNSServiceErr_NoError) { + purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", errorCode); + return FALSE; + } - return (err == kDNSServiceErr_NoError); + return TRUE; } void _mdns_init_buddy(BonjourBuddy *buddy) { @@ -566,8 +598,9 @@ } if (idata->null_query != NULL) { - purple_input_remove(idata->null_query_handler); - DNSServiceRefDeallocate(idata->null_query); + purple_input_remove(idata->null_query->input_handler); + DNSServiceRefDeallocate(idata->null_query->sdRef); + g_free(idata->null_query); } g_free(idata); @@ -583,17 +616,30 @@ /* Cancel any existing query */ if (idata->null_query != NULL) { - purple_input_remove(idata->null_query_handler); - idata->null_query_handler = 0; - DNSServiceRefDeallocate(idata->null_query); + purple_input_remove(idata->null_query->input_handler); + DNSServiceRefDeallocate(idata->null_query->sdRef); + g_free(idata->null_query); idata->null_query = NULL; } - DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local"); - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, kDNSServiceInterfaceIndexAny, svc_name, - kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy)) { - idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query), - PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); + if (DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local") != 0) + purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy->name); + else { + DNSServiceRef null_query_sr; + + DNSServiceErrorType errorCode = DNSServiceQueryRecord(&null_query_sr, 0, kDNSServiceInterfaceIndexAny, + svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy); + + if (errorCode == kDNSServiceErr_NoError) { + idata->null_query = g_new(DnsSDServiceRefHandlerData, 1); + + idata->null_query->sdRef = null_query_sr; + idata->null_query->account = buddy->account; + + idata->null_query->input_handler = purple_input_add(DNSServiceRefSockFD(null_query_sr), + PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); + } else + purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode); } }
--- a/libpurple/protocols/jabber/jabber.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sat Jan 05 18:07:16 2008 +0000 @@ -614,7 +614,7 @@ js->user = jabber_id_new(purple_account_get_username(account)); js->next_id = g_random_int(); js->write_buffer = purple_circ_buffer_new(512); - js->old_length = -1; + js->old_length = 0; js->keepalive_timeout = -1; if(!js->user) { @@ -1100,7 +1100,7 @@ g_free, g_free); js->user = jabber_id_new(purple_account_get_username(account)); js->next_id = g_random_int(); - js->old_length = -1; + js->old_length = 0; if(!js->user) { purple_connection_error_reason (gc, @@ -1523,10 +1523,16 @@ } else purple_notify_user_info_add_pair(user_info, _("Mood"), mood); } - if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { PurpleStatus *tune = purple_presence_get_status(presence, "tune"); const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); - purple_notify_user_info_add_pair(user_info, _("Current media"), title); + const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); + const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); + char *playing = purple_util_format_song_info(title, artist, album, NULL); + if (playing) { + purple_notify_user_info_add_pair(user_info, _("Now Listening"), playing); + g_free(playing); + } } }
--- a/libpurple/protocols/jabber/usertune.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/jabber/usertune.c Sat Jan 05 18:07:16 2008 +0000 @@ -35,11 +35,12 @@ xmlnode *tuneinfo, *tune; PurpleJabberTuneInfo tuneinfodata; JabberBuddyResource *resource; - + gboolean valid = FALSE; + /* ignore the tune of people not on our buddy list */ if (!buddy || !item) return; - + tuneinfodata.artist = NULL; tuneinfodata.title = NULL; tuneinfodata.album = NULL; @@ -58,36 +59,47 @@ if (!strcmp(tuneinfo->name, "artist")) { if (tuneinfodata.artist == NULL) /* only pick the first one */ tuneinfodata.artist = xmlnode_get_data(tuneinfo); + valid = TRUE; } 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); + if (tuneinfodata.time > 0) + valid = TRUE; } } else if (!strcmp(tuneinfo->name, "source")) { if (tuneinfodata.album == NULL) /* only pick the first one */ tuneinfodata.album = xmlnode_get_data(tuneinfo); + valid = TRUE; } else if (!strcmp(tuneinfo->name, "title")) { if (tuneinfodata.title == NULL) /* only pick the first one */ tuneinfodata.title = xmlnode_get_data(tuneinfo); + valid = TRUE; } else if (!strcmp(tuneinfo->name, "track")) { if (tuneinfodata.track == NULL) /* only pick the first one */ tuneinfodata.track = xmlnode_get_data(tuneinfo); + valid = TRUE; } else if (!strcmp(tuneinfo->name, "uri")) { if (tuneinfodata.url == NULL) /* only pick the first one */ tuneinfodata.url = xmlnode_get_data(tuneinfo); + valid = TRUE; } } } - purple_prpl_got_user_status(js->gc->account, from, "tune", - 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); + if (valid) { + purple_prpl_got_user_status(js->gc->account, from, "tune", + 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); + } else { + purple_prpl_got_user_status_deactive(js->gc->account, from, "tune"); + } g_free(tuneinfodata.artist); g_free(tuneinfodata.title); @@ -119,7 +131,7 @@ xmlnode_insert_data(xmlnode_new_child(tunenode, "source"),tuneinfo->album,-1); if(tuneinfo->url && tuneinfo->url[0] != '\0') xmlnode_insert_data(xmlnode_new_child(tunenode, "uri"),tuneinfo->url,-1); - if(tuneinfo->time >= 0) { + if(tuneinfo->time > 0) { char *length = g_strdup_printf("%d", tuneinfo->time); xmlnode_insert_data(xmlnode_new_child(tunenode, "length"),length,-1); g_free(length);
--- a/libpurple/protocols/msn/msn.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/msn/msn.c Sat Jan 05 18:07:16 2008 +0000 @@ -593,8 +593,8 @@ PurpleStatus *tune = purple_presence_get_status(presence, "tune"); const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); - currentmedia = g_strdup_printf("%s%s%s", title, artist ? " - " : "", - artist ? artist : ""); + const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); + currentmedia = purple_util_format_song_info(title, artist, album, NULL); /* We could probably just use user->media.title etc. here */ } @@ -643,9 +643,7 @@ } if (currentmedia) { - tmp = g_markup_escape_text(currentmedia, -1); - purple_notify_user_info_add_pair(user_info, _("Current media"), tmp); - g_free(tmp); + purple_notify_user_info_add_pair(user_info, _("Now Listening"), currentmedia); g_free(currentmedia); } }
--- a/libpurple/protocols/oscar/family_auth.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/family_auth.c Sat Jan 05 18:07:16 2008 +0000 @@ -196,6 +196,10 @@ * unknown= 0x0000008b * serverstore = 0x01 * + * @param truncate_pass Truncate the password to 8 characters. This + * usually happens for AOL accounts. We are told that we + * should truncate it if the 0x0017/0x0007 SNAC contains + * a TLV of type 0x0026 with data 0x0000. */ int aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key) @@ -522,8 +526,8 @@ /* * If the truncate_pass TLV exists then we should truncate the - * user's password to 8 characters. This flag is sent when you - * try to log in with an AOL user's screen name. + * user's password to 8 characters. This flag is sent to us + * when logging in with an AOL user's screen name. */ truncate_pass = aim_tlv_gettlv(tlvlist, 0x0026, 1) != NULL;
--- a/libpurple/protocols/oscar/family_icbm.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Sat Jan 05 18:07:16 2008 +0000 @@ -51,6 +51,9 @@ #include "win32dep.h" #endif +#include "util.h" + + /** * Add a standard ICBM header to the given bstream with the given * information. @@ -2335,11 +2338,166 @@ sn = byte_stream_getstr(bs, snlen); reason = byte_stream_get16(bs); - if (channel == 0x0002) { /* File transfer declined */ + if (channel == 0x0002) + { + /* parse status note text */ + + struct aim_icq_info *info = NULL; + struct aim_icq_info *prev_info = NULL; + char *response = NULL; + char *encoding = NULL; + char *stripped_encoding = NULL; + char *status_note_text = NULL; + char *stripped_status_note_text = NULL; + char *status_note = NULL; + + /* + * TODO: Using a while statement here is kind of an ugly hack + * to be able to use 'break'. We might as well be using + * 'goto'. Should probably get rid of this. + */ + while (reason == 0x0003) /* channel-specific */ + { + guint32 length; + guint16 version; + guint32 capability; + guint8 message_type; + guint16 status_code; + guint16 text_length; + guint32 request_length; + guint32 response_length; + guint32 encoding_length; + PurpleAccount *account; + PurpleBuddy *buddy; + PurplePresence *presence; + PurpleStatus *status; + + for (info = od->icq_info; info != NULL; info = info->next) + { + if (memcmp(&info->icbm_cookie, cookie, 8) == 0) + { + if (prev_info == NULL) + od->icq_info = info->next; + else + prev_info->next = info->next; + + break; + } + + prev_info = info; + } + + if (info == NULL) + break; + + if ((length = byte_stream_getle16(bs)) != 27) + { + purple_debug_misc("oscar", "clientautoresp: incorrect header size; expected 27, received %u.\n", length); + break; + } + if ((version = byte_stream_getle16(bs)) != 9) + { + purple_debug_misc("oscar", "clientautoresp: incorrect version; expected 9, received %u.\n", version); + break; + } + capability = aim_locate_getcaps(od, bs, 0x10); + if (capability != OSCAR_CAPABILITY_EMPTY) + { + purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n"); + break; + } + byte_stream_advance(bs, 2); /* unknown */ + byte_stream_advance(bs, 4); /* client capabilities flags */ + byte_stream_advance(bs, 1); /* unknown */ + byte_stream_advance(bs, 2); /* downcouner? */ + + if ((length = byte_stream_getle16(bs)) != 14) + { + purple_debug_misc("oscar", "clientautoresp: incorrect header size; expected 14, received %u.\n", length); + break; + } + byte_stream_advance(bs, 2); /* downcounter? */ + byte_stream_advance(bs, 12); /* unknown */ + + if ((message_type = byte_stream_get8(bs)) != 0x1a) + { + purple_debug_misc("oscar", "clientautoresp: incorrect message type; expected 0x1a, received 0x%x.\n", message_type); + break; + } + byte_stream_advance(bs, 1); /* message flags */ + if ((status_code = byte_stream_getle16(bs)) != 0) + { + purple_debug_misc("oscar", "clientautoresp: incorrect status code; expected 0, received %u.\n", status_code); + break; + } + byte_stream_advance(bs, 2); /* priority code */ + + text_length = byte_stream_getle16(bs); + byte_stream_advance(bs, text_length); /* text */ + + length = byte_stream_getle16(bs); + byte_stream_advance(bs, 18); /* unknown */ + if (length != 18 + 4 + (request_length = byte_stream_getle32(bs)) + 17) + { + purple_debug_misc("oscar", "clientautoresp: incorrect block; expected length is %u, got %u.\n", 18 + 4 + request_length + 17, length); + break; + } + byte_stream_advance(bs, request_length); /* x request */ + byte_stream_advance(bs, 17); /* unknown */ + + length = byte_stream_getle32(bs); + response_length = byte_stream_getle32(bs); + response = byte_stream_getstr(bs, response_length); + if (length != 4 + response_length + 4 + (encoding_length = byte_stream_getle32(bs))) + { + purple_debug_misc("oscar", "clientautoresp: incorrect block; expected length is %u, got %u.\n", 4 + response_length + 4 + encoding_length, length); + break; + } + encoding = byte_stream_getstr(bs, encoding_length); + + account = purple_connection_get_account(od->gc); + stripped_encoding = oscar_encoding_extract(encoding); + status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length); + stripped_status_note_text = purple_markup_strip_html(status_note_text); + + if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0) + status_note = g_strdup_printf("%s: %s", info->status_note_title, stripped_status_note_text); + else + status_note = g_strdup(info->status_note_title); + + buddy = purple_find_buddy(account, sn); + if (buddy == NULL) + { + purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", sn); + break; + } + + purple_debug_misc("oscar", "clientautoresp: setting status message to \"%s\".\n", status_note); + + presence = purple_buddy_get_presence(buddy); + status = purple_presence_get_active_status(presence); + + purple_prpl_got_user_status(account, sn, + purple_status_get_id(status), + "message", status_note, NULL); + + break; + } + + g_free(status_note); + g_free(stripped_status_note_text); + g_free(status_note_text); + g_free(stripped_encoding); + g_free(encoding); + g_free(response); + g_free(info->status_note_title); + g_free(info); + byte_stream_get16(bs); /* Unknown */ byte_stream_get16(bs); /* Unknown */ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, channel, sn, reason, cookie); + } else if (channel == 0x0004) { /* ICQ message */ switch (reason) { case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */
--- a/libpurple/protocols/oscar/family_icq.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/family_icq.c Sat Jan 05 18:07:16 2008 +0000 @@ -435,6 +435,65 @@ return 0; } +/* + * getstatusnote may be a misleading name because the response + * contains a lot of different information but currently it's only + * used to get that. + */ +int aim_icq_getstatusnote(OscarData *od, const char *uin, guint8 *note_hash, guint16 note_hash_len) +{ + FlapConnection *conn; + FlapFrame *frame; + aim_snacid_t snacid; + int bslen; + + purple_debug_misc("oscar", "aim_icq_getstatusnote: requesting status note for %s.\n", uin); + + if (!od || !(conn = flap_connection_findbygroup(od, 0x0015))) + { + purple_debug_misc("oscar", "aim_icq_getstatusnote: no connection.\n"); + return -EINVAL; + } + + bslen = 2 + 4 + 2 + 2 + 2 + 2 + 58 + strlen(uin); + + frame = flap_frame_new(od, 0x02, 10 + 4 + bslen); + + snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid); + + /* For simplicity, don't bother using a tlvlist */ + byte_stream_put16(&frame->data, 0x0001); + byte_stream_put16(&frame->data, bslen); + + byte_stream_putle16(&frame->data, bslen - 2); + byte_stream_putle32(&frame->data, atoi(od->sn)); + byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */ + byte_stream_putle16(&frame->data, snacid); /* eh. */ + byte_stream_putle16(&frame->data, 0x0fa0); /* shrug. */ + byte_stream_putle16(&frame->data, 58 + strlen(uin)); + + byte_stream_put32(&frame->data, 0x05b90002); /* don't ask */ + byte_stream_put32(&frame->data, 0x80000000); + byte_stream_put32(&frame->data, 0x00000006); + byte_stream_put32(&frame->data, 0x00010002); + byte_stream_put32(&frame->data, 0x00020000); + byte_stream_put32(&frame->data, 0x04e30000); + byte_stream_put32(&frame->data, 0x00020002); + byte_stream_put32(&frame->data, 0x00000001); + + byte_stream_put16(&frame->data, 24 + strlen(uin)); + byte_stream_put32(&frame->data, 0x003c0010); + byte_stream_putraw(&frame->data, note_hash, 16); /* status note hash */ + byte_stream_put16(&frame->data, 0x0032); /* buddy uin */ + byte_stream_put16(&frame->data, strlen(uin)); + byte_stream_putstr(&frame->data, uin); + + flap_connection_send(conn, frame); + + return 0; +} + static void aim_icq_freeinfo(struct aim_icq_info *info) { int i; @@ -467,6 +526,7 @@ g_free(info->workposition); g_free(info->workwebpage); g_free(info->info); + g_free(info->status_note_title); g_free(info); } @@ -641,6 +701,178 @@ info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs)); /* Then 0x00 02 00 00 00 00 00 */ } break; + + /* status note title and send request for status note text */ + case 0x0fb4: { + GSList *tlvlist; + aim_tlv_t *tlv; + FlapConnection *conn; + char *uin = NULL; + char *status_note_title = NULL; + + conn = flap_connection_findbygroup(od, 0x0004); + if (conn == NULL) + { + purple_debug_misc("oscar", "icq/0x0fb4: flap connection was not found.\n"); + break; + } + + byte_stream_advance(&qbs, 0x02); /* length */ + byte_stream_advance(&qbs, 0x2f); /* unknown stuff */ + + tlvlist = aim_tlvlist_read(&qbs); + + tlv = aim_tlv_gettlv(tlvlist, 0x0032, 1); + if (tlv != NULL) + /* Get user number */ + uin = aim_tlv_getvalue_as_string(tlv); + + tlv = aim_tlv_gettlv(tlvlist, 0x0226, 1); + if (tlv != NULL) + /* Get status note title */ + status_note_title = aim_tlv_getvalue_as_string(tlv); + + aim_tlvlist_free(tlvlist); + + if (uin == NULL || status_note_title == NULL) + { + purple_debug_misc("oscar", "icq/0x0fb4: uin or " + "status_note_title was not found\n"); + g_free(uin); + g_free(status_note_title); + break; + } + + if (status_note_title[0] == '\0') + { + PurpleAccount *account; + PurpleBuddy *buddy; + PurplePresence *presence; + PurpleStatus *status; + + account = purple_connection_get_account(od->gc); + buddy = purple_find_buddy(account, uin); + presence = purple_buddy_get_presence(buddy); + status = purple_presence_get_active_status(presence); + + purple_prpl_got_user_status(account, uin, + purple_status_get_id(status), + "message", NULL, NULL); + + g_free(status_note_title); + } + else + { + struct aim_icq_info *info; + guint32 data_len; + FlapFrame *frame; + aim_snacid_t snacid; + guchar cookie[8]; + + info = g_new0(struct aim_icq_info, 1); + + if (info == NULL) + { + g_free(uin); + g_free(status_note_title); + + break; + } + + data_len = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4; + frame = flap_frame_new(od, 0x0002, 10 + 4 + data_len); + snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + + aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid); + + aim_icbm_makecookie(cookie); + + byte_stream_putraw(&frame->data, cookie, 8); /* ICBM cookie */ + byte_stream_put16(&frame->data, 0x0002); /* message channel */ + byte_stream_put8(&frame->data, strlen(uin)); /* uin */ + byte_stream_putstr(&frame->data, uin); + + byte_stream_put16(&frame->data, 0x0005); /* rendez vous data */ + byte_stream_put16(&frame->data, 0x00b2); + byte_stream_put16(&frame->data, 0x0000); /* request */ + byte_stream_putraw(&frame->data, cookie, 8); /* ICBM cookie */ + byte_stream_put32(&frame->data, 0x09461349); /* ICQ server relaying */ + byte_stream_put16(&frame->data, 0x4c7f); + byte_stream_put16(&frame->data, 0x11d1); + byte_stream_put32(&frame->data, 0x82224445); + byte_stream_put32(&frame->data, 0x53540000); + + byte_stream_put16(&frame->data, 0x000a); /* unknown TLV */ + byte_stream_put16(&frame->data, 0x0002); + byte_stream_put16(&frame->data, 0x0001); + + byte_stream_put16(&frame->data, 0x000f); /* unknown TLV */ + byte_stream_put16(&frame->data, 0x0000); + + byte_stream_put16(&frame->data, 0x2711); /* extended data */ + byte_stream_put16(&frame->data, 0x008a); + byte_stream_putle16(&frame->data, 0x001b); /* length */ + byte_stream_putle16(&frame->data, 0x0009); /* version */ + byte_stream_putle32(&frame->data, 0x00000000); /* plugin: none */ + byte_stream_putle32(&frame->data, 0x00000000); + byte_stream_putle32(&frame->data, 0x00000000); + byte_stream_putle32(&frame->data, 0x00000000); + byte_stream_putle16(&frame->data, 0x0000); /* unknown */ + byte_stream_putle32(&frame->data, 0x00000000); /* client capabilities flags */ + byte_stream_put8(&frame->data, 0x00); /* unknown */ + byte_stream_putle16(&frame->data, 0x0064); /* downcounter? */ + byte_stream_putle16(&frame->data, 0x000e); /* length */ + byte_stream_putle16(&frame->data, 0x0064); /* downcounter? */ + byte_stream_putle32(&frame->data, 0x00000000); /* unknown */ + byte_stream_putle32(&frame->data, 0x00000000); + byte_stream_putle32(&frame->data, 0x00000000); + byte_stream_put8(&frame->data, 0x1a); /* message type: plugin message descibed by text string */ + byte_stream_put8(&frame->data, 0x00); /* message flags */ + byte_stream_putle16(&frame->data, 0x0000); /* status code */ + byte_stream_putle16(&frame->data, 0x0001); /* priority code */ + byte_stream_putle16(&frame->data, 0x0000); /* text length */ + + byte_stream_put8(&frame->data, 0x3a); /* message dump */ + byte_stream_put32(&frame->data, 0x00811a18); + byte_stream_put32(&frame->data, 0xbc0e6c18); + byte_stream_put32(&frame->data, 0x47a5916f); + byte_stream_put32(&frame->data, 0x18dcc76f); + byte_stream_put32(&frame->data, 0x1a010013); + byte_stream_put32(&frame->data, 0x00000041); + byte_stream_put32(&frame->data, 0x77617920); + byte_stream_put32(&frame->data, 0x53746174); + byte_stream_put32(&frame->data, 0x7573204d); + byte_stream_put32(&frame->data, 0x65737361); + byte_stream_put32(&frame->data, 0x67650100); + byte_stream_put32(&frame->data, 0x00000000); + byte_stream_put32(&frame->data, 0x00000000); + byte_stream_put32(&frame->data, 0x00000000); + byte_stream_put32(&frame->data, 0x00000015); + byte_stream_put32(&frame->data, 0x00000000); + byte_stream_put32(&frame->data, 0x0000000d); + byte_stream_put32(&frame->data, 0x00000074); + byte_stream_put32(&frame->data, 0x6578742f); + byte_stream_put32(&frame->data, 0x782d616f); + byte_stream_put32(&frame->data, 0x6c727466); + + byte_stream_put16(&frame->data, 0x0003); /* server ACK requested */ + byte_stream_put16(&frame->data, 0x0000); + + info->uin = atoi(uin); + info->status_note_title = status_note_title; + + memcpy(&info->icbm_cookie, cookie, 8); + + info->next = od->icq_info; + od->icq_info = info; + + flap_connection_send(conn, frame); + } + + g_free(uin); + + } break; + } /* End switch statement */ if (!(snac->flags & 0x0001)) {
--- a/libpurple/protocols/oscar/family_locate.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Sat Jan 05 18:07:16 2008 +0000 @@ -320,10 +320,10 @@ cur->away_encoding = g_strdup(userinfo->away_encoding); cur->away_len = userinfo->away_len; - } else if (!(userinfo->flags & AIM_FLAG_AWAY)) { + } else { /* - * We don't have an away message specified in this user_info block. - * If the user is not away, clear any cached away message now. + * We don't have an away message specified in this user_info + * block, so clear any cached away message now. */ if (cur->away) { g_free(cur->away); @@ -347,41 +347,6 @@ userfunc(od, conn, NULL, cur); } -void -aim_locate_dorequest(OscarData *od) -{ - struct userinfo_node *cur = od->locate.torequest; - - if (od->locate.waiting_for_response == TRUE) - return; - - od->locate.waiting_for_response = TRUE; - aim_locate_getinfoshort(od, cur->sn, 0x00000003); - - /* Move this node to the "requested" queue */ - od->locate.torequest = cur->next; - cur->next = od->locate.requested; - od->locate.requested = cur; -} - -static gboolean -purple_reqinfo_timeout_cb(void *data) -{ - OscarData *od; - - od = data; - - if (od->locate.torequest == NULL) - { - od->getinfotimer = 0; - return FALSE; - } - - aim_locate_dorequest(od); - - return TRUE; -} - /** * Remove this screen name from our queue. If this info was requested * by our info request queue, then pop the next element off of the queue. @@ -417,19 +382,6 @@ cur = cur->next; } - if (!was_explicit) { - od->locate.waiting_for_response = FALSE; - - /* - * Wait a little while then call aim_locate_dorequest(od). - * This keeps us from hitting the rate limit due to - * requesting away messages and info too quickly. - */ - if (od->getinfotimer == 0) - od->getinfotimer = purple_timeout_add(500, - purple_reqinfo_timeout_cb, od); - } - return was_explicit; } @@ -438,22 +390,18 @@ { struct userinfo_node *cur; - /* Make sure we aren't already requesting info for this buddy */ - cur = od->locate.torequest; - while (cur != NULL) { + /* Make sure we haven't already requested info for this buddy */ + for (cur = od->locate.requested; cur != NULL; cur = cur->next) if (aim_sncmp(sn, cur->sn) == 0) return; - cur = cur->next; - } /* Add a new node to our request queue */ cur = (struct userinfo_node *)g_malloc(sizeof(struct userinfo_node)); cur->sn = g_strdup(sn); - cur->next = od->locate.torequest; - od->locate.torequest = cur; + cur->next = od->locate.requested; + od->locate.requested = cur; - /* Actually request some info up in this piece */ - aim_locate_dorequest(od); + aim_locate_getinfoshort(od, cur->sn, 0x00000003); } aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn) {
--- a/libpurple/protocols/oscar/oscar.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sat Jan 05 18:07:16 2008 +0000 @@ -1722,8 +1722,7 @@ int type = 0; gboolean buddy_is_away = FALSE; const char *status_id; - gboolean have_status_message = FALSE; - char *message = NULL; + char *itmsurl = NULL; va_list ap; aim_userinfo_t *info; @@ -1771,20 +1770,10 @@ status_id = OSCAR_STATUS_ID_AVAILABLE; } - /* - * Handle the available message. If info->status is NULL then the user - * may or may not have an available message, so don't do anything. If - * info->status is set to the empty string, then the user's client DOES - * support available messages and the user DOES NOT have one set. - * Otherwise info->status contains the available message. - */ - if (info->status != NULL) - { - have_status_message = TRUE; - if (info->status[0] != '\0') - message = oscar_encoding_to_utf8(account, info->status_encoding, - info->status, info->status_len); - } + if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) + /* Grab the iTunes Music Store URL */ + itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, + info->itmsurl, info->itmsurl_len); if (info->flags & AIM_FLAG_WIRELESS) { @@ -1793,38 +1782,27 @@ purple_prpl_got_user_status_deactive(account, info->sn, OSCAR_STATUS_ID_MOBILE); } - if (have_status_message) + if (status_id == OSCAR_STATUS_ID_AVAILABLE) { - if ((!strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE)) && (info->itmsurl != NULL)) - { - char *itmsurl; - itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, - info->itmsurl, info->itmsurl_len); - purple_prpl_got_user_status(account, info->sn, status_id, - "message", message, "itmsurl", itmsurl, NULL); - g_free(itmsurl); - } - else - { - purple_prpl_got_user_status(account, info->sn, status_id, - "message", message, NULL); - } + char *message = NULL; + + if (info->status != NULL && info->status[0] != '\0') + /* Grab the available message */ + message = oscar_encoding_to_utf8(account, info->status_encoding, + info->status, info->status_len); + + purple_prpl_got_user_status(account, info->sn, status_id, + "message", message, "itmsurl", itmsurl, NULL); + g_free(message); } else { - PurpleBuddy *b = purple_find_buddy(account, info->sn); - PurpleStatus *status = NULL; - const char *active_status_id = NULL; - - if (b != NULL) { - status = purple_presence_get_active_status(purple_buddy_get_presence(b)); - active_status_id = purple_status_get_id(status); - } - - if (!active_status_id || strcmp(active_status_id, status_id)) - purple_prpl_got_user_status(account, info->sn, status_id, NULL); - } + purple_prpl_got_user_status(account, info->sn, status_id, + "itmsurl", itmsurl, NULL); + } + + g_free(itmsurl); /* Login time stuff */ if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE) @@ -1879,6 +1857,31 @@ g_free(b16); } + /* + * If we didn't receive a status message with the status change, + * or if the message is empty, and we have a note hash, then + * query the ICQ6 status note. + * + * TODO: We should probably always query the status note regardless + * of whether they have a status message set, and we should + * figure out a way to display both the status note and the + * status message at the same time. + */ + if (info->status == NULL || info->status[0] == '\0') + { + struct aim_ssi_item *ssi_item; + aim_tlv_t *note_hash; + + ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, + NULL, info->sn, AIM_SSI_TYPE_BUDDY); + if (ssi_item != NULL) + { + note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1); + if (note_hash != NULL) + aim_icq_getstatusnote(od, info->sn, note_hash->value, note_hash->length); + } + } + return 1; } @@ -3000,7 +3003,7 @@ if (!aim_snvalid_icq(userinfo->sn)) { - if (strcmp(purple_buddy_get_name(b), userinfo->sn)) + if (strcmp(purple_buddy_get_name(b), userinfo->sn) != 0) serv_got_alias(gc, purple_buddy_get_name(b), userinfo->sn); else serv_got_alias(gc, purple_buddy_get_name(b), NULL); @@ -3009,23 +3012,19 @@ presence = purple_buddy_get_presence(b); status = purple_presence_get_active_status(presence); - if (!purple_status_is_available(status) && purple_status_is_online(status)) + if (purple_status_is_online(status) && !purple_status_is_available(status) && + userinfo->flags & AIM_FLAG_AWAY && userinfo->away_len > 0 && + userinfo->away != NULL && userinfo->away_encoding != NULL) { - if ((userinfo->flags & AIM_FLAG_AWAY) && - (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { - gchar *charset = oscar_encoding_extract(userinfo->away_encoding); - message = oscar_encoding_to_utf8(account, charset, - userinfo->away, - userinfo->away_len); - g_free(charset); - purple_status_set_attr_string(status, "message", message); - g_free(message); - } - else - /* Set an empty message so that we know not to show "pending" */ - purple_status_set_attr_string(status, "message", ""); - - purple_blist_update_buddy_status(b, status); + gchar *charset = oscar_encoding_extract(userinfo->away_encoding); + message = oscar_encoding_to_utf8(account, charset, + userinfo->away, + userinfo->away_len); + g_free(charset); + purple_prpl_got_user_status(account, userinfo->sn, + purple_status_get_id(status), + "message", message, NULL); + g_free(message); } return 1; @@ -4520,12 +4519,11 @@ /* This is needed for us to un-set any previous away message. */ away = g_strdup(""); } - else if ((primitive == PURPLE_STATUS_AWAY) || - (primitive == PURPLE_STATUS_EXTENDED_AWAY)) + else { htmlaway = purple_status_get_attr_string(status, "message"); if ((htmlaway == NULL) || (*htmlaway == '\0')) - htmlaway = _("Away"); + htmlaway = purple_status_type_get_name(status_type); away = purple_prpl_oscar_convert_to_infotext(htmlaway, &awaylen, &away_encoding); if (awaylen > od->rights.maxawaymsglen) @@ -5099,6 +5097,8 @@ char *gname, *gname_utf8, *alias, *alias_utf8; PurpleBuddy *b; PurpleGroup *g; + struct aim_ssi_item *ssi_item; + aim_tlv_t *note_hash; va_list ap; guint16 snac_subtype, type; const char *name; @@ -5166,6 +5166,21 @@ } + ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, + gname, name, AIM_SSI_TYPE_BUDDY); + if (ssi_item != NULL) + { + note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1); + if (note_hash != NULL) + aim_icq_getstatusnote(od, name, note_hash->value, note_hash->length); + } + else + { + purple_debug_error("oscar", "purple_ssi_parseaddmod: " + "Could not find ssi item for oncoming buddy %s, " + "group %s\n", name, gname); + } + g_free(gname_utf8); g_free(alias_utf8);
--- a/libpurple/protocols/oscar/oscar.h Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sat Jan 05 18:07:16 2008 +0000 @@ -3,8 +3,6 @@ * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * - * Some code copyright (C) 2007, ComBOTS Product GmbH (htfv) <foss@combots.com> - * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -311,7 +309,7 @@ } #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036 -#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_5_45_3777 +#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQBASIC_14_34_3000 typedef enum { @@ -468,7 +466,6 @@ gboolean icq; guint getblisttimer; - guint getinfotimer; struct { guint maxwatchers; /* max users who can watch you */ @@ -513,9 +510,7 @@ struct { struct aim_userinfo_s *userinfo; - struct userinfo_node *torequest; struct userinfo_node *requested; - gboolean waiting_for_response; } locate; /* Server-stored information (ssi) */ @@ -1329,6 +1324,10 @@ /* we keep track of these in a linked list because we're 1337 */ struct aim_icq_info *next; + + /* status note info */ + guint8 icbm_cookie[8]; + char *status_note_title; }; int aim_icq_reqofflinemsgs(OscarData *od); @@ -1339,7 +1338,7 @@ int aim_icq_getalias(OscarData *od, const char *uin); int aim_icq_getallinfo(OscarData *od, const char *uin); int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias); - +int aim_icq_getstatusnote(OscarData *od, const char *uin, guint8 *note_hash, guint16 note_hash_len); /* 0x0017 - family_auth.c */
--- a/libpurple/protocols/oscar/oscar_data.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/protocols/oscar/oscar_data.c Sat Jan 05 18:07:16 2008 +0000 @@ -97,8 +97,6 @@ g_free(od->oldp); if (od->getblisttimer > 0) purple_timeout_remove(od->getblisttimer); - if (od->getinfotimer > 0) - purple_timeout_remove(od->getinfotimer); while (od->oscar_connections != NULL) flap_connection_destroy(od->oscar_connections->data, OSCAR_DISCONNECT_DONE, NULL);
--- a/libpurple/util.c Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/util.c Sat Jan 05 18:07:16 2008 +0000 @@ -4628,3 +4628,57 @@ #endif /* HAVE_SIGNAL_H */ #endif /* !_WIN32 */ } + +void purple_util_set_current_song(const char *title, const char *artist, const char *album) +{ + GList *list = purple_accounts_get_all(); + for (; list; list = list->next) { + PurplePresence *presence; + PurpleStatus *tune; + PurpleAccount *account = list->data; + if (!purple_account_get_enabled(account, purple_core_get_ui())) + continue; + + presence = purple_account_get_presence(account); + tune = purple_presence_get_status(presence, "tune"); + if (!tune) + continue; + if (title) { + purple_status_set_active(tune, TRUE); + purple_status_set_attr_string(tune, PURPLE_TUNE_TITLE, title); + purple_status_set_attr_string(tune, PURPLE_TUNE_ARTIST, artist); + purple_status_set_attr_string(tune, PURPLE_TUNE_ALBUM, album); + } else { + purple_status_set_active(tune, FALSE); + } + } +} + +char * purple_util_format_song_info(const char *title, const char *artist, const char *album, gpointer unused) +{ + GString *string; + char *esc; + + if (!title) + return NULL; + + esc = g_markup_escape_text(title, -1); + string = g_string_new(""); + g_string_append_printf(string, "%s", esc); + g_free(esc); + + if (artist) { + esc = g_markup_escape_text(artist, -1); + g_string_append_printf(string, _(" - %s"), esc); + g_free(esc); + } + + if (album) { + esc = g_markup_escape_text(album, -1); + g_string_append_printf(string, _(" (%s)"), esc); + g_free(esc); + } + + return g_string_free(string, FALSE); +} +
--- a/libpurple/util.h Sat Jan 05 18:01:12 2008 +0000 +++ b/libpurple/util.h Sat Jan 05 18:07:16 2008 +0000 @@ -85,6 +85,31 @@ */ void purple_menu_action_free(PurpleMenuAction *act); +/** + * Set the appropriate presence values for the currently playing song. + * + * @param title The title of the song, @c NULL to unset the value. + * @param artist The artist of the song, can be @c NULL. + * @param album The album of the song, can be @c NULL. + * @since 2.4.0 + */ +void purple_util_set_current_song(const char *title, const char *artist, + const char *album); + +/** + * Format song information. + * + * @param title The title of the song, @c NULL to unset the value. + * @param artist The artist of the song, can be @c NULL. + * @param album The album of the song, can be @c NULL. + * @param unused Currently unused, must be @c NULL. + * + * @return The formatted string. The caller must #g_free the returned string. + * @since 2.4.0 + */ +char * purple_util_format_song_info(const char *title, const char *artist, + const char *album, gpointer unused); + /**************************************************************************/ /** @name Utility Subsystem */ /**************************************************************************/
--- a/pidgin/gtkaccount.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkaccount.c Sat Jan 05 18:07:16 2008 +0000 @@ -158,25 +158,7 @@ add_pref_box(AccountPrefsDialog *dialog, GtkWidget *parent, const char *text, GtkWidget *widget) { - GtkWidget *hbox; - GtkWidget *label; - - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); - gtk_widget_show(hbox); - - label = gtk_label_new_with_mnemonic(text); - gtk_size_group_add_widget(dialog->sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget); - gtk_widget_show(label); - - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, PIDGIN_HIG_BORDER); - gtk_widget_show(widget); - pidgin_set_accessible_label (widget, label); - - return hbox; + return pidgin_add_widget_to_vbox(GTK_BOX(parent), text, dialog->sg, widget, TRUE, NULL); } static void
--- a/pidgin/gtkblist.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkblist.c Sat Jan 05 18:07:16 2008 +0000 @@ -843,20 +843,10 @@ for (tmp = list; tmp; tmp = tmp->next) { - GtkWidget *label; - GtkWidget *rowbox; GtkWidget *input; pce = tmp->data; - rowbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); - gtk_box_pack_start(GTK_BOX(data->entries_box), rowbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(pce->label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(data->sg, label); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - if (pce->is_int) { GtkObject *adjust; @@ -864,7 +854,7 @@ 1, 10, 10); input = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); gtk_widget_set_size_request(input, 50, -1); - gtk_box_pack_end(GTK_BOX(rowbox), input, FALSE, FALSE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, FALSE, NULL); } else { @@ -880,7 +870,7 @@ if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR); } - gtk_box_pack_end(GTK_BOX(rowbox), input, TRUE, TRUE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL); g_signal_connect(G_OBJECT(input), "changed", G_CALLBACK(joinchat_set_sensitive_if_input_cb), data); } @@ -891,8 +881,6 @@ gtk_widget_grab_focus(input); focus = FALSE; } - gtk_label_set_mnemonic_widget(GTK_LABEL(label), input); - pidgin_set_accessible_label(input, label); g_object_set_data(G_OBJECT(input), "identifier", (gpointer)pce->identifier); g_object_set_data(G_OBJECT(input), "is_spin", GINT_TO_POINTER(pce->is_int)); g_object_set_data(G_OBJECT(input), "required", GINT_TO_POINTER(pce->required)); @@ -988,23 +976,14 @@ gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - rowbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); - gtk_box_pack_start(GTK_BOX(vbox), rowbox, TRUE, TRUE, 0); - data->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - label = gtk_label_new_with_mnemonic(_("_Account:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(data->sg, label); - data->account_menu = pidgin_account_option_menu_new(NULL, FALSE, G_CALLBACK(joinchat_select_account_cb), chat_account_filter_func, data); gtk_box_pack_start(GTK_BOX(rowbox), data->account_menu, TRUE, TRUE, 0); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), - GTK_WIDGET(data->account_menu)); - pidgin_set_accessible_label (data->account_menu, label); + + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Account:"), data->sg, data->account_menu, TRUE, NULL); data->entries_box = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(vbox), data->entries_box); @@ -2576,6 +2555,35 @@ int height; }; +static PangoLayout * create_pango_layout(const char *markup, int *width, int *height) +{ + PangoLayout *layout; + int w, h; + + layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); + pango_layout_set_markup(layout, markup, -1); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD); + pango_layout_set_width(layout, 300000); + + pango_layout_get_size (layout, &w, &h); + if (width) + *width = PANGO_PIXELS(w); + if (height) + *height = PANGO_PIXELS(h); + return layout; +} + +static struct tooltip_data * create_tip_for_account(PurpleAccount *account) +{ + struct tooltip_data *td = g_new0(struct tooltip_data, 1); + td->status_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + /* Yes, status_icon, not prpl_icon */ + if (purple_account_is_disconnected(account)) + gdk_pixbuf_saturate_and_pixelate(td->status_icon, td->status_icon, 0.0, FALSE); + td->layout = create_pango_layout(purple_account_get_username(account), &td->width, &td->height); + return td; +} + static struct tooltip_data * create_tip_for_node(PurpleBlistNode *node, gboolean full) { struct tooltip_data *td = g_new0(struct tooltip_data, 1); @@ -2594,8 +2602,9 @@ td->prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); } tooltip_text = pidgin_get_tooltip_text(node, full); - td->layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); - td->name_layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); + if (tooltip_text && *tooltip_text) { + td->layout = create_pango_layout(tooltip_text, &td->width, &td->height); + } if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { tmp = g_markup_escape_text(purple_buddy_get_name((PurpleBuddy*)node), -1); @@ -2612,21 +2621,9 @@ node_name = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>", tmp); g_free(tmp); - pango_layout_set_markup(td->layout, tooltip_text, -1); - pango_layout_set_wrap(td->layout, PANGO_WRAP_WORD); - pango_layout_set_width(td->layout, 300000); - - pango_layout_get_size (td->layout, &td->width, &td->height); - td->width = PANGO_PIXELS(td->width); - td->height = PANGO_PIXELS(td->height); - - pango_layout_set_markup(td->name_layout, node_name, -1); - pango_layout_set_wrap(td->name_layout, PANGO_WRAP_WORD); - pango_layout_set_width(td->name_layout, 300000); - - pango_layout_get_size (td->name_layout, &td->name_width, &td->name_height); - td->name_width = PANGO_PIXELS(td->name_width) + SMALL_SPACE + PRPL_SIZE; - td->name_height = MAX(PANGO_PIXELS(td->name_height), PRPL_SIZE + SMALL_SPACE); + td->name_layout = create_pango_layout(node_name, &td->name_width, &td->name_height); + td->name_width += SMALL_SPACE + PRPL_SIZE; + td->name_height = MAX(td->name_height, PRPL_SIZE + SMALL_SPACE); #if 0 /* PRPL Icon as avatar */ if(!td->avatar && full) { td->avatar = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_LARGE); @@ -2654,6 +2651,7 @@ GList *l; int prpl_col = 0; GtkTextDirection dir = gtk_widget_get_direction(widget); + int status_size = 0; if(gtkblist->tooltipdata == NULL) return FALSE; @@ -2670,13 +2668,15 @@ max_text_width = MAX(max_text_width, MAX(td->width, td->name_width)); max_avatar_width = MAX(max_avatar_width, td->avatar_width); - } - - max_width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; + if (td->status_icon) + status_size = STATUS_SIZE; + } + + max_width = TOOLTIP_BORDER + status_size + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; if (dir == GTK_TEXT_DIR_RTL) prpl_col = TOOLTIP_BORDER + max_avatar_width + SMALL_SPACE; else - prpl_col = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + max_text_width - PRPL_SIZE; + prpl_col = TOOLTIP_BORDER + status_size + SMALL_SPACE + max_text_width - PRPL_SIZE; current_height = 12; for(l = gtkblist->tooltipdata; l; l = l->next) @@ -2700,7 +2700,7 @@ if (td->status_icon) { if (dir == GTK_TEXT_DIR_RTL) gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, - 0, 0, max_width - TOOLTIP_BORDER - STATUS_SIZE, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + 0, 0, max_width - TOOLTIP_BORDER - status_size, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); else gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, 0, 0, TOOLTIP_BORDER, current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); @@ -2733,26 +2733,31 @@ max_width - (td->avatar_width + TOOLTIP_BORDER), current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); #endif - if (dir == GTK_TEXT_DIR_RTL) { - gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, - NULL, gtkblist->tipwindow, "tooltip", - max_width -(TOOLTIP_BORDER + STATUS_SIZE +SMALL_SPACE) - PANGO_PIXELS(300000), - current_height, td->name_layout); - } else { - gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, - NULL, gtkblist->tipwindow, "tooltip", - TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE, current_height, td->name_layout); + if (td->name_layout) { + if (dir == GTK_TEXT_DIR_RTL) { + gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, + NULL, gtkblist->tipwindow, "tooltip", + max_width -(TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000), + current_height, td->name_layout); + } else { + gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, + NULL, gtkblist->tipwindow, "tooltip", + TOOLTIP_BORDER + status_size + SMALL_SPACE, current_height, td->name_layout); + } } - if (dir != GTK_TEXT_DIR_RTL) { - gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, - NULL, gtkblist->tipwindow, "tooltip", - TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE, current_height + td->name_height, td->layout); - } else { - gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, - NULL, gtkblist->tipwindow, "tooltip", - max_width - (TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE) - PANGO_PIXELS(300000), - current_height + td->name_height, - td->layout); + + if (td->layout) { + if (dir != GTK_TEXT_DIR_RTL) { + gtk_paint_layout (style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, + NULL, gtkblist->tipwindow, "tooltip", + TOOLTIP_BORDER + status_size + SMALL_SPACE, current_height + td->name_height, td->layout); + } else { + gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE, + NULL, gtkblist->tipwindow, "tooltip", + max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000), + current_height + td->name_height, + td->layout); + } } current_height += MAX(td->name_height + td->height, td->avatar_height) + TOOLTIP_BORDER; @@ -2772,8 +2777,10 @@ g_object_unref(td->status_icon); if(td->prpl_icon) g_object_unref(td->prpl_icon); - g_object_unref(td->layout); - g_object_unref(td->name_layout); + if (td->layout) + g_object_unref(td->layout); + if (td->name_layout) + g_object_unref(td->name_layout); g_free(td); gtkblist->tooltipdata = g_list_delete_link(gtkblist->tooltipdata, gtkblist->tooltipdata); } @@ -2790,6 +2797,10 @@ { PurpleBlistNode *node = data; int width, height; + GList *list; + int max_text_width = 0; + int max_avatar_width = 0; + int status_size = 0; if (gtkblist->tooltipdata) { gtkblist->tipwindow = NULL; @@ -2797,20 +2808,27 @@ } gtkblist->tipwindow = widget; - if(PURPLE_BLIST_NODE_IS_CHAT(node) || - PURPLE_BLIST_NODE_IS_BUDDY(node) || - PURPLE_BLIST_NODE_IS_GROUP(node)) { + if (PURPLE_BLIST_NODE_IS_CHAT(node) || + PURPLE_BLIST_NODE_IS_BUDDY(node)) { + struct tooltip_data *td = create_tip_for_node(node, TRUE); + gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); + } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { + PurpleGroup *group = (PurpleGroup*)node; + GSList *accounts; struct tooltip_data *td = create_tip_for_node(node, TRUE); gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); - width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + - MAX(td->width, td->name_width) + SMALL_SPACE + td->avatar_width + TOOLTIP_BORDER; - height = TOOLTIP_BORDER + MAX(td->height + td->name_height, MAX(STATUS_SIZE, td->avatar_height)) - + TOOLTIP_BORDER; - } else if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { + + /* Accounts with buddies in group */ + accounts = purple_group_get_accounts(group); + for (; accounts != NULL; + accounts = g_slist_delete_link(accounts, accounts)) { + PurpleAccount *account = accounts->data; + td = create_tip_for_account(account); + gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); + } + } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { PurpleBlistNode *child; PurpleBuddy *b = purple_contact_get_priority_buddy((PurpleContact *)node); - int max_text_width = 0; - int max_avatar_width = 0; width = height = 0; for(child = node->child; child; child = child->next) @@ -2822,18 +2840,25 @@ } else { gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); } - max_text_width = MAX(max_text_width, MAX(td->width, td->name_width)); - max_avatar_width = MAX(max_avatar_width, td->avatar_width); - height += MAX(TOOLTIP_BORDER + MAX(STATUS_SIZE,td->avatar_height), - TOOLTIP_BORDER + td->height + td->name_height); } } - height += TOOLTIP_BORDER; - width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; } else { return FALSE; } + height = width = 0; + for (list = gtkblist->tooltipdata; list; list = list->next) { + struct tooltip_data *td = list->data; + max_text_width = MAX(max_text_width, MAX(td->width, td->name_width)); + max_avatar_width = MAX(max_avatar_width, td->avatar_width); + height += MAX(TOOLTIP_BORDER + MAX(STATUS_SIZE, td->avatar_height), + TOOLTIP_BORDER + td->height + td->name_height); + if (td->status_icon) + status_size = MAX(status_size, STATUS_SIZE); + } + height += TOOLTIP_BORDER; + width = TOOLTIP_BORDER + status_size + SMALL_SPACE + max_text_width + SMALL_SPACE + max_avatar_width + TOOLTIP_BORDER; + if (w) *w = width; if (h) @@ -3100,7 +3125,7 @@ if (g_list_length(purple_connections_get_all()) > 1) { tmp = g_markup_escape_text(chat->account->username, -1); - g_string_append_printf(str, _("\n<b>Account:</b> %s"), tmp); + g_string_append_printf(str, _("<b>Account:</b> %s"), tmp); g_free(tmp); } @@ -3293,7 +3318,6 @@ purple_notify_user_info_destroy(user_info); } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { - GSList *accounts; PurpleGroup *group = (PurpleGroup*)node; PurpleNotifyUserInfo *user_info; @@ -3313,14 +3337,6 @@ tmp); g_free(tmp); - /* Accounts with buddies in group */ - accounts = purple_group_get_accounts(group); - for (; accounts != NULL; - accounts = g_slist_delete_link(accounts, accounts)) { - PurpleAccount *account = accounts->data; - purple_notify_user_info_add_pair(user_info, _("Account"), purple_account_get_username(account)); - } - tmp = purple_notify_user_info_get_text_with_newline(user_info, "\n"); g_string_append(str, tmp); g_free(tmp); @@ -6480,20 +6496,10 @@ for (tmp = list; tmp; tmp = tmp->next) { - GtkWidget *label; - GtkWidget *rowbox; GtkWidget *input; pce = tmp->data; - rowbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(data->entries_box), rowbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(pce->label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(data->sg, label); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - if (pce->is_int) { GtkObject *adjust; @@ -6501,7 +6507,7 @@ 1, 10, 10); input = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); gtk_widget_set_size_request(input, 50, -1); - gtk_box_pack_end(GTK_BOX(rowbox), input, FALSE, FALSE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, FALSE, NULL); } else { @@ -6517,7 +6523,7 @@ if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR); } - gtk_box_pack_end(GTK_BOX(rowbox), input, TRUE, TRUE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL); g_signal_connect(G_OBJECT(input), "changed", G_CALLBACK(addchat_set_sensitive_if_input_cb), data); } @@ -6528,8 +6534,6 @@ gtk_widget_grab_focus(input); focus = FALSE; } - gtk_label_set_mnemonic_widget(GTK_LABEL(label), input); - pidgin_set_accessible_label(input, label); g_object_set_data(G_OBJECT(input), "identifier", (gpointer)pce->identifier); g_object_set_data(G_OBJECT(input), "is_spin", GINT_TO_POINTER(pce->is_int)); g_object_set_data(G_OBJECT(input), "required", GINT_TO_POINTER(pce->required)); @@ -6572,7 +6576,6 @@ GList *l; PurpleConnection *gc; GtkWidget *label; - GtkWidget *rowbox; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *img; @@ -6648,20 +6651,10 @@ gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - rowbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Account:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(data->sg, label); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - data->account_menu = pidgin_account_option_menu_new(account, FALSE, G_CALLBACK(addchat_select_account_cb), chat_account_filter_func, data); - gtk_box_pack_start(GTK_BOX(rowbox), data->account_menu, TRUE, TRUE, 0); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->account_menu); - pidgin_set_accessible_label (data->account_menu, label); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Account:"), data->sg, data->account_menu, TRUE, NULL); data->entries_box = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(data->entries_box), 0); @@ -6669,36 +6662,17 @@ rebuild_addchat_entries(data); - rowbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("A_lias:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(data->sg, label); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - data->alias_entry = gtk_entry_new(); if (alias != NULL) gtk_entry_set_text(GTK_ENTRY(data->alias_entry), alias); - gtk_box_pack_end(GTK_BOX(rowbox), data->alias_entry, TRUE, TRUE, 0); gtk_entry_set_activates_default(GTK_ENTRY(data->alias_entry), TRUE); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->alias_entry); - pidgin_set_accessible_label (data->alias_entry, label); + + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("A_lias:"), data->sg, data->alias_entry, TRUE, NULL); if (name != NULL) gtk_widget_grab_focus(data->alias_entry); - rowbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Group:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(data->sg, label); - gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); - data->group_combo = pidgin_text_combo_box_entry_new(group ? group->name : NULL, groups_tree()); - 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); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Group:"), data->sg, data->group_combo, TRUE, NULL); data->autojoin = gtk_check_button_new_with_mnemonic(_("Auto_join when account becomes online.")); data->persistent = gtk_check_button_new_with_mnemonic(_("_Hide chat when the window is closed.")); @@ -6972,7 +6946,8 @@ pidgin_blist_update_sort_methods(); } -void pidgin_blist_sort_method_unreg(const char *id){ +void pidgin_blist_sort_method_unreg(const char *id) +{ GList *l = pidgin_blist_sort_methods; while(l) { @@ -6984,6 +6959,7 @@ g_free(method); break; } + l = l->next; } pidgin_blist_update_sort_methods(); }
--- a/pidgin/gtkconv.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkconv.c Sat Jan 05 18:07:16 2008 +0000 @@ -2444,7 +2444,6 @@ { PidginConversation *gtkconv; PidginWindow *win; - PurpleBuddy *b; GList *l; GdkPixbuf *status = NULL; GdkPixbuf *infopane_status = NULL; @@ -2457,13 +2456,18 @@ if (conv != gtkconv->active_conv) return; - status = pidgin_conv_get_tab_icon(conv, TRUE); infopane_status = pidgin_conv_get_tab_icon(conv, FALSE); - b = purple_find_buddy(conv->account, conv->name); - if (b) - emblem = pidgin_blist_get_emblem((PurpleBlistNode*)b); + if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { + PurpleBuddy *b = purple_find_buddy(conv->account, conv->name); + if (b) + emblem = pidgin_blist_get_emblem((PurpleBlistNode*)b); + } else { + PurpleChat *c = purple_blist_find_chat(conv->account, conv->name); + if (c) + emblem = pidgin_blist_get_emblem((PurpleBlistNode*)c); + } g_return_if_fail(status != NULL);
--- a/pidgin/gtkpluginpref.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkpluginpref.c Sat Jan 05 18:07:16 2008 +0000 @@ -93,22 +93,6 @@ case PURPLE_PLUGIN_PREF_NONE: default: if (format == PURPLE_STRING_FORMAT_TYPE_NONE) - box = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - else - box = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - - gtk_widget_show(box); - gtk_box_pack_start(GTK_BOX(parent), box, FALSE, FALSE, 0); - - gtk_label = gtk_label_new_with_mnemonic(pref_label); - gtk_misc_set_alignment(GTK_MISC(gtk_label), 0, 0.5); - gtk_widget_show(gtk_label); - gtk_box_pack_start(GTK_BOX(box), gtk_label, FALSE, FALSE, 0); - - if(sg) - gtk_size_group_add_widget(sg, gtk_label); - - if (format == PURPLE_STRING_FORMAT_TYPE_NONE) { entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), purple_prefs_get_string(pref_name)); @@ -123,9 +107,7 @@ g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_cb), (gpointer)pref_name); - gtk_label_set_mnemonic_widget(GTK_LABEL(gtk_label), entry); - gtk_widget_show(entry); - gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(parent), pref_label, sg, entry, TRUE, NULL); } else { @@ -135,6 +117,19 @@ GtkWidget *toolbar; GtkWidget *frame; + box = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + + gtk_widget_show(box); + gtk_box_pack_start(GTK_BOX(parent), box, FALSE, FALSE, 0); + + gtk_label = gtk_label_new_with_mnemonic(pref_label); + gtk_misc_set_alignment(GTK_MISC(gtk_label), 0, 0.5); + gtk_widget_show(gtk_label); + gtk_box_pack_start(GTK_BOX(box), gtk_label, FALSE, FALSE, 0); + + if(sg) + gtk_size_group_add_widget(sg, gtk_label); + hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox);
--- a/pidgin/gtkprefs.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkprefs.c Sat Jan 05 18:07:16 2008 +0000 @@ -89,23 +89,12 @@ pidgin_prefs_labeled_spin_button(GtkWidget *box, const gchar *title, const char *key, int min, int max, GtkSizeGroup *sg) { - GtkWidget *hbox; - GtkWidget *label; GtkWidget *spin; GtkObject *adjust; int val; val = purple_prefs_get_int(key); - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5); - gtk_widget_show(hbox); - - label = gtk_label_new_with_mnemonic(title); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_widget_show(label); - adjust = gtk_adjustment_new(val, min, max, 1, 1, 1); spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); g_object_set_data(G_OBJECT(spin), "val", (char *)key); @@ -113,21 +102,11 @@ gtk_widget_set_size_request(spin, 50, -1); else gtk_widget_set_size_request(spin, 60, -1); - gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(adjust), "value-changed", G_CALLBACK(update_spin_value), GTK_WIDGET(spin)); gtk_widget_show(spin); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin); - - if (sg) { - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - } - - pidgin_set_accessible_label (spin, label); - - return hbox; + return pidgin_add_widget_to_vbox(GTK_BOX(box), title, sg, spin, FALSE, NULL); } static void @@ -141,37 +120,18 @@ pidgin_prefs_labeled_entry(GtkWidget *page, const gchar *title, const char *key, GtkSizeGroup *sg) { - GtkWidget *hbox, *label, *entry; + GtkWidget *entry; const gchar *value; value = purple_prefs_get_string(key); - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 0); - gtk_widget_show(hbox); - - label = gtk_label_new_with_mnemonic(title); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_widget_show(label); - entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), value); - gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_set), (char*)key); gtk_widget_show(entry); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); - - if(sg) { - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - } - - pidgin_set_accessible_label(entry, label); - - return hbox; + return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL); } static void @@ -205,7 +165,6 @@ { GtkWidget *dropdown, *opt, *menu; GtkWidget *label = NULL; - GtkWidget *hbox; gchar *text; const char *stored_str = NULL; int stored_int = 0; @@ -215,19 +174,6 @@ g_return_val_if_fail(menuitems != NULL, NULL); - if (title != NULL) { - hbox = gtk_hbox_new(FALSE, 5); - /*gtk_container_add (GTK_CONTAINER (box), hbox);*/ - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); - gtk_widget_show(hbox); - - label = gtk_label_new_with_mnemonic(title); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_widget_show(label); - } else { - hbox = box; - } - #if 0 /* GTK_CHECK_VERSION(2,4,0) */ if(type == PURPLE_PREF_INT) model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); @@ -239,11 +185,6 @@ menu = gtk_menu_new(); #endif - if (label != NULL) { - gtk_label_set_mnemonic_widget(GTK_LABEL(label), dropdown); - pidgin_set_accessible_relations (dropdown, label); - } - if (type == PURPLE_PREF_INT) stored_int = purple_prefs_get_int(key); else if (type == PURPLE_PREF_STRING) @@ -293,8 +234,8 @@ } gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); - gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0); - gtk_widget_show(dropdown); + + pidgin_add_widget_to_vbox(GTK_BOX(box), title, NULL, dropdown, FALSE, &label); return label; } @@ -983,7 +924,6 @@ #if GTK_CHECK_VERSION(2,4,0) GtkWidget *hbox; - GtkWidget *label; GtkWidget *font_button; const char *font_name; #endif @@ -1026,19 +966,15 @@ fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); else fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); - hbox = gtk_hbox_new(FALSE, 3); - label = gtk_label_new_with_mnemonic(_("Conversation _font:")); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font"); font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL); gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE); - gtk_box_pack_start(GTK_BOX(hbox), font_button, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL); if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) gtk_widget_set_sensitive(hbox, FALSE); g_signal_connect(G_OBJECT(fontpref), "clicked", G_CALLBACK(pidgin_toggle_sensitive), hbox); g_signal_connect(G_OBJECT(font_button), "font-set", G_CALLBACK(pidgin_custom_font_set), NULL); - gtk_widget_show_all(hbox); #endif vbox = pidgin_make_frame(ret, _("Default Formatting")); @@ -1520,28 +1456,16 @@ browser_changed1_cb, hbox); } - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - label = gtk_label_new_with_mnemonic(_("_Manual:\n(%s for URL)")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - gtk_size_group_add_widget(sg, label); - entry = gtk_entry_new(); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); - if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom")) gtk_widget_set_sensitive(hbox, FALSE); purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser", browser_changed2_cb, hbox); - - gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); - gtk_entry_set_text(GTK_ENTRY(entry), purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command")); g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(manual_browser_set), NULL); - pidgin_set_accessible_label (entry, label); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL); gtk_widget_show_all(ret); g_object_unref(sg); @@ -1824,33 +1748,20 @@ gtk_size_group_add_widget(sg, dd); gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5); - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("Sound c_ommand:\n(%s for filename)")); - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - entry = gtk_entry_new(); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); - gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); cmd = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/sound/command"); if(cmd) gtk_entry_set_text(GTK_ENTRY(entry), cmd); - - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(sound_cmd_yeah), NULL); + hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Sound c_ommand:\n(%s for filename)"), sg, entry, TRUE, NULL); purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method", sound_changed1_cb, hbox); gtk_widget_set_sensitive(hbox, !strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "custom")); - - pidgin_set_accessible_label (entry, label); #endif /* _WIN32 */ vbox = pidgin_make_frame (ret, _("Sound Options")); @@ -1864,13 +1775,6 @@ NULL); #ifdef USE_GSTREAMER - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("Volume:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - sw = gtk_hscale_new_with_range(0.0, 100.0, 5.0); gtk_range_set_increments(GTK_RANGE(sw), 5.0, 25.0); gtk_range_set_value(GTK_RANGE(sw), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/sound/volume")); @@ -1880,7 +1784,7 @@ g_signal_connect (G_OBJECT (sw), "value-changed", G_CALLBACK (prefs_sound_volume_changed), NULL); - gtk_box_pack_start(GTK_BOX(hbox), sw, TRUE, TRUE, 0); + hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Volume:"), NULL, sw, TRUE, NULL); purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method", sound_changed3_cb, hbox); @@ -2009,7 +1913,6 @@ { GtkWidget *ret; GtkWidget *vbox; - GtkWidget *hbox; GtkWidget *dd; GtkWidget *label; GtkWidget *button; @@ -2060,22 +1963,13 @@ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pidgin_toggle_sensitive), select); - hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(vbox), hbox); - - label = gtk_label_new_with_mnemonic(_("Change _status to:")); - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + /* TODO: Show something useful if we don't have any saved statuses. */ + menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away)); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Change _status to:"), sg, menu, TRUE, &label); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(pidgin_toggle_sensitive), menu); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pidgin_toggle_sensitive), label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - /* TODO: Show something useful if we don't have any saved statuses. */ - menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away)); - gtk_box_pack_start(GTK_BOX(hbox), menu, FALSE, FALSE, 0); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(pidgin_toggle_sensitive), menu); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), menu); if (!purple_prefs_get_bool("/purple/away/away_when_idle")) { gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE); @@ -2089,22 +1983,13 @@ button = pidgin_prefs_checkbox(_("Use status from last _exit at startup"), "/purple/savedstatus/startup_current_status", vbox); - hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(vbox), hbox); - - label = gtk_label_new_with_mnemonic(_("Status to a_pply at startup:")); - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + /* TODO: Show something useful if we don't have any saved statuses. */ + menu = pidgin_status_menu(purple_savedstatus_get_startup(), G_CALLBACK(set_startupstatus)); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(pidgin_toggle_sensitive), menu); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Status to a_pply at startup:"), sg, menu, TRUE, &label); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pidgin_toggle_sensitive), label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - /* TODO: Show something useful if we don't have any saved statuses. */ - menu = pidgin_status_menu(purple_savedstatus_get_startup(), G_CALLBACK(set_startupstatus)); - gtk_box_pack_start(GTK_BOX(hbox), menu, FALSE, FALSE, 0); - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(pidgin_toggle_sensitive), menu); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), menu); if (purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) { gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
--- a/pidgin/gtkprivacy.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkprivacy.c Sat Jan 05 18:07:16 2008 +0000 @@ -359,7 +359,6 @@ privacy_dialog_new(void) { PidginPrivacyDialog *dialog; - GtkWidget *hbox; GtkWidget *vbox; GtkWidget *button; GtkWidget *dropdown; @@ -386,22 +385,10 @@ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_widget_show(label); - /* Hbox for the accounts drop-down and label. */ - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show(hbox); - - /* "Set privacy for:" label */ - label = gtk_label_new(_("Set privacy for:")); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_widget_show(label); - /* Accounts drop-down */ dropdown = pidgin_account_option_menu_new(NULL, FALSE, G_CALLBACK(select_account_cb), NULL, dialog); - gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0); - gtk_widget_show(dropdown); - pidgin_set_accessible_label (dropdown, label); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Set privacy for:"), NULL, dropdown, TRUE, NULL); dialog->account = pidgin_account_option_menu_get_selected(dropdown); /* Add the drop-down list with the allow/block types. */
--- a/pidgin/gtkroomlist.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkroomlist.c Sat Jan 05 18:07:16 2008 +0000 @@ -521,9 +521,7 @@ GtkWidget *window; GtkWidget *vbox; GtkWidget *vbox2; - GtkWidget *account_hbox; GtkWidget *bbox; - GtkWidget *label; dialog = g_new0(PidginRoomlistDialog, 1); dialog->account = account; @@ -542,25 +540,11 @@ gtk_widget_show(vbox2); /* accounts dropdown list */ - account_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox2), account_hbox, FALSE, FALSE, 0); - gtk_widget_show(account_hbox); - - label = gtk_label_new(NULL); - gtk_box_pack_start(GTK_BOX(account_hbox), label, FALSE, FALSE, 0); - gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Account:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_widget_show(label); - dialog->account_widget = pidgin_account_option_menu_new(dialog->account, FALSE, G_CALLBACK(dialog_select_account_cb), account_filter_func, dialog); - if (!dialog->account) /* this is normally null, and we normally don't care what the first selected item is */ dialog->account = pidgin_account_option_menu_get_selected(dialog->account_widget); - - gtk_box_pack_start(GTK_BOX(account_hbox), dialog->account_widget, TRUE, TRUE, 0); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_WIDGET(dialog->account_widget)); - gtk_widget_show(dialog->account_widget); + pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL); /* scrolled window */ dialog->sw = gtk_scrolled_window_new(NULL, NULL);
--- a/pidgin/gtksavedstatuses.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtksavedstatuses.c Sat Jan 05 18:07:16 2008 +0000 @@ -1092,7 +1092,6 @@ GtkWidget *entry; GtkWidget *frame; GtkWidget *hbox; - GtkWidget *label; GtkWidget *sw; GtkWidget *text; GtkWidget *toolbar; @@ -1141,52 +1140,29 @@ sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); /* Title */ - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Title:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - entry = gtk_entry_new(); dialog->title = GTK_ENTRY(entry); if ((saved_status != NULL) && !purple_savedstatus_is_transient(saved_status) && (purple_savedstatus_get_title(saved_status) != NULL)) gtk_entry_set_text(GTK_ENTRY(entry), purple_savedstatus_get_title(saved_status)); - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(editor_title_changed_cb), dialog); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Title:"), sg, entry, TRUE, NULL); /* Status type */ - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Status:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - if (saved_status != NULL) dropdown = create_status_type_menu(purple_savedstatus_get_type(saved_status)); else dropdown = create_status_type_menu(PURPLE_STATUS_AWAY); dialog->type = GTK_OPTION_MENU(dropdown); - gtk_box_pack_start(GTK_BOX(hbox), dropdown, TRUE, TRUE, 0); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Status:"), sg, dropdown, TRUE, NULL); /* Status message */ - hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - - label = gtk_label_new_with_mnemonic(_("_Message:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - frame = pidgin_create_imhtml(TRUE, &text, &toolbar, NULL); dialog->message = GTK_IMHTML(text); - gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); + hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Message:"), sg, frame, TRUE, NULL); + gtk_container_child_set(GTK_CONTAINER(vbox), hbox, "expand", TRUE, "fill", TRUE, NULL); focus_chain = g_list_prepend(focus_chain, dialog->message); gtk_container_set_focus_chain(GTK_CONTAINER(hbox), focus_chain); g_list_free(focus_chain);
--- a/pidgin/gtkutils.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkutils.c Sat Jan 05 18:07:16 2008 +0000 @@ -1701,23 +1701,23 @@ GdkPixbuf *pixbuf = NULL; if (prim == PURPLE_STATUS_UNAVAILABLE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_BUSY, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_AWAY) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AWAY, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_EXTENDED_AWAY) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_XA, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_INVISIBLE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_INVISIBLE, - icon_size, "GtkWidget"); - else if (prim == PURPLE_STATUS_OFFLINE) - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_OFFLINE, - icon_size, "GtkWidget"); - else - pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AVAILABLE, - icon_size, "GtkWidget"); + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_BUSY, + icon_size, "GtkWidget"); + else if (prim == PURPLE_STATUS_AWAY) + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AWAY, + icon_size, "GtkWidget"); + else if (prim == PURPLE_STATUS_EXTENDED_AWAY) + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_XA, + icon_size, "GtkWidget"); + else if (prim == PURPLE_STATUS_INVISIBLE) + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_INVISIBLE, + icon_size, "GtkWidget"); + else if (prim == PURPLE_STATUS_OFFLINE) + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_OFFLINE, + icon_size, "GtkWidget"); + else + pixbuf = gtk_widget_render_icon (w, PIDGIN_STOCK_STATUS_AVAILABLE, + icon_size, "GtkWidget"); return pixbuf; } @@ -3321,6 +3321,40 @@ gtk_entry_set_text(GTK_ENTRY(GTK_BIN((widget))->child), (text)); } +GtkWidget * +pidgin_add_widget_to_vbox(GtkBox *vbox, const char *widget_label, GtkSizeGroup *sg, GtkWidget *widget, gboolean expand, GtkWidget **p_label) +{ + GtkWidget *hbox; + GtkWidget *label = NULL; + + if (widget_label) { + hbox = gtk_hbox_new(FALSE, 5); + gtk_widget_show(hbox); + gtk_box_pack_start(vbox, hbox, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic(widget_label); + gtk_widget_show(label); + if (sg) { + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_size_group_add_widget(sg, label); + } + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + } else { + hbox = GTK_WIDGET(vbox); + } + + gtk_widget_show(widget); + gtk_box_pack_start(GTK_BOX(hbox), widget, expand, TRUE, 0); + if (label) { + gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget); + pidgin_set_accessible_label (widget, label); + } + + if (p_label) + (*p_label) = label; + return hbox; +} + gboolean pidgin_auto_parent_window(GtkWidget *widget) { #if 0
--- a/pidgin/gtkutils.h Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/gtkutils.h Sat Jan 05 18:07:16 2008 +0000 @@ -794,5 +794,20 @@ */ gboolean pidgin_auto_parent_window(GtkWidget *window); +/** + * 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 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. + * + * @return A GtkHBox already added to the GtkVBox containing the GtkLabel and the GtkWidget. + * @since 2.4.0 + */ +GtkWidget *pidgin_add_widget_to_vbox(GtkBox *vbox, const char *widget_label, GtkSizeGroup *sg, GtkWidget *widget, gboolean expand, GtkWidget **p_label); + #endif /* _PIDGINUTILS_H_ */
--- a/pidgin/plugins/spellchk.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/plugins/spellchk.c Sat Jan 05 18:07:16 2008 +0000 @@ -2161,14 +2161,13 @@ get_config_frame(PurplePlugin *plugin) { GtkWidget *ret, *vbox, *win; - GtkWidget *hbox, *label; + GtkWidget *hbox; GtkWidget *button; GtkSizeGroup *sg; GtkSizeGroup *sg2; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *vbox2; - GtkWidget *hbox2; GtkWidget *vbox3; ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); @@ -2275,37 +2274,15 @@ sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); sg2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - hbox2 = gtk_hbox_new(FALSE, 2); - gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0); - gtk_widget_show(hbox2); - - label = gtk_label_new_with_mnemonic(_("You _type:")); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - bad_entry = gtk_entry_new(); /* Set a minimum size. Since they're in a size group, the other entry will match up. */ gtk_widget_set_size_request(bad_entry, 350, -1); - gtk_box_pack_start(GTK_BOX(hbox2), bad_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg2, bad_entry); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry); - gtk_widget_show(bad_entry); - - hbox2 = gtk_hbox_new(FALSE, 2); - gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0); - gtk_widget_show(hbox2); - - label = gtk_label_new_with_mnemonic(_("You _send:")); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("You _type:"), sg, bad_entry, FALSE, NULL); good_entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox2), good_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg2, good_entry); - gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry); - gtk_widget_show(good_entry); + pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("You _send:"), sg, good_entry, FALSE, NULL); /* Created here so it can be passed to whole_words_button_toggled. */ case_toggle = gtk_check_button_new_with_mnemonic(_("_Exact case match (uncheck for automatic case handling)"));
--- a/pidgin/win32/winpidgin.c Sat Jan 05 18:01:12 2008 +0000 +++ b/pidgin/win32/winpidgin.c Sat Jan 05 18:07:16 2008 +0000 @@ -450,23 +450,25 @@ if ((h = CreateMutex(NULL, FALSE, "pidgin_is_running"))) { DWORD err = GetLastError(); - if (err == ERROR_ALREADY_EXISTS && fail_if_running) { - HWND msg_win; + if (err == ERROR_ALREADY_EXISTS) { + if (fail_if_running) { + HWND msg_win; - printf("An instance of Pidgin is already running.\n"); + printf("An instance of Pidgin is already running.\n"); - if((msg_win = FindWindowEx(HWND_MESSAGE, NULL, TEXT("WinpidginMsgWinCls"), NULL))) - if(SendMessage(msg_win, PIDGIN_WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL)) - return FALSE; + if((msg_win = FindWindowEx(HWND_MESSAGE, NULL, TEXT("WinpidginMsgWinCls"), NULL))) + if(SendMessage(msg_win, PIDGIN_WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL)) + return FALSE; - /* If we get here, the focus request wasn't successful */ + /* If we get here, the focus request wasn't successful */ - MessageBox(NULL, - "An instance of Pidgin is already running", - NULL, MB_OK | MB_TOPMOST); + MessageBox(NULL, + "An instance of Pidgin is already running", + NULL, MB_OK | MB_TOPMOST); - return FALSE; - } else + return FALSE; + } + } else if (err != ERROR_SUCCESS) printf("Error (%u) accessing \"pidgin_is_running\" mutex.\n", (UINT) err); } return TRUE;
--- a/po/de.po Sat Jan 05 18:01:12 2008 +0000 +++ b/po/de.po Sat Jan 05 18:07:16 2008 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-12-19 10:17+0100\n" -"PO-Revision-Date: 2007-12-19 10:17+0100\n" +"POT-Creation-Date: 2008-01-05 13:31+0100\n" +"PO-Revision-Date: 2008-01-05 13:31+0100\n" "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n" "Language-Team: Deutsch <de@li.org>\n" "MIME-Version: 1.0\n" @@ -1436,19 +1436,6 @@ msgstr "Ze_rtifikat ansehen..." #. Prompt the user to authenticate the certificate -#. TODO: Provide the user with more guidance about why he is -#. being prompted -#. vrq will be completed by user_auth -#, c-format -msgid "" -"The certificate presented by \"%s\" claims to be from \"%s\" instead. This " -"could mean that you are not connecting to the service you believe you are." -msgstr "" -"Das Zertifikat, welches von „%s“ präsentiert wurde, behauptet stattdessen " -"von „%s“ zu kommen. Das kann bedeuten, dass Sie tatsächlich nicht mit dem " -"Dienst verbunden sind, mit dem Sie glauben verbunden zu sein." - -#. Prompt the user to authenticate the certificate #. vrq will be completed by user_auth #, c-format msgid "" @@ -1498,6 +1485,19 @@ msgid "Invalid certificate authority signature" msgstr "Unbekannte Zertifizierungsstellensignatur" +#. Prompt the user to authenticate the certificate +#. TODO: Provide the user with more guidance about why he is +#. being prompted +#. vrq will be completed by user_auth +#, c-format +msgid "" +"The certificate presented by \"%s\" claims to be from \"%s\" instead. This " +"could mean that you are not connecting to the service you believe you are." +msgstr "" +"Das Zertifikat, welches von „%s“ präsentiert wurde, behauptet stattdessen " +"von „%s“ zu kommen. Das kann bedeuten, dass Sie tatsächlich nicht mit dem " +"Dienst verbunden sind, mit dem Sie glauben verbunden zu sein." + #. Make messages #, c-format msgid "" @@ -3285,6 +3285,10 @@ msgid "nickserv: Send a command to nickserv" msgstr "nickserv: Sendet ein Kommando zum Nickserv" +msgid "notice <target<: Send a notice to a user or channel." +msgstr "" +"notice <Ziel>: Sende eine Notiz an einen Benutzer oder an einen Kanal." + msgid "" "op <nick1> [nick2] ...: Grant channel operator status to someone. You " "must be a channel operator to do this." @@ -3971,8 +3975,8 @@ msgid "Mood" msgstr "Stimmung" -msgid "Current media" -msgstr "Aktuelles Medium" +msgid "Now Listening" +msgstr "" msgid "Mood Text" msgstr "Stimmungstext" @@ -9632,6 +9636,14 @@ msgid "Unable to connect to %s: %s" msgstr "Verbindung zu %s nicht möglich: %s" +#, c-format +msgid " - %s" +msgstr " - %s" + +#, c-format +msgid " (%s)" +msgstr " (%s)" + #. 10053 #, c-format msgid "Connection interrupted by other software on your computer." @@ -9640,7 +9652,7 @@ "unterbrochen." #. 10054 -#, fuzzy, c-format +#, c-format msgid "Remote host closed connection." msgstr "Der entfernte Host hat die Verbindung beendet." @@ -9908,6 +9920,12 @@ "Sie sind im Moment nicht mit einem Konto angemeldet, welches benutzt werden " "kann, um diesen Buddy hinzuzufügen." +#. I don't believe this can happen currently, I think +#. * everything that calls this function checks for one of the +#. * above node types first. +msgid "Unknown node type" +msgstr "Unbekannter Knotentyp" + #. Buddies menu msgid "/_Buddies" msgstr "/_Buddys" @@ -10009,12 +10027,8 @@ msgstr "/Hilfe/Ü_ber" #, c-format -msgid "" -"\n" -"<b>Account:</b> %s" -msgstr "" -"\n" -"<b>Konto:</b> %s" +msgid "<b>Account:</b> %s" +msgstr "<b>Konto:</b> %s" #, c-format msgid "" @@ -10045,6 +10059,12 @@ msgid "Rockin'" msgstr "Abgefahren" +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" @@ -11108,31 +11128,33 @@ msgstr "" "Farbe zum Darstellen von Hyperlinks, wenn sich die Maus darüber befindet." -#, fuzzy msgid "Sent Message Name Color" -msgstr "Gesendete Nachrichten" +msgstr "Farbe des Absendernamens für gesendete Nachrichten" msgid "Color to draw the name of a message you sent." msgstr "" - -#, fuzzy +"Farbe, mit der der Name in einer gesendeten Nachricht dargestellt wird." + msgid "Received Message Name Color" -msgstr "Empfangene Nachrichten" +msgstr "Farbe des Absendernamens für empfangene Nachrichten" msgid "Color to draw the name of a message you received." msgstr "" +"Farbe, mit der der Name in einer empfangenen Nachricht dargestellt wird." msgid "\"Attention\" Name Color" -msgstr "" +msgstr "Farbe des Absendernamens für \"Achtung\"-Nachrichten" msgid "Color to draw the name of a message you received containing your name." msgstr "" +"Farbe, mit der der Name in einer Nachricht dargestellt wird, die Ihren Namen " +"enthält." msgid "Action Message Name Color" -msgstr "" +msgstr "Farbe des Absendernamens für Aktions-Nachrichten" msgid "Color to draw the name of an action message." -msgstr "" +msgstr "Farbe, mit der der Name in einer Aktions-Nachricht dargestellt wird." msgid "_Copy E-Mail Address" msgstr "Kopiere _E-Mail-Adresse" @@ -11187,15 +11209,6 @@ msgid "_Save Image..." msgstr "Bild _speichern..." -msgid "_Font" -msgstr "_Schrift" - -msgid "_Insert" -msgstr "_Einfügen" - -msgid "S_mile!" -msgstr "_Lächeln!" - msgid "Select Font" msgstr "Schriftart wählen" @@ -11224,6 +11237,9 @@ msgid "Insert Link" msgstr "Link einfügen" +msgid "_Insert" +msgstr "_Einfügen" + #, c-format msgid "Failed to store image: %s\n" msgstr "Speichern des Bildes fehlgeschlagen: %s\n" @@ -11231,12 +11247,14 @@ msgid "Insert Image" msgstr "Bild einfügen" +msgid "Smile!" +msgstr "Lächeln!" + msgid "This theme has no available smileys." msgstr "Dieses Thema verfügt über keine Smileys." -#. show everything -msgid "Smile!" -msgstr "Lächeln!" +msgid "_Font" +msgstr "_Schrift" msgid "Group Items" msgstr "Elemente gruppieren" @@ -12029,7 +12047,6 @@ msgid "Changes to privacy settings take effect immediately." msgstr "Einstellungen bzgl. der Privatsphäre werden sofort wirksam." -#. "Set privacy for:" label msgid "Set privacy for:" msgstr "Setze Privatsphäre für:" @@ -12850,9 +12867,8 @@ msgid "Hyperlink Color" msgstr "Hyperlink-Farbe" -#, fuzzy msgid "Highlighted Message Name Color" -msgstr "Hervorgehobene Nachrichten" +msgstr "Farbe des Absendernamens für hervorgehobene Nachrichten" msgid "GtkTreeView Horizontal Separation" msgstr "GtkTreeview horizontaler Abstand" @@ -12861,7 +12877,7 @@ msgstr "Unterhaltungseintrag" msgid "Request Dialog" -msgstr "Dialog anfordern" +msgstr "Anfrage-Dialog" msgid "Notify Dialog" msgstr "Benachrichtigungsdialog"