[gwibber/f13/master] update to 867bzr, add gowalla support, fix pango_overlay crash, fix undefined mark, treat all string
Tom Callaway
spot at fedoraproject.org
Sat Sep 25 15:15:02 UTC 2010
commit 4bf07b9a62d368c9e601b4a3ca682fde39706603
Author: Tom "spot" Callaway <tcallawa at redhat.com>
Date: Sat Sep 25 11:14:52 2010 -0400
update to 867bzr, add gowalla support, fix pango_overlay crash, fix undefined mark, treat all strings as unicode, fix bug on character choke, fix extraneous deps, add autoreplace support
gwibber-867bzr-gowalla-icons.patch | Bin 0 -> 7909 bytes
gwibber-867bzr-gowalla.patch | 432 +++++++++++++
gwibber-867bzr-handle-x00-in-content.patch | 14 +
gwibber-867bzr-kitchen-utf8.patch | 927 ++++++++++++++++++++++++++++
gwibber-867bzr-minimize-chars.patch | 111 ++++
gwibber-867bzr-missing-mark.patch | 12 +
gwibber.spec | 82 ++-
sources | 2 +-
8 files changed, 1565 insertions(+), 15 deletions(-)
---
diff --git a/gwibber-867bzr-gowalla-icons.patch b/gwibber-867bzr-gowalla-icons.patch
new file mode 100644
index 0000000..a03b302
Binary files /dev/null and b/gwibber-867bzr-gowalla-icons.patch differ
diff --git a/gwibber-867bzr-gowalla.patch b/gwibber-867bzr-gowalla.patch
new file mode 100644
index 0000000..978dbae
--- /dev/null
+++ b/gwibber-867bzr-gowalla.patch
@@ -0,0 +1,432 @@
+diff -up gwibber-867bzr/gwibber/lib/gtk/gowalla.py.NEW gwibber-867bzr/gwibber/lib/gtk/gowalla.py
+--- gwibber-867bzr/gwibber/lib/gtk/gowalla.py.NEW 2010-09-23 13:17:52.955184949 -0400
++++ gwibber-867bzr/gwibber/lib/gtk/gowalla.py 2010-09-23 13:22:37.900184989 -0400
+@@ -0,0 +1,44 @@
++#
++# Gowalla support for Gwibber
++#
++# Derived from Foursquare support (foursquare.py)
++#
++# Copyright 2010, Tom "spot" Callaway <tcallawa at redhat.com>
++#
++# Permission to use, copy, modify, and distribute this software and its
++# documentation for any purpose and without fee is hereby granted,
++# provided that the above copyright notice appear in all copies and that
++# both that copyright notice and this permission notice appear in
++# supporting documentation.
++#
++# THE AUTHOR PROVIDES THIS SOFTWARE ''AS IS'' AND ANY EXPRESSED OR
++# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++import gtk
++from gtk import Builder
++import gwibber.microblog
++
++class AccountWidget(gtk.VBox):
++ """AccountWidget: A widget that provides a user interface for configuring Gowalla accounts in Gwibber
++ """
++
++ def __init__(self, account=None, dialog=None):
++ """Creates the account pane for configuring Gowalla accounts"""
++ gtk.VBox.__init__( self, False, 20 )
++ self.ui = gtk.Builder()
++ self.ui.set_translation_domain ("gwibber")
++ self.ui.add_from_file (gwibber.resources.get_ui_asset("gwibber-accounts-gowalla.ui"))
++ self.ui.connect_signals(self)
++ self.vbox_settings = self.ui.get_object("vbox_settings")
++ self.pack_start(self.vbox_settings, False, False)
++ self.show_all()
++ if dialog:
++ dialog.get_object("vbox_create").show()
+diff -up gwibber-867bzr/gwibber/lib/gtk/__init__.py.NEW gwibber-867bzr/gwibber/lib/gtk/__init__.py
+--- gwibber-867bzr/gwibber/lib/gtk/__init__.py.NEW 2010-09-23 13:17:15.513185001 -0400
++++ gwibber-867bzr/gwibber/lib/gtk/__init__.py 2010-09-23 13:17:28.901184999 -0400
+@@ -1 +1 @@
+-__all__ = ["twitter", "identica", "flickr", "facebook", "friendfeed", "statusnet", "digg", "qaiku", "buzz", "pingfm", "foursquare"]
++__all__ = ["twitter", "identica", "flickr", "facebook", "friendfeed", "statusnet", "digg", "qaiku", "buzz", "pingfm", "foursquare", "gowalla"]
+diff -up gwibber-867bzr/gwibber/microblog/dispatcher.py.NEW gwibber-867bzr/gwibber/microblog/dispatcher.py
+--- gwibber-867bzr/gwibber/microblog/dispatcher.py.NEW 2010-09-23 13:22:43.941184999 -0400
++++ gwibber-867bzr/gwibber/microblog/dispatcher.py 2010-09-23 13:23:04.068184978 -0400
+@@ -4,7 +4,7 @@ import multiprocessing, threading, trace
+ import gobject, dbus, dbus.service
+ import twitter, identica, statusnet, flickr, facebook
+ import qaiku, friendfeed, digg, buzz, pingfm
+-import foursquare
++import foursquare, gowalla
+ import sqlite3, mx.DateTime, re, uuid
+ import urlshorter, storage, network, util, config
+
+@@ -42,6 +42,7 @@ PROTOCOLS = {
+ "buzz": buzz,
+ "pingfm": pingfm,
+ "foursquare": foursquare,
++ "gowalla": gowalla,
+ }
+
+ FEATURES = json.loads(GWIBBER_OPERATIONS)
+diff -up gwibber-867bzr/gwibber/microblog/gowalla.py.NEW gwibber-867bzr/gwibber/microblog/gowalla.py
+--- gwibber-867bzr/gwibber/microblog/gowalla.py.NEW 2010-09-23 09:44:48.714185000 -0400
++++ gwibber-867bzr/gwibber/microblog/gowalla.py 2010-09-23 13:16:46.095185001 -0400
+@@ -0,0 +1,123 @@
++#
++# Gowalla support for Gwibber
++#
++# Derived from Foursquare support (foursquare.py)
++#
++# Copyright 2010, Tom "spot" Callaway <tcallawa at redhat.com>
++#
++# Permission to use, copy, modify, and distribute this software and its
++# documentation for any purpose and without fee is hereby granted,
++# provided that the above copyright notice appear in all copies and that
++# both that copyright notice and this permission notice appear in
++# supporting documentation.
++#
++# THE AUTHOR PROVIDES THIS SOFTWARE ''AS IS'' AND ANY EXPRESSED OR
++# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++import network, json, util, htmllib, re
++from util import log
++from util import exceptions
++from gettext import lgettext as _
++log.logger.name = "Gowalla"
++
++PROTOCOL_INFO = {
++ "name": "Gowalla",
++ "version": "1.0",
++
++ "config": [
++ "private:password",
++ "receive_enabled",
++ "username",
++ "color",
++ ],
++
++ "authtype": "none",
++ "color": "#f7911f",
++
++ "features": [
++ "receive",
++ ],
++
++ "default_streams": [
++ "receive",
++ ],
++}
++
++URL_PREFIX = "https://api.gowalla.com"
++
++class Client:
++ def __init__(self, acct):
++ self.account = acct
++
++ def _message(self, data):
++
++ m = {};
++ m["mid"] = str(data["user"]["first_name"]) + str(data["user"]["last_name"])
++ m["service"] = "gowalla"
++ m["account"] = self.account["id"]
++ m["time"] = util.parsetime(data["created_at"])
++
++ messagetext = ""
++ text = ""
++ if data.has_key("spot"):
++ if data.has_key("message"):
++ messagetext += data["message"] + "<br/><br/>"
++ text += data["message"] + "\n"
++ m["url"] = "<a href='http://gowalla.com%s'>" % data["spot"]["url"]
++ m["url"] = "http://gowalla.com%s" % data["spot"]["url"]
++ img = "<table><tr><td><img src='%s'/></td><td>" % data["spot"]["image_url"]
++ messagetext += img + "Checked in at <a href='" + m["url"] + "'>" + data["spot"]["name"] + "</a>"
++ text += "Checked in at " + data["spot"]["name"]
++ else:
++ if data.has_key("message"):
++ messagetext += data["message"] + "<br/><br/>"
++ text += data["message"] + "\n"
++ else:
++ text= "Checked in off the grid"
++ shouttext= "<table><tr><td><img src='http://gowalla.com/favicon.ico'/></td><td>Checked in off the grid"
++
++ m["text"] = text
++ m["content"] = messagetext + "</td></tr></table>"
++ m["html"] = messagetext + "</td></tr></table>"
++
++ m["sender"] = {}
++ m["sender"]["image"] = data["user"]["image_url"]
++ m["sender"]["url"] = "http://gowalla.com%s" % data["user"]["url"]
++ fullname = ""
++ if data["user"].has_key("first_name"):
++ fullname += data["user"]["first_name"] + " "
++ if data["user"].has_key("last_name"):
++ fullname += data["user"]["last_name"]
++
++ m["sender"]["name"] = fullname
++ m["sender"]["nick"] = fullname
++
++ m["source"] = "<a href='http://gowalla.com/'>Gowalla</a>"
++
++ return m
++
++ def _get(self, path, parse="message", post=False, single=False, **args):
++ url = "/".join((URL_PREFIX, path))
++
++ data = network.Download(url, util.compact(args) or None, post,
++ self.account["username"], self.account["password"]).get_json()
++
++ checkins = data["activity"]
++ if single: return [getattr(self, "_%s" % parse)(checkins)]
++ if parse: return [getattr(self, "_%s" % parse)(m) for m in checkins]
++ else: return []
++
++ def __call__(self, opname, **args):
++ return getattr(self, opname)(**args)
++
++ def receive(self):
++ return self._get("users/%s/activity/friends" % self.account["username"])
++
+diff -up gwibber-867bzr/ui/gwibber-accounts-gowalla.ui.NEW gwibber-867bzr/ui/gwibber-accounts-gowalla.ui
+--- gwibber-867bzr/ui/gwibber-accounts-gowalla.ui.NEW 2010-09-23 13:23:40.381184999 -0400
++++ gwibber-867bzr/ui/gwibber-accounts-gowalla.ui 2010-09-23 13:23:32.281184974 -0400
+@@ -0,0 +1,219 @@
++<?xml version="1.0"?>
++<interface>
++ <requires lib="gtk+" version="2.16"/>
++ <!-- interface-naming-policy toplevel-contextual -->
++ <object class="GtkVBox" id="vbox_settings">
++ <property name="visible">True</property>
++ <property name="orientation">vertical</property>
++ <property name="spacing">6</property>
++ <child>
++ <object class="GtkTable" id="table_common_settings">
++ <property name="visible">True</property>
++ <property name="n_rows">3</property>
++ <property name="n_columns">3</property>
++ <property name="column_spacing">12</property>
++ <property name="row_spacing">6</property>
++ <child>
++ <object class="GtkEntry" id="password">
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <property name="visibility">False</property>
++ <property name="invisible_char">●</property>
++ </object>
++ <packing>
++ <property name="left_attach">1</property>
++ <property name="right_attach">3</property>
++ <property name="top_attach">2</property>
++ <property name="bottom_attach">3</property>
++ <property name="y_options"></property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkEntry" id="username">
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <property name="invisible_char">●</property>
++ </object>
++ <packing>
++ <property name="left_attach">1</property>
++ <property name="right_attach">3</property>
++ <property name="y_options"></property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkLabel" id="label_username">
++ <property name="visible">True</property>
++ <property name="xalign">0</property>
++ <property name="label" translatable="yes">Login I_D:</property>
++ <property name="use_underline">True</property>
++ <property name="mnemonic_widget">username</property>
++ </object>
++ <packing>
++ <property name="x_options">GTK_FILL</property>
++ <property name="y_options"></property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkLabel" id="label_password">
++ <property name="visible">True</property>
++ <property name="xalign">0</property>
++ <property name="label" translatable="yes">Pass_word:</property>
++ <property name="use_underline">True</property>
++ <property name="justify">right</property>
++ <property name="mnemonic_widget">password</property>
++ </object>
++ <packing>
++ <property name="top_attach">2</property>
++ <property name="bottom_attach">3</property>
++ <property name="x_options">GTK_FILL</property>
++ <property name="y_options"></property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkVBox" id="vbox1">
++ <property name="visible">True</property>
++ <property name="orientation">vertical</property>
++ <child>
++ <object class="GtkLabel" id="label_username_example">
++ <property name="visible">True</property>
++ <property name="xalign">0</property>
++ <property name="xpad">3</property>
++ <property name="label" translatable="yes"><span size="small"><b>Example:</b> username at email.com</span></property>
++ <property name="use_markup">True</property>
++ </object>
++ <packing>
++ <property name="position">0</property>
++ </packing>
++ </child>
++ </object>
++ <packing>
++ <property name="left_attach">1</property>
++ <property name="right_attach">2</property>
++ <property name="top_attach">1</property>
++ <property name="bottom_attach">2</property>
++ </packing>
++ </child>
++ <child>
++ <placeholder/>
++ </child>
++ <child>
++ <placeholder/>
++ </child>
++ </object>
++ <packing>
++ <property name="expand">False</property>
++ <property name="fill">False</property>
++ <property name="position">0</property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkExpander" id="expander1">
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <child>
++ <object class="GtkVBox" id="vbox_advanced">
++ <property name="visible">True</property>
++ <property name="orientation">vertical</property>
++ <property name="spacing">6</property>
++ <child>
++ <object class="GtkLabel" id="label3">
++ <property name="visible">True</property>
++ <property name="label" translatable="yes">Account Status</property>
++ <attributes>
++ <attribute name="weight" value="bold"/>
++ </attributes>
++ </object>
++ <packing>
++ <property name="position">0</property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkTable" id="table_advanced_settings">
++ <property name="visible">True</property>
++ <property name="n_rows">2</property>
++ <property name="n_columns">3</property>
++ <property name="column_spacing">12</property>
++ <property name="row_spacing">6</property>
++ <child>
++ <object class="GtkCheckButton" id="receive_enabled">
++ <property name="label" translatable="yes">_Receive Messages</property>
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <property name="receives_default">False</property>
++ <property name="use_underline">True</property>
++ <property name="active">True</property>
++ <property name="draw_indicator">True</property>
++ </object>
++ <packing>
++ <property name="right_attach">3</property>
++ <property name="x_options">GTK_FILL</property>
++ <property name="y_options"></property>
++ </packing>
++ </child>
++ </object>
++ <packing>
++ <property name="position">1</property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkLabel" id="label2">
++ <property name="visible">True</property>
++ <property name="label" translatable="yes">Appearance</property>
++ <attributes>
++ <attribute name="weight" value="bold"/>
++ </attributes>
++ </object>
++ <packing>
++ <property name="position">2</property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkHBox" id="hbox1">
++ <property name="visible">True</property>
++ <property name="homogeneous">True</property>
++ <child>
++ <object class="GtkLabel" id="label4">
++ <property name="visible">True</property>
++ <property name="label" translatable="yes">Message Color:</property>
++ </object>
++ <packing>
++ <property name="position">0</property>
++ </packing>
++ </child>
++ <child>
++ <object class="GtkColorButton" id="color">
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <property name="receives_default">True</property>
++ <property name="color">#000000000000</property>
++ </object>
++ <packing>
++ <property name="expand">False</property>
++ <property name="position">1</property>
++ </packing>
++ </child>
++ </object>
++ <packing>
++ <property name="position">3</property>
++ </packing>
++ </child>
++ </object>
++ </child>
++ <child type="label">
++ <object class="GtkLabel" id="label1">
++ <property name="visible">True</property>
++ <property name="label" translatable="yes">Advanced</property>
++ <attributes>
++ <attribute name="weight" value="bold"/>
++ </attributes>
++ </object>
++ </child>
++ </object>
++ <packing>
++ <property name="expand">False</property>
++ <property name="fill">False</property>
++ <property name="position">1</property>
++ </packing>
++ </child>
++ </object>
++</interface>
+diff -up gwibber-867bzr/ui/icons/breakdance/16x16/gowalla.png.NEW gwibber-867bzr/ui/icons/breakdance/16x16/gowalla.png
+Binary files gwibber-867bzr/ui/icons/breakdance/16x16/gowalla.png.NEW and gwibber-867bzr/ui/icons/breakdance/16x16/gowalla.png differ
+diff -up gwibber-867bzr/ui/icons/breakdance/22x22/gowalla.png.NEW gwibber-867bzr/ui/icons/breakdance/22x22/gowalla.png
+Binary files gwibber-867bzr/ui/icons/breakdance/22x22/gowalla.png.NEW and gwibber-867bzr/ui/icons/breakdance/22x22/gowalla.png differ
+diff -up gwibber-867bzr/ui/icons/breakdance/32x32/gowalla.png.NEW gwibber-867bzr/ui/icons/breakdance/32x32/gowalla.png
+Binary files gwibber-867bzr/ui/icons/breakdance/32x32/gowalla.png.NEW and gwibber-867bzr/ui/icons/breakdance/32x32/gowalla.png differ
+diff -up gwibber-867bzr/ui/icons/breakdance/scalable/gowalla.png.NEW gwibber-867bzr/ui/icons/breakdance/scalable/gowalla.png
+Binary files gwibber-867bzr/ui/icons/breakdance/scalable/gowalla.png.NEW and gwibber-867bzr/ui/icons/breakdance/scalable/gowalla.png differ
diff --git a/gwibber-867bzr-handle-x00-in-content.patch b/gwibber-867bzr-handle-x00-in-content.patch
new file mode 100644
index 0000000..ac7305e
--- /dev/null
+++ b/gwibber-867bzr-handle-x00-in-content.patch
@@ -0,0 +1,14 @@
+diff -up gwibber-867bzr/gwibber/gwui.py.BAD gwibber-867bzr/gwibber/gwui.py
+--- gwibber-867bzr/gwibber/gwui.py.BAD 2010-09-24 14:01:18.721249996 -0400
++++ gwibber-867bzr/gwibber/gwui.py 2010-09-24 14:05:27.224250053 -0400
+@@ -255,6 +255,10 @@ class WebUi(webkit.WebView):
+ template = Template(template, lookup=TemplateLookup(directories=lookup_paths))
+ content = template.render(theme=util.get_theme_colors(), resources=resources, _=_, **kwargs)
+
++ # Content occasionally ends up with nulls (\x00) which causes a traceback
++ # This works around it by replacing \x00 with a space whenever it is found.
++ content = content.replace('\x00', ' ')
++
+ # Avoid navigation redraw crashes
+ if isinstance(self, Navigation) and not self.get_property("visible"):
+ return content
diff --git a/gwibber-867bzr-kitchen-utf8.patch b/gwibber-867bzr-kitchen-utf8.patch
new file mode 100644
index 0000000..4bb5973
--- /dev/null
+++ b/gwibber-867bzr-kitchen-utf8.patch
@@ -0,0 +1,927 @@
+diff -up gwibber-867bzr/gwibber/microblog/brightkite.py.kitchen gwibber-867bzr/gwibber/microblog/brightkite.py
+--- gwibber-867bzr/gwibber/microblog/brightkite.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/brightkite.py 2010-09-25 10:35:44.285191001 -0400
+@@ -8,6 +8,7 @@ SegPhault (Ryan Paul) - 10/19/2008
+ from . import support
+ import urllib2, urllib, base64, re, simplejson
+ from xml.dom import minidom
++from kitchen.text.converters import to_unicode
+
+ PROTOCOL_INFO = {
+ "name": "BrightKite",
+@@ -34,62 +35,62 @@ class Message:
+ def __init__(self, client, data):
+ self.client = client
+ self.account = client.account
+- self.service = client.account["service"]
+- self.username = client.account["username"]
++ self.service = to_unicode(client.account["service"])
++ self.username = to_unicode(client.account["username"])
+
+- self.sender = data["creator"]["fullname"]
+- self.sender_nick = data["creator"]["login"]
+- self.sender_id = data["creator"]["login"]
+- self.image = data["creator"]["small_avatar_url"]
++ self.sender = to_unicode(data["creator"]["fullname"])
++ self.sender_nick = to_unicode(data["creator"]["login"])
++ self.sender_id = to_unicode(data["creator"]["login"])
++ self.image = to_unicode(data["creator"]["small_avatar_url"])
+
+ self.time = support.parse_time(data["created_at"])
+- self.text = data["body"] or ""
+- self.bgcolor = "message_color"
+- self.id = data["id"]
++ self.text = to_unicode(data["body"]) or u""
++ self.bgcolor = u"message_color"
++ self.id = to_unicode(data["id"])
+
+- self.url = "http://brightkite.com/objects/%s" % data["id"]
+- self.profile_url = "http://brightkite.com/people/%s" % self.sender_nick
++ self.url = to_unicode("http://brightkite.com/objects/%s" % data["id"])
++ self.profile_url = to_unicode("http://brightkite.com/people/%s" % self.sender_nick)
+
+- self.html_string = '<span class="text">%s</span>' % \
++ self.html_string = to_unicode('<span class="text">%s</span>' % \
+ NICK_PARSE.sub('@<a class="inlinenick" href="http://brightkite.com/people/\\1">\\1</a>',
+- support.linkify(self.text))
++ support.linkify(self.text)))
+
+ self.is_reply = ("@%s" % self.username) in self.text
+ self.can_thread = data["comments_count"] > 0
+
+ # Geolocation
+- self.location_lon = data["place"]["longitude"]
+- self.location_lat = data["place"]["latitude"]
+- self.location_id = data["place"]["id"]
+- self.location_name = data["place"]["name"]
+- self.location_fullname = data["place"]["display_location"]
++ self.location_lon = to_unicode(data["place"]["longitude"])
++ self.location_lat = to_unicode(data["place"]["latitude"])
++ self.location_id = to_unicode(data["place"]["id"])
++ self.location_name = to_unicode(data["place"]["name"])
++ self.location_fullname = to_unicode(data["place"]["display_location"])
+ self.geo_position = (self.location_lat, self.location_lon)
+
+ if "photo" in data:
+- self.thumbnails = [{"src": data["photo"], "href": data["photo"]}]
++ self.thumbnails = [{"src": to_unicode(data["photo"]), "href": to_unicode(data["photo"])}]
+
+ class Comment:
+ def __init__(self, client, data):
+ self.client = client
+ self.account = client.account
+- self.service = client.account["service"]
+- self.username = client.account["username"]
++ self.service = to_unicode(client.account["service"])
++ self.username = to_unicode(client.account["username"])
+
+- self.sender = data["user"]["fullname"]
+- self.sender_nick = data["user"]["login"]
+- self.sender_id = data["user"]["login"]
+- self.image = data["user"]["small_avatar_url"]
++ self.sender = to_unicode(data["user"]["fullname"])
++ self.sender_nick = to_unicode(data["user"]["login"])
++ self.sender_id = to_unicode(data["user"]["login"])
++ self.image = to_unicode(data["user"]["small_avatar_url"])
+
+ self.time = support.parse_time(data["created_at"])
+- self.text = data["comment"]
+- self.bgcolor = "message_color"
++ self.text = to_unicode(data["comment"])
++ self.bgcolor = u"message_color"
+
+- self.url = "http://brightkite.com/objects/%s" % data["place_object"]["id"]
+- self.profile_url = "http://brightkite.com/people/%s" % self.sender_nick
++ self.url = to_unicode("http://brightkite.com/objects/%s" % data["place_object"]["id"])
++ self.profile_url = to_unicode("http://brightkite.com/people/%s" % self.sender_nick)
+
+- self.html_string = '<span class="text">%s</span>' % \
++ self.html_string = to_unicode('<span class="text">%s</span>' % \
+ NICK_PARSE.sub('@<a class="inlinenick" href="http://brightkite.com/people/\\1">\\1</a>',
+- support.linkify(self.text))
++ support.linkify(self.text)))
+
+ self.is_reply = ("@%s" % self.username) in self.text
+
+@@ -97,26 +98,26 @@ class FriendPosition:
+ def __init__(self, client, data):
+ self.client = client
+ self.account = client.account
+- self.service = client.account["service"]
+- self.username = client.account["username"]
+- self.sender = data["fullname"]
+- self.sender_nick = data["login"]
++ self.service = to_unicode(client.account["service"])
++ self.username = to_unicode(client.account["username"])
++ self.sender = to_unicode(data["fullname"])
++ self.sender_nick = to_unicode(data["login"])
+ self.sender_id = self.sender_nick
+ self.time = support.parse_time(data["last_checked_in"])
+- self.text = data["place"]["display_location"]
+- self.image = data["small_avatar_url"]
+- self.image_small = data["smaller_avatar_url"]
+- self.bgcolor = "message_color"
+- self.url = "http://brightkite.com" # TODO
+- self.profile_url = "http://brightkite.com" # TODO
++ self.text = to_unicode(data["place"]["display_location"])
++ self.image = to_unicode(data["small_avatar_url"])
++ self.image_small = to_unicode(data["smaller_avatar_url"])
++ self.bgcolor = u"message_color"
++ self.url = u"http://brightkite.com" # TODO
++ self.profile_url = u"http://brightkite.com" # TODO
+ self.is_reply = False
+
+ # Geolocation
+- self.location_lon = data["place"]["longitude"]
+- self.location_lat = data["place"]["latitude"]
+- self.location_id = data["place"]["id"]
+- self.location_name = data["place"]["name"]
+- self.location_fullname = data["place"]["display_location"]
++ self.location_lon = to_unicode(data["place"]["longitude"])
++ self.location_lat = to_unicode(data["place"]["latitude"])
++ self.location_id = to_unicode(data["place"]["id"])
++ self.location_name = to_unicode(data["place"]["name"])
++ self.location_fullname = to_unicode(data["place"]["display_location"])
+
+ class Client:
+ def __init__(self, acct):
+diff -up gwibber-867bzr/gwibber/microblog/buzz.py.kitchen gwibber-867bzr/gwibber/microblog/buzz.py
+--- gwibber-867bzr/gwibber/microblog/buzz.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/buzz.py 2010-09-25 10:35:44.286191002 -0400
+@@ -1,5 +1,6 @@
+ import network, util, json
+ from oauth import oauth
++from kitchen.text.converters import to_unicode
+
+ PROTOCOL_INFO = {
+ "name": "Buzz",
+@@ -41,32 +42,32 @@ class Client:
+
+ def _actor(self, user):
+ return {
+- "name": user["name"],
+- "nick": user["id"],
+- "id": user["id"],
+- "image": user.get("thumbnailUrl", "https://mail.google.com/mail/images/blue_ghost.jpg?sz=45"),
+- "url": user.get("profileUrl", None),
++ "name": to_unicode(user["name"]),
++ "nick": to_unicode(user["id"]),
++ "id": to_unicode(user["id"]),
++ "image": to_unicode(user.get("thumbnailUrl", "https://mail.google.com/mail/images/blue_ghost.jpg?sz=45")),
++ "url": to_unicode(user.get("profileUrl", None)),
+ "is_me": user["id"] == self.account["user_id"],
+ }
+
+ def _message(self, data):
+ m = {
+ "mid": data["id"],
+- "service": "buzz",
+- "account": self.account["id"],
++ "service": u"buzz",
++ "account": to_unicode(self.account["id"]),
+ "time": util.parsetime(data["published"]),
+- "url": data.get("links", {})["alternate"][0].get("href", ""),
+- "source": data.get("source", {}).get("title", None),
++ "url": to_unicode(data.get("links", {})["alternate"][0].get("href", "")),
++ "source": to_unicode(data.get("source", {}).get("title", None)),
+ "sender": self._actor(data["actor"]),
+ }
+
+- m["text"] = data["object"]["content"]
++ m["text"] = to_unicode(data["object"]["content"])
+
+ if data.get("source", {}).get("title", 0) == "Twitter":
+ m["text"] = m["text"].split(">:", 1)[1].strip()
+
+- m["html"] = m["text"]
+- m["content"] = m["text"]
++ m["html"] = to_unicode(m["text"])
++ m["content"] = to_unicode(m["text"])
+
+ if data.get("geocode", 0):
+ m["location"] = {
+@@ -75,24 +76,24 @@ class Client:
+ }
+
+ if data.get("address", 0):
+- m["location"]["address"] = data["address"]
++ m["location"]["address"] = to_unicode(data["address"])
+
+ m["images"] = []
+ for a in data["object"].get("attachments", []):
+ if a["type"] == "photo":
+ m["images"].append({
+- "src": a["links"]["preview"][0]["href"],
+- "url": a["links"]["enclosure"][0]["href"]
++ "src": to_unicode(a["links"]["preview"][0]["href"]),
++ "url": to_unicode(a["links"]["enclosure"][0]["href"])
+ })
+
+ if a["type"] == "video":
+ m["images"].append({
+- "src": a["links"]["preview"][0]["href"],
+- "url": a["links"]["alternate"][0]["href"],
++ "src": to_unicode(a["links"]["preview"][0]["href"]),
++ "url": to_unicode(a["links"]["alternate"][0]["href"]),
+ })
+
+ if a["type"] == "article":
+- m["content"] += "<p><b><a href=\"%s\">%s</a></b></p>" % (a["links"]["alternate"][0]["href"], a["title"])
++ m["content"] += to_unicode("<p><b><a href=\"%s\">%s</a></b></p>" % (a["links"]["alternate"][0]["href"], a["title"]))
+
+ return m
+
+diff -up gwibber-867bzr/gwibber/microblog/dispatcher.py.kitchen gwibber-867bzr/gwibber/microblog/dispatcher.py
+--- gwibber-867bzr/gwibber/microblog/dispatcher.py.kitchen 2010-09-25 10:35:44.252191000 -0400
++++ gwibber-867bzr/gwibber/microblog/dispatcher.py 2010-09-25 10:35:44.287191002 -0400
+@@ -8,6 +8,7 @@ import qaiku, friendfeed, digg, buzz, pi
+ import foursquare, gowalla
+ import sqlite3, mx.DateTime, re, uuid
+ import urlshorter, storage, network, util, config
++from kitchen.text.converters import to_unicode
+
+ from util import log
+ from util import resources
+@@ -86,9 +87,9 @@ def perform_operation((account, opname,
+ if message_data is not None:
+ for m in message_data:
+ if "mid" in m:
+- m["id"] = uuid.uuid1().hex
+- m["operation"] = opname
+- m["stream"] = stream
++ m["id"] = to_unicode(uuid.uuid1().hex)
++ m["operation"] = to_unicode(opname)
++ m["stream"] = to_unicode(stream)
+ m["transient"] = transient
+ m["rtl"] = util.isRTL(re.sub(text_cleaner, "", m["text"].decode('utf-8')))
+
+diff -up gwibber-867bzr/gwibber/microblog/facebook.py.kitchen gwibber-867bzr/gwibber/microblog/facebook.py
+--- gwibber-867bzr/gwibber/microblog/facebook.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/facebook.py 2010-09-25 10:40:22.387190997 -0400
+@@ -6,6 +6,7 @@ import hashlib, mx.DateTime, time
+ from os.path import join, getmtime, exists
+ from gettext import lgettext as _
+ from util.const import *
++from kitchen.text.converters import to_unicode
+ # Try to import * from custom, install custom.py to include packaging
+ # customizations like distro API keys, etc
+ try:
+@@ -90,44 +91,44 @@ class Client:
+
+ def _sender(self, user):
+ sender = {
+- "name": user["name"],
+- "id": str(user["id"]),
++ "name": to_unicode(user["name"]),
++ "id": user["id"],
+ "is_me": str(user["id"]) == self.user_id,
+- "url": user["url"],
+- "image": user["pic_square"],
++ "url": to_unicode(user["url"]),
++ "image": to_unicode(user["pic_square"]),
+ }
+
+ if user["url"] and not "?" in user["url"]:
+- sender["nick"] = user["url"].rsplit("/", 1)[-1]
++ sender["nick"] = to_unicode(user["url"].rsplit("/", 1)[-1])
+ return sender
+
+ def _message(self, data, profiles):
+ m = {}
+- m["mid"] = str(data["post_id"])
+- m["service"] = "facebook"
++ m["mid"] = to_unicode(data["post_id"])
++ m["service"] = u"facebook"
+ m["account"] = self.account["id"]
+ m["time"] = int(mx.DateTime.DateTimeFrom(int(data['created_time'])).gmtime())
+- m["url"] = data["permalink"]
++ m["url"] = to_unicode(data["permalink"])
+
+ if data.get("attribution", 0):
+- m["source"] = util.strip_urls(data["attribution"]).replace("via ", "")
++ m["source"] = to_unicode(util.strip_urls(data["attribution"]).replace("via ", ""))
+
+ if data.get("message", "").strip():
+- m["text"] = data["message"]
+- m["html"] = util.linkify(data["message"])
+- m["content"] = m["html"]
++ m["text"] = to_unicode(data["message"])
++ m["html"] = to_unicode(util.linkify(data["message"]))
++ m["content"] = to_unicode(m["html"])
+ else:
+- m["text"] = ""
+- m["html"] = ""
+- m["content"] = ""
++ m["text"] = u""
++ m["html"] = u""
++ m["content"] = u""
+
+ if data.get("actor_id", 0) in profiles:
+ m["sender"] = self._sender(profiles[data["actor_id"]])
+
+ if data.get("likes", {}).get("count", None):
+ m["likes"] = {
+- "count": data["likes"]["count"],
+- "url": data["likes"]["href"],
++ "count": to_unicode(data["likes"]["count"]),
++ "url": to_unicode(data["likes"]["href"]),
+ }
+
+ if data.get("comments", 0):
+@@ -135,100 +136,100 @@ class Client:
+ for item in data["comments"]["comment_list"]:
+ if item["fromid"] in profiles:
+ m["comments"].append({
+- "text": item["text"],
++ "text": to_unicode(item["text"]),
+ "time": int(mx.DateTime.DateTimeFrom(int(item["time"])).gmtime()),
+ "sender": self._sender(profiles[item["fromid"]]),
+ })
+
+ if data.get("attachment", 0):
+ if data["attachment"].get("name", 0):
+- m["content"] += "<p><b>%s</b></p>" % data["attachment"]["name"]
++ m["content"] += to_unicode("<p><b>%s</b></p>" % data["attachment"]["name"])
+
+ if data["attachment"].get("description", 0):
+- m["content"] += "<p>%s</p>" % data["attachment"]["description"]
++ m["content"] += to_unicode("<p>%s</p>" % data["attachment"]["description"])
+
+ m["images"] = []
+ for a in data["attachment"].get("media", []):
+ if a["type"] in ["photo", "video", "link"]:
+ if a.get("src", 0):
+ if a["src"].startswith("/"):
+- a["src"] = "http://facebook.com" + a["src"]
+- m["images"].append({"src": a["src"], "url": a["href"]})
++ a["src"] = u"http://facebook.com" + to_unicode(a["src"])
++ m["images"].append({"src": a["src"], "url": to_unicode(a["href"])})
+
+ return m
+
+ def _comment(self, data, profiles):
+ user = profiles[data["fromid"]]
+ return {
+- "mid": str(data["id"]),
+- "service": "facebook",
++ "mid": to_unicode(data["id"]),
++ "service": u"facebook",
+ "account": self.account["id"],
+ "time": int(mx.DateTime.DateTimeFrom(int(data['time'])).gmtime()),
+- "text": "@%s: %s" % (self.account["username"], data["text"]),
+- "content": "@%s: %s" % (self.account["username"], data["text"]),
+- "html": "@%s: %s" % (self.account["username"], data["text"]),
++ "text": to_unicode("@%s: %s" % (self.account["username"], data["text"])),
++ "content": to_unicode("@%s: %s" % (self.account["username"], data["text"])),
++ "html": to_unicode("@%s: %s" % (self.account["username"], data["text"])),
+ "reply": {
+ "id": data["post_id"],
+- "nick": self.account["username"],
+- "url": POST_URL % (self.user_id, data["object_id"]),
++ "nick": to_unicode(self.account["username"]),
++ "url": to_unicode(POST_URL % (self.user_id, data["object_id"])),
+ },
+ "sender": {
+- "nick": user["username"] or str(user["uid"]),
+- "name": user["name"],
++ "nick": to_unicode(user["username"]) or to_unicode(user["uid"]),
++ "name": to_unicode(user["name"]),
+ "id": str(user["uid"]),
+- "url": user["profile_url"],
+- "image": user["pic_square"],
++ "url": to_unicode(user["profile_url"]),
++ "image": to_unicode(user["pic_square"]),
+ }
+ }
+
+ def _image(self, data, profiles):
+ user = profiles[data["owner"]]
+ return {
+- "mid": str(data["object_id"]),
+- "service": "facebook",
++ "mid": to_unicode(data["object_id"]),
++ "service": u"facebook",
+ "account": self.account["id"],
+ "time": int(mx.DateTime.DateTimeFrom(int(data['created'])).gmtime()),
+- "content": data["caption"],
+- "text": data["caption"],
+- "html": data["caption"],
++ "content": to_unicode(data["caption"]),
++ "text": to_unicode(data["caption"]),
++ "html": to_unicode(data["caption"]),
+ "images": [{
+- "full": data["src_big"],
+- "src": data["src_big"],
+- "thumb": data["src_small"],
+- "url": data["link"],
++ "full": to_unicode(data["src_big"]),
++ "src": to_unicode(data["src_big"]),
++ "thumb": to_unicode(data["src_small"]),
++ "url": to_unicode(data["link"]),
+ }],
+ "sender": {
+- "nick": user["username"] or str(user["uid"]),
+- "name": user["name"],
++ "nick": to_unicode(user["username"]) or to_unicode(user["uid"]),
++ "name": to_unicode(user["name"]),
+ "id": str(user["uid"]),
+- "url": user["profile_url"],
+- "image": user["pic_square"],
++ "url": to_unicode(user["profile_url"]),
++ "image": to_unicode(user["pic_square"]),
+ }
+ }
+
+ def _list(self, data, user):
+ return {
+ "mid": data["value"],
+- "service": "facebook",
++ "service": u"facebook",
+ "account": self.account["id"],
+ "time": 0,
+- "text": "",
+- "html": "",
+- "content": "",
+- "url": "#", # http://www.facebook.com/friends/?filter=flp_%s" % data["flid"],
+- "name": data["name"],
+- "nick": data["name"],
+- "key": data["filter_key"],
+- "full": "",
+- "type": data["type"],
+- "kind": "list",
+- "fbstreamicon": data["icon_url"],
++ "text": u"",
++ "html": u"",
++ "content": u"",
++ "url": u"#", # http://www.facebook.com/friends/?filter=flp_%s" % data["flid"],
++ "name": to_unicode(data["name"]),
++ "nick": to_unicode(data["name"]),
++ "key": to_unicode(data["filter_key"]),
++ "full": u"",
++ "type": to_unicode(data["type"]),
++ "kind": u"list",
++ "fbstreamicon": to_unicode(data["icon_url"]),
+ "sender": {
+- "nick": user["username"] or str(user["uid"]),
+- "name": user["name"],
++ "nick": to_unicode(user["username"]) or to_unicode(user["uid"]),
++ "name": to_unicode(user["name"]),
+ "id": str(user["uid"]),
+- "url": user["profile_url"],
+- "image": user["pic_square"],
++ "url": to_unicode(user["profile_url"]),
++ "image": to_unicode(user["pic_square"]),
+ }
+ }
+
+diff -up gwibber-867bzr/gwibber/microblog/gowalla.py.kitchen gwibber-867bzr/gwibber/microblog/gowalla.py
+--- gwibber-867bzr/gwibber/microblog/gowalla.py.kitchen 2010-09-25 10:35:44.253191000 -0400
++++ gwibber-867bzr/gwibber/microblog/gowalla.py 2010-09-25 10:35:44.288191002 -0400
+@@ -26,6 +26,7 @@ import network, json, util, htmllib, re
+ from util import log
+ from util import exceptions
+ from gettext import lgettext as _
++from kitchen.text.converters import to_unicode
+ log.logger.name = "Gowalla"
+
+ PROTOCOL_INFO = {
+@@ -60,47 +61,47 @@ class Client:
+ def _message(self, data):
+
+ m = {};
+- m["mid"] = str(data["user"]["first_name"]) + str(data["user"]["last_name"])
+- m["service"] = "gowalla"
++ m["mid"] = to_unicode(str(data["user"]["first_name"]) + str(data["user"]["last_name"]))
++ m["service"] = u"gowalla"
+ m["account"] = self.account["id"]
+ m["time"] = util.parsetime(data["created_at"])
+
+- messagetext = ""
+- text = ""
++ messagetext = u""
++ text = u""
+ if data.has_key("spot"):
+ if data.has_key("message"):
+ messagetext += data["message"] + "<br/><br/>"
+ text += data["message"] + "\n"
+- m["url"] = "<a href='http://gowalla.com%s'>" % data["spot"]["url"]
+- m["url"] = "http://gowalla.com%s" % data["spot"]["url"]
+- img = "<table><tr><td><img src='%s'/></td><td>" % data["spot"]["image_url"]
+- messagetext += img + "Checked in at <a href='" + m["url"] + "'>" + data["spot"]["name"] + "</a>"
+- text += "Checked in at " + data["spot"]["name"]
++ m["url"] = to_unicode("<a href='http://gowalla.com%s'>" % data["spot"]["url"])
++ m["url"] = to_unicode("http://gowalla.com%s" % data["spot"]["url"])
++ img = to_unicode("<table><tr><td><img src='%s'/></td><td>" % data["spot"]["image_url"])
++ messagetext += img + "Checked in at <a href='" + m["url"] + "'>" + to_unicode(data["spot"]["name"]) + "</a>"
++ text += u"Checked in at " + to_unicode(data["spot"]["name"])
+ else:
+ if data.has_key("message"):
+- messagetext += data["message"] + "<br/><br/>"
+- text += data["message"] + "\n"
++ messagetext += to_unicode(data["message"]) + u"<br/><br/>"
++ text += to_unicode(data["message"]) + u"\n"
+ else:
+- text= "Checked in off the grid"
+- shouttext= "<table><tr><td><img src='http://gowalla.com/favicon.ico'/></td><td>Checked in off the grid"
++ text= u"Checked in off the grid"
++ shouttext= u"<table><tr><td><img src='http://gowalla.com/favicon.ico'/></td><td>Checked in off the grid"
+
+ m["text"] = text
+- m["content"] = messagetext + "</td></tr></table>"
+- m["html"] = messagetext + "</td></tr></table>"
++ m["content"] = messagetext + u"</td></tr></table>"
++ m["html"] = messagetext + u"</td></tr></table>"
+
+ m["sender"] = {}
+- m["sender"]["image"] = data["user"]["image_url"]
+- m["sender"]["url"] = "http://gowalla.com%s" % data["user"]["url"]
+- fullname = ""
++ m["sender"]["image"] = to_unicode(data["user"]["image_url"])
++ m["sender"]["url"] = to_unicode("http://gowalla.com%s" % data["user"]["url"])
++ fullname = u""
+ if data["user"].has_key("first_name"):
+- fullname += data["user"]["first_name"] + " "
++ fullname += to_unicode(data["user"]["first_name"]) + u" "
+ if data["user"].has_key("last_name"):
+- fullname += data["user"]["last_name"]
++ fullname += to_unicode(data["user"]["last_name"])
+
+ m["sender"]["name"] = fullname
+ m["sender"]["nick"] = fullname
+
+- m["source"] = "<a href='http://gowalla.com/'>Gowalla</a>"
++ m["source"] = u"<a href='http://gowalla.com/'>Gowalla</a>"
+
+ return m
+
+diff -up gwibber-867bzr/gwibber/microblog/identica.py.kitchen gwibber-867bzr/gwibber/microblog/identica.py
+--- gwibber-867bzr/gwibber/microblog/identica.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/identica.py 2010-09-25 10:35:44.289191002 -0400
+@@ -2,6 +2,7 @@ import re, network, util
+ from util import log
+ from util import exceptions
+ from gettext import lgettext as _
++from kitchen.text.converters import to_unicode
+ log.logger.name = "Identi.ca"
+
+ PROTOCOL_INFO = {
+@@ -53,28 +54,28 @@ class Client:
+ def _common(self, data):
+ m = {}
+ try:
+- m["mid"] = str(data["id"])
+- m["service"] = "identica"
++ m["mid"] = to_unicode(data["id"])
++ m["service"] = u"identica"
+ m["account"] = self.account["id"]
+ m["time"] = util.parsetime(data["created_at"])
+- m["source"] = data.get("source", False)
+- m["text"] = data["text"]
++ m["source"] = to_unicode(data.get("source", False))
++ m["text"] = to_unicode(data["text"])
+ m["to_me"] = ("@%s" % self.account["username"]) in data["text"]
+
+- m["html"] = util.linkify(m["text"],
++ m["html"] = to_unicode(util.linkify(m["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="%s#search?q=\\1">\\1</a>' % URL_PREFIX),
+- (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % URL_PREFIX)))
++ (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % URL_PREFIX))))
+
+- m["content"] = util.linkify(m["text"],
++ m["content"] = to_unicode(util.linkify(m["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="gwibber:/tag?acct=%s&query=\\1">\\1</a>' % m["account"]),
+- (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"])))
++ (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"]))))
+
+ images = []
+ if data.get("attachments", 0):
+ for a in data["attachments"]:
+ mime = a.get("mimetype", "")
+ if mime and mime.startswith("image") and a.get("url", 0):
+- images.append({"src": a["url"], "url": a["url"]})
++ images.append({"src": to_unicode(a["url"]), "url": to_unicode(a["url"])})
+
+ images.extend(util.imgpreview(m["text"]))
+
+@@ -91,33 +92,33 @@ class Client:
+ if data.get("in_reply_to_status_id", 0) and data.get("in_reply_to_screen_name", 0):
+ m["reply"] = {}
+ m["reply"]["id"] = data["in_reply_to_status_id"]
+- m["reply"]["nick"] = data["in_reply_to_screen_name"]
+- m["reply"]["url"] = "/".join((URL_PREFIX, "notice", str(m["reply"]["id"])))
++ m["reply"]["nick"] = to_unicode(data["in_reply_to_screen_name"])
++ m["reply"]["url"] = to_unicode("/".join((URL_PREFIX, "notice", str(m["reply"]["id"]))))
+
+ user = data.get("user", data.get("sender", 0))
+
+ m["sender"] = {}
+- m["sender"]["name"] = user["name"]
+- m["sender"]["nick"] = user["screen_name"]
++ m["sender"]["name"] = to_unicode(user["name"])
++ m["sender"]["nick"] = to_unicode(user["screen_name"])
+ m["sender"]["id"] = user["id"]
+- m["sender"]["location"] = user["location"]
++ m["sender"]["location"] = to_unicode(user["location"])
+ m["sender"]["followers"] = user["followers_count"]
+- m["sender"]["image"] = user["profile_image_url"]
+- m["sender"]["url"] = "/".join((URL_PREFIX, m["sender"]["nick"]))
++ m["sender"]["image"] = to_unicode(user["profile_image_url"])
++ m["sender"]["url"] = to_unicode("/".join((URL_PREFIX, m["sender"]["nick"])))
+ m["sender"]["is_me"] = m["sender"]["nick"] == self.account["username"]
+- m["url"] = "/".join((URL_PREFIX, "notice", m["mid"]))
++ m["url"] = to_unicode("/".join((URL_PREFIX, "notice", m["mid"])))
+ return m
+
+ def _private(self, data):
+ m = self._message(data)
+ m["private"] = True
+ m["recipient"] = {}
+- m["recipient"]["name"] = data["recipient"]["name"]
+- m["recipient"]["nick"] = data["recipient"]["screen_name"]
++ m["recipient"]["name"] = to_unicode(data["recipient"]["name"])
++ m["recipient"]["nick"] = to_unicode(data["recipient"]["screen_name"])
+ m["recipient"]["id"] = data["recipient"]["id"]
+- m["recipient"]["image"] = data["recipient"]["profile_image_url"]
+- m["recipient"]["location"] = data["recipient"]["location"]
+- m["recipient"]["url"] = "/".join((URL_PREFIX, m["recipient"]["nick"]))
++ m["recipient"]["image"] = to_unicode(data["recipient"]["profile_image_url"])
++ m["recipient"]["location"] = to_unicode(data["recipient"]["location"])
++ m["recipient"]["url"] = to_unicode("/".join((URL_PREFIX, m["recipient"]["nick"])))
+ m["recipient"]["is_me"] = m["recipient"]["nick"].lower() == self.account["username"].lower()
+ return m
+
+@@ -127,14 +128,14 @@ class Client:
+ if data["to_user_id"]:
+ m["reply"] = {}
+ m["reply"]["id"] = data["to_user_id"]
+- m["reply"]["nick"] = data["to_user"]
++ m["reply"]["nick"] = to_unicode(data["to_user"])
+
+ m["sender"] = {}
+- m["sender"]["nick"] = data["from_user"]
++ m["sender"]["nick"] = to_unicode(data["from_user"])
+ m["sender"]["id"] = data["from_user_id"]
+- m["sender"]["image"] = data["profile_image_url"]
+- m["sender"]["url"] = "/".join((URL_PREFIX, m["sender"]["nick"]))
+- m["url"] = "/".join((URL_PREFIX, "notice", str(m["mid"])))
++ m["sender"]["image"] = to_unicode(data["profile_image_url"])
++ m["sender"]["url"] = to_unicode("/".join((URL_PREFIX, m["sender"]["nick"])))
++ m["url"] = to_unicode("/".join((URL_PREFIX, "notice", str(m["mid"]))))
+ return m
+
+ def _get(self, path, parse="message", post=False, single=False, **args):
+diff -up gwibber-867bzr/gwibber/microblog/statusnet.py.kitchen gwibber-867bzr/gwibber/microblog/statusnet.py
+--- gwibber-867bzr/gwibber/microblog/statusnet.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/statusnet.py 2010-09-25 10:35:44.289191002 -0400
+@@ -2,6 +2,7 @@ import re, network, util
+ from util import log
+ from util import exceptions
+ from gettext import lgettext as _
++from kitchen.text.converters import to_unicode
+ log.logger.name = "StatusNet"
+
+ PROTOCOL_INFO = {
+@@ -55,28 +56,28 @@ class Client:
+ def _common(self, data):
+ m = {}
+ try:
+- m["mid"] = str(data["id"])
+- m["service"] = "statusnet"
++ m["mid"] = to_unicode(data["id"])
++ m["service"] = u"statusnet"
+ m["account"] = self.account["id"]
+ m["time"] = util.parsetime(data["created_at"])
+- m["source"] = data.get("source", False)
+- m["text"] = data["text"]
++ m["source"] = to_unicode(data.get("source", False))
++ m["text"] = to_unicode(data["text"])
+ m["to_me"] = ("@%s" % self.account["username"]) in data["text"]
+
+- m["html"] = util.linkify(m["text"],
++ m["html"] = to_unicode(util.linkify(m["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="%s#search?q=\\1">\\1</a>' % self.url_prefix),
+- (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % self.url_prefix)))
++ (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % self.url_prefix))))
+
+- m["content"] = util.linkify(m["text"],
++ m["content"] = to_unicode(util.linkify(m["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="gwibber:/tag?acct=%s&query=\\1">\\1</a>' % m["account"]),
+- (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"])))
++ (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"]))))
+
+ images = []
+ if data.get("attachments", 0):
+ for a in data["attachments"]:
+ mime = a.get("mimetype", "")
+ if mime and mime.startswith("image") and a.get("url", 0):
+- images.append({"src": a["url"], "url": a["url"]})
++ images.append({"src": to_unicode(a["url"]), "url": to_unicode(a["url"])})
+
+ images.extend(util.imgpreview(m["text"]))
+
+@@ -93,33 +94,33 @@ class Client:
+ if data.get("in_reply_to_status_id", 0) and data.get("in_reply_to_screen_name", 0):
+ m["reply"] = {}
+ m["reply"]["id"] = data["in_reply_to_status_id"]
+- m["reply"]["nick"] = data["in_reply_to_screen_name"]
+- m["reply"]["url"] = "/".join((self.url_prefix, "notice", str(m["reply"]["id"])))
++ m["reply"]["nick"] = to_unicode(data["in_reply_to_screen_name"])
++ m["reply"]["url"] = to_unicode("/".join((self.url_prefix, "notice", str(m["reply"]["id"]))))
+
+ user = data.get("user", data.get("sender", 0))
+
+ m["sender"] = {}
+- m["sender"]["name"] = user["name"]
+- m["sender"]["nick"] = user["screen_name"]
++ m["sender"]["name"] = to_unicode(user["name"])
++ m["sender"]["nick"] = to_unicode(user["screen_name"])
+ m["sender"]["id"] = user["id"]
+- m["sender"]["location"] = user["location"]
++ m["sender"]["location"] = to_unicode(user["location"])
+ m["sender"]["followers"] = user["followers_count"]
+- m["sender"]["image"] = user["profile_image_url"]
+- m["sender"]["url"] = "/".join((self.url_prefix, m["sender"]["nick"]))
++ m["sender"]["image"] = to_unicode(user["profile_image_url"])
++ m["sender"]["url"] = to_unicode("/".join((self.url_prefix, m["sender"]["nick"])))
+ m["sender"]["is_me"] = m["sender"]["nick"] == self.account["username"]
+- m["url"] = "/".join((self.url_prefix, "notice", m["mid"]))
++ m["url"] = to_unicode("/".join((self.url_prefix, "notice", m["mid"])))
+ return m
+
+ def _private(self, data):
+ m = self._message(data)
+ m["private"] = True
+ m["recipient"] = {}
+- m["recipient"]["name"] = data["recipient"]["name"]
+- m["recipient"]["nick"] = data["recipient"]["screen_name"]
++ m["recipient"]["name"] = to_unicode(data["recipient"]["name"])
++ m["recipient"]["nick"] = to_unicode(data["recipient"]["screen_name"])
+ m["recipient"]["id"] = data["recipient"]["id"]
+- m["recipient"]["image"] = data["recipient"]["profile_image_url"]
+- m["recipient"]["location"] = data["recipient"]["location"]
+- m["recipient"]["url"] = "/".join((self.url_prefix, m["recipient"]["nick"]))
++ m["recipient"]["image"] = to_unicode(data["recipient"]["profile_image_url"])
++ m["recipient"]["location"] = to_unicode(data["recipient"]["location"])
++ m["recipient"]["url"] = to_unicode("/".join((self.url_prefix, m["recipient"]["nick"])))
+ m["recipient"]["is_me"] = m["recipient"]["nick"].lower() == self.account["username"].lower()
+ return m
+
+@@ -132,11 +133,11 @@ class Client:
+ m["reply"]["nick"] = data["to_user"]
+
+ m["sender"] = {}
+- m["sender"]["nick"] = data["from_user"]
++ m["sender"]["nick"] = to_unicode(data["from_user"])
+ m["sender"]["id"] = data["from_user_id"]
+- m["sender"]["image"] = data["profile_image_url"]
+- m["sender"]["url"] = "/".join((self.url_prefix, m["sender"]["nick"]))
+- m["url"] = "/".join((self.url_prefix, "notice", str(m["mid"])))
++ m["sender"]["image"] = to_unicode(data["profile_image_url"])
++ m["sender"]["url"] = to_unicode("/".join((self.url_prefix, m["sender"]["nick"])))
++ m["url"] = to_unicode("/".join((self.url_prefix, "notice", str(m["mid"]))))
+ return m
+
+ def _get(self, path, parse="message", post=False, single=False, **args):
+diff -up gwibber-867bzr/gwibber/microblog/twitter.py.kitchen gwibber-867bzr/gwibber/microblog/twitter.py
+--- gwibber-867bzr/gwibber/microblog/twitter.py.kitchen 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/twitter.py 2010-09-25 10:35:44.290191002 -0400
+@@ -3,6 +3,7 @@ import gnomekeyring
+ from oauth import oauth
+ from util import log, exceptions
+ from gettext import lgettext as _
++from kitchen.text.converters import to_unicode
+ log.logger.name = "Twitter"
+
+ PROTOCOL_INFO = {
+@@ -72,19 +73,19 @@ class Client:
+ m = {};
+ try:
+ m["mid"] = str(data["id"])
+- m["service"] = "twitter"
++ m["service"] = u"twitter"
+ m["account"] = self.account["id"]
+ m["time"] = util.parsetime(data["created_at"])
+- m["text"] = unescape(data["text"])
++ m["text"] = to_unicode(unescape(data["text"]))
+ m["to_me"] = ("@%s" % self.account["username"]) in data["text"]
+
+- m["html"] = util.linkify(data["text"],
++ m["html"] = to_unicode(util.linkify(data["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="%s#search?q=\\1">\\1</a>' % URL_PREFIX),
+- (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % URL_PREFIX)), escape=False)
++ (util.PARSE_NICK, '@<a class="nick" href="%s/\\1">\\1</a>' % URL_PREFIX)), escape=False))
+
+- m["content"] = util.linkify(data["text"],
++ m["content"] = to_unicode(util.linkify(data["text"],
+ ((util.PARSE_HASH, '#<a class="hash" href="gwibber:/tag?acct=%s&query=\\1">\\1</a>' % m["account"]),
+- (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"])), escape=False)
++ (util.PARSE_NICK, '@<a class="nick" href="gwibber:/user?acct=%s&name=\\1">\\1</a>' % m["account"])), escape=False))
+
+ images = util.imgpreview(m["text"])
+ if images:
+@@ -96,13 +97,13 @@ class Client:
+
+ def _user(self, user):
+ return {
+- "name": user["name"],
+- "nick": user["screen_name"],
++ "name": to_unicode(user["name"]),
++ "nick": to_unicode(user["screen_name"]),
+ "id": user["id"],
+- "location": user["location"],
++ "location": to_unicode(user["location"]),
+ "followers": user.get("followers", None),
+- "image": user["profile_image_url"],
+- "url": "/".join((URL_PREFIX, user["screen_name"])),
++ "image": to_unicode(user["profile_image_url"]),
++ "url": to_unicode("/".join((URL_PREFIX, user["screen_name"]))),
+ "is_me": user["screen_name"] == self.account["username"],
+ }
+
+@@ -116,11 +117,11 @@ class Client:
+ if "in_reply_to_status_id" in data and data["in_reply_to_status_id"]:
+ m["reply"] = {}
+ m["reply"]["id"] = data["in_reply_to_status_id"]
+- m["reply"]["nick"] = data["in_reply_to_screen_name"]
+- m["reply"]["url"] = "/".join((URL_PREFIX, m["reply"]["nick"], "statuses", str(m["reply"]["id"])))
++ m["reply"]["nick"] = to_unicode(data["in_reply_to_screen_name"])
++ m["reply"]["url"] = to_unicode("/".join((URL_PREFIX, m["reply"]["nick"], "statuses", str(m["reply"]["id"]))))
+
+ m["sender"] = self._user(data["user"] if "user" in data else data["sender"])
+- m["url"] = "/".join((m["sender"]["url"], "statuses", str(m["mid"])))
++ m["url"] = to_unicode("/".join((m["sender"]["url"], "statuses", str(m["mid"]))))
+
+ return m
+
+@@ -129,12 +130,12 @@ class Client:
+ m["private"] = True
+
+ m["recipient"] = {}
+- m["recipient"]["name"] = data["recipient"]["name"]
+- m["recipient"]["nick"] = data["recipient"]["screen_name"]
++ m["recipient"]["name"] = to_unicode(data["recipient"]["name"])
++ m["recipient"]["nick"] = to_unicode(data["recipient"]["screen_name"])
+ m["recipient"]["id"] = data["recipient"]["id"]
+- m["recipient"]["image"] = data["recipient"]["profile_image_url"]
+- m["recipient"]["location"] = data["recipient"]["location"]
+- m["recipient"]["url"] = "/".join((URL_PREFIX, m["recipient"]["nick"]))
++ m["recipient"]["image"] = to_unicode(data["recipient"]["profile_image_url"])
++ m["recipient"]["location"] = to_unicode(data["recipient"]["location"])
++ m["recipient"]["url"] = to_unicode("/".join((URL_PREFIX, m["recipient"]["nick"])))
+ m["recipient"]["is_me"] = m["recipient"]["nick"] == self.account["username"]
+
+ return m
+@@ -145,37 +146,37 @@ class Client:
+ if data["to_user_id"]:
+ m["reply"] = {}
+ m["reply"]["id"] = data["to_user_id"]
+- m["reply"]["nick"] = data["to_user"]
++ m["reply"]["nick"] = to_unicode(data["to_user"])
+
+ m["sender"] = {}
+- m["sender"]["nick"] = data["from_user"]
++ m["sender"]["nick"] = to_unicode(data["from_user"])
+ m["sender"]["id"] = data["from_user_id"]
+- m["sender"]["image"] = data["profile_image_url"]
+- m["sender"]["url"] = "/".join((URL_PREFIX, m["sender"]["nick"]))
++ m["sender"]["image"] = to_unicode(data["profile_image_url"])
++ m["sender"]["url"] = to_unicode("/".join((URL_PREFIX, m["sender"]["nick"])))
+ m["sender"]["is_me"] = m["sender"]["nick"] == self.account["username"]
+- m["url"] = "/".join((m["sender"]["url"], "statuses", str(m["mid"])))
++ m["url"] = to_unicode("/".join((m["sender"]["url"], "statuses", str(m["mid"]))))
+ return m
+
+ def _list(self, data):
+ return {
+ "mid": data["id"],
+- "service": "twitter",
++ "service": u"twitter",
+ "account": self.account["id"],
+ "time": 0,
+- "text": data["description"],
+- "html": data["description"],
+- "content": data["description"],
+- "url": "/".join((URL_PREFIX, data["uri"])),
+- "sender": self._user(data["user"]),
+- "name": data["name"],
+- "nick": data["slug"],
++ "text": to_unicode(data["description"]),
++ "html": to_unicode(data["description"]),
++ "content": to_unicode(data["description"]),
++ "url": to_unicode("/".join((URL_PREFIX, data["uri"]))),
++ "sender": to_unicode(self._user(data["user"])),
++ "name": to_unicode(data["name"]),
++ "nick": to_unicode(data["slug"]),
+ "key": data["slug"],
+- "full": data["full_name"],
+- "uri": data["uri"],
++ "full": to_unicode(data["full_name"]),
++ "uri": to_unicode(data["uri"]),
+ "mode": data["mode"],
+ "members": data["member_count"],
+ "followers": data["subscriber_count"],
+- "kind": "list",
++ "kind": u"list",
+ }
+
+ def _get(self, path, parse="message", post=False, single=False, **args):
diff --git a/gwibber-867bzr-minimize-chars.patch b/gwibber-867bzr-minimize-chars.patch
new file mode 100644
index 0000000..e03e946
--- /dev/null
+++ b/gwibber-867bzr-minimize-chars.patch
@@ -0,0 +1,111 @@
+diff -up gwibber-867bzr/gwibber/gwui.py.minimize gwibber-867bzr/gwibber/gwui.py
+--- gwibber-867bzr/gwibber/gwui.py.minimize 2010-09-25 10:33:39.140191002 -0400
++++ gwibber-867bzr/gwibber/gwui.py 2010-09-25 10:34:43.056191003 -0400
+@@ -1,4 +1,5 @@
+-
++# -*- coding: utf-8 -*-
++#
+ import os, json, urlparse, resources, util, sqlite3
+ import gtk, gobject, pango, webkit, time, gconf
+ import microblog.util
+@@ -916,6 +917,14 @@ class InputTextView(gtk.TextView):
+ except:
+ pass
+
++ # Replace these characters with shorter ones
++ # First field: search for string if this character was entered
++ # Second field: string to search for
++ # Third field: replace with this string
++ self.replacements = [(".", "...", "…"), ("-", "--", "—")]
++ # Keep replacements from triggering themselves
++ self.__replace_lock = False
++
+ def get_text(self):
+ buf = self.get_buffer()
+ return buf.get_text(*buf.get_bounds()).strip()
+@@ -924,8 +933,11 @@ class InputTextView(gtk.TextView):
+ return len(unicode(self.get_text(), "utf-8"))
+
+ def on_add_text(self, buf, iter, text, tlen):
++ if not text:
++ return
++
+ if self.model.settings["shorten_urls"]:
+- if text and text.startswith("http") and not " " in text \
++ if text.startswith("http") and not " " in text \
+ and len(text) > 30:
+
+ buf = self.get_buffer()
+@@ -953,6 +965,26 @@ class InputTextView(gtk.TextView):
+ self.shortener.Shorten(text,
+ reply_handler=add_shortened,
+ error_handler=error_shortened)
++ if self.model.settings["minimize_chars"] and not self.__replace_lock:
++ for entry in self.replacements:
++ if entry[0] in text:
++ buf = self.get_buffer()
++ buf.stop_emission("insert-text")
++ try:
++ self.__replace_lock = True
++ buf.insert(iter, text)
++ finally:
++ self.__replace_lock = False
++
++ # Search the whole buffer in case someone pastes something with the
++ # replacement string as a subset
++ search_iter = buf.get_start_iter()
++ match = search_iter.forward_search(entry[1], 0)
++ while match:
++ buf.delete(match[0], match[1])
++ buf.insert(match[0], entry[2])
++ search_iter = buf.get_start_iter()
++ match = search_iter.forward_search(entry[1], 0)
+
+ def set_overlay_text(self, text):
+ if not hasattr(self, 'pango_overlay'):
+diff -up gwibber-867bzr/gwibber/microblog/util/const.py.minimize gwibber-867bzr/gwibber/microblog/util/const.py
+--- gwibber-867bzr/gwibber/microblog/util/const.py.minimize 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/microblog/util/const.py 2010-09-25 10:33:39.169191002 -0400
+@@ -39,6 +39,7 @@ DEFAULT_SETTINGS = {
+ "presence_check": True,
+ "show_fullname": True,
+ "shorten_urls": True,
++ "minimize_chars": False,
+ "urlshorter": "is.gd",
+ "reply_append_colon": True,
+ "retweet_style": "recycle",
+diff -up gwibber-867bzr/gwibber/preferences.py.minimize gwibber-867bzr/gwibber/preferences.py
+--- gwibber-867bzr/gwibber/preferences.py.minimize 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/gwibber/preferences.py 2010-09-25 10:35:12.323191088 -0400
+@@ -68,6 +68,7 @@ class GwibberPreferences(object):
+ "no_notifications",
+ "show_fullname",
+ "shorten_urls",
++ "minimize_chars",
+ "reply_append_colon",
+ "global_retweet",
+ "interval",
+diff -up gwibber-867bzr/ui/gwibber-preferences-dialog.ui.minimize gwibber-867bzr/ui/gwibber-preferences-dialog.ui
+--- gwibber-867bzr/ui/gwibber-preferences-dialog.ui.minimize 2010-09-23 09:42:12.000000000 -0400
++++ gwibber-867bzr/ui/gwibber-preferences-dialog.ui 2010-09-25 10:33:39.170191002 -0400
+@@ -396,6 +396,20 @@
+ <property name="n_rows">3</property>
+ <property name="homogeneous">True</property>
+ <child>
++ <object class="GtkCheckButton" id="minimize_chars">
++ <property name="label" translatable="yes">Automatically replace common strings with unicode equivalents to minimize characters (e.g. ... replaced with …)</property>
++ <property name="visible">True</property>
++ <property name="can_focus">True</property>
++ <property name="receives_default">False</property>
++ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
++ <property name="draw_indicator">True</property>
++ </object>
++ <packing>
++ <property name="top_attach">3</property>
++ <property name="bottom_attach">4</property>
++ </packing>
++ </child>
++ <child>
+ <object class="GtkCheckButton" id="reply_append_colon">
+ <property name="label" translatable="yes">Append colon to username when replying</property>
+ <property name="visible">True</property>
diff --git a/gwibber-867bzr-missing-mark.patch b/gwibber-867bzr-missing-mark.patch
new file mode 100644
index 0000000..65178ec
--- /dev/null
+++ b/gwibber-867bzr-missing-mark.patch
@@ -0,0 +1,12 @@
+diff -up gwibber-867bzr/gwibber/gwui.py.BAD gwibber-867bzr/gwibber/gwui.py
+--- gwibber-867bzr/gwibber/gwui.py.BAD 2010-09-24 11:21:19.897185001 -0400
++++ gwibber-867bzr/gwibber/gwui.py 2010-09-24 11:21:44.167184972 -0400
+@@ -939,7 +939,7 @@ class InputTextView(gtk.TextView):
+ buf.insert(iter_start, shortened_url)
+ def error_shortened(dbus_exc):
+ "Internal shortening-url-died function: a closure"
+- iter = buf.get_iter_at_mark(mark)
++ iter = buf.get_iter_at_mark(mark_start)
+ buf.insert(iter, text) # shortening failed
+
+ # set a mark at iter, so that the callback knows where to insert
diff --git a/gwibber.spec b/gwibber.spec
index eed8154..8e5af94 100644
--- a/gwibber.spec
+++ b/gwibber.spec
@@ -1,11 +1,11 @@
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%global basever 2.31.93
-%global bzr_rev 847
+%global basever 2.33.0
+%global bzr_rev 867
Name: gwibber
Version: %{basever}
-Release: 1.%{bzr_rev}bzr%{?dist}
+Release: 7.%{bzr_rev}bzr%{?dist}
Epoch: 1
Summary: An open source microblogging client for GNOME developed with Python and GTK
Group: Applications/Internet
@@ -19,9 +19,9 @@ URL: https://launchpad.net/gwibber
Source0: gwibber-%{bzr_rev}bzr.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-# Gwibber unicode hack
-# See: https://bugs.launchpad.net/gwibber/+bug/532952
-Patch1: gwibber-838bzr-twitter-unicode-hack.patch
+# Fix situation where pango_overlay can be undefined
+# https://bugs.launchpad.net/gwibber/+bug/577050
+Patch0: gwibber-865bzr-undefined.patch
# Disable libproxy support
# It doesn't work for some unknown reason.
@@ -30,13 +30,29 @@ Patch2: gwibber-pre3-no-libproxy.patch
# Turn off Position printing debug. Noise noise noise!
Patch3: gwibber-794bzr-no-Position-printing.patch
-# Quit when minimized to icon and I tell the icon to quit.
-Patch4: gwibber-794bzr-quit-when-minimized.patch
-
# Oauth bits
Patch6: gwibber-832bzr-twitter-oauth.patch
-Requires: libsoup, python-pycurl, PyXML
+# Gowalla
+Patch7: gwibber-867bzr-gowalla.patch
+Patch8: gwibber-867bzr-gowalla-icons.patch
+
+# Minimize characters with unicode equivs
+Patch10: gwibber-867bzr-minimize-chars.patch
+
+# Fix iter call to non-existent "mark", use "mark_start"
+# bz635345 bz623754
+Patch11: gwibber-867bzr-missing-mark.patch
+
+# Use kitchen to force all strings generated by microblog inputs to unicode
+Patch12: gwibber-867bzr-kitchen-utf8.patch
+
+# Handle \x00 if it shows up in our content string
+# bz 630944 & 620170
+# https://bugs.launchpad.net/gwibber/+bug/647049
+Patch13: gwibber-867bzr-handle-x00-in-content.patch
+
+Requires: libsoup, python-pycurl
Requires: python
Requires: dbus-python >= 0.80.2
Requires: pygtk2 >= 2.10.4
@@ -50,10 +66,11 @@ Requires: python-distutils-extra
Requires: python-feedparser >= 4.1
Requires: pyxdg >= 0.15
Requires: python-mako >= 0.2.2
-Requires: python-sexy, gnome-python2-gnomekeyring
+Requires: gnome-python2-gnomekeyring
Requires: python-oauth
Requires: gnome-python2-libwnck
Requires: gnome-python2-gtkspell
+Requires: python-kitchen
BuildRequires: python-devel, desktop-file-utils, python-distutils-extra, intltool, gettext
BuildArch: noarch
@@ -64,13 +81,21 @@ and GTK. It supports Twitter, Jaiku, Identi.ca, Facebook, and Digg.
%prep
%setup -q -n gwibber-%{bzr_rev}bzr
-%patch1 -p1 -b .gwibber-unicode-hack
+%patch0 -p1 -b .undefined
%patch2 -p1 -b .no-libproxy
%patch3 -p1 -b .no-position-printing
-%patch4 -p1 -b .quit
%patch6 -p1 -b .oauth
-sed -i -e '/^#! \?\//, 1d' $(find %{name} | grep "\.py$")
+%patch7 -p1 -b .gowalla
+%patch8 -p1 -b .gowalla-icons
+
+%patch10 -p1 -b .minimize
+
+%patch12 -p1 -b .kitchen
+
+# %%patch13 -p1 -b .x00
+
+# sed -i -e '/^#! \?\//, 1d' $(find %{name} | grep "\.py$")
%build
%{__python} setup.py build
@@ -112,6 +137,35 @@ rm -rf %{buildroot}
%{_datadir}/indicators/messages/applications/gwibber
%changelog
+* Sat Sep 25 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-7.867bzr
+- enable toshio's improved character minimization code
+
+* Fri Sep 24 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-6.867bzr
+- replace \x00 with a blank space in the content string to prevent load_html_string
+ from choking on it (bz 620170 & 630944)
+
+* Thu Sep 23 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-5.867bzr
+- drop debug patch
+- don't apply auto-minimizer patch until upstream gives feedback
+- drop extraneous dependencies (bz 632621)
+- fix call to non-existent "mark" to call "mark_start" instead (bz 623754, 635345)
+
+* Thu Sep 23 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-4.867bzr
+- add support for auto-minimizing common character strings to unicode equivs
+
+* Thu Sep 23 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-2.867bzr
+- use kitchen to handle non-utf8 characters
+- gowalla support
+
+* Thu Sep 23 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-1.867bzr
+- fix some crash issues by moving to bzr867
+
+* Tue Sep 21 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.33.0-1.865bzr
+- update to 2.33
+- drop local "fix quit" patch, upstream fixed differently.
+- drop unicode fix hack, no longer works
+- properly fix case where pango_overlay could be undefined (bz 636409 627394)
+
* Thu Sep 9 2010 Tom "spot" Callaway <tcallawa at redhat.com> - 1:2.31.92-1.847bzr
- update to 2.31.93 (847bzr)
diff --git a/sources b/sources
index eb8e20e..75c06b3 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-50aa187a09c8fa219975a1448fc4b832 gwibber-847bzr.tar.gz
+869d7b4909a2f88f532608bdbdf648ce gwibber-867bzr.tar.gz
More information about the scm-commits
mailing list