1 # -*- coding: utf-8 -*-
2 #===============================================================================
7 #==============================
8 from Screens.Screen import Screen
9 from Screens.MessageBox import MessageBox
10 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
11 from Screens.InputBox import InputBox
12 from Screens import Standby
13 from Screens.HelpMenu import HelpableScreen
15 from enigma import eTimer, eSize, ePoint#@UnresolvedImport
16 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT
18 from Components.MenuList import MenuList
19 from Components.ActionMap import ActionMap
20 from Components.Label import Label
21 from Components.Button import Button
22 from Components.Pixmap import Pixmap
23 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger
24 from Components.ConfigList import ConfigListScreen
25 from Components.Harddisk import harddiskmanager
27 from Components.config import ConfigPassword
29 ConfigPassword = ConfigText
31 from Plugins.Plugin import PluginDescriptor
32 from Tools import Notifications
33 from Tools.NumericalTextInput import NumericalTextInput
34 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA
35 from Tools.LoadPixmap import LoadPixmap
37 from twisted.internet import reactor #@UnresolvedImport
38 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
39 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
40 from twisted.web.client import getPage #@UnresolvedImport
42 from urllib import urlencode
43 import re, time, os, hashlib, traceback
45 from nrzuname import ReverseLookupAndNotifier, html2unicode
46 import FritzOutlookCSV, FritzLDIF
47 from . import _, debug #@UnresolvedImport
49 from enigma import getDesktop
50 DESKTOP_WIDTH = getDesktop(0).size().width()
51 DESKTOP_HEIGHT = getDesktop(0).size().height()
52 DESKTOP_SKIN = config.skin.primary_skin.value.replace("/skin.xml", "")
53 XXX = 0 # TODO: Platzhalter für fullscreen SD skin
56 # It returns the first value, if HD (1280x720),
57 # the second if SD (720x576),
58 # else something scaled accordingly
59 # if one of the parameters is -1, scale proportionally
66 return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
72 return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
73 def scale(y2, y1, x2, x1, x):
74 return (y2 - y1) * (x - x1) / (x2 - x1) + y1
76 my_global_session = None
78 config.plugins.FritzCall = ConfigSubsection()
79 config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
80 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default=False)
81 config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
82 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
83 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
84 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
85 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
86 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
87 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
88 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
89 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
90 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
91 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
92 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
93 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
94 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
95 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
96 config.plugins.FritzCall.extension.setUseableChars('0123456789')
97 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
98 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
99 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
100 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
101 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
102 config.plugins.FritzCall.fullscreen = ConfigEnableDisable(default=False)
104 mountedDevs= [(resolveFilename(SCOPE_CONFIG), _("Flash") + " (" + resolveFilename(SCOPE_CONFIG) + ")")]
105 if os.path.isdir(resolveFilename(SCOPE_MEDIA, "cf")):
106 mountedDevs.append((resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash") + " (" + resolveFilename(SCOPE_MEDIA, "cf") + ")"))
107 if os.path.isdir(resolveFilename(SCOPE_MEDIA, "usb")):
108 mountedDevs.append((resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device") + " (" + resolveFilename(SCOPE_MEDIA, "usb") + ")"))
109 for p in harddiskmanager.getMountedPartitions(True):
110 mp = p.mountpoint[:-1]
112 mountedDevs.append((mp, _(p.description)+ ' (' + mp + ')'))
114 mountedDevs.append((mp, mp))
115 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=mountedDevs)
118 ("0049", _("Germany")),
119 ("0031", _("The Netherlands")),
120 ("0033", _("France")),
121 ("0039", _("Italy")),
122 ("0041", _("Switzerland")),
123 ("0043", _("Austria"))
125 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
129 FBF_MISSED_CALLS = "2"
131 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
132 FBF_IN_CALLS: _("Incoming calls"),
133 FBF_MISSED_CALLS: _("Missed calls"),
134 FBF_OUT_CALLS: _("Outgoing calls")
136 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
138 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
139 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
140 config.plugins.FritzCall.number.setUseableChars('0123456789')
147 os.remove("/tmp/FritzDebug.log")
154 avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/avon.dat")
155 if os.path.exists(avonFileName):
156 for line in open(avonFileName):
157 line = line.decode("iso-8859-1").encode('utf-8')
160 parts = line.split(':')
162 avon[parts[0].replace('-','').replace('*','').replace('/','')] = parts[1]
164 def resolveNumberWithAvon(number, countrycode):
165 if not number or number[0]!='0':
168 countrycode = countrycode.replace('00','+')
169 if number[:2] == '00':
170 normNumber = '+' + number[2:]
171 elif number[:1] == '0':
172 normNumber = countrycode + number[1:]
173 else: # this should can not happen, but safety first
176 # debug('normNumer: ' + normNumber)
177 for i in reversed(range(min(10, len(number)))):
178 if avon.has_key(normNumber[:i]):
179 return '[' + avon[normNumber[:i]].strip() + ']'
182 def handleReverseLookupResult(name):
183 found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
185 ( name,firstname,street,streetno,zipcode,city ) = (found.group(1),
192 if firstname: name += ' ' + firstname
193 if street or streetno or zipcode or city: name += ', '
194 if street: name += street
195 if streetno: name += ' ' + streetno
196 if (street or streetno) and (zipcode or city): name += ', '
197 if zipcode and city: name += zipcode + ' ' + city
198 elif zipcode: name += zipcode
199 elif city: name += city
202 from xml.dom.minidom import parse
205 callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/callbycall_world.xml")
206 if os.path.exists(callbycallFileName):
207 dom = parse(callbycallFileName)
208 for top in dom.getElementsByTagName("callbycalls"):
209 for cbc in top.getElementsByTagName("country"):
210 code = cbc.getAttribute("code").replace("+","00")
211 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
213 debug("[FritzCall] initCbC: callbycallFileName does not exist?!?!")
215 def stripCbCPrefix(number, countrycode):
216 if number and number[:2]!="00" and cbcInfos.has_key(countrycode):
217 for cbc in cbcInfos[countrycode]:
218 if len(cbc.getElementsByTagName("length"))<1 or len(cbc.getElementsByTagName("prefix"))<1:
219 debug("[FritzCall] stripCbCPrefix: entries for " + countrycode + " %s invalid")
221 length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
222 prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
223 # if re.match('^'+prefix, number):
224 if number[:len(prefix)] == prefix:
225 return number[length:]
228 class FritzAbout(Screen):
230 def __init__(self, session):
231 textFieldWidth = scaleV(350,250)
232 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
233 height = 5 + 175 + 5 + 25 + 5
234 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
236 <screen name="FritzAbout" position="%d,%d" size="%d,%d" title="%s" >
237 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
238 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
239 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
240 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
242 (DESKTOP_WIDTH - width) / 2, (DESKTOP_HEIGHT - height) / 2, # position
243 width, height, # size
244 _("About FritzCall"), # title
245 (height-scaleV(150,130)) / 2, # text vertical position
247 scaleV(150,130), # text height
248 scaleV(24,21), # text font size
249 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
250 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
251 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
252 width-40, # url width
253 scaleV(24,21) # url font size
255 Screen.__init__(self, session)
256 self["aboutActions"] = ActionMap(["OkCancelActions"],
261 self["text"] = Label(
262 "FritzCall Plugin" + "\n\n" +
263 "$Author$"[1:-2] + "\n" +
264 "$Revision$"[1:-2] + "\n" +
265 "$Date$"[1:23] + "\n"
267 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
284 debug("[FritzCallFBF] __init__")
285 self._callScreen = None
286 self._md5LoginTimestamp = None
287 self._md5Sid = '0000000000000000'
288 self._callTimestamp = 0
290 self._callType = config.plugins.FritzCall.fbfCalls.value
291 self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
294 def _notify(self, text):
295 debug("[FritzCallFBF] notify: " + text)
296 self._md5LoginTimestamp = None
298 debug("[FritzCallFBF] notify: try to close callScreen")
299 self._callScreen.close()
300 self._callScreen = None
301 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
303 def _login(self, callback=None):
304 debug("[FritzCallFBF] _login")
306 self._callScreen.updateStatus(_("login"))
307 if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
308 debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
309 self._md5LoginTimestamp = time.time()
312 debug("[FritzCallFBF] _login: not logged in or outdated login")
313 # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
314 parms = urlencode({'getpage':'../html/login_sid.xml'})
315 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
316 debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
319 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
320 }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
322 def _oldLogin(self, callback, error):
323 debug("[FritzCallFBF] _oldLogin: " + repr(error))
324 self._md5LoginTimestamp = None
325 if config.plugins.FritzCall.password.value != "":
326 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
327 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
328 debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
331 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
332 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
333 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
335 debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
338 def _md5Login(self, callback, sidXml):
339 def buildResponse(challenge, text):
340 debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
341 text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
342 for i in range(len(text)):
343 if ord(text[i]) > 255:
347 debug("[FritzCallFBF] md5Login/buildResponse: " + m.hexdigest())
348 return challenge + '-' + m.hexdigest()
350 debug("[FritzCallFBF] _md5Login")
351 found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
353 self._md5Sid = found.group(1)
354 debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
356 debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
357 self._oldLogin(callback, 'No error')
360 debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
361 self._md5LoginTimestamp = time.time()
362 if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
363 debug("[FritzCallFBF] _md5Login: logging in")
364 found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
366 challenge = found.group(1)
367 debug("[FritzCallFBF] _md5Login: challenge " + challenge)
370 debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
372 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
373 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
375 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
376 debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
379 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
380 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
381 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
382 elif callback: # we assume value 1 here, no login necessary
383 debug("[FritzCallFBF] _md5Login: no login necessary")
386 def _gotPageLogin(self, html):
388 self._callScreen.updateStatus(_("login verification"))
389 debug("[FritzCallFBF] _gotPageLogin: verify login")
390 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
392 text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
396 self._callScreen.updateStatus(_("login ok"))
398 found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
400 self._md5Sid = found.group(1)
401 debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
403 def _errorLogin(self, error):
404 debug("[FritzCallFBF] _errorLogin: %s" % (error))
405 text = _("FRITZ!Box - Error logging in: %s") % error
409 if self._md5LoginTimestamp:
410 self._md5LoginTimestamp = None
412 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
413 'login:command/logout':'bye bye Fritz'
415 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
416 debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
419 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
420 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
421 }, postdata=parms).addErrback(self._errorLogout)
423 def _errorLogout(self, error):
424 debug("[FritzCallFBF] _errorLogout: %s" % (error))
425 text = _("FRITZ!Box - Error logging out: %s") % error
428 def loadFritzBoxPhonebook(self):
429 debug("[FritzCallFBF] loadFritzBoxPhonebook")
430 if config.plugins.FritzCall.fritzphonebook.value:
431 self._phoneBookID = '0'
432 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
433 self._login(self._loadFritzBoxPhonebook)
435 def _loadFritzBoxPhonebook(self, html):
437 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
439 self._errorLoad('Login: ' + found.group(1))
442 'getpage':'../html/de/menus/menu2.html',
444 'var:pagename':'fonbuch',
447 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
449 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
450 debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
453 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
454 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
455 }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
457 def _parseFritzBoxPhonebook(self, html):
458 debug("[FritzCallFBF] _parseFritzBoxPhonebook")
459 # if not re.search('document.write\(TrFon\("[^"]+", "[^"]+", "[^"]+", "[^"]+", "[^"]+"\)\)', html):
460 if re.search('document.write\(TrFon1\(\)', html):
461 #===============================================================================
462 # New Style: 7270 (FW 54.04.58, 54.04.63-11941, 54.04.70, 54.04.74-14371, 54.04.76)
463 # 7170 (FW 29.04.70) 22.03.2009
464 # 7141 (FW 40.04.68) 22.03.2009
465 # We expect one line with TrFonName followed by several lines with
466 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
467 #===============================================================================
468 found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
470 phoneBookID = found.group(1)
471 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
472 if self._phoneBookID != phoneBookID:
473 self._phoneBookID = phoneBookID
474 debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
475 self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
478 found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
480 charset = found.group(1)
481 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
482 html = html2unicode(html.decode(charset)).encode('utf-8') # this looks silly, but has to be
483 else: # this is kind of emergency conversion...
485 html = html2unicode(html.decode('utf-8')).encode('utf-8') # this looks silly, but has to be
486 except UnicodeDecodeError:
487 html = html2unicode(html.decode('iso-8859-1')).encode('utf-8') # this looks silly, but has to be
488 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"\);.*?)document.write\(TrFon1\(\)', re.S)
489 entries = entrymask.finditer(html)
490 for entry in entries:
491 # debug(entry.group(1)
492 # TrFonName (id, name, category)
493 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"\);', entry.group(1))
495 name = found.group(1).replace(',','').strip()
498 # TrFonNr (type, rufnr, code, vanity)
499 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
500 details = detailmask.finditer(entry.group(1))
501 for found in details:
502 thisnumber = found.group(2).strip()
504 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
508 type = found.group(1)
509 if config.plugins.FritzCall.showType.value:
511 thisname = thisname + " (" + _("mobile") + ")"
513 thisname = thisname + " (" + _("home") + ")"
515 thisname = thisname + " (" + _("work") + ")"
517 if config.plugins.FritzCall.showShortcut.value and found.group(3):
518 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
519 if config.plugins.FritzCall.showVanity.value and found.group(4):
520 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
522 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
523 # Beware: strings in phonebook.phonebook have to be in utf-8!
524 phonebook.phonebook[thisnumber] = thisname
526 elif re.search('document.write\(TrFon\(', html):
527 #===============================================================================
528 # Old Style: 7050 (FW 14.04.33)
529 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
530 # Encoding should be plain Ascii...
531 #===============================================================================
532 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
533 entries = entrymask.finditer(html)
534 for found in entries:
535 name = found.group(1).strip().replace(',','')
536 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
537 thisnumber = found.group(2).strip()
538 if config.plugins.FritzCall.showShortcut.value and found.group(3):
539 name = name + ", " + _("Shortcut") + ": " + found.group(3)
540 if config.plugins.FritzCall.showVanity.value and found.group(4):
541 name = name + ", " + _("Vanity") + ": " + found.group(4)
543 name = html2unicode(unicode(name)).encode('utf-8')
544 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
545 # Beware: strings in phonebook.phonebook have to be in utf-8!
546 phonebook.phonebook[thisnumber] = name
548 debug("[FritzCallFBF] ignoring empty number for %s" % name)
550 elif self._md5Sid=='0000000000000000': # retry, it could be a race condition
551 debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
552 self.loadFritzBoxPhonebook()
554 self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
556 def _errorLoad(self, error):
557 debug("[FritzCallFBF] _errorLoad: %s" % (error))
558 text = _("FRITZ!Box - Could not load phonebook: %s") % error
561 def getCalls(self, callScreen, callback, type):
563 # call sequence must be:
565 # - getPage -> _gotPageLogin
566 # - loginCallback (_getCalls)
567 # - getPage -> _getCalls1
568 debug("[FritzCallFBF] getCalls")
569 self._callScreen = callScreen
570 self._callType = type
571 if (time.time() - self._callTimestamp) > 180:
572 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
573 self._callTimestamp = time.time()
574 self._login(lambda x:self._getCalls(callback,x))
575 elif not self._callList:
576 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
577 self._getCalls1(callback)
579 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
580 self._gotPageCalls(callback)
582 def _getCalls(self, callback, html):
584 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
586 self._errorCalls('Login: ' + found.group(1))
589 # we need this to fill Anrufliste.csv
590 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
592 debug("[FritzCallFBF] _getCalls")
594 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
596 text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
601 self._callScreen.updateStatus(_("preparing"))
602 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
603 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
604 getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls) #@UnusedVariable
606 def _getCalls1(self, callback):
608 # finally we should have successfully lgged in and filled the csv
610 debug("[FritzCallFBF] _getCalls1")
612 self._callScreen.updateStatus(_("finishing"))
613 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
614 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
615 getPage(url).addCallback(lambda x:self._gotPageCalls(callback,x)).addErrback(self._errorCalls)
617 def _gotPageCalls(self, callback, csv=""):
618 def _resolveNumber(number):
620 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0": number = number[1:]
622 number = stripCbCPrefix(number, config.plugins.FritzCall.country.value)
623 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
624 number = config.plugins.FritzCall.prefix.value + number
625 name = phonebook.search(number)
627 found = re.match('(.*?)\n.*', name)
629 name = found.group(1)
632 name = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
634 number = number + ' ' + name
636 number = _("UNKNOWN")
637 # if len(number) > 20: number = number[:20]
641 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
643 self._callScreen.updateStatus(_("done"))
644 # check for error: wrong password or password not set... TODO
645 found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
647 text = _("You need to set the password of the FRITZ!Box\nin the configuration dialog to display calls\n\nIt could be a communication issue, just try again.")
648 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
652 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
653 lines = csv.splitlines()
654 self._callList = lines
656 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
658 self._callScreen.updateStatus(_("done, using last list"))
659 lines = self._callList
661 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, leaving")
666 # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
667 found = re.match("^(" + self._callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
669 direct = found.group(1)
670 date = found.group(2)
671 length = found.group(7)
672 remote = _resolveNumber(found.group(4))
673 if not remote and direct != FBF_OUT_CALLS and found.group(3):
674 remote = found.group(3)
675 found1 = re.match('Internet: (.*)', found.group(6))
677 here = _resolveNumber(found1.group(1))
679 here = _resolveNumber(found.group(6))
681 number = stripCbCPrefix(found.group(4), config.plugins.FritzCall.country.value)
682 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
683 number = config.plugins.FritzCall.prefix.value + number
684 _callList.append((number, date, here, direct, remote, length))
686 # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
689 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
691 self._callScreen = None
693 def _errorCalls(self, error):
694 debug("[FritzCallFBF] _errorCalls: %s" % (error))
695 text = _("FRITZ!Box - Could not load calls: %s") % error
698 def dial(self, number):
699 ''' initiate a call to number '''
701 self._login(self._dial)
703 def _dial(self, html):
705 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
707 self._errorDial('Login: ' + found.group(1))
709 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
711 'getpage':'../html/de/menus/menu2.html',
712 'var:pagename':'fonbuch',
714 'telcfg:settings/UseClickToDial':'1',
715 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
716 'telcfg:command/Dial':self.number,
719 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
722 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
724 'Content-Type': "application/x-www-form-urlencoded",
725 'Content-Length': str(len(parms))},
726 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
728 def _okDial(self, html): #@UnusedVariable
729 debug("[FritzCallFBF] okDial")
731 def _errorDial(self, error):
732 debug("[FritzCallFBF] errorDial: $s" % error)
733 text = _("FRITZ!Box - Dialling failed: %s") % error
736 def changeWLAN(self, statusWLAN):
737 ''' get status info from FBF '''
738 debug("[FritzCallFBF] changeWLAN start")
739 if not statusWLAN or (statusWLAN <> '1' and statusWLAN <> '0'):
741 self.statusWLAN = statusWLAN
742 self._login(self._changeWLAN)
744 def _changeWLAN(self, html):
746 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
748 self._errorChangeWLAN('Login: ' + found.group(1))
750 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
752 'getpage':'../html/de/menus/menu2.html',
754 'var:pagename':'wlan',
756 'wlan:settings/ap_enabled':str(self.statusWLAN),
759 debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
762 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
764 'Content-Type': "application/x-www-form-urlencoded",
765 'Content-Length': str(len(parms))},
766 postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
768 def _okChangeWLAN(self, html): #@UnusedVariable
769 debug("[FritzCallFBF] okDial")
771 def _errorChangeWLAN(self, error):
772 debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
773 text = _("FRITZ!Box - Failed changing WLAN: %s") % error
776 def changeMailbox(self, whichMailbox):
777 ''' switch mailbox on/off '''
778 debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
779 self.whichMailbox = whichMailbox
780 self._login(self._changeMailbox)
782 def _changeMailbox(self, html):
784 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
786 self._errorChangeMailbox('Login: ' + found.group(1))
788 debug("[FritzCallFBF] _changeMailbox")
789 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
790 if self.whichMailbox == -1:
792 if self.info[FBF_tamActive][i+1]:
797 'tam:settings/TAM'+str(i)+'/Active':state,
800 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
803 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
805 'Content-Type': "application/x-www-form-urlencoded",
806 'Content-Length': str(len(parms))},
807 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
808 elif self.whichMailbox > 4:
809 debug("[FritzCallFBF] changeMailbox invalid mailbox number")
811 if self.info[FBF_tamActive][self.whichMailbox+1]:
816 'tam:settings/TAM'+str(self.whichMailbox)+'/Active':state,
819 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
822 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
824 'Content-Type': "application/x-www-form-urlencoded",
825 'Content-Length': str(len(parms))},
826 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
828 def _okChangeMailbox(self, html): #@UnusedVariable
829 debug("[FritzCallFBF] _okChangeMailbox")
831 def _errorChangeMailbox(self, error):
832 debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
833 text = _("FRITZ!Box - Failed changing Mailbox: %s") % error
836 def getInfo(self, callback):
837 ''' get status info from FBF '''
838 debug("[FritzCallFBF] getInfo")
839 self._login(lambda x:self._getInfo(callback,x))
841 def _getInfo(self, callback, html):
842 # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
843 debug("[FritzCallFBF] _getInfo: verify login")
845 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
847 self._errorGetInfo('Login: ' + found.group(1))
850 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
852 'getpage':'../html/de/menus/menu2.html',
854 'var:pagename':'home',
858 debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
861 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
863 'Content-Type': "application/x-www-form-urlencoded",
864 'Content-Length': str(len(parms))},
865 postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
867 def _okGetInfo(self, callback, html):
870 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
872 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
874 debug("[FritzCallFBF] _okGetInfo/readinfo")
875 found = re.match('.*<table class="tborder" id="tProdukt">\s*<tr>\s*<td style="padding-top:2px;">([^<]*)</td>\s*<td style="padding-top:2px;text-align:right;">\s*([^\s]*)\s*</td>', html, re.S)
877 boxInfo = found.group(1)+ ', ' + found.group(2)
878 boxInfo = boxInfo.replace(' ',' ')
879 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
881 found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
883 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
884 boxInfo = found.group(1)
886 if html.find('home_coninf.txt') != -1:
887 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
889 'getpage':'../html/de/home/home_coninf.txt',
892 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
895 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
897 'Content-Type': "application/x-www-form-urlencoded",
898 'Content-Length': str(len(parms))},
899 postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
901 found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
903 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
904 upTime = found.group(1)
906 found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
908 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
909 upTime = found.group(1)
911 found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
913 # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
914 ipAddress = found.group(1)
916 if html.find('g_tamActive') != -1:
917 entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
918 tamActive = [0, False, False, False, False, False]
920 for entry in entries:
921 state = entry.group(1)
926 # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
928 if html.find('home_dect.txt') != -1:
929 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
931 'getpage':'../html/de/home/home_dect.txt',
934 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
937 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
939 'Content-Type': "application/x-www-form-urlencoded",
940 'Content-Length': str(len(parms))},
941 postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
943 if html.find('countDect2') != -1:
944 entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
945 dectActive = len(entries)
946 # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
948 found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
951 # debug("[FritzCallFBF] _okGetInfo faxActive")
953 if html.find('cntRufumleitung') != -1:
954 entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
955 rufumlActive = len(entries)
956 entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
958 for entry in entries:
959 # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
960 if entry.group(1) == entry.group(2): isAllIncoming += 1
961 if isAllIncoming==2 and rufumlActive>0: rufumlActive -= 1
962 # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
964 # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
965 # { "dsl_carrier_state": "5", "umts_enabled": "0", "ata_mode": "0", "isusbgsm": "", "dsl_ds_nrate": "3130", "dsl_us_nrate": "448", "hint_dsl_no_cable": "0", "wds_enabled": "0", "wds_hop": "0", "isata": "" }
966 if html.find('home_dsl.txt') != -1:
967 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
969 'getpage':'../html/de/home/home_dsl.txt',
972 # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
975 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
977 'Content-Type': "application/x-www-form-urlencoded",
978 'Content-Length': str(len(parms))},
979 postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
981 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
983 # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
984 dslState = [ found.group(1), None ] # state, speed
985 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
987 # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
988 dslState[1] = found.group(1).strip()
990 # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
991 # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
992 if html.find('home_wlan.txt') != -1:
993 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
995 'getpage':'../html/de/home/home_wlan.txt',
998 # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
1001 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1003 'Content-Type': "application/x-www-form-urlencoded",
1004 'Content-Length': str(len(parms))},
1005 postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
1007 found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
1009 # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
1010 wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
1011 found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
1013 # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
1014 wlanState[1] = found.group(1)
1016 return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1018 debug("[FritzCallFBF] _okGetInfo")
1019 info = readInfo(html)
1020 debug("[FritzCallFBF] _okGetInfo info: " + str(info))
1025 def _okSetDect(self, callback, html):
1026 # debug("[FritzCallFBF] _okSetDect: " + html)
1027 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1028 if html.find('"dect_enabled": "1"') != -1:
1029 # debug("[FritzCallFBF] _okSetDect: dect_enabled")
1030 found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
1032 # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
1033 entries = re.compile('"1"', re.S).findall(found.group(1))
1034 dectActive = len(entries)
1035 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
1036 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1037 debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
1041 def _okSetConInfo(self, callback, html):
1042 # debug("[FritzCallFBF] _okSetConInfo: " + html)
1043 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
1044 found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
1046 # debug("[FritzCallFBF] _okSetConInfo: ipAddress: %s upTime: %s" %( found.group(1), found.group(2)))
1047 ipAddress = found.group(1)
1048 upTime = found.group(2)
1049 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1050 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1051 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1055 def _okSetWlanState(self, callback, html):
1056 # debug("[FritzCallFBF] _okSetWlanState: " + html)
1057 found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
1059 # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
1060 wlanState = [ found.group(1), None, None ]
1061 found = re.match('.*"encryption": "(\d+)"', html, re.S)
1063 # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
1064 wlanState[1] = found.group(1)
1065 found = re.match('.*"active_stations": "(\d+)"', html, re.S)
1067 # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
1068 wlanState[2] = found.group(1)
1069 (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1070 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1071 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1075 def _okSetDslState(self, callback, html):
1076 # debug("[FritzCallFBF] _okSetDslState: " + html)
1077 found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
1079 # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
1080 dslState = [ found.group(1), None ]
1081 found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
1083 # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
1084 dslState[1] = found.group(1)
1085 found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
1087 # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
1088 dslState[1] = dslState[1] + '/' + found.group(1)
1089 (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
1090 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1091 debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
1095 def _errorGetInfo(self, error):
1096 debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
1097 text = _("FRITZ!Box - Error getting status: %s") % error
1099 # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
1100 # linkP.write(error)
1104 self._login(self._reset)
1106 def _reset(self, html):
1107 # POSTDATA=getpage=../html/reboot.html&errorpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:errorpagename=home&var:menu=home&var:pagemaster=&time:settings/time=1242207340%2C-120&var:tabReset=0&logic:command/reboot=../gateway/commands/saveconfig.html
1109 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1111 self._errorReset('Login: ' + found.group(1))
1113 if self._callScreen:
1114 self._callScreen.close()
1115 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1117 'getpage':'../html/reboot.html',
1119 'var:pagename':'reset',
1120 'var:menu':'system',
1121 'logic:command/reboot':'../gateway/commands/saveconfig.html',
1124 debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
1127 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1129 'Content-Type': "application/x-www-form-urlencoded",
1130 'Content-Length': str(len(parms))},
1133 def _okReset(self, html): #@UnusedVariable
1134 debug("[FritzCallFBF] _okReset")
1136 def _errorReset(self, error):
1137 debug("[FritzCallFBF] _errorReset: %s" % (error))
1138 text = _("FRITZ!Box - Error resetting: %s") % error
1141 #===============================================================================
1143 # ''' hangup call on port; not used for now '''
1144 # url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1145 # parms = urlencode({
1146 # 'id':'uiPostForm',
1147 # 'name':'uiPostForm',
1148 # 'login:command/password': config.plugins.FritzCall.password.value,
1149 # 'telcfg:settings/UseClickToDial':'1',
1150 # 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
1151 # 'telcfg:command/Hangup':'',
1152 # 'sid':self._md5Sid
1154 # debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
1158 # 'Content-Type': "application/x-www-form-urlencoded",
1159 # 'Content-Length': str(len(parms))},
1161 #===============================================================================
1163 fritzbox = FritzCallFBF()
1165 class FritzMenu(Screen,HelpableScreen):
1166 def __init__(self, session):
1167 fontSize = scaleV(24,21) # indeed this is font size +2
1168 noButtons = 2 # reset, wlan
1170 if not fritzbox or not fritzbox.info: return
1172 if fritzbox.info[FBF_tamActive]:
1173 noButtons += 1 # toggle mailboxes
1174 width = max(DESKTOP_WIDTH - scaleH(500,250), noButtons*140+(noButtons+1)*10)
1175 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
1176 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
1177 if fritzbox.info[FBF_tamActive] is not None: height += fontSize
1178 if fritzbox.info[FBF_dectActive] is not None: height += fontSize
1179 if fritzbox.info[FBF_faxActive] is not None: height += fontSize
1180 if fritzbox.info[FBF_rufumlActive] is not None: height += fontSize
1181 buttonsGap = (width-noButtons*140)/(noButtons+1)
1182 buttonsVPos = height-40-5
1185 if fritzbox.info[FBF_tamActive] is not None:
1187 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
1188 <widget name="mailbox_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1189 <widget name="mailbox_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1190 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1191 <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1193 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
1194 width-40-20, fontSize, # size mailbox
1196 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1197 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1198 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1199 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1205 if fritzbox.info[FBF_dectActive] is not None:
1207 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
1208 <widget name="dect_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1209 <widget name="dect_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1211 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1212 width-40-20, fontSize, # size dect
1214 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1215 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1221 if fritzbox.info[FBF_faxActive] is not None:
1223 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
1224 <widget name="fax_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1225 <widget name="fax_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1227 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1228 width-40-20, fontSize, # size dect
1230 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1231 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1237 if fritzbox.info[FBF_rufumlActive] is not None:
1239 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
1240 <widget name="rufuml_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1241 <widget name="rufuml_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1243 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1244 width-40-20, fontSize, # size dect
1246 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1247 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1254 <screen name="FritzMenu" position="%d,%d" size="%d,%d" title="%s" >
1255 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
1256 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
1257 <widget name="internet_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1258 <widget name="internet_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1259 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
1260 <widget name="dsl_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1261 <widget name="dsl_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1262 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
1263 <widget name="wlan_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1264 <widget name="wlan_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1269 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1270 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1271 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1272 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1274 (DESKTOP_WIDTH - width) / 2, (DESKTOP_HEIGHT - height) / 2, # position
1275 width, height, # size
1276 _("FRITZ!Box Fon Status"),
1277 40, 5, # position info
1278 width-2*40, 2*fontSize, # size info
1280 40, 5+2*fontSize+10, # position internet
1281 width-40, 2*fontSize, # size internet
1283 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1284 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1285 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
1286 width-40-20, fontSize, # size dsl
1288 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1289 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1290 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
1291 width-40-20, fontSize, # size wlan
1293 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1294 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1299 buttonsGap, buttonsVPos, buttonsGap, buttonsVPos,
1300 buttonsGap+140+buttonsGap, buttonsVPos, buttonsGap+140+buttonsGap, buttonsVPos,
1303 Screen.__init__(self, session)
1304 HelpableScreen.__init__(self)
1305 # TRANSLATORS: keep it short, this is a button
1306 self["key_red"] = Button(_("Reset"))
1307 # TRANSLATORS: keep it short, this is a button
1308 self["key_green"] = Button(_("Toggle WLAN"))
1309 self._mailboxActive = False
1310 if fritzbox.info[FBF_tamActive] is not None:
1311 # TRANSLATORS: keep it short, this is a button
1312 self["key_yellow"] = Button(_("Toggle Mailbox"))
1313 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
1315 "cancel": self._exit,
1318 "green": self._toggleWlan,
1319 "yellow": (lambda: self._toggleMailbox(-1)),
1320 "0": (lambda: self._toggleMailbox(0)),
1321 "1": (lambda: self._toggleMailbox(1)),
1322 "2": (lambda: self._toggleMailbox(2)),
1323 "3": (lambda: self._toggleMailbox(3)),
1324 "4": (lambda: self._toggleMailbox(4)),
1325 "info": self._getInfo,
1327 # TRANSLATORS: keep it short, this is a help text
1328 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
1329 # TRANSLATORS: keep it short, this is a help text
1330 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
1331 # TRANSLATORS: keep it short, this is a help text
1332 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
1333 # TRANSLATORS: keep it short, this is a help text
1334 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
1335 # TRANSLATORS: keep it short, this is a help text
1336 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
1337 # TRANSLATORS: keep it short, this is a help text
1338 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
1339 self["FBFMailbox"] = Label(_('Mailbox'))
1340 self["mailbox_inactive"] = Pixmap()
1341 self["mailbox_active"] = Pixmap()
1342 self["mailbox_active"].hide()
1344 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
1346 "cancel": self._exit,
1348 "green": self._toggleWlan,
1350 "info": self._getInfo,
1353 # TRANSLATORS: keep it short, this is a help text
1354 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1355 # TRANSLATORS: keep it short, this is a help text
1356 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
1357 # TRANSLATORS: keep it short, this is a help text
1358 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
1359 # TRANSLATORS: keep it short, this is a help text
1360 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
1361 # TRANSLATORS: keep it short, this is a help text
1362 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
1364 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
1366 self["FBFInternet"] = Label('Internet')
1367 self["internet_inactive"] = Pixmap()
1368 self["internet_active"] = Pixmap()
1369 self["internet_active"].hide()
1371 self["FBFDsl"] = Label('DSL')
1372 self["dsl_inactive"] = Pixmap()
1373 self["dsl_inactive"].hide()
1374 self["dsl_active"] = Pixmap()
1375 self["dsl_active"].hide()
1377 self["FBFWlan"] = Label('WLAN ')
1378 self["wlan_inactive"] = Pixmap()
1379 self["wlan_inactive"].hide()
1380 self["wlan_active"] = Pixmap()
1381 self["wlan_active"].hide()
1382 self._wlanActive = False
1384 if fritzbox.info[FBF_dectActive] is not None:
1385 self["FBFDect"] = Label('DECT')
1386 self["dect_inactive"] = Pixmap()
1387 self["dect_active"] = Pixmap()
1388 self["dect_active"].hide()
1390 if fritzbox.info[FBF_faxActive] is not None:
1391 self["FBFFax"] = Label('Fax')
1392 self["fax_inactive"] = Pixmap()
1393 self["fax_active"] = Pixmap()
1394 self["fax_active"].hide()
1396 if fritzbox.info[FBF_rufumlActive] is not None:
1397 self["FBFRufuml"] = Label(_('Call redirection'))
1398 self["rufuml_inactive"] = Pixmap()
1399 self["rufuml_active"] = Pixmap()
1400 self["rufuml_active"].hide()
1402 self._timer = eTimer()
1403 self._timer.callback.append(self._getInfo)
1404 self.onShown.append(lambda: self._timer.start(5000))
1405 self.onHide.append(lambda: self._timer.stop())
1409 fritzbox.getInfo(self._fillMenu)
1411 def _fillMenu(self, status):
1412 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
1413 self._wlanActive = (wlanState[0] == '1')
1414 self._mailboxActive = False
1417 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
1419 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
1423 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
1425 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
1426 self["internet_inactive"].hide()
1427 self["internet_active"].show()
1429 self["internet_active"].hide()
1430 self["internet_inactive"].show()
1433 if dslState[0]=='5':
1434 self["dsl_inactive"].hide()
1435 self["dsl_active"].show()
1437 self["FBFDsl"].setText('DSL ' + dslState[1])
1439 self["dsl_active"].hide()
1440 self["dsl_inactive"].show()
1442 self["FBFDsl"].setText('DSL ' + _('Status not available'))
1443 self["dsl_active"].hide()
1444 self["dsl_inactive"].hide()
1447 if wlanState[0]=='1':
1448 self["wlan_inactive"].hide()
1449 self["wlan_active"].show()
1451 if wlanState[1]=='0':
1452 message += ' ' + _('not encrypted')
1454 message += ' ' + _('encrypted')
1456 if wlanState[2]=='0':
1457 message = message + ', ' + _('no device active')
1458 elif wlanState[2]=='1':
1459 message = message + ', ' + _('one device active')
1461 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
1462 self["FBFWlan"].setText(message)
1464 self["wlan_active"].hide()
1465 self["wlan_inactive"].show()
1466 self["FBFWlan"].setText('WLAN')
1468 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
1469 self["wlan_active"].hide()
1470 self["wlan_inactive"].hide()
1472 if fritzbox.info[FBF_tamActive]:
1473 if not tamActive or tamActive[0] == 0:
1474 self._mailboxActive = False
1475 self["mailbox_active"].hide()
1476 self["mailbox_inactive"].show()
1477 self["FBFMailbox"].setText(_('No mailbox active'))
1479 self._mailboxActive = True
1483 message = message + str(i) + ','
1484 message = message[:-1] + ')'
1485 self["mailbox_inactive"].hide()
1486 self["mailbox_active"].show()
1487 if tamActive[0] == 1:
1488 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
1490 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
1492 if fritzbox.info[FBF_dectActive] and dectActive:
1493 self["dect_inactive"].hide()
1494 self["dect_active"].show()
1496 self["FBFDect"].setText(_('No DECT phone registered'))
1499 self["FBFDect"].setText(_('One DECT phone registered'))
1501 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
1503 if fritzbox.info[FBF_faxActive] and faxActive:
1504 self["fax_inactive"].hide()
1505 self["fax_active"].show()
1506 self["FBFFax"].setText(_('Software fax active'))
1508 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
1509 if rufumlActive == 0:
1510 self["rufuml_active"].hide()
1511 self["rufuml_inactive"].show()
1512 self["FBFRufuml"].setText(_('No call redirection active'))
1514 self["rufuml_inactive"].hide()
1515 self["rufuml_active"].show()
1516 if rufumlActive == 1:
1517 self["FBFRufuml"].setText(_('One call redirection active'))
1519 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
1522 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
1524 def _toggleWlan(self):
1525 if self._wlanActive:
1526 debug("[FritzMenu] toggleWlan off")
1527 fritzbox.changeWLAN('0')
1529 debug("[FritzMenu] toggleWlan off")
1530 fritzbox.changeWLAN('1')
1532 def _toggleMailbox(self, which):
1533 debug("[FritzMenu] toggleMailbox")
1534 if fritzbox.info[FBF_tamActive]:
1535 debug("[FritzMenu] toggleMailbox off")
1536 fritzbox.changeMailbox(which)
1547 class FritzDisplayCalls(Screen, HelpableScreen):
1549 def __init__(self, session, text=""): #@UnusedVariable
1550 if config.plugins.FritzCall.fullscreen.value:
1551 self.width = DESKTOP_WIDTH
1552 self.height = DESKTOP_HEIGHT
1554 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
1555 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
1556 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
1557 backMainPng = "Kerni-HD1/menu/back-main.png"
1558 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
1559 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
1561 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
1564 debug("[FritzDisplayCalls] backMainLine: " + backMainLine)
1566 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1568 <screen name="FritzDisplayCalls" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
1570 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1571 <convert type="ClockToText">Default</convert>
1573 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1574 <convert type="ClockToText">Date</convert>
1576 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
1578 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#353e575e" transparent="1" />
1579 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
1581 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
1582 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
1583 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
1584 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
1585 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1586 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1587 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1588 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1589 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
1591 self.width, self.height, _("Phone calls"),
1593 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
1594 scaleH(890, XXX), scaleV(70, XXX), scaleH(320, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
1595 "FritzCall " + _("Phone calls"), scaleH(500, XXX), scaleV(63, XXX), scaleH(330, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
1596 scaleH(80, XXX), scaleV(150, XXX), scaleH(280, XXX), scaleV(200, XXX), scaleV(22, XXX), # statusbar
1597 scaleH(420, XXX), scaleV(120, XXX), scaleH(790, XXX), scaleV(438, XXX), # entries
1598 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
1599 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
1600 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
1601 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
1602 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
1603 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
1604 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
1605 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
1606 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
1609 self.width = scaleH(1100, 570)
1610 debug("[FritzDisplayCalls] width: " + str(self.width))
1611 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1613 <screen name="FritzDisplayCalls" position="%d,%d" size="%d,%d" title="%s" >
1614 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1615 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
1616 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1617 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
1618 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1619 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1620 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1621 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1622 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1623 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1624 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1625 <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1626 <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1628 scaleH(90, 75), scaleV(100, 78), # position
1629 scaleH(1100, 570), scaleV(560, 430), # size
1631 scaleH(1100, 570), # eLabel width
1632 scaleH(40, 5), scaleV(10, 5), # statusbar position
1633 scaleH(1050, 560), scaleV(25, 22), # statusbar size
1634 scaleV(21, 21), # statusbar font size
1635 scaleV(40, 28), # eLabel position vertical
1636 scaleH(1100, 570), # eLabel width
1637 scaleH(40, 5), scaleV(55, 40), # entries position
1638 scaleH(1040, 560), scaleV(458, 340), # entries size
1639 scaleV(518, 390), # eLabel position vertical
1640 scaleH(1100, 570), # eLabel width
1641 scaleH(20, 5), scaleV(525, 395), # widget red
1642 scaleH(290, 145), scaleV(525, 395), # widget green
1643 scaleH(560, 285), scaleV(525, 395), # widget yellow
1644 scaleH(830, 425), scaleV(525, 395), # widget blue
1645 scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
1646 scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
1647 scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
1648 scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
1651 Screen.__init__(self, session)
1652 HelpableScreen.__init__(self)
1654 # TRANSLATORS: keep it short, this is a button
1655 self["key_yellow"] = Button(_("All"))
1656 # TRANSLATORS: keep it short, this is a button
1657 self["key_red"] = Button(_("Missed"))
1658 # TRANSLATORS: keep it short, this is a button
1659 self["key_blue"] = Button(_("Incoming"))
1660 # TRANSLATORS: keep it short, this is a button
1661 self["key_green"] = Button(_("Outgoing"))
1663 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1665 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1666 "red": (lambda: self.display(FBF_MISSED_CALLS)),
1667 "blue": (lambda: self.display(FBF_IN_CALLS)),
1668 "green": (lambda: self.display(FBF_OUT_CALLS)),
1670 "ok": self.showEntry, }, - 2)
1672 # TRANSLATORS: keep it short, this is a help text
1673 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1674 # TRANSLATORS: keep it short, this is a help text
1675 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1676 # TRANSLATORS: keep it short, this is a help text
1677 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1678 # TRANSLATORS: keep it short, this is a help text
1679 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1680 # TRANSLATORS: keep it short, this is a help text
1681 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1682 # TRANSLATORS: keep it short, this is a help text
1683 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1685 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1686 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
1687 fontSize = scaleV(22, 18)
1688 fontHeight = scaleV(24, 20)
1689 self["entries"].l.setFont(0, gFont("Regular", fontSize))
1690 self["entries"].l.setItemHeight(fontHeight)
1692 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1698 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
1699 debug("[FritzDisplayCalls] display")
1700 config.plugins.FritzCall.fbfCalls.value = which
1701 config.plugins.FritzCall.fbfCalls.save()
1702 self.header = fbfCallsChoices[which]
1703 fritzbox.getCalls(self, self.gotCalls, which)
1705 def gotCalls(self, callList):
1706 debug("[FritzDisplayCalls] gotCalls")
1707 self.updateStatus(self.header + " (" + str(len(callList)) + ")")
1708 dateFieldWidth = scaleH(130,100)
1710 lengthFieldWidth = scaleH(45,45)
1711 scrollbarWidth = scaleH(35,35)
1712 if config.plugins.FritzCall.fullscreen.value:
1713 remoteFieldWidth = scaleH(140,100)
1714 fieldWidth = 790 -dateFieldWidth -5 -dirFieldWidth -5 -lengthFieldWidth -5 -remoteFieldWidth -scrollbarWidth -5
1715 fontSize = scaleV(24,20)
1717 remoteFieldWidth = scaleH(160,100)
1718 fieldWidth = self.width -scaleH(60, 5) -dateFieldWidth -5 -dirFieldWidth -5 -lengthFieldWidth -5 -remoteFieldWidth -scrollbarWidth -5
1719 fontSize = scaleV(24,20)
1721 for (number, date, remote, direct, here, length) in callList:
1722 found = re.match("(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
1723 if found: date = found.group(1) + found.group(2)
1724 if direct == FBF_OUT_CALLS:
1725 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1726 elif direct == FBF_IN_CALLS:
1727 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1729 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1730 # debug("[FritzDisplayCalls] gotCalls: d: %d; f: %d; d: %d; r: %d" %(dateFieldWidth, fieldWidth, dirFieldWidth, remoteFieldWidth))
1731 sortlist.append([number,
1732 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, dateFieldWidth, fontSize, 0, RT_HALIGN_LEFT, date),
1733 (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, dateFieldWidth+5, 0, dirFieldWidth, 16, dir),
1734 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5, 0, fieldWidth, fontSize, 0, RT_HALIGN_LEFT, here),
1735 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5+fieldWidth+5, 0, lengthFieldWidth, fontSize, 0, RT_HALIGN_LEFT, length),
1736 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5+fieldWidth+5+lengthFieldWidth+5, 0, remoteFieldWidth, fontSize, 0, RT_HALIGN_RIGHT, remote)
1739 self["entries"].setList(sortlist)
1741 def updateStatus(self, text):
1742 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1744 def showEntry(self):
1745 debug("[FritzDisplayCalls] showEntry")
1746 cur = self["entries"].getCurrent()
1749 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1751 fullname = phonebook.search(cur[0])
1753 # we have a name for this number
1755 self.session.open(FritzOfferAction, self, number, name)
1758 fullname = resolveNumberWithAvon(number, config.plugins.FritzCall.country.value)
1761 self.session.open(FritzOfferAction, self, number, name)
1763 self.session.open(FritzOfferAction, self, number)
1765 # we do not even have a number...
1766 self.session.open(MessageBox,
1768 type=MessageBox.TYPE_INFO)
1771 class FritzOfferAction(Screen):
1773 def __init__(self, session, parent, number, name=""):
1774 # the layout will completely be recalculated in finishLayout
1775 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1777 <screen name="FritzOfferAction" title="%s" >
1778 <widget name="text" size="%d,%d" font="Regular;%d" />
1779 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1780 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1781 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1782 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1783 <widget name="key_red" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1784 <widget name="key_green" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1785 <widget name="key_yellow" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1788 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1789 scaleH(22,21), # text
1790 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1792 debug("[FritzOfferAction] init: %s, %s" %(number, name))
1793 Screen.__init__(self, session)
1795 # TRANSLATORS: keep it short, this is a button
1796 self["key_red"] = Button(_("Lookup"))
1797 # TRANSLATORS: keep it short, this is a button
1798 self["key_green"] = Button(_("Call"))
1799 # TRANSLATORS: keep it short, this is a button
1800 self["key_yellow"] = Button(_("Save"))
1801 # TRANSLATORS: keep it short, this is a button
1802 # self["key_blue"] = Button(_("Search"))
1804 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1809 "cancel": self.exit,
1810 "ok": self.exit, }, - 2)
1812 self.number = number
1813 self.name = name.replace("\n", ", ")
1814 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
1815 self.parent = parent
1816 self.lookupState = 0
1817 self["key_red_p"] = Pixmap()
1818 self["key_green_p"] = Pixmap()
1819 self["key_yellow_p"] = Pixmap()
1820 self["FacePixmap"] = Pixmap()
1821 self.onLayoutFinish.append(self.finishLayout)
1823 def finishLayout(self):
1824 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self.number, self.name))
1826 picPixmap = LoadPixmap(findFace(self.number, self.name))
1827 if not picPixmap: # that means most probably, that the picture is not 8 bit...
1828 picPixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_question.png"))
1829 picSize = picPixmap.size()
1830 self["FacePixmap"].instance.setPixmap(picPixmap)
1833 # recalculate window size
1834 textSize = self["text"].getSize()
1835 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
1836 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
1837 textSize = eSize(*textSize)
1838 width = max(scaleH(620,545), noButtons*145, picSize.width() + textSize.width() + 30)
1839 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1,136)) + 5 + 40 + 5
1840 buttonsGap = (width-noButtons*140)/(noButtons+1)
1841 buttonsVPos = height-40-5
1842 wSize = (width, height)
1843 wSize = eSize(*wSize)
1845 # center the smaller vertically
1846 hGap = (width-picSize.width()-textSize.width())/3
1847 picPos = (hGap,(height-50-picSize.height())/2+5)
1848 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
1851 self.instance.resize(wSize)
1853 self["text"].instance.resize(textSize)
1855 self["FacePixmap"].instance.resize(picSize)
1857 buttonPos = (buttonsGap, buttonsVPos)
1858 self["key_red_p"].instance.move(ePoint(*buttonPos))
1859 self["key_red"].instance.move(ePoint(*buttonPos))
1860 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
1861 self["key_green_p"].instance.move(ePoint(*buttonPos))
1862 self["key_green"].instance.move(ePoint(*buttonPos))
1863 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
1864 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
1865 self["key_yellow"].instance.move(ePoint(*buttonPos))
1867 self["text"].instance.move(ePoint(*textPos))
1869 self["FacePixmap"].instance.move(ePoint(*picPos))
1871 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
1873 def setTextAndResize(self, message):
1874 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH,DESKTOP_HEIGHT)))
1875 self["text"].setText(self.number + "\n\n" + message)
1879 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
1880 if self.lookupState == 0:
1881 self.lookupState = 1
1882 self.setTextAndResize(_("Reverse searching..."))
1883 ReverseLookupAndNotifier(self.number, self.lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
1885 if self.lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
1886 self.setTextAndResize(_("Searching in Outlook export..."))
1887 self.lookupState = 2
1888 self.lookedUp(self.number, FritzOutlookCSV.findNumber(self.number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
1891 self.lookupState = 2
1892 if self.lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
1893 self.setTextAndResize(_("Searching in LDIF..."))
1894 self.lookupState = 0
1895 FritzLDIF.findNumber(self.number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self.lookedUp)
1898 self.lookupState = 0
1901 def lookedUp(self, number, name):
1902 name = handleReverseLookupResult(name)
1904 if self.lookupState == 1:
1905 name = _("No result from reverse lookup")
1906 elif self.lookupState == 2:
1907 name = _("No result from Outlook export")
1909 name = _("No result from LDIF")
1911 self.number = number
1912 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
1913 self.setTextAndResize(str(name.replace(", ", "\n")))
1916 debug("[FritzOfferAction] add: %s" %self.number)
1917 fritzbox.dial(self.number)
1921 debug("[FritzOfferAction] add: %s, %s" %(self.number, self.name))
1922 phonebook.FritzDisplayPhonebook(self.session).add(self.parent, self.number, self.name)
1929 class FritzCallPhonebook:
1931 debug("[FritzCallPhonebook] init")
1932 # Beware: strings in phonebook.phonebook have to be in utf-8!
1937 debug("[FritzCallPhonebook] reload")
1938 # Beware: strings in phonebook.phonebook have to be in utf-8!
1941 if not config.plugins.FritzCall.enable.value:
1944 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1945 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
1946 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
1947 phonebookTxtCorrupt = False
1948 for line in open(phonebookFilename):
1950 # Beware: strings in phonebook.phonebook have to be in utf-8!
1951 line = line.decode("utf-8")
1952 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
1954 line = line.decode("iso-8859-1")
1955 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
1956 phonebookTxtCorrupt = True
1958 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1959 phonebookTxtCorrupt = True
1960 line = line.encode("utf-8")
1961 if re.match("^\d+#.*$", line):
1963 number, name = line.split("#")
1964 if not self.phonebook.has_key(number):
1965 # Beware: strings in phonebook.phonebook have to be in utf-8!
1966 self.phonebook[number] = name
1967 except ValueError: # how could this possibly happen?!?!
1968 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1969 phonebookTxtCorrupt = True
1971 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1972 phonebookTxtCorrupt = True
1974 if phonebookTxtCorrupt:
1975 # dump phonebook to PhoneBook.txt
1976 debug("[FritzCallPhonebook] dump Phonebook.txt")
1977 os.rename(phonebookFilename, phonebookFilename + ".bck")
1978 fNew = open(phonebookFilename, 'w')
1979 # Beware: strings in phonebook.phonebook are utf-8!
1980 for (number, name) in self.phonebook.iteritems():
1981 # Beware: strings in PhoneBook.txt have to be in utf-8!
1982 fNew.write(number + "#" + name.encode("utf-8"))
1985 #===============================================================================
1987 # # read entries from Outlook export
1989 # # not reliable with coding yet
1991 # # import csv exported from Outlook 2007 with csv(Windows)
1992 # csvFilename = "/tmp/PhoneBook.csv"
1993 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
1995 # readOutlookCSV(csvFilename, self.add)
1996 # os.rename(csvFilename, csvFilename + ".done")
1997 # except ImportError:
1998 # debug("[FritzCallPhonebook] CSV import failed" %line)
1999 #===============================================================================
2002 #===============================================================================
2004 # # read entries from LDIF
2006 # # import ldif exported from Thunderbird 2.0.0.19
2007 # ldifFilename = "/tmp/PhoneBook.ldif"
2008 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
2010 # parser = MyLDIF(open(ldifFilename), self.add)
2012 # os.rename(ldifFilename, ldifFilename + ".done")
2013 # except ImportError:
2014 # debug("[FritzCallPhonebook] LDIF import failed" %line)
2015 #===============================================================================
2017 if config.plugins.FritzCall.fritzphonebook.value:
2018 fritzbox.loadFritzBoxPhonebook()
2020 if DESKTOP_WIDTH <> 1280 or DESKTOP_HEIGHT <> 720:
2021 config.plugins.FritzCall.fullscreen.value = False
2023 def search(self, number):
2024 # debug("[FritzCallPhonebook] Searching for %s" %number
2026 if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
2027 if self.phonebook.has_key(number):
2028 name = self.phonebook[number].replace(", ", "\n").strip()
2031 def add(self, number, name):
2034 @param number: number of entry
2035 @param name: name of entry, has to be in utf-8
2037 debug("[FritzCallPhonebook] add")
2038 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
2040 self.phonebook[number] = name;
2041 if number and number <> 0:
2042 if config.plugins.FritzCall.phonebook.value:
2044 name = name.strip() + "\n"
2045 string = "%s#%s" % (number, name)
2046 # Beware: strings in PhoneBook.txt have to be in utf-8!
2047 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
2050 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
2056 def remove(self, number):
2057 if number in self.phonebook:
2058 debug("[FritzCallPhonebook] remove entry in phonebook")
2059 del self.phonebook[number]
2060 if config.plugins.FritzCall.phonebook.value:
2062 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
2063 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
2064 fOld = open(phonebookFilename, 'r')
2065 fNew = open(phonebookFilename + str(os.getpid()), 'w')
2066 line = fOld.readline()
2068 if not re.match("^" + number + "#.*$", line):
2070 line = fOld.readline()
2073 os.remove(phonebookFilename)
2074 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
2075 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
2082 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
2084 def __init__(self, session):
2085 if config.plugins.FritzCall.fullscreen.value:
2086 self.width = DESKTOP_WIDTH
2087 self.height = DESKTOP_HEIGHT
2088 self.entriesWidth = 790
2090 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
2091 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
2092 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
2093 backMainPng = "Kerni-HD1/menu/back-main.png"
2094 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
2095 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
2097 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
2100 debug("[FritzDisplayPhonebook] backMainLine: " + backMainLine)
2102 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2104 <screen name="FritzdisplayPhonebook" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
2106 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2107 <convert type="ClockToText">Default</convert>
2109 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2110 <convert type="ClockToText">Date</convert>
2112 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
2114 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
2116 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
2117 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
2118 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
2119 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
2120 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2121 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2122 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2123 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2124 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
2126 self.width, self.height, _("Phonebook"),
2128 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
2129 scaleH(890, XXX), scaleV(70, XXX), scaleH(320, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
2130 "FritzCall " + _("Phonebook"), scaleH(80, XXX), scaleV(63, XXX), scaleH(300, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
2131 scaleH(420, XXX), scaleV(120, XXX), scaleH(self.entriesWidth, XXX), scaleV(438, XXX), # entries
2132 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
2133 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
2134 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
2135 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
2136 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
2137 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
2138 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
2139 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
2140 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
2143 self.width = scaleH(1100, 570)
2144 self.entriesWidth = scaleH(1040, 560)
2145 debug("[FritzDisplayPhonebook] width: " + str(self.width))
2146 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2148 <screen name="FritzDisplayPhonebook" position="%d,%d" size="%d,%d" title="%s" >
2149 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2150 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
2151 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2152 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2153 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2154 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
2155 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
2156 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2157 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2158 <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2159 <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2161 scaleH(90, 75), scaleV(100, 73), # position
2162 scaleH(1100, 570), scaleV(560, 430), # size
2164 scaleH(1100, 570), # eLabel width
2165 scaleH(40, 5), scaleV(20, 5), # entries position
2166 self.entriesWidth, scaleV(488, 380), # entries size
2167 scaleV(518, 390), # eLabel position vertical
2168 scaleH(1100, 570), # eLabel width
2169 scaleH(20, 5), scaleV(525, 395), # ePixmap red
2170 scaleH(290, 145), scaleV(525, 395), # ePixmap green
2171 scaleH(560, 285), scaleV(525, 395), # ePixmap yellow
2172 scaleH(830, 425), scaleV(525, 395), # ePixmap blue
2173 scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
2174 scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
2175 scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
2176 scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
2179 Screen.__init__(self, session)
2180 NumericalTextInput.__init__(self)
2181 HelpableScreen.__init__(self)
2183 # TRANSLATORS: keep it short, this is a button
2184 self["key_red"] = Button(_("Delete"))
2185 # TRANSLATORS: keep it short, this is a button
2186 self["key_green"] = Button(_("New"))
2187 # TRANSLATORS: keep it short, this is a button
2188 self["key_yellow"] = Button(_("Edit"))
2189 # TRANSLATORS: keep it short, this is a button
2190 self["key_blue"] = Button(_("Search"))
2192 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
2196 "yellow": self.edit,
2197 "blue": self.search,
2198 "cancel": self.exit,
2199 "ok": self.showEntry, }, - 2)
2201 # TRANSLATORS: keep it short, this is a help text
2202 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
2203 # TRANSLATORS: keep it short, this is a help text
2204 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
2205 # TRANSLATORS: keep it short, this is a help text
2206 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
2207 # TRANSLATORS: keep it short, this is a help text
2208 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
2209 # TRANSLATORS: keep it short, this is a help text
2210 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
2211 # TRANSLATORS: keep it short, this is a help text
2212 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
2214 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
2215 fontSize = scaleV(22, 18)
2216 fontHeight = scaleV(24, 20)
2217 self["entries"].l.setFont(0, gFont("Regular", fontSize))
2218 self["entries"].l.setItemHeight(fontHeight)
2219 debug("[FritzCallPhonebook] displayPhonebook init")
2222 def display(self, filter=""):
2223 debug("[FritzCallPhonebook] displayPhonebook/display")
2225 # Beware: strings in phonebook.phonebook are utf-8!
2226 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
2227 for (low, name, number) in sortlistHelp:
2228 if number == "01234567890":
2231 low = low.decode("utf-8")
2232 except (UnicodeDecodeError, UnicodeEncodeError): # this should definitely not happen
2234 low = low.decode("iso-8859-1")
2236 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
2237 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
2238 phonebook.remove(number)
2242 filter = filter.lower()
2243 if low.find(filter) == - 1:
2245 name = name.strip().decode("utf-8")
2246 number = number.strip().decode("utf-8")
2247 found = re.match("([^,]*),.*", name) # strip address information from the name part
2249 shortname = found.group(1)
2252 numberFieldWidth = scaleV(200,150)
2253 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10 -scaleH(90,45)
2254 number = number.encode("utf-8", "replace")
2255 name = name.encode("utf-8", "replace")
2256 shortname = shortname.encode('utf-8', 'replace')
2257 self.sortlist.append([(number, name),
2258 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, fieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, shortname),
2259 (eListboxPythonMultiContent.TYPE_TEXT, fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, number)
2262 self["entries"].setList(self.sortlist)
2264 def showEntry(self):
2265 cur = self["entries"].getCurrent()
2267 debug("[FritzCallPhonebook] displayPhonebook/showEntry (%s,%s)" % (cur[0][0], cur[0][1]))
2270 self.session.open(FritzOfferAction, self, number, name)
2273 cur = self["entries"].getCurrent()
2275 debug("[FritzCallPhonebook] displayPhonebook/delete " + cur[0][0])
2276 self.session.openWithCallback(
2277 self.deleteConfirmed,
2279 _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
2280 % { 'number':str(cur[0][0]), 'name':str(cur[0][1]).replace(", ", "\n") }
2283 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2285 def deleteConfirmed(self, ret):
2286 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
2288 # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2290 cur = self["entries"].getCurrent()
2293 # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2294 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed: remove " + cur[0][0])
2295 phonebook.remove(cur[0][0])
2298 # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
2300 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2302 def add(self, parent=None, number="", name=""):
2303 class addScreen(Screen, ConfigListScreen):
2304 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
2306 def __init__(self, session, parent, number="", name=""):
2308 # setup screen with two ConfigText and OK and ABORT button
2311 width = max(scaleH(-1,570), noButtons*140)
2312 height = scaleV(-1,100) # = 5 + 126 + 40 + 5; 6 lines of text possible
2313 buttonsGap = (width-noButtons*140)/(noButtons+1)
2314 buttonsVPos = height-40-5
2315 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2317 <screen position="%d,%d" size="%d,%d" title="%s" >
2318 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
2319 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2320 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2321 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2322 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2324 (DESKTOP_WIDTH - width) / 2,
2325 (DESKTOP_HEIGHT - height) / 2,
2328 _("Add entry to phonebook"),
2330 height - 5 - 40 - 5,
2331 buttonsGap, buttonsVPos,
2332 buttonsGap+140+buttonsGap, buttonsVPos,
2333 buttonsGap, buttonsVPos,
2334 buttonsGap+140+buttonsGap, buttonsVPos,
2336 Screen.__init__(self, session)
2337 self.session = session
2338 self.parent = parent
2339 # TRANSLATORS: keep it short, this is a button
2340 self["key_red"] = Button(_("Cancel"))
2341 # TRANSLATORS: keep it short, this is a button
2342 self["key_green"] = Button(_("OK"))
2343 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2345 "cancel": self.cancel,
2352 ConfigListScreen.__init__(self, self.list, session=session)
2353 config.plugins.FritzCall.name.value = name
2354 config.plugins.FritzCall.number.value = number
2355 self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
2356 self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
2357 self["config"].list = self.list
2358 self["config"].l.setList(self.list)
2361 # get texts from Screen
2362 # add (number,name) to sortlist and phonebook.phonebook and disk
2363 self.number = config.plugins.FritzCall.number.value
2364 self.name = config.plugins.FritzCall.name.value
2365 if not self.number or not self.name:
2366 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
2368 # add (number,name) to sortlist and phonebook.phonebook and disk
2369 # oldname = phonebook.search(self.number)
2371 # self.session.openWithCallback(
2372 # self.overwriteConfirmed,
2374 # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
2376 # 'number':self.number,
2378 # 'newname':self.name.replace(", ","\n")
2383 phonebook.add(self.number, self.name)
2385 self.parent.display()
2387 def overwriteConfirmed(self, ret):
2389 phonebook.remove(self.number)
2390 phonebook.add(self.number, self.name)
2391 self.parent.display()
2396 debug("[FritzCallPhonebook] displayPhonebook/add")
2399 self.session.open(addScreen, parent, number, name)
2402 debug("[FritzCallPhonebook] displayPhonebook/edit")
2403 cur = self["entries"].getCurrent()
2405 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2407 (number, name) = cur[0]
2408 self.add(self, number, name)
2411 debug("[FritzCallPhonebook] displayPhonebook/search")
2412 self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
2413 self.help_window.show()
2414 self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
2416 def doSearch(self, searchTerms):
2417 if not searchTerms: searchTerms = ""
2418 debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
2419 if self.help_window:
2420 self.session.deleteDialog(self.help_window)
2421 self.help_window = None
2422 self.display(searchTerms)
2427 phonebook = FritzCallPhonebook()
2429 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
2431 def __init__(self, session, args=None): #@UnusedVariable
2432 if config.plugins.FritzCall.fullscreen.value:
2433 self.width = DESKTOP_WIDTH
2434 self.height = DESKTOP_HEIGHT
2437 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
2438 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
2439 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
2440 backMainPng = "Kerni-HD1/menu/back-main.png"
2441 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
2442 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
2444 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
2447 debug("[FritzCallSetup] backMainLine: " + backMainLine)
2448 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2450 <screen name="FritzCallSetup" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
2452 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2453 <convert type="ClockToText">Default</convert>
2455 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2456 <convert type="ClockToText">Date</convert>
2458 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
2460 <widget name="consideration" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#353e575e" transparent="1" />
2461 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
2463 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
2464 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
2465 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
2466 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
2467 <ePixmap pixmap="skin_default/buttons/key_info.png" position="%d,%d" size="%d,%d" alphatest="on" />
2468 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="%d,%d" size="%d,%d" alphatest="on" />
2469 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2470 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2471 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2472 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2473 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
2475 self.width, self.height, _("FritzCall Setup"),
2477 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
2478 scaleH(890, XXX), scaleV(70, XXX), scaleH(320, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
2479 _("FritzCall Setup"), scaleH(500, XXX), scaleV(63, XXX), scaleH(330, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
2480 scaleH(80, XXX), scaleV(150, XXX), scaleH(250, XXX), scaleV(200, XXX), scaleV(22, XXX), # consideration
2481 scaleH(420, XXX), scaleV(125, XXX), scaleH(790, XXX), scaleV(428, XXX), # config
2482 scaleH(150, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
2483 scaleH(350, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
2484 scaleH(550, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
2485 scaleH(750, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
2486 scaleH(1050, XXX), scaleV(586, XXX), scaleH(35, XXX), scaleV(24, XXX), # info
2487 scaleH(1150, XXX), scaleV(586, XXX), scaleH(35, XXX), scaleV(24, XXX), # menu
2488 scaleH(175, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
2489 scaleH(375, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
2490 scaleH(575, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
2491 scaleH(775, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
2492 scaleH(120, XXX), scaleV(430, XXX), scaleH(150, XXX), scaleV(110, XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png") # Fritz Logo size and pixmap
2495 self.width = scaleH(20+4*(140+90)+2*(35+40)+20, 4*140+2*35)
2497 debug("[FritzCallSetup] width: " + str(self.width))
2498 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2500 <screen name="FritzCallSetup" position="%d,%d" size="%d,%d" title="%s" >
2501 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2502 <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="#20040404" transparent="1" />
2503 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2504 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
2505 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2506 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2507 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2508 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
2509 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
2510 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2511 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2512 <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2513 <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2514 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="skin_default/buttons/key_info.png" transparent="1" alphatest="on" />
2515 <ePixmap position="%d,%d" zPosition="4" size="35,25" pixmap="skin_default/buttons/key_menu.png" transparent="1" alphatest="on" />
2517 (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position
2518 width, scaleV(560, 430), # size
2519 _("FritzCall Setup") +
2520 " (" + "$Revision$"[1: - 1] +
2521 "$Date$"[7:23] + ")",
2522 width, # eLabel width
2523 scaleH(40, 20), scaleV(10, 5), # consideration position
2524 scaleH(width-80, width-40), scaleV(25, 45), # consideration size
2525 scaleV(22, 20), # consideration font size
2526 scaleV(40, 50), # eLabel position vertical
2527 width, # eLabel width
2528 scaleH(40, 5), scaleV(60, 57), # config position
2529 scaleH(width-80, width-10), scaleV(453, 328), # config size
2530 scaleV(518, 390), # eLabel position vertical
2531 width, # eLabel width
2532 scaleH(20, 0), scaleV(525, 395), # pixmap red
2533 scaleH(20+140+90, 140), scaleV(525, 395), # pixmap green
2534 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), # pixmap yellow
2535 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), # pixmap blue
2536 scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # pixmap red
2537 scaleH(20+(140+90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
2538 scaleH(20+2*(140+90), 2*140), scaleV(525, 395), scaleV(21, 21), # widget yellow
2539 scaleH(20+3*(140+90), 3*140), scaleV(525, 395), scaleV(21, 21), # widget blue
2540 scaleH(20+4*(140+90), 4*140), scaleV(532, 402), # button info
2541 scaleH(20+4*(140+90)+(35+40), 4*140+35), scaleV(532, 402) # button menu
2544 Screen.__init__(self, session)
2545 HelpableScreen.__init__(self)
2546 self.session = session
2548 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
2551 # Initialize Buttons
2552 # TRANSLATORS: keep it short, this is a button
2553 self["key_red"] = Button(_("Cancel"))
2554 # TRANSLATORS: keep it short, this is a button
2555 self["key_green"] = Button(_("OK"))
2556 # TRANSLATORS: keep it short, this is a button
2557 self["key_yellow"] = Button(_("Phone calls"))
2558 # TRANSLATORS: keep it short, this is a button
2559 self["key_blue"] = Button(_("Phonebook"))
2560 # TRANSLATORS: keep it short, this is a button
2561 self["key_info"] = Button(_("About FritzCall"))
2562 # TRANSLATORS: keep it short, this is a button
2563 self["key_menu"] = Button(_("FRITZ!Box Fon Status"))
2565 self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
2569 "yellow": self.displayCalls,
2570 "blue": self.displayPhonebook,
2571 "cancel": self.cancel,
2577 # TRANSLATORS: keep it short, this is a help text
2578 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
2579 # TRANSLATORS: keep it short, this is a help text
2580 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
2581 # TRANSLATORS: keep it short, this is a help text
2582 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
2583 # TRANSLATORS: keep it short, this is a help text
2584 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
2585 # TRANSLATORS: keep it short, this is a help text
2586 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("save and quit"))]))
2587 # TRANSLATORS: keep it short, this is a help text
2588 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("quit"))]))
2589 # TRANSLATORS: keep it short, this is a help text
2590 self.helpList.append((self["setupActions"], "MenuActions", [("menu", _("FRITZ!Box Fon Status"))]))
2591 # TRANSLATORS: keep it short, this is a help text
2592 self.helpList.append((self["setupActions"], "EPGSelectActions", [("info", _("About FritzCall"))]))
2594 ConfigListScreen.__init__(self, self.list, session=session)
2599 ConfigListScreen.keyLeft(self)
2603 ConfigListScreen.keyRight(self)
2606 def createSetup(self):
2608 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
2609 if config.plugins.FritzCall.enable.value:
2610 self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
2611 self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
2613 self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
2615 self.list.append(getConfigListEntry(_("Show Calls for specific MSN"), config.plugins.FritzCall.filter))
2616 if config.plugins.FritzCall.filter.value:
2617 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
2619 self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
2620 if config.plugins.FritzCall.showOutgoing.value:
2621 self.list.append(getConfigListEntry(_("Areacode to add to Outgoing Calls (if necessary)"), config.plugins.FritzCall.prefix))
2622 self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
2623 self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
2624 if config.plugins.FritzCall.lookup.value:
2625 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
2627 self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
2628 self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
2629 self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
2630 if config.plugins.FritzCall.fritzphonebook.value:
2631 self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
2632 self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
2633 self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
2635 self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
2636 if config.plugins.FritzCall.phonebook.value:
2637 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
2638 if config.plugins.FritzCall.lookup.value:
2639 self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
2641 self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
2642 # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
2643 if DESKTOP_WIDTH == 1280 and DESKTOP_HEIGHT == 720:
2644 self.list.append(getConfigListEntry(_("Full screen display"), config.plugins.FritzCall.fullscreen))
2645 self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
2647 self["config"].list = self.list
2648 self["config"].l.setList(self.list)
2651 # debug("[FritzCallSetup] save"
2652 for x in self["config"].list:
2655 fritz_call.connect()
2659 # debug("[FritzCallSetup] cancel"
2660 for x in self["config"].list:
2664 def displayCalls(self):
2665 self.session.open(FritzDisplayCalls)
2667 def displayPhonebook(self):
2668 self.session.open(phonebook.FritzDisplayPhonebook)
2671 self.session.open(FritzAbout)
2674 self.session.open(FritzMenu)
2678 class FritzCallList:
2682 def add(self, event, date, number, caller, phone):
2683 debug("[FritzCallList] add")
2684 if len(self.callList) > 10:
2685 if self.callList[0] != "Start":
2686 self.callList[0] = "Start"
2687 del self.callList[1]
2689 self.callList.append((event, number, date, caller, phone))
2692 debug("[FritzCallList] display")
2694 global my_global_session
2696 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
2697 # build screen from call list
2699 if self.callList[0] == "Start":
2700 text = text + _("Last 10 calls:\n")
2701 del self.callList[0]
2703 for call in self.callList:
2704 (event, number, date, caller, phone) = call
2710 # shorten the date info
2711 found = re.match(".*(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
2712 if found: date = found.group(1) + found.group(2)
2714 # our phone could be of the form "0123456789 (home)", then we only take "home"
2715 found = re.match(".*\((.*)\)", phone)
2716 if found: phone = found.group(1)
2718 # if we have an unknown number, show the number
2719 if caller == _("UNKNOWN") and number != "":
2722 # strip off the address part of the remote number, if there is any
2723 found = re.match("(.*)\n.*", caller)
2724 if found: caller = found.group(1)
2726 while (len(caller) + len(phone)) > 40:
2727 if len(caller) > len(phone):
2728 caller = caller[: - 1]
2730 phone = phone[: - 1]
2732 text = text + "%s %s %s %s\n" % (date, caller, direction, phone)
2734 debug("[FritzCallList] display: '%s %s %s %s'" % (date, caller, direction, phone))
2736 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
2737 # my_global_session.open(FritzDisplayCalls, text) # TODO please HELP: from where can I get a session?
2741 callList = FritzCallList()
2743 def findFace(number,name):
2744 debug("[FritzCall] findFace number/name: %s/%s" % (number, name))
2745 sep = name.find(',')
2746 if sep != -1: name = name[:sep]
2747 sep = name.find('\n')
2748 if sep != -1: name = name[:sep]
2750 #===========================================================================
2752 # for filename in os.listdir(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")):
2753 # debug("[FritzCall] findFace check: %s name: %s" % (repr(filename.decode('utf-8')), repr(name.decode('utf-8'))))
2754 # if re.match("^" + number + "\.(png|PNG|jpg|JPG)$", filename) or re.match("^" + name.decode('utf-8') + "\.(png|PNG|jpg|JPG)$", filename.decode('utf-8')):
2755 # facesFile = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces", filename)
2758 # facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2759 #===========================================================================
2760 facesDir = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "FritzCallFaces")
2761 numberFile = os.path.join(facesDir, number)
2762 nameFile = os.path.join(facesDir, name)
2764 if number and os.path.exists(numberFile):
2765 facesFile = numberFile
2766 elif number and os.path.exists(numberFile + ".png"):
2767 facesFile = numberFile + ".png"
2768 elif number and os.path.exists(numberFile + ".PNG"):
2769 facesFile = numberFile + ".PNG"
2770 elif name and os.path.exists(nameFile + ".png"):
2771 facesFile = nameFile + ".png"
2772 elif name and os.path.exists(nameFile + ".PNG"):
2773 facesFile = nameFile + ".PNG"
2775 facesFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/input_info.png")
2777 debug("[FritzCall] findFace result: %s" % (facesFile))
2780 class MessageBoxPixmap(Screen):
2781 def __init__(self, session, text, number = "", name = "", timeout = -1):
2783 <screen name="MessageBoxPixmap" position="%d,%d" size="600,10" title="Message">
2784 <widget name="text" position="115,8" size="520,0" font="Regular;%d" />
2785 <widget name="InfoPixmap" pixmap="skin_default/icons/input_info.png" position="5,5" size="100,100" alphatest="on" />
2788 scaleH(350,60), scaleV(175,245),
2791 debug("[FritzCall] MessageBoxPixmap number: %s" % number)
2792 Screen.__init__(self, session)
2793 # MessageBox.__init__(self, session, text, type=MessageBox.TYPE_INFO, timeout=timeout)
2794 self["text"] = Label(text)
2795 self["InfoPixmap"] = Pixmap()
2796 self.number = number
2798 self.timerRunning = False
2799 self.initTimeout(timeout)
2800 self.onLayoutFinish.append(self.finishLayout)
2801 self["actions"] = ActionMap(["OkCancelActions"],
2803 "cancel": self.exit,
2804 "ok": self.exit, }, - 2)
2806 def finishLayout(self):
2807 debug("[FritzCall] MessageBoxPixmap/setInfoPixmap number: %s/%s" % (self.number, self.name))
2809 picPixmap = LoadPixmap(findFace(self.number, self.name))
2810 picSize = picPixmap.size()
2811 self["InfoPixmap"].instance.setPixmap(picPixmap)
2813 # recalculate window size
2814 textSize = self["text"].getSize()
2815 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
2816 textSize = eSize(*textSize)
2817 width = max(scaleH(600,280), picSize.width() + textSize.width() + 30)
2818 height = max(scaleV(300,250), picSize.height()+10, textSize.height()+10)
2819 wSize = (width, height)
2820 wSize = eSize(*wSize)
2822 # center the smaller vertically
2823 hGap = (width-picSize.width()-textSize.width())/3
2824 picPos = (hGap,(height-picSize.height())/2+1)
2825 textPos = (hGap+picSize.width()+hGap, (height-textSize.height())/2+1)
2828 self.instance.resize(wSize)
2830 self["text"].instance.resize(textSize)
2832 self["InfoPixmap"].instance.resize(picSize)
2834 self["text"].instance.move(ePoint(*textPos))
2836 self["InfoPixmap"].instance.move(ePoint(*picPos))
2838 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
2840 def initTimeout(self, timeout):
2841 self.timeout = timeout
2843 self.timer = eTimer()
2844 self.timer.callback.append(self.timerTick)
2845 self.onExecBegin.append(self.startTimer)
2846 self.origTitle = None
2850 self.onShown.append(self.__onShown)
2851 self.timerRunning = True
2853 self.timerRunning = False
2855 def __onShown(self):
2856 self.onShown.remove(self.__onShown)
2859 def startTimer(self):
2860 self.timer.start(1000)
2862 #===============================================================================
2863 # def stopTimer(self):
2864 # if self.timerRunning:
2866 # self.setTitle(self.origTitle)
2867 # self.timerRunning = False
2868 #===============================================================================
2870 def timerTick(self):
2873 if self.origTitle is None:
2874 self.origTitle = self.instance.getTitle()
2875 self.setTitle(self.origTitle + " (" + str(self.timeout) + ")")
2876 if self.timeout == 0:
2878 self.timerRunning = False
2885 from GlobalActions import globalActionMap
2886 def notifyCall(event, date, number, caller, phone):
2887 if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
2888 if config.plugins.FritzCall.muteOnCall.value:
2889 globalActionMap.actions["volumeMute"]()
2891 text = _("Incoming Call on %(date)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
2893 text = _("Outgoing Call on %(date)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
2894 debug("[FritzCall] notifyCall:\n%s" % text)
2895 # Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
2896 Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.FritzCall.timeout.value)
2897 elif config.plugins.FritzCall.afterStandby.value == "inList":
2899 # if not yet done, register function to show call list
2901 if not standbyMode :
2903 Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
2904 # add text/timeout to call list
2905 callList.add(event, date, number, caller, phone)
2906 debug("[FritzCall] notifyCall: added to callList")
2907 else: # this is the "None" case
2908 debug("[FritzCall] notifyCall: standby and no show")
2911 #===============================================================================
2912 # We need a separate class for each invocation of reverseLookup to retain
2913 # the necessary data for the notification
2914 #===============================================================================
2917 reverselookupMtime = 0
2919 class FritzReverseLookupAndNotifier:
2920 def __init__(self, event, number, caller, phone, date):
2923 Initiate a reverse lookup for the given number in the configured country
2925 @param event: CALL or RING
2926 @param number: number to be looked up
2927 @param caller: caller including name and address
2928 @param phone: Number (and name) of or own phone
2929 @param date: date of call
2931 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" % number)
2933 self.number = number
2934 self.caller = caller
2938 if number[0] != "0":
2939 self.notifyAndReset(number, caller)
2942 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
2944 def notifyAndReset(self, number, caller):
2947 this gets called with the result of the reverse lookup
2949 @param number: number
2950 @param caller: name and address of remote. it comes in with name, address and city separated by commas
2952 debug("[FritzReverseLookupAndNotifier] got: " + caller)
2953 self.number = number
2954 #===============================================================================
2955 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv"):
2956 # caller = FritzOutlookCSV.findNumber(number, config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.csv") #@UndefinedVariable
2957 # debug("[FritzReverseLookupAndNotifier] got from Outlook csv: " + caller)
2958 #===============================================================================
2959 #===============================================================================
2960 # if not caller and os.path.exists(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"):
2961 # caller = FritzLDIF.findNumber(number, open(config.plugins.FritzCall.phonebookLocation.value + "/PhoneBook.ldif"))
2962 # debug("[FritzReverseLookupAndNotifier] got from ldif: " + caller)
2963 #===============================================================================
2965 name = handleReverseLookupResult(caller)
2967 self.caller = name.replace(", ", "\n").replace('#','')
2968 if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
2969 debug("[FritzReverseLookupAndNotifier] add to phonebook")
2970 phonebook.add(self.number, self.caller)
2972 self.caller = resolveNumberWithAvon(self.number, config.plugins.FritzCall.country.value)
2974 self.caller = _("UNKNOWN")
2975 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
2976 # kill that object...
2978 class FritzProtocol(LineReceiver):
2980 debug("[FritzProtocol] " + "$Revision$"[1:-1] + "$Date$"[7:23] + " starting")
2983 def resetValues(self):
2984 debug("[FritzProtocol] resetValues")
2990 def notifyAndReset(self):
2991 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
2994 def lineReceived(self, line):
2995 debug("[FritzProtocol] lineReceived: %s" % line)
2996 #15.07.06 00:38:54;CALL;1;4;<from/extern>;<to/our msn>;
2997 #15.07.06 00:38:58;DISCONNECT;1;0;
2998 #15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
2999 #15.07.06 00:39:27;DISCONNECT;0;0;
3001 (self.date, self.event) = a[0:2]
3003 if self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
3006 if self.event == "RING":
3011 debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
3013 filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
3014 for i in range(len(filtermsns)):
3015 filtermsns[i] = filtermsns[i].strip()
3016 if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
3017 debug("[FritzProtocol] lineReceived no filter hit")
3018 phonename = phonebook.search(phone) # do we have a name for the number of our side?
3019 if phonename is not None:
3020 self.phone = "%s (%s)" % (phone, phonename)
3024 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0":
3025 debug("[FritzProtocol] lineReceived: strip leading 0")
3026 self.number = number[1:]
3028 self.number = number
3029 if self.event == "CALL" and self.number[0] != '0': # should only happen for outgoing
3030 debug("[FritzProtocol] lineReceived: add local prefix")
3031 self.number = config.plugins.FritzCall.prefix.value + self.number
3033 # strip CbC prefixes
3034 if self.event == "CALL":
3035 number = stripCbCPrefix(self.number, config.plugins.FritzCall.country.value)
3037 if self.number is not "":
3038 debug("[FritzProtocol] lineReceived phonebook.search: %s" % self.number)
3039 self.caller = phonebook.search(self.number)
3040 debug("[FritzProtocol] lineReceived phonebook.search reault: %s" % self.caller)
3041 if (self.caller is None) and config.plugins.FritzCall.lookup.value:
3042 FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date)
3043 return # reverselookup is supposed to handle the message itself
3045 if self.caller is None:
3046 self.caller = _("UNKNOWN")
3048 self.notifyAndReset()
3050 class FritzClientFactory(ReconnectingClientFactory):
3055 self.hangup_ok = False
3057 def startedConnecting(self, connector): #@UnusedVariable
3058 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
3060 def buildProtocol(self, addr): #@UnusedVariable
3061 global fritzbox, phonebook
3062 Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
3067 fritzbox = FritzCallFBF()
3068 phonebook = FritzCallPhonebook()
3069 return FritzProtocol()
3071 def clientConnectionLost(self, connector, reason):
3072 if not self.hangup_ok:
3073 Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
3074 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
3076 def clientConnectionFailed(self, connector, reason):
3077 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
3078 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
3088 if config.plugins.FritzCall.enable.value:
3089 f = FritzClientFactory()
3090 self.d = (f, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, f)) #@UndefinedVariable
3096 if self.d is not None:
3097 self.d[0].hangup_ok = True
3098 self.d[0].stopTrying()
3099 self.d[1].disconnect()
3102 def displayCalls(session, servicelist=None): #@UnusedVariable
3103 session.open(FritzDisplayCalls)
3105 def displayPhonebook(session, servicelist=None): #@UnusedVariable
3106 session.open(phonebook.FritzDisplayPhonebook)
3108 def displayFBFStatus(session, servicelist=None): #@UnusedVariable
3109 session.open(FritzMenu)
3112 session.open(FritzCallSetup)
3116 def autostart(reason, **kwargs):
3119 # ouch, this is a hack
3120 if kwargs.has_key("session"):
3121 global my_global_session
3122 my_global_session = kwargs["session"]
3125 debug("[FRITZ!Call] - Autostart")
3127 fritz_call = FritzCall()
3129 fritz_call.shutdown()
3132 def Plugins(**kwargs): #@UnusedVariable
3133 what = _("Display FRITZ!box-Fon calls on screen")
3134 what_calls = _("Phone calls")
3135 what_phonebook = _("Phonebook")
3136 what_status = _("FRITZ!Box Fon Status")
3137 return [ PluginDescriptor(name="FritzCall", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
3138 PluginDescriptor(name=what_calls, description=what_calls, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
3139 PluginDescriptor(name=what_phonebook, description=what_phonebook, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
3140 PluginDescriptor(name=what_status, description=what_status, where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayFBFStatus),
3141 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]