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