Mercurial > pidgin.yaz
changeset 25021:951b7ff9a888
propagate from branch 'im.pidgin.pidgin' (head 586bc4a7e754d6b26a95c0d69dd5f2967c7a98a1)
to branch 'im.pidgin.cpw.darkrain42.oscar.ssl' (head a6ac2fbddf65812a7fe2e01d10451f8b82ab35e5)
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 27 Jan 2009 09:36:35 +0000 (2009-01-27) |
parents | 86ba0d87c04b (diff) 0ba3da7724ff (current diff) |
children | f6ef3a9534db |
files | |
diffstat | 36 files changed, 405 insertions(+), 190 deletions(-) [+] |
line wrap: on
line diff
--- a/AUTHORS Mon Jan 19 18:44:31 2009 +0000 +++ b/AUTHORS Tue Jan 27 09:36:35 2009 +0000 @@ -36,7 +36,6 @@ Crazy Patch Writers: ------------------- Paul Aurich -Felipe 'shx' Contreras Marcus 'malu' Lundblad Dennis 'EvilDennisR' Ristuccia Peter 'Fmoo' Ruibal @@ -57,6 +56,7 @@ Retired Crazy Patch Writers: --------------------------- +Felipe 'shx' Contreras Decklin Foster Peter 'Bleeter' Lawler Robert 'Robot101' McQueen
--- a/COPYRIGHT Mon Jan 19 18:44:31 2009 +0000 +++ b/COPYRIGHT Tue Jan 27 09:36:35 2009 +0000 @@ -63,6 +63,7 @@ Damien Carbery Michael Carlson Keegan Carruthers-Smith +Ludovico Cavedon Steve Cavilia Julien Cegarra Cerulean Studios, LLC @@ -210,6 +211,7 @@ Jarom鱈r Karmaz鱈n John Kelm Jochen Kemnade +Yann Kerherve Akuke Kok Kir Kolyshkin Konstantin Korikov @@ -229,6 +231,7 @@ Steve L叩posi Daniel Larsson Peter Lawler +Vadim Lebedev Ho-seok Lee Jean-Yves Lefort Moses Lei @@ -441,6 +444,7 @@ Todd Troxell Brad Turcotte Kyle Turman +Jon Turney Junichi Uekawa Igor Vlasenko Istv叩n V叩radi @@ -477,6 +481,7 @@ Dan Winship Michal Witkowski Scott Wolchok +Rogier Wolff The Written Word, Inc. Kevin Wu Won Pui Lam Wong
--- a/ChangeLog Mon Jan 19 18:44:31 2009 +0000 +++ b/ChangeLog Tue Jan 27 09:36:35 2009 +0000 @@ -1,6 +1,12 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.5.5 (??/??/????): + libpurple: + * Fix transfer of buddy icons, custom smileys and files from the + latest WLM 9 official client. (Thomas Gibson-Robinson) + * Fix a crash when removing an account with an unknown protocol id. + * Large (multi-part) messages on MSN are now correctly re-combined. + Finch: * Allow rebinding keys to change the focused widget (details in the man-page, look for GntBox::binding)
--- a/ChangeLog.API Mon Jan 19 18:44:31 2009 +0000 +++ b/ChangeLog.API Tue Jan 27 09:36:35 2009 +0000 @@ -1,5 +1,12 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.5.5 (??/??/2009): + libpurple: + Changed: + * purple_status_type_new now defaults "saveable" to TRUE. + This was necessary in order to maintain the current behavior + while fixing non-saveable statuses not to be saved. + version 2.5.4 (01/12/2009): perl: Changed:
--- a/doc/finch.1.in Mon Jan 19 18:44:31 2009 +0000 +++ b/doc/finch.1.in Tue Jan 27 09:36:35 2009 +0000 @@ -543,23 +543,26 @@ \fIhttp://developer.pidgin.im/query?status=new&status=assigned&status=reopened&component=finch+%28gnt%2Fncurses%29&order=priority\fR Before sending a bug report, please verify that you have the latest -version of \fBfinch\fR and \fBlibpurple\fR. Many bugs (major and minor) are +version of \fBfinch\fR and libpurple. Many bugs (major and minor) are fixed at each release, and if yours is out of date, the problem may already have been solved. - .SH PATCHES If you fix a bug in \fBfinch\fR (or otherwise enhance it), please submit a -patch (using \fImtn diff > my.diff\fR against the latest version from the -Monotone repository) at -.br -\fIhttp://developer.pidgin.im/newticket\fR +patch (using \fBmtn diff > my.diff\fR against the latest version from the +Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR -You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR to -discuss development. +You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR +to discuss development. .SH SEE ALSO \fIhttp://pidgin.im/\fR +.br +\fIhttp://developer.pidgin.im/\fR +.br +\fBpurple-remote\fR(1) +.br +\fBpidgin\fR(1) .SH LICENSE This program is free software; you can redistribute it and/or modify
--- a/doc/pidgin.1.in Mon Jan 19 18:44:31 2009 +0000 +++ b/doc/pidgin.1.in Tue Jan 27 09:36:35 2009 +0000 @@ -34,6 +34,9 @@ many common features found in other clients, as well as many unique features. Pidgin is not endorsed by or affiliated with America Online, ICQ, Microsoft, or Yahoo. +.PP +Pidgin can be extended by plugins written in multiple programming languages and +controlled through DBus or \fBpurple-remote\fR. .SH OPTIONS The following options are provided by Pidgin using the standard GNU @@ -556,20 +559,28 @@ .SH BUGS The bug tracker can be reached by visiting \fIhttp://developer.pidgin.im/query\fR -.SH PATCHES -If you fix a bug in Pidgin (or otherwise enhance it), please submit a -patch (using \fImtn diff > my.diff\fR against the latest version from the -Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR - Before sending a bug report, please verify that you have the latest version of Pidgin. Many bugs (major and minor) are fixed at each release, and if yours is out of date, the problem may already have been solved. +.SH PATCHES +If you fix a bug in Pidgin (or otherwise enhance it), please submit a +patch (using \fBmtn diff > my.diff\fR against the latest version from the +Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR + +You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR +to discuss development. + + .SH SEE ALSO \fIhttp://pidgin.im/\fR .br \fIhttp://developer.pidgin.im/\fR +.br +\fBpurple-remote\fR(1) +.br +\fBfinch\fR(1) .SH LICENSE This program is free software; you can redistribute it and/or modify @@ -643,8 +654,6 @@ .br Paul Aurich .br - Felipe 'shx' Contreras -.br Marcus 'malu' Lundblad .br Dennis 'EvilDennisR' Ristuccia @@ -687,6 +696,8 @@ Our retired crazy patch writers include: .br + Felipe 'shx' Contreras +.br Decklin Foster .br Peter 'Bleeter' Lawler
--- a/libpurple/account.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/account.c Tue Jan 27 09:36:35 2009 +0000 @@ -257,15 +257,20 @@ statuses_to_xmlnode(const PurplePresence *presence) { xmlnode *node, *child; - GList *statuses, *status; + GList *statuses; + PurpleStatus *status; node = xmlnode_new("statuses"); statuses = purple_presence_get_statuses(presence); - for (status = statuses; status != NULL; status = status->next) + for (; statuses != NULL; statuses = statuses->next) { - child = status_to_xmlnode((PurpleStatus *)status->data); - xmlnode_insert_child(node, child); + status = statuses->data; + if (purple_status_type_is_saveable(purple_status_get_type(status))) + { + child = status_to_xmlnode(status); + xmlnode_insert_child(node, child); + } } return node;
--- a/libpurple/blist.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/blist.c Tue Jan 27 09:36:35 2009 +0000 @@ -1811,7 +1811,7 @@ PurpleGroup *group; struct _purple_hbuddy hb; PurplePlugin *prpl; - PurplePluginProtocolInfo *prpl_info; + PurplePluginProtocolInfo *prpl_info = NULL; g_return_if_fail(buddy != NULL); @@ -1872,7 +1872,8 @@ * can free proto_data */ prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account)); - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + if (prpl) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); if (prpl_info && prpl_info->buddy_free) prpl_info->buddy_free(buddy);
--- a/libpurple/certificate.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/certificate.c Tue Jan 27 09:36:35 2009 +0000 @@ -1546,31 +1546,11 @@ void purple_certificate_uninit(void) { - GList *full_list, *l; - - /* Unregister all Schemes */ - full_list = g_list_copy(cert_schemes); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_scheme( - (PurpleCertificateScheme *) l->data ); - } - g_list_free(full_list); - /* Unregister all Verifiers */ - full_list = g_list_copy(cert_verifiers); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_verifier( - (PurpleCertificateVerifier *) l->data ); - } - g_list_free(full_list); + g_list_foreach(cert_verifiers, (GFunc)purple_certificate_unregister_verifier, NULL); /* Unregister all Pools */ - full_list = g_list_copy(cert_pools); /* Make a working copy */ - for (l = full_list; l; l = l->next) { - purple_certificate_unregister_pool( - (PurpleCertificatePool *) l->data ); - } - g_list_free(full_list); + g_list_foreach(cert_pools, (GFunc)purple_certificate_unregister_pool, NULL); } gpointer
--- a/libpurple/connection.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/connection.c Tue Jan 27 09:36:35 2009 +0000 @@ -545,7 +545,7 @@ } if (description == NULL) { - purple_debug_error("connection", "purple_connection_error_reason: check `description != NULL' failed\n"); + purple_debug_error("connection", "purple_connection_error_reason called with NULL description\n"); description = _("Unknown error"); }
--- a/libpurple/core.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/core.c Tue Jan 27 09:36:35 2009 +0000 @@ -137,7 +137,7 @@ * subsystem right away too. */ purple_plugins_init(); - + /* Initialize all static protocols. */ static_proto_init(); @@ -198,22 +198,40 @@ /* Transmission ends */ purple_connections_disconnect_all(); + /* + * Certificates must be destroyed before the SSL plugins, because + * PurpleCertificates contain pointers to PurpleCertificateSchemes, + * and the PurpleCertificateSchemes will be unregistered when the + * SSL plugin is uninit. + */ + purple_certificate_uninit(); + + /* The SSL plugins must be uninit before they're unloaded */ + purple_ssl_uninit(); + + /* Unload all plugins before the UI because UI plugins might call + * UI-specific functions */ + purple_debug_info("main", "Unloading all plugins\n"); + purple_plugins_destroy_all(); + + /* Shut down the UI before all the subsystems */ + ops = purple_core_get_ui_ops(); + if (ops != NULL && ops->quit != NULL) + ops->quit(); + /* Save .xml files, remove signals, etc. */ purple_smileys_uninit(); purple_idle_uninit(); - purple_ssl_uninit(); purple_pounces_uninit(); purple_blist_uninit(); purple_ciphers_uninit(); purple_notify_uninit(); purple_conversations_uninit(); purple_connections_uninit(); - purple_certificate_uninit(); purple_buddy_icons_uninit(); purple_accounts_uninit(); purple_savedstatuses_uninit(); purple_status_uninit(); - purple_prefs_uninit(); purple_sound_uninit(); purple_xfers_uninit(); purple_proxy_uninit(); @@ -221,19 +239,15 @@ purple_imgstore_uninit(); purple_network_uninit(); - purple_debug_info("main", "Unloading all plugins\n"); - purple_plugins_destroy_all(); - - ops = purple_core_get_ui_ops(); - if (ops != NULL && ops->quit != NULL) - ops->quit(); - + /* Everything after this must not try to read any prefs */ + purple_prefs_uninit(); purple_plugins_uninit(); #ifdef HAVE_DBUS purple_dbus_uninit(); #endif purple_cmds_uninit(); + /* Everything after this cannot try to write things to the confdir */ purple_util_uninit(); purple_signals_uninit();
--- a/libpurple/dbus-analyze-functions.py Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/dbus-analyze-functions.py Tue Jan 27 09:36:35 2009 +0000 @@ -117,7 +117,7 @@ self.params.append(Parameter.fromtokens(paramtexts[i].split(), i)) self.call = "%s(%s)" % (self.function.name, - ", ".join([param.name for param in self.params])) + ", ".join(param.name for param in self.params)) def process(self): @@ -160,6 +160,10 @@ elif type[0].startswith("Purple") or type[0] == "xmlnode": return self.inputpurplestructure(type, name) + # special case for *_get_data functions, be careful here... + elif (type[0] == "size_t") and (name == "len"): + return self.inputgetdata(type, name) + # unknown pointers are always replaced with NULL else: return self.inputpointer(type, name) @@ -196,6 +200,10 @@ if type[0] in ["GList", "GSList"]: return self.outputlist(type, name) + # Special case for *_get_data functions + if type[0] == "gconstpointer": + return self.outputgetdata(type, name) + raise myexception @@ -309,7 +317,13 @@ self.returncode.append("return garray_int_to_%s(%s);" % (type[0].lower(), name)); - + # Special case for *_get_data functions, don't need client bindings, + # but do need the name so it doesn't crash + def inputgetdata(self, type, name): + raise myexception + def outputgetdata(self, type, name): + raise myexception + class ServerBinding (Binding): def __init__(self, functiontext, paramtexts): Binding.__init__(self, functiontext, paramtexts) @@ -475,6 +489,21 @@ % (name, name)) self.addouttype("ai", name) + # Special case for *_get_data functions + def inputgetdata(self, type, name): + self.cdecls.append("\tsize_t %s = 0;" % name) + return True + def outputgetdata(self, type, name): + # This is a total hack, but self.call is set up before the parameters + # are processed, so we can't tell it to pass a parameter by reference. + self.call = "%s(%s)" % (self.function.name, + ", ".join(param.name if param.name != "len" else "&len" for param in self.params)) + + self.cdecls.append("\tgconstpointer %s;" % name) + self.ccode.append("\t%s = %s;" % (name, self.call)) + self.cparamsout.append("DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &%s, %s" \ + % (name, "len")) + self.addouttype("ay", name) class BindingSet: regexp = r"^(\w[^()]*)\(([^()]*)\)\s*;\s*$";
--- a/libpurple/prefs.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/prefs.c Tue Jan 27 09:36:35 2009 +0000 @@ -693,12 +693,15 @@ char *name; GSList *l; - if(!pref || pref == &prefs) + if(!pref) return; while(pref->first_child) remove_pref(pref->first_child); + if(pref == &prefs) + return; + if(pref->parent->first_child == pref) { pref->parent->first_child = pref->sibling; } else { @@ -711,7 +714,8 @@ name = pref_full_name(pref); - purple_debug_info("prefs", "removing pref %s\n", name); + if (prefs_loaded) + purple_debug_info("prefs", "removing pref %s\n", name); g_hash_table_remove(prefs_hash, name); g_free(name); @@ -1451,6 +1455,9 @@ sync_prefs(); } + prefs_loaded = FALSE; + purple_prefs_destroy(); + g_hash_table_destroy(prefs_hash); + prefs_hash = NULL; - prefs_loaded = FALSE; }
--- a/libpurple/protocols/jabber/auth.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/jabber/auth.c Tue Jan 27 09:36:35 2009 +0000 @@ -749,8 +749,8 @@ val_end = cur; while (val_end != val_start && (*val_end == ' ' || *val_end == ',' || *val_end == '\t' - || *val_end == '\r' || *val_start == '\n' - || *val_end == '"')) + || *val_end == '\r' || *val_end == '\n' + || *val_end == '"' || *val_end == '\0')) val_end--; if (val_start != val_end)
--- a/libpurple/protocols/jabber/buddy.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Tue Jan 27 09:36:35 2009 +0000 @@ -2518,7 +2518,7 @@ JabberBuddyResource *jbr = jabber_buddy_find_resource((JabberBuddy*)jb, NULL); if (!jbr) { - purple_debug_error("jabber", + purple_debug_info("jabber", "Unable to find caps: buddy might be offline\n"); return FALSE; }
--- a/libpurple/protocols/msn/cmdproc.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Tue Jan 27 09:36:35 2009 +0000 @@ -35,6 +35,9 @@ cmdproc->txqueue = g_queue_new(); cmdproc->history = msn_history_new(); + cmdproc->multiparts = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, (GDestroyNotify)msn_message_unref); + return cmdproc; } @@ -53,6 +56,8 @@ if (cmdproc->last_cmd != NULL) msn_command_destroy(cmdproc->last_cmd); + g_hash_table_destroy(cmdproc->multiparts); + g_free(cmdproc); } @@ -235,6 +240,61 @@ msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { MsnMsgTypeCb cb; + const char *messageId = NULL; + + /* Multi-part messages */ + if ((messageId = msn_message_get_attr(msg, "Message-ID")) != NULL) { + const char *chunk_text = msn_message_get_attr(msg, "Chunks"); + guint chunk; + if (chunk_text != NULL) { + chunk = strtol(chunk_text, NULL, 10); + /* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent + some random client causing pidgin to hog a ton of memory. + Probably should figure out the maximum that the official client + actually supports, though. */ + if (chunk > 0 && chunk < 1024) { + msg->total_chunks = chunk; + msg->received_chunks = 1; + g_hash_table_insert(cmdproc->multiparts, (gpointer)messageId, msn_message_ref(msg)); + purple_debug_info("msn", "Received chunked message, messageId: '%s', total chunks: %d\n", + messageId, chunk); + } else { + purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", messageId, chunk); + } + return; + } else { + chunk_text = msn_message_get_attr(msg, "Chunk"); + if (chunk_text != NULL) { + MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, messageId); + chunk = strtol(chunk_text, NULL, 10); + if (first == NULL) { + purple_debug_error("msn", + "Unable to find first chunk of messageId '%s' to correspond with chunk %d.\n", + messageId, chunk+1); + } else if (first->received_chunks == chunk) { + /* Chunk is from 1 to total-1 (doesn't count first one) */ + purple_debug_info("msn", "Received chunk %d of %d, messageId: '%s'\n", + chunk+1, first->total_chunks, messageId); + first->body = g_realloc(first->body, first->body_len + msg->body_len); + memcpy(first->body + first->body_len, msg->body, msg->body_len); + first->body_len += msg->body_len; + first->received_chunks++; + if (first->received_chunks != first->total_chunks) + return; + else + /* We're done! Send it along... The caller takes care of + freeing the old one. */ + msg = first; + } else { + /* TODO: Can you legitimately receive chunks out of order? */ + g_hash_table_remove(cmdproc->multiparts, messageId); + return; + } + } else { + purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", messageId); + } + } + } if (msn_message_get_content_type(msg) == NULL) { @@ -245,15 +305,14 @@ cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, msn_message_get_content_type(msg)); - if (cb == NULL) - { + if (cb != NULL) + cb(cmdproc, msg); + else purple_debug_warning("msn", "Unhandled content-type '%s'\n", msn_message_get_content_type(msg)); - return; - } - - cb(cmdproc, msg); + if (messageId != NULL) + g_hash_table_remove(cmdproc->multiparts, messageId); } void
--- a/libpurple/protocols/msn/cmdproc.h Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/cmdproc.h Tue Jan 27 09:36:35 2009 +0000 @@ -46,6 +46,8 @@ MsnHistory *history; + GHashTable *multiparts; /**< Multi-part message ID's */ + void *data; /**< Extra data, like the switchboard. */ };
--- a/libpurple/protocols/msn/msg.h Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/msg.h Tue Jan 27 09:36:35 2009 +0000 @@ -109,6 +109,8 @@ char *charset; char *body; gsize body_len; + guint total_chunks; /**< How many chunks in this multi-part message */ + guint received_chunks; /**< How many chunks we've received so far */ MsnSlpHeader msnslp_header; MsnSlpFooter msnslp_footer;
--- a/libpurple/protocols/msn/session.h Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/session.h Tue Jan 27 09:36:35 2009 +0000 @@ -123,7 +123,7 @@ } passport_info; GHashTable *soap_table; - int soap_cleanup_handle; + guint soap_cleanup_handle; }; /**
--- a/libpurple/protocols/msn/slpcall.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/slpcall.c Tue Jan 27 09:36:35 2009 +0000 @@ -206,7 +206,7 @@ body = slpmsg->buffer; body_len = slpmsg->size; - if (slpmsg->flags == 0x0) + if (slpmsg->flags == 0x0 || slpmsg->flags == 0x1000000) { char *body_str; @@ -214,7 +214,9 @@ slpcall = msn_slp_sip_recv(slplink, body_str); g_free(body_str); } - else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + else if (slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000020 || + slpmsg->flags == 0x1000030) { slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); @@ -237,6 +239,13 @@ msn_slpcall_session_init(slpcall); } #endif + else if (slpmsg->flags == 0x2) + { + /* Acknowledgement of previous message. Don't do anything currently. */ + } + else + purple_debug_warning("msn", "Unprocessed SLP message with flags 0x%08lx\n", + slpmsg->flags); return slpcall; }
--- a/libpurple/protocols/msn/slplink.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/slplink.c Tue Jan 27 09:36:35 2009 +0000 @@ -281,7 +281,8 @@ g_list_append(slpmsg->msgs, msg); msn_slplink_send_msg(slplink, msg); - if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && + if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 || + slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL)) { slpmsg->slpcall->progress = TRUE; @@ -316,7 +317,8 @@ else { /* The whole message has been sent */ - if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + if (slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) { if (slpmsg->slpcall != NULL) { @@ -362,7 +364,8 @@ msg->msnslp_header.ack_size = slpmsg->ack_size; msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; } - else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + else if (slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) { MsnSlpCall *slpcall; slpcall = slpmsg->slpcall; @@ -532,7 +535,8 @@ if (slpmsg->slpcall != NULL) { - if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + if (slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) { PurpleXfer *xfer; @@ -595,7 +599,8 @@ memcpy(slpmsg->buffer + offset, data, len); } - if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && + if ((slpmsg->flags == 0x20 || + slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL)) { slpmsg->slpcall->progress = TRUE; @@ -630,8 +635,9 @@ msn_directconn_send_handshake(directconn); #endif } - else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 || - slpmsg->flags == 0x1000030) + else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 || + slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 || + slpmsg->flags == 0x1000030) { /* Release all the messages and send the ACK */
--- a/libpurple/protocols/msn/switchboard.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/protocols/msn/switchboard.c Tue Jan 27 09:36:35 2009 +0000 @@ -799,7 +799,7 @@ msn_cmdproc_process_msg(cmdproc, msg); - msn_message_destroy(msg); + msn_message_unref(msg); } static void
--- a/libpurple/purple-url-handler Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/purple-url-handler Tue Jan 27 09:36:35 2009 +0000 @@ -207,7 +207,11 @@ def correct_server(account): username = cpurple.PurpleAccountGetUsername(account) - return (server == (username.split("@"))[1]) + user_split = (username.split("@")) + # Not all accounts have a split, so append an empty string so the + # [1] doesn't throw an IndexError. + user_split.append("") + return (server == user_split[1]) account = findaccount(protocol, matcher=correct_server)
--- a/libpurple/status.c Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/status.c Tue Jan 27 09:36:35 2009 +0000 @@ -250,7 +250,7 @@ { g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL); - return purple_status_type_new_full(primitive, id, name, FALSE, + return purple_status_type_new_full(primitive, id, name, TRUE, user_settable, FALSE); } @@ -816,28 +816,42 @@ /* Reset any unspecified attributes to their default value */ status_type = purple_status_get_type(status); l = purple_status_type_get_attrs(status_type); - while (l != NULL) - { + while (l != NULL) { PurpleStatusAttr *attr; attr = l->data; - if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) - { + l = l->next; + + if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) { PurpleValue *default_value; default_value = purple_status_attr_get_value(attr); - if (default_value->type == PURPLE_TYPE_STRING) - purple_status_set_attr_string(status, attr->id, - purple_value_get_string(default_value)); - else if (default_value->type == PURPLE_TYPE_INT) - purple_status_set_attr_int(status, attr->id, - purple_value_get_int(default_value)); - else if (default_value->type == PURPLE_TYPE_BOOLEAN) - purple_status_set_attr_boolean(status, attr->id, - purple_value_get_boolean(default_value)); + if (default_value->type == PURPLE_TYPE_STRING) { + const char *cur = purple_status_get_attr_string(status, attr->id); + const char *def = purple_value_get_string(default_value); + if ((cur == NULL && def == NULL) + || (cur != NULL && def != NULL + && !strcmp(cur, def))) { + continue; + } + + purple_status_set_attr_string(status, attr->id, def); + } else if (default_value->type == PURPLE_TYPE_INT) { + int cur = purple_status_get_attr_int(status, attr->id); + int def = purple_value_get_int(default_value); + if (cur == def) + continue; + + purple_status_set_attr_int(status, attr->id, def); + } else if (default_value->type == PURPLE_TYPE_BOOLEAN) { + gboolean cur = purple_status_get_attr_boolean(status, attr->id); + gboolean def = purple_value_get_boolean(default_value); + if (cur == def) + continue; + + purple_status_set_attr_boolean(status, attr->id, def); + } changed = TRUE; } - - l = l->next; } g_list_free(specified_attr_ids);
--- a/libpurple/status.h Mon Jan 19 18:44:31 2009 +0000 +++ b/libpurple/status.h Tue Jan 27 09:36:35 2009 +0000 @@ -199,8 +199,8 @@ gboolean independent); /** - * Creates a new status type with some default values (not - * savable and not independent). + * Creates a new status type with some default values ( + * saveable and not independent). * * @param primitive The primitive status type. * @param id The ID of the status type, or @c NULL to use the id of
--- a/pidgin/gtkaccount.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkaccount.c Tue Jan 27 09:36:35 2009 +0000 @@ -84,6 +84,13 @@ typedef struct { + GtkWidget *widget; + gchar *setting; + PurplePrefType type; +} ProtocolOptEntry; + +typedef struct +{ PidginAccountDialogType type; PurpleAccount *account; @@ -548,8 +555,10 @@ /* Password */ dialog->password_entry = gtk_entry_new(); gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->password_entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ dialog->password_box = add_pref_box(dialog, vbox, _("_Password:"), dialog->password_entry); @@ -740,21 +749,22 @@ char *title, *tmp; const char *str_value; gboolean bool_value; + ProtocolOptEntry *opt_entry; if (dialog->protocol_frame != NULL) { gtk_widget_destroy(dialog->protocol_frame); dialog->protocol_frame = NULL; } - if (dialog->protocol_opt_entries != NULL) { - g_list_free(dialog->protocol_opt_entries); - dialog->protocol_opt_entries = NULL; - } - if (dialog->prpl_info == NULL || - dialog->prpl_info->protocol_options == NULL) { - + dialog->prpl_info->protocol_options == NULL) return; + + while (dialog->protocol_opt_entries != NULL) { + ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data; + g_free(opt_entry->setting); + g_free(opt_entry); + dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries); } account = dialog->account; @@ -778,7 +788,11 @@ { option = (PurpleAccountOption *)l->data; - switch (purple_account_option_get_type(option)) + opt_entry = g_new0(ProtocolOptEntry, 1); + opt_entry->type = purple_account_option_get_type(option); + opt_entry->setting = g_strdup(purple_account_option_get_setting(option)); + + switch (opt_entry->type) { case PURPLE_PREF_BOOLEAN: if (account == NULL || @@ -795,7 +809,7 @@ } tmp = g_strconcat("_", purple_account_option_get_text(option), NULL); - check = gtk_check_button_new_with_mnemonic(tmp); + opt_entry->widget = check = gtk_check_button_new_with_mnemonic(tmp); g_free(tmp); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), @@ -803,10 +817,6 @@ gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); gtk_widget_show(check); - - dialog->protocol_opt_entries = - g_list_append(dialog->protocol_opt_entries, check); - break; case PURPLE_PREF_INT: @@ -825,19 +835,13 @@ g_snprintf(buf, sizeof(buf), "%d", int_value); - entry = gtk_entry_new(); + opt_entry->widget = entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), buf); title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); - add_pref_box(dialog, vbox, title, entry); - g_free(title); - - dialog->protocol_opt_entries = - g_list_append(dialog->protocol_opt_entries, entry); - break; case PURPLE_PREF_STRING: @@ -854,12 +858,14 @@ purple_account_option_get_default_string(option)); } - entry = gtk_entry_new(); + opt_entry->widget = entry = gtk_entry_new(); if (purple_account_option_get_masked(option)) { gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } if (str_value != NULL) @@ -867,14 +873,8 @@ title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); - add_pref_box(dialog, vbox, title, entry); - g_free(title); - - dialog->protocol_opt_entries = - g_list_append(dialog->protocol_opt_entries, entry); - break; case PURPLE_PREF_STRING_LIST: @@ -896,7 +896,7 @@ list = purple_account_option_get_list(option); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); + opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); /* Loop through list of PurpleKeyValuePair items */ for (node = list; node != NULL; node = node->next) { @@ -928,20 +928,21 @@ title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); - add_pref_box(dialog, vbox, title, combo); - g_free(title); - - dialog->protocol_opt_entries = - g_list_append(dialog->protocol_opt_entries, combo); - break; - default: - break; + purple_debug_error("gtkaccount", "Invalid Account Option pref type (%d)\n", + opt_entry->type); + g_free(opt_entry->setting); + g_free(opt_entry); + continue; } + + dialog->protocol_opt_entries = + g_list_append(dialog->protocol_opt_entries, opt_entry); + } } @@ -1092,8 +1093,10 @@ /* Password */ dialog->proxy_pass_entry = gtk_entry_new(); gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry); if (dialog->account != NULL && @@ -1152,7 +1155,12 @@ gtk_widget_destroy(dialog->window); g_list_free(dialog->user_split_entries); - g_list_free(dialog->protocol_opt_entries); + while (dialog->protocol_opt_entries != NULL) { + ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data; + g_free(opt_entry->setting); + g_free(opt_entry); + dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries); + } g_free(dialog->protocol_id); g_object_unref(dialog->sg); @@ -1317,46 +1325,38 @@ /* Add the protocol settings */ if (dialog->prpl_info) { - for (l = dialog->prpl_info->protocol_options, - l2 = dialog->protocol_opt_entries; - l != NULL && l2 != NULL; - l = l->next, l2 = l2->next) { - - PurplePrefType type; - PurpleAccountOption *option = l->data; - GtkWidget *widget = l2->data; - GtkTreeIter iter; - const char *setting; - char *value2; - int int_value; - gboolean bool_value; - - type = purple_account_option_get_type(option); - - setting = purple_account_option_get_setting(option); - - switch (type) { + ProtocolOptEntry *opt_entry; + GtkTreeIter iter; + char *value2; + int int_value; + gboolean bool_value; + + for (l2 = dialog->protocol_opt_entries; l2; l2 = l2->next) { + + opt_entry = l2->data; + + switch (opt_entry->type) { case PURPLE_PREF_STRING: - value = gtk_entry_get_text(GTK_ENTRY(widget)); - purple_account_set_string(account, setting, value); + value = gtk_entry_get_text(GTK_ENTRY(opt_entry->widget)); + purple_account_set_string(account, opt_entry->setting, value); break; case PURPLE_PREF_INT: - int_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); - purple_account_set_int(account, setting, int_value); + int_value = atoi(gtk_entry_get_text(GTK_ENTRY(opt_entry->widget))); + purple_account_set_int(account, opt_entry->setting, int_value); break; case PURPLE_PREF_BOOLEAN: bool_value = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - purple_account_set_bool(account, setting, bool_value); + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(opt_entry->widget)); + purple_account_set_bool(account, opt_entry->setting, bool_value); break; case PURPLE_PREF_STRING_LIST: value2 = NULL; - if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) - gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value2, -1); - purple_account_set_string(account, setting, value2); + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(opt_entry->widget), &iter)) + gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(opt_entry->widget)), &iter, 1, &value2, -1); + purple_account_set_string(account, opt_entry->setting, value2); break; default:
--- a/pidgin/gtkblist.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkblist.c Tue Jan 27 09:36:35 2009 +0000 @@ -955,8 +955,10 @@ if (pce->secret) { gtk_entry_set_visibility(GTK_ENTRY(input), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL); g_signal_connect(G_OBJECT(input), "changed", @@ -6826,8 +6828,10 @@ if (pce->secret) { gtk_entry_set_visibility(GTK_ENTRY(input), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL); g_signal_connect(G_OBJECT(input), "changed",
--- a/pidgin/gtkgaim-compat.h Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkgaim-compat.h Tue Jan 27 09:36:35 2009 +0000 @@ -297,7 +297,9 @@ #define GAIM_HIG_BORDER PIDGIN_HIG_BORDER #define GAIM_HIG_BOX_SPACE PIDGIN_HIG_BOX_SPACE #define GAIM_HIG_CAT_SPACE PIDGIN_HIG_CAT_SPACE +#if !GTK_CHECK_VERSION(2,16,0) #define GAIM_INVISIBLE_CHAR PIDGIN_INVISIBLE_CHAR +#endif /* Less than GTK+ 2.16 */ #define GAIM_IS_GTK_CONVERSATION PIDGIN_IS_PIDGIN_CONVERSATION #define GAIM_IS_GTK_PLUGIN PIDGIN_IS_PIDGIN_PLUGIN #define gaim_new_check_item pidgin_new_check_item
--- a/pidgin/gtkimhtml.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkimhtml.c Tue Jan 27 09:36:35 2009 +0000 @@ -5378,12 +5378,14 @@ text_tag_data_destroy(tmp); } - if (tmp == NULL) - purple_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); - else { + if (tmp != NULL) { g_string_append(str, tmp->end); text_tag_data_destroy(tmp); } +#if 0 /* This can't be allowed to happen because it causes the iters to be invalidated in the debug window imhtml during text copying */ + else + purple_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); +#endif while ((tmp = g_queue_pop_head(r))) { g_string_append(str, tmp->start);
--- a/pidgin/gtkmain.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkmain.c Tue Jan 27 09:36:35 2009 +0000 @@ -322,9 +322,6 @@ pidgin_session_end(); #endif - /* Save the plugins we have loaded for next time. */ - pidgin_plugins_save(); - /* Uninit */ pidgin_smileys_uninit(); pidgin_conversations_uninit(); @@ -787,8 +784,8 @@ dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); #endif - purple_debug_info("main", "exiting because another libpurple client is already running\n"); purple_core_quit(); + g_printerr(_("Exiting because another libpurple client is already running.\n")); #ifdef HAVE_SIGNAL_H g_free(segfault_message); #endif
--- a/pidgin/gtkpluginpref.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkpluginpref.c Tue Jan 27 09:36:35 2009 +0000 @@ -101,8 +101,10 @@ if (purple_plugin_pref_get_masked(pref)) { gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_cb),
--- a/pidgin/gtkprefs.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkprefs.c Tue Jan 27 09:36:35 2009 +0000 @@ -1412,8 +1412,10 @@ gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 1, 2, GTK_FILL , 0, 0, 0); gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(proxy_print_option), (void *)PROXYPASS);
--- a/pidgin/gtkrequest.c Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/gtkrequest.c Tue Jan 27 09:36:35 2009 +0000 @@ -430,8 +430,10 @@ if (masked) { gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } } gtk_widget_show_all(vbox); @@ -791,8 +793,10 @@ if (purple_request_field_string_is_masked(field)) { gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE); +#if !GTK_CHECK_VERSION(2,16,0) if (gtk_entry_get_invisible_char(GTK_ENTRY(widget)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(widget), PIDGIN_INVISIBLE_CHAR); +#endif /* Less than GTK+ 2.16 */ } gtk_editable_set_editable(GTK_EDITABLE(widget),
--- a/pidgin/pidgin.h Mon Jan 19 18:44:31 2009 +0000 +++ b/pidgin/pidgin.h Tue Jan 27 09:36:35 2009 +0000 @@ -91,11 +91,22 @@ #define PIDGIN_HIG_BORDER 12 #define PIDGIN_HIG_BOX_SPACE 6 +#if !GTK_CHECK_VERSION(2,16,0) || !defined(PIDGIN_DISABLE_DEPRECATED) /* - * See GNOME bug #307304 for some discussion about the invisible - * character. 0x25cf is a good choice, too. + * Older versions of GNOME defaulted to using an asterisk as the invisible + * character. But this is ugly and we want to use something nicer. + * + * The default invisible character was changed in GNOME revision 21446 + * (GTK+ 2.16) from an asterisk to the first available character out of + * 0x25cf, 0x2022, 0x2731, 0x273a. See GNOME bugs 83935 and 307304 for + * discussion leading up to the change. + * + * Here's the change: + * http://svn.gnome.org/viewvc/gtk%2B?view=revision&revision=21446 + * */ -#define PIDGIN_INVISIBLE_CHAR (gunichar)0x2022 +#define PIDGIN_INVISIBLE_CHAR (gunichar)0x25cf +#endif /* Less than GTK+ 2.16 */ #endif /* _PIDGIN_H_ */
--- a/po/fi.po Mon Jan 19 18:44:31 2009 +0000 +++ b/po/fi.po Tue Jan 27 09:36:35 2009 +0000 @@ -11,7 +11,7 @@ "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-01-07 13:30+0200\n" -"PO-Revision-Date: 2009-01-07 13:30+0200\n" +"PO-Revision-Date: 2009-01-23 19:58+0200\n" "Last-Translator: Timo Jyrinki <timo.jyrinki@iki.fi>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -1169,7 +1169,7 @@ msgstr "Keskustelut" msgid "Logging" -msgstr "Kirjataan lokiin" +msgstr "Lokiinkirjaus" msgid "You must fill all the required fields." msgstr "T辰yt辰 kaikki vaaditut kent辰t." @@ -15466,7 +15466,7 @@ #~ "keskustelun uuden keskustelun aluksi.\n" #~ "\n" #~ "Historia-liit辰nn辰inen vaatii lokiinkirjauksen k辰ytt旦辰. Loki voidaan ottaa " -#~ "k辰ytt旦旦n menem辰ll辰 Ty旦kalut -> Asetukset -> Kirjataan lokiin. Lokien " +#~ "k辰ytt旦旦n menem辰ll辰 Ty旦kalut -> Asetukset -> Lokiinkirjaus. Lokien " #~ "k辰ytt旦旦notto pikaviesteille ja/tai ryhm辰keskusteluille ottaa k辰ytt旦旦n " #~ "historiatoiminnon vastaaville keskustelutyypeille."
--- a/po/l10n.xsl Mon Jan 19 18:44:31 2009 +0000 +++ b/po/l10n.xsl Tue Jan 27 09:36:35 2009 +0000 @@ -1,22 +1,47 @@ <?xml version='1.0' ?> <xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> + <xsl:output + method="html" + omit-xml-declaration="yes" + doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" + doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" + indent="yes" + /> <xsl:template match='/project'> - <html> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title><xsl:value-of select='@name'/> translation statistics</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <!-- <link rel="Stylesheet" href="/gaim.css" type="text/css" media="screen" /> --> - <style> + <style type="text/css"> .bargraph { width: 200px; height: 20px; - background: black; + background-color: red; border-collapse: collapse; border-spacing: 0px; margin: 0px; border: 0px; padding: 0px; } - + .translated { + background-color: green; + padding: 0px; + } + .fuzzy { + background-color: blue; + padding: 0px; + } + .untranslated { + background-color: red; + padding: 0px; + } + td.sep { + padding-right: 10px; + } + th { + text-align: left; + } </style> </head> <body> @@ -28,21 +53,23 @@ <xsl:sort select='@code' /> <tr> <td><a><xsl:attribute name='href'><xsl:value-of select='@code'/>.po</xsl:attribute><xsl:value-of select='@name'/> (<xsl:value-of select='@code'/>)</a></td> - <td><xsl:value-of select='@translated'/></td><td><xsl:value-of select="format-number(@translated div ../@strings * 100,'#.##')"/> %</td> - <td><xsl:value-of select='@fuzzy'/></td><td><xsl:value-of select="format-number(@fuzzy div ../@strings * 100,'#.##')"/> %</td> - <td><xsl:value-of select='../@strings - (@translated + @fuzzy)'/></td><td><xsl:value-of select="format-number((../@strings - (@translated + @fuzzy)) div ../@strings * 100,'#.##')"/> %</td> + <td><xsl:value-of select='@translated'/></td> + <td class='sep'><xsl:value-of select="format-number(@translated div ../@strings * 100,'#.##')"/> %</td> + <td><xsl:value-of select='@fuzzy'/></td> + <td class='sep'><xsl:value-of select="format-number(@fuzzy div ../@strings * 100,'#.##')"/> %</td> + <td><xsl:value-of select='../@strings - (@translated + @fuzzy)'/></td> + <td><xsl:value-of select="format-number((../@strings - (@translated + @fuzzy)) div ../@strings * 100,'#.##')"/> %</td> <td> <table class='bargraph'><tr> - <td bgcolor='green'><xsl:attribute name='width'><xsl:value-of select='round(@translated div ../@strings * 200)'/>px;</xsl:attribute></td> - <td bgcolor='blue'><xsl:attribute name='width'><xsl:value-of select='round(@fuzzy div ../@strings * 200)'/>px;</xsl:attribute></td> - <!-- <td bgcolor='red'><xsl:attribute name='width'><xsl:value-of select='200 - round((@translated + @fuzzy) div ../@strings * 200)'/>px;</xsl:attribute></td> --> - <td bgcolor='red'></td> + <td class="translated"><xsl:attribute name='style'>width:<xsl:value-of select='round(@translated div ../@strings * 200)'/>px;</xsl:attribute></td> + <td class="fuzzy"><xsl:attribute name='style'>width:<xsl:value-of select='round(@fuzzy div ../@strings * 200)'/>px;</xsl:attribute></td> + <td class="untranslated"><xsl:attribute name='style'>width:<xsl:value-of select='round((../@strings - @translated - @fuzzy) div ../@strings * 200)'/>px;</xsl:attribute></td> </tr></table> </td> </tr> </xsl:for-each> </table> - <a><xsl:attribute name='href'><xsl:value-of select='@pofile'/></xsl:attribute><xsl:value-of select='@pofile'/></a> generated on <xsl:value-of select='@generated'/> + <p><a><xsl:attribute name='href'><xsl:value-of select='@pofile'/></xsl:attribute><xsl:value-of select='@pofile'/></a> generated on <xsl:value-of select='@generated'/></p> <!-- </div> --> </body> </html>