]> git.pld-linux.org Git - packages/ekg2-script-pynotif.git/blame - pynotif.py
- up to current version from git
[packages/ekg2-script-pynotif.git] / pynotif.py
CommitLineData
7c8d37d7 1# vim:fileencoding=utf-8:sw=4
8f9d83b6 2
461ea624 3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16# Copyright (c) 2009 by Paweł Tomak <satherot (at) gmail (dot) com>
7c8d37d7 17# Copyright (c) 2009 by Paweł Zuzelski <pawelz.pld-linux.org>
461ea624 18
19import ekg
20import time
21import pynotify
22import re
23import sys
7c8d37d7 24import glib
461ea624 25
26TIMEOUT_STATUS=3500
27TIMEOUT_MSG=3500
28
344b33ab 29def removeTextFormatting(text):
30 """
31 Removes advance text formatting from notifications.
32
33 Converts html reserved characters (&, ", < and >) to xml entities.
34 Removes ANSII color strings.
35 """
36 # Remove html tags
461ea624 37 reg = re.compile("&")
38 text = reg.sub("&#38;", text)
7c8d37d7 39 reg = re.compile('"')
40 text = reg.sub("&#34;", text)
461ea624 41 reg = re.compile("<")
42 text = reg.sub("&#60;", text)
43 reg = re.compile(">")
44 text = reg.sub("&#62;", text)
344b33ab 45 # Remove terminal color codes
46 reg = re.compile("\e\[[0-9]+;[0-9]+m")
47 text = reg.sub("", text)
48 reg = re.compile("\e\[[0-9]+m")
49 text = reg.sub("", text)
50 return text
51
52def parseMeCommand(text, user):
53 """
54 Interpretes /me command as defined in JEP-0245
55
56 If text begins with '/me ', substitute it with '* user '
57 """
58
59 if (text[:4] == "/me "):
60 text = "* " + user + text[3:]
61
461ea624 62 return text
63
7c8d37d7 64def catchURL(text):
344b33ab 65 """
66 Converts URLs to html "a href" tags, so they will be clickable if
67 notification daemon supports basic html.
68 """
7c8d37d7 69 reg = re.compile("((news|telnet|nttp|file|http|ftp|https)://[^ ]+|www.[^ ]+)")
70 if len(reg.findall(text)):
71 text = reg.sub(r'<a href="\1">\1</a>', text)
72 return [1, text]
73 else:
74 return [0, text]
75
461ea624 76def transStatus(status):
77 return {
78 'avail': 'dostepny',
79 'away': 'zaraz wracam',
80 'blocking': 'BLOKUJE',
81 'error': 'BLAD STATUSU!!',
82 'ffc': 'chetny do rozmowy',
83 'chat': 'chetny do rozmowy',
84 'dnd': 'nie przeszkadzac',
85 'xa': 'bardzo zajety',
86 'notavail': 'niedostepny',
7c8d37d7 87 'unknown': 'nieznany',
461ea624 88 }[status]
89
344b33ab 90def getUrgency(title, text):
91 """
92 Performs notify:urgency_critical_regexp and notify:urgency_normal_regexp
93 matching on "title&text". "&" character was chosen as separator, because
94 acording to RFC3920, Apendix A, use of this character is forbiden i JID,
95 so it should not apear in title.
96
97 If notify:urgency_critical_regexp matches, returns urgency CRITICAL. If
98 not, tries to match notify:urgency_normal_regexp, on success return
99 urgency NORMAL. Finally return urgency LOW.
100
101 Default values are "^$" wich are never matched, as string always contain
102 at least single "&" character.
103 """
104
105 message=title+"&"+text
106
107 urgencyCritical = re.compile(ekg.config["notify:urgency_critical_regexp"])
108 if (urgencyCritical.match(message)):
109 return pynotify.URGENCY_CRITICAL
110
111 urgencyNormal = re.compile(ekg.config["notify:urgency_normal_regexp"])
112 if (urgencyNormal.match(message)):
113 return pynotify.URGENCY_NORMAL
114
115 return pynotify.URGENCY_LOW
116
461ea624 117def displayNotify(title, text, timeout, type):
344b33ab 118 """
119 Sends notification to dbus org.freedesktop.Notifications service using
120 pynotify python library.
121 """
461ea624 122 if not pynotify.init("EkgNotif"):
123 ekg.echo("you don't seem to have pynotify installed")
124 return 0
7c8d37d7 125 if ekg.config["notify:catch_url"] != "0":
126 l = catchURL(text)
127 if l[0]:
128 text = l[1]
129 timeout = int(ekg.config["notify:catch_url_timeout"])
461ea624 130 n = pynotify.Notification(title, text, type)
344b33ab 131
461ea624 132 n.set_timeout(timeout)
344b33ab 133 n.set_urgency(getUrgency(title, text))
7c8d37d7 134
135 # Most probably glib.GError is:
136 # The name org.freedesktop.Notifications was not provided by any
137 # .service files
138 # Catch this exception and print information in debug window.
139 # Sometimes I
140 # do not have org.freedesktop.Notifications registered and
141 # I do not want
142 # error messages in chat window.
143 # Or logs buffer has overflowed ;/
144 try:
145 n.show()
146 except glib.GError as e:
147 ekg.debug("pynotif: " + str(e))
148
461ea624 149 return 1
150
151def notifyStatus(session, uid, status, descr):
344b33ab 152 """
153 Display status change notifications, but first check if status change
154 notifications are enabled, then check if session and uids match
155 ignore_{sessions,uids}_regexp.
156
157 This function is bound to protocol-status handler
158 """
7c8d37d7 159 if ekg.config["notify:status_notify"] == "0":
160 return 1
344b33ab 161 if (ekg.config["notify:ignore_sessions_regexp"]):
162 regexp = re.compile(ekg.config["notify:ignore_sessions_regexp"])
163 if regexp.match(session):
164 return 1
165 if (ekg.config["notify:ignore_uids_regexp"]):
166 regexp = re.compile(ekg.config["notify:ignore_uids_regexp"])
167 if regexp.match(uid):
168 return 1
461ea624 169 regexp = re.compile('.*' + session + '.*')
7c8d37d7 170 if regexp.match(uid):
171 ekg.debug("Zmienil sie status sesji: %s. Nie zostal on zmieniony przez ten program. Sprawdz to, jesli nie zmieniales statusu jakims innym programem" % session)
461ea624 172 return 1
173 sesja = ekg.session_get(session)
174 regexp = re.compile('([a-z]{2,4}:[^/]+)')
175 regexp = regexp.match(uid)
176 regexp = regexp.group()
177 try:
178 user = sesja.user_get(regexp)
179 except KeyError:
7c8d37d7 180 ekg.debug("Nie znalazlem uzytkownika %s." % uid)
181 user = "Empty"
461ea624 182 status = transStatus(status)
7c8d37d7 183 if user == "Empty":
184 nick = regexp
185 else:
186 nick = user.nickname or user.uid or "Empty"
461ea624 187 s = status or "Empty"
344b33ab 188 s = removeTextFormatting(s)
461ea624 189 text = "<b>" + nick + "</b> zmienil status na <b>" + s + "</b>"
190 if descr:
344b33ab 191 descr = removeTextFormatting(descr)
461ea624 192 text = text + ":\n" + descr + "\n"
193 return displayNotify(session, text, TIMEOUT_STATUS, ekg.config["notify:icon_status"])
194
195def notifyMessage(session, uid, type, text, stime, ignore_level):
344b33ab 196 """
197 Display message notifications, but first check if message notifications
198 are enabled, then check if session and uids match
199 ignore_{sessions,uids}_regexp.
200
201 This function is bound to protocol-message handler
202 """
7c8d37d7 203 if ekg.config["notify:message_notify"] == "0":
204 return 1
344b33ab 205 if (ekg.config["notify:ignore_sessions_regexp"]):
206 regexp = re.compile(ekg.config["notify:ignore_sessions_regexp"])
207 if regexp.match(session):
208 return 1
209 if (ekg.config["notify:ignore_uids_regexp"]):
210 regexp = re.compile(ekg.config["notify:ignore_uids_regexp"])
211 if regexp.match(uid):
212 return 1
461ea624 213 sesja = ekg.session_get(session)
214 try:
215 user = sesja.user_get(uid)
216 except KeyError:
7c8d37d7 217 ekg.debug("Nie znalazlem uzytkownika %s." % uid)
218 user = "Empty"
344b33ab 219 if user == None:
220 user = "Empty"
7c8d37d7 221 if user == "Empty" and ekg.config["notify:message_notify_unknown"] == "0":
222 return 1
223 if user == "Empty":
224 user = uid
225 else:
226 user = user.nickname
344b33ab 227 try:
228 title = user
229 except KeyError:
230 title = uid
231 if (ekg.config["notify:show_timestamps"] == "1"):
232 title = time.strftime("%H:%M:%S", time.localtime(stime)) + " " + title
233 text = removeTextFormatting(text)
234 text = parseMeCommand(text, user)
461ea624 235 if len(text) > 200:
236 text = text[0:199] + "... >>>\n\n"
237 return displayNotify(title, text, TIMEOUT_MSG, ekg.config["notify:icon_msg"])
238
239def timeCheck(name, args):
240 global TIMEOUT_MSG
241 global TIMEOUT_STATUS
242 rexp = re.compile('^[0-9]{4,4}')
243 rexp = rexp.findall(args)
244 if len(rexp) == 1:
245 if name == "notify:message_timeout":
246 TIMEOUT_MSG = int(rexp[0])
247 return 1
248 if name == "notify:status_timeout":
249 TIMEOUT_STATUS = int(rexp[0])
250 return 1
7c8d37d7 251 if name == "notify:catch_url_timeout":
252 return 1
461ea624 253
254 if name == "notify:message_timeout":
255 ekg.echo("Zmienna %s bedzie pomijana do czasu, az zostanie ustawiona wartosc z zakresu od 1000ms do 9999ms. Jej obecna wartosc to: %i" % (name,TIMEOUT_MSG))
256 elif name == "notify:status_timeout":
257 ekg.echo("Zmienna %s bedzie pomijana do czasu, az zostanie ustawiona wartosc z zakresu od 1000ms do 9999ms. Jej obecna wartosc to: %i" % (name,TIMEOUT_STATUS))
7c8d37d7 258 elif name == "notify:catch_url_timeout":
259 ekg.echo("Zmienna %s bedzie pomijana do czasu, az zostanie ustawiona wartosc z zakresu od 1000ms do 9999ms. Jej obecna wartosc to: %i" % (name,TIMEOUT_STATUS))
461ea624 260 return 0
261
7c8d37d7 262def notifyTest(name, args):
344b33ab 263 """
264 Sends test notification.
265
266 This function is bound to notify:send command
267 """
7c8d37d7 268 args = args.split(None, 1)
269 if (len(args) == 0):
270 title="Test"
271 else:
272 title=args[0]
273
274 if (len(args) <= 1):
275 text="Pięćdziesiąt trzy"
276 else:
277 text = args[1]
278
279 return displayNotify(title, text, TIMEOUT_MSG, ekg.config["notify:icon_msg"])
280
461ea624 281ekg.handler_bind('protocol-status', notifyStatus)
282ekg.handler_bind("protocol-message-received", notifyMessage)
344b33ab 283ekg.variable_add("notify:ignore_sessions_regexp", "^irc:")
284ekg.variable_add("notify:ignore_uids_regexp", "^xmpp:.*@conference\.")
285ekg.variable_add("notify:urgency_critical_regexp", "^$")
286ekg.variable_add("notify:urgency_normal_regexp", "^$")
461ea624 287ekg.variable_add("notify:icon_status", "dialog-warning")
288ekg.variable_add("notify:icon_msg", "dialog-warning")
289ekg.variable_add("notify:message_timeout", "3500", timeCheck)
7c8d37d7 290ekg.variable_add("notify:message_notify", "1")
291ekg.variable_add("notify:message_notify_unknown", "1")
344b33ab 292ekg.variable_add("notify:show_timestamps", "1")
461ea624 293ekg.variable_add("notify:status_timeout", "3500", timeCheck)
7c8d37d7 294ekg.variable_add("notify:status_notify", "1")
295ekg.variable_add("notify:catch_url", "1")
296ekg.variable_add("notify:catch_url_timeout", "5000", timeCheck)
297ekg.command_bind("notify:send", notifyTest)
461ea624 298
299if int(ekg.config["notify:message_timeout"]) < 1000 or int(ekg.config["notify:message_timeout"]) > 9999:
300 timeCheck("notify:message_timeout", ekg.config["notify:message_timeout"])
301if int(ekg.config["notify:status_timeout"]) < 1000 or int(ekg.config["notify:status_timeout"]) > 9999:
302 timeCheck("notify:status_timeout", ekg.config["notify:status_timeout"])
303
This page took 0.104889 seconds and 4 git commands to generate.