|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
1 |
#!/usr/bin/env python
|
|
674.2.1
by Behrooz
Added proper support for RTL messages |
2 |
# -*- coding: utf-8 -*-
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
3 |
|
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
4 |
import multiprocessing, threading, traceback, json, time |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
5 |
import gobject, dbus, dbus.service, mx.DateTime |
|
599
by Ryan Paul
Added support for Qaiku |
6 |
import twitter, identica, statusnet, flickr, facebook |
|
674.6.4
by Travis B. Hartwell
Remove unused import. |
7 |
import qaiku, friendfeed, digg |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
8 |
|
|
527
by Ken VanDine
Ported urlshortening |
9 |
import urlshorter |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
10 |
import util, util.couch |
|
674.1.37
by Ken VanDine
MapAsync doesn't need to inherit from threading.Thread |
11 |
import util.keyring |
|
490.7.7
by Ken VanDine
fixed some imports |
12 |
from util import log |
|
490.7.6
by Ken VanDine
* Added a new console logger with the -o arg to gwibber-daemon |
13 |
from util import resources |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
14 |
from util.couch import Monitor as CouchMonitor |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
15 |
from util.couch import RecordMonitor |
|
693
by Ken VanDine
Raise account dialog when password is missing from the keyring |
16 |
from util import exceptions |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
17 |
from desktopcouch.records.server import CouchDatabase |
18 |
from desktopcouch.records.record import Record as CouchRecord |
|
|
674.2.1
by Behrooz
Added proper support for RTL messages |
19 |
import re |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
20 |
from util.const import * |
21 |
||
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
22 |
try: |
23 |
import indicate |
|
24 |
except: |
|
25 |
indicate = None |
|
26 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
27 |
gobject.threads_init() |
28 |
||
|
490.7.1
by Ken VanDine
* Log to a file |
29 |
log.logger.name = "Gwibber Dispatcher" |
30 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
31 |
PROTOCOLS = { |
32 |
"twitter": twitter, |
|
33 |
"identica": identica, |
|
34 |
"flickr": flickr, |
|
|
490.2.27
by Ken VanDine
start of accounts admin for facebook |
35 |
"facebook": facebook, |
|
490.1.11
by Ryan Paul
Updated the FriendFeed module to make it compatible with the new backend |
36 |
"friendfeed": friendfeed, |
|
596
by Ryan Paul
Added support for StatusNet |
37 |
"statusnet": statusnet, |
|
597
by Ryan Paul
Added support for Digg |
38 |
"digg": digg, |
|
599
by Ryan Paul
Added support for Qaiku |
39 |
"qaiku": qaiku, |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
40 |
}
|
41 |
||
|
490.1.3
by Ryan Paul
Fixed the startup scripts in bin |
42 |
FEATURES = json.loads(GWIBBER_OPERATIONS) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
43 |
SERVICES = dict([(k, v.PROTOCOL_INFO) for k, v in PROTOCOLS.items()]) |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
44 |
SETTINGS = RecordMonitor(COUCH_DB_SETTINGS, COUCH_RECORD_SETTINGS, COUCH_TYPE_CONFIG, DEFAULT_SETTINGS) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
45 |
|
46 |
def perform_operation((acctid, opname, args, transient)): |
|
47 |
try: |
|
48 |
stream = FEATURES[opname]["stream"] or opname |
|
49 |
accounts = CouchDatabase(COUCH_DB_ACCOUNTS, create=True) |
|
50 |
messages = CouchDatabase(COUCH_DB_MESSAGES, create=True) |
|
51 |
account = dict(accounts.get_record(acctid).items()) |
|
52 |
||
|
711
by Ken VanDine
Fix handling of raising the keyring error (LP: #539781) |
53 |
if not 'failed_id' in globals(): |
54 |
global failed_id |
|
55 |
failed_id = [] |
|
56 |
||
|
674.1.16
by Ryan Paul
Use the keyring to store private account fields |
57 |
for key, val in account.items(): |
58 |
if isinstance(val, str) and val.startswith(":KEYRING:"): |
|
|
674.1.37
by Ken VanDine
MapAsync doesn't need to inherit from threading.Thread |
59 |
value = util.keyring.get_account_password(account["_id"]) |
|
674.6.1
by Travis B. Hartwell
First pass at fixing LP: #554005 |
60 |
|
61 |
if value is None: |
|
|
711
by Ken VanDine
Fix handling of raising the keyring error (LP: #539781) |
62 |
if account["_id"] not in failed_id: |
63 |
log.logger.debug("Adding %s to failed_id global", account["_id"]) |
|
64 |
failed_id.append(account["_id"]) |
|
65 |
log.logger.debug("Raising error to resolve failure for %s", account["_id"]) |
|
66 |
raise exceptions.GwibberProtocolError("keyring") |
|
|
693
by Ken VanDine
Raise account dialog when password is missing from the keyring |
67 |
return ("Failure", 0) |
|
674.1.16
by Ryan Paul
Use the keyring to store private account fields |
68 |
|
69 |
account[key] = value |
|
70 |
||
|
490.1.4
by Ryan Paul
Make dispatcher use logging module for debug instead of print statements |
71 |
logtext = "<%s:%s>" % (account["protocol"], opname) |
|
490.7.1
by Ken VanDine
* Log to a file |
72 |
log.logger.debug("%s Performing operation", logtext) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
73 |
|
|
502
by Ryan Paul
Added support for liking and deleting messages |
74 |
args = dict((str(k), v) for k, v in args.items()) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
75 |
message_data = PROTOCOLS[account["protocol"]].Client(account)(opname, **args) |
76 |
new_messages = [] |
|
|
674.2.1
by Behrooz
Added proper support for RTL messages |
77 |
text_cleaner = re.compile(u"[: \n\t\r♻♺]+|@[^ ]+|![^ ]+|#[^ ]+") # signs, @nickname, !group, #tag |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
78 |
|
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
79 |
if message_data is not None: |
80 |
for m in message_data: |
|
|
699
by Ken VanDine
use has_key instead of hasattr to check for message contents |
81 |
if m.has_key("id"): |
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
82 |
key = (m["id"], m["account"], opname, transient) |
83 |
key = "-".join(x for x in key if x) |
|
|
744
by Ken VanDine
Drop the responses operation from facebook, it abuses the |
84 |
m["operation"] = opname |
85 |
m["stream"] = stream |
|
86 |
m["transient"] = transient |
|
87 |
m["rtl"] = util.isRTL(re.sub(text_cleaner, "", m["text"].decode('utf-8'))) |
|
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
88 |
if not messages.record_exists(key): |
89 |
log.logger.debug("%s Adding record", logtext) |
|
90 |
new_messages.append(m) |
|
91 |
messages.put_record(CouchRecord(m, COUCH_TYPE_MESSAGE, key)) |
|
|
744
by Ken VanDine
Drop the responses operation from facebook, it abuses the |
92 |
else: |
93 |
if m.has_key("comments"): |
|
94 |
try: |
|
95 |
if m["comments"] > 0 and m["comments"] != dict(messages.get_record(key).items())["comments"]: |
|
96 |
log.logger.debug("%s Updating record", logtext) |
|
97 |
messages.update_fields(key, m) |
|
98 |
except: |
|
99 |
pass
|
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
100 |
|
|
490.7.1
by Ken VanDine
* Log to a file |
101 |
log.logger.debug("%s Finished operation", logtext) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
102 |
return ("Success", new_messages) |
103 |
except Exception as e: |
|
|
490.1.4
by Ryan Paul
Make dispatcher use logging module for debug instead of print statements |
104 |
if not "logtext" in locals(): logtext = "<UNKNOWN>" |
|
490.7.4
by Ken VanDine
set somethings to log using the error level |
105 |
log.logger.error("%s Operation failed", logtext) |
|
490.7.1
by Ken VanDine
* Log to a file |
106 |
log.logger.debug("Traceback:\n%s", traceback.format_exc()) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
107 |
return ("Failure", traceback.format_exc()) |
108 |
||
109 |
class OperationCollector: |
|
110 |
def __init__(self): |
|
111 |
self.accounts = CouchDatabase(COUCH_DB_ACCOUNTS, create=True) |
|
112 |
self.settings = CouchDatabase(COUCH_DB_SETTINGS, create=True) |
|
113 |
self.messages = CouchDatabase(COUCH_DB_MESSAGES, create=True) |
|
114 |
||
115 |
def handle_max_id(self, acct, opname, id=None): |
|
116 |
if not id: id = acct["_id"] |
|
117 |
if "sinceid" in SERVICES[acct["protocol"]]["features"]: |
|
118 |
view = self.messages.execute_view("maxid", "messages") |
|
119 |
result = view[[id, opname]][[id, opname]].rows |
|
120 |
if len(result) > 0: return {"since": result[0].value} |
|
121 |
return {} |
|
122 |
||
123 |
def validate_operation(self, acct, opname, enabled="receive_enabled"): |
|
124 |
protocol = SERVICES[acct["protocol"]] |
|
125 |
return acct["protocol"] in PROTOCOLS and \ |
|
126 |
opname in protocol["features"] and \ |
|
127 |
opname in FEATURES and acct[enabled] |
|
128 |
||
|
490.1.25
by Ryan Paul
Perform operation immediately when transient stream is created |
129 |
def stream_to_operation(self, stream): |
130 |
account = self.accounts.get_record(stream["account"]) |
|
131 |
args = stream["parameters"] |
|
132 |
opname = stream["operation"] |
|
133 |
if self.validate_operation(account, opname): |
|
134 |
args.update(self.handle_max_id(account, opname, stream["_id"])) |
|
135 |
return (stream["account"], stream["operation"], args, stream["_id"]) |
|
136 |
||
|
506.1.4
by Ryan Paul
Added support for search in single stream mode |
137 |
def search_to_operations(self, search): |
138 |
for account in self.accounts.get_records(COUCH_TYPE_ACCOUNT, True): |
|
139 |
account = account.value |
|
140 |
args = {"query": search["query"]} |
|
141 |
if self.validate_operation(account, "search"): |
|
142 |
args.update(self.handle_max_id(account, "search", search["_id"])) |
|
143 |
yield (account["_id"], "search", args, search["_id"]) |
|
144 |
||
|
540
by Ryan Paul
Force account to refresh when it is created |
145 |
def account_to_operations(self, acct): |
146 |
if isinstance(acct, basestring): |
|
147 |
acct = dict(self.accounts.get_record(acct).items()) |
|
148 |
for opname in SERVICES[acct["protocol"]]["default_streams"]: |
|
149 |
if self.validate_operation(acct, opname): |
|
150 |
args = self.handle_max_id(acct, opname) |
|
151 |
yield (acct["_id"], opname, args, False) |
|
152 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
153 |
def get_send_operations(self, message): |
|
490.1.6
by Ryan Paul
Make sure that the CouchDB databases all get properly initialized |
154 |
for account in self.accounts.get_records(COUCH_TYPE_ACCOUNT, True): |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
155 |
account = account.value |
156 |
if self.validate_operation(account, "send", "send_enabled"): |
|
|
490.1.25
by Ryan Paul
Perform operation immediately when transient stream is created |
157 |
yield (account["_id"], "send", {"message": message}, False) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
158 |
|
|
490.1.25
by Ryan Paul
Perform operation immediately when transient stream is created |
159 |
def get_operation_by_id(self, id): |
160 |
if self.settings.record_exists(id): |
|
161 |
item = dict(self.settings.get_record(id).items()) |
|
162 |
if item["record_type"] == COUCH_TYPE_STREAM: |
|
|
506.1.4
by Ryan Paul
Added support for search in single stream mode |
163 |
return [self.stream_to_operation(item)] |
164 |
if item["record_type"] == COUCH_TYPE_SEARCH: |
|
165 |
return list(self.search_to_operations(item)) |
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
166 |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
167 |
def get_operations(self): |
|
490.1.6
by Ryan Paul
Make sure that the CouchDB databases all get properly initialized |
168 |
for acct in self.accounts.get_records(COUCH_TYPE_ACCOUNT, True): |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
169 |
acct = acct.value |
|
540
by Ryan Paul
Force account to refresh when it is created |
170 |
for o in self.account_to_operations(acct): |
171 |
yield o |
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
172 |
|
|
490.1.6
by Ryan Paul
Make sure that the CouchDB databases all get properly initialized |
173 |
for stream in self.settings.get_records(COUCH_TYPE_STREAM, True): |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
174 |
stream = stream.value |
175 |
if self.accounts.record_exists(stream["account"]): |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
176 |
o = self.stream_to_operation(stream) |
177 |
if o: yield o |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
178 |
|
|
490.1.6
by Ryan Paul
Make sure that the CouchDB databases all get properly initialized |
179 |
for search in self.settings.get_records(COUCH_TYPE_SEARCH, True): |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
180 |
search = search.value |
|
506.1.4
by Ryan Paul
Added support for search in single stream mode |
181 |
for o in self.search_to_operations(search): |
182 |
yield o |
|
|
490.1.22
by Ryan Paul
Improved default handling for RecordMonitor |
183 |
|
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
184 |
class StreamMonitor(dbus.service.Object): |
185 |
__dbus_object_path__ = "/com/gwibber/Streams" |
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
186 |
|
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
187 |
def __init__(self): |
188 |
self.bus = dbus.SessionBus() |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
189 |
bus_name = dbus.service.BusName("com.Gwibber.Streams", bus=self.bus) |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
190 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
191 |
||
192 |
setting_monitor = CouchMonitor(COUCH_DB_SETTINGS) |
|
193 |
setting_monitor.connect("record-updated", self.on_setting_changed) |
|
194 |
setting_monitor.connect("record-deleted", self.on_setting_deleted) |
|
195 |
||
196 |
def on_setting_changed(self, monitor, id): |
|
197 |
if id == "settings": self.SettingChanged() |
|
198 |
else: |
|
|
490.7.6
by Ken VanDine
* Added a new console logger with the -o arg to gwibber-daemon |
199 |
log.logger.debug("Stream changed: %s", id) |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
200 |
self.StreamChanged(id) |
201 |
||
202 |
def on_setting_deleted(self, monitor, id): |
|
|
490.7.6
by Ken VanDine
* Added a new console logger with the -o arg to gwibber-daemon |
203 |
log.logger.debug("Stream closed: %s", id) |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
204 |
self.StreamClosed(id) |
205 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
206 |
@dbus.service.signal("com.Gwibber.Streams", signature="s") |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
207 |
def StreamChanged(self, id): pass |
208 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
209 |
@dbus.service.signal("com.Gwibber.Streams", signature="s") |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
210 |
def StreamClosed(self, id): pass |
211 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
212 |
@dbus.service.signal("com.Gwibber.Streams") |
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
213 |
def SettingChanged(self): pass |
214 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
215 |
class AccountMonitor(dbus.service.Object): |
216 |
__dbus_object_path__ = "/com/gwibber/Accounts" |
|
217 |
||
218 |
def __init__(self): |
|
219 |
self.bus = dbus.SessionBus() |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
220 |
bus_name = dbus.service.BusName("com.Gwibber.Accounts", bus=self.bus) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
221 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
222 |
||
|
490.1.20
by Ryan Paul
Make the navigation update when transient streams are added or removed |
223 |
account_monitor = CouchMonitor(COUCH_DB_ACCOUNTS) |
224 |
account_monitor.connect("record-updated", self.on_account_changed) |
|
225 |
account_monitor.connect("record-deleted", self.on_account_deleted) |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
226 |
|
227 |
def on_account_changed(self, monitor, id): |
|
|
490.7.1
by Ken VanDine
* Log to a file |
228 |
log.logger.debug("Account changed: %s", id) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
229 |
self.AccountChanged(id) |
230 |
||
231 |
def on_account_deleted(self, monitor, id): |
|
|
490.7.1
by Ken VanDine
* Log to a file |
232 |
log.logger.debug("Account deleted: %s", id) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
233 |
self.AccountDeleted(id) |
234 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
235 |
@dbus.service.signal("com.Gwibber.Accounts", signature="s") |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
236 |
def AccountChanged(self, id): pass |
237 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
238 |
@dbus.service.signal("com.Gwibber.Accounts", signature="s") |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
239 |
def AccountDeleted(self, id): pass |
240 |
||
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
241 |
class MessagesMonitor(dbus.service.Object): |
242 |
__dbus_object_path__ = "/com/gwibber/Messages" |
|
243 |
||
244 |
def __init__(self): |
|
245 |
self.bus = dbus.SessionBus() |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
246 |
bus_name = dbus.service.BusName("com.Gwibber.Messages", bus=self.bus) |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
247 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
248 |
||
|
647
by Ken VanDine
Moved the init_design_doc method call to MessageMonitor, this fixes a bug loading the design document before it is created |
249 |
self.messages = CouchDatabase(COUCH_DB_MESSAGES, create=True) |
250 |
util.couch.init_design_doc(self.messages, "messages", COUCH_VIEW_MESSAGES) |
|
|
674.1.16
by Ryan Paul
Use the keyring to store private account fields |
251 |
#util.couch.exclude_databases(["gwibber_messages"])
|
|
647
by Ken VanDine
Moved the init_design_doc method call to MessageMonitor, this fixes a bug loading the design document before it is created |
252 |
|
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
253 |
self.monitor = CouchMonitor(COUCH_DB_MESSAGES) |
254 |
self.monitor.connect("record-updated", self.on_message_updated) |
|
255 |
||
256 |
self.indicator_items = {} |
|
257 |
self.notified_items = [] |
|
258 |
||
|
515
by Ken VanDine
- Don't use the indicator if we can't find a desktop file |
259 |
if indicate and util.resources.get_desktop_file(): |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
260 |
self.indicate = indicate.indicate_server_ref_default() |
261 |
self.indicate.set_type("message.gwibber") |
|
|
515
by Ken VanDine
- Don't use the indicator if we can't find a desktop file |
262 |
self.indicate.set_desktop_file(util.resources.get_desktop_file()) |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
263 |
self.indicate.connect("server-display", self.on_indicator_activate) |
264 |
self.indicate.show() |
|
265 |
||
266 |
def on_message_updated(self, monitor, id): |
|
|
490.5.3
by Ken VanDine
* make config values in PROTOCOL_INFO required for account data |
267 |
try: |
|
607
by Ryan Paul
Properly escape HTML so that it isn't treated as markup in the stream |
268 |
#log.logger.debug("Message updated: %s", id)
|
|
490.5.3
by Ken VanDine
* make config values in PROTOCOL_INFO required for account data |
269 |
message = self.messages.get_record(id) |
270 |
self.new_message(message) |
|
271 |
except: |
|
|
490.7.4
by Ken VanDine
set somethings to log using the error level |
272 |
log.logger.error("Message updated: %s, failed", id) |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
273 |
|
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
274 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
275 |
@dbus.service.signal("com.Gwibber.Messages", signature="s") |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
276 |
def MessageUpdated(self, id): pass |
277 |
||
|
576
by Ken VanDine
* removed an import for gtk |
278 |
def on_indicator_activate(self, indicator, timestamp): |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
279 |
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
280 |
client_bus = dbus.SessionBus() |
|
|
490.7.1
by Ken VanDine
* Log to a file |
281 |
log.logger.debug("Raising gwibber client") |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
282 |
try: |
283 |
client_obj = client_bus.get_object("com.GwibberClient", |
|
284 |
"/com/GwibberClient", follow_name_owner_changes = True, |
|
285 |
introspect = False) |
|
286 |
gw = dbus.Interface(client_obj, "com.GwibberClient") |
|
287 |
gw.focus_client(reply_handler=self.handle_focus_reply, |
|
288 |
error_handler=self.handle_focus_error) |
|
289 |
except dbus.DBusException: |
|
|
632
by Ken VanDine
fixed failed calls to print_exc |
290 |
traceback.print_exc() |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
291 |
|
292 |
||
|
576
by Ken VanDine
* removed an import for gtk |
293 |
def on_indicator_reply_activate(self, indicator, timestamp): |
|
490.7.1
by Ken VanDine
* Log to a file |
294 |
log.logger.debug("Raising gwibber client, focusing replies stream") |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
295 |
client_bus = dbus.SessionBus() |
296 |
try: |
|
297 |
client_obj = client_bus.get_object("com.GwibberClient", "/com/GwibberClient") |
|
298 |
gw = dbus.Interface(client_obj, "com.GwibberClient") |
|
299 |
gw.show_replies(reply_handler=self.handle_focus_reply, |
|
300 |
error_handler=self.handle_focus_error) |
|
301 |
indicator.hide() |
|
302 |
except dbus.DBusException: |
|
|
632
by Ken VanDine
fixed failed calls to print_exc |
303 |
traceback.print_exc() |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
304 |
|
|
519
by Ken VanDine
Really raise the client when called |
305 |
def handle_focus_reply(self, *args): |
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
306 |
log.logger.debug("Gwibber Client raised") |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
307 |
|
|
519
by Ken VanDine
Really raise the client when called |
308 |
def handle_focus_error(self, *args): |
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
309 |
log.logger.error("Failed to raise client %s", args) |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
310 |
|
311 |
def new_message(self, message): |
|
312 |
min_time = mx.DateTime.DateTimeFromTicks() - mx.DateTime.TimeDelta(minutes=10.0) |
|
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
313 |
log.logger.debug("Checking message %s timestamp (%s) to see if it is newer than %s", message["id"], mx.DateTime.DateTimeFromTicks(message["time"]).localtime(), min_time) |
|
490.2.25
by Ken VanDine
compare timestamps using localtime and added a little more logging |
314 |
if mx.DateTime.DateTimeFromTicks(message["time"]).localtime() > mx.DateTime.DateTimeFromTicks(min_time): |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
315 |
log.logger.debug("Message %s newer than %s, notifying", message["id"], min_time) |
|
632.2.1
by Ken VanDine
Fixed notifications for mentions only |
316 |
if indicate and message["to_me"]: |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
317 |
if message["id"] not in self.indicator_items: |
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
318 |
log.logger.debug("Message %s is a reply, adding messaging indicator", message["id"]) |
319 |
self.handle_indicator_item(message) |
|
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
320 |
if message["id"] not in self.notified_items: |
321 |
self.notified_items.append(message["id"]) |
|
322 |
self.show_notification_bubble(message) |
|
323 |
||
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
324 |
def handle_indicator_item(self, message): |
325 |
indicator = indicate.Indicator() if hasattr(indicate, "Indicator") else indicate.IndicatorMessage() |
|
326 |
indicator.connect("user-display", self.on_indicator_reply_activate) |
|
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
327 |
indicator.set_property("subtype", "im.gwibber") |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
328 |
indicator.set_property("sender", message["sender"].get("name", "")) |
329 |
indicator.set_property("body", message["text"]) |
|
330 |
indicator.set_property_time("time", |
|
331 |
mx.DateTime.DateTimeFromTicks(message["time"]).localtime().ticks()) |
|
332 |
self.indicator_items[message["id"]] = indicator |
|
333 |
indicator.show() |
|
|
615
by Ken VanDine
* fixed a bug that prevented mentions/replies to get added to the messaging indicator |
334 |
log.logger.debug("Message from %s added to indicator", message["sender"].get("name", "")) |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
335 |
|
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
336 |
def show_notification_bubble(self, message): |
|
490.1.23
by Ryan Paul
Respect the user's notification settings |
337 |
if util.can_notify and SETTINGS["show_notifications"]: |
|
632.2.1
by Ken VanDine
Fixed notifications for mentions only |
338 |
if SETTINGS["notify_mentions_only"] and not message["to_me"]: return |
|
695
by Ken VanDine
Respect full name preference in notification bubbles |
339 |
|
340 |
if SETTINGS["show_fullname"]: |
|
341 |
sender_name = message["sender"].get("name", 0) or data["sender"].get("nick", "") |
|
342 |
else: |
|
343 |
sender_name = message["sender"].get("nick", 0) or data["sender"].get("name", "") |
|
344 |
||
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
345 |
#until image caching is working again, we will post the gwibber icon
|
346 |
#image = hasattr(message, "image_path") and message["image_path"] or ''
|
|
|
490.5.5
by Ken VanDine
* Moved the gtk widgets from gwibber.microblog.gtk to gwibber.lib.gtk |
347 |
image = util.resources.get_ui_asset("gwibber.svg") |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
348 |
expire_timeout = 5000 |
|
695
by Ken VanDine
Respect full name preference in notification bubbles |
349 |
n = util.notify(sender_name, message["text"], image, expire_timeout) |
|
490.2.23
by Ken VanDine
added notifications and messaging indicator support |
350 |
|
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
351 |
class MapAsync(threading.Thread): |
|
727
by Ken VanDine
bump the timeout for each thread to allow enough time for pycurl to finish (or timeout) |
352 |
def __init__(self, func, iterable, cbsuccess, cbfailure, timeout=240): |
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
353 |
threading.Thread.__init__(self) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
354 |
self.iterable = iterable |
355 |
self.callback = cbsuccess |
|
356 |
self.failure = cbfailure |
|
357 |
self.timeout = timeout |
|
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
358 |
self.daemon = True |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
359 |
self.func = func |
|
674.1.42
by Ken VanDine
* revert the change dropping threading from MapAsync, without it there is some blocking. |
360 |
self.start() |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
361 |
|
362 |
def run(self): |
|
363 |
try: |
|
364 |
pool = multiprocessing.Pool() |
|
|
727
by Ken VanDine
bump the timeout for each thread to allow enough time for pycurl to finish (or timeout) |
365 |
pool.map_async(self.func, self.iterable, callback=self.callback).get(timeout=self.timeout) |
|
490.1.4
by Ryan Paul
Make dispatcher use logging module for debug instead of print statements |
366 |
except Exception as e: |
367 |
self.failure(e, traceback.format_exc()) |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
368 |
|
|
696.1.1
by Ken VanDine
don't make Dispatcher inherit from thread.Threading, it isn't actually used |
369 |
class Dispatcher(dbus.service.Object): |
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
370 |
"""
|
371 |
The Gwibber Dispatcher handles all the backend operations.
|
|
372 |
"""
|
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
373 |
__dbus_object_path__ = "/com/gwibber/Service" |
374 |
||
375 |
def __init__(self, loop, autorefresh=True): |
|
376 |
self.bus = dbus.SessionBus() |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
377 |
bus_name = dbus.service.BusName("com.Gwibber.Service", bus=self.bus) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
378 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
379 |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
380 |
self.collector = OperationCollector() |
381 |
||
382 |
self.refresh_count = 0 |
|
383 |
self.mainloop = loop |
|
384 |
||
|
674.6.6
by Travis B. Hartwell
Move loading account passwords to the Dispatcher class and expose it |
385 |
self.RefreshCreds() |
386 |
||
|
740
by Ken VanDine
Ensure there is always only one refresh timer (LP: #595265) |
387 |
self.refresh_timer_id = None |
388 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
389 |
if autorefresh: |
390 |
self.refresh() |
|
391 |
||
|
490.2.4
by Ken VanDine
merged |
392 |
self.accounts = CouchDatabase(COUCH_DB_ACCOUNTS, create=True) |
393 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
394 |
@dbus.service.signal("com.Gwibber.Service") |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
395 |
def LoadingComplete(self): pass |
396 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
397 |
@dbus.service.signal("com.Gwibber.Service") |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
398 |
def LoadingStarted(self): pass |
399 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
400 |
@dbus.service.method("com.Gwibber.Service") |
|
674.1.12
by Ryan Paul
Added support for automatically compacting the database every 20 refresh cycles |
401 |
def CompactDB(self): |
402 |
log.logger.debug("Compacting the database") |
|
403 |
self.collector.messages.db.compact() |
|
404 |
||
405 |
@dbus.service.method("com.Gwibber.Service") |
|
|
599.1.1
by Ken VanDine
Added some doc strings |
406 |
def Refresh(self): |
407 |
"""
|
|
408 |
Calls the Gwibber Service to trigger a refresh operation
|
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
409 |
example:
|
410 |
import dbus
|
|
411 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
412 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
413 |
service.Refresh()
|
|
414 |
||
|
599.1.1
by Ken VanDine
Added some doc strings |
415 |
"""
|
416 |
self.refresh() |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
417 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
418 |
@dbus.service.method("com.Gwibber.Service", in_signature="s") |
|
490.1.26
by Ryan Paul
Added support for replies |
419 |
def PerformOp(self, opdata): |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
420 |
try: o = json.loads(opdata) |
421 |
except: return |
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
422 |
|
|
490.7.10
by Ken VanDine
Merged the NM branch |
423 |
log.logger.debug("** Starting Single Operation **") |
|
490.1.26
by Ryan Paul
Added support for replies |
424 |
self.LoadingStarted() |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
425 |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
426 |
params = ["account", "operation", "args", "transient"] |
427 |
operation = None |
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
428 |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
429 |
if "id" in o: |
430 |
operation = self.collector.get_operation_by_id(o["id"]) |
|
431 |
elif all(i in o for i in params): |
|
|
506.1.4
by Ryan Paul
Added support for search in single stream mode |
432 |
operation = [tuple(o[i] for i in params)] |
|
540
by Ryan Paul
Force account to refresh when it is created |
433 |
elif "account" in o and self.accounts.record_exists(o["account"]): |
434 |
operation = self.collector.account_to_operations(o["account"]) |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
435 |
|
436 |
if operation: |
|
|
506.1.4
by Ryan Paul
Added support for search in single stream mode |
437 |
MapAsync(perform_operation, operation, self.loading_complete, self.loading_failed) |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
438 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
439 |
@dbus.service.method("com.Gwibber.Service", in_signature="s") |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
440 |
def SendMessage(self, message): |
|
599.1.1
by Ken VanDine
Added some doc strings |
441 |
"""
|
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
442 |
Posts a message/status update to all accounts with send_enabled = True. It
|
|
599.1.1
by Ken VanDine
Added some doc strings |
443 |
takes one argument, which is a message formated as a string.
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
444 |
example:
|
445 |
import dbus
|
|
446 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
447 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
448 |
service.SendMessage("Your message")
|
|
|
599.1.1
by Ken VanDine
Added some doc strings |
449 |
"""
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
450 |
self.send(self.collector.get_send_operations(message)) |
451 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
452 |
@dbus.service.method("com.Gwibber.Service", in_signature="s") |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
453 |
def Send(self, opdata): |
|
497
by Ryan Paul
Fixed retweeting and added support for more formats |
454 |
try: |
455 |
o = json.loads(opdata) |
|
456 |
if "target" in o: |
|
457 |
args = {"message": o["message"], "target": o["target"]} |
|
458 |
operations = [(o["target"]["account"], "send_thread", args, None)] |
|
459 |
elif "accounts" in o: |
|
460 |
operations = [(a, "send", {"message": o["message"]}, None) for a in o["accounts"]] |
|
461 |
self.send(operations) |
|
462 |
except: pass |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
463 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
464 |
@dbus.service.method("com.Gwibber.Service", out_signature="s") |
|
599.1.1
by Ken VanDine
Added some doc strings |
465 |
def GetServices(self): |
466 |
"""
|
|
467 |
Returns a list of services available as json string
|
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
468 |
example:
|
469 |
import dbus, json
|
|
470 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
471 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
472 |
services = json.loads(service.GetServices())
|
|
473 |
||
|
599.1.1
by Ken VanDine
Added some doc strings |
474 |
"""
|
475 |
return json.dumps(SERVICES) |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
476 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
477 |
@dbus.service.method("com.Gwibber.Service", out_signature="s") |
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
478 |
def GetFeatures(self): |
479 |
"""
|
|
480 |
Returns a list of features as json string
|
|
481 |
example:
|
|
482 |
import dbus, json
|
|
483 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
484 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
485 |
features = json.loads(service.GetFeatures())
|
|
486 |
"""
|
|
487 |
return json.dumps(FEATURES) |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
488 |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
489 |
@dbus.service.method("com.Gwibber.Service", out_signature="s") |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
490 |
def GetAccounts(self): |
|
599.1.1
by Ken VanDine
Added some doc strings |
491 |
"""
|
492 |
Returns a list of accounts as json string
|
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
493 |
example:
|
494 |
import dbus, json
|
|
495 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
496 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
497 |
accounts = json.loads(service.GetAccounts())
|
|
|
599.1.1
by Ken VanDine
Added some doc strings |
498 |
"""
|
|
490.2.4
by Ken VanDine
merged |
499 |
all_accounts = [] |
500 |
for account in self.accounts.get_records(COUCH_TYPE_ACCOUNT, True): |
|
501 |
all_accounts.append(account.value) |
|
502 |
return json.dumps(all_accounts) |
|
503 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
504 |
@dbus.service.method("com.Gwibber.Service") |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
505 |
def Quit(self): |
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
506 |
"""
|
|
674.1.22
by Ken VanDine
fixed a typo |
507 |
Shutdown the service
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
508 |
example:
|
509 |
import dbus
|
|
510 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
511 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
512 |
service.Quit()
|
|
513 |
"""
|
|
|
622
by Ken VanDine
log quit and close events in the client and service |
514 |
log.logger.info("Gwibber Service is being shutdown") |
515 |
self.mainloop.quit() |
|
|
674.6.6
by Travis B. Hartwell
Move loading account passwords to the Dispatcher class and expose it |
516 |
|
517 |
@dbus.service.method("com.Gwibber.Service") |
|
518 |
def RefreshCreds(self): |
|
519 |
"""
|
|
520 |
Reload accounts and credentials from Gnome Keyring
|
|
521 |
example:
|
|
522 |
import dbus
|
|
523 |
obj = dbus.SessionBus().get_object("com.Gwibber.Service", "/com/gwibber/Service")
|
|
524 |
service = dbus.Interface(obj, "com.Gwibber.Service")
|
|
525 |
service.RefreshCreds()
|
|
526 |
"""
|
|
527 |
log.logger.info("Gwibber Service is reloading account credentials") |
|
528 |
util.keyring.get_account_passwords() |
|
529 |
||
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
530 |
def loading_complete(self, output): |
531 |
self.refresh_count += 1 |
|
532 |
self.LoadingComplete() |
|
|
490.7.6
by Ken VanDine
* Added a new console logger with the -o arg to gwibber-daemon |
533 |
log.logger.info("Loading complete: %s - %s", self.refresh_count, [o[0] for o in output]) |
|
674.1.12
by Ryan Paul
Added support for automatically compacting the database every 20 refresh cycles |
534 |
if self.refresh_count % 20 == 0 and self.refresh_count > 1: |
535 |
self.CompactDB() |
|
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
536 |
|
|
490.1.4
by Ryan Paul
Make dispatcher use logging module for debug instead of print statements |
537 |
def loading_failed(self, exception, tb): |
|
490.7.4
by Ken VanDine
set somethings to log using the error level |
538 |
log.logger.error("Loading failed: %s - %s", exception, tb) |
|
490.1.1
by Ryan Paul
Major refactoring for Gwibber 2.30 |
539 |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
540 |
def send(self, operations): |
541 |
operations = util.compact(operations) |
|
542 |
if operations: |
|
543 |
self.LoadingStarted() |
|
|
601
by Ken VanDine
fixed merge breakage |
544 |
log.logger.debug("*** Sending Message ***") |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
545 |
MapAsync(perform_operation, operations, self.loading_complete, self.loading_failed) |
546 |
||
|
740
by Ken VanDine
Ensure there is always only one refresh timer (LP: #595265) |
547 |
def refresh(self): |
548 |
if self.refresh_timer_id: |
|
549 |
gobject.source_remove(self.refresh_timer_id) |
|
550 |
log.logger.info("Refresh interval is set to %s", SETTINGS["interval"]) |
|
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
551 |
operations = list(self.collector.get_operations()) |
552 |
if operations: |
|
|
740
by Ken VanDine
Ensure there is always only one refresh timer (LP: #595265) |
553 |
log.logger.info("** Starting Refresh - %s **", time.asctime()) |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
554 |
self.LoadingStarted() |
555 |
MapAsync(perform_operation, operations, self.loading_complete, self.loading_failed) |
|
|
740
by Ken VanDine
Ensure there is always only one refresh timer (LP: #595265) |
556 |
self.refresh_timer_id = gobject.timeout_add_seconds(int(60 * SETTINGS["interval"]), self.refresh) |
|
694
by Ken VanDine
Reset refresh interval to pick up changes in settings |
557 |
return False |
|
490.1.27
by Ryan Paul
Refactored message sending in the Gwibber backend |
558 |
|
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
559 |
class ConnectionMonitor(dbus.service.Object): |
560 |
__dbus_object_path__ = "/com/gwibber/Connection" |
|
561 |
||
562 |
def __init__(self): |
|
563 |
self.bus = dbus.SessionBus() |
|
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
564 |
bus_name = dbus.service.BusName("com.Gwibber.Connection", bus=self.bus) |
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
565 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
566 |
||
567 |
self.sysbus = dbus.SystemBus() |
|
|
509
by Ken VanDine
Attempt to not actually require NetworkManager, if it can't get the state from NM assume online |
568 |
try: |
569 |
self.nm = self.sysbus.get_object(NM_DBUS_SERVICE, NM_DBUS_OBJECT_PATH) |
|
570 |
self.nm.connect_to_signal("StateChanged", self.on_connection_changed) |
|
571 |
except: |
|
572 |
pass
|
|
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
573 |
|
574 |
def on_connection_changed(self, state): |
|
575 |
if state == NM_STATE_CONNECTED: |
|
|
490.7.10
by Ken VanDine
Merged the NM branch |
576 |
log.logger.info("Network state changed to Online") |
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
577 |
self.ConnectionOnline(state) |
578 |
if state == NM_STATE_DISCONNECTED: |
|
|
490.7.10
by Ken VanDine
Merged the NM branch |
579 |
log.logger.info("Network state changed to Offline") |
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
580 |
self.ConnectionOffline(state) |
581 |
||
|
632.1.1
by Ken VanDine
fixed typo that would cause the ConnectionMonitor to fail |
582 |
@dbus.service.signal("com.Gwibber.Connection", signature="u") |
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
583 |
def ConnectionOnline(self, state): pass |
584 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
585 |
@dbus.service.signal("com.Gwibber.Connection", signature="u") |
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
586 |
def ConnectionOffline(self, state): pass |
587 |
||
|
517
by Ken VanDine
* Make the dbus interface names match the object path |
588 |
@dbus.service.method("com.Gwibber.Connection") |
|
674.6.2
by Travis B. Hartwell
Undo whitespace changes made previously. |
589 |
def isConnected(self): |
|
509
by Ken VanDine
Attempt to not actually require NetworkManager, if it can't get the state from NM assume online |
590 |
try: |
|
511
by Ken VanDine
Fixed a method call |
591 |
if self.nm.state() == NM_STATE_CONNECTED: |
|
509
by Ken VanDine
Attempt to not actually require NetworkManager, if it can't get the state from NM assume online |
592 |
return True |
593 |
return False |
|
594 |
except: |
|
|
507
by Ken VanDine
set online/offline mode depending on NM_STATE |
595 |
return True |
596 |
||
|
527
by Ken VanDine
Ported urlshortening |
597 |
class URLShorten(dbus.service.Object): |
598 |
__dbus_object_path__ = "/com/gwibber/URLShorten" |
|
599 |
||
600 |
def __init__(self): |
|
601 |
self.bus = dbus.SessionBus() |
|
602 |
bus_name = dbus.service.BusName("com.Gwibber.URLShorten", bus=self.bus) |
|
603 |
dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) |
|
604 |
||
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
605 |
@dbus.service.method("com.Gwibber.URLShorten", in_signature="s", out_signature="s") |
606 |
def Shorten(self, url): |
|
607 |
"""
|
|
608 |
Takes a url as a string and returns a shortened url as a string.
|
|
609 |
example:
|
|
610 |
import dbus
|
|
611 |
url = "http://www.example.com/this/is/a/long/url"
|
|
612 |
obj = dbus.SessionBus().get_object("com.Gwibber.URLShorten", "/com/gwibber/URLShorten")
|
|
613 |
shortener = dbus.Interface(obj, "com.Gwibber.URLShorten")
|
|
614 |
short_url = shortener.Shorten(url)
|
|
615 |
"""
|
|
|
738
by Ken VanDine
Remove the tr.im urlshortener, the service is closed (LP: #583316) |
616 |
if SETTINGS["urlshorter"] in urlshorter.PROTOCOLS.keys(): |
617 |
service = SETTINGS["urlshorter"] |
|
618 |
else: |
|
619 |
service = "is.gd" |
|
|
674.1.7
by Ken VanDine
* Moved the dbus docs into docstrings in dispatcher.py |
620 |
log.logger.info("Shortening URL %s with %s", url, service) |
|
557.2.1
by Ken VanDine
Make dbus method camel case |
621 |
if self.IsShort(url): return url |
|
527
by Ken VanDine
Ported urlshortening |
622 |
try: |
623 |
s = urlshorter.PROTOCOLS[service].URLShorter() |
|
624 |
return s.short(url) |
|
625 |
except: return url |
|
626 |
||
|
557.2.1
by Ken VanDine
Make dbus method camel case |
627 |
def IsShort(self, url): |
|
527
by Ken VanDine
Ported urlshortening |
628 |
for us in urlshorter.PROTOCOLS.values(): |
629 |
if url.startswith(us.PROTOCOL_INFO["fqdn"]): |
|
630 |
return True |
|
631 |
return False |