27b16838 |
1 | #!/usr/bin/python |
2 | |
3 | import os, sys, signal |
4 | from time import time |
5 | import socket, select |
6 | import pynotify |
7 | |
8 | if len(sys.argv) < 2: |
9 | sys.stderr.write("usage: cidnotify SERVER\n") |
10 | sys.exit(1) |
11 | server = sys.argv[1] |
12 | |
13 | pynotify.init("cidnotify") |
14 | |
15 | sk = None |
16 | notif = None |
17 | curnum = None |
18 | lastring = None |
19 | t2n = None |
20 | buf = "" |
21 | namebuf = "" |
22 | name = None |
23 | actab = [] |
24 | |
25 | signal.signal(signal.SIGCHLD, signal.SIG_IGN) |
26 | |
27 | try: |
28 | acfile = open(os.getenv("HOME") + "/phone/actab") |
29 | except IOError: |
30 | pass |
31 | else: |
32 | for line in acfile: |
33 | pos = line.find(" ") |
34 | if pos < 0: continue |
35 | actab += [(line[:pos], line[pos + 1:].strip())] |
36 | acfile.close() |
37 | |
38 | for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo(server, 5001, 0, socket.SOCK_STREAM): |
39 | try: |
40 | sk = socket.socket(family, socktype, proto) |
41 | sk.connect(sockaddr) |
42 | except socket.error: |
43 | sk = None |
44 | continue |
45 | else: |
46 | break |
47 | |
48 | if sk is None: |
49 | sys.stderr.write("cidnotify: could not connect to " + server + "\n"); |
50 | sys.exit(1) |
51 | |
52 | def popen(*cmd): |
53 | rfd, wfd = os.pipe() |
54 | pid = os.fork() |
55 | if pid == 0: |
56 | os.dup2(wfd, 1) |
57 | os.close(rfd) |
58 | os.close(wfd) |
59 | os.execvp(cmd[0], cmd) |
60 | sys.exit(127) |
61 | os.close(wfd) |
62 | return pid, rfd |
63 | |
64 | def closet2n(): |
65 | global t2n |
66 | if t2n is not None: |
67 | try: |
68 | os.kill(t2n[0], signal.SIGINT) |
69 | except: |
70 | pass |
71 | os.close(t2n[1]) |
72 | t2n = None |
73 | |
74 | def close(): |
75 | global notif, curnum, lastring |
76 | closet2n() |
77 | if notif is not None: |
78 | notif.close() |
79 | notif = None |
80 | curnum = None |
81 | lastring = None |
82 | name = None |
83 | |
84 | def findac(num): |
85 | for ac, acn in actab: |
86 | if num[:len(ac)] == ac: |
87 | return acn |
88 | return None |
89 | |
90 | def notiftext(): |
91 | if curnum == "B10": |
92 | return "<i>Undisclosed number</i>" |
93 | text = "<b>Number</b>: " + curnum + "\n" |
94 | acn = findac(curnum) |
95 | if acn is not None: |
96 | text += "<b>Area code</b>: " + acn + "\n" |
97 | else: |
98 | text += "<b>Area code</b>: <i>Unknown</i>\n" |
99 | if name is None: |
100 | text += "<b>Name</b>: <i>Looking up...</i>\n" |
101 | elif name == "": |
102 | text += "<b>Name</b>: <i>No hits</i>\n" |
103 | else: |
104 | text += "<b>Name</b>: " + name + "\n" |
105 | return text.strip() |
106 | |
107 | def newnum(num): |
108 | global curnum, t2n, notif, lastring |
109 | close() |
110 | curnum = num |
111 | notif = pynotify.Notification("Phone call", notiftext()) |
112 | notif.set_timeout(0) |
113 | notif.show() |
114 | lastring = time() |
115 | if curnum.isdigit(): |
116 | t2n = popen("tel2name", num) |
117 | |
118 | try: |
119 | while True: |
120 | fds = [sk.fileno()] |
121 | if t2n is not None: |
122 | fds += [t2n[1]] |
123 | if lastring is not None: |
124 | timeout = lastring + 10 - time() |
125 | else: |
126 | timeout = None |
127 | fds = reduce(lambda s, l: s | set(l), |
128 | select.select(fds, [], fds, timeout), |
129 | set()) |
130 | |
131 | if sk.fileno() in fds: |
132 | ret = sk.recv(100) |
133 | if ret == "": sys.exit(0) |
134 | buf += ret |
135 | lines = buf.split("\n") |
136 | buf = lines[-1] |
137 | for line in lines[:-1]: |
138 | if line[0] == "N": |
139 | newnum(line[1:]) |
140 | elif line[0] == "R": |
141 | if lastring is not None: |
142 | lastring = time() |
143 | |
144 | if t2n is not None and t2n[1] in fds: |
145 | ret = os.read(t2n[1], 100) |
146 | namebuf += ret |
147 | if ret == "": |
148 | closet2n() |
149 | name = namebuf.strip() |
150 | namebuf = "" |
151 | if notif is not None: |
152 | notif.update("Phone call", notiftext()) |
153 | notif.show() |
154 | |
155 | if lastring is not None and lastring + 10 < time(): |
156 | close() |
157 | |
158 | except KeyboardInterrupt: |
159 | pass |