1
from deskbar.core.GconfStore import GconfStore
2
from deskbar.core.Utils import strip_html, get_proxy, load_base64_icon
3
from deskbar.core.Web import GnomeURLopener, Account, AccountDialog, ConcurrentRequestsException
4
from deskbar.defs import VERSION
5
from deskbar.handlers.actions.CopyToClipboardAction import CopyToClipboardAction
6
from deskbar.handlers.actions.ShowUrlAction import ShowUrlAction
7
from gettext import gettext as _
8
from xml.sax.saxutils import unescape
10
import deskbar.interfaces.Action
11
import deskbar.interfaces.Match
12
import deskbar.interfaces.Module
18
LOGGER = logging.getLogger (__name__)
20
TWITTER_UPDATE_URL = "http://twitter.com/statuses/update.xml"
21
IDENTICA_UPDATE_URL = "http://identi.ca/api/statuses/update.xml"
23
# Base64 encoded Twitter logo
25
"""iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAcVJREFUOI2FkztuFEEQhr/q7nnIa2GQVgiDCYCEAzhAHMY3gASJgAtwAXLuQ0AGRiQbOEBeGdsy4PXOTNdPMLOrWVbCJVXUVf+ru42h2pzVZEdmBEQwo07JuKUSgEta5szMjfNOTKLxvIDsrhjCf0ESABJXDl+WHTVw0sE0JB7gtwkYAIBG4mcWCVgCGTA5N22rngTMjBiMFKNtATjwx0Vh0Am+NpmzGPB+FwBDPEzQdFll6kESQAjBZjetfrsozDDEp0U3MmBrmAS8uldvW8jAlaBESGvVYIZJgDAz5tmZuzYB3F3fl5kLd+oRoQbZq/FO4mkZeFKETQADMuLSndqM6yxe3605rBJLaW0gI6YxUo6uNq0sNoK5i12DXy52gjExcSdFGCw5kP55FwH68wI4dXHiYubiW+skA7n3AxK44xoFMA7xcWGUZhxngcHbiwVnueIgBroVO/CyTuN91nKUO72/bHh3fg1xCGmDTCBjPxqfD/bYL/t3sI7TLfBmr+Jot4LO+9SCjTpANH50znGbNzMAiCFYNPh4f4cP0wnPklFJVBL10Lh4UScOq7htYVXZXblrWRA5deGjIQGPolEaVMNX/wuhBOJI5bQAKAAAAABJRU5ErkJggg=="""
28
"""iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gIBRUoA+uuEZoAAACXSURBVDjLY5Q0cfzPQAFgYqAQDLwBLNgEOdjZGJRVpBmMDNQYGBgYGM5duMVw985Thh8/fxE2gIOdjcHVxZRBW1sRLiYtLcpw9ep9ht17TmMYguEFZRVpFM0woK2tyKCsIk04DGDOxgawyVE/Fs5duIVTMTY5DAPu3nnKcPXqfQyFV6/eZ7h75ymGOCO2pExKNDKO5gUGAHZcMhS+r1WkAAAAAElFTkSuQmCC"""
30
# Singleton ref to the loaded pixbufs
31
_twitter_pixbuf = load_base64_icon (TWITTER_ICON)
32
_identica_pixbuf = load_base64_icon (IDENTICA_ICON)
34
HANDLERS = ["TwitterModule", "IdenticaModule"]
40
"""Failed to post update to %(domain)s. Please make sure that:
42
- Your internet connection is working
43
- You can connect to <i>http://%(domain)s</i> in your web browser
44
- Your credentials in the preferences are correct
49
def __init__ (self, domain="twitter.com", update_url=TWITTER_UPDATE_URL, realm="Twitter API"):
50
self._account = Account (domain, realm)
51
self._opener = GnomeURLopener (self._account)
53
self._update_url = update_url
56
self._opener.connect ("done", self._on_opener_done)
58
def update (self, msg):
60
post_payload = urllib.urlencode({"status" : msg})
61
self._opener.open_async (self._update_url, post_payload)
62
except ConcurrentRequestsException :
63
LOGGER.warning ("Attempting to post while another post is already running. Ignoring")
64
error = gtk.MessageDialog (None,
65
type=gtk.MESSAGE_WARNING,
66
buttons=gtk.BUTTONS_OK)
67
error.set_markup (_("A post is already awaiting submission, please wait before you post another message"))
68
error.set_title (_("Error posting to %s" % self._domain))
74
def _on_opener_done (self, opener, info):
75
LOGGER.debug ("Got reply from %s. Success: %s" % (self._update_url, self._opener.get_success()))
76
if not self._opener.get_success() :
77
error = gtk.MessageDialog (None,
78
type=gtk.MESSAGE_WARNING,
79
buttons=gtk.BUTTONS_OK)
80
error.set_markup (_FAIL_POST % {"domain" : self._domain})
81
error.set_title (_("Error posting to %s" % self._domain))
86
class TwitterUpdateAction(deskbar.interfaces.Action):
88
def __init__(self, msg, client, domain="twitter.com", service="Twitter", pixbuf=None):
89
deskbar.interfaces.Action.__init__ (self, msg)
91
global _twitter_pixbuf
96
self._service = service
98
if pixbuf : self._pixbuf = pixbuf
99
else : self._pixbuf = _twitter_pixbuf
102
return "%s:%s" % (self._service,self._msg)
105
# We use only pixbufs
108
def get_pixbuf(self) :
111
def activate(self, text=None):
112
LOGGER.info ("Posting: '%s'" % self._msg)
114
self._client.update (self._msg)
116
LOGGER.warning ("Failed to post to %s: %s" % (self._domain,e))
117
error = gtk.MessageDialog (None,
118
type=gtk.MESSAGE_WARNING,
119
buttons=gtk.BUTTONS_OK)
120
error.set_markup (_FAIL_POST % {"domain" : self._domain})
121
error.set_title (_("Error posting to %s" % self._domain))
127
return _('<small>(%(remain)s)</small> Post <i>"%(msg)s"</i>')
129
def get_tooltip(self, text=None):
130
return _("Update your %s account with the message:\n\n\t<i>%s</i>") % (self._service_name, self._msg)
132
def get_name(self, text=None):
133
return {"name": self._msg, "msg" : self._msg, "remain" : str(140 - len(self._msg))}
135
def skip_history(self):
138
class TwitterMatch(deskbar.interfaces.Match):
140
def __init__(self, msg, client, domain="twitter.com", service="Twitter", pixbuf=None, **args):
141
global _twitter_pixbuf
143
self._service = service
144
self._domain = domain
146
if pixbuf : self._pixbuf = pixbuf
147
else : self._pixbuf = _twitter_pixbuf
149
deskbar.interfaces.Match.__init__ (self,
155
action = TwitterUpdateAction(self.get_name(), client,
157
service=self._service,
159
self.add_action(action)
162
return "%s:%s" % (self._service,self.get_name())
164
class TwitterModule(deskbar.interfaces.Module):
166
INFOS = {'icon': _twitter_pixbuf,
167
'name': _("Twitter"),
168
'description': _("Post updates to your Twitter account"),
171
def __init__(self, domain="twitter.com", service="Twitter", pixbuf=None, update_url=TWITTER_UPDATE_URL, realm="Twitter API"):
172
global _twitter_pixbuf
174
deskbar.interfaces.Module.__init__(self)
176
self._domain = domain
177
self._service = service
180
if pixbuf : self._pixbuf = pixbuf
181
else : self._pixbuf = _twitter_pixbuf
183
self._client = TwitterClient(domain=self._domain, update_url=update_url, realm=self._realm)
185
def query(self, qstring):
186
if len (qstring) <= MIN_MESSAGE_LEN and \
187
len (qstring) > 140: return None
189
match = TwitterMatch(qstring, self._client,
191
service=self._service,
194
self._emit_query_ready(qstring, [match])
196
def has_config(self):
199
def show_config(self, parent):
200
LOGGER.debug ("Showing config")
201
account = Account (self._domain, self._realm)
203
login_dialog = AccountDialog(account)
204
login_dialog.show_all()
206
login_dialog.destroy()
208
def get_domain (self):
211
class IdenticaModule(TwitterModule):
213
INFOS = {'icon': _identica_pixbuf,
214
'name': _("identi.ca"),
215
'description': _("Post updates to your identi.ca account"),
219
TwitterModule.__init__(self,
222
pixbuf=_identica_pixbuf,
223
update_url=IDENTICA_UPDATE_URL,
224
realm="Laconica API")