]> git.ipfire.org Git - ipfire.org.git/blame - src/backend/talk.py
Add blocked page
[ipfire.org.git] / src / backend / talk.py
CommitLineData
66862195
MT
1#!/usr/bin/python
2
917434b8
MT
3import ipaddress
4import logging
77431b9c 5import re
9f05796c 6import time
77431b9c 7
5ac74b02 8from . import database
66862195 9
11347e46 10from .misc import Object
13e89ccc
MT
11from .decorators import *
12
13class Freeswitch(Object):
14 @lazy_property
15 def db(self):
16 credentials = {
17 "host" : self.settings.get("freeswitch_database_host"),
18 "database" : self.settings.get("freeswitch_database_name", "freeswitch"),
19 "user" : self.settings.get("freeswitch_database_user"),
20 "password" : self.settings.get("freeswitch_database_password"),
21 }
22
23 return database.Connection(**credentials)
24
917434b8
MT
25 def get_sip_registrations(self, sip_uri):
26 logging.debug("Fetching SIP registrations for %s" % sip_uri)
27
28 user, delim, domain = sip_uri.partition("@")
29
30 res = self.db.query("SELECT * FROM sip_registrations \
31 WHERE sip_user = %s AND sip_host = %s AND expires >= EXTRACT(epoch FROM CURRENT_TIMESTAMP) \
32 ORDER BY contact", user, domain)
33
34 for row in res:
35 yield SIPRegistration(self, data=row)
36
9f05796c
MT
37 def get_sip_channels(self, account):
38 res = self.db.query("SELECT * FROM channels \
39 WHERE (direction = %s AND cid_num = %s) OR \
8476e80f
MT
40 (direction = %s AND (callee_num = %s OR callee_num = ANY(%s))) \
41 ORDER BY created_epoch",
42 "inbound", account.sip_id, "outbound", account.sip_id,
43 account._all_telephone_numbers)
9f05796c 44
9c50164e
MT
45 channels = []
46
9f05796c 47 for row in res:
9c50164e
MT
48 c = Channel(self, data=row)
49 channels.append(c)
50
51 return channels
9f05796c 52
bdaf6b46 53 def get_cdr_by_account(self, account, date=None, limit=None):
525c01f7 54 res = self.db.query("SELECT * FROM cdr \
8476e80f
MT
55 WHERE ((caller_id_number = ANY(%s) AND bleg_uuid IS NOT NULL) \
56 OR (destination_number = ANY(%s) AND bleg_uuid IS NULL)) \
bdaf6b46 57 AND (%s IS NULL OR start_stamp::date = %s) \
8476e80f
MT
58 ORDER BY end_stamp DESC LIMIT %s", account._all_telephone_numbers,
59 account._all_telephone_numbers, date, date, limit)
525c01f7
MT
60
61 for row in res:
62 yield CDR(self, data=row)
63
68ece434
MT
64 def get_call_by_uuid(self, uuid):
65 res = self.db.get("SELECT * FROM cdr \
66 WHERE uuid = %s", uuid)
67
68 if res:
69 return CDR(self, data=res)
70
917434b8
MT
71
72class SIPRegistration(object):
73 def __init__(self, freeswitch, data):
74 self.freeswitch = freeswitch
75 self.data = data
76
77 @lazy_property
78 def protocol(self):
79 m = re.match(r"Registered\(([A-Z]+)(\-NAT)?\)", self.data.status)
80
81 if m:
82 return m.group(1)
83
84 @property
85 def network_ip(self):
86 return ipaddress.ip_address(self.data.network_ip)
87
88 @property
89 def network_port(self):
90 return self.data.network_port
91
92 @property
93 def user_agent(self):
94 return self.data.user_agent
95
96 def is_reachable(self):
97 return self.data.ping_status == "Reachable"
98
99 @lazy_property
100 def latency(self):
b78ec69b 101 if self.is_reachable() and self.data.ping_time:
917434b8
MT
102 return self.data.ping_time / 1000.0
103
104
9f05796c
MT
105class Channel(object):
106 def __init__(self, freeswitch, data):
107 self.freeswitch = freeswitch
108 self.data = data
66862195 109
9f05796c
MT
110 @property
111 def backend(self):
112 return self.freeswitch.backend
13e89ccc 113
9f05796c
MT
114 @property
115 def uuid(self):
116 return self.data.uuid
66862195 117
9f05796c
MT
118 @property
119 def direction(self):
120 return self.data.direction
121
122 @lazy_property
123 def caller(self):
124 return self.backend.accounts.get_by_sip_id(self.caller_number)
125
126 @property
127 def caller_name(self):
128 return self.data.cid_name
129
130 @property
131 def caller_number(self):
132 return self.data.cid_num
133
134 @lazy_property
135 def callee(self):
136 return self.backend.accounts.get_by_sip_id(self.callee_number)
66862195 137
9f05796c
MT
138 @property
139 def callee_name(self):
140 return self.data.callee_name
141
142 @property
143 def callee_number(self):
144 return self.data.callee_num
145
146 @property
147 def called_number(self):
148 return self.data.dest
149
150 @property
151 def application(self):
152 return self.data.application
66862195 153
9f05796c
MT
154 @property
155 def application_data(self):
156 return self.data.application_data
66862195 157
9f05796c
MT
158 @property
159 def duration(self):
160 return time.time() - self.data.created_epoch
66862195 161
9f05796c
MT
162 @property
163 def codec(self):
164 # We always assume a symmetric codec
8f06a493 165 return format_codec(self.data.write_codec, int(self.data.write_rate or 0), int(self.data.write_bit_rate or 0))
9f05796c 166
fe55357f
MT
167 def is_secure(self):
168 if self.data.secure:
169 return True
170
171 return False
172
9f05796c
MT
173 @property
174 def secure(self):
fe55357f
MT
175 try:
176 transport_protocol, key_negotiation, cipher_suite = self.data.secure.split(":")
177 except:
178 return
179
180 return "%s: %s" % (key_negotiation.upper(), cipher_suite.replace("_", "-"))
9f05796c
MT
181
182
525c01f7
MT
183class CDR(object):
184 def __init__(self, freeswitch, data):
185 self.freeswitch = freeswitch
186 self.data = data
187
188 @property
189 def backend(self):
190 return self.freeswitch.backend
191
68ece434
MT
192 @property
193 def db(self):
194 return self.freeswitch.db
195
196 @property
197 def uuid(self):
198 return self.data.uuid
199
200 @lazy_property
201 def bleg(self):
202 if self.data.bleg_uuid:
203 return self.freeswitch.get_call_by_uuid(self.data.bleg_uuid)
204
205 # If we are the bleg, we need to search for one where UUID is the bleg
206 res = self.db.get("SELECT * FROM cdr WHERE bleg_uuid = %s", self.uuid)
207
208 if res:
209 return CDR(self.freeswitch, data=res)
210
525c01f7
MT
211 @property
212 def direction(self):
213 if self.data.bleg_uuid:
214 return "inbound"
215
216 return "outbound"
217
218 @lazy_property
219 def caller(self):
220 return self.backend.accounts.get_by_phone_number(self.data.caller_id_number)
221
222 @property
223 def caller_number(self):
224 return self.data.caller_id_number
225
226 @lazy_property
227 def callee(self):
228 return self.backend.accounts.get_by_phone_number(self.data.destination_number)
229
230 @property
231 def callee_number(self):
232 return self.data.destination_number
233
234 @property
235 def time_start(self):
236 return self.data.start_stamp
237
238 @property
239 def time_answered(self):
240 return self.data.answer_stamp
241
242 @property
243 def duration(self):
244 return self.data.duration
245
246 @property
247 def codec(self):
8f06a493 248 return format_codec(self.data.write_codec, int(self.data.write_rate or 0), int(self.data.write_bit_rate or 0))
525c01f7
MT
249
250 @property
251 def user_agent(self):
68ece434
MT
252 if self.data.user_agent:
253 return self.data.user_agent.replace("_", " ")
525c01f7 254
354445ed
MT
255 @property
256 def size(self):
257 return sum((self.data.rtp_audio_in_raw_bytes or 0, self.data.rtp_audio_out_raw_bytes or 0))
258
259 @property
260 def mos(self):
261 return self.data.rtp_audio_in_mos
262
525c01f7 263
9f05796c
MT
264class Talk(Object):
265 def init(self):
266 # Connect to FreeSWITCH
267 self.freeswitch = Freeswitch(self.backend)
66862195 268
66862195
MT
269 # Conferences
270
271 @property
272 def conferences(self):
273 conferences = []
274
275 for no in range(1, 10):
276 conference = Conference(self.backend, no)
277 conferences.append(conference)
278
279 return conferences
280
281 def get_conference(self, id):
282 for c in self.conferences:
283 if not c.sip_id == id:
284 continue
285
286 return c
287
288
289class Conference(Object):
290 def __init__(self, backend, no):
291 Object.__init__(self, backend)
292 self.no = no
293
294 def __cmp__(self, other):
295 return cmp(self.no, other.no)
296
297 @property
298 def name(self):
299 return "IPFire Conference Room %s" % self.no
300
301 @property
302 def sip_id(self):
303 return "%s" % (9000 + self.no)
304
305 @property
306 def sip_url(self):
307 return "%s@ipfire.org" % self.sip_id
308
309 @property
310 def participants(self):
311 if not hasattr(self, "_participants"):
312 self._participants = self.backend.talk.get_ongoing_calls(sip_id=self.sip_id)
313
314 return self._participants
8f06a493
MT
315
316
317def format_codec(name, bit_rate, bandwidth):
318 s = [
319 name,
320 ]
321
322 if bit_rate:
323 s.append("%.0f kHz" % (bit_rate / 1000.0))
324
325 if bandwidth:
326 s.append("%.0f kBit/s" % (bandwidth / 1000.0))
327 else:
328 s.append("VBR")
329
330 return " ".join(s)