2 # -*- coding: ISO-8859-1 -*-
9 from xml.dom.minidom import parse
10 from twisted.web.client import getPage
11 from twisted.internet import reactor
22 def html2utf8(in_html):
27 return in_html.replace("&", "&").replace("ß", "ß
\9f").replace("ä", "ä").replace("ö", "ö").replace("ü", "ü").replace("Ä", "Ä").replace("Ö", "Ö").replace("Ü", "Ü")
28 except UnicodeDecodeError:
31 # first convert some WML codes; does not work?!?!
43 in_html = in_html.replace(a,b)
47 htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
49 entities = htmlentitynamemask.finditer(in_html)
51 entitydict[x.group(1)] = x.group(2)
52 for key, name in entitydict.items():
54 entitydict[key] = htmlentitydefs.name2codepoint[name]
56 myprint("[Callhtml2utf8] KeyError " + key + "/" + name)
59 htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
60 entities = htmlentitynumbermask.finditer(in_html)
62 entitydict[x.group(1)] = x.group(2)
63 for key, codepoint in entitydict.items():
65 in_html = in_html.replace(key, (unichr(int(codepoint)).encode('utf8', "replace")))
67 myprint("[Callhtml2utf8] ValueError " + key + "/" + str(codepoint))
71 def out(number, caller):
72 name = vorname = strasse = hnr = plz = ort = ""
73 lines = caller.split(', ')
74 found = re.match("(.+?)\s+(.+)", lines[0])
77 vorname = found.group(2)
81 found = re.match("^(.+) (\d+)$", lines[1], re.S)
83 strasse = found.group(1)
87 found = re.match("^(\d+) (.+)$", lines[1], re.S)
89 strasse = found.group(2)
94 for i in range(aktuell, len(lines)):
95 found = re.match("(\S+)\s+(.+)", lines[i], re.S)
101 ort = lines[aktuell].strip()
102 print "NA: %s;VN: %s;STR: %s;HNR: %s;PLZ: %s;ORT: %s" %( name,vorname,strasse,hnr,plz,ort )
104 def simpleout(number, caller):
108 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
109 reverseLookupFileName = resolveFilename(SCOPE_PLUGINS, "Extensions/FritzCall/reverselookup.xml")
111 reverseLookupFileName = "reverselookup.xml"
114 reverselookupMtime = 0
116 class ReverseLookupAndNotifier:
117 def __init__(self, number, outputFunction=out, charset="ISO-8859-1", countrycode = "0049"):
118 myprint("[ReverseLookupAndNotifier] reverse Lookup for %s!" %number)
120 self.outputFunction = outputFunction
121 self.charset = charset
123 self.currentWebsite = None
124 self.nextWebsiteNo = 0
126 global reverselookupMtime
127 reverselookupMtimeAct = os.stat(reverseLookupFileName)[8]
128 if not countries or reverselookupMtimeAct > reverselookupMtime:
129 myprint("[ReverseLookupAndNotifier] (Re-)Reading %s\n" %reverseLookupFileName)
130 reverselookupMtime = reverselookupMtimeAct
131 dom = parse(reverseLookupFileName)
132 for top in dom.getElementsByTagName("reverselookup"):
133 for country in top.getElementsByTagName("country"):
134 code = country.getAttribute("code").replace("+","00")
135 countries[code] = country.getElementsByTagName("website")
137 self.countrycode = countrycode
140 # self.caller = _("UNKNOWN")
141 self.notifyAndReset()
144 if self.number[:2] == "00":
145 if countries.has_key(self.number[:3]): # e.g. USA
146 self.countrycode = self.number[:3]
147 elif countries.has_key(self.number[:4]):
148 self.countrycode = self.number[:4]
149 elif countries.has_key(self.number[:5]):
150 self.countrycode = self.number[:5]
152 myprint("[ReverseLookupAndNotifier] Country cannot be reverse handled")
153 # self.caller = _("UNKNOWN")
154 self.notifyAndReset()
157 if countries.has_key(self.countrycode):
158 myprint("[ReverseLookupAndNotifier] Found website for reverse lookup")
159 self.websites = countries[self.countrycode]
160 self.nextWebsiteNo = 1
161 self.handleWebsite(self.websites[0])
163 myprint("[ReverseLookupAndNotifier] Country cannot be reverse handled")
164 # self.caller = _("UNKNOWN")
165 self.notifyAndReset()
168 def handleWebsite(self, website):
169 myprint("[ReverseLookupAndNotifier] handleWebsite: " + website.getAttribute("name"))
170 if self.number[:2] == "00":
171 number = website.getAttribute("prefix") + self.number.replace(self.countrycode,"")
175 url = website.getAttribute("url")
176 if re.search('$AREACODE',url) or re.search('$PFXAREACODE',url):
177 myprint("[ReverseLookupAndNotifier] handleWebsite: (PFX)ARECODE cannot be handled")
178 # self.caller = _("UNKNOWN")
179 self.notifyAndReset()
182 # Apparently, there is no attribute called (pfx)areacode anymore
183 # So, this below will not work.
185 if re.search('\\$AREACODE',url) and website.hasAttribute("areacode"):
186 areaCodeLen = int(website.getAttribute("areacode"))
187 url = url.replace("$AREACODE","%(areacode)s").replace("$NUMBER","%(number)s")
188 url = url %{ 'areacode':number[:areaCodeLen], 'number':number[areaCodeLen:] }
189 elif re.search('\\$PFXAREACODE',url) and website.hasAttribute("pfxareacode"):
190 areaCodeLen = int(website.getAttribute("pfxareacode"))
191 url = url.replace("$PFXAREACODE","%(pfxareacode)s").replace("$NUMBER","%(number)s")
192 url = url %{ 'pfxareacode':number[:areaCodeLen], 'number':number[areaCodeLen:] }
193 elif re.search('\\$NUMBER',url):
194 url = url.replace("$NUMBER","%s") %number
196 myprint("[ReverseLookupAndNotifier] handleWebsite: cannot handle websites with no $NUMBER in url")
197 # self.caller = _("UNKNOWN")
198 self.notifyAndReset()
200 myprint("[ReverseLookupAndNotifier] Url to query: " + url)
201 url = url.encode("UTF-8", "replace")
202 self.currentWebsite = website
203 # I am not sure, whether setting the user-agent works this way
205 agent="Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5"
206 ).addCallback(self._gotPage).addErrback(self._gotError)
208 def _gotPage(self, page):
209 myprint("[ReverseLookupAndNotifier] _gotPage")
210 found = re.match('.*content=".*?charset=([^"]+)"',page,re.S)
212 myprint("[ReverseLookupAndNotifier] Charset: " + found.group(1))
213 page = page.replace("\xa0"," ").decode(found.group(1), "replace")
215 page = page.replace("\xa0"," ").decode("ISO-8859-1", "replace")
217 for entry in self.currentWebsite.getElementsByTagName("entry"):
218 # myprint("[ReverseLookupAndNotifier] _gotPage: try entry")
220 for what in ["name", "street", "city", "zipcode"]:
221 # myprint("[ReverseLookupAndNotifier] _gotPage: look for '''%s''' with '''%s'''" %( what, pat ))
222 pat = ".*?" + self.getPattern(entry, what)
223 found = re.match(pat, page, re.S|re.M)
225 # myprint("[ReverseLookupAndNotifier] _gotPage: found for '''%s''': '''%s'''" %( what, found.group(2) ))
226 myprint(found.group(1))
227 item = found.group(1).replace(" "," ").replace("</b>","").replace(","," ")
228 item = html2utf8(item).decode("ISO-8859-1", "replace")
229 newitem = item.replace(" ", " ")
230 while newitem != item:
232 newitem = item.replace(" ", " ")
233 details.append(item.strip())
237 if len(details) != 4:
241 address = details[1] + ", " + details[3] + " " + details[2]
242 myprint("[ReverseLookupAndNotifier] _gotPage: Reverse lookup succeeded:\nName: %s\nAddress: %s" %(name, address))
243 self.caller = "%s, %s" %(name, address)
244 # if self.number != 0 and config.plugins.Call.addcallers.value and self.event == "RING":
245 # phonebook.add(self.number, self.caller)
247 self.caller = self.caller.encode("UTF-8", "replace")
248 self.notifyAndReset()
252 self._gotError("[ReverseLookupAndNotifier] _gotPage: Nothing found at %s" %self.currentWebsite.getAttribute("name"))
254 def _gotError(self, error = ""):
255 myprint("[ReverseLookupAndNotifier] _gotError - Error: %s" %error)
256 if self.nextWebsiteNo >= len(self.websites):
257 myprint("[ReverseLookupAndNotifier] _gotError: I give up")
258 # self.caller = _("UNKNOWN")
259 self.notifyAndReset()
262 myprint("[ReverseLookupAndNotifier] _gotError: try next website")
263 self.nextWebsiteNo = self.nextWebsiteNo+1
264 self.handleWebsite(self.websites[self.nextWebsiteNo-1])
266 def getPattern(self, website, which):
267 pat1 = website.getElementsByTagName(which)
269 myprint("Something strange: more than one %s for website %s" %(which, website.getAttribute("name")))
270 return pat1[0].childNodes[0].data
272 def notifyAndReset(self):
273 myprint("[ReverseLookupAndNotifier] notifyAndReset: Number: " + self.number + "; Caller: " + self.caller)
275 self.outputFunction(self.number, self.caller.decode("utf-8").encode(self.charset))
277 self.outputFunction(self.number, "")
278 if __name__ == '__main__':
279 reactor.stop() #@UndefinedVariable
281 if __name__ == '__main__':
282 cwd = os.path.dirname(sys.argv[0])
283 if (len(sys.argv) == 2):
285 ReverseLookupAndNotifier(sys.argv[1])
286 reactor.run() #@UndefinedVariable
287 elif (len(sys.argv) == 3):
288 # nrzuname.py Nummer SimpleOut
290 ReverseLookupAndNotifier(sys.argv[1], simpleout)
291 reactor.run() #@UndefinedVariable