[WebInterface] - forward opener for externals to have access to functions of WebInterface
[enigma2-plugins.git] / ncidclient / src / plugin.py
1 # -*- coding: utf-8 -*-
2 '''
3 $Author: sreichholf $
4 '''
5 from enigma import eTimer, eSize, ePoint, getDesktop, eDVBVolumecontrol, eBackgroundFileEraser
6
7 from Screens.Screen import Screen
8 from Screens.MessageBox import MessageBox
9 from Screens.NumericalTextInputHelpDialog import NumericalTextInputHelpDialog
10 from Screens.InputBox import InputBox
11 from Screens import Standby
12 from Screens.HelpMenu import HelpableScreen
13
14 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigOnOff, getConfigListEntry, ConfigText, ConfigInteger
15 from Components.ActionMap import ActionMap
16 from Components.Label import Label
17 from Components.Button import Button
18 from Components.Pixmap import Pixmap
19 from Components.Sources.List import List
20 from Components.ConfigList import ConfigListScreen
21 from Components.Harddisk import harddiskmanager
22
23 from Plugins.Plugin import PluginDescriptor
24 from Tools import Notifications
25 from Tools.NumericalTextInput import NumericalTextInput
26 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_CONFIG, SCOPE_MEDIA
27 from Tools.LoadPixmap import LoadPixmap
28 from GlobalActions import globalActionMap # for muting
29
30 from twisted.internet import reactor
31 from twisted.internet.protocol import ReconnectingClientFactory
32 from twisted.protocols.basic import LineReceiver
33
34 import re, os
35
36 from datetime import datetime
37
38 from . import debug
39 from reverselookup import ReverseLookupAndNotify
40
41 my_global_session = None
42
43 COUNTRY_CODES = [
44         ("0049", _("Germany")),
45         ("0031", _("The Netherlands")),
46         ("0033", _("France")),
47         ("0039", _("Italy")),
48         ("0041", _("Switzerland")),
49         ("0043", _("Austria"))
50         ]
51
52 DESKTOP_WIDTH = getDesktop(0).size().width()
53 DESKTOP_HEIGHT = getDesktop(0).size().height()
54
55 #
56 # this is pure magic.
57 # It returns the first value, if HD (1280x720),
58 # the second if SD (720x576),
59 # else something scaled accordingly
60 # if one of the parameters is -1, scale proportionally
61 #
62 def scaleH(y2, y1):
63         if y2 == -1:
64                 y2 = y1 * 1280 / 720
65         elif y1 == -1:
66                 y1 = y2 * 720 / 1280
67         return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
68 def scaleV(y2, y1):
69         if y2 == -1:
70                 y2 = y1 * 720 / 576
71         elif y1 == -1:
72                 y1 = y2 * 576 / 720
73         return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
74 def scale(y2, y1, x2, x1, x):
75         return (y2 - y1) * (x - x1) / (x2 - x1) + y1
76
77 def getMountedDevices():
78         def handleMountpoint(loc):
79                 # debug("[NcidClient] handleMountpoint: %s" %repr(loc))
80                 mp = loc[0]
81                 while mp[-1] == '/':
82                         mp = mp[:-1]
83
84                 desc = loc[1]
85                 return (mp, desc + " (" + mp + ")")
86
87         mountedDevs = [(resolveFilename(SCOPE_CONFIG), _("Flash")),
88                                    (resolveFilename(SCOPE_MEDIA, "cf"), _("Compact Flash")),
89                                    (resolveFilename(SCOPE_MEDIA, "usb"), _("USB Device"))]
90         mountedDevs += map(lambda p: (p.mountpoint, (_(p.description) if p.description else "")), harddiskmanager.getMountedPartitions(True))
91         mediaDir = resolveFilename(SCOPE_MEDIA)
92         for p in os.listdir(mediaDir):
93                 if os.path.join(mediaDir, p) not in [path[0] for path in mountedDevs]:
94                         mountedDevs.append((os.path.join(mediaDir, p), _("Media directory")))
95         debug("[NcidClient] getMountedDevices1: %s" % repr(mountedDevs))
96         mountedDevs = filter(lambda path: os.path.isdir(path[0]) and os.access(path[0], os.W_OK | os.X_OK), mountedDevs)
97         # put this after the write/executable check, that is far too slow...
98         netDir = resolveFilename(SCOPE_MEDIA, "net")
99         if os.path.isdir(netDir):
100                 mountedDevs += map(lambda p: (os.path.join(netDir, p), _("Network mount")), os.listdir(netDir))
101         mountedDevs = map(handleMountpoint, mountedDevs)
102         return mountedDevs
103
104 config.plugins.NcidClient = ConfigSubsection()
105 config.plugins.NcidClient.debug = ConfigOnOff(default=False)
106 config.plugins.NcidClient.muteOnCall = ConfigOnOff(default=False)
107 config.plugins.NcidClient.hostname = ConfigText(default="easy.box", fixed_size=False)
108 config.plugins.NcidClient.port = ConfigInteger(limits=[1, 65535], default=3333)
109 config.plugins.NcidClient.afterStandby = ConfigSelection(choices=[("none", _("show nothing")), ("inList", _("show as list")), ("each", _("show each call"))])
110 config.plugins.NcidClient.timeout = ConfigInteger(default=15, limits=(0, 60))
111 config.plugins.NcidClient.lookup = ConfigOnOff(default=False)
112 config.plugins.NcidClient.internal = ConfigOnOff(default=False)
113
114 config.plugins.NcidClient.addcallers = ConfigOnOff(default=False)
115 config.plugins.NcidClient.enable = ConfigOnOff(default=True)
116 config.plugins.NcidClient.extension = ConfigText(default='1', fixed_size=False)
117 config.plugins.NcidClient.extension.setUseableChars('0123456789')
118 config.plugins.NcidClient.showType = ConfigOnOff(default=True)
119 config.plugins.NcidClient.prefix = ConfigText(default="", fixed_size=False)
120 config.plugins.NcidClient.prefix.setUseableChars('0123456789')
121 config.plugins.NcidClient.connectionVerbose = ConfigOnOff(default=True)
122 config.plugins.NcidClient.phonebook = ConfigOnOff(default=False)
123 config.plugins.NcidClient.phonebookLocation = ConfigSelection(choices=getMountedDevices())
124 config.plugins.NcidClient.country = ConfigSelection(choices=COUNTRY_CODES)
125 config.plugins.NcidClient.name = ConfigText(default="", fixed_size=False)
126 config.plugins.NcidClient.number = ConfigText(default="", fixed_size=False)
127 config.plugins.NcidClient.number.setUseableChars('0123456789')
128
129 phonebook = None
130 ncidsrv = None
131
132 avon = {}
133
134 def initAvon():
135         avonFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/NcidClient/avon.dat")
136         if os.path.exists(avonFileName):
137                 with open(avonFileName) as file:
138                         for line in file:
139                                 line = line.decode("iso-8859-1").encode('utf-8')
140                                 if line[0] == '#':
141                                         continue
142                                 parts = line.split(':')
143                                 if len(parts) == 2:
144                                         avon[parts[0].replace('-', '').replace('*', '').replace('/', '')] = parts[1]
145
146 def resolveNumberWithAvon(number, countrycode):
147         if not number or number[0] != '0':
148                 return ""
149
150         countrycode = countrycode.replace('00', '+')
151         if number[:2] == '00':
152                 normNumber = '+' + number[2:]
153         elif number[:1] == '0':
154                 normNumber = countrycode + number[1:]
155         else: # this should can not happen, but safety first
156                 return ""
157
158         # debug('normNumer: ' + normNumber)
159         for i in reversed(range(min(10, len(number)))):
160                 if avon.has_key(normNumber[:i]):
161                         return '[' + avon[normNumber[:i]].strip() + ']'
162         return ""
163
164 def handleReverseLookupResult(name):
165         found = re.match("NA: ([^;]*);VN: ([^;]*);STR: ([^;]*);HNR: ([^;]*);PLZ: ([^;]*);ORT: ([^;]*)", name)
166         if found:
167                 (name, firstname, street, streetno, zipcode, city) = (found.group(1),
168                                                                                                 found.group(2),
169                                                                                                 found.group(3),
170                                                                                                 found.group(4),
171                                                                                                 found.group(5),
172                                                                                                 found.group(6)
173                                                                                                 )
174                 if firstname:
175                         name += ' ' + firstname
176                 if street or streetno or zipcode or city:
177                         name += ', '
178                 if street:
179                         name += street
180                 if streetno:
181                         name += ' ' + streetno
182                 if (street or streetno) and (zipcode or city):
183                         name += ', '
184                 if zipcode and city:
185                         name += zipcode + ' ' + city
186                 elif zipcode:
187                         name += zipcode
188                 elif city:
189                         name += city
190         return name
191
192 from xml.dom.minidom import parse
193 cbcInfos = {}
194 def initCbC():
195         callbycallFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/NcidClient/callbycall_world.xml")
196         if os.path.exists(callbycallFileName):
197                 dom = parse(callbycallFileName)
198                 for top in dom.getElementsByTagName("callbycalls"):
199                         for cbc in top.getElementsByTagName("country"):
200                                 code = cbc.getAttribute("code").replace("+", "00")
201                                 cbcInfos[code] = cbc.getElementsByTagName("callbycall")
202         else:
203                 debug("[NcidClient] initCbC: callbycallFileName does not exist?!?!")
204
205 def stripCbCPrefix(number, countrycode):
206         if number and number[:2] != "00" and cbcInfos.has_key(countrycode):
207                 for cbc in cbcInfos[countrycode]:
208                         if len(cbc.getElementsByTagName("length")) < 1 or len(cbc.getElementsByTagName("prefix")) < 1:
209                                 debug("[NcidClient] stripCbCPrefix: entries for " + countrycode + " %s invalid")
210                                 return number
211                         length = int(cbc.getElementsByTagName("length")[0].childNodes[0].data)
212                         prefix = cbc.getElementsByTagName("prefix")[0].childNodes[0].data
213                         # if re.match('^'+prefix, number):
214                         if number[:len(prefix)] == prefix:
215                                 return number[length:]
216         return number
217
218
219 FBF_boxInfo = 0
220 FBF_upTime = 1
221 FBF_ipAddress = 2
222 FBF_wlanState = 3
223 FBF_dslState = 4
224 FBF_tamActive = 5
225 FBF_dectActive = 6
226 FBF_faxActive = 7
227 FBF_rufumlActive = 8
228
229 class NcidCall:
230         def __init__(self):
231                 debug("[NcidCall] __init__")
232                 self._callScreen = None
233                 self._callTimestamp = 0
234                 self._callList = []
235
236         def _notify(self, text):
237                 debug("[NcidCall] notify: " + text)
238                 self._md5LoginTimestamp = None
239                 if self._callScreen:
240                         debug("[NcidCall] notify: try to close callScreen")
241                         self._callScreen.close()
242                         self._callScreen = None
243                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_ERROR, timeout=config.plugins.NcidClient.timeout.value)
244
245 class NcidClientPhonebook:
246         def __init__(self):
247                 debug("[NcidClientPhonebook] init")
248                 # Beware: strings in phonebook.phonebook have to be in utf-8!
249                 self.phonebook = {}
250                 self.reload()
251
252         def reload(self):
253                 debug("[NcidClientPhonebook] reload")
254                 # Beware: strings in phonebook.phonebook have to be in utf-8!
255                 self.phonebook = {}
256
257                 if not config.plugins.NcidClient.enable.value:
258                         return
259
260                 phonebookFilename = os.path.join(config.plugins.NcidClient.phonebookLocation.value, "PhoneBook.txt")
261                 if config.plugins.NcidClient.phonebook.value and os.path.exists(phonebookFilename):
262                         debug("[NcidClientPhonebook] reload: read " + phonebookFilename)
263                         phonebookTxtCorrupt = False
264                         self.phonebook = {}
265                         for line in open(phonebookFilename):
266                                 try:
267                                         # Beware: strings in phonebook.phonebook have to be in utf-8!
268                                         line = line.decode("utf-8")
269                                 except UnicodeDecodeError: # this is just for the case, somebody wrote latin1 chars into PhoneBook.txt
270                                         try:
271                                                 line = line.decode("iso-8859-1")
272                                                 debug("[NcidClientPhonebook] Fallback to ISO-8859-1 in %s" % line)
273                                                 phonebookTxtCorrupt = True
274                                         except UnicodeDecodeError:
275                                                 debug("[NcidClientPhonebook] Could not parse internal Phonebook Entry %s" % line)
276                                                 phonebookTxtCorrupt = True
277                                 line = line.encode("utf-8")
278                                 elems = line.split('#')
279                                 if len(elems) == 2:
280                                         try:
281                                                 self.phonebook[elems[0]] = elems[1]
282                                         except ValueError: # how could this possibly happen?!?!
283                                                 debug("[NcidClientPhonebook] Could not parse internal Phonebook Entry %s" % line)
284                                                 phonebookTxtCorrupt = True
285                                 else:
286                                         debug("[NcidClientPhonebook] Could not parse internal Phonebook Entry %s" % line)
287                                         phonebookTxtCorrupt = True
288
289                         if phonebookTxtCorrupt:
290                                 # dump phonebook to PhoneBook.txt
291                                 debug("[NcidClientPhonebook] dump Phonebook.txt")
292                                 try:
293                                         os.rename(phonebookFilename, phonebookFilename + ".bck")
294                                         fNew = open(phonebookFilename, 'w')
295                                         # Beware: strings in phonebook.phonebook are utf-8!
296                                         for (number, name) in self.phonebook.iteritems():
297                                                 # Beware: strings in PhoneBook.txt have to be in utf-8!
298                                                 fNew.write(number + "#" + name.encode("utf-8"))
299                                         fNew.close()
300                                 except (IOError, OSError):
301                                         debug("[NcidClientPhonebook] error renaming or writing to %s" % phonebookFilename)
302
303         def search(self, number):
304                 # debug("[NcidClientPhonebook] Searching for %s" %number)
305                 name = ""
306                 if not self.phonebook or not number:
307                         return
308
309                 if config.plugins.NcidClient.prefix.value:
310                         prefix = config.plugins.NcidClient.prefix.value
311                         if number[0] != '0':
312                                 number = prefix + number
313                                 # debug("[NcidClientPhonebook] search: added prefix: %s" %number)
314                         elif number[:len(prefix)] == prefix and self.phonebook.has_key(number[len(prefix):]):
315                                 # debug("[NcidClientPhonebook] search: same prefix")
316                                 name = self.phonebook[number[len(prefix):]]
317                                 # debug("[NcidClientPhonebook] search: result: %s" %name)
318                 else:
319                         prefix = ""
320
321                 if not name and self.phonebook.has_key(number):
322                         name = self.phonebook[number]
323
324                 return name.replace(", ", "\n").strip()
325
326         def add(self, number, name):
327                 '''
328
329                 @param number: number of entry
330                 @param name: name of entry, has to be in utf-8
331                 '''
332                 debug("[NcidClientPhonebook] add")
333                 name = name.replace("\n", ", ").replace('#', '') # this is just for safety reasons. add should only be called with newlines converted into commas
334                 self.remove(number)
335                 self.phonebook[number] = name
336                 if number and number != 0:
337                         if config.plugins.NcidClient.phonebook.value:
338                                 try:
339                                         name = name.strip() + "\n"
340                                         string = "%s#%s" % (number, name)
341                                         # Beware: strings in PhoneBook.txt have to be in utf-8!
342                                         f = open(os.path.join(config.plugins.NcidClient.phonebookLocation.value, "PhoneBook.txt"), 'a')
343                                         f.write(string)
344                                         f.close()
345                                         debug("[NcidClientPhonebook] added %s with %s to Phonebook.txt" % (number, name.strip()))
346                                         return True
347
348                                 except IOError:
349                                         return False
350
351         def remove(self, number):
352                 if number in self.phonebook:
353                         debug("[NcidClientPhonebook] remove entry in phonebook")
354                         del self.phonebook[number]
355                         if config.plugins.NcidClient.phonebook.value:
356                                 try:
357                                         phonebookFilename = os.path.join(config.plugins.NcidClient.phonebookLocation.value, "PhoneBook.txt")
358                                         debug("[NcidClientPhonebook] remove entry in Phonebook.txt")
359                                         fOld = open(phonebookFilename, 'r')
360                                         fNew = open(phonebookFilename + str(os.getpid()), 'w')
361                                         line = fOld.readline()
362                                         while (line):
363                                                 elems = line.split('#')
364                                                 if len(elems) == 2 and not elems[0] == number:
365                                                         fNew.write(line)
366                                                 line = fOld.readline()
367                                         fOld.close()
368                                         fNew.close()
369                                         # os.remove(phonebookFilename)
370                                         eBackgroundFileEraser.getInstance().erase(phonebookFilename)
371                                         os.rename(phonebookFilename + str(os.getpid()),         phonebookFilename)
372                                         debug("[NcidClientPhonebook] removed %s from Phonebook.txt" % number)
373                                         return True
374
375                                 except (IOError, OSError):
376                                         debug("[NcidClientPhonebook] error removing %s from %s" % (number, phonebookFilename))
377                 return False
378
379         class NcidDisplayPhonebook(Screen, NumericalTextInput):
380
381                 def __init__(self, session):
382                         self.entriesWidth = DESKTOP_WIDTH * scaleH(75, 85) / 100
383                         self.height = DESKTOP_HEIGHT * 0.75
384                         numberFieldWidth = scaleH(220, 160)
385                         fieldWidth = self.entriesWidth - 5 - numberFieldWidth - 10
386                         fontSize = scaleV(22, 18)
387                         fontHeight = scaleV(24, 20)
388                         buttonGap = (self.entriesWidth - 4 * 140) / 5
389                         debug("[NcidDisplayPhonebook] width: " + str(self.entriesWidth))
390                         self.skin = """
391                                 <screen name="NcidDisplayPhonebook" position="center,center" size="%d,%d" title="Phonebook" >
392                                         <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
393                                         <widget source="entries" render="Listbox" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" transparent="1">
394                                                 <convert type="TemplatedMultiContent">
395                                                         {"template": [
396                                                                         MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 1), # index 0 is the name, index 1 is shortname
397                                                                         MultiContentEntryText(pos = (%d,%d), size = (%d,%d), font=0, flags = RT_HALIGN_LEFT, text = 2), # index 2 is number
398                                                                 ],
399                                                         "fonts": [gFont("Regular", %d)],
400                                                         "itemHeight": %d
401                                                         }
402                                                 </convert>
403                                         </widget>
404                                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
405                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
406                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
407                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
408                                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
409                                         <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
410                                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
411                                         <widget name="key_yellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
412                                         <widget name="key_blue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
413                                 </screen>""" % (
414                                                 # scaleH(90, 75), scaleV(100, 73), # position
415                                                 self.entriesWidth, self.height, # size
416                                                 self.entriesWidth, # eLabel width
417                                                 scaleH(40, 5), scaleV(20, 5), # entries position
418                                                 self.entriesWidth - scaleH(40, 5), self.height - scaleV(20, 5) - 5 - 5 - 40, # entries size
419                                                 0, 0, fieldWidth, scaleH(24, 20), # name pos/size
420                                                 fieldWidth + 5, 0, numberFieldWidth, scaleH(24, 20), # dir pos/size
421                                                 fontSize, # fontsize
422                                                 fontHeight, # itemHeight
423                                                 self.height - 40 - 5, # eLabel position vertical
424                                                 self.entriesWidth, # eLabel width
425                                                 buttonGap, self.height - 40, "skin_default/buttons/red.png", # ePixmap red
426                                                 2 * buttonGap + 140, self.height - 40, "skin_default/buttons/green.png", # ePixmap green
427                                                 3 * buttonGap + 2 * 140, self.height - 40, "skin_default/buttons/yellow.png", # ePixmap yellow
428                                                 4 * buttonGap + 3 * 140, self.height - 40, "skin_default/buttons/blue.png", # ePixmap blue
429                                                 buttonGap, self.height - 40, scaleV(22, 21), # widget red
430                                                 2 * buttonGap + 140, self.height - 40, scaleV(22, 21), # widget green
431                                                 3 * buttonGap + 2 * 140, self.height - 40, scaleV(22, 21), # widget yellow
432                                                 4 * buttonGap + 3 * 140, self.height - 40, scaleV(22, 21), # widget blue
433                                                 )
434
435                         # debug("[NcidDisplayCalls] skin: " + self.skin)
436                         Screen.__init__(self, session)
437                         NumericalTextInput.__init__(self)
438                         HelpableScreen.__init__(self)
439
440                         # TRANSLATORS: keep it short, this is a button
441                         self["key_red"] = Button(_("Delete"))
442                         # TRANSLATORS: keep it short, this is a button
443                         self["key_green"] = Button(_("New"))
444                         # TRANSLATORS: keep it short, this is a button
445                         self["key_yellow"] = Button(_("Edit"))
446                         # TRANSLATORS: keep it short, this is a button
447                         self["key_blue"] = Button(_("Search"))
448
449                         self["setupActions"] = ActionMap(["OkCancelActions", "ColorActions"],
450                         {
451                                 "red": self.delete,
452                                 "green": self.add,
453                                 "yellow": self.edit,
454                                 "blue": self.search,
455                                 "cancel": self.exit,
456                                 "ok": self.showEntry, }, -2)
457
458                         self["entries"] = List([])
459                         debug("[NcidClientPhonebook] displayPhonebook init")
460                         self.help_window = None
461                         self.sortlist = []
462                         self.onLayoutFinish.append(self.setWindowTitle)
463                         self.display()
464
465                 def setWindowTitle(self):
466                         # TRANSLATORS: this is a window title.
467                         self.setTitle(_("Phonebook"))
468
469                 def display(self, filterNumber=""):
470                         debug("[NcidClientPhonebook] displayPhonebook/display")
471                         self.sortlist = []
472                         # Beware: strings in phonebook.phonebook are utf-8!
473                         sortlistHelp = sorted((name.lower(), name, number) for (number, name) in phonebook.phonebook.iteritems())
474                         for (low, name, number) in sortlistHelp:
475                                 if number == "01234567890":
476                                         continue
477                                 try:
478                                         low = low.decode("utf-8")
479                                 except UnicodeDecodeError:  # this should definitely not happen
480                                         try:
481                                                 low = low.decode("iso-8859-1")
482                                         except UnicodeDecodeError:
483                                                 debug("[NcidClientPhonebook] displayPhonebook/display: corrupt phonebook entry for %s" % number)
484                                                 # self.session.open(MessageBox, _("Corrupt phonebook entry\nfor number %s\nDeleting.") %number, type = MessageBox.TYPE_ERROR)
485                                                 phonebook.remove(number)
486                                                 continue
487                                 else:
488                                         if filterNumber:
489                                                 filterNumber = filterNumber.lower()
490                                                 if low.find(filterNumber) == -1:
491                                                         continue
492                                         name = name.strip().decode("utf-8")
493                                         number = number.strip().decode("utf-8")
494                                         comma = name.find(',')
495                                         if comma != -1:
496                                                 shortname = name[:comma]
497                                         else:
498                                                 shortname = name
499                                         number = number.encode("utf-8", "replace")
500                                         name = name.encode("utf-8", "replace")
501                                         shortname = shortname.encode('utf-8', 'replace')
502                                         self.sortlist.append((name, shortname, number))
503
504                         self["entries"].setList(self.sortlist)
505
506                 def showEntry(self):
507                         cur = self["entries"].getCurrent()
508                         if cur:
509                                 debug("[NcidClientPhonebook] displayPhonebook/showEntry %s" % (repr(cur)))
510                                 number = cur[2]
511                                 name = cur[0]
512                                 self.session.open(NcidOfferAction, self, number, name)
513
514                 def delete(self):
515                         cur = self["entries"].getCurrent()
516                         if cur:
517                                 debug("[NcidClientPhonebook] displayPhonebook/delete %s" % (repr(cur)))
518                                 self.session.openWithCallback(
519                                         self.deleteConfirmed,
520                                         MessageBox,
521                                         _("Do you really want to delete entry for\n\n%(number)s\n\n%(name)s?")
522                                         % { 'number':str(cur[2]), 'name':str(cur[0]).replace(", ", "\n") }
523                                                                 )
524                         else:
525                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
526
527                 def deleteConfirmed(self, ret):
528                         debug("[NcidClientPhonebook] displayPhonebook/deleteConfirmed")
529                         #
530                         # if ret: delete number from sortlist, delete number from phonebook.phonebook and write it to disk
531                         #
532                         cur = self["entries"].getCurrent()
533                         if cur:
534                                 if ret:
535                                         # delete number from sortlist, delete number from phonebook.phonebook and write it to disk
536                                         debug("[NcidClientPhonebook] displayPhonebook/deleteConfirmed %s" % (repr(cur)))
537                                         phonebook.remove(cur[2])
538                                         self.display()
539                                 # else:
540                                         # self.session.open(MessageBox, _("Not deleted."), MessageBox.TYPE_INFO)
541                         else:
542                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
543
544                 def add(self, parent=None, number="", name=""):
545                         class AddScreen(Screen, ConfigListScreen):
546                                 '''ConfiglistScreen with two ConfigTexts for Name and Number'''
547
548                                 def __init__(self, session, parent, number="", name=""):
549                                         #
550                                         # setup screen with two ConfigText and OK and ABORT button
551                                         #
552                                         noButtons = 2
553                                         width = max(scaleH(-1, 570), noButtons * 140)
554                                         height = scaleV(-1, 100) # = 5 + 126 + 40 + 5; 6 lines of text possible
555                                         buttonsGap = (width - noButtons * 140) / (noButtons + 1)
556                                         buttonsVPos = height - 40 - 5
557                                         self.skin = """
558                                                 <screen position="center,center" size="%d,%d" title="Add entry to phonebook" >
559                                                 <widget name="config" position="5,5" size="%d,%d" scrollbarMode="showOnDemand" />
560                                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
561                                                 <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
562                                                 <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
563                                                 <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
564                                                 </screen>""" % (
565                                                                                 width, height,
566                                                                                 width - 5 - 5, height - 5 - 40 - 5,
567                                                                                 buttonsGap, buttonsVPos, "skin_default/buttons/red.png",
568                                                                                 buttonsGap + 140 + buttonsGap, buttonsVPos, "skin_default/buttons/green.png",
569                                                                                 buttonsGap, buttonsVPos,
570                                                                                 buttonsGap + 140 + buttonsGap, buttonsVPos,
571                                                                                 )
572                                         Screen.__init__(self, session)
573                                         self.session = session
574                                         self.parent = parent
575                                         # TRANSLATORS: keep it short, this is a button
576                                         self["key_red"] = Button(_("Cancel"))
577                                         # TRANSLATORS: keep it short, this is a button
578                                         self["key_green"] = Button(_("OK"))
579                                         self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
580                                         {
581                                                 "cancel": self.cancel,
582                                                 "red": self.cancel,
583                                                 "green": self.add,
584                                                 "ok": self.add,
585                                         }, -2)
586
587                                         self.list = [ ]
588                                         ConfigListScreen.__init__(self, self.list, session=session)
589                                         self.name = name
590                                         self.number = number
591                                         config.plugins.NcidClient.name.value = name
592                                         config.plugins.NcidClient.number.value = number
593                                         self.list.append(getConfigListEntry(_("Name"), config.plugins.NcidClient.name))
594                                         self.list.append(getConfigListEntry(_("Number"), config.plugins.NcidClient.number))
595                                         self["config"].list = self.list
596                                         self["config"].l.setList(self.list)
597                                         self.onLayoutFinish.append(self.setWindowTitle)
598
599                                 def setWindowTitle(self):
600                                         # TRANSLATORS: this is a window title.
601                                         self.setTitle(_("Add entry to phonebook"))
602
603                                 def add(self):
604                                         # get texts from Screen
605                                         # add (number,name) to sortlist and phonebook.phonebook and disk
606                                         self.name = config.plugins.NcidClient.name.value
607                                         self.number = config.plugins.NcidClient.number.value
608                                         if not self.number or not self.name:
609                                                 self.session.open(MessageBox, _("Entry incomplete."), type=MessageBox.TYPE_ERROR)
610                                                 return
611
612                                         phonebook.add(self.number, self.name)
613                                         self.close()
614                                         self.parent.display()
615
616                                 def overwriteConfirmed(self, ret):
617                                         if ret:
618                                                 phonebook.remove(self.number)
619                                                 phonebook.add(self.number, self.name)
620                                                 self.parent.display()
621
622                                 def cancel(self):
623                                         self.close()
624
625                         debug("[NcidClientPhonebook] displayPhonebook/add")
626                         if not parent:
627                                 parent = self
628                         self.session.open(AddScreen, parent, number, name)
629
630                 def edit(self):
631                         debug("[NcidClientPhonebook] displayPhonebook/edit")
632                         cur = self["entries"].getCurrent()
633                         if cur is None:
634                                 self.session.open(MessageBox, _("No entry selected"), MessageBox.TYPE_INFO)
635                         else:
636                                 self.add(self, cur[2], cur[0])
637
638                 def search(self):
639                         debug("[NcidClientPhonebook] displayPhonebook/search")
640                         self.help_window = self.session.instantiateDialog(NumericalTextInputHelpDialog, self)
641                         self.help_window.show()
642                         # VirtualKeyboard instead of InputBox?
643                         self.session.openWithCallback(self.doSearch, InputBox, _("Enter Search Terms"), _("Search phonebook"))
644
645                 def doSearch(self, searchTerms):
646                         if not searchTerms:
647                                 searchTerms = ""
648                         debug("[NcidClientPhonebook] displayPhonebook/doSearch: " + searchTerms)
649                         if self.help_window:
650                                 self.session.deleteDialog(self.help_window)
651                                 self.help_window = None
652                         self.display(searchTerms)
653
654                 def exit(self):
655                         self.close()
656
657 phonebook = NcidClientPhonebook()
658
659 class NcidClientSetup(Screen, ConfigListScreen):
660
661         def __init__(self, session, args=None): #@UnusedVariable # pylint: disable=W0613
662                 self.width = scaleH(20 + 4 * (140 + 90) + 2 * (35 + 40) + 20, 4 * 140 + 2 * 35)
663                 width = self.width
664                 debug("[NcidClientSetup] width: " + str(self.width))
665                 self.skin = """
666                         <screen name="NcidClientSetup" position="center,center" size="%d,%d" title="NcidClient Setup" >
667                         <eLabel position="0,0" size="%d,2" backgroundColor="#aaaaaa" />
668                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
669                         <widget name="config" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" backgroundColor="#20040404" transparent="1" />
670                         <eLabel position="0,%d" size="%d,2" backgroundColor="#aaaaaa" />
671                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
672                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="%s" transparent="1" alphatest="on" />
673                         <widget name="key_red" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
674                         <widget name="key_green" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
675                         </screen>""" % (
676                                                 # (DESKTOP_WIDTH-width)/2, scaleV(100, 73), # position
677                                                 width, scaleV(560, 430), # size
678                                                 width, # eLabel width
679                                                 scaleV(40, 50), # eLabel position vertical
680                                                 width, # eLabel width
681                                                 scaleH(40, 5), scaleV(60, 57), # config position
682                                                 scaleH(width - 80, width - 10), scaleV(453, 328), # config size
683                                                 scaleV(518, 390), # eLabel position vertical
684                                                 width, # eLabel width
685                                                 scaleH(20, 0), scaleV(525, 395), "skin_default/buttons/red.png", # pixmap red
686                                                 scaleH(20 + 140 + 90, 140), scaleV(525, 395), "skin_default/buttons/green.png", # pixmap green
687                                                 scaleH(20, 0), scaleV(525, 395), scaleV(21, 21), # widget red
688                                                 scaleH(20 + (140 + 90), 140), scaleV(525, 395), scaleV(21, 21), # widget green
689                                                                                                         )
690
691                 Screen.__init__(self, session)
692                 self.session = session
693
694                 self.list = []
695
696                 # Initialize Buttons
697                 # TRANSLATORS: keep it short, this is a button
698                 self["key_red"] = Button(_("Cancel"))
699                 # TRANSLATORS: keep it short, this is a button
700                 self["key_green"] = Button(_("OK"))
701
702                 self["setupActions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions", "EPGSelectActions"],
703                 {
704                         "red": self.cancel,
705                         "green": self.save,
706                         "cancel": self.cancel,
707                         "ok": self.save,
708                 }, -2)
709
710                 ConfigListScreen.__init__(self, self.list, session=session)
711
712                 # get new list of locations for PhoneBook.txt
713                 self._mountedDevices = getMountedDevices()
714                 self.createSetup()
715                 self.onLayoutFinish.append(self.setWindowTitle)
716
717         def setWindowTitle(self):
718                 # TRANSLATORS: this is a window title.
719                 self.setTitle(_("NCID Client - Setup"))
720
721         def keyLeft(self):
722                 ConfigListScreen.keyLeft(self)
723                 self.createSetup()
724
725         def keyRight(self):
726                 ConfigListScreen.keyRight(self)
727                 self.createSetup()
728
729         def createSetup(self):
730                 self.list = [ ]
731                 self.list.append(getConfigListEntry(_("Call monitoring"), config.plugins.NcidClient.enable))
732                 if config.plugins.NcidClient.enable.value:
733                         self.list.append(getConfigListEntry(_("NCID server (Name or IP)"), config.plugins.NcidClient.hostname))
734                         self.list.append(getConfigListEntry(_("NCID server listening port (1-65535)"), config.plugins.NcidClient.port))
735
736                         self.list.append(getConfigListEntry(_("Show after Standby"), config.plugins.NcidClient.afterStandby))
737
738                         # not only for outgoing: config.plugins.NcidClient.showOutgoing.value:
739                         self.list.append(getConfigListEntry(_("Areacode to add to calls without one (if necessary)"), config.plugins.NcidClient.prefix))
740                         self.list.append(getConfigListEntry(_("Timeout for Call Notifications (seconds)"), config.plugins.NcidClient.timeout))
741                         self.list.append(getConfigListEntry(_("Reverse Lookup Caller ID (select country below)"), config.plugins.NcidClient.lookup))
742                         if config.plugins.NcidClient.lookup.value:
743                                 self.list.append(getConfigListEntry(_("Country"), config.plugins.NcidClient.country))
744
745                         self.list.append(getConfigListEntry(_("Use internal PhoneBook"), config.plugins.NcidClient.phonebook))
746                         if config.plugins.NcidClient.phonebook.value:
747                                 if config.plugins.NcidClient.phonebookLocation.value in self._mountedDevices:
748                                         config.plugins.NcidClient.phonebookLocation.setChoices(self._mountedDevices, config.plugins.NcidClient.phonebookLocation.value)
749                                 else:
750                                         config.plugins.NcidClient.phonebookLocation.setChoices(self._mountedDevices)
751                                 path = config.plugins.NcidClient.phonebookLocation.value
752                                 # check whether we can write to PhoneBook.txt
753                                 if os.path.exists(os.path.join(path[0], "PhoneBook.txt")):
754                                         if not os.access(os.path.join(path[0], "PhoneBook.txt"), os.W_OK):
755                                                 debug("[NcidClientSetup] createSetup: %s/PhoneBook.txt not writable, resetting to default" % (path[0]))
756                                                 config.plugins.NcidClient.phonebookLocation.setChoices(self._mountedDevices)
757                                 elif not (os.path.isdir(path[0]) and os.access(path[0], os.W_OK | os.X_OK)):
758                                         debug("[NcidClientSetup] createSetup: directory %s not writable, resetting to default" % (path[0]))
759                                         config.plugins.NcidClient.phonebookLocation.setChoices(self._mountedDevices)
760
761                                 self.list.append(getConfigListEntry(_("PhoneBook Location"), config.plugins.NcidClient.phonebookLocation))
762                                 if config.plugins.NcidClient.lookup.value:
763                                         self.list.append(getConfigListEntry(_("Automatically add new Caller to PhoneBook"), config.plugins.NcidClient.addcallers))
764
765                         self.list.append(getConfigListEntry(_("Strip Leading 0"), config.plugins.NcidClient.internal))
766                         self.list.append(getConfigListEntry(_("Show connection information popups"), config.plugins.NcidClient.connectionVerbose))
767
768                 self["config"].list = self.list
769                 self["config"].l.setList(self.list)
770
771         def save(self):
772 #               debug("[NcidClientSetup] save"
773                 for x in self["config"].list:
774                         x[1].save()
775                 if config.plugins.NcidClient.phonebookLocation.isChanged():
776                         global phonebook
777                         phonebook = NcidClientPhonebook()
778                 if ncid_call:
779                         if config.plugins.NcidClient.enable.value:
780                                 ncid_call.connect()
781                         else:
782                                 ncid_call.shutdown()
783                 self.close()
784
785         def cancel(self):
786 #               debug("[NcidClientSetup] cancel"
787                 for x in self["config"].list:
788                         x[1].cancel()
789                 self.close()
790
791         def displayPhonebook(self):
792                 if phonebook:
793                         if config.plugins.NcidClient.enable.value:
794                                 self.session.open(phonebook.NcidDisplayPhonebook)
795                         else:
796                                 self.session.open(MessageBox, _("Plugin not active"), type=MessageBox.TYPE_INFO)
797                 else:
798                         self.session.open(MessageBox, _("No phonebook"), type=MessageBox.TYPE_INFO)
799
800
801 standbyMode = False
802
803 class NcidCallList:
804         def __init__(self):
805                 self.callList = [ ]
806
807         def add(self, date, number, caller):
808                 debug("[NcidCallList] add: %s %s" % (number, caller))
809                 if len(self.callList) > 10:
810                         if self.callList[0] != "Start":
811                                 self.callList[0] = "Start"
812                         del self.callList[1]
813
814                 self.callList.append((number, date, caller))
815
816         def display(self):
817                 debug("[NcidCallList] display")
818                 global standbyMode
819                 standbyMode = False
820                 # Standby.inStandby.onClose.remove(self.display) object does not exist anymore...
821                 # build screen from call list
822                 text = "\n"
823
824                 if not self.callList:
825                         text = _("no calls")
826                 else:
827                         if self.callList[0] == "Start":
828                                 text = text + _("Last 10 calls:\n")
829                                 del self.callList[0]
830
831                         for call in self.callList:
832                                 (number, date, caller) = call
833
834                                 # should not happen, for safety reasons
835                                 if not caller:
836                                         caller = _("UNKNOWN")
837
838                                 #  if we have an unknown number, show the number
839                                 if caller == _("UNKNOWN") and number != "":
840                                         caller = number
841                                 else:
842                                         # strip off the address part of the remote caller/callee, if there is any
843                                         nl = caller.find('\n')
844                                         if nl != -1:
845                                                 caller = caller[:nl]
846                                         elif caller[0] == '[' and caller[-1] == ']':
847                                                 # that means, we've got an unknown number with a city added from avon.dat
848                                                 if (len(number) + 1 + len(caller)) <= 40:
849                                                         caller = number + ' ' + caller
850                                                 else:
851                                                         caller = number
852
853                                 while (len(caller)) > 40:
854                                         caller = caller[:-1]
855
856                                 text = text + "%s - %s\n" % (date, caller)
857                                 debug("[NcidCallList] display: '%s - %s'" % (date, caller))
858
859                 # display screen
860                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO)
861                 # TODO please HELP: from where can I get a session?
862                 # my_global_session.open(NcidDisplayCalls, text)
863                 self.callList = [ ]
864
865 callList = NcidCallList()
866
867 global_muted = None
868 def notifyCall(date, number, caller):
869         if Standby.inStandby is None or config.plugins.NcidClient.afterStandby.value == "each":
870                 global global_muted
871                 if config.plugins.NcidClient.muteOnCall.value and not global_muted:
872                         # eDVBVolumecontrol.getInstance().volumeMute() # with this, we get no mute icon...
873                         if not eDVBVolumecontrol.getInstance().isMuted():
874                                 globalActionMap.actions["volumeMute"]()
875                 text = _("Incoming Call on %s from\n---------------------------------------------\n%s\n%s\n---------------------------------------------") % (date, number, caller)
876                 debug("[NcidClient] notifyCall:\n%s" % text)
877                 Notifications.AddNotification(MessageBox, text, type=MessageBox.TYPE_INFO, timeout=config.plugins.NcidClient.timeout.value)
878                 #Notifications.AddNotification(MessageBoxPixmap, text, number=number, name=caller, timeout=config.plugins.NcidClient.timeout.value)
879         elif config.plugins.NcidClient.afterStandby.value == "inList":
880                 #
881                 # if not yet done, register function to show call list
882                 global standbyMode
883                 if not standbyMode :
884                         standbyMode = True
885                         Standby.inStandby.onHide.append(callList.display) #@UndefinedVariable
886                 # add text/timeout to call list
887                 callList.add(date, number, caller)
888                 debug("[NcidClient] notifyCall: added to callList")
889         else: # this is the "None" case
890                 debug("[NcidClient] notifyCall: standby and no show")
891
892
893 #===============================================================================
894 #               We need a separate class for each invocation of reverseLookup to retain
895 #               the necessary data for the notification
896 #===============================================================================
897
898 countries = { }
899 reverselookupMtime = 0
900
901 class NcidReverseLookupAndNotify:
902         def __init__(self, number, caller, date):
903                 '''
904
905                 Initiate a reverse lookup for the given number in the configured country
906                 @param number: number to be looked up
907                 @param caller: caller including name and address
908                 @param date: date of call
909                 '''
910                 debug("[NcidReverseLookupAndNotify] reverse Lookup for %s!" % number)
911                 self.number = number
912                 self.caller = caller
913                 self.date = date
914
915                 if number[0] != "0":
916                         self.notifyAndReset(number, caller)
917                         return
918
919                 ReverseLookupAndNotify(number, self.notifyAndReset, "UTF-8", config.plugins.NcidClient.country.value)
920
921         def notifyAndReset(self, number, caller):
922                 '''
923
924                 this gets called with the result of the reverse lookup
925
926                 @param number: number
927                 @param caller: name and address of remote. it comes in with name, address and city separated by commas
928                 '''
929                 debug("[NcidReverseLookupAndNotify] got: %s" % caller)
930                 self.number = number
931                 name = handleReverseLookupResult(caller)
932                 if name:
933                         self.caller = name.replace(", ", "\n").replace('#', '')
934
935                         if self.number != 0 and config.plugins.NcidClient.addcallers.value:
936                                 debug("[NcidReverseLookupAndNotify] add to phonebook")
937                                 phonebook.add(self.number, self.caller)
938                 else:
939                         name = resolveNumberWithAvon(self.number, config.plugins.NcidClient.country.value)
940                         if not name:
941                                 self.caller = _("UNKNOWN")
942                         else:
943                                 self.caller = name
944                 notifyCall(self.date, self.number, self.caller)
945
946 class NcidLineReceiver(LineReceiver):
947         def __init__(self):
948                 global global_muted
949                 global_muted = None
950                 self.resetValues()
951
952         def resetValues(self):
953                 self.number = None
954                 self.caller = None
955                 self.date = '01011970'
956                 self.time = '0001'
957                 self.line = ''
958
959         def notifyAndReset(self):
960                 notifyCall(self.date, self.number, self.caller)
961                 self.resetValues()
962
963         def lineReceived(self, line):
964                 debug("[NcidLineReceiver] lineReceived: %s" % line)
965 #200 NCID Server:  ARC_ncidd 0.01
966 #CIDLOG: *DATE*21102010*TIME*1454*LINE**NMBR*089999999999*MESG*NONE*NAME*NO NAME*
967 #CIDLOG: *DATE*21102010*TIME*1456*LINE**NMBR*089999999999*MESG*NONE*NAME*NO NAME*
968 #CID: *DATE*22102010*TIME*1502*LINE**NMBR*089999999999*MESG*NONE*NAME*NO NAME*
969
970 #Callog entries begin with CIDLOG, "current" events begin with CID
971 #we don't want to do anything with log-entries
972                 if line.startswith("CID:"):
973                         line = line[6:]
974                         debug("[NcidLineReceiver.lineReceived] filtered Line: %s" % line)
975                 else:
976                         return
977
978                 items = line.split('*')
979
980                 for i in range(0, len(items)):
981                         item = items[i]
982
983                         if item == 'DATE':
984                                 self.date = items[i + 1]
985                         elif item == 'TIME':
986                                 self.time = items[i + 1]
987                         elif item == 'LINE':
988                                 self.line = items[i + 1]
989                         elif item == 'NMBR':
990                                 self.number = items[i + 1]
991                         elif item == 'NAME':
992                                 self.myName = items[i + 1]
993
994                 if not self.myName:
995                         self.myName = _("UNKNOWN")
996
997                 date = None
998                 try:
999                         date = datetime.strptime("%s - %s" % (self.date, self.time), "%d%m%Y - %H%M")
1000                 except:
1001                         date = datetime.strptime("%s - %s" % (self.date, self.time), "%m%d%Y - %H%M")
1002
1003                 self.date = date.strftime("%d.%m.%Y - %H:%M")
1004
1005                 if not self.number:
1006                         debug("[NcidLineReceiver] lineReceived: no number")
1007                         self.number = _("number suppressed")
1008                         self.caller = self.myName
1009                 else:
1010                         if config.plugins.NcidClient.internal.value and len(self.number) > 3 and self.number[0] == "0":
1011                                 debug("[NcidLineReceiver] lineReceived: strip leading 0")
1012                                 self.number = self.number[1:]
1013                         else:
1014                                 if self.number[0] != '0':
1015                                         debug("[NcidLineReceiver] lineReceived: add local prefix")
1016                                         self.number = config.plugins.NcidClient.prefix.value + self.number
1017
1018                         self.number = stripCbCPrefix(self.number, config.plugins.NcidClient.country.value)
1019
1020                         debug("[NcidLineReceiver] lineReceived phonebook.search: %s" % self.number)
1021                         self.caller = phonebook.search(self.number)
1022                         debug("[NcidLineReceiver] lineReceived phonebook.search reault: %s" % self.caller)
1023                         if not self.caller:
1024                                 if config.plugins.NcidClient.lookup.value:
1025                                         NcidReverseLookupAndNotify(self.number, self.caller, self.date)
1026                                         return                                                  # reverselookup is supposed to handle the message itself
1027                                 else:
1028                                         self.caller = self.myName
1029
1030                 self.notifyAndReset()
1031
1032 class NcidClientFactory(ReconnectingClientFactory):
1033         initialDelay = 20
1034         maxDelay = 30
1035
1036         def __init__(self):
1037                 self.hangup_ok = False
1038         def startedConnecting(self, connector): #@UnusedVariable # pylint: disable=W0613
1039                 if config.plugins.NcidClient.connectionVerbose.value:
1040                         Notifications.AddNotification(MessageBox, _("Connecting to NCID Server..."), type=MessageBox.TYPE_INFO, timeout=2)
1041
1042         def buildProtocol(self, addr): #@UnusedVariable # pylint: disable=W0613
1043                 global ncidsrv, phonebook
1044                 if config.plugins.NcidClient.connectionVerbose.value:
1045                         Notifications.AddNotification(MessageBox, _("Connected to NCID Server"), type=MessageBox.TYPE_INFO, timeout=4)
1046                 self.resetDelay()
1047                 initAvon()
1048                 ncidsrv = NcidCall()
1049                 phonebook = NcidClientPhonebook()
1050                 return NcidLineReceiver()
1051
1052         def clientConnectionLost(self, connector, reason):
1053                 global ncidsrv
1054                 if not self.hangup_ok and config.plugins.NcidClient.connectionVerbose.value:
1055                         Notifications.AddNotification(MessageBox, _("Connection to NCID Server lost\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.NcidClient.timeout.value)
1056                 ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
1057                 # config.plugins.NcidClient.enable.value = False
1058                 ncidsrv = None
1059
1060         def clientConnectionFailed(self, connector, reason):
1061                 global ncidsrv
1062                 if config.plugins.NcidClient.connectionVerbose.value:
1063                         Notifications.AddNotification(MessageBox, _("Connecting to NCID Server failed\n (%s)\nretrying...") % reason.getErrorMessage(), type=MessageBox.TYPE_INFO, timeout=config.plugins.NcidClient.timeout.value)
1064                 ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
1065                 # config.plugins.NcidClient.enable.value = False
1066                 ncidsrv = None
1067
1068 class NcidClient:
1069         def __init__(self):
1070                 self.dialog = None
1071                 self.desc = None
1072                 if config.plugins.NcidClient.enable.value:
1073                         self.connect()
1074
1075         def connect(self):
1076                 self.abort()
1077                 if config.plugins.NcidClient.enable.value:
1078                         factory = NcidClientFactory()
1079                         self.desc = (factory, reactor.connectTCP(config.plugins.NcidClient.hostname.value, config.plugins.NcidClient.port.value, factory))
1080
1081         def shutdown(self):
1082                 self.abort()
1083
1084         def abort(self):
1085                 if self.desc is not None:
1086                         self.desc[0].hangup_ok = True
1087                         self.desc[0].stopTrying()
1088                         self.desc[1].disconnect()
1089                         self.desc = None
1090
1091 def main(session):
1092         session.open(NcidClientSetup)
1093
1094 ncid_call = None
1095
1096 def autostart(reason, **kwargs):
1097         global ncid_call
1098
1099         # ouch, this is a hack
1100         if kwargs.has_key("session"):
1101                 global my_global_session
1102                 my_global_session = kwargs["session"]
1103                 return
1104
1105         debug("[NcidClient] - Autostart")
1106         if reason == 0:
1107                 ncid_call = NcidClient()
1108         elif reason == 1:
1109                 ncid_call.shutdown()
1110                 ncid_call = None
1111
1112 def Plugins(**kwargs): #@UnusedVariable # pylint: disable=W0613,C0103
1113         what = _("Display Fon calls on screen")
1114         return [ PluginDescriptor(name="NCID Client", description=what, where=PluginDescriptor.WHERE_PLUGINMENU, icon="plugin.png", fnc=main),
1115                 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc=autostart) ]
1116