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
25 from Components.config import ConfigPassword
27 ConfigPassword = ConfigText
28 from Components.ConfigList import ConfigListScreen
29 from Components.Harddisk import harddiskmanager
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
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
79 config.plugins.FritzCall = ConfigSubsection()
80 config.plugins.FritzCall.debug = ConfigEnableDisable(default=False)
81 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default=False)
82 config.plugins.FritzCall.hostname = ConfigText(default="fritz.box", fixed_size=False)
83 config.plugins.FritzCall.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
84 config.plugins.FritzCall.filter = ConfigEnableDisable(default=False)
85 config.plugins.FritzCall.filtermsn = ConfigText(default="", fixed_size=False)
86 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
87 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default=False)
88 config.plugins.FritzCall.timeout = ConfigInteger(default=15, limits=(0, 60))
89 config.plugins.FritzCall.lookup = ConfigEnableDisable(default=False)
90 config.plugins.FritzCall.internal = ConfigEnableDisable(default=False)
91 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default=False)
92 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default=False)
93 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default=False)
94 config.plugins.FritzCall.enable = ConfigEnableDisable(default=False)
95 config.plugins.FritzCall.password = ConfigPassword(default="", fixed_size=False)
96 config.plugins.FritzCall.extension = ConfigText(default='1', fixed_size=False)
97 config.plugins.FritzCall.extension.setUseableChars('0123456789')
98 config.plugins.FritzCall.showType = ConfigEnableDisable(default=True)
99 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default=False)
100 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default=False)
101 config.plugins.FritzCall.prefix = ConfigText(default="", fixed_size=False)
102 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
103 config.plugins.FritzCall.fullscreen = ConfigEnableDisable(default=False)
105 mountedDevs= [("/etc/enigma2", _("Flash"))]
106 if os.path.isdir("/media/cf"):
107 mountedDevs.append(("/media/cf", _("Compact Flash")))
108 if os.path.isdir("/media/usb"):
109 mountedDevs.append(("/media/usb", _("USB Device")))
110 for p in harddiskmanager.getMountedPartitions(True):
111 mp = p.mountpoint[:-1]
113 mountedDevs.append((mp, _(p.description)+ ' (' + mp + ')'))
115 mountedDevs.append((mp, mp))
116 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices=mountedDevs)
119 ("0049", _("Germany")),
120 ("0031", _("The Netherlands")),
121 ("0033", _("France")),
122 ("0039", _("Italy")),
123 ("0041", _("Switzerland")),
124 ("0043", _("Austria"))
126 config.plugins.FritzCall.country = ConfigSelection(choices=countryCodes)
130 FBF_MISSED_CALLS = "2"
132 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
133 FBF_IN_CALLS: _("Incoming calls"),
134 FBF_MISSED_CALLS: _("Missed calls"),
135 FBF_OUT_CALLS: _("Outgoing calls")
137 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices=fbfCallsChoices)
139 config.plugins.FritzCall.name = ConfigText(default="", fixed_size=False)
140 config.plugins.FritzCall.number = ConfigText(default="", fixed_size=False)
141 config.plugins.FritzCall.number.setUseableChars('0123456789')
148 os.remove("/tmp/FritzDebug.log")
152 class FritzAbout(Screen):
154 def __init__(self, session):
155 textFieldWidth = scaleV(350,250)
156 width = 5 + 150 + 20 + textFieldWidth + 5 + 175 + 5
157 height = 5 + 175 + 5 + 25 + 5
158 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
160 <screen name="FritzAbout" position="%d,%d" size="%d,%d" title="%s" >
161 <widget name="text" position="175,%d" size="%d,%d" font="Regular;%d" />
162 <ePixmap position="5,37" size="150,110" pixmap="%s" transparent="1" alphatest="blend" />
163 <ePixmap position="%d,5" size="175,175" pixmap="%s" transparent="1" alphatest="blend" />
164 <widget name="url" position="20,185" size="%d,25" font="Regular;%d" />
166 (DESKTOP_WIDTH - width) / 2, (DESKTOP_HEIGHT - height) / 2, # position
167 width, height, # size
168 _("About FritzCall"), # title
169 (height-scaleV(150,130)) / 2, # text vertical position
171 scaleV(150,130), # text height
172 scaleV(24,21), # text font size
173 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/fritz.png"), # 150x110
174 5 + 150 + 5 + textFieldWidth + 5, # qr code horizontal offset
175 resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/website.png"), # 175x175
176 width-40, # url width
177 scaleV(24,21) # url font size
179 Screen.__init__(self, session)
180 self["aboutActions"] = ActionMap(["OkCancelActions"],
185 self["text"] = Label(
186 "FritzCall Plugin" + "\n\n" +
187 "$Author$"[1:-2] + "\n" +
188 "$Revision$"[1:-2] + "\n" +
189 "$Date$"[1:23] + "\n"
191 self["url"] = Label("http://wiki.blue-panel.com/index.php/FritzCall")
208 debug("[FritzCallFBF] __init__")
209 self._callScreen = None
210 self._md5LoginTimestamp = None
211 self._md5Sid = '0000000000000000'
212 self._callTimestamp = 0
214 self._callType = config.plugins.FritzCall.fbfCalls.value
215 self.info = None # (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive)
218 def _notify(self, text):
219 debug("[FritzCallFBF] notify: " + text)
220 self._md5LoginTimestamp = None
222 debug("[FritzCallFBF] notify: try to close callScreen")
223 self._callScreen.close()
224 self._callScreen = None
225 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
227 def _login(self, callback=None):
228 debug("[FritzCallFBF] _login")
230 self._callScreen.updateStatus(_("login"))
231 if self._md5LoginTimestamp and ((time.time() - self._md5LoginTimestamp) < float(9.5*60)) and self._md5Sid != '0000000000000000': # new login after 9.5 minutes inactivity
232 debug("[FritzCallFBF] _login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
233 self._md5LoginTimestamp = time.time()
236 debug("[FritzCallFBF] _login: not logged in or outdated login")
237 # http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml
238 parms = urlencode({'getpage':'../html/login_sid.xml'})
239 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
240 debug("[FritzCallFBF] _login: '" + url + "' parms: '" + parms + "'")
243 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
244 }, postdata=parms).addCallback(lambda x: self._md5Login(callback,x)).addErrback(lambda x:self._oldLogin(callback,x))
246 def _oldLogin(self, callback, error):
247 debug("[FritzCallFBF] _oldLogin: " + repr(error))
248 self._md5LoginTimestamp = None
249 if config.plugins.FritzCall.password.value != "":
250 parms = "login:command/password=%s" % (config.plugins.FritzCall.password.value)
251 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
252 debug("[FritzCallFBF] _oldLogin: '" + url + "' parms: '" + parms + "'")
255 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
256 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
257 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
259 debug("[FritzCallFBF] _oldLogin: no password, calling " + repr(callback))
262 def _md5Login(self, callback, sidXml):
263 def buildResponse(challenge, text):
264 debug("[FritzCallFBF] _md5Login7buildResponse: challenge: " + challenge + ' text: ' + text)
265 text = (challenge + '-' + text).decode('utf-8','ignore').encode('utf-16-le')
266 for i in range(len(text)):
267 if ord(text[i]) > 255:
271 debug("[FritzCallFBF] md5Login/buildResponse: " + m.hexdigest())
272 return challenge + '-' + m.hexdigest()
274 debug("[FritzCallFBF] _md5Login")
275 found = re.match('.*<SID>([^<]*)</SID>', sidXml, re.S)
277 self._md5Sid = found.group(1)
278 debug("[FritzCallFBF] _md5Login: SID "+ self._md5Sid)
280 debug("[FritzCallFBF] _md5Login: no sid! That must be an old firmware.")
281 self._oldLogin(callback, 'No error')
284 debug("[FritzCallFBF] _md5Login: renew timestamp: " + time.ctime(self._md5LoginTimestamp) + " time: " + time.ctime())
285 self._md5LoginTimestamp = time.time()
286 if sidXml.find('<iswriteaccess>0</iswriteaccess>') != -1:
287 debug("[FritzCallFBF] _md5Login: logging in")
288 found = re.match('.*<Challenge>([^<]*)</Challenge>', sidXml, re.S)
290 challenge = found.group(1)
291 debug("[FritzCallFBF] _md5Login: challenge " + challenge)
294 debug("[FritzCallFBF] _md5Login: login necessary and no challenge! That is terribly wrong.")
296 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
297 'login:command/response': buildResponse(challenge, config.plugins.FritzCall.password.value),
299 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
300 debug("[FritzCallFBF] _md5Login: '" + url + "' parms: '" + parms + "'")
303 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
304 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
305 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self._errorLogin)
306 elif callback: # we assume value 1 here, no login necessary
307 debug("[FritzCallFBF] _md5Login: no login necessary")
310 def _gotPageLogin(self, html):
312 self._callScreen.updateStatus(_("login verification"))
313 debug("[FritzCallFBF] _gotPageLogin: verify login")
314 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
316 text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
320 self._callScreen.updateStatus(_("login ok"))
322 found = re.match('.*<input type="hidden" name="sid" value="([^\"]*)"', html, re.S)
324 self._md5Sid = found.group(1)
325 debug("[FritzCallFBF] _gotPageLogin: found sid: " + self._md5Sid)
327 def _errorLogin(self, error):
328 debug("[FritzCallFBF] _errorLogin: %s" % (error))
329 text = _("FRITZ!Box - Error logging in: %s") % error
333 if self._md5LoginTimestamp:
334 self._md5LoginTimestamp = None
336 'getpage':'../html/de/menus/menu2.html', # 'var:pagename':'home', 'var:menu':'home',
337 'login:command/logout':'bye bye Fritz'
339 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
340 debug("[FritzCallFBF] logout: '" + url + "' parms: '" + parms + "'")
343 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
344 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
345 }, postdata=parms).addErrback(self._errorLogout)
347 def _errorLogout(self, error):
348 debug("[FritzCallFBF] _errorLogout: %s" % (error))
349 text = _("FRITZ!Box - Error logging out: %s") % error
352 def loadFritzBoxPhonebook(self):
353 debug("[FritzCallFBF] loadFritzBoxPhonebook")
354 if config.plugins.FritzCall.fritzphonebook.value:
355 self._phoneBookID = '0'
356 debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
357 self._login(self._loadFritzBoxPhonebook)
359 def _loadFritzBoxPhonebook(self, html):
361 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
363 self._errorLoad('Login: ' + found.group(1))
366 'getpage':'../html/de/menus/menu2.html',
368 'var:pagename':'fonbuch',
371 'telcfg:settings/Phonebook/Books/Select':self._phoneBookID, # this selects always the first phonbook
373 url = "http://%s/cgi-bin/webcm" % (config.plugins.FritzCall.hostname.value)
374 debug("[FritzCallFBF] _loadFritzBoxPhonebook: '" + url + "' parms: '" + parms + "'")
377 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
378 headers={'Content-Type': "application/x-www-form-urlencoded", 'Content-Length': str(len(parms))
379 }, postdata=parms).addCallback(self._parseFritzBoxPhonebook).addErrback(self._errorLoad)
381 def _parseFritzBoxPhonebook(self, html):
382 debug("[FritzCallFBF] _parseFritzBoxPhonebook")
383 # if not re.search('document.write\(TrFon\("[^"]+", "[^"]+", "[^"]+", "[^"]+", "[^"]+"\)\)', html):
384 if re.search('document.write\(TrFon1\(\)', html):
385 #===============================================================================
386 # New Style: 7270 (FW 54.04.58, 54.04.63-11941, 54.04.70, 54.04.74-14371, 54.04.76)
387 # 7170 (FW 29.04.70) 22.03.2009
388 # 7141 (FW 40.04.68) 22.03.2009
389 # We expect one line with TrFonName followed by several lines with
390 # TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
391 #===============================================================================
392 found = re.match('.*<input type="hidden" name="telcfg:settings/Phonebook/Books/Name(\d+)" value="[Dd]reambox" id="uiPostPhonebookName\d+" disabled>', html, re.S)
394 phoneBookID = found.group(1)
395 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found dreambox phonebook with id: " + phoneBookID)
396 if self._phoneBookID != phoneBookID:
397 self._phoneBookID = phoneBookID
398 debug("[FritzCallFBF] _parseFritzBoxPhonebook: reload phonebook")
399 self._loadFritzBoxPhonebook(self._phoneBookID) # reload with dreambox phonebook
402 found = re.match('.*<meta http-equiv=content-type content="text/html; charset=([^"]*)">', html, re.S)
404 charset = found.group(1)
405 debug("[FritzCallFBF] _parseFritzBoxPhonebook: found charset: " + charset)
406 html = html2unicode(html.decode(charset)).encode('utf-8') # this looks silly, but has to be
407 else: # this is kind of emergency conversion...
409 html = html2unicode(html.decode('utf-8')).encode('utf-8') # this looks silly, but has to be
410 except UnicodeDecodeError:
411 html = html2unicode(html.decode('iso-8859-1')).encode('utf-8') # this looks silly, but has to be
412 entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"\);.*?)document.write\(TrFon1\(\)', re.S)
413 entries = entrymask.finditer(html)
414 for entry in entries:
415 # debug(entry.group(1)
416 # TrFonName (id, name, category)
417 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"\);', entry.group(1))
419 name = found.group(1).replace(',','').strip()
422 # TrFonNr (type, rufnr, code, vanity)
423 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
424 details = detailmask.finditer(entry.group(1))
425 for found in details:
426 thisnumber = found.group(2).strip()
428 debug("[FritzCallFBF] Ignoring entry with empty number for '''%s'''" % (name))
432 type = found.group(1)
433 if config.plugins.FritzCall.showType.value:
435 thisname = thisname + " (" + _("mobile") + ")"
437 thisname = thisname + " (" + _("home") + ")"
439 thisname = thisname + " (" + _("work") + ")"
441 if config.plugins.FritzCall.showShortcut.value and found.group(3):
442 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
443 if config.plugins.FritzCall.showVanity.value and found.group(4):
444 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
446 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (thisname.strip(), thisnumber))
447 # Beware: strings in phonebook.phonebook have to be in utf-8!
448 phonebook.phonebook[thisnumber] = thisname
450 elif re.search('document.write\(TrFon\(', html):
451 #===============================================================================
452 # Old Style: 7050 (FW 14.04.33)
453 # We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
454 # Encoding should be plain Ascii...
455 #===============================================================================
456 entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
457 entries = entrymask.finditer(html)
458 for found in entries:
459 name = found.group(1).strip().replace(',','')
460 # debug("[FritzCallFBF] pos: %s name: %s" %(found.group(0),name))
461 thisnumber = found.group(2).strip()
462 if config.plugins.FritzCall.showShortcut.value and found.group(3):
463 name = name + ", " + _("Shortcut") + ": " + found.group(3)
464 if config.plugins.FritzCall.showVanity.value and found.group(4):
465 name = name + ", " + _("Vanity") + ": " + found.group(4)
467 name = html2unicode(unicode(name)).encode('utf-8')
468 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" % (name, thisnumber))
469 # Beware: strings in phonebook.phonebook have to be in utf-8!
470 phonebook.phonebook[thisnumber] = name
472 debug("[FritzCallFBF] ignoring empty number for %s" % name)
474 elif self._md5Sid=='0000000000000000': # retry, it could be a race condition
475 debug("[FritzCallFBF] _parseFritzBoxPhonebook: retry loading phonebook")
476 self.loadFritzBoxPhonebook()
478 self._notify(_("Could not parse FRITZ!Box Phonebook entry"))
480 def _errorLoad(self, error):
481 debug("[FritzCallFBF] _errorLoad: %s" % (error))
482 text = _("FRITZ!Box - Could not load phonebook: %s") % error
485 def getCalls(self, callScreen, callback, type):
487 # call sequence must be:
489 # - getPage -> _gotPageLogin
490 # - loginCallback (_getCalls)
491 # - getPage -> _getCalls1
492 debug("[FritzCallFBF] getCalls")
493 self._callScreen = callScreen
494 self._callType = type
495 if (time.time() - self._callTimestamp) > 180:
496 debug("[FritzCallFBF] getCalls: outdated data, login and get new ones: " + time.ctime(self._callTimestamp) + " time: " + time.ctime())
497 self._callTimestamp = time.time()
498 self._login(lambda x:self._getCalls(callback,x))
499 elif not self._callList:
500 debug("[FritzCallFBF] getCalls: time is ok, but no callList")
501 self._getCalls1(callback)
503 debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
504 self._gotPageCalls(callback)
506 def _getCalls(self, callback, html):
508 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
510 self._errorCalls('Login: ' + found.group(1))
513 # we need this to fill Anrufliste.csv
514 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
516 debug("[FritzCallFBF] _getCalls")
518 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
520 text = _("FRITZ!Box - Error logging in: %s") + found.group(1)
525 self._callScreen.updateStatus(_("preparing"))
526 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de', 'var:pagename':'foncalls', 'var:menu':'fon', 'sid':self._md5Sid})
527 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
528 getPage(url).addCallback(lambda x:self._getCalls1(callback)).addErrback(self._errorCalls)
530 def _getCalls1(self, callback):
532 # finally we should have successfully lgged in and filled the csv
534 debug("[FritzCallFBF] _getCalls1")
536 self._callScreen.updateStatus(_("finishing"))
537 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv', 'sid':self._md5Sid})
538 url = "http://%s/cgi-bin/webcm?%s" % (config.plugins.FritzCall.hostname.value, parms)
539 getPage(url).addCallback(lambda x:self._gotPageCalls(callback,x)).addErrback(self._errorCalls)
541 def _gotPageCalls(self, callback, csv=""):
542 def _resolveNumber(number):
544 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0] == "0": number = number[1:]
546 if config.plugins.FritzCall.country.value == '0049':
547 if re.match('^0100\d\d', number):
549 elif re.match('^010\d\d', number):
551 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
552 number = config.plugins.FritzCall.prefix.value + number
553 name = phonebook.search(number)
555 found = re.match('(.*?)\n.*', name)
557 name = found.group(1)
560 number = _("UNKNOWN")
561 # if len(number) > 20: number = number[:20]
565 debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
567 self._callScreen.updateStatus(_("done"))
568 # check for error: wrong password or password not set... TODO
569 found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
571 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.")
572 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
576 csv = csv.decode('iso-8859-1', 'replace').encode('utf-8', 'replace')
577 lines = csv.splitlines()
578 self._callList = lines
580 debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
582 self._callScreen.updateStatus(_("done, using last list"))
583 lines = self._callList
585 debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, leaving")
590 # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
591 found = re.match("^(" + self._callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
593 direct = found.group(1)
594 date = found.group(2)
595 length = found.group(7)
596 remote = _resolveNumber(found.group(4))
597 if not remote and direct != FBF_OUT_CALLS and found.group(3):
598 remote = found.group(3)
599 found1 = re.match('Internet: (.*)', found.group(6))
601 here = _resolveNumber(found1.group(1))
603 here = _resolveNumber(found.group(6))
605 # strip CbC prefix for Germany
606 number = found.group(4)
607 if config.plugins.FritzCall.country.value == '0049':
608 if re.match('^0100\d\d', number):
610 elif re.match('^010\d\d', number):
612 if config.plugins.FritzCall.prefix.value and number and number[0] != '0': # should only happen for outgoing
613 number = config.plugins.FritzCall.prefix.value + number
614 _callList.append((number, date, here, direct, remote, length))
616 # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
619 # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
621 self._callScreen = None
623 def _errorCalls(self, error):
624 debug("[FritzCallFBF] _errorCalls: %s" % (error))
625 text = _("FRITZ!Box - Could not load calls: %s") % error
628 def dial(self, number):
629 ''' initiate a call to number '''
631 self._login(self._dial)
633 def _dial(self, html):
635 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
637 self._errorDial('Login: ' + found.group(1))
639 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
641 'getpage':'../html/de/menus/menu2.html',
642 'var:pagename':'fonbuch',
644 'telcfg:settings/UseClickToDial':'1',
645 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
646 'telcfg:command/Dial':self.number,
649 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
652 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
654 'Content-Type': "application/x-www-form-urlencoded",
655 'Content-Length': str(len(parms))},
656 postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
658 def _okDial(self, html):
659 debug("[FritzCallFBF] okDial")
661 def _errorDial(self, error):
662 debug("[FritzCallFBF] errorDial: $s" % error)
663 text = _("FRITZ!Box - Dialling failed: %s") % error
666 def changeWLAN(self, statusWLAN):
667 ''' get status info from FBF '''
668 debug("[FritzCallFBF] changeWLAN start")
669 if not statusWLAN or (statusWLAN <> '1' and statusWLAN <> '0'):
671 self.statusWLAN = statusWLAN
672 self._login(self._changeWLAN)
674 def _changeWLAN(self, html):
676 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
678 self._errorChangeWLAN('Login: ' + found.group(1))
680 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
682 'getpage':'../html/de/menus/menu2.html',
684 'var:pagename':'wlan',
686 'wlan:settings/ap_enabled':str(self.statusWLAN),
689 debug("[FritzCallFBF] changeWLAN url: '" + url + "' parms: '" + parms + "'")
692 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
694 'Content-Type': "application/x-www-form-urlencoded",
695 'Content-Length': str(len(parms))},
696 postdata=parms).addCallback(self._okChangeWLAN).addErrback(self._errorChangeWLAN)
698 def _okChangeWLAN(self, html):
699 debug("[FritzCallFBF] okDial")
701 def _errorChangeWLAN(self, error):
702 debug("[FritzCallFBF] _errorChangeWLAN: $s" % error)
703 text = _("FRITZ!Box - Failed changing WLAN: %s") % error
706 def changeMailbox(self, whichMailbox):
707 ''' switch mailbox on/off '''
708 debug("[FritzCallFBF] changeMailbox start: " + str(whichMailbox))
709 self.whichMailbox = whichMailbox
710 self._login(self._changeMailbox)
712 def _changeMailbox(self, html):
714 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
716 self._errorChangeMailbox('Login: ' + found.group(1))
718 debug("[FritzCallFBF] _changeMailbox")
719 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
720 if self.whichMailbox == -1:
722 if self.info[FBF_tamActive][i+1]:
727 'tam:settings/TAM'+str(i)+'/Active':state,
730 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
733 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
735 'Content-Type': "application/x-www-form-urlencoded",
736 'Content-Length': str(len(parms))},
737 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
738 elif self.whichMailbox > 4:
739 debug("[FritzCallFBF] changeMailbox invalid mailbox number")
741 if self.info[FBF_tamActive][self.whichMailbox+1]:
746 'tam:settings/TAM'+str(self.whichMailbox)+'/Active':state,
749 debug("[FritzCallFBF] changeMailbox url: '" + url + "' parms: '" + parms + "'")
752 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
754 'Content-Type': "application/x-www-form-urlencoded",
755 'Content-Length': str(len(parms))},
756 postdata=parms).addCallback(self._okChangeMailbox).addErrback(self._errorChangeMailbox)
758 def _okChangeMailbox(self, html):
759 debug("[FritzCallFBF] _okChangeMailbox")
761 def _errorChangeMailbox(self, error):
762 debug("[FritzCallFBF] _errorChangeMailbox: $s" % error)
763 text = _("FRITZ!Box - Failed changing Mailbox: %s") % error
766 def getInfo(self, callback):
767 ''' get status info from FBF '''
768 debug("[FritzCallFBF] getInfo")
769 self._login(lambda x:self._getInfo(callback,x))
771 def _getInfo(self, callback, html):
772 # http://192.168.178.1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:pagename=home&var:menu=home
773 debug("[FritzCallFBF] _getInfo: verify login")
775 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
777 self._errorGetInfo('Login: ' + found.group(1))
780 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
782 'getpage':'../html/de/menus/menu2.html',
784 'var:pagename':'home',
788 debug("[FritzCallFBF] _getInfo url: '" + url + "' parms: '" + parms + "'")
791 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
793 'Content-Type': "application/x-www-form-urlencoded",
794 'Content-Length': str(len(parms))},
795 postdata=parms).addCallback(lambda x:self._okGetInfo(callback,x)).addErrback(self._errorGetInfo)
797 def _okGetInfo(self, callback, html):
800 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
802 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = (None, None, None, None, None, None, None, None, None)
804 debug("[FritzCallFBF] _okGetInfo/readinfo")
805 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)
807 boxInfo = found.group(1)+ ', ' + found.group(2)
808 boxInfo = boxInfo.replace(' ',' ')
809 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + boxInfo)
811 found = re.match('.*<p class="ac">([^<]*)</p>', html, re.S)
813 # debug("[FritzCallFBF] _okGetInfo Boxinfo: " + found.group(1))
814 boxInfo = found.group(1)
816 if html.find('home_coninf.txt') != -1:
817 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
819 'getpage':'../html/de/home/home_coninf.txt',
822 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
825 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
827 'Content-Type': "application/x-www-form-urlencoded",
828 'Content-Length': str(len(parms))},
829 postdata=parms).addCallback(lambda x:self._okSetConInfo(callback,x)).addErrback(self._errorGetInfo)
831 found = re.match('.*if \(isNaN\(jetzt\)\)\s*return "";\s*var str = "([^"]*)";', html, re.S)
833 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
834 upTime = found.group(1)
836 found = re.match('.*str = g_pppSeit \+"([^<]*)<br>"\+mldIpAdr;', html, re.S)
838 # debug("[FritzCallFBF] _okGetInfo Uptime: " + found.group(1))
839 upTime = found.group(1)
841 found = re.match(".*IpAdrDisplay\('([.\d]+)'\)", html, re.S)
843 # debug("[FritzCallFBF] _okGetInfo IpAdrDisplay: " + found.group(1))
844 ipAddress = found.group(1)
846 if html.find('g_tamActive') != -1:
847 entries = re.compile('if \("(\d)" == "1"\) {\s*g_tamActive \+= 1;\s*}', re.S).finditer(html)
848 tamActive = [0, False, False, False, False, False]
850 for entry in entries:
851 state = entry.group(1)
856 # debug("[FritzCallFBF] _okGetInfo tamActive: " + str(tamActive))
858 if html.find('home_dect.txt') != -1:
859 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
861 'getpage':'../html/de/home/home_dect.txt',
864 # debug("[FritzCallFBF] get coninfo: url: '" + url + "' parms: '" + parms + "'")
867 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
869 'Content-Type': "application/x-www-form-urlencoded",
870 'Content-Length': str(len(parms))},
871 postdata=parms).addCallback(lambda x:self._okSetDect(callback,x)).addErrback(self._errorGetInfo)
873 if html.find('countDect2') != -1:
874 entries = re.compile('if \("1" == "1"\) countDect2\+\+;', re.S).findall(html)
875 dectActive = len(entries)
876 # debug("[FritzCallFBF] _okGetInfo dectActive: " + str(dectActive))
878 found = re.match('.*var g_intFaxActive = "0";\s*if \("1" != ""\) {\s*g_intFaxActive = "1";\s*}\s*', html, re.S)
881 # debug("[FritzCallFBF] _okGetInfo faxActive")
883 if html.find('cntRufumleitung') != -1:
884 entries = re.compile('mode = "1";\s*ziel = "[^"]+";\s*if \(mode == "1" \|\| ziel != ""\)\s*{\s*g_RufumleitungAktiv = true;', re.S).findall(html)
885 rufumlActive = len(entries)
886 entries = re.compile('if \("([^"]*)"=="([^"]*)"\) isAllIncoming\+\+;', re.S).finditer(html)
888 for entry in entries:
889 # debug("[FritzCallFBF] _okGetInfo rufumlActive add isAllIncoming")
890 if entry.group(1) == entry.group(2): isAllIncoming += 1
891 if isAllIncoming==2 and rufumlActive>0: rufumlActive -= 1
892 # debug("[FritzCallFBF] _okGetInfo rufumlActive: " + str(rufumlActive))
894 # /cgi-bin/webcm?getpage=../html/de/home/home_dsl.txt
895 # { "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": "" }
896 if html.find('home_dsl.txt') != -1:
897 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
899 'getpage':'../html/de/home/home_dsl.txt',
902 # debug("[FritzCallFBF] get dsl state: url: '" + url + "' parms: '" + parms + "'")
905 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
907 'Content-Type': "application/x-www-form-urlencoded",
908 'Content-Length': str(len(parms))},
909 postdata=parms).addCallback(lambda x:self._okSetDslState(callback,x)).addErrback(self._errorGetInfo)
911 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "(\d+)";', html, re.S)
913 # debug("[FritzCallFBF] _okGetInfo DslState: " + found.group(1))
914 dslState = [ found.group(1), None ] # state, speed
915 found = re.match('.*function DslStateDisplay \(state\){\s*var state = "\d+";.*?if \("3130" != "0"\) str = "([^"]*)";', html, re.S)
917 # debug("[FritzCallFBF] _okGetInfo DslSpeed: " + found.group(1).strip())
918 dslState[1] = found.group(1).strip()
920 # /cgi-bin/webcm?getpage=../html/de/home/home_wlan.txt
921 # { "ap_enabled": "1", "active_stations": "0", "encryption": "4", "wireless_stickandsurf_enabled": "0", "is_macfilter_active": "0", "wmm_enabled": "1", "wlan_state": [ "end" ] }
922 if html.find('home_wlan.txt') != -1:
923 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
925 'getpage':'../html/de/home/home_wlan.txt',
928 # debug("[FritzCallFBF] get wlan state: url: '" + url + "' parms: '" + parms + "'")
931 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
933 'Content-Type': "application/x-www-form-urlencoded",
934 'Content-Length': str(len(parms))},
935 postdata=parms).addCallback(lambda x:self._okSetWlanState(callback,x)).addErrback(self._errorGetInfo)
937 found = re.match('.*function WlanStateLed \(state\){.*?return StateLed\("(\d+)"\);\s*}', html, re.S)
939 # debug("[FritzCallFBF] _okGetInfo WlanState: " + found.group(1))
940 wlanState = [ found.group(1), 0, 0 ] # state, encryption, number of devices
941 found = re.match('.*var (?:g_)?encryption = "(\d+)";', html, re.S)
943 # debug("[FritzCallFBF] _okGetInfo WlanEncrypt: " + found.group(1))
944 wlanState[1] = found.group(1)
946 return (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
948 debug("[FritzCallFBF] _okGetInfo")
949 info = readInfo(html)
950 debug("[FritzCallFBF] _okGetInfo info: " + str(info))
955 def _okSetDect(self, callback, html):
956 # debug("[FritzCallFBF] _okSetDect: " + html)
957 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
958 if html.find('"dect_enabled": "1"') != -1:
959 # debug("[FritzCallFBF] _okSetDect: dect_enabled")
960 found = re.match('.*"dect_device_list":.*\[([^\]]*)\]', html, re.S)
962 # debug("[FritzCallFBF] _okSetDect: dect_device_list: %s" %(found.group(1)))
963 entries = re.compile('"1"', re.S).findall(found.group(1))
964 dectActive = len(entries)
965 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dummy, faxActive, rufumlActive) = self.info
966 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
967 debug("[FritzCallFBF] _okSetDect info: " + str(self.info))
971 def _okSetConInfo(self, callback, html):
972 # debug("[FritzCallFBF] _okSetConInfo: " + html)
973 # found = re.match('.*"connection_status":"(\d+)".*"connection_ip":"([.\d]+)".*"connection_detail":"([^"]+)".*"connection_uptime":"([^"]+)"', html, re.S)
974 found = re.match('.*"connection_ip": "([.\d]+)".*"connection_uptime": "([^"]+)"', html, re.S)
976 # debug("[FritzCallFBF] _okSetConInfo: ipAddress: %s upTime: %s" %( found.group(1), found.group(2)))
977 ipAddress = found.group(1)
978 upTime = found.group(2)
979 (boxInfo, dummy, dummy, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
980 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
981 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
985 def _okSetWlanState(self, callback, html):
986 # debug("[FritzCallFBF] _okSetWlanState: " + html)
987 found = re.match('.*"ap_enabled": "(\d+)"', html, re.S)
989 # debug("[FritzCallFBF] _okSetWlanState: ap_enabled: " + found.group(1))
990 wlanState = [ found.group(1), None, None ]
991 found = re.match('.*"encryption": "(\d+)"', html, re.S)
993 # debug("[FritzCallFBF] _okSetWlanState: encryption: " + found.group(1))
994 wlanState[1] = found.group(1)
995 found = re.match('.*"active_stations": "(\d+)"', html, re.S)
997 # debug("[FritzCallFBF] _okSetWlanState: active_stations: " + found.group(1))
998 wlanState[2] = found.group(1)
999 (boxInfo, upTime, ipAddress, dummy, dslState, tamActive, dectActive, faxActive, rufumlActive) = self.info
1000 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1001 debug("[FritzCallFBF] _okSetWlanState info: " + str(self.info))
1005 def _okSetDslState(self, callback, html):
1006 # debug("[FritzCallFBF] _okSetDslState: " + html)
1007 found = re.match('.*"dsl_carrier_state": "(\d+)"', html, re.S)
1009 # debug("[FritzCallFBF] _okSetDslState: dsl_carrier_state: " + found.group(1))
1010 dslState = [ found.group(1), None ]
1011 found = re.match('.*"dsl_ds_nrate": "(\d+)"', html, re.S)
1013 # debug("[FritzCallFBF] _okSetDslState: dsl_ds_nrate: " + found.group(1))
1014 dslState[1] = found.group(1)
1015 found = re.match('.*"dsl_us_nrate": "(\d+)"', html, re.S)
1017 # debug("[FritzCallFBF] _okSetDslState: dsl_us_nrate: " + found.group(1))
1018 dslState[1] = dslState[1] + '/' + found.group(1)
1019 (boxInfo, upTime, ipAddress, wlanState, dummy, tamActive, dectActive, faxActive, rufumlActive) = self.info
1020 self.info = (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive)
1021 debug("[FritzCallFBF] _okSetDslState info: " + str(self.info))
1025 def _errorGetInfo(self, error):
1026 debug("[FritzCallFBF] _errorGetInfo: %s" % (error))
1027 text = _("FRITZ!Box - Error getting status: %s") % error
1029 # linkP = open("/tmp/FritzCall_errorGetInfo.htm", "w")
1030 # linkP.write(error)
1034 self._login(self._reset)
1036 def _reset(self, html):
1037 # 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
1039 found = re.match('.*<p class="errorMessage">FEHLER: ([^<]*)</p>', html, re.S)
1041 self._errorReset('Login: ' + found.group(1))
1043 if self._callScreen:
1044 self._callScreen.close()
1045 url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1047 'getpage':'../html/reboot.html',
1049 'var:pagename':'reset',
1050 'var:menu':'system',
1051 'logic:command/reboot':'../gateway/commands/saveconfig.html',
1054 debug("[FritzCallFBF] _reset url: '" + url + "' parms: '" + parms + "'")
1057 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
1059 'Content-Type': "application/x-www-form-urlencoded",
1060 'Content-Length': str(len(parms))},
1063 def _okReset(self, html):
1064 debug("[FritzCallFBF] _okReset")
1066 def _errorReset(self, error):
1067 debug("[FritzCallFBF] _errorReset: %s" % (error))
1068 text = _("FRITZ!Box - Error resetting: %s") % error
1071 #===============================================================================
1073 # ''' hangup call on port; not used for now '''
1074 # url = "http://%s/cgi-bin/webcm" % config.plugins.FritzCall.hostname.value
1075 # parms = urlencode({
1076 # 'id':'uiPostForm',
1077 # 'name':'uiPostForm',
1078 # 'login:command/password': config.plugins.FritzCall.password.value,
1079 # 'telcfg:settings/UseClickToDial':'1',
1080 # 'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
1081 # 'telcfg:command/Hangup':'',
1082 # 'sid':self._md5Sid
1084 # debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
1088 # 'Content-Type': "application/x-www-form-urlencoded",
1089 # 'Content-Length': str(len(parms))},
1091 #===============================================================================
1093 fritzbox = FritzCallFBF()
1095 class FritzMenu(Screen,HelpableScreen):
1096 def __init__(self, session):
1097 fontSize = scaleV(24,21) # indeed this is font size +2
1098 noButtons = 2 # reset, wlan
1100 if not fritzbox or not fritzbox.info: return
1102 if fritzbox.info[FBF_tamActive]:
1103 noButtons += 1 # toggle mailboxes
1104 width = max(DESKTOP_WIDTH - scaleH(500,250), noButtons*140+(noButtons+1)*10)
1105 # boxInfo 2 lines, gap, internet 2 lines, gap, dsl/wlan each 1 line, gap, buttons
1106 height = 5 + 2*fontSize + 10 + 2*fontSize + 10 + 2*fontSize + 10 + 40 + 5
1107 if fritzbox.info[FBF_tamActive] is not None: height += fontSize
1108 if fritzbox.info[FBF_dectActive] is not None: height += fontSize
1109 if fritzbox.info[FBF_faxActive] is not None: height += fontSize
1110 if fritzbox.info[FBF_rufumlActive] is not None: height += fontSize
1111 buttonsGap = (width-noButtons*140)/(noButtons+1)
1112 buttonsVPos = height-40-5
1115 if fritzbox.info[FBF_tamActive] is not None:
1117 <widget name="FBFMailbox" position="%d,%d" size="%d,%d" font="Regular;%d" />
1118 <widget name="mailbox_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1119 <widget name="mailbox_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1120 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1121 <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" />
1123 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position mailbox
1124 width-40-20, fontSize, # size mailbox
1126 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1127 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button mailbox
1128 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1129 noButtons*buttonsGap+(noButtons-1)*140, buttonsVPos,
1135 if fritzbox.info[FBF_dectActive] is not None:
1137 <widget name="FBFDect" position="%d,%d" size="%d,%d" font="Regular;%d" />
1138 <widget name="dect_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1139 <widget name="dect_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1141 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1142 width-40-20, fontSize, # size dect
1144 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1145 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1151 if fritzbox.info[FBF_faxActive] is not None:
1153 <widget name="FBFFax" position="%d,%d" size="%d,%d" font="Regular;%d" />
1154 <widget name="fax_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1155 <widget name="fax_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1157 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1158 width-40-20, fontSize, # size dect
1160 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1161 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1167 if fritzbox.info[FBF_rufumlActive] is not None:
1169 <widget name="FBFRufuml" position="%d,%d" size="%d,%d" font="Regular;%d" />
1170 <widget name="rufuml_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1171 <widget name="rufuml_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1173 40, 5+2*fontSize+10+varLinePos*fontSize+10, # position dect
1174 width-40-20, fontSize, # size dect
1176 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1177 20, 5+2*fontSize+10+varLinePos*fontSize+10+(fontSize-16)/2, # position button dect
1184 <screen name="FritzMenu" position="%d,%d" size="%d,%d" title="%s" >
1185 <widget name="FBFInfo" position="%d,%d" size="%d,%d" font="Regular;%d" />
1186 <widget name="FBFInternet" position="%d,%d" size="%d,%d" font="Regular;%d" />
1187 <widget name="internet_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1188 <widget name="internet_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1189 <widget name="FBFDsl" position="%d,%d" size="%d,%d" font="Regular;%d" />
1190 <widget name="dsl_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1191 <widget name="dsl_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1192 <widget name="FBFWlan" position="%d,%d" size="%d,%d" font="Regular;%d" />
1193 <widget name="wlan_inactive" pixmap="skin_default/buttons/button_green_off.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1194 <widget name="wlan_active" pixmap="skin_default/buttons/button_green.png" position="%d,%d" size="15,16" transparent="1" alphatest="on"/>
1199 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1200 <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" />
1201 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1202 <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" />
1204 (DESKTOP_WIDTH - width) / 2, (DESKTOP_HEIGHT - height) / 2, # position
1205 width, height, # size
1206 _("FRITZ!Box Fon Status"),
1207 40, 5, # position info
1208 width-2*40, 2*fontSize, # size info
1210 40, 5+2*fontSize+10, # position internet
1211 width-40, 2*fontSize, # size internet
1213 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1214 20, 5+2*fontSize+10+(fontSize-16)/2, # position button internet
1215 40, 5+2*fontSize+10+2*fontSize+10, # position dsl
1216 width-40-20, fontSize, # size dsl
1218 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1219 20, 5+2*fontSize+10+2*fontSize+10+(fontSize-16)/2, # position button dsl
1220 40, 5+2*fontSize+10+3*fontSize+10, # position wlan
1221 width-40-20, fontSize, # size wlan
1223 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1224 20, 5+2*fontSize+10+3*fontSize+10+(fontSize-16)/2, # position button wlan
1229 buttonsGap, buttonsVPos, buttonsGap, buttonsVPos,
1230 buttonsGap+140+buttonsGap, buttonsVPos, buttonsGap+140+buttonsGap, buttonsVPos,
1233 Screen.__init__(self, session)
1234 HelpableScreen.__init__(self)
1235 # TRANSLATORS: keep it short, this is a button
1236 self["key_red"] = Button(_("Reset"))
1237 # TRANSLATORS: keep it short, this is a button
1238 self["key_green"] = Button(_("Toggle WLAN"))
1239 self._mailboxActive = False
1240 if fritzbox.info[FBF_tamActive] is not None:
1241 # TRANSLATORS: keep it short, this is a button
1242 self["key_yellow"] = Button(_("Toggle Mailbox"))
1243 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "EPGSelectActions"],
1245 "cancel": self._exit,
1248 "green": self._toggleWlan,
1249 "yellow": (lambda: self._toggleMailbox(-1)),
1250 "0": (lambda: self._toggleMailbox(0)),
1251 "1": (lambda: self._toggleMailbox(1)),
1252 "2": (lambda: self._toggleMailbox(2)),
1253 "3": (lambda: self._toggleMailbox(3)),
1254 "4": (lambda: self._toggleMailbox(4)),
1255 "info": self._getInfo,
1257 # TRANSLATORS: keep it short, this is a help text
1258 self.helpList.append((self["menuActions"], "ColorActions", [("yellow", _("Toggle all mailboxes"))]))
1259 # TRANSLATORS: keep it short, this is a help text
1260 self.helpList.append((self["menuActions"], "NumberActions", [("0", _("Toggle 1. mailbox"))]))
1261 # TRANSLATORS: keep it short, this is a help text
1262 self.helpList.append((self["menuActions"], "NumberActions", [("1", _("Toggle 2. mailbox"))]))
1263 # TRANSLATORS: keep it short, this is a help text
1264 self.helpList.append((self["menuActions"], "NumberActions", [("2", _("Toggle 3. mailbox"))]))
1265 # TRANSLATORS: keep it short, this is a help text
1266 self.helpList.append((self["menuActions"], "NumberActions", [("3", _("Toggle 4. mailbox"))]))
1267 # TRANSLATORS: keep it short, this is a help text
1268 self.helpList.append((self["menuActions"], "NumberActions", [("4", _("Toggle 5. mailbox"))]))
1269 self["FBFMailbox"] = Label(_('Mailbox'))
1270 self["mailbox_inactive"] = Pixmap()
1271 self["mailbox_active"] = Pixmap()
1272 self["mailbox_active"].hide()
1274 self["menuActions"] = ActionMap(["OkCancelActions", "ColorActions", "EPGSelectActions"],
1276 "cancel": self._exit,
1278 "green": self._toggleWlan,
1280 "info": self._getInfo,
1283 # TRANSLATORS: keep it short, this is a help text
1284 self.helpList.append((self["menuActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1285 # TRANSLATORS: keep it short, this is a help text
1286 self.helpList.append((self["menuActions"], "OkCancelActions", [("ok", _("Quit"))]))
1287 # TRANSLATORS: keep it short, this is a help text
1288 self.helpList.append((self["menuActions"], "ColorActions", [("green", _("Toggle WLAN"))]))
1289 # TRANSLATORS: keep it short, this is a help text
1290 self.helpList.append((self["menuActions"], "ColorActions", [("red", _("Reset"))]))
1291 # TRANSLATORS: keep it short, this is a help text
1292 self.helpList.append((self["menuActions"], "EPGSelectActions", [("info", _("Refresh status"))]))
1294 self["FBFInfo"] = Label(_('Getting status from FRITZ!Box Fon...'))
1296 self["FBFInternet"] = Label('Internet')
1297 self["internet_inactive"] = Pixmap()
1298 self["internet_active"] = Pixmap()
1299 self["internet_active"].hide()
1301 self["FBFDsl"] = Label('DSL')
1302 self["dsl_inactive"] = Pixmap()
1303 self["dsl_inactive"].hide()
1304 self["dsl_active"] = Pixmap()
1305 self["dsl_active"].hide()
1307 self["FBFWlan"] = Label('WLAN ')
1308 self["wlan_inactive"] = Pixmap()
1309 self["wlan_inactive"].hide()
1310 self["wlan_active"] = Pixmap()
1311 self["wlan_active"].hide()
1312 self._wlanActive = False
1314 if fritzbox.info[FBF_dectActive] is not None:
1315 self["FBFDect"] = Label('DECT')
1316 self["dect_inactive"] = Pixmap()
1317 self["dect_active"] = Pixmap()
1318 self["dect_active"].hide()
1320 if fritzbox.info[FBF_faxActive] is not None:
1321 self["FBFFax"] = Label('Fax')
1322 self["fax_inactive"] = Pixmap()
1323 self["fax_active"] = Pixmap()
1324 self["fax_active"].hide()
1326 if fritzbox.info[FBF_rufumlActive] is not None:
1327 self["FBFRufuml"] = Label(_('Call redirection'))
1328 self["rufuml_inactive"] = Pixmap()
1329 self["rufuml_active"] = Pixmap()
1330 self["rufuml_active"].hide()
1332 self._timer = eTimer()
1333 self._timer.callback.append(self._getInfo)
1334 self.onShown.append(lambda: self._timer.start(5000))
1335 self.onHide.append(lambda: self._timer.stop())
1339 fritzbox.getInfo(self._fillMenu)
1341 def _fillMenu(self, status):
1342 (boxInfo, upTime, ipAddress, wlanState, dslState, tamActive, dectActive, faxActive, rufumlActive) = status
1343 self._wlanActive = (wlanState[0] == '1')
1344 self._mailboxActive = False
1347 self["FBFInfo"].setText(boxInfo.replace(', ', '\n'))
1349 self["FBFInfo"].setText('BoxInfo ' + _('Status not available'))
1353 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress + '\n' + _('Connected since') + ' ' + upTime)
1355 self["FBFInternet"].setText('Internet ' + _('IP Address:') + ' ' + ipAddress)
1356 self["internet_inactive"].hide()
1357 self["internet_active"].show()
1359 self["internet_active"].hide()
1360 self["internet_inactive"].show()
1363 if dslState[0]=='5':
1364 self["dsl_inactive"].hide()
1365 self["dsl_active"].show()
1367 self["FBFDsl"].setText('DSL ' + dslState[1])
1369 self["dsl_active"].hide()
1370 self["dsl_inactive"].show()
1372 self["FBFDsl"].setText('DSL ' + _('Status not available'))
1373 self["dsl_active"].hide()
1374 self["dsl_inactive"].hide()
1377 if wlanState[0]=='1':
1378 self["wlan_inactive"].hide()
1379 self["wlan_active"].show()
1381 if wlanState[1]=='0':
1382 message += ' ' + _('not encrypted')
1384 message += ' ' + _('encrypted')
1386 if wlanState[2]=='0':
1387 message = message + ', ' + _('no device active')
1388 elif wlanState[2]=='1':
1389 message = message + ', ' + _('one device active')
1391 message = message + ', ' + wlanState[2] + ' ' + _('devices active')
1392 self["FBFWlan"].setText(message)
1394 self["wlan_active"].hide()
1395 self["wlan_inactive"].show()
1396 self["FBFWlan"].setText('WLAN')
1398 self["FBFWlan"].setText('WLAN ' + _('Status not available'))
1399 self["wlan_active"].hide()
1400 self["wlan_inactive"].hide()
1402 if fritzbox.info[FBF_tamActive]:
1403 if not tamActive or tamActive[0] == 0:
1404 self._mailboxActive = False
1405 self["mailbox_active"].hide()
1406 self["mailbox_inactive"].show()
1407 self["FBFMailbox"].setText(_('No mailbox active'))
1409 self._mailboxActive = True
1413 message = message + str(i) + ','
1414 message = message[:-1] + ')'
1415 self["mailbox_inactive"].hide()
1416 self["mailbox_active"].show()
1417 if tamActive[0] == 1:
1418 self["FBFMailbox"].setText(_('One mailbox active') + ' ' + message)
1420 self["FBFMailbox"].setText(str(tamActive[0]) + ' ' + _('mailboxes active') + ' ' + message)
1422 if fritzbox.info[FBF_dectActive] and dectActive:
1423 self["dect_inactive"].hide()
1424 self["dect_active"].show()
1426 self["FBFDect"].setText(_('No DECT phone registered'))
1429 self["FBFDect"].setText(_('One DECT phone registered'))
1431 self["FBFDect"].setText(str(dectActive) + ' ' + _('DECT phones registered'))
1433 if fritzbox.info[FBF_faxActive] and faxActive:
1434 self["fax_inactive"].hide()
1435 self["fax_active"].show()
1436 self["FBFFax"].setText(_('Software fax active'))
1438 if fritzbox.info[FBF_rufumlActive] is not None and rufumlActive is not None:
1439 if rufumlActive == 0:
1440 self["rufuml_active"].hide()
1441 self["rufuml_inactive"].show()
1442 self["FBFRufuml"].setText(_('No call redirection active'))
1444 self["rufuml_inactive"].hide()
1445 self["rufuml_active"].show()
1446 if rufumlActive == 1:
1447 self["FBFRufuml"].setText(_('One call redirection active'))
1449 self["FBFRufuml"].setText(str(rufumlActive) + ' ' + _('call redirections active'))
1452 debug("[FritzCallFBF] _fillMenu: " + traceback.format_exc())
1454 def _toggleWlan(self):
1455 if self._wlanActive:
1456 debug("[FritzMenu] toggleWlan off")
1457 fritzbox.changeWLAN('0')
1459 debug("[FritzMenu] toggleWlan off")
1460 fritzbox.changeWLAN('1')
1462 def _toggleMailbox(self, which):
1463 debug("[FritzMenu] toggleMailbox")
1464 if fritzbox.info[FBF_tamActive]:
1465 debug("[FritzMenu] toggleMailbox off")
1466 fritzbox.changeMailbox(which)
1477 class FritzDisplayCalls(Screen, HelpableScreen):
1479 def __init__(self, session, text=""):
1480 if config.plugins.FritzCall.fullscreen.value:
1481 self.width = DESKTOP_WIDTH
1482 self.height = DESKTOP_HEIGHT
1484 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
1485 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
1486 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
1487 backMainPng = "Kerni-HD1/menu/back-main.png"
1488 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
1489 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
1491 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
1494 debug("[FritzDisplayCalls] backMainLine: " + backMainLine)
1496 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1498 <screen name="FritzDisplayCalls" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
1500 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1501 <convert type="ClockToText">Default</convert>
1503 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1504 <convert type="ClockToText">Date</convert>
1506 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
1508 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#353e575e" transparent="1" />
1509 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
1511 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
1512 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
1513 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
1514 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
1515 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1516 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1517 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1518 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1519 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
1521 self.width, self.height, _("Phone calls"),
1523 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
1524 scaleH(900, XXX), scaleV(70, XXX), scaleH(310, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
1525 "FritzCall " + _("Phone calls"), scaleH(500, XXX), scaleV(63, XXX), scaleH(330, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
1526 scaleH(80, XXX), scaleV(150, XXX), scaleH(280, XXX), scaleV(200, XXX), scaleV(22, XXX), # statusbar
1527 scaleH(420, XXX), scaleV(120, XXX), scaleH(790, XXX), scaleV(438, XXX), # entries
1528 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
1529 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
1530 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
1531 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
1532 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
1533 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
1534 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
1535 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
1536 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
1539 self.width = scaleH(1100, 570)
1540 debug("[FritzDisplayCalls] width: " + str(self.width))
1541 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1543 <screen name="FritzDisplayCalls" position="%d,%d" size="%d,%d" title="%s" >
1544 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1545 <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
1546 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1547 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
1548 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1549 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1550 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1551 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1552 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1553 <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" />
1554 <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" />
1555 <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" />
1556 <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" />
1558 scaleH(90, 75), scaleV(100, 78), # position
1559 scaleH(1100, 570), scaleV(560, 430), # size
1561 scaleH(1100, 570), # eLabel width
1562 scaleH(40, 5), scaleV(10, 5), # statusbar position
1563 scaleH(1050, 560), scaleV(25, 22), # statusbar size
1564 scaleV(21, 21), # statusbar font size
1565 scaleV(40, 28), # eLabel position vertical
1566 scaleH(1100, 570), # eLabel width
1567 scaleH(40, 5), scaleV(55, 40), # entries position
1568 scaleH(1040, 560), scaleV(458, 340), # entries size
1569 scaleV(518, 390), # eLabel position vertical
1570 scaleH(1100, 570), # eLabel width
1571 scaleH(20, 5), scaleV(525, 395), # widget red
1572 scaleH(290, 145), scaleV(525, 395), # widget green
1573 scaleH(560, 285), scaleV(525, 395), # widget yellow
1574 scaleH(830, 425), scaleV(525, 395), # widget blue
1575 scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
1576 scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
1577 scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
1578 scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
1581 Screen.__init__(self, session)
1582 HelpableScreen.__init__(self)
1584 # TRANSLATORS: keep it short, this is a button
1585 self["key_yellow"] = Button(_("All"))
1586 # TRANSLATORS: keep it short, this is a button
1587 self["key_red"] = Button(_("Missed"))
1588 # TRANSLATORS: keep it short, this is a button
1589 self["key_blue"] = Button(_("Incoming"))
1590 # TRANSLATORS: keep it short, this is a button
1591 self["key_green"] = Button(_("Outgoing"))
1593 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1595 "yellow": (lambda: self.display(FBF_ALL_CALLS)),
1596 "red": (lambda: self.display(FBF_MISSED_CALLS)),
1597 "blue": (lambda: self.display(FBF_IN_CALLS)),
1598 "green": (lambda: self.display(FBF_OUT_CALLS)),
1600 "ok": self.showEntry, }, - 2)
1602 # TRANSLATORS: keep it short, this is a help text
1603 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1604 # TRANSLATORS: keep it short, this is a help text
1605 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1606 # TRANSLATORS: keep it short, this is a help text
1607 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display all calls"))]))
1608 # TRANSLATORS: keep it short, this is a help text
1609 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display missed calls"))]))
1610 # TRANSLATORS: keep it short, this is a help text
1611 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display incoming calls"))]))
1612 # TRANSLATORS: keep it short, this is a help text
1613 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display outgoing calls"))]))
1615 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
1616 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
1617 fontSize = scaleV(22, 18)
1618 fontHeight = scaleV(24, 20)
1619 self["entries"].l.setFont(0, gFont("Regular", fontSize))
1620 self["entries"].l.setItemHeight(fontHeight)
1622 debug("[FritzDisplayCalls] init: '''%s'''" % config.plugins.FritzCall.fbfCalls.value)
1628 def display(self, which=config.plugins.FritzCall.fbfCalls.value):
1629 debug("[FritzDisplayCalls] display")
1630 config.plugins.FritzCall.fbfCalls.value = which
1631 config.plugins.FritzCall.fbfCalls.save()
1632 self.header = fbfCallsChoices[which]
1633 fritzbox.getCalls(self, self.gotCalls, which)
1635 def gotCalls(self, callList):
1636 debug("[FritzDisplayCalls] gotCalls")
1637 self.updateStatus(self.header + " (" + str(len(callList)) + ")")
1638 dateFieldWidth = scaleH(140,100)
1640 lengthFieldWidth = scaleH(50,50)
1641 remoteFieldWidth = scaleH(140,100)
1642 scrollbarWidth = scaleH(35,35)
1643 if config.plugins.FritzCall.fullscreen.value:
1644 fieldWidth = 790 -dateFieldWidth -5 -dirFieldWidth -5 -lengthFieldWidth -5 -remoteFieldWidth -scrollbarWidth -5
1645 fontSize = scaleV(22,20)
1647 fieldWidth = self.width -scaleH(60, 5) -dateFieldWidth -5 -dirFieldWidth -5 -lengthFieldWidth -5 -remoteFieldWidth -scrollbarWidth -5
1648 fontSize = scaleV(24,20)
1650 for (number, date, remote, direct, here, length) in callList:
1651 found = re.match("(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
1652 if found: date = found.group(1) + found.group(2)
1653 if direct == FBF_OUT_CALLS:
1654 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callout.png"))
1655 elif direct == FBF_IN_CALLS:
1656 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callin.png"))
1658 dir = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/images/callinfailed.png"))
1659 # debug("[FritzDisplayCalls] gotCalls: d: %d; f: %d; d: %d; r: %d" %(dateFieldWidth, fieldWidth, dirFieldWidth, remoteFieldWidth))
1660 sortlist.append([number,
1661 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, dateFieldWidth, fontSize, 0, RT_HALIGN_LEFT, date),
1662 (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, dateFieldWidth+5, 0, dirFieldWidth, 16, dir),
1663 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5, 0, fieldWidth, fontSize, 0, RT_HALIGN_LEFT, here),
1664 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5+fieldWidth+5, 0, lengthFieldWidth, fontSize, 0, RT_HALIGN_LEFT, length),
1665 (eListboxPythonMultiContent.TYPE_TEXT, dateFieldWidth+5+dirFieldWidth+5+fieldWidth+5+lengthFieldWidth+5, 0, remoteFieldWidth, fontSize, 0, RT_HALIGN_RIGHT, remote)
1668 self["entries"].setList(sortlist)
1670 def updateStatus(self, text):
1671 self["statusbar"].setText(_("Getting calls from FRITZ!Box...") + ' ' + text)
1673 def showEntry(self):
1674 debug("[FritzDisplayCalls] showEntry")
1675 cur = self["entries"].getCurrent()
1678 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
1680 fullname = phonebook.search(cur[0])
1682 # we have a name for this number
1684 self.session.open(FritzOfferAction, self, number, name)
1687 self.session.open(FritzOfferAction, self, number)
1689 # we do not even have a number...
1690 self.session.open(MessageBox,
1692 type=MessageBox.TYPE_INFO)
1695 class FritzOfferAction(Screen):
1697 def __init__(self, session, parent, number, name=""):
1698 # the layout will completely be recalculated in finishLayout
1699 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1701 <screen name="FritzOfferAction" title="%s" >
1702 <widget name="text" size="%d,%d" font="Regular;%d" />
1703 <widget name="FacePixmap" size="%d,%d" alphatest="on" />
1704 <widget name="key_red_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1705 <widget name="key_green_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1706 <widget name="key_yellow_p" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1707 <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" />
1708 <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" />
1709 <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" />
1712 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1713 scaleH(22,21), # text
1714 DESKTOP_WIDTH, DESKTOP_HEIGHT, # set maximum size
1716 debug("[FritzOfferAction] init: %s, %s" %(number, name))
1717 Screen.__init__(self, session)
1719 # TRANSLATORS: keep it short, this is a button
1720 self["key_red"] = Button(_("Lookup"))
1721 # TRANSLATORS: keep it short, this is a button
1722 self["key_green"] = Button(_("Call"))
1723 # TRANSLATORS: keep it short, this is a button
1724 self["key_yellow"] = Button(_("Save"))
1725 # TRANSLATORS: keep it short, this is a button
1726 # self["key_blue"] = Button(_("Search"))
1728 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1733 "cancel": self.exit,
1734 "ok": self.exit, }, - 2)
1736 self.number = number
1737 self.name = name.replace("\n", ", ")
1738 self["text"] = Label(number + "\n\n" + name.replace(", ", "\n"))
1739 self.parent = parent
1740 self.lookupState = 0
1741 self["key_red_p"] = Pixmap()
1742 self["key_green_p"] = Pixmap()
1743 self["key_yellow_p"] = Pixmap()
1744 self["FacePixmap"] = Pixmap()
1745 self.onLayoutFinish.append(self.finishLayout)
1747 def finishLayout(self):
1748 debug("[FritzCall] FritzOfferAction/finishLayout number: %s/%s" % (self.number, self.name))
1750 picPixmap = LoadPixmap(findFace(self.number, self.name))
1751 picSize = picPixmap.size()
1752 self["FacePixmap"].instance.setPixmap(picPixmap)
1755 # recalculate window size
1756 textSize = self["text"].getSize()
1757 textSize = (textSize[0]+20, textSize[1]+20) # don't know, why, but size is too small
1758 debug("[FritzCall] FritzOfferAction/finishLayout textsize: %s/%s" % textSize)
1759 textSize = eSize(*textSize)
1760 width = max(scaleH(620,545), noButtons*145, picSize.width() + textSize.width() + 30)
1761 height = max(picSize.height()+5, textSize.height()+5, scaleV(-1,136)) + 5 + 40 + 5
1762 buttonsGap = (width-noButtons*140)/(noButtons+1)
1763 buttonsVPos = height-40-5
1764 wSize = (width, height)
1765 wSize = eSize(*wSize)
1767 # center the smaller vertically
1768 hGap = (width-picSize.width()-textSize.width())/3
1769 picPos = (hGap,(height-50-picSize.height())/2+5)
1770 textPos = (hGap+picSize.width()+hGap, (height-50-textSize.height())/2+5)
1773 self.instance.resize(wSize)
1775 self["text"].instance.resize(textSize)
1777 self["FacePixmap"].instance.resize(picSize)
1779 buttonPos = (buttonsGap, buttonsVPos)
1780 self["key_red_p"].instance.move(ePoint(*buttonPos))
1781 self["key_red"].instance.move(ePoint(*buttonPos))
1782 buttonPos = (buttonsGap+140+buttonsGap, buttonsVPos)
1783 self["key_green_p"].instance.move(ePoint(*buttonPos))
1784 self["key_green"].instance.move(ePoint(*buttonPos))
1785 buttonPos = (buttonsGap+140+buttonsGap+140+buttonsGap, buttonsVPos)
1786 self["key_yellow_p"].instance.move(ePoint(*buttonPos))
1787 self["key_yellow"].instance.move(ePoint(*buttonPos))
1789 self["text"].instance.move(ePoint(*textPos))
1791 self["FacePixmap"].instance.move(ePoint(*picPos))
1793 self.instance.move(ePoint((DESKTOP_WIDTH-wSize.width())/2, (DESKTOP_HEIGHT-wSize.height())/2))
1795 def setTextAndResize(self, message):
1796 self["text"].instance.resize(eSize(*(DESKTOP_WIDTH,DESKTOP_HEIGHT)))
1797 self["text"].setText(self.number + "\n\n" + message)
1801 phonebookLocation = config.plugins.FritzCall.phonebookLocation.value
1802 if self.lookupState == 0:
1803 self.lookupState = 1
1804 self.setTextAndResize(_("Reverse searching..."))
1805 ReverseLookupAndNotifier(self.number, self.lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
1807 if self.lookupState == 1 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.csv")):
1808 self.setTextAndResize(_("Searching in Outlook export..."))
1809 self.lookupState = 2
1810 self.lookedUp(self.number, FritzOutlookCSV.findNumber(self.number, os.path.join(phonebookLocation, "PhoneBook.csv"))) #@UndefinedVariable
1813 self.lookupState = 2
1814 if self.lookupState == 2 and os.path.exists(os.path.join(phonebookLocation, "PhoneBook.ldif")):
1815 self.setTextAndResize(_("Searching in LDIF..."))
1816 self.lookupState = 0
1817 FritzLDIF.findNumber(self.number, open(os.path.join(phonebookLocation, "PhoneBook.ldif")), self.lookedUp)
1820 self.lookupState = 0
1823 def lookedUp(self, number, name):
1825 if self.lookupState == 1:
1826 name = _("No result from reverse lookup")
1827 elif self.lookupState == 2:
1828 name = _("No result from Outlook export")
1830 name = _("No result from LDIF")
1831 self.number = number
1833 debug("[FritzOfferAction] lookedUp: " + str(name.replace(", ", "\n")))
1834 self.setTextAndResize(str(name.replace(", ", "\n")))
1837 debug("[FritzOfferAction] add: %s" %self.number)
1838 fritzbox.dial(self.number)
1842 debug("[FritzOfferAction] add: %s, %s" %(self.number, self.name))
1843 phonebook.FritzDisplayPhonebook(self.session).add(self.parent, self.number, self.name)
1850 class FritzCallPhonebook:
1852 debug("[FritzCallPhonebook] init")
1853 # Beware: strings in phonebook.phonebook have to be in utf-8!
1858 debug("[FritzCallPhonebook] reload")
1859 # Beware: strings in phonebook.phonebook have to be in utf-8!
1862 if not config.plugins.FritzCall.enable.value:
1865 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1866 if config.plugins.FritzCall.phonebook.value and os.path.exists(phonebookFilename):
1867 debug("[FritzCallPhonebook] reload: read " + phonebookFilename)
1868 phonebookTxtCorrupt = False
1869 for line in open(phonebookFilename):
1871 # Beware: strings in phonebook.phonebook have to be in utf-8!
1872 line = line.decode("utf-8")
1873 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
1875 line = line.decode("iso-8859-1")
1876 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" % line)
1877 phonebookTxtCorrupt = True
1879 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1880 phonebookTxtCorrupt = True
1881 line = line.encode("utf-8")
1882 if re.match("^\d+#.*$", line):
1884 number, name = line.split("#")
1885 if not self.phonebook.has_key(number):
1886 # Beware: strings in phonebook.phonebook have to be in utf-8!
1887 self.phonebook[number] = name
1888 except ValueError: # how could this possibly happen?!?!
1889 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1890 phonebookTxtCorrupt = True
1892 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" % line)
1893 phonebookTxtCorrupt = True
1895 if phonebookTxtCorrupt:
1896 # dump phonebook to PhoneBook.txt
1897 debug("[FritzCallPhonebook] dump Phonebook.txt")
1898 os.rename(phonebookFilename, phonebookFilename + ".bck")
1899 fNew = open(phonebookFilename, 'w')
1900 # Beware: strings in phonebook.phonebook are utf-8!
1901 for (number, name) in self.phonebook.iteritems():
1902 # Beware: strings in PhoneBook.txt have to be in utf-8!
1903 fNew.write(number + "#" + name.encode("utf-8"))
1906 #===============================================================================
1908 # # read entries from Outlook export
1910 # # not reliable with coding yet
1912 # # import csv exported from Outlook 2007 with csv(Windows)
1913 # csvFilename = "/tmp/PhoneBook.csv"
1914 # if config.plugins.FritzCall.phonebook.value and os.path.exists(csvFilename):
1916 # readOutlookCSV(csvFilename, self.add)
1917 # os.rename(csvFilename, csvFilename + ".done")
1918 # except ImportError:
1919 # debug("[FritzCallPhonebook] CSV import failed" %line)
1920 #===============================================================================
1923 #===============================================================================
1925 # # read entries from LDIF
1927 # # import ldif exported from Thunderbird 2.0.0.19
1928 # ldifFilename = "/tmp/PhoneBook.ldif"
1929 # if config.plugins.FritzCall.phonebook.value and os.path.exists(ldifFilename):
1931 # parser = MyLDIF(open(ldifFilename), self.add)
1933 # os.rename(ldifFilename, ldifFilename + ".done")
1934 # except ImportError:
1935 # debug("[FritzCallPhonebook] LDIF import failed" %line)
1936 #===============================================================================
1938 if config.plugins.FritzCall.fritzphonebook.value:
1939 fritzbox.loadFritzBoxPhonebook()
1941 if DESKTOP_WIDTH <> 1280 or DESKTOP_HEIGHT <> 720:
1942 config.plugins.FritzCall.fullscreen.value = False
1944 def search(self, number):
1945 # debug("[FritzCallPhonebook] Searching for %s" %number
1947 if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
1948 if self.phonebook.has_key(number):
1949 name = self.phonebook[number].replace(", ", "\n").strip()
1952 def add(self, number, name):
1955 @param number: number of entry
1956 @param name: name of entry, has to be in utf-8
1958 debug("[FritzCallPhonebook] add")
1959 name = name.replace("\n", ", ").replace('#','') # this is just for safety reasons. add should only be called with newlines converted into commas
1961 self.phonebook[number] = name;
1962 if number and number <> 0:
1963 if config.plugins.FritzCall.phonebook.value:
1965 name = name.strip() + "\n"
1966 string = "%s#%s" % (number, name)
1967 # Beware: strings in PhoneBook.txt have to be in utf-8!
1968 f = open(os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt"), 'a')
1971 debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
1977 def remove(self, number):
1978 if number in self.phonebook:
1979 debug("[FritzCallPhonebook] remove entry in phonebook")
1980 del self.phonebook[number]
1981 if config.plugins.FritzCall.phonebook.value:
1983 phonebookFilename = os.path.join(config.plugins.FritzCall.phonebookLocation.value, "PhoneBook.txt")
1984 debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
1985 fOld = open(phonebookFilename, 'r')
1986 fNew = open(phonebookFilename + str(os.getpid()), 'w')
1987 line = fOld.readline()
1989 if not re.match("^" + number + "#.*$", line):
1991 line = fOld.readline()
1994 os.remove(phonebookFilename)
1995 os.rename(phonebookFilename + str(os.getpid()), phonebookFilename)
1996 debug("[FritzCallPhonebook] removed %s from Phonebook.txt" % number)
2003 class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
2005 def __init__(self, session):
2006 if config.plugins.FritzCall.fullscreen.value:
2007 self.width = DESKTOP_WIDTH
2008 self.height = DESKTOP_HEIGHT
2009 self.entriesWidth = 790
2011 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
2012 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
2013 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1/menu/back-main.png")):
2014 backMainPng = "Kerni-HD1/menu/back-main.png"
2015 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
2016 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
2018 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" % (self.width, self.height, backMainPng)
2021 debug("[FritzDisplayPhonebook] backMainLine: " + backMainLine)
2023 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2025 <screen name="FritzdisplayPhonebook" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
2027 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2028 <convert type="ClockToText">Default</convert>
2030 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
2031 <convert type="ClockToText">Date</convert>
2033 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
2035 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
2037 <ePixmap pixmap="skin_default/buttons/red.png" position="%d,%d" size="%d,%d" alphatest="on" />
2038 <ePixmap pixmap="skin_default/buttons/green.png" position="%d,%d" size="%d,%d" alphatest="on" />
2039 <ePixmap pixmap="skin_default/buttons/yellow.png" position="%d,%d" size="%d,%d" alphatest="on" />
2040 <ePixmap pixmap="skin_default/buttons/blue.png" position="%d,%d" size="%d,%d" alphatest="on" />
2041 <widget name="key_red" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2042 <widget name="key_green" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2043 <widget name="key_yellow" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2044 <widget name="key_blue" position="%d,%d" size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
2045 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />
2047 self.width, self.height, _("Phonebook"),
2049 scaleH(1130, XXX), scaleV(40, XXX), scaleH(80, XXX), scaleV(26, XXX), scaleV(26, XXX), # time
2050 scaleH(900, XXX), scaleV(70, XXX), scaleH(310, XXX), scaleV(22, XXX), scaleV(20, XXX), # date
2051 "FritzCall " + _("Phonebook"), scaleH(80, XXX), scaleV(63, XXX), scaleH(300, XXX), scaleV(30, XXX), scaleV(27, XXX), # eLabel
2052 scaleH(420, XXX), scaleV(120, XXX), scaleH(self.entriesWidth, XXX), scaleV(438, XXX), # entries
2053 scaleH(450, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # red
2054 scaleH(640, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # green
2055 scaleH(830, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # yellow
2056 scaleH(1020, XXX), scaleV(588, XXX), scaleH(21, XXX), scaleV(21, XXX), # blue
2057 scaleH(480, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # red
2058 scaleH(670, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # green
2059 scaleH(860, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # yellow
2060 scaleH(1050, XXX), scaleV(587, XXX), scaleH(160, XXX), scaleV(22, XXX), scaleV(20, XXX), # blue
2061 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
2064 self.width = scaleH(1100, 570)
2065 self.entriesWidth = scaleH(1040, 560)
2066 debug("[FritzDisplayPhonebook] width: " + str(self.width))
2067 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2069 <screen name="FritzDisplayPhonebook" position="%d,%d" size="%d,%d" title="%s" >
2070 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
2071 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
2072 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
2073 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2074 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2075 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
2076 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
2077 <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" />
2078 <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" />
2079 <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" />
2080 <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" />
2082 scaleH(90, 75), scaleV(100, 73), # position
2083 scaleH(1100, 570), scaleV(560, 430), # size
2085 scaleH(1100, 570), # eLabel width
2086 scaleH(40, 5), scaleV(20, 5), # entries position
2087 self.entriesWidth, scaleV(488, 380), # entries size
2088 scaleV(518, 390), # eLabel position vertical
2089 scaleH(1100, 570), # eLabel width
2090 scaleH(20, 5), scaleV(525, 395), # ePixmap red
2091 scaleH(290, 145), scaleV(525, 395), # ePixmap green
2092 scaleH(560, 285), scaleV(525, 395), # ePixmap yellow
2093 scaleH(830, 425), scaleV(525, 395), # ePixmap blue
2094 scaleH(20, 5), scaleV(525, 395), scaleV(22, 21), # widget red
2095 scaleH(290, 145), scaleV(525, 395), scaleV(22, 21), # widget green
2096 scaleH(560, 285), scaleV(525, 395), scaleV(22, 21), # widget yellow
2097 scaleH(830, 425), scaleV(525, 395), scaleV(22, 21), # widget blue
2100 Screen.__init__(self, session)
2101 NumericalTextInput.__init__(self)
2102 HelpableScreen.__init__(self)
2104 # TRANSLATORS: keep it short, this is a button
2105 self["key_red"] = Button(_("Delete"))
2106 # TRANSLATORS: keep it short, this is a button
2107 self["key_green"] = Button(_("New"))
2108 # TRANSLATORS: keep it short, this is a button
2109 self["key_yellow"] = Button(_("Edit"))
2110 # TRANSLATORS: keep it short, this is a button
2111 self["key_blue"] = Button(_("Search"))
2113 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
2117 "yellow": self.edit,
2118 "blue": self.search,
2119 "cancel": self.exit,
2120 "ok": self.showEntry, }, - 2)
2122 # TRANSLATORS: keep it short, this is a help text
2123 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
2124 # TRANSLATORS: keep it short, this is a help text
2125 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
2126 # TRANSLATORS: keep it short, this is a help text
2127 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
2128 # TRANSLATORS: keep it short, this is a help text
2129 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
2130 # TRANSLATORS: keep it short, this is a help text
2131 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
2132 # TRANSLATORS: keep it short, this is a help text
2133 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
2135 self["entries"] = MenuList([], True, content=eListboxPythonMultiContent)
2136 fontSize = scaleV(22, 18)
2137 fontHeight = scaleV(24, 20)
2138 self["entries"].l.setFont(0, gFont("Regular", fontSize))
2139 self["entries"].l.setItemHeight(fontHeight)
2140 debug("[FritzCallPhonebook] displayPhonebook init")
2143 def display(self, filter=""):
2144 debug("[FritzCallPhonebook] displayPhonebook/display")
2146 # Beware: strings in phonebook.phonebook are utf-8!
2147 sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
2148 for (low, name, number) in sortlistHelp:
2149 if number == "01234567890":
2152 low = low.decode("utf-8")
2153 except (UnicodeDecodeError, UnicodeEncodeError): # this should definitely not happen
2155 low = low.decode("iso-8859-1")
2157 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
2158 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
2159 phonebook.remove(number)
2163 filter = filter.lower()
2164 if low.find(filter) == - 1:
2166 name = name.strip().decode("utf-8")
2167 number = number.strip().decode("utf-8")
2168 found = re.match("([^,]*),.*", name) # strip address information from the name part
2170 shortname = found.group(1)
2173 numberFieldWidth = scaleV(200,150)
2174 fieldWidth = self.entriesWidth -5 -numberFieldWidth -10 -scaleH(90,45)
2175 number = number.encode("utf-8", "replace")
2176 name = name.encode("utf-8", "replace")
2177 shortname = shortname.encode('utf-8', 'replace')
2178 self.sortlist.append([(number, name),
2179 (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, fieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, shortname),
2180 (eListboxPythonMultiContent.TYPE_TEXT, fieldWidth +5, 0, numberFieldWidth, scaleH(24,20), 0, RT_HALIGN_LEFT, number)
2183 self["entries"].setList(self.sortlist)
2185 def showEntry(self):
2186 cur = self["entries"].getCurrent()
2188 debug("[FritzCallPhonebook] displayPhonebook/showEntry (%s,%s)" % (cur[0][0], cur[0][1]))
2191 self.session.open(FritzOfferAction, self, number, name)
2194 cur = self["entries"].getCurrent()
2196 debug("[FritzCallPhonebook] displayPhonebook/delete " + cur[0][0])
2197 self.session.openWithCallback(
2198 self.deleteConfirmed,
2200 _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
2201 % { 'number':str(cur[0][0]), 'name':str(cur[0][1]).replace(", ", "\n") }
2204 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2206 def deleteConfirmed(self, ret):
2207 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
2209 # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2211 cur = self["entries"].getCurrent()
2214 # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
2215 debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed: remove " + cur[0][0])
2216 phonebook.remove(cur[0][0])
2219 # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
2221 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2223 def add(self, parent=None, number="", name=""):
2224 class addScreen(Screen, ConfigListScreen):
2225 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
2227 def __init__(self, session, parent, number="", name=""):
2229 # setup screen with two ConfigText and OK and ABORT button
2232 width = max(scaleH(-1,570), noButtons*140)
2233 height = scaleV(-1,100) # = 5 + 126 + 40 + 5; 6 lines of text possible
2234 buttonsGap = (width-noButtons*140)/(noButtons+1)
2235 buttonsVPos = height-40-5
2236 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
2238 <screen position="%d,%d" size="%d,%d" title="%s" >
2239 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
2240 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2241 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2242 <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" />
2243 <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" />
2245 (DESKTOP_WIDTH - width) / 2,
2246 (DESKTOP_HEIGHT - height) / 2,
2249 _("Add entry to phonebook"),
2251 height - 5 - 40 - 5,
2252 buttonsGap, buttonsVPos,
2253 buttonsGap+140+buttonsGap, buttonsVPos,
2254 buttonsGap, buttonsVPos,
2255 buttonsGap+140+buttonsGap, buttonsVPos,
2257 Screen.__init__(self, session)
2258 self.session = session
2259 self.parent = parent
2260 # TRANSLATORS: keep it short, this is a button
2261 self["key_red"] = Button(_("Cancel"))
2262 # TRANSLATORS: keep it short, this is a button
2263 self["key_green"] = Button(_("OK"))
2264 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2266 "cancel": self.cancel,
2273 ConfigListScreen.__init__(self, self.list, session=session)
2274 config.plugins.FritzCall.name.value = name
2275 config.plugins.FritzCall.number.value = number
2276 self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
2277 self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
2278 self["config"].list = self.list
2279 self["config"].l.setList(self.list)
2282 # get texts from Screen
2283 # add (number,name) to sortlist and phonebook.phonebook and disk
2284 self.number = config.plugins.FritzCall.number.value
2285 self.name = config.plugins.FritzCall.name.value
2286 if not self.number or not self.name:
2287 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
2289 # add (number,name) to sortlist and phonebook.phonebook and disk
2290 # oldname = phonebook.search(self.number)
2292 # self.session.openWithCallback(
2293 # self.overwriteConfirmed,
2295 # _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
2297 # 'number':self.number,
2299 # 'newname':self.name.replace(", ","\n")
2304 phonebook.add(self.number, self.name)
2306 self.parent.display()
2308 def overwriteConfirmed(self, ret):
2310 phonebook.remove(self.number)
2311 phonebook.add(self.number, self.name)
2312 self.parent.display()
2317 debug("[FritzCallPhonebook] displayPhonebook/add")
2320 self.session.open(addScreen, parent, number, name)
2323 debug("[FritzCallPhonebook] displayPhonebook/edit")
2324 cur = self["entries"].getCurrent()
2326 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
2328 (number, name) = cur[0]
2329 self.add(self, number, name)
2332 debug("[FritzCallPhonebook] displayPhonebook/search")
2333 self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
2334 self.help_window.show()
2335 self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
2337 def doSearch(self, searchTerms):
2338 if not searchTerms: searchTerms = ""
2339 debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
2340 if self.help_window:
2341 self.session.deleteDialog(self.help_window)
2342 self.help_window = None
2343 self.display(searchTerms)
2348 phonebook = FritzCallPhonebook()
2350 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
2352 def __init__(self, session, args=None):
2353 if config.plugins.FritzCall.fullscreen.value:
2354 self.width = DESKTOP_WIDTH
2355 self.height = DESKTOP_HEIGHT