]>
Commit | Line | Data |
---|---|---|
66862195 MT |
1 | #!/usr/bin/python |
2 | ||
77431b9c MT |
3 | import re |
4 | ||
5ac74b02 MT |
5 | from . import asterisk |
6 | from . import database | |
66862195 MT |
7 | |
8 | from misc import Object | |
9 | ||
10 | class Talk(Object): | |
11 | def init(self): | |
12 | db_args = self.backend.db._db_args | |
13 | db_args.update({ | |
77431b9c | 14 | "database" : "kamailio", |
66862195 MT |
15 | }) |
16 | ||
17 | self._db = database.Connection(**db_args) | |
18 | ||
19 | @property | |
20 | def db(self): | |
21 | return self._db | |
22 | ||
5ac74b02 MT |
23 | def connect_to_asterisk(self): |
24 | hostname = self.settings.get("asterisk_hostname") | |
25 | username = self.settings.get("asterisk_username") | |
26 | password = self.settings.get("asterisk_password") | |
27 | ||
28 | return asterisk.AsteriskManager( | |
29 | hostname, username=username, password=password | |
30 | ) | |
31 | ||
66862195 MT |
32 | def get_phonebook(self, account=None): |
33 | accounts = [] | |
34 | for a in self.accounts.list(): | |
35 | if account and a == account: | |
36 | continue | |
37 | ||
38 | if not a.is_talk_enabled(): | |
39 | continue | |
40 | ||
41 | accounts.append(a) | |
42 | ||
43 | return accounts | |
44 | ||
45 | def user_is_online(self, sip_id): | |
77431b9c | 46 | res = self.db.get("SELECT 1 FROM location WHERE username = %s \ |
66862195 MT |
47 | AND expires >= NOW() LIMIT 1", sip_id) |
48 | ||
49 | if res: | |
50 | return True | |
51 | ||
52 | return False | |
53 | ||
77431b9c MT |
54 | def get_lines(self, account=None): |
55 | accounts_cache = {} | |
66862195 | 56 | |
77431b9c | 57 | if account and not account.is_talk_enabled(): |
66862195 MT |
58 | return [] |
59 | ||
77431b9c MT |
60 | if account: |
61 | res = self.db.query("SELECT contact AS location, expires, user_agent, socket \ | |
62 | FROM location WHERE domain = %s AND username = %s ORDER BY expires DESC", | |
63 | "ipfire.org", account.sip_id) | |
64 | else: | |
65 | res = self.db.query("SELECT username, domain, contact AS location, \ | |
66 | expires, user_agent, socket FROM location ORDER BY username, expires DESC") | |
66862195 MT |
67 | |
68 | result = [] | |
69 | for row in res: | |
77431b9c MT |
70 | if account: |
71 | row.account = account | |
72 | elif row.username: | |
73 | try: | |
74 | row.account = accounts_cache[row.username] | |
75 | except KeyError: | |
76 | row.account = accounts_cache[row.username] = \ | |
77 | self.accounts.get_by_sip_id(row.username) | |
78 | else: | |
79 | row.account = None | |
66862195 | 80 | |
77431b9c MT |
81 | # Check if TLS is used |
82 | row.tls_enabled = row.socket.startswith("tls:") | |
66862195 MT |
83 | |
84 | # Cut off everything after ; | |
85 | row.location, sep, rest = row.location.partition(";") | |
86 | ||
87 | result.append(row) | |
88 | ||
89 | return result | |
90 | ||
77431b9c MT |
91 | def _process_sip_uri(self, sip_uri): |
92 | sip_uri, delimiter, rest = sip_uri.partition(";") | |
93 | ||
94 | m = re.match(r"^sip:([0-9]{4})@ipfire\.org", sip_uri) | |
95 | if m: | |
96 | return m.group(1) | |
97 | ||
98 | # Remove trailing default port | |
99 | if sip_uri.endswith(":5060"): | |
100 | sip_uri = sip_uri.replace(":5060", "") | |
101 | ||
102 | return sip_uri | |
103 | ||
104 | def _process_cdr(self, entries, replace_sip_uris=False): | |
66862195 MT |
105 | accounts_cache = {} |
106 | ||
107 | result = [] | |
108 | for row in entries: | |
77431b9c MT |
109 | if replace_sip_uris: |
110 | row["caller"] = self._process_sip_uri(row.caller) | |
111 | ||
66862195 | 112 | try: |
77431b9c | 113 | row["caller_account"] = accounts_cache[row.caller] |
66862195 | 114 | except KeyError: |
77431b9c | 115 | row["caller_account"] = accounts_cache[row.caller] = \ |
66862195 MT |
116 | self.accounts.get_by_sip_id(row.caller) |
117 | ||
77431b9c MT |
118 | if replace_sip_uris: |
119 | row["called"] = self._process_sip_uri(row.called) | |
120 | ||
66862195 | 121 | try: |
77431b9c | 122 | row["called_account"] = accounts_cache[row.called] |
66862195 | 123 | except KeyError: |
77431b9c | 124 | row["called_account"] = accounts_cache[row.called] = \ |
66862195 MT |
125 | self.accounts.get_by_sip_id(row.called) |
126 | ||
127 | if not row.called_account: | |
77431b9c | 128 | row["called_conference"] = self.get_conference(row.called) |
66862195 | 129 | else: |
77431b9c MT |
130 | row["called_conference"] = None |
131 | ||
132 | try: | |
133 | row["time"] = datetime.datetime.fromutctimestamp(row.time) | |
134 | except: | |
135 | pass | |
66862195 MT |
136 | |
137 | result.append(row) | |
138 | ||
139 | return result | |
140 | ||
141 | def get_call_log(self, account, limit=25): | |
77431b9c MT |
142 | if account: |
143 | res = self.db.query("SELECT * FROM cdr WHERE (caller = %s OR called = %s) \ | |
144 | ORDER BY time DESC LIMIT %s", account.sip_id, account.sip_id, limit) | |
145 | else: | |
146 | res = self.db.query("SELECT * FROM cdr ORDER BY time DESC LIMIT %s", limit) | |
66862195 MT |
147 | |
148 | return self._process_cdr(res) | |
149 | ||
5ac74b02 MT |
150 | def get_channels(self, account=None): |
151 | a = self.connect_to_asterisk() | |
152 | ||
153 | channels = [] | |
154 | for c in a.list_channels(): | |
155 | if account and not account.sip_id in (c.caller, c.callee): | |
156 | continue | |
157 | ||
158 | channels.append(c) | |
159 | ||
160 | return sorted(channels) | |
161 | ||
40818cf2 MT |
162 | def get_channel(self, channel_id, account=None): |
163 | channels = self.get_channels(account=account) | |
164 | ||
165 | for channel in channels: | |
166 | if channel.id == channel_id: | |
167 | return channel | |
168 | ||
66862195 MT |
169 | def get_ongoing_calls(self, account=None, sip_id=None): |
170 | if account and sip_id is None: | |
171 | sip_id = account.sip_id | |
172 | ||
77431b9c MT |
173 | # If the given account does not have a SIP ID, |
174 | # we not need to search for any active sessions | |
175 | if sip_id is None: | |
176 | return [] | |
177 | ||
66862195 | 178 | if sip_id: |
77431b9c MT |
179 | sip_id = "sip:%s@%%" % sip_id |
180 | ||
181 | res = self.db.query("SELECT from_uri AS caller, \ | |
182 | to_uri AS called, start_time AS time FROM dialog \ | |
183 | WHERE from_uri LIKE %s OR to_uri LIKE %s ORDER BY time", | |
184 | sip_id, sip_id) | |
66862195 | 185 | else: |
77431b9c MT |
186 | res = self.db.query("SELECT from_uri AS caller, to_uri AS called, \ |
187 | start_time AS time FROM dialog ORDER BY time") | |
66862195 | 188 | |
77431b9c | 189 | return self._process_cdr(res, replace_sip_uris=True) |
66862195 | 190 | |
66862195 MT |
191 | # Favourites |
192 | ||
193 | def get_favourite_contacts(self, account, limit=6): | |
77431b9c MT |
194 | res = self.db.query("SELECT src_user AS caller, dst_ouser AS called, \ |
195 | COUNT(*) AS count FROM acc WHERE method = %s AND src_user = %s AND \ | |
196 | dst_ouser BETWEEN %s AND %s AND time >= NOW() - INTERVAL '1 year' \ | |
197 | GROUP BY caller, called ORDER BY count DESC LIMIT %s", | |
198 | "INVITE", account.sip_id, "1000", "1999", limit) | |
66862195 MT |
199 | |
200 | return self._process_cdr(res) | |
201 | ||
202 | # Conferences | |
203 | ||
204 | @property | |
205 | def conferences(self): | |
206 | conferences = [] | |
207 | ||
208 | for no in range(1, 10): | |
209 | conference = Conference(self.backend, no) | |
210 | conferences.append(conference) | |
211 | ||
212 | return conferences | |
213 | ||
214 | def get_conference(self, id): | |
215 | for c in self.conferences: | |
216 | if not c.sip_id == id: | |
217 | continue | |
218 | ||
219 | return c | |
220 | ||
221 | ||
222 | class Conference(Object): | |
223 | def __init__(self, backend, no): | |
224 | Object.__init__(self, backend) | |
225 | self.no = no | |
226 | ||
227 | def __cmp__(self, other): | |
228 | return cmp(self.no, other.no) | |
229 | ||
230 | @property | |
231 | def name(self): | |
232 | return "IPFire Conference Room %s" % self.no | |
233 | ||
234 | @property | |
235 | def sip_id(self): | |
236 | return "%s" % (9000 + self.no) | |
237 | ||
238 | @property | |
239 | def sip_url(self): | |
240 | return "%s@ipfire.org" % self.sip_id | |
241 | ||
242 | @property | |
243 | def participants(self): | |
244 | if not hasattr(self, "_participants"): | |
245 | self._participants = self.backend.talk.get_ongoing_calls(sip_id=self.sip_id) | |
246 | ||
247 | return self._participants |