back to older revision. This was buggy with FBF fonbuch
[enigma2-plugins.git] / fritzcall / src / plugin.py
1 # -*- coding: utf-8 -*-
2 #===============================================================================
3 # $Author$
4 # $Revision$
5 # $Date$
6 #==============================
7 from Screens.Screen import Screen #@UnresolvedImport
8 from Screens.MessageBox import MessageBox #@UnresolvedImport
9 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog #@UnresolvedImport
10 from Screens.InputBox import InputBox #@UnresolvedImport
11 from Screens import Standby #@UnresolvedImport
12 from Screens.HelpMenu import HelpableScreen #@UnresolvedImport
13
14 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT #@UnresolvedImport
15
16 from Components.MenuList import MenuList #@UnresolvedImport
17 from Components.ActionMap import ActionMap #@UnresolvedImport
18 from Components.Label import Label #@UnresolvedImport
19 from Components.Button import Button #@UnresolvedImport
20 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigEnableDisable, getConfigListEntry, ConfigText, ConfigInteger #@UnresolvedImport
21 try:
22         from Components.config import ConfigPassword
23 except ImportError:
24         ConfigPassword = ConfigText
25 from Components.ConfigList import ConfigListScreen #@UnresolvedImport
26
27 from Plugins.Plugin import PluginDescriptor #@UnresolvedImport
28 from Tools import Notifications #@UnresolvedImport
29 from Tools.NumericalTextInput import NumericalTextInput #@UnresolvedImport
30
31 from twisted.internet import reactor #@UnresolvedImport
32 from twisted.internet.protocol import ReconnectingClientFactory #@UnresolvedImport
33 from twisted.protocols.basic import LineReceiver #@UnresolvedImport
34 from twisted.web.client import getPage #@UnresolvedImport
35
36 from urllib import urlencode 
37 import re, time, os
38
39 from nrzuname import ReverseLookupAndNotifier
40
41 import gettext
42 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE #@UnresolvedImport
43 try:
44         _ = gettext.translation('FritzCall', resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/locale"), [config.osd.language.getText()]).gettext
45 except IOError:
46         pass
47
48 from enigma import getDesktop #@UnresolvedImport
49 DESKTOP_WIDTH = getDesktop(0).size().width()
50 DESKTOP_HEIGHT = getDesktop(0).size().height()
51 DESKTOP_SKIN = config.skin.primary_skin.value.replace("/skin.xml","")
52 XXX = 0 # TODO: Platzhalter fr fullscreen SD skin
53 #
54 # this is pure magic.
55 # It returns the first value, if HD (1280x720),
56 # the second if SD (720x576),
57 # else something scaled accordingly
58 #
59 def scaleH(y2,y1):
60         return scale(y2,y1,1280,720,DESKTOP_WIDTH)
61 def scaleV(y2,y1):
62         return scale(y2,y1,720,576,DESKTOP_HEIGHT)
63 def scale(y2,y1,x2,x1,x):
64         return (y2-y1)*(x-x1)/(x2-x1)+y1
65
66 my_global_session = None
67
68 config.plugins.FritzCall = ConfigSubsection()
69 config.plugins.FritzCall.enable = ConfigEnableDisable(default = False)
70 config.plugins.FritzCall.muteOnCall = ConfigEnableDisable(default = False)
71 config.plugins.FritzCall.hostname = ConfigText(default = "fritz.box", fixed_size = False)
72 config.plugins.FritzCall.afterStandby = ConfigSelection(choices = [("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
73 config.plugins.FritzCall.filter = ConfigEnableDisable(default = False)
74 config.plugins.FritzCall.filtermsn = ConfigText(default = "", fixed_size = False)
75 config.plugins.FritzCall.filtermsn.setUseableChars('0123456789,')
76 config.plugins.FritzCall.showOutgoing = ConfigEnableDisable(default = False)
77 config.plugins.FritzCall.timeout = ConfigInteger(default = 15, limits = (0,60))
78 config.plugins.FritzCall.lookup = ConfigEnableDisable(default = False)
79 config.plugins.FritzCall.internal = ConfigEnableDisable(default = False)
80 config.plugins.FritzCall.fritzphonebook = ConfigEnableDisable(default = False)
81 config.plugins.FritzCall.phonebook = ConfigEnableDisable(default = False)
82 config.plugins.FritzCall.addcallers = ConfigEnableDisable(default = False)
83 config.plugins.FritzCall.phonebookLocation = ConfigSelection(choices = [("/etc/enigma2/PhoneBook.txt", _("Flash")), ("/media/usb/PhoneBook.txt", _("USB Stick")), ("/media/cf/PhoneBook.txt", _("CF Drive")), ("/media/hdd/PhoneBook.txt", _("Harddisk"))])
84 config.plugins.FritzCall.password = ConfigPassword(default = "", fixed_size = False)
85 config.plugins.FritzCall.extension = ConfigText(default = '1', fixed_size = False)
86 config.plugins.FritzCall.extension.setUseableChars('0123456789')
87 config.plugins.FritzCall.showType = ConfigEnableDisable(default = True)
88 config.plugins.FritzCall.showShortcut = ConfigEnableDisable(default = False)
89 config.plugins.FritzCall.showVanity = ConfigEnableDisable(default = False)
90 config.plugins.FritzCall.prefix = ConfigText(default = "", fixed_size = False)
91 config.plugins.FritzCall.prefix.setUseableChars('0123456789')
92 config.plugins.FritzCall.fullscreen = ConfigEnableDisable(default = False)
93 config.plugins.FritzCall.debug = ConfigEnableDisable(default = False)
94
95 countryCodes = [
96         ("0049", _("Germany")),
97         ("0031", _("The Netherlands")),
98         ("0033", _("France")),
99         ("0039", _("Italy")),
100         ("0041", _("Switzerland")),
101         ("0043", _("Austria"))
102         ]
103 config.plugins.FritzCall.country = ConfigSelection(choices = countryCodes)
104
105 FBF_ALL_CALLS = "."
106 FBF_IN_CALLS = "1"
107 FBF_MISSED_CALLS = "2"
108 FBF_OUT_CALLS = "3"
109 fbfCallsChoices = {FBF_ALL_CALLS: _("All calls"),
110                                    FBF_IN_CALLS: _("Incoming calls"),
111                                    FBF_MISSED_CALLS: _("Missed calls"),
112                                    FBF_OUT_CALLS: _("Outgoing calls")
113                                    }
114 config.plugins.FritzCall.fbfCalls = ConfigSelection(choices = fbfCallsChoices)
115
116 config.plugins.FritzCall.name = ConfigText(default = "", fixed_size = False)
117 config.plugins.FritzCall.number= ConfigText(default = "", fixed_size = False)
118 config.plugins.FritzCall.number.setUseableChars('0123456789')
119
120 def initDebug():
121         try:
122                 os.remove("/tmp/FritzDebug.log")
123         except:
124                 pass
125
126 # from time import localtime()
127 def debug(message):
128         # ltim = localtime()
129         # headerstr = "%04d%02d%02d %02d:%02d " %(ltim[0],ltim[1],ltim[2],ltim[3],ltim[4])
130         # message = headerstr + message
131         if config.plugins.FritzCall.debug.value:
132                 deb = open("/tmp/FritzDebug.log", "aw")
133                 deb.write(message + "\n")
134                 deb.close()
135
136 def html2utf8(in_html):
137         try:
138                 import htmlentitydefs
139
140                 # TODO: first convert some WML codes; does not work?!?!
141                 # in_html = in_html.replace("ß;", "").replace("ä", "").replace("ö", "").replace("ü", "").replace("Ä", "").replace("Ö", "").replace("Ü", "")
142
143                 htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
144                 entitydict = {}
145                 entities = htmlentitynamemask.finditer(in_html)
146                 for x in entities:
147                         entitydict[x.group(1)] = x.group(2)
148                 for key, name in entitydict.items():
149                         try:
150                                 entitydict[key] = htmlentitydefs.name2codepoint[name]
151                         except KeyError:
152                                 debug("[FritzCallhtml2utf8] KeyError " + key + "/" + name)
153                                 pass
154
155                 htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
156                 entities = htmlentitynumbermask.finditer(in_html)
157                 for x in entities:
158                         entitydict[x.group(1)] = x.group(2)
159                 for key, codepoint in entitydict.items():
160                         try:
161                                 in_html = in_html.replace(key, (unichr(int(codepoint)).encode('utf8', "replace")))
162                         except ValueError:
163                                 debug( "[FritzCallhtml2utf8] ValueError " + key + "/" + str(codepoint))
164                                 pass
165         except ImportError:
166                 try:
167                         return in_html.replace("&", "&").replace("ß", "").replace("ä", "").replace("ö", "").replace("ü", "").replace("Ä", "").replace("Ö", "").replace("Ü", "")
168                 except UnicodeDecodeError:
169                         pass
170         return in_html
171
172 class FritzCallFBF:
173         def __init__(self):
174                 debug("[FritzCallFBF] __init__")
175                 self.callScreen= None
176                 self.loggedIn = False
177                 self.Callback = None
178                 self.timestamp = 0
179                 self.callList = []
180                 self.callType = config.plugins.FritzCall.fbfCalls.value
181
182         def notify(self, text):
183                 debug("[FritzCallFBF] notify")
184                 if self.callScreen:
185                         debug("[FritzCallFBF] notify: try to close callScreen")
186                         self.callScreen.close()
187                         self.callScreen = None
188                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
189
190         def errorLogin(self, error):
191                 text = _("FRITZ!Box Login failed! - Error: %s") %error
192                 self.notify(text)
193
194         def _gotPageLogin(self, html):
195 #               debug("[FritzCallPhonebook] _gotPageLogin"
196                 # workaround: exceptions in gotPage-callback were ignored
197                 if self.callScreen:
198                         self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login verification"))
199                 try:
200                         debug("[FritzCallFBF] _gotPageLogin: verify login")
201                         found = re.match('.*<p class="errorMessage">FEHLER:&nbsp;Das angegebene Kennwort', html, re.S)
202                         if found:
203                                 text = _("FRITZ!Box Login failed! - Wrong Password!")
204                                 self.notify(text)
205                         else:
206                                 if self.callScreen:
207                                         self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login ok"))
208                                 self.loggedIn = True
209                 except:
210                         import traceback, sys
211                         traceback.print_exc(file=sys.stdout)
212                         #raise e
213
214         def login(self, callback = None):
215                 debug("[FritzCallFBF] Login")
216                 if config.plugins.FritzCall.password.value != "":
217                         if self.callScreen:
218                                 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("login"))
219                         parms = "login:command/password=%s" %(config.plugins.FritzCall.password.value)
220                         url = "http://%s/cgi-bin/webcm" %(config.plugins.FritzCall.hostname.value)
221                         getPage(url,
222                                 method="POST",
223                                 headers = {'Content-Type': "application/x-www-form-urlencoded",'Content-Length': str(len(parms))
224                                                 }, postdata=parms).addCallback(self._gotPageLogin).addCallback(callback).addErrback(self.errorLogin)
225                 elif callback:
226                         callback()
227
228         def errorLoad(self, error):
229                 text = _("Could not load phonebook from FRITZ!Box - Error: %s") %error
230                 self.notify(text)
231
232         def _gotPageLoad(self, html):
233                 debug("[FritzCallFBF] _gotPageLoad")
234                 # workaround: exceptions in gotPage-callback were ignored
235                 try:
236                         self.parseFritzBoxPhonebook(html)
237                 except:
238                         import traceback, sys
239                         traceback.print_exc(file=sys.stdout)
240                         #raise e
241
242         def loadFritzBoxPhonebook(self):
243                 debug("[FritzCallFBF] loadFritzBoxPhonebook")
244                 if config.plugins.FritzCall.fritzphonebook.value:
245                         debug("[FritzCallFBF] loadFritzBoxPhonebook: logging in")
246                         self.login(self._loadFritzBoxPhonebook)
247
248         def _loadFritzBoxPhonebook(self, html=None):
249                         parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de','var:pagename':'fonbuch','var:menu':'fon'})
250                         url = "http://%s/cgi-bin/webcm?%s" %(config.plugins.FritzCall.hostname.value, parms)
251
252                         getPage(url).addCallback(self._gotPageLoad).addErrback(self.errorLoad)
253
254         def parseFritzBoxPhonebook(self, html):
255                 debug("[FritzCallFBF] parseFritzBoxPhonebook")
256
257                 table = html2utf8(html.replace("\xa0"," ").decode("ISO-8859-1", "replace"))
258                 if re.search('TrFonName', table):
259                         #===============================================================================
260                         #                                New Style: 7170 / 7270 (FW 54.04.58, 54.04.63-11941) 
261                         #       We expect one line with TrFonName followed by several lines with
262                         #       TrFonNr(Type,Number,Shortcut,Vanity), which all belong to the name in TrFonName.
263                         #===============================================================================
264                         # entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]+"\);</SCRIPT>\s+[<SCRIPT type=text/javascript>TrFonNr\("[^"]+", "[^"]+", "[^"]+", "[^"]+"\);</SCRIPT>\s+]+)<SCRIPT type=text/javascript>document.write(TrFon1());</SCRIPT>', re.DOTALL)
265                         # entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]+"\);.*?[.*?TrFonNr\("[^"]+", "[^"]+", "[^"]+", "[^"]+"\);.*?]+).*?document.write(TrFon1());', re.DOTALL)
266                         entrymask = re.compile('(TrFonName\("[^"]+", "[^"]+", "[^"]*"\);.*?)TrFon1\(\)', re.S)
267                         entries = entrymask.finditer(html)
268                         for entry in entries:
269                                 # debug(entry.group(1)
270                                 found = re.match('TrFonName\("[^"]*", "([^"]+)", "[^"]*"\);', entry.group(1))
271                                 if found:
272                                         name = found.group(1)
273                                 else:
274                                         continue
275                                 detailmask = re.compile('TrFonNr\("([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\);', re.S)
276                                 details = detailmask.finditer(entry.group(1))
277                                 for found in details:
278                                         thisname = name
279
280                                         type = found.group(1)
281                                         if config.plugins.FritzCall.showType.value:
282                                                 if type == "mobile":
283                                                         thisname = thisname + " (" +_("mobile") + ")"
284                                                 elif type == "home":
285                                                         thisname = thisname + " (" +_("home") + ")"
286                                                 elif type == "work":
287                                                         thisname = thisname + " (" +_("work") + ")"
288
289                                         if config.plugins.FritzCall.showShortcut.value and found.group(3):
290                                                 thisname = thisname + ", " + _("Shortcut") + ": " + found.group(3)
291                                         if config.plugins.FritzCall.showVanity.value and found.group(4):
292                                                 thisname = thisname + ", " + _("Vanity") + ": " + found.group(4)
293
294                                         thisnumber = found.group(2).strip()
295                                         thisname = html2utf8(thisname.strip())
296                                         if thisnumber:
297                                                 debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" %(thisname, thisnumber))
298                                                 phonebook.phonebook[thisnumber] = thisname
299                                         else:
300                                                 debug("[FritzCallFBF] ignoring empty number for %s" %thisname)
301                                         continue
302
303                 elif re.search('TrFon', table):
304                         #===============================================================================
305                         #                               Old Style: 7050 (FW 14.04.33)
306                         #       We expect one line with TrFon(No,Name,Number,Shortcut,Vanity)
307                         #===============================================================================                                
308                         entrymask = re.compile('TrFon\("[^"]*", "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"\)', re.S)
309                         entries = entrymask.finditer(html)
310                         for found in entries:
311                                 name = found.group(1).strip()
312                                 thisnumber = found.group(2).strip()
313                                 if config.plugins.FritzCall.showShortcut.value and found.group(3):
314                                         name = name + ", " + _("Shortcut") + ": " + found.group(3)
315                                 if config.plugins.FritzCall.showVanity.value and found.group(4):
316                                         name = name + ", " +_("Vanity") +": " + found.group(4)
317                                 if thisnumber:
318                                         name = html2utf8(name)
319                                         debug("[FritzCallFBF] Adding '''%s''' with '''%s''' from FRITZ!Box Phonebook!" %(name, thisnumber))
320                                         phonebook.phonebook[thisnumber] = name
321                                 else:
322                                         debug("[FritzCallFBF] ignoring empty number for %s" %name)
323                                 continue
324                 else:
325                         self.notify(_("Could not parse FRITZ!Box Phonebook entry"))
326
327         def errorCalls(self, error):
328                 text = _("Could not load calls from FRITZ!Box - Error: %s") %error
329                 self.notify(text)
330
331         def _gotPageCalls(self, csv = ""):
332                 def _resolveNumber(number):
333                         if number.isdigit():
334                                 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0]=="0": number = number[1:]
335                                 # strip CbC prefix
336                                 if config.plugins.FritzCall.country.value == '0049':
337                                         if re.match('^0100\d\d', number):
338                                                 number = number[6:]
339                                         elif re.match('^010\d\d', number):
340                                                 number = number[5:]
341                                 if config.plugins.FritzCall.prefix.value and number and number[0] != '0':               # should only happen for outgoing
342                                         number = config.plugins.FritzCall.prefix.value + number
343                                 name = phonebook.search(number)
344                                 if name:
345                                         found = re.match('(.*?)\n.*', name)
346                                         if found:
347                                                 name = found.group(1)
348                                         number = name
349                         elif number == "":
350                                 number = _("UNKNOWN")
351                         # if len(number) > 20: number = number[:20]
352                         return number
353
354                 if csv:
355                         debug("[FritzCallFBF] _gotPageCalls: got csv, setting callList")
356                         if self.callScreen:
357                                 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("done"))
358                         # check for error: wrong password or password not set... TODO
359                         found = re.search('Melden Sie sich mit dem Kennwort der FRITZ!Box an', csv)
360                         if found:
361                                 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.")
362                                 # self.session.open(MessageBox, text, MessageBox.TYPE_ERROR, timeout=config.plugins.FritzCall.timeout.value)
363                                 self.notify(text)
364                                 return
365
366                         csv = csv.decode('iso-8859-1','replace').encode('utf-8','replace')
367                         lines = csv.splitlines()
368                         self.callList = lines
369                 elif self.callList:
370                         debug("[FritzCallFBF] _gotPageCalls: got no csv, but have callList")
371                         if self.callScreen:
372                                 self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("done, using last list"))
373                         lines = self.callList
374                 else:
375                         debug("[FritzCallFBF] _gotPageCalls: got no csv, no callList, leaving")
376                         return
377                         
378                 callList = []
379                 for line in lines:
380                         # debug(line
381                         # Typ;Datum;Name;Rufnummer;Nebenstelle;Eigene Rufnummer;Dauer
382                         found = re.match("^(" + self.callType + ");([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)", line)
383                         if found:
384                                 direct = found.group(1)
385                                 date = found.group(2)
386                                 remote = _resolveNumber(found.group(4))
387                                 if not remote and direct != FBF_OUT_CALLS and found.group(3):
388                                         remote = found.group(3)
389                                 found1 = re.match('Internet: (.*)', found.group(6))
390                                 if found1:
391                                         here = _resolveNumber(found1.group(1))
392                                 else:
393                                         here = _resolveNumber(found.group(6))
394                                 
395                                 # strip CbC prefix for Germany
396                                 number = found.group(4)
397                                 if config.plugins.FritzCall.country.value == '0049':
398                                         if re.match('^0100\d\d', number):
399                                                 number = number[6:]
400                                         elif re.match('^010\d\d', number):
401                                                 number = number[5:]
402                                 if config.plugins.FritzCall.prefix.value and number and number[0] != '0':               # should only happen for outgoing
403                                         number = config.plugins.FritzCall.prefix.value + number
404                                 callList.append((number, date, here, direct, remote))
405
406                 # debug("[FritzCallFBF] _gotPageCalls result:\n" + text
407
408                 if self.Callback is not None:
409                         # debug("[FritzCallFBF] _gotPageCalls call callback with\n" + text
410                         self.Callback(callList)
411                         self.Callback = None
412                 self.callScreen = None
413
414         def getCalls(self, callScreen, callback, type):
415                 #
416                 # call sequence must be:
417                 # - login
418                 # - getPage -> _gotPageLogin
419                 # - loginCallback (_getCalls)
420                 # - getPage -> _getCalls1
421                 debug("[FritzCallFBF] getCalls")
422                 self.callScreen = callScreen
423                 self.callType = type
424                 self.Callback = callback
425                 if (time.time() - self.timestamp) > 180: 
426                         debug("[FritzCallFBF] getCalls: outdated data, login and get new ones")
427                         self.timestamp = time.time()
428                         self.login(self._getCalls)
429                 elif not self.callList:
430                         debug("[FritzCallFBF] getCalls: time is ok, but no callList")
431                         self._getCalls1()
432                 else:
433                         debug("[FritzCallFBF] getCalls: time is ok, callList is ok")
434                         self._gotPageCalls()
435
436         def _getCalls(self, html=None):
437                 #
438                 # we need this to fill Anrufliste.csv
439                 # http://repeater1/cgi-bin/webcm?getpage=../html/de/menus/menu2.html&var:lang=de&var:menu=fon&var:pagename=foncalls
440                 #
441                 debug("[FritzCallFBF] _getCalls")
442                 if self.callScreen:
443                         self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("preparing"))
444                 parms = urlencode({'getpage':'../html/de/menus/menu2.html', 'var:lang':'de','var:pagename':'foncalls','var:menu':'fon'})
445                 url = "http://%s/cgi-bin/webcm?%s" %(config.plugins.FritzCall.hostname.value, parms)
446                 getPage(url).addCallback(self._getCalls1).addErrback(self.errorCalls)
447
448         def _getCalls1(self, html = ""):
449                 #
450                 # finally we should have successfully lgged in and filled the csv
451                 #
452                 debug("[FritzCallFBF] _getCalls1")
453                 if self.callScreen:
454                         self.callScreen.updateStatus(_("Getting calls from FRITZ!Box...") + _("finishing"))
455                 parms = urlencode({'getpage':'../html/de/FRITZ!Box_Anrufliste.csv'})
456                 url = "http://%s/cgi-bin/webcm?%s" %(config.plugins.FritzCall.hostname.value, parms)
457                 getPage(url).addCallback(self._gotPageCalls).addErrback(self.errorCalls)
458
459         def dial(self, number):
460                 ''' initiate a call to number '''
461                 self.number = number
462                 self.login(self._dial)
463                 
464         def _dial(self, html=None):
465                 url = "http://%s/cgi-bin/webcm" %config.plugins.FritzCall.hostname.value
466                 parms = urlencode({
467                         'getpage':'../html/de/menus/menu2.html',
468                         # 'id':'uiPostForm',
469                         # 'name':'uiPostForm',
470                         'login:command/password': config.plugins.FritzCall.password.value,
471                         'var:pagename':'fonbuch',
472                         'var:menu':'home',
473                         'telcfg:settings/UseClickToDial':'1',
474                         'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
475                         'telcfg:command/Dial':self.number
476                         })
477                 debug("[FritzCallFBF] dial url: '" + url + "' parms: '" + parms + "'")
478                 getPage(url,
479                         method="POST",
480                         agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5",
481                         headers = {
482                                         'Content-Type': "application/x-www-form-urlencoded",
483                                         'Content-Length': str(len(parms))},
484                         postdata=parms).addCallback(self._okDial).addErrback(self._errorDial)
485
486         def _okDial(self, html):
487                 debug("[FritzCallFBF] okDial")
488                 linkP =  open("/tmp/FritzCallDialOK.htm", "w")
489                 linkP.write(html)
490                 linkP.close()
491
492         def _errorDial(self, error):
493                 debug("[FritzCallFBF] errorDial: $s" %error)
494                 linkP =  open("/tmp/FritzCallDialError.htm", "w")
495                 linkP.write(error)
496                 linkP.close()
497                 text = _("Dialling failed - Error: %s") %error
498                 self.notify(text)
499
500         def hangup(self):
501                 ''' hangup call on port; not used for now '''
502                 url = "http://%s/cgi-bin/webcm" %config.plugins.FritzCall.hostname.value
503                 parms = urlencode({
504                         #'getpage':'../html/de/menus/menu2.html',
505                         'id':'uiPostForm',
506                         'name':'uiPostForm',
507                         'login:command/password': config.plugins.FritzCall.password.value,
508                         #'var:pagename':'fonbuch',
509                         #'var:menu':'home',
510                         'telcfg:settings/UseClickToDial':'1',
511                         'telcfg:settings/DialPort':config.plugins.FritzCall.extension.value,
512                         'telcfg:command/Hangup':''
513                         })
514                 debug("[FritzCallFBF] hangup url: '" + url + "' parms: '" + parms + "'")
515                 getPage(url,
516                         method="POST",
517                         headers = {
518                                         'Content-Type': "application/x-www-form-urlencoded",
519                                         'Content-Length': str(len(parms))},
520                         postdata=parms)
521
522
523 fritzbox = FritzCallFBF()
524
525 class FritzDisplayCalls(Screen, HelpableScreen):
526
527
528         def __init__(self, session, text = ""):
529                 if config.plugins.FritzCall.fullscreen.value:
530                         self.width = DESKTOP_WIDTH
531                         self.height = DESKTOP_HEIGHT
532                         backMainPng = ""
533                         if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
534                                 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
535                         elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
536                                 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
537                         if backMainPng:
538                                         backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" %(self.width, self.height, backMainPng)
539                         else:
540                                 backMainLine = ""
541                         debug("[FritzDisplayCalls] backMainLine: " + backMainLine)
542                                 
543                         # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
544                         self.skin = """
545                                 <screen name="FritzDisplayCalls" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
546                                         %s
547                                         <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
548                                                 <convert type="ClockToText">Default</convert>
549                                         </widget>
550                                         <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
551                                                 <convert type="ClockToText">Date</convert>
552                                         </widget>
553                                         <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
554                         
555                                         <widget name="statusbar" position="%d,%d"  size="%d,%d" font="Regular;%d" backgroundColor="#353e575e" transparent="1" />
556                                         <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
557                         
558                                         <ePixmap pixmap="skin_default/buttons/red.png"          position="%d,%d"        size="%d,%d" alphatest="on" />
559                                         <ePixmap pixmap="skin_default/buttons/green.png"        position="%d,%d"        size="%d,%d" alphatest="on" />
560                                         <ePixmap pixmap="skin_default/buttons/yellow.png"       position="%d,%d"        size="%d,%d" alphatest="on" />
561                                         <ePixmap pixmap="skin_default/buttons/blue.png"         position="%d,%d"        size="%d,%d" alphatest="on" />
562                                         <widget name="key_red"  position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
563                                         <widget name="key_green"        position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
564                                         <widget name="key_yellow"       position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
565                                         <widget name="key_blue"         position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
566                                         <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />           
567                                 </screen>""" % (
568                                                         self.width, self.height, _("Phone calls"),
569                                                         backMainLine,
570                                                         scaleH(1130,XXX), scaleV(40,XXX), scaleH(80,XXX), scaleV(26,XXX), scaleV(26,XXX), # time
571                                                         scaleH(900,XXX), scaleV(70,XXX), scaleH(310,XXX), scaleV(22,XXX), scaleV(20,XXX), # date
572                                                         "FritzCall " + _("Phone calls"), scaleH(500,XXX), scaleV(63,XXX), scaleH(330,XXX), scaleV(30,XXX), scaleV(27,XXX), # eLabel
573                                                         scaleH(80,XXX), scaleV(150,XXX), scaleH(280,XXX), scaleV(200,XXX), scaleV(22,XXX), # statusbar
574                                                         scaleH(420,XXX), scaleV(120,XXX), scaleH(790,XXX), scaleV(438,XXX), # entries
575                                                         scaleH(450,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # red
576                                                         scaleH(640,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # green
577                                                         scaleH(830,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # yellow
578                                                         scaleH(1020,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # blue
579                                                         scaleH(480,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # red
580                                                         scaleH(670,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # green
581                                                         scaleH(860,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # yellow
582                                                         scaleH(1050,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # blue
583                                                         scaleH(120,XXX), scaleV(430,XXX), scaleH(150,XXX), scaleV(110,XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/fritz.png") # Fritz Logo size and pixmap
584                                                         )
585                 else:
586                         self.width = scaleH(1100,570)
587                         debug("[FritzDisplayCalls] width: " + str(self.width))
588                         # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
589                         self.skin = """
590                                 <screen name="FritzDisplayCalls" position="%d,%d" size="%d,%d" title="%s" >
591                                         <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
592                                         <widget name="statusbar" position="%d,%d" size="%d,%d" font="Regular;%d" backgroundColor="#aaaaaa" transparent="1" />
593                                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
594                                         <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#aaaaaa" transparent="1" />
595                                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
596                                         <widget name="key_red" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="red" />
597                                         <widget name="key_green" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="green" />
598                                         <widget name="key_yellow" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="yellow" />
599                                         <widget name="key_blue" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="blue" />
600                                 </screen>""" % (
601                                                         scaleH(90,75), scaleV(100,78), # position 
602                                                         scaleH(1100,570), scaleV(560,430), # size
603                                                         _("Phone calls"),
604                                                         scaleH(1100,570), # eLabel width
605                                                         scaleH(40,5), scaleV(10,5), # statusbar position
606                                                         scaleH(1050,560), scaleV(25,22), # statusbar size
607                                                         scaleV(22,21), # statusbar font size
608                                                         scaleV(40,28), # eLabel position vertical
609                                                         scaleH(1100,570), # eLabel width
610                                                         scaleH(40,5), scaleV(55,40), # entries position
611                                                         scaleH(1040,560), scaleV(458,340), # entries size
612                                                         scaleV(518,390), # eLabel position vertical
613                                                         scaleH(1100,570), # eLabel width
614                                                         scaleH(20,5),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget red
615                                                         scaleH(290,145),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget green
616                                                         scaleH(560,285),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget yellow
617                                                         scaleH(830,425),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget blue
618                                                         )
619
620                 Screen.__init__(self, session)
621                 HelpableScreen.__init__(self)
622
623                 # TRANSLATORS: keep it short, this is a button
624                 self["key_red"] = Button(_("All"))
625                 # TRANSLATORS: keep it short, this is a button
626                 self["key_green"] = Button(_("Missed"))
627                 # TRANSLATORS: keep it short, this is a button
628                 self["key_yellow"] = Button(_("Incoming"))
629                 # TRANSLATORS: keep it short, this is a button
630                 self["key_blue"] = Button(_("Outgoing"))
631
632                 self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
633                 {
634                         "red": self.displayAllCalls,
635                         "green": self.displayMissedCalls,
636                         "yellow": self.displayInCalls,
637                         "blue": self.displayOutCalls,
638                         "cancel": self.ok,
639                         "ok": self.showEntry,}, -2)
640
641                 # TRANSLATORS: this is a help text, keep it short
642                 self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
643                 # TRANSLATORS: this is a help text, keep it short
644                 self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
645                 # TRANSLATORS: this is a help text, keep it short
646                 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Display all calls"))]))
647                 # TRANSLATORS: this is a help text, keep it short
648                 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Display missed calls"))]))
649                 # TRANSLATORS: this is a help text, keep it short
650                 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Display incoming calls"))]))
651                 # TRANSLATORS: this is a help text, keep it short
652                 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Display outgoing calls"))]))
653
654                 self["statusbar"] = Label(_("Getting calls from FRITZ!Box..."))
655                 self["entries"] = MenuList([], True, content = eListboxPythonMultiContent)
656                 fontSize = scaleV(22,16)
657                 fontHeight = scaleV(24,20)
658                 self["entries"].l.setFont(0, gFont("Console", fontSize))
659                 self["entries"].l.setItemHeight(fontHeight)
660
661                 debug("[FritzDisplayCalls] init: '''%s'''" %config.plugins.FritzCall.fbfCalls.value)
662                 self.display()
663
664         def ok(self):
665                 self.close()
666
667         def displayAllCalls(self):
668                 debug("[FritzDisplayCalls] displayAllCalls")
669                 self.display(FBF_ALL_CALLS)
670
671         def displayMissedCalls(self):
672                 debug("[FritzDisplayCalls] displayMissedCalls")
673                 self.display(FBF_MISSED_CALLS)
674
675         def displayInCalls(self):
676                 debug("[FritzDisplayCalls] displayInCalls")
677                 self.display(FBF_IN_CALLS)
678
679         def displayOutCalls(self):
680                 debug("[FritzDisplayCalls] displayOutCalls")
681                 self.display(FBF_OUT_CALLS)
682
683         def display(self, which=config.plugins.FritzCall.fbfCalls.value):
684                 debug("[FritzDisplayCalls] display")
685                 config.plugins.FritzCall.fbfCalls.value = which
686                 config.plugins.FritzCall.fbfCalls.save()
687                 self.header = fbfCallsChoices[which]
688                 fritzbox.getCalls(self, self.gotCalls, which)
689
690         def gotCalls(self, callList):
691                 debug("[FritzDisplayCalls] gotCalls")
692                 self.updateStatus(self.header + " (" + str(len(callList)) + ")")
693                 sortlist = []
694                 # TODO: colculate number of chars, we can display
695                 noChars = scaleV(60,40)
696                 for (number, date, remote, direct, here) in callList:
697                         while (len(remote) + len(here)) > noChars:
698                                 if len(remote) > len(here):
699                                         remote = remote[:-1]
700                                 else:
701                                         here = here[:-1]
702                         found = re.match("(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
703                         if found: date = found.group(1) + found.group(2)
704                         if direct == FBF_OUT_CALLS:
705                                 message = date + " " + remote + " -> " + here
706                         else:
707                                 message = date + " " + here + " -> " + remote
708                         sortlist.append([number, (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, self.width-10, 20, 0, RT_HALIGN_LEFT, message)])
709                 self["entries"].setList(sortlist)
710
711         def updateStatus(self, text):
712                 self["statusbar"].setText(text)
713
714         def showEntry(self):
715                 debug("[FritzDisplayCalls] showEntry")
716                 cur = self["entries"].getCurrent()
717                 if cur:
718                         if cur[0]:
719                                 debug("[FritzDisplayCalls] showEntry %s" % (cur[0]))
720                                 number = cur[0]
721                                 fullname = phonebook.search(cur[0])
722                                 if fullname:
723                                         # we have a name for this number
724                                         name = fullname
725                                         self.session.open(FritzOfferAction, self, number, name)
726                                 else:
727                                         # we don't
728                                         self.session.open(FritzOfferAction, self, number)
729                         else:
730                                 # we do not even have a number...
731                                 self.session.open(MessageBox,
732                                                   _("UNKNOWN"),
733                                                   type = MessageBox.TYPE_INFO)
734
735
736 class FritzOfferAction(Screen):
737         # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
738         width = 430 # = 5 + 3x140 + 5; 3 Buttons
739         height = 176 # = 5 + 126 + 40 + 5; 6 lines of text possible
740         skin = """
741                 <screen name="FritzOfferAction" position="%d,%d" size="%d,%d" title="%s" >
742                         <widget name="text" position="5,5" size="%d,%d" font="Regular;21" />
743                         <ePixmap position="5,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
744                         <ePixmap position="145,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
745                         <ePixmap position="285,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
746                         <widget name="key_red" position="5,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
747                         <widget name="key_green" position="145,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
748                         <widget name="key_yellow" position="285,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
749                 </screen>""" % (
750                                                 (DESKTOP_WIDTH - width) / 2,
751                                                 (DESKTOP_HEIGHT - height) / 2,
752                                                 width,
753                                                 height,
754                                                 _("Do what?"),
755                                                 width -10,
756                                                 height -10 -40,
757                                                 height -5 -40, height -5 -40, height -5 -40, height -5 -40, height -5 -40, height -5 -40 # Buttons
758                                                 ) 
759
760         def __init__(self, session, parent, number, name = ""):
761                 Screen.__init__(self, session)
762         
763                 # TRANSLATORS: keep it short, this is a button
764                 self["key_red"] = Button(_("Lookup"))
765                 # TRANSLATORS: keep it short, this is a button
766                 self["key_green"] = Button(_("Call"))
767                 # TRANSLATORS: keep it short, this is a button
768                 self["key_yellow"] = Button(_("Save"))
769                 # TRANSLATORS: keep it short, this is a button
770                 # self["key_blue"] = Button(_("Search"))
771
772                 self["FritzOfferActions"] = ActionMap(["OkCancelActions", "ColorActions"],
773                 {
774                         "red": self.lookup,
775                         "green": self.call,
776                         "yellow": self.add,
777                         "cancel": self.exit,
778                         "ok": self.exit,}, -2)
779
780                 self["text"] = Label(number + "\n\n" + name.replace(", ","\n"))
781                 self.actualNumber = number
782                 self.actualName = name
783                 self.parent = parent
784
785         def lookup(self):
786                 ReverseLookupAndNotifier(self.actualNumber, self.lookedUp, "UTF-8", config.plugins.FritzCall.country.value)
787
788         def lookedUp(self, number, name):
789                 self.actualNumber = number
790                 self.actualName = name
791                 self["text"].setText(number + "\n\n" + name.replace(", ","\n"))
792
793         def call(self):
794                 fritzbox.dial(self.actualNumber)
795                 self.exit()
796
797         def add(self):
798                 phonebook.FritzDisplayPhonebook(self.session).add(self.parent, self.actualNumber, self.actualName)
799                 self.exit()
800
801         def exit(self):
802                 self.close()
803
804
805 class FritzCallPhonebook:
806         def __init__(self):
807                 self.phonebook = {}
808                 self.reload()
809
810         def reload(self):
811                 debug("[FritzCallPhonebook] reload")
812                 self.phonebook = {}
813
814                 if not config.plugins.FritzCall.enable.value:
815                         return
816
817                 if config.plugins.FritzCall.phonebook.value and os.path.exists(config.plugins.FritzCall.phonebookLocation.value):
818                         phonebookTxtCorrupt = False
819                         for line in open(config.plugins.FritzCall.phonebookLocation.value):
820                                 try:
821                                         line = line.decode("utf-8")
822                                 except UnicodeDecodeError:
823                                         try:
824                                                 line = line.decode("iso-8859-1")
825                                                 debug("[FritzCallPhonebook] Fallback to ISO-8859-1 in %s" %line)
826                                                 phonebookTxtCorrupt = True
827                                         except:
828                                                 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" %line)
829                                                 phonebookTxtCorrupt = True
830                                 line = line.encode("utf-8")
831                                 if re.match("^\d+#.*$", line):
832                                         try:
833                                                 number, name = line.split("#")
834                                                 if not self.phonebook.has_key(number):
835                                                         self.phonebook[number] = name
836                                         except ValueError: # how could this possibly happen?!?!
837                                                 debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" %line)
838                                                 phonebookTxtCorrupt = True
839                                 else:
840                                         debug("[FritzCallPhonebook] Could not parse internal Phonebook Entry %s" %line)
841                                         phonebookTxtCorrupt = True
842
843                         if phonebookTxtCorrupt:
844                                 # dump phonebook to PhoneBook.txt
845                                 debug("[FritzCallPhonebook] dump Phonebook.txt")
846                                 os.rename(config.plugins.FritzCall.phonebookLocation.value,
847                                                 config.plugins.FritzCall.phonebookLocation.value + ".bck")
848                                 fNew = open(config.plugins.FritzCall.phonebookLocation.value, 'w')
849                                 for (number, name) in self.phonebook.iteritems():
850                                         fNew.write(number + "#" + name.encode("utf-8"))
851                                 fNew.close()
852
853                 if config.plugins.FritzCall.fritzphonebook.value:
854                         fritzbox.loadFritzBoxPhonebook()
855
856                 if DESKTOP_WIDTH <> 1280 or DESKTOP_HEIGHT <> 720:
857                         config.plugins.FritzCall.fullscreen.value = False
858
859
860         def search(self, number):
861                 # debug("[FritzCallPhonebook] Searching for %s" %number
862                 name = None
863                 if config.plugins.FritzCall.phonebook.value or config.plugins.FritzCall.fritzphonebook.value:
864                         if self.phonebook.has_key(number):
865                                 name = self.phonebook[number].replace(", ", "\n").strip()
866                 return name
867
868         def add(self, number, name):
869                 debug("[FritzCallPhonebook] add")
870                 #===============================================================================
871                 #               It could happen, that two reverseLookups are running in parallel,
872                 #               so check first, whether we have already added the number to the phonebook.
873                 #===============================================================================
874                 name = name.replace("\n", ", ") # this is just for safety reasons. add should only be called with newlines converted into commas
875                 self.phonebook[number] = name;
876                 if number and number <> 0 and config.plugins.FritzCall.addcallers.value:
877                         if config.plugins.FritzCall.phonebook.value:
878                                 try:
879                                         f = open(config.plugins.FritzCall.phonebookLocation.value, 'a')
880                                         name = name.strip() + "\n"
881                                         string = "%s#%s" %(number, name)
882                                         f.write(string.encode("utf-8"))
883                                         f.close()
884                                         debug("[FritzCallPhonebook] added %s with %s to Phonebook.txt" %(number, name))
885                                         return True
886         
887                                 except IOError:
888                                         return False
889
890         def remove(self, number):
891                 debug("[FritzCallPhonebook] remove")
892                 if number in self.phonebook:
893                         debug("[FritzCallPhonebook] remove entry in phonebook")
894                         del self.phonebook[number]
895                         if config.plugins.FritzCall.phonebook.value:
896                                 try:
897                                         debug("[FritzCallPhonebook] remove entry in Phonebook.txt")
898                                         fOld = open(config.plugins.FritzCall.phonebookLocation.value, 'r')
899                                         fNew = open(config.plugins.FritzCall.phonebookLocation.value + str(os.getpid()), 'w')
900                                         line = fOld.readline()
901                                         while (line):
902                                                 if not re.match("^"+number+"#.*$", line):
903                                                         fNew.write(line)
904                                                 line = fOld.readline()
905                                         fOld.close()
906                                         fNew.close()
907                                         os.remove(config.plugins.FritzCall.phonebookLocation.value)
908                                         os.rename(config.plugins.FritzCall.phonebookLocation.value + str(os.getpid()),
909                                                         config.plugins.FritzCall.phonebookLocation.value)
910                                         debug("[FritzCallPhonebook] removed %s from Phonebook.txt" %number)
911                                         return True
912         
913                                 except IOError:
914                                         pass
915                 return False
916
917         class FritzDisplayPhonebook(Screen, HelpableScreen, NumericalTextInput):
918
919                 def __init__(self, session):
920                         if config.plugins.FritzCall.fullscreen.value:
921                                 self.width = DESKTOP_WIDTH
922                                 self.height = DESKTOP_HEIGHT
923                                 backMainPng = ""
924                                 if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
925                                         backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
926                                 elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
927                                         backMainPng = "Kerni-HD1-picon/menu/back-main.png"
928                                 if backMainPng:
929                                         backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" %(self.width, self.height, backMainPng)
930                                 else:
931                                         backMainLine = ""
932                                 debug("[FritzDisplayPhonebook] backMainLine: " + backMainLine)
933                                         
934                                 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
935                                 self.skin = """
936                                         <screen name="FritzdisplayPhonebook" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
937                                                 %s
938                                                 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
939                                                         <convert type="ClockToText">Default</convert>
940                                                 </widget>
941                                                 <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
942                                                         <convert type="ClockToText">Date</convert>
943                                                 </widget>
944                                                 <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
945                                 
946                                                 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
947                                 
948                                                 <ePixmap pixmap="skin_default/buttons/red.png"          position="%d,%d"        size="%d,%d" alphatest="on" />
949                                                 <ePixmap pixmap="skin_default/buttons/green.png"        position="%d,%d"        size="%d,%d" alphatest="on" />
950                                                 <ePixmap pixmap="skin_default/buttons/yellow.png"       position="%d,%d"        size="%d,%d" alphatest="on" />
951                                                 <ePixmap pixmap="skin_default/buttons/blue.png"         position="%d,%d"        size="%d,%d" alphatest="on" />
952                                                 <widget name="key_red"  position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
953                                                 <widget name="key_green"        position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
954                                                 <widget name="key_yellow"       position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
955                                                 <widget name="key_blue"         position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
956                                                 <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />   
957                                         </screen>""" % (
958                                                                     self.width, self.height, _("Phonebook"),
959                                                                     backMainLine,
960                                                                     scaleH(1130,XXX), scaleV(40,XXX), scaleH(80,XXX), scaleV(26,XXX), scaleV(26,XXX), # time
961                                                                     scaleH(900,XXX), scaleV(70,XXX), scaleH(310,XXX), scaleV(22,XXX), scaleV(20,XXX), # date
962                                                                     "FritzCall " + _("Phonebook"), scaleH(80,XXX), scaleV(63,XXX), scaleH(300,XXX), scaleV(30,XXX), scaleV(27,XXX), # eLabel
963                                                                     scaleH(420,XXX), scaleV(120,XXX), scaleH(790,XXX), scaleV(438,XXX), # entries
964                                                                     scaleH(450,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # red
965                                                                     scaleH(640,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # green
966                                                                     scaleH(830,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # yellow
967                                                                     scaleH(1020,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # blue
968                                                                     scaleH(480,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # red
969                                                                     scaleH(670,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # green
970                                                                     scaleH(860,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # yellow
971                                                                     scaleH(1050,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # blue
972                                                                     scaleH(120,XXX), scaleV(430,XXX), scaleH(150,XXX), scaleV(110,XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/fritz.png") # Fritz Logo size and pixmap
973                                                                 )
974                         else:
975                                 self.width = scaleH(1100,570)
976                                 debug("[FritzDisplayPhonebook] width: " + str(self.width))
977                                 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
978                                 self.skin = """
979                                         <screen name="FritzDisplayPhonebook" position="%d,%d" size="%d,%d" title="%s" >
980                                                 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
981                                                 <widget name="entries" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="transpBlack" transparent="1" />
982                                                 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
983                                                 <widget name="key_red" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="red" />
984                                                 <widget name="key_green" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="green" />
985                                                 <widget name="key_yellow" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="yellow" />
986                                                 <widget name="key_blue" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="blue" />
987                                         </screen>""" % (
988                                                         scaleH(90,75), scaleV(100,73), # position 
989                                                         scaleH(1100,570), scaleV(560,430), # size
990                                                         _("Phonebook"),
991                                                         scaleH(1100,570), # eLabel width
992                                                         scaleH(40,5), scaleV(20,5), # entries position
993                                                         scaleH(1040,560), scaleV(488,380), # entries size
994                                                         scaleV(518,390), # eLabel position vertical
995                                                         scaleH(1100,570), # eLabel width
996                                                         scaleH(20,5),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget red
997                                                         scaleH(290,145),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget green
998                                                         scaleH(560,285),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget yellow
999                                                         scaleH(830,425),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget blue
1000                                                                 )
1001
1002                         Screen.__init__(self, session)
1003                         NumericalTextInput.__init__(self)
1004                         HelpableScreen.__init__(self)
1005                 
1006                         # TRANSLATORS: keep it short, this is a button
1007                         self["key_red"] = Button(_("Delete"))
1008                         # TRANSLATORS: keep it short, this is a button
1009                         self["key_green"] = Button(_("New"))
1010                         # TRANSLATORS: keep it short, this is a button
1011                         self["key_yellow"] = Button(_("Edit"))
1012                         # TRANSLATORS: keep it short, this is a button
1013                         self["key_blue"] = Button(_("Search"))
1014         
1015                         self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
1016                         {
1017                                 "red": self.delete,
1018                                 "green": self.add,
1019                                 "yellow": self.edit,
1020                                 "blue": self.search,
1021                                 "cancel": self.exit,
1022                                 "ok": self.showEntry,}, -2)
1023
1024                         # TRANSLATORS: this is a help text, keep it short
1025                         self.helpList.append((self["setupActions"], "OkCancelActions", [("ok", _("Show details of entry"))]))
1026                         # TRANSLATORS: this is a help text, keep it short
1027                         self.helpList.append((self["setupActions"], "OkCancelActions", [("cancel", _("Quit"))]))
1028                         # TRANSLATORS: this is a help text, keep it short
1029                         self.helpList.append((self["setupActions"], "ColorActions", [("red", _("Delete entry"))]))
1030                         # TRANSLATORS: this is a help text, keep it short
1031                         self.helpList.append((self["setupActions"], "ColorActions", [("green", _("Add entry to phonebook"))]))
1032                         # TRANSLATORS: this is a help text, keep it short
1033                         self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("Edit selected entry"))]))
1034                         # TRANSLATORS: this is a help text, keep it short
1035                         self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("Search (case insensitive)"))]))
1036
1037                         self["entries"] = MenuList([], True, content = eListboxPythonMultiContent)
1038                         fontSize = scaleV(22,16)
1039                         fontHeight = scaleV(24,20)
1040                         self["entries"].l.setFont(0, gFont("Console", fontSize))
1041                         self["entries"].l.setItemHeight(fontHeight)
1042                         debug("[FritzCallPhonebook] displayPhonebook init")
1043                         self.display()
1044
1045                 def display(self, filter=""):
1046                         debug("[FritzCallPhonebook] displayPhonebook/display")
1047                         self.sortlist = []
1048                         sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
1049                         for (low, name, number) in sortlistHelp:
1050                                 if number == "01234567890":
1051                                         continue
1052                                 try:
1053                                         low = low.decode("utf-8")
1054                                 except UnicodeDecodeError:  # this should definitely not happen
1055                                         try:
1056                                                 low = low.decode("iso-8859-1")
1057                                         except:
1058                                                 debug("[FritzCallPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" %number)
1059                                                 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
1060                                                 phonebook.remove(number)
1061                                                 continue
1062                                 else:
1063                                         if filter:
1064                                                 filter = filter.lower()
1065                                                 if low.find(filter) == -1:
1066                                                         continue
1067                                         name = name.strip().decode("utf-8")
1068                                         number = number.strip().decode("utf-8")
1069                                         found = re.match("([^,]*),.*", name)   # strip address information from the name part
1070                                         if found:
1071                                                 shortname = found.group(1)
1072                                         else:
1073                                                 shortname = name
1074                                         # TODO: colculate number of chars, we can display
1075                                         noChars = scaleV(40,35)
1076                                         if len(shortname) > noChars:
1077                                                 shortname = shortname[:noChars]
1078                                         message = u"%-35s  %-18s" %(shortname, number)
1079                                         message = message.encode("utf-8")
1080                                         # debug("[FritzCallPhonebook] displayPhonebook/display: add " + message
1081                                         self.sortlist.append([(number.encode("utf-8","replace"),
1082                                                                    name.encode("utf-8","replace")),
1083                                                                    (eListboxPythonMultiContent.TYPE_TEXT, 0, 0, self.width-10, 20, 0, RT_HALIGN_LEFT, message)])
1084                                 
1085                         self["entries"].setList(self.sortlist)
1086
1087                 def showEntry(self):
1088                         cur = self["entries"].getCurrent()
1089                         if cur and cur[0]:
1090                                 debug("[FritzCallPhonebook] displayPhonebook/showEntry (%s,%s)" % (cur[0][0],cur[0][1]))
1091                                 number = cur[0][0]
1092                                 name = phonebook.search(number).replace('\n',', ')
1093                                 self.session.open(FritzOfferAction, self, number, name)
1094
1095                 def delete(self):
1096                         cur = self["entries"].getCurrent()
1097                         if cur and cur[0]:
1098                                 debug("[FritzCallPhonebook] displayPhonebook/delete " + cur[0][0])
1099                                 self.session.openWithCallback(
1100                                         self.deleteConfirmed,
1101                                         MessageBox,
1102                                         _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?") 
1103                                         % { 'number':str(cur[0][0]), 'name':str(cur[0][1]).replace(", ","\n") }
1104                                 )
1105                         else:
1106                                 self.session.open(MessageBox,_("No entry selected"), MessageBox.TYPE_INFO)
1107
1108                 def deleteConfirmed(self, ret):
1109                         debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed")
1110                         #
1111                         # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1112                         #
1113                         cur = self["entries"].getCurrent()
1114                         if cur:
1115                                 if ret:
1116                                         # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
1117                                         debug("[FritzCallPhonebook] displayPhonebook/deleteConfirmed: remove " +cur[0][0])
1118                                         phonebook.remove(cur[0][0])
1119                                         self.display()
1120                                 # else:
1121                                         # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
1122                         else:
1123                                 self.session.open(MessageBox,_("No entry selected"), MessageBox.TYPE_INFO)
1124
1125                 def add(self, parent = None, number = "", name=""):
1126                         class addScreen(Screen, ConfigListScreen):
1127                                 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
1128                                 width = 570
1129                                 height = 100
1130                                 # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1131                                 skin = """
1132                                         <screen position="%d,%d" size="%d,%d" title="%s" >
1133                                         <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
1134                                         <ePixmap position="145,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1135                                         <ePixmap position="285,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1136                                         <widget name="key_red" position="145,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1137                                         <widget name="key_green" position="285,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1138                                         </screen>"""  % (
1139                                                                         (DESKTOP_WIDTH - width) / 2,
1140                                                                         (DESKTOP_HEIGHT - height) / 2,
1141                                                                         width,
1142                                                                         height,
1143                                                                         _("Add entry to phonebook"),
1144                                                                         width -5 -5,
1145                                                                         height -5 -40 -5,
1146                                                                         height -40 -5, height -40 -5, height -40 -5, height -40 -5
1147                                                                          )
1148
1149
1150                                 def __init__(self, session, parent, number = "", name = ""):
1151                                         #
1152                                         # setup screen with two ConfigText and OK and ABORT button
1153                                         # 
1154                                         Screen.__init__(self, session)
1155                                         self.session = session
1156                                         self.parent = parent
1157                                         # TRANSLATORS: keep it short, this is a button
1158                                         self["key_red"] = Button(_("Cancel"))
1159                                         # TRANSLATORS: keep it short, this is a button
1160                                         self["key_green"] = Button(_("OK"))
1161                                         self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
1162                                         {
1163                                                 "cancel": self.cancel,
1164                                                 "red": self.cancel,
1165                                                 "green": self.add,
1166                                                 "ok": self.add,
1167                                         }, -2)
1168
1169                                         self.list = [ ]
1170                                         ConfigListScreen.__init__(self, self.list, session = session)
1171                                         config.plugins.FritzCall.name.value = name
1172                                         config.plugins.FritzCall.number.value = number
1173                                         self.list.append(getConfigListEntry(_("Name"), config.plugins.FritzCall.name))
1174                                         self.list.append(getConfigListEntry(_("Number"), config.plugins.FritzCall.number))
1175                                         self["config"].list = self.list
1176                                         self["config"].l.setList(self.list)
1177
1178
1179                                 def add(self):
1180                                         # get texts from Screen
1181                                         # add (number,name) to sortlist and phonebook.phonebook and disk
1182                                         self.number = config.plugins.FritzCall.number.value
1183                                         self.name = config.plugins.FritzCall.name.value
1184                                         if not self.number or not self.name:
1185                                                 self.session.open(MessageBox, _("Entry incomplete."), type = MessageBox.TYPE_ERROR)
1186                                                 return
1187                                         # add (number,name) to sortlist and phonebook.phonebook and disk
1188                                         oldname = phonebook.search(self.number)
1189                                         if oldname:
1190                                                 self.session.openWithCallback(
1191                                                         self.overwriteConfirmed,
1192                                                         MessageBox,
1193                                                         _("Do you really want to overwrite entry for %(number)s\n\n%(name)s\n\nwith\n\n%(newname)s?")
1194                                                         % {
1195                                                         'number':self.number,
1196                                                         'name': oldname,
1197                                                         'newname':self.name.replace(", ","\n")
1198                                                         }
1199                                                         )
1200                                                 self.close()
1201                                                 return
1202                                         phonebook.add(self.number, self.name)
1203                                         self.close()
1204                                         self.parent.display()
1205
1206                                 def overwriteConfirmed(self, ret):
1207                                         if ret:
1208                                                 phonebook.remove(self.number)
1209                                                 phonebook.add(self.number, self.name)
1210                                                 self.parent.display()
1211
1212                                 def cancel(self):
1213                                         self.close()
1214
1215                         debug("[FritzCallPhonebook] displayPhonebook/add")
1216                         if not parent:
1217                                 parent = self
1218                         self.session.open(addScreen, parent, number, name)
1219
1220                 def edit(self):
1221                         debug("[FritzCallPhonebook] displayPhonebook/edit")
1222                         cur = self["entries"].getCurrent()
1223                         if cur is None:
1224                                 self.session.open(MessageBox,_("No entry selected"), MessageBox.TYPE_INFO)
1225                         else:
1226                                 (number, name) = cur[0]
1227                                 self.add(self, number, name)
1228
1229                 def search(self):
1230                         debug("[FritzCallPhonebook] displayPhonebook/search")
1231                         self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
1232                         self.help_window.show()
1233                         self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
1234
1235                 def doSearch(self, searchTerms):
1236                         if not searchTerms: searchTerms = ""
1237                         debug("[FritzCallPhonebook] displayPhonebook/doSearch: " + searchTerms)
1238                         if self.help_window:
1239                                 self.session.deleteDialog(self.help_window)
1240                                 self.help_window = None
1241                         self.display(searchTerms)
1242
1243                 def exit(self):
1244                         self.close()
1245
1246 phonebook = FritzCallPhonebook()
1247
1248
1249 class FritzCallSetup(Screen, ConfigListScreen, HelpableScreen):
1250
1251         def __init__(self, session, args = None):
1252                 if config.plugins.FritzCall.fullscreen.value:
1253                         self.width = DESKTOP_WIDTH
1254                         self.height = DESKTOP_HEIGHT
1255                         backMainPng = ""
1256                         backMainLine = ""
1257                         if os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, DESKTOP_SKIN + "/menu/back-main.png")):
1258                                 backMainPng = DESKTOP_SKIN + "/menu/back-main.png"
1259                         elif os.path.exists(resolveFilename(SCOPE_SKIN_IMAGE, "Kerni-HD1-picon/menu/back-main.png")):
1260                                 backMainPng = "Kerni-HD1-picon/menu/back-main.png"
1261                         if backMainPng:
1262                                 backMainLine = """<ePixmap position="0,0" zPosition="-10" size="%d,%d" pixmap="%s" transparent="1" />""" %(self.width, self.height, backMainPng)
1263                         else:
1264                                 backMainLine = ""
1265                         debug("[FritzCallSetup] backMainLine: " + backMainLine)
1266                         # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1267                         self.skin = """
1268                                 <screen name="FritzCallSetup" position="0,0" size="%d,%d" title="%s" flags="wfNoBorder">
1269                                         %s
1270                                         <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1271                                                 <convert type="ClockToText">Default</convert>
1272                                         </widget>
1273                                         <widget source="global.CurrentTime" render="Label" position="%d,%d" size="%d,%d" font="Regular;%d" halign="right" backgroundColor="#0b67a2" transparent="1">
1274                                                 <convert type="ClockToText">Date</convert>
1275                                         </widget>
1276                                         <eLabel text="%s" position="%d,%d" size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#0b67a2" transparent="1"/>
1277                         
1278                                         <widget name="consideration" position="%d,%d"  size="%d,%d" font="Regular;%d" halign="center" backgroundColor="#353e575e" transparent="1" />
1279                                         <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1" />
1280                         
1281                                         <ePixmap pixmap="skin_default/buttons/red.png"          position="%d,%d"        size="%d,%d" alphatest="on" />
1282                                         <ePixmap pixmap="skin_default/buttons/green.png"        position="%d,%d"        size="%d,%d" alphatest="on" />
1283                                         <ePixmap pixmap="skin_default/buttons/yellow.png"       position="%d,%d"        size="%d,%d" alphatest="on" />
1284                                         <ePixmap pixmap="skin_default/buttons/blue.png"         position="%d,%d"        size="%d,%d" alphatest="on" />
1285                                         <widget name="key_red" position="%d,%d"                 size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1286                                         <widget name="key_green"  position="%d,%d"      size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1287                                         <widget name="key_yellow" position="%d,%d"      size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1288                                         <widget name="key_blue" position="%d,%d"        size="%d,%d" zPosition="1" font="Regular;%d" halign="left" backgroundColor="black" transparent="1" />
1289                                         <ePixmap position="%d,%d" size="%d,%d" zPosition="2" pixmap="%s" transparent="1" alphatest="blend" />           
1290                                 </screen>""" % (
1291                                                             self.width, self.height, _("FritzCall Setup"),
1292                                                             backMainLine,
1293                                                             scaleH(1130,XXX), scaleV(40,XXX), scaleH(80,XXX), scaleV(26,XXX), scaleV(26,XXX), # time
1294                                                             scaleH(900,XXX), scaleV(70,XXX), scaleH(310,XXX), scaleV(22,XXX), scaleV(20,XXX), # date
1295                                                             _("FritzCall Setup"), scaleH(500,XXX), scaleV(63,XXX), scaleH(330,XXX), scaleV(30,XXX), scaleV(27,XXX), # eLabel
1296                                                             scaleH(80,XXX), scaleV(150,XXX), scaleH(250,XXX), scaleV(200,XXX), scaleV(22,XXX), # consideration
1297                                                             scaleH(420,XXX), scaleV(125,XXX), scaleH(790,XXX), scaleV(428,XXX), # config
1298                                                             scaleH(450,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # red
1299                                                             scaleH(640,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # green
1300                                                             scaleH(830,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # yellow
1301                                                             scaleH(1020,XXX), scaleV(588,XXX), scaleH(21,XXX), scaleV(21,XXX), # blue
1302                                                             scaleH(480,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # red
1303                                                             scaleH(670,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # green
1304                                                             scaleH(860,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # yellow
1305                                                             scaleH(1050,XXX), scaleV(587,XXX), scaleH(160,XXX), scaleV(22,XXX), scaleV(20,XXX), # blue
1306                                                             scaleH(120,XXX), scaleV(430,XXX), scaleH(150,XXX), scaleV(110,XXX), resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/fritz.png") # Fritz Logo size and pixmap
1307                                                                 ) 
1308                 else:
1309                         self.width = scaleH(1100,570)
1310                         debug("[FritzCallSetup] width: " + str(self.width))
1311                         # TRANSLATORS: this is a window title. Avoid the use of non ascii chars
1312                         self.skin = """
1313                                 <screen name="FritzCallSetup" position="%d,%d" size="%d,%d" title="%s" >
1314                                 <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
1315                                 <widget name="consideration" position="%d,%d" halign="center" size="%d,%d" font="Regular;%d" backgroundColor="transpBlack" transparent="1" />
1316                                 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1317                                 <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="transpBlack" transparent="1" />
1318                                 <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
1319                                 <widget name="key_red" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="red" />
1320                                 <widget name="key_green" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="green" />
1321                                 <widget name="key_yellow" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="yellow" />
1322                                 <widget name="key_blue" position="%d,%d" size="%d,%d" valign="center" halign="center" font="Regular;%d" foregroundColor="blue" />
1323                                 </screen>""" % (
1324                                                         scaleH(90,75), scaleV(100,73), # position 
1325                                                         scaleH(1100,570), scaleV(560,430), # size
1326                                                         _("FritzCall Setup") +
1327                                                         " (" + "$Revision$"[1:-1] +
1328                                                         "$Date$"[7:23] + ")",
1329                                                         scaleH(1100,570), # eLabel width
1330                                                         scaleH(40,20), scaleV(10,5), # consideration position
1331                                                         scaleH(1050,530), scaleV(25,45), # consideration size
1332                                                         scaleV(22,20), # consideration font size
1333                                                         scaleV(40,50), # eLabel position vertical
1334                                                         scaleH(1100,570), # eLabel width
1335                                                         scaleH(40,5), scaleV(60,57), # config position
1336                                                         scaleH(1040,560), scaleV(453,328), # config size
1337                                                         scaleV(518,390), # eLabel position vertical
1338                                                         scaleH(1100,570), # eLabel width
1339                                                         scaleH(20,5),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget red
1340                                                         scaleH(290,145),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget green
1341                                                         scaleH(560,285),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget yellow
1342                                                         scaleH(830,425),scaleV(525,395),scaleH(250,140),scaleV(30,40),scaleV(24,21), # widget blue
1343                                                         )
1344
1345                 Screen.__init__(self, session)
1346                 HelpableScreen.__init__(self)
1347                 self.session = session
1348
1349                 self["consideration"] = Label(_("You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"))
1350                 self.list = []
1351
1352                 # Initialize Buttons
1353                 # TRANSLATORS: keep it short, this is a button
1354                 self["key_red"] = Button(_("Cancel"))
1355                 # TRANSLATORS: keep it short, this is a button
1356                 self["key_green"] = Button(_("OK"))
1357                 # TRANSLATORS: keep it short, this is a button
1358                 self["key_yellow"] = Button(_("Phone calls"))
1359                 # TRANSLATORS: keep it short, this is a button
1360                 self["key_blue"] = Button(_("Phonebook"))
1361
1362                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
1363                 {
1364                         "red": self.cancel,
1365                         "green": self.save,
1366                         "yellow": self.displayCalls,
1367                         "blue": self.displayPhonebook,
1368                         "cancel": self.cancel,
1369                         "save": self.save,
1370                         "ok": self.save,
1371                 }, -2)
1372
1373                 # TRANSLATORS: this is a help text, keep it short
1374                 self.helpList.append((self["setupActions"], "SetupActions", [("ok", _("save and quit"))]))
1375                 # TRANSLATORS: this is a help text, keep it short
1376                 self.helpList.append((self["setupActions"], "SetupActions", [("save", _("save and quit"))]))
1377                 # TRANSLATORS: this is a help text, keep it short
1378                 self.helpList.append((self["setupActions"], "SetupActions", [("cancel", _("quit"))]))
1379                 # TRANSLATORS: this is a help text, keep it short
1380                 self.helpList.append((self["setupActions"], "ColorActions", [("red", _("quit"))]))
1381                 # TRANSLATORS: this is a help text, keep it short
1382                 self.helpList.append((self["setupActions"], "ColorActions", [("green", _("save and quit"))]))
1383                 # TRANSLATORS: this is a help text, keep it short
1384                 self.helpList.append((self["setupActions"], "ColorActions", [("yellow", _("display calls"))]))
1385                 # TRANSLATORS: this is a help text, keep it short
1386                 self.helpList.append((self["setupActions"], "ColorActions", [("blue", _("display phonebook"))]))
1387
1388                 ConfigListScreen.__init__(self, self.list, session = session)
1389                 self.createSetup()
1390
1391
1392         def keyLeft(self):
1393                 ConfigListScreen.keyLeft(self)
1394                 self.createSetup()
1395
1396         def keyRight(self):
1397                 ConfigListScreen.keyRight(self)
1398                 self.createSetup()
1399
1400         def createSetup(self):
1401                 self.list = [ ]
1402                 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.FritzCall.enable))
1403                 if config.plugins.FritzCall.enable.value:
1404                         self.list.append(getConfigListEntry(_("Mute on call"), config.plugins.FritzCall.muteOnCall))
1405                         self.list.append(getConfigListEntry(_("FRITZ!Box FON address (Name or IP)"), config.plugins.FritzCall.hostname))
1406
1407                         self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.FritzCall.afterStandby))
1408
1409                         self.list.append(getConfigListEntry(_("Show Calls for specific MSN"), config.plugins.FritzCall.filter))
1410                         if config.plugins.FritzCall.filter.value:
1411                                 self.list.append(getConfigListEntry(_("MSN to show (separated by ,)"), config.plugins.FritzCall.filtermsn))
1412
1413                         self.list.append(getConfigListEntry(_("Show Outgoing Calls"), config.plugins.FritzCall.showOutgoing))
1414                         if config.plugins.FritzCall.showOutgoing.value:
1415                                 self.list.append(getConfigListEntry(_("Areacode to add to Outgoing Calls (if necessary)"), config.plugins.FritzCall.prefix))
1416                         self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.FritzCall.timeout))
1417                         self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.FritzCall.lookup))
1418                         if config.plugins.FritzCall.lookup.value:
1419                                 self.list.append(getConfigListEntry(_("Country"), config.plugins.FritzCall.country))
1420
1421                         self.list.append(getConfigListEntry(_("Password Accessing FRITZ!Box"), config.plugins.FritzCall.password))
1422                         self.list.append(getConfigListEntry(_("Extension number to initiate call on"), config.plugins.FritzCall.extension))
1423                         self.list.append(getConfigListEntry(_("Read PhoneBook from FRITZ!Box"), config.plugins.FritzCall.fritzphonebook))
1424                         if config.plugins.FritzCall.fritzphonebook.value:
1425                                 self.list.append(getConfigListEntry(_("Append type of number"), config.plugins.FritzCall.showType))
1426                                 self.list.append(getConfigListEntry(_("Append shortcut number"), config.plugins.FritzCall.showShortcut))
1427                                 self.list.append(getConfigListEntry(_("Append vanity name"), config.plugins.FritzCall.showVanity))
1428
1429                         self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.FritzCall.phonebook))
1430                         if config.plugins.FritzCall.phonebook.value:
1431                                 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.FritzCall.phonebookLocation))
1432                                 if config.plugins.FritzCall.lookup.value:
1433                                         self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.FritzCall.addcallers))
1434
1435                         self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.FritzCall.internal))
1436                         # self.list.append(getConfigListEntry(_("Default display mode for FRITZ!Box calls"), config.plugins.FritzCall.fbfCalls))
1437                         if DESKTOP_WIDTH == 1280 and DESKTOP_HEIGHT == 720:
1438                                 self.list.append(getConfigListEntry(_("Full screen display"), config.plugins.FritzCall.fullscreen))
1439                         self.list.append(getConfigListEntry(_("Debug"), config.plugins.FritzCall.debug))
1440
1441                 self["config"].list = self.list
1442                 self["config"].l.setList(self.list)
1443
1444         def save(self):
1445 #               debug("[FritzCallSetup] save"
1446                 for x in self["config"].list:
1447                         x[1].save()
1448                 if fritz_call is not None:
1449                         fritz_call.connect()
1450                         debug("[FritzCallSetup] called phonebook.reload()")
1451                         phonebook.reload()
1452                 self.close()
1453
1454         def cancel(self):
1455 #               debug("[FritzCallSetup] cancel"
1456                 for x in self["config"].list:
1457                         x[1].cancel()
1458                 self.close()
1459
1460         def displayCalls(self):
1461                 self.session.open(FritzDisplayCalls)
1462
1463         def displayPhonebook(self):
1464                 self.session.open(phonebook.FritzDisplayPhonebook)
1465
1466
1467 standbyMode = False
1468
1469 class FritzCallList:
1470         def __init__(self):
1471                 self.callList = [ ]
1472         
1473         def add(self, event, date, number, caller, phone):
1474                 debug("[FritzCallList] add")
1475                 if len(self.callList) > 10:
1476                         if self.callList[0] != "Start":
1477                                 self.callList[0] = "Start"
1478                         del self.callList[1]
1479
1480                 self.callList.append((event, number, date, caller, phone))
1481         
1482         def display(self):
1483                 debug("[FritzCallList] display")
1484                 global standbyMode
1485                 global my_global_session
1486                 standbyMode = False
1487                 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
1488                 # build screen from call list
1489                 text = "\n"
1490                 if self.callList[0] == "Start":
1491                         text = text + _("Last 10 calls:\n")
1492                         del self.callList[0]
1493
1494                 for call in self.callList:
1495                         (event, number, date, caller, phone) = call
1496                         if event == "RING":
1497                                 direction = "->"
1498                         else:
1499                                 direction = "<-"
1500
1501                         # shorten the date info
1502                         found = re.match(".*(\d\d.\d\d.)\d\d( \d\d:\d\d)", date)
1503                         if found: date = found.group(1) + found.group(2)
1504
1505                         # our phone could be of the form "0123456789 (home)", then we only take "home"
1506                         found = re.match(".*\((.*)\)", phone)
1507                         if found: phone = found.group(1)
1508
1509                         #  if we have an unknown number, show the number
1510                         if caller == _("UNKNOWN") and number != "":
1511                                 caller = number
1512                         else:
1513                                 # strip off the address part of the remote number, if there is any
1514                                 found = re.match("(.*)\n.*", caller)
1515                                 if found: caller = found.group(1)
1516
1517                         while (len(caller) + len(phone)) > 40:
1518                                 if len(caller) > len(phone):
1519                                         caller = caller[:-1]
1520                                 else:
1521                                         phone = phone[:-1]
1522
1523                         text = text + "%s %s %s %s\n" %(date, caller, direction, phone)
1524
1525                 debug("[FritzCallList] display: '%s %s %s %s'" %(date, caller, direction, phone))
1526                 # display screen
1527                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
1528                 # my_global_session.open(FritzDisplayCalls, text) # TODO please HELP: from where can I get a session?
1529                 self.callList = [ ]
1530                 self.text = ""
1531
1532 callList = FritzCallList()
1533
1534 from GlobalActions import globalActionMap #@UnresolvedImport
1535 def notifyCall(event, date, number, caller, phone):
1536         if Standby.inStandby is None or config.plugins.FritzCall.afterStandby.value == "each":
1537                 if config.plugins.FritzCall.muteOnCall.value:
1538                         globalActionMap.actions["volumeMute"]()
1539                 if event == "RING":
1540                         text = _("Incoming Call on %(date)s from\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nto: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
1541                 else:
1542                         text = _("Outgoing Call on %(date)s to\n---------------------------------------------\n%(number)s\n%(caller)s\n---------------------------------------------\nfrom: %(phone)s") % { 'date':date, 'number':number, 'caller':caller, 'phone':phone }
1543                 debug("[FritzCall] notifyCall:\n%s" %text)
1544                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1545         elif config.plugins.FritzCall.afterStandby.value == "inList":
1546                 #
1547                 # if not yet done, register function to show call list
1548                 global standbyMode
1549                 if not standbyMode :
1550                         standbyMode = True
1551                         Standby.inStandby.onHide.append(callList.display)
1552                 # add text/timeout to call list
1553                 callList.add(event, date, number, caller, phone)
1554                 debug("[FritzCall] notifyCall: added to callList")
1555         else: # this is the "None" case
1556                 debug("[FritzCall] notifyCall: standby and no show")
1557
1558
1559 #===============================================================================
1560 #               We need a separate class for each invocation of reverseLookup to retain
1561 #               the necessary data for the notification
1562 #===============================================================================
1563
1564 countries = { }
1565 reverselookupMtime = 0
1566
1567 class FritzReverseLookupAndNotifier:
1568         def __init__(self, event, number, caller, phone, date):
1569                 '''
1570                 
1571                 Initiate a reverse lookup for the given number in the configured country
1572                 
1573                 @param event: CALL or RING
1574                 @param number: number to be looked up
1575                 @param caller: caller including name and address
1576                 @param phone: Number (and name) of or own phone
1577                 @param date: date of call
1578                 '''
1579                 debug("[FritzReverseLookupAndNotifier] reverse Lookup for %s!" %number)
1580                 self.event = event
1581                 self.number = number
1582                 self.caller = caller
1583                 self.phone = phone
1584                 self.date = date
1585
1586                 if number[0] != "0":
1587                         self.notifyAndReset(number,caller)
1588                         return
1589
1590                 ReverseLookupAndNotifier(number, self.notifyAndReset, "UTF-8", config.plugins.FritzCall.country.value)
1591
1592         def notifyAndReset(self, number, caller):
1593                 '''
1594                 
1595                 this gets called with the result of the reverse lookup
1596                 
1597                 @param number: number
1598                 @param caller: name and address of remote. it comes in with name, address and city separated by commas
1599                 '''
1600                 debug("[FritzReverseLookupAndNotifier] got: " + caller)
1601                 if caller:
1602                         self.caller = caller.replace(", ", "\n")
1603                         if self.number != 0 and config.plugins.FritzCall.addcallers.value and self.event == "RING":
1604                                 debug("[FritzReverseLookupAndNotifier] add to phonebook")
1605                                 phonebook.add(self.number, self.caller.replace("\n", ", "))
1606                 else:
1607                         self.caller = _("UNKNOWN")
1608                 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
1609                 # kill that object...
1610
1611
1612 class FritzProtocol(LineReceiver):
1613         def __init__(self):
1614                 debug("[FritzProtocol] __init__")
1615                 self.resetValues()
1616
1617         def resetValues(self):
1618                 debug("[FritzProtocol] resetValues")
1619                 self.number = '0'
1620                 self.caller = None
1621                 self.phone = None
1622                 self.date = '0'
1623
1624         def notifyAndReset(self, timeout=config.plugins.FritzCall.timeout.value):
1625                 notifyCall(self.event, self.date, self.number, self.caller, self.phone)
1626                 self.resetValues()
1627
1628         def lineReceived(self, line):
1629                 debug("[FritzProtocol] lineReceived: %s" %line)
1630 #15.07.06 00:38:54;CALL;1;4;<from/extern>;<to/our msn>;
1631 #15.07.06 00:38:58;DISCONNECT;1;0;
1632 #15.07.06 00:39:22;RING;0;<from/extern>;<to/our msn>;
1633 #15.07.06 00:39:27;DISCONNECT;0;0;
1634                 a = line.split(';')
1635                 (self.date, self.event) = a[0:2]
1636
1637                 if self.event == "RING" or (self.event == "CALL" and config.plugins.FritzCall.showOutgoing.value):
1638                         phone = a[4]
1639
1640                         if self.event == "RING":
1641                                 number = a[3] 
1642                         else:
1643                                 number = a[5]
1644                                 
1645                         debug("[FritzProtocol] lineReceived phone: '''%s''' number: '''%s'''" % (phone, number))
1646
1647                         filtermsns = config.plugins.FritzCall.filtermsn.value.split(",")
1648                         for i in range(len(filtermsns)):
1649                                 filtermsns[i] = filtermsns[i].strip()
1650                         if not (config.plugins.FritzCall.filter.value and phone not in filtermsns):
1651                                 debug("[FritzProtocol] lineReceived no filter hit")
1652                                 phonename = phonebook.search(phone)                # do we have a name for the number of our side?
1653                                 if phonename is not None:
1654                                         self.phone = "%s (%s)" %(phone, phonename)
1655                                 else:
1656                                         self.phone = phone
1657
1658                                 if config.plugins.FritzCall.internal.value and len(number) > 3 and number[0]=="0":
1659                                         debug("[FritzProtocol] lineReceived: strip leading 0")
1660                                         self.number = number[1:]
1661                                 else:
1662                                         self.number = number
1663                                         if self.event == "CALL" and self.number[0] != '0':                                        # should only happen for outgoing
1664                                                 debug("[FritzProtocol] lineReceived: add local prefix")
1665                                                 self.number = config.plugins.FritzCall.prefix.value + self.number
1666
1667                                 # check, whether we are in Germany and number has call-by-call prefix. If so strip it
1668                                 if self.event == "CALL" and config.plugins.FritzCall.country.value == '0049':
1669                                         if re.match('^0100\d\d', self.number):
1670                                                 debug("[FritzProtocol] lineReceived: strip CbC 0100.. prefix")
1671                                                 self.number = self.number[6:]
1672                                         elif re.match('^010\d\d', self.number):
1673                                                 debug("[FritzProtocol] lineReceived: strip CbC 010.. prefix")
1674                                                 self.number = self.number[5:]
1675
1676                                 if self.number is not "":
1677                                         debug("[FritzProtocol] lineReceived phonebook.search: %s" %self.number)
1678                                         self.caller = phonebook.search(self.number)
1679                                         debug("[FritzProtocol] lineReceived phonebook.search reault: %s" %self.caller)
1680                                         if (self.caller is None) and config.plugins.FritzCall.lookup.value:
1681                                                 FritzReverseLookupAndNotifier(self.event, self.number, self.caller, self.phone, self.date)
1682                                                 return                                                  # reverselookup is supposed to handle the message itself 
1683
1684                                 if self.caller is None:
1685                                         self.caller = _("UNKNOWN")
1686
1687                                 self.notifyAndReset()
1688
1689 class FritzClientFactory(ReconnectingClientFactory):
1690         initialDelay = 20
1691         maxDelay = 500
1692
1693         def __init__(self):
1694                 self.hangup_ok = False
1695
1696         def startedConnecting(self, connector):
1697                 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box..."), type=MessageBox.TYPE_INFO, timeout=2)
1698
1699         def buildProtocol(self, addr):
1700                 Notifications.AddNotification(MessageBox, _("Connected to FRITZ!Box!"), type=MessageBox.TYPE_INFO, timeout=4)
1701                 self.resetDelay()
1702                 return FritzProtocol()
1703
1704         def clientConnectionLost(self, connector, reason):
1705                 if not self.hangup_ok:
1706                         Notifications.AddNotification(MessageBox, _("Connection to FRITZ!Box! lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1707                 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
1708
1709         def clientConnectionFailed(self, connector, reason):
1710                 Notifications.AddNotification(MessageBox, _("Connecting to FRITZ!Box failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.FritzCall.timeout.value)
1711                 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
1712
1713 class FritzCall:
1714         def __init__(self):
1715                 self.dialog = None
1716                 self.d = None
1717                 self.connect()
1718
1719         def connect(self):
1720                 self.abort()
1721                 if config.plugins.FritzCall.enable.value:
1722                         f = FritzClientFactory()
1723                         self.d = (f, reactor.connectTCP(config.plugins.FritzCall.hostname.value, 1012, f)) #@UndefinedVariable
1724                         initDebug()
1725
1726         def shutdown(self):
1727                 self.abort()
1728
1729         def abort(self):
1730                 if self.d is not None:
1731                         self.d[0].hangup_ok = True
1732                         self.d[0].stopTrying()
1733                         self.d[1].disconnect()
1734                         self.d = None
1735
1736 def displayCalls(session, servicelist):
1737         session.open(FritzDisplayCalls)
1738
1739 def displayPhonebook(session, servicelist):
1740         session.open(phonebook.FritzDisplayPhonebook)
1741
1742 def main(session):
1743         session.open(FritzCallSetup)
1744
1745 fritz_call = None
1746
1747 def autostart(reason, **kwargs):
1748         global fritz_call
1749
1750         # ouch, this is a hack
1751         if kwargs.has_key("session"):
1752                 global my_global_session
1753                 my_global_session = kwargs["session"]
1754                 return
1755
1756         debug("[FRITZ!Call] - Autostart")
1757         if reason == 0:
1758                 fritz_call = FritzCall()
1759         elif reason == 1:
1760                 fritz_call.shutdown()
1761                 fritz_call = None
1762
1763 def Plugins(**kwargs):
1764         what = _("Display FRITZ!box-Fon calls on screen")
1765         what_calls = _("Phone calls")
1766         what_phonebook = _("Phonebook")
1767         return [ PluginDescriptor(name="FritzCall", description=what, where = PluginDescriptor.WHERE_PLUGINMENU, icon = "plugin.png", fnc=main),
1768                 PluginDescriptor(name=what_calls, description=what_calls, where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayCalls),
1769                 PluginDescriptor(name=what_phonebook, description=what_phonebook, where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=displayPhonebook),
1770                 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart) ]