Mercurial > pidgin.yaz
changeset 27845:0aa090fde749
propagate from branch 'im.pidgin.pidgin' (head eeed2c960a1dbe213de63e3115629056ac809beb)
to branch 'im.pidgin.pidgin.yaz' (head d545b8061fc6864f28add1244ef187cd2131985e)
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Fri, 30 May 2008 14:29:33 +0000 |
parents | f7944b0ffe46 (current diff) 996c80ab3dbc (diff) |
children | 9f91d6e0983c |
files | libpurple/protocols/irc/parse.c libpurple/protocols/oscar/oscar.c libpurple/util.c pidgin/gtkimhtml.c pidgin/gtkimhtmltoolbar.c |
diffstat | 16 files changed, 466 insertions(+), 333 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Tue May 27 14:14:40 2008 +0000 +++ b/COPYRIGHT Fri May 30 14:29:33 2008 +0000 @@ -388,6 +388,7 @@ Richard Stellingwerff Charlie Stockman David Stoddard +Adam Strzelecki Andreas Stührk Oleg Sukhodolsky Sun Microsystems
--- a/ChangeLog Tue May 27 14:14:40 2008 +0000 +++ b/ChangeLog Fri May 30 14:29:33 2008 +0000 @@ -18,6 +18,9 @@ * Group and Chat buddy list entries can now be given custom buddy icons. + Finch: + * Added "Invite..." menu to chats. + version 2.4.2 (05/17/2008): libpurple: * In MySpaceIM, messages from spambots are discarded (Justin Williams)
--- a/finch/gntconv.c Tue May 27 14:14:40 2008 +0000 +++ b/finch/gntconv.c Fri May 30 14:29:33 2008 +0000 @@ -38,10 +38,11 @@ #include "gntdebug.h" #include "gntlog.h" #include "gntplugin.h" +#include "gntpounce.h" #include "gntprefs.h" +#include "gntrequest.h" #include "gntsound.h" #include "gntstatus.h" -#include "gntpounce.h" #include "gnt.h" #include "gntbox.h" @@ -557,6 +558,47 @@ } static void +invite_select_cb(FinchConv *fc, PurpleRequestFields *fields) +{ + PurpleConversation *conv = fc->active_conv; + const char *buddy = purple_request_fields_get_string(fields, "screenname"); + const char *message = purple_request_fields_get_string(fields, "message"); + serv_chat_invite(purple_conversation_get_gc(conv), + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), + message, buddy); + +} + +static void +invite_cb(GntMenuItem *item, gpointer ggconv) +{ + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + + fields = purple_request_fields_new(); + + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); + + field = purple_request_field_string_new("screenname", _("Name"), NULL, FALSE); + purple_request_field_set_type_hint(field, "screenname"); + purple_request_field_set_required(field, TRUE); + purple_request_field_group_add_field(group, field); + field = purple_request_field_string_new("message", _("Invite message"), NULL, FALSE); + purple_request_field_group_add_field(group, field); + purple_request_fields(finch_conv_get_handle(), _("Invite"), + NULL, + _("Please enter the name of the user " + "you wish to invite,\nalong with an optional invite message."), + fields, + _("OK"), G_CALLBACK(invite_select_cb), + _("Cancel"), NULL, + NULL, NULL, NULL, + ggconv); +} + +static void gg_create_menu(FinchConv *ggc) { GntWidget *menu, *sub; @@ -606,6 +648,10 @@ } generate_send_to_menu(ggc); + } else if (purple_conversation_get_type(ggc->active_conv) == PURPLE_CONV_TYPE_CHAT) { + item = gnt_menuitem_new(_("Invite...")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, invite_cb, ggc); } item = gnt_menuitem_new(_("View Log..."));
--- a/libpurple/protocols/gg/gg.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/protocols/gg/gg.c Fri May 30 14:29:33 2008 +0000 @@ -343,7 +343,8 @@ { PurpleConnection *gc = (PurpleConnection *)action->context; - purple_request_file(action, "Load buddylist from file...", NULL, FALSE, + purple_request_file(action, _("Load buddylist from file..."), NULL, + FALSE, G_CALLBACK(ggp_callback_buddylist_load_ok), NULL, purple_connection_get_account(gc), NULL, NULL, gc); @@ -926,8 +927,10 @@ /* ----- INTERNAL CALLBACKS --------------------------------------------- */ /* ---------------------------------------------------------------------- */ -/* just a prototype */ +/* Prototypes */ static void ggp_set_status(PurpleAccount *account, PurpleStatus *status); +static int ggp_to_gg_status(PurpleStatus *status, char **msg); + /** * Handle change of the status of the buddy. @@ -1488,23 +1491,12 @@ break; case GG_EVENT_CONN_SUCCESS: { - PurpleAccount *account; - PurplePresence *presence; - PurpleStatus *status; - purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS\n"); purple_input_remove(gc->inpa); gc->inpa = purple_input_add(info->session->fd, PURPLE_INPUT_READ, ggp_callback_recv, gc); - /* gg_change_status(info->session, GG_STATUS_AVAIL); */ - - account = purple_connection_get_account(gc); - presence = purple_account_get_presence(account); - status = purple_presence_get_active_status(presence); - - ggp_set_status(account, status); purple_connection_set_state(gc, PURPLE_CONNECTED); ggp_buddylist_send(gc); } @@ -1692,6 +1684,8 @@ static void ggp_login(PurpleAccount *account) { PurpleConnection *gc; + PurplePresence *presence; + PurpleStatus *status; struct gg_login_params *glp; GGPInfo *info; @@ -1714,8 +1708,11 @@ glp->uin = ggp_get_uin(account); glp->password = (char *)purple_account_get_password(account); + presence = purple_account_get_presence(account); + status = purple_presence_get_active_status(presence); + glp->async = 1; - glp->status = GG_STATUS_AVAIL; + glp->status = ggp_to_gg_status(status, &glp->status_descr); glp->tls = 0; info->session = gg_login(glp); @@ -1826,22 +1823,15 @@ /* }}} */ /* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ -static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) +static int ggp_to_gg_status(PurpleStatus *status, char **msg) { - PurpleConnection *gc; - GGPInfo *info; - const char *status_id, *msg; + const char *status_id = purple_status_get_id(status); int new_status, new_status_descr; + const char *new_msg; - if (!purple_status_is_active(status)) - return; + g_return_val_if_fail(msg == NULL, 0); - gc = purple_account_get_connection(account); - info = gc->proto_data; - - status_id = purple_status_get_id(status); - - purple_debug_info("gg", "ggp_set_status: Requested status = %s\n", + purple_debug_info("gg", "ggp_to_gg_status: Requested status = %s\n", status_id); if (strcmp(status_id, "available") == 0) { @@ -1860,22 +1850,45 @@ new_status = GG_STATUS_AVAIL; new_status_descr = GG_STATUS_AVAIL_DESCR; purple_debug_info("gg", - "ggp_set_status: uknown status requested (status_id=%s)\n", + "ggp_set_status: unknown status requested (status_id=%s)\n", status_id); } - msg = purple_status_get_attr_string(status, "message"); + new_msg = purple_status_get_attr_string(status, "message"); + + if(new_msg) { + char *tmp = purple_markup_strip_html(new_msg); + *msg = charset_convert(tmp, "UTF-8", "CP1250"); + g_free(tmp); + + return new_status_descr; + } else { + *msg = NULL; + return new_status; + } +} +/* }}} */ - if (msg == NULL) { +/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */ +static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) +{ + PurpleConnection *gc; + GGPInfo *info; + int new_status; + char *new_msg = NULL; + + if (!purple_status_is_active(status)) + return; + + gc = purple_account_get_connection(account); + info = gc->proto_data; + + new_status = ggp_to_gg_status(status, &new_msg); + + if (new_msg == NULL) { gg_change_status(info->session, new_status); } else { - gchar *tmp, *new_msg; - - tmp = charset_convert(msg, "UTF-8", "CP1250"); - new_msg = purple_markup_strip_html(tmp); - g_free(tmp); - - gg_change_status_descr(info->session, new_status_descr, new_msg); + gg_change_status_descr(info->session, new_status, new_msg); g_free(new_msg); }
--- a/libpurple/protocols/irc/parse.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/protocols/irc/parse.c Fri May 30 14:29:33 2008 +0000 @@ -256,7 +256,7 @@ if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) { g_strfreev(encodings); - return g_strdup(string); + return NULL; } strtmp = botch_utf(string, strlen(string), &strtmp_len); @@ -798,7 +798,7 @@ case 'n': case 'c': tmp = irc_send_convert(irc, tok); - g_string_append(string, tmp); + g_string_append(string, tmp ? tmp : tok); g_free(tmp); break; default:
--- a/libpurple/protocols/oscar/oscar.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Fri May 30 14:29:33 2008 +0000 @@ -789,18 +789,6 @@ } static void -oscar_string_convert_and_append(PurpleAccount *account, GString *str, const char *newline, - const char *name, const char *value) -{ - gchar *utf8; - - if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, value))) { - g_string_append_printf(str, "%s<b>%s:</b> %s", newline, name, utf8); - g_free(utf8); - } -} - -static void oscar_user_info_convert_and_add(PurpleAccount *account, PurpleNotifyUserInfo *user_info, const char *name, const char *value) { @@ -812,7 +800,114 @@ } } -static void oscar_string_append_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) +static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) +{ + PurpleAccount *account = purple_connection_get_account(gc); + OscarData *od; + PurplePresence *presence = NULL; + PurpleStatus *status = NULL; + gchar *message = NULL, *itmsurl = NULL, *tmp; + + od = gc->proto_data; + + if (userinfo == NULL) + userinfo = aim_locate_finduserinfo(od, b->name); + + if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL))) + return; + + if (b == NULL) + b = purple_find_buddy(purple_connection_get_account(gc), userinfo->sn); + + if (b) { + presence = purple_buddy_get_presence(b); + status = purple_presence_get_active_status(presence); + + message = g_strdup(purple_status_get_attr_string(status, "message")); + itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl")); + + } else { + /* This is an OSCAR contact for whom we don't have a PurpleBuddy but do have information. */ + if ((userinfo->flags & AIM_FLAG_AWAY)) { + /* Away message? */ + if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { + gchar *away_utf8; + + tmp = oscar_encoding_extract(userinfo->away_encoding); + away_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->away, + userinfo->away_len); + g_free(tmp); + if (away_utf8 != NULL) { + message = purple_str_sub_away_formatters(away_utf8, purple_account_get_username(account)); + g_free(away_utf8); + } + } + } else { + /* Available message? */ + if ((userinfo->status != NULL) && userinfo->status[0] != '\0') { + tmp = oscar_encoding_to_utf8(account, userinfo->status_encoding, + userinfo->status, userinfo->status_len); + /* Available messages are plain text */ + message = g_markup_escape_text(tmp, -1); + g_free(tmp); + } +#if defined (_WIN32) || defined (__APPLE__) + if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) + itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, + userinfo->itmsurl, userinfo->itmsurl_len); +#endif + } + } + + if (itmsurl) { + tmp = g_strdup_printf("<a href=\"%s\">%s</a>", + itmsurl, message); + g_free(itmsurl); + g_free(message); + message = tmp; + } + + if (b) { + if (purple_presence_is_online(presence)) { + if (aim_snvalid_icq(b->name) || !message || !(*message)) { + /* Append the status name for online ICQ statuses and for all buddies with no message. + * If the status name and the message are the same, only show one. */ + const char *status_name = purple_status_get_name(status); + if (status_name && message && !strcmp(status_name, message)) + status_name = NULL; + + tmp = g_strdup_printf("%s%s%s", + status_name, + ((status_name && message) && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } + + } else { + if (aim_ssi_waitingforauth(od->ssi.local, + aim_ssi_itemlist_findparentname(od->ssi.local, b->name), + b->name)) { + /* Note if an offline buddy is not authorized */ + tmp = g_strdup_printf("%s%s%s", + _("Not Authorized"), + (message && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } else { + g_free(message); + message = g_strdup(_("Offline")); + } + } + + } + + purple_notify_user_info_add_pair(user_info, _("Status"), message); + g_free(message); +} + +static void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) { OscarData *od; PurpleAccount *account; @@ -842,22 +937,7 @@ if (userinfo != NULL) bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->sn)); - - if (b != NULL) { - if (purple_presence_is_online(presence)) { - if (aim_snvalid_icq(b->name)) { - PurpleStatus *status = purple_presence_get_active_status(presence); - oscar_user_info_add_pair(user_info, _("Status"), purple_status_get_name(status)); - } - } else { - tmp = aim_ssi_itemlist_findparentname(od->ssi.local, b->name); - if (aim_ssi_waitingforauth(od->ssi.local, tmp, b->name)) - oscar_user_info_add_pair(user_info, _("Status"), _("Not Authorized")); - else - oscar_user_info_add_pair(user_info, _("Status"), _("Offline")); - } - } - + if ((bi != NULL) && (bi->ipaddr != 0)) { tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", (bi->ipaddr & 0xff000000) >> 24, @@ -868,7 +948,6 @@ g_free(tmp); } - if ((userinfo != NULL) && (userinfo->warnlevel != 0)) { tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5)); oscar_user_info_add_pair(user_info, _("Warning Level"), tmp); @@ -1016,8 +1095,8 @@ if (source < 0) { - purple_debug_error("oscar", "unable to connect FLAP server " - "of type 0x%04hx\n", conn->type); + purple_debug_error("oscar", "unable to connect to FLAP " + "server of type 0x%04hx\n", conn->type); if (conn->type == SNAC_FAMILY_AUTH) { gchar *msg; @@ -2965,7 +3044,7 @@ PurpleConnection *gc = od->gc; PurpleAccount *account = purple_connection_get_account(gc); PurpleNotifyUserInfo *user_info; - gchar *tmp = NULL, *info_utf8 = NULL, *away_utf8 = NULL; + gchar *tmp = NULL, *info_utf8 = NULL; va_list ap; aim_userinfo_t *userinfo; @@ -2974,23 +3053,8 @@ va_end(ap); user_info = purple_notify_user_info_new(); - purple_notify_user_info_add_pair(user_info, _("Username"), userinfo->sn); - - if (userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) { - time_t t = userinfo->onlinesince; - oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); - } - - if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { - time_t t = userinfo->membersince; - oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t))); - } - - if (userinfo->capabilities != 0) { - tmp = oscar_caps_to_string(userinfo->capabilities); - oscar_user_info_add_pair(user_info, _("Capabilities"), tmp); - g_free(tmp); - } + + oscar_user_info_append_status(gc, user_info, NULL, userinfo); if (userinfo->present & AIM_USERINFO_PRESENT_IDLE) { tmp = purple_str_seconds_to_string(userinfo->idletime*60); @@ -2998,44 +3062,25 @@ g_free(tmp); } - oscar_string_append_info(gc, user_info, NULL, userinfo); - - /* Available message */ - if ((userinfo->status != NULL) && !(userinfo->flags & AIM_FLAG_AWAY)) - { - if (userinfo->status[0] != '\0') - tmp = oscar_encoding_to_utf8(account, userinfo->status_encoding, - userinfo->status, userinfo->status_len); -#if defined (_WIN32) || defined (__APPLE__) - if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) { - gchar *itmsurl, *tmp2; - itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, - userinfo->itmsurl, userinfo->itmsurl_len); - tmp2 = g_strdup_printf("<a href=\"%s\">%s</a>", - itmsurl, tmp); - g_free(tmp); - tmp = tmp2; - g_free(itmsurl); - } -#endif - oscar_user_info_add_pair(user_info, _("Available Message"), tmp); + oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo); + + if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !aim_snvalid_sms(userinfo->sn)) { + /* An SMS contact is always online; its Online Since valid is not useful */ + time_t t = userinfo->onlinesince; + oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); + } + + if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { + time_t t = userinfo->membersince; + oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t))); + } + + if (userinfo->capabilities != 0) { + tmp = oscar_caps_to_string(userinfo->capabilities); + oscar_user_info_add_pair(user_info, _("Capabilities"), tmp); g_free(tmp); } - /* Away message */ - if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { - tmp = oscar_encoding_extract(userinfo->away_encoding); - away_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->away, - userinfo->away_len); - g_free(tmp); - if (away_utf8 != NULL) { - tmp = purple_str_sub_away_formatters(away_utf8, purple_account_get_username(account)); - oscar_user_info_add_pair(user_info, _("Away Message"), tmp); - g_free(tmp); - g_free(away_utf8); - } - } - /* Info */ if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->info_encoding); @@ -3732,12 +3777,9 @@ PurpleConnection *gc; PurpleAccount *account; PurpleBuddy *buddy; - PurplePresence *presence; - PurpleStatus *status; struct buddyinfo *bi; gchar who[16]; PurpleNotifyUserInfo *user_info; - GString *tmp; gchar *utf8; gchar *buf; const gchar *alias; @@ -3818,8 +3860,7 @@ if ((info->age > 0) && (info->age < 255)) { char age[5]; snprintf(age, sizeof(age), "%hhd", info->age); - purple_notify_user_info_add_pair(user_info, - _("Age"), age); + purple_notify_user_info_add_pair(user_info, _("Age"), age); } if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->personalwebpage))) { buf = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8); @@ -3828,65 +3869,41 @@ g_free(utf8); } - if (buddy != NULL) { - const gchar *message; - gchar *utf8, *tmp; - - presence = purple_buddy_get_presence(buddy); - status = purple_presence_get_active_status(presence); - message = purple_status_get_attr_string(status, "message"); - - utf8 = message && message[0] ? oscar_utf8_try_convert(account, message) : NULL; - tmp = g_strdup_printf("%s%s%s", - purple_status_get_name(status), - utf8 && *utf8 ? ": " : "", - utf8 && *utf8 ? utf8 : ""); - g_free(utf8); - - oscar_user_info_convert_and_add(account, - user_info, _("Status"), tmp); - } + if (buddy != NULL) + oscar_user_info_append_status(gc, user_info, buddy, NULL); oscar_user_info_convert_and_add(account, user_info, _("Additional Information"), info->info); purple_notify_user_info_add_section_break(user_info); if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { - tmp = g_string_sized_new(100); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Address"), info->homeaddr); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("City"), info->homecity); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("State"), info->homestate); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Zip Code"), info->homezip); - - purple_notify_user_info_add_pair(user_info, _("Home Address"), tmp->str); - purple_notify_user_info_add_section_break(user_info); - - g_string_free(tmp, TRUE); + purple_notify_user_info_add_section_header(user_info, _("Home Address")); + + oscar_user_info_convert_and_add(account, user_info, _("Address"), info->homeaddr); + oscar_user_info_convert_and_add(account, user_info, _("City"), info->homecity); + oscar_user_info_convert_and_add(account, user_info, _("State"), info->homestate); + oscar_user_info_convert_and_add(account, user_info, _("Zip Code"), info->homezip); } if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { - tmp = g_string_sized_new(100); - - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Address"), info->workaddr); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("City"), info->workcity); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("State"), info->workstate); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Zip Code"), info->workzip); - - purple_notify_user_info_add_pair(user_info, _("Work Address"), tmp->str); - purple_notify_user_info_add_section_break(user_info); - - g_string_free(tmp, TRUE); + purple_notify_user_info_add_section_header(user_info, _("Work Address")); + + oscar_user_info_convert_and_add(account, user_info, _("Address"), info->workaddr); + oscar_user_info_convert_and_add(account, user_info, _("City"), info->workcity); + oscar_user_info_convert_and_add(account, user_info, _("State"), info->workstate); + oscar_user_info_convert_and_add(account, user_info, _("Zip Code"), info->workzip); } if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { - tmp = g_string_sized_new(100); + purple_notify_user_info_add_section_header(user_info, _("Work Information")); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Company"), info->workcompany); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Division"), info->workdivision); - oscar_string_convert_and_append(account, tmp, "\n<br>", _("Position"), info->workposition); + oscar_user_info_convert_and_add(account, user_info, _("Company"), info->workcompany); + oscar_user_info_convert_and_add(account, user_info, _("Division"), info->workdivision); + oscar_user_info_convert_and_add(account, user_info, _("Position"), info->workposition); + if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->workwebpage))) { - g_string_append_printf(tmp, "\n<br><b>%s:</b> <a href=\"%s\">%s</a>", _("Web Page"), utf8, utf8); + char *webpage = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8); + purple_notify_user_info_add_pair(user_info, _("Web Page"), webpage); + g_free(webpage); g_free(utf8); } - purple_notify_user_info_add_pair(user_info, _("Work Information"), tmp->str); - g_string_free(tmp, TRUE); } if (buddy != NULL) @@ -5671,47 +5688,10 @@ aim_userinfo_t *userinfo = aim_locate_finduserinfo(od, b->name); if (PURPLE_BUDDY_IS_ONLINE(b)) { - PurplePresence *presence; - PurpleStatus *status; - const char *message; + oscar_user_info_append_status(gc, user_info, b, userinfo); if (full) - oscar_string_append_info(gc, user_info, b, userinfo); - - presence = purple_buddy_get_presence(b); - status = purple_presence_get_active_status(presence); - message = purple_status_get_attr_string(status, "message"); - - if (purple_status_is_available(status)) - { - if (message != NULL) - { - /* Available status messages are plain text */ - gchar *tmp; - tmp = g_markup_escape_text(message, -1); - purple_notify_user_info_add_pair(user_info, _("Message"), tmp); - g_free(tmp); - } - } - else - { - if (message != NULL) - { - /* Away messages are HTML */ - gchar *tmp1, *tmp2; - tmp2 = purple_markup_strip_html(message); - tmp1 = g_markup_escape_text(tmp2, -1); - g_free(tmp2); - tmp2 = purple_str_sub_away_formatters(tmp1, purple_account_get_username(purple_connection_get_account(gc))); - g_free(tmp1); - purple_notify_user_info_add_pair(user_info, _("Away Message"), tmp2); - g_free(tmp2); - } - else - { - purple_notify_user_info_add_pair(user_info, _("Away Message"), _("<i>(retrieving)</i>")); - } - } + oscar_user_info_append_extra_info(gc, user_info, b, userinfo); } }
--- a/libpurple/smiley.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/smiley.c Fri May 30 14:29:33 2008 +0000 @@ -641,10 +641,9 @@ old_filename = purple_imgstore_get_filename(old_img); new_filename = purple_imgstore_get_filename(smiley->img); - if (g_ascii_strcasecmp(old_filename, new_filename)) { + if (g_ascii_strcasecmp(old_filename, new_filename)) purple_smiley_data_unstore(old_filename); - purple_imgstore_unref(old_img); - } + purple_imgstore_unref(old_img); }
--- a/libpurple/status.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/status.c Fri May 30 14:29:33 2008 +0000 @@ -107,8 +107,6 @@ PurpleStatusType *type; PurplePresence *presence; - const char *title; - gboolean active; /*
--- a/libpurple/util.c Tue May 27 14:14:40 2008 +0000 +++ b/libpurple/util.c Fri May 30 14:29:33 2008 +0000 @@ -1359,6 +1359,14 @@ GString *cdata = NULL; GList *tags = NULL, *tag; const char *c = html; + char quote = '\0'; + +#define CHECK_QUOTE(ptr) if (*(ptr) == '\'' || *(ptr) == '\"') \ + quote = *(ptr++); \ + else \ + quote = '\0'; + +#define VALID_CHAR(ptr) (*(ptr) && *(ptr) != quote && (quote || (*(ptr) != ' ' && *(ptr) != '>'))) g_return_if_fail(xhtml_out != NULL || plain_out != NULL); @@ -1516,38 +1524,37 @@ xhtml = g_string_append(xhtml, "<span style='vertical-align:super;'>"); continue; } - if(!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) { + const char *p = c + 4; GString *src = NULL, *alt = NULL; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "src=", strlen("src="))) { - const char *q = p + strlen("src="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "src=", 4)) { + const char *q = p + 4; if (src) g_string_free(src, TRUE); src = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { src = g_string_append_c(src, *q); q++; } p = q; - } else if(!g_ascii_strncasecmp(p, "alt=", strlen("alt="))) { - const char *q = p + strlen("alt="); + } else if (!g_ascii_strncasecmp(p, "alt=", 4)) { + const char *q = p + 4; if (alt) g_string_free(alt, TRUE); alt = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { alt = g_string_append_c(alt, *q); q++; } p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1564,21 +1571,20 @@ g_string_free(src, TRUE); continue; } - if(!g_ascii_strncasecmp(c, "<a", 2) && (*(c+2) == '>' || *(c+2) == ' ')) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<a", 2) && (*(c+2) == '>' || *(c+2) == ' ')) { + const char *p = c + 2; struct purple_parse_tag *pt; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "href=", strlen("href="))) { - const char *q = p + strlen("href="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "href=", 5)) { + const char *q = p + 5; if (url) g_string_free(url, TRUE); url = g_string_new(""); if (cdata) g_string_free(cdata, TRUE); cdata = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { int len; if ((*q == '&') && (purple_markup_unescape_entity(q, &len) == NULL)) url = g_string_append(url, "&"); @@ -1587,10 +1593,11 @@ q++; } p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1603,55 +1610,48 @@ continue; } if(!g_ascii_strncasecmp(c, "<font", 5) && (*(c+5) == '>' || *(c+5) == ' ')) { - const char *p = c; + const char *p = c + 5; GString *style = g_string_new(""); struct purple_parse_tag *pt; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "back=", strlen("back="))) { - const char *q = p + strlen("back="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "back=", 5)) { + const char *q = p + 5; GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } g_string_append_printf(style, "background: %s; ", color->str); g_string_free(color, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "color=", strlen("color="))) { - const char *q = p + strlen("color="); + } else if (!g_ascii_strncasecmp(p, "color=", 6)) { + const char *q = p + 6; GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } g_string_append_printf(style, "color: %s; ", color->str); g_string_free(color, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "face=", strlen("face="))) { - const char *q = p + strlen("face="); - gboolean space_allowed = FALSE; + } else if (!g_ascii_strncasecmp(p, "face=", 5)) { + const char *q = p + 5; GString *face = g_string_new(""); - if(*q == '\'' || *q == '\"') { - space_allowed = TRUE; - q++; - } - while(*q && *q != '\"' && *q != '\'' && (space_allowed || *q != ' ')) { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { face = g_string_append_c(face, *q); q++; } g_string_append_printf(style, "font-family: %s; ", g_strstrip(face->str)); g_string_free(face, TRUE); p = q; - } else if(!g_ascii_strncasecmp(p, "size=", strlen("size="))) { - const char *q = p + strlen("size="); + } else if (!g_ascii_strncasecmp(p, "size=", 5)) { + const char *q = p + 5; int sz; const char *size = "medium"; - if(*q == '\'' || *q == '\"') - q++; + CHECK_QUOTE(q); sz = atoi(q); switch (sz) { @@ -1681,10 +1681,11 @@ } g_string_append_printf(style, "font-size: %s; ", size); p = q; + } else { + p++; } - p++; } - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1699,24 +1700,23 @@ g_string_free(style, TRUE); continue; } - if(!g_ascii_strncasecmp(c, "<body ", 6)) { - const char *p = c; + if (!g_ascii_strncasecmp(c, "<body ", 6)) { + const char *p = c + 6; gboolean did_something = FALSE; - while(*p && *p != '>') { - if(!g_ascii_strncasecmp(p, "bgcolor=", strlen("bgcolor="))) { - const char *q = p + strlen("bgcolor="); + while (*p && *p != '>') { + if (!g_ascii_strncasecmp(p, "bgcolor=", 8)) { + const char *q = p + 8; struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1); GString *color = g_string_new(""); - if(*q == '\'' || *q == '\"') - q++; - while(*q && *q != '\"' && *q != '\'' && *q != ' ') { + CHECK_QUOTE(q); + while (VALID_CHAR(q)) { color = g_string_append_c(color, *q); q++; } - if(xhtml) + if (xhtml) g_string_append_printf(xhtml, "<span style='background: %s;'>", g_strstrip(color->str)); g_string_free(color, TRUE); - if ((c = strchr(c, '>')) != NULL) + if ((c = strchr(p, '>')) != NULL) c++; else c = p; @@ -1728,7 +1728,7 @@ } p++; } - if(did_something) continue; + if (did_something) continue; } /* this has to come after the special case for bgcolor */ ALLOW_TAG("body"); @@ -1791,6 +1791,8 @@ g_string_free(url, TRUE); if (cdata) g_string_free(cdata, TRUE); +#undef CHECK_QUOTE +#undef VALID_CHAR } /* The following are probably reasonable changes:
--- a/pidgin/gtkaccount.c Tue May 27 14:14:40 2008 +0000 +++ b/pidgin/gtkaccount.c Fri May 30 14:29:33 2008 +0000 @@ -2191,8 +2191,7 @@ G_TYPE_STRING, /* COLUMN_SCREENNAME */ G_TYPE_BOOLEAN, /* COLUMN_ENABLED */ G_TYPE_STRING, /* COLUMN_PROTOCOL */ - G_TYPE_POINTER, /* COLUMN_DATA */ - G_TYPE_POINTER /* COLUMN_PULSE_DATA */ + G_TYPE_POINTER /* COLUMN_DATA */ ); /* And now the actual treeview */
--- a/pidgin/gtkimhtml.c Tue May 27 14:14:40 2008 +0000 +++ b/pidgin/gtkimhtml.c Fri May 30 14:29:33 2008 +0000 @@ -519,6 +519,7 @@ tmp); g_free(tmp); + g_object_unref(layout); return FALSE; } @@ -558,6 +559,7 @@ gtk_widget_show (imhtml->tip_window); pango_font_metrics_unref(font_metrics); + g_object_unref(font); g_object_unref(layout); return FALSE; @@ -5061,6 +5063,7 @@ break; default: str += g_snprintf(str, sizeof(buf) - (str - buf), "text-decoration: underline;"); + empty = FALSE; } } @@ -5112,6 +5115,38 @@ } } +typedef struct { + GtkTextTag *tag; + char *end; + char *start; +} PidginTextTagData; + +static PidginTextTagData *text_tag_data_new(GtkTextTag *tag) +{ + const char *start, *end; + PidginTextTagData *ret = NULL; + + start = tag_to_html_start(tag); + if (!start || !*start) + return NULL; + end = tag_to_html_end(tag); + if (!end || !*end) + return NULL; + + ret = g_new0(PidginTextTagData, 1); + ret->start = g_strdup(start); + ret->end = g_strdup(end); + ret->tag = tag; + return ret; +} + +static void text_tag_data_destroy(PidginTextTagData *data) +{ + g_free(data->start); + g_free(data->end); + g_free(data); +} + static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) { return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && @@ -5132,12 +5167,11 @@ gboolean is_rtl_message = FALSE; GString *str = g_string_new(""); GSList *tags, *sl; - GQueue *q, *r; + GQueue *q; GtkTextTag *tag; + PidginTextTagData *tagdata; q = g_queue_new(); - r = g_queue_new(); - gtk_text_iter_order(start, end); non_neutral_iter = next_iter = iter = *start; @@ -5160,9 +5194,11 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { - if (strlen(tag_to_html_end(tag)) > 0) - g_string_append(str, tag_to_html_start(tag)); - g_queue_push_tail(q, tag); + PidginTextTagData *data = text_tag_data_new(tag); + if (data) { + g_string_append(str, data->start); + g_queue_push_tail(q, data); + } } } g_slist_free(tags); @@ -5174,13 +5210,14 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { - if (strlen(tag_to_html_end(tag)) > 0) - g_string_append(str, tag_to_html_start(tag)); - g_queue_push_tail(q, tag); + PidginTextTagData *data = text_tag_data_new(tag); + if (data) { + g_string_append(str, data->start); + g_queue_push_tail(q, data); + } } } - if (c == 0xFFFC) { GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); if (anchor) { @@ -5206,28 +5243,31 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; /** don't worry about non-printing tags ending */ - if (tag_ends_here(tag, &iter, &next_iter) && strlen(tag_to_html_end(tag)) > 0) { - - GtkTextTag *tmp; - - while ((tmp = g_queue_pop_tail(q)) != tag) { - if (tmp == NULL) - break; - - if (!tag_ends_here(tmp, &iter, &next_iter) && strlen(tag_to_html_end(tmp)) > 0) + if (tag_ends_here(tag, &iter, &next_iter) && + strlen(tag_to_html_end(tag)) > 0 && + strlen(tag_to_html_start(tag)) > 0) { + + PidginTextTagData *tmp; + GQueue *r = g_queue_new(); + + while ((tmp = g_queue_pop_tail(q)) && tmp->tag != tag) { + g_string_append(str, tmp->end); + if (!tag_ends_here(tmp->tag, &iter, &next_iter)) g_queue_push_tail(r, tmp); - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); + else + text_tag_data_destroy(tmp); } if (tmp == NULL) purple_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); else - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); + g_string_append(str, tmp->end); while ((tmp = g_queue_pop_head(r))) { - g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); + g_string_append(str, tmp->start); g_queue_push_tail(q, tmp); } + g_queue_free(r); } } @@ -5236,15 +5276,16 @@ gtk_text_iter_forward_char(&next_iter); } - while ((tag = g_queue_pop_tail(q))) - g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); + while ((tagdata = g_queue_pop_tail(q))) { + g_string_append(str, tagdata->end); + text_tag_data_destroy(tagdata); + } /* Bi-directional text support - close tags */ if (is_rtl_message) g_string_append(str, "</SPAN>"); g_queue_free(q); - g_queue_free(r); return g_string_free(str, FALSE); }
--- a/pidgin/gtkimhtml.h Tue May 27 14:14:40 2008 +0000 +++ b/pidgin/gtkimhtml.h Fri May 30 14:29:33 2008 +0000 @@ -854,11 +854,36 @@ */ void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags); +/** + * Create a new GtkIMHtmlSmiley. + * + * @param file The image file for the smiley + * @param shortcut The key shortcut for the smiley + * @param hide @c TRUE if the smiley should be hidden in the smiley dialog, @c FALSE otherwise + * @param flags The smiley flags + * + * @return The newly created smiley + * @since 2.5.0 + */ GtkIMHtmlSmiley *gtk_imhtml_smiley_create(const char *file, const char *shortcut, gboolean hide, GtkIMHtmlSmileyFlags flags); +/** + * Reload the image data for the smiley. + * + * @param smiley The smiley to reload + * + * @since 2.5.0 + */ void gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley); +/** + * Destroy a GtkIMHtmlSmiley. + * + * @param smiley The smiley to destroy + * + * @since 2.5.0 + */ void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley); /*@}*/
--- a/pidgin/gtkimhtmltoolbar.c Tue May 27 14:14:40 2008 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Fri May 30 14:29:33 2008 +0000 @@ -1122,7 +1122,10 @@ } destroy_toolbar_font(NULL, NULL, toolbar); - destroy_smiley_dialog(toolbar); + if (toolbar->smiley_dialog != NULL) { + g_signal_handlers_disconnect_by_func(G_OBJECT(toolbar->smiley_dialog), close_smiley_dialog, toolbar); + destroy_smiley_dialog(toolbar); + } destroy_toolbar_bgcolor(NULL, NULL, toolbar); destroy_toolbar_fgcolor(NULL, NULL, toolbar); close_link_dialog(toolbar);
--- a/pidgin/gtksmiley.c Tue May 27 14:14:40 2008 +0000 +++ b/pidgin/gtksmiley.c Fri May 30 14:29:33 2008 +0000 @@ -96,6 +96,18 @@ gtksmiley->smile = g_strdup(purple_smiley_get_shortcut(smiley)); } +static void +image_changed_cb(PurpleSmiley *smiley, gpointer dontcare, GtkIMHtmlSmiley *gtksmiley) +{ + const char *file; + + g_free(gtksmiley->file); + + file = purple_imgstore_get_filename(purple_smiley_get_stored_image(smiley)); + gtksmiley->file = g_build_filename(purple_smileys_get_storing_dir(), file, NULL); + gtk_imhtml_smiley_reload(gtksmiley); +} + static GtkIMHtmlSmiley *smiley_purple_to_gtkimhtml(PurpleSmiley *smiley) { GtkIMHtmlSmiley *gtksmiley; @@ -114,6 +126,10 @@ g_signal_connect(G_OBJECT(smiley), "notify::shortcut", G_CALLBACK(shortcut_changed_cb), gtksmiley); + /* And update the pixbuf too when the image is changed */ + g_signal_connect(G_OBJECT(smiley), "notify::image", + G_CALLBACK(image_changed_cb), gtksmiley); + return gtksmiley; }
--- a/po/de.po Tue May 27 14:14:40 2008 +0000 +++ b/po/de.po Fri May 30 14:29:33 2008 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-05-26 21:14+0200\n" -"PO-Revision-Date: 2008-05-26 21:14+0200\n" +"POT-Creation-Date: 2008-05-29 17:29+0200\n" +"PO-Revision-Date: 2008-05-29 17:28+0200\n" "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n" "Language-Team: Deutsch <de@li.org>\n" "MIME-Version: 1.0\n" @@ -612,6 +612,20 @@ msgid "Send To" msgstr "Senden an" +msgid "Invite message" +msgstr "Einladungsnachricht" + +msgid "Invite" +msgstr "Einladen" + +#, fuzzy +msgid "" +"Please enter the name of the user you wish to invite,\n" +"along with an optional invite message." +msgstr "" +"Bitte geben Sie den Benutzernamen der Person ein, die Sie einladen möchten " +"zusammen mit einer optionalen Einladungsnachricht." + msgid "Conversation" msgstr "Unterhaltung" @@ -624,6 +638,9 @@ msgid "Add Buddy Pounce..." msgstr "Buddy-Alarm hinzufügen..." +msgid "Invite..." +msgstr "Einladen..." + msgid "Enable Logging" msgstr "Mitschnitt einschalten" @@ -870,9 +887,6 @@ msgid "IM" msgstr "Nachricht" -msgid "Invite" -msgstr "Einladen" - msgid "(none)" msgstr "(kein)" @@ -2875,6 +2889,9 @@ msgid "Save buddylist..." msgstr "Buddy-Liste speichern..." +msgid "Load buddylist from file..." +msgstr "Buddy-Liste aus Datei laden..." + msgid "Fill in the registration fields." msgstr "Füllen Sie die Registrierungsfelder aus." @@ -3051,9 +3068,6 @@ msgid "Save buddylist to file..." msgstr "Buddy-Liste in Datei speichern..." -msgid "Load buddylist from file..." -msgstr "Buddy-Liste aus Datei laden..." - #. magic #. major_version #. minor_version @@ -3620,6 +3634,8 @@ msgid "Country" msgstr "Land" +#. lots of clients (including purple) do this, but it's +#. * out of spec msgid "Telephone" msgstr "Telefon" @@ -3807,12 +3823,12 @@ msgid "Capabilities" msgstr "Fähigkeiten" +msgid "Priority" +msgstr "Priorität" + msgid "Resource" msgstr "Ressource" -msgid "Priority" -msgstr "Priorität" - msgid "Middle Name" msgstr "Zweiter Name" @@ -6514,9 +6530,6 @@ msgid "Member Since" msgstr "Mitglied seit" -msgid "Available Message" -msgstr "Verfügbarkeitsnachricht" - msgid "Your AIM connection may be lost." msgstr "Ihre AIM-Verbindung könnte unterbrochen sein." @@ -6552,6 +6565,9 @@ msgid "Zip Code" msgstr "PLZ" +msgid "Work Information" +msgstr "Information (Arbeit)" + msgid "Division" msgstr "Abteilung" @@ -6561,9 +6577,6 @@ msgid "Web Page" msgstr "Webseite" -msgid "Work Information" -msgstr "Information (Arbeit)" - msgid "Pop-Up Message" msgstr "Pop-Up Nachricht" @@ -6784,12 +6797,6 @@ "Ihr IM-Bild wurde nicht gesendet. Sie können keine IM-Bilder in AIM-Chats " "senden." -msgid "Away Message" -msgstr "Abwesenheitsnachricht" - -msgid "<i>(retrieving)</i>" -msgstr "<i>(empfange)</i>" - msgid "iTunes Music Store Link" msgstr "iTunes Music Store Link"