]> git.ipfire.org Git - ipfire.org.git/blame - src/backend/talk.py
passwd: Ask for old password first and then the new ones
[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
917434b8
MT
64
65class SIPRegistration(object):
66 def __init__(self, freeswitch, data):
67 self.freeswitch = freeswitch
68 self.data = data
69
70 @lazy_property
71 def protocol(self):
72 m = re.match(r"Registered\(([A-Z]+)(\-NAT)?\)", self.data.status)
73
74 if m:
75 return m.group(1)
76
77 @property
78 def network_ip(self):
79 return ipaddress.ip_address(self.data.network_ip)
80
81 @property
82 def network_port(self):
83 return self.data.network_port
84
85 @property
86 def user_agent(self):
87 return self.data.user_agent
88
89 def is_reachable(self):
90 return self.data.ping_status == "Reachable"
91
92 @lazy_property
93 def latency(self):
b78ec69b 94 if self.is_reachable() and self.data.ping_time:
917434b8
MT
95 return self.data.ping_time / 1000.0
96
97
9f05796c
MT
98class Channel(object):
99 def __init__(self, freeswitch, data):
100 self.freeswitch = freeswitch
101 self.data = data
66862195 102
9f05796c
MT
103 @property
104 def backend(self):
105 return self.freeswitch.backend
13e89ccc 106
9f05796c
MT
107 @property
108 def uuid(self):
109 return self.data.uuid
66862195 110
9f05796c
MT
111 @property
112 def direction(self):
113 return self.data.direction
114
115 @lazy_property
116 def caller(self):
117 return self.backend.accounts.get_by_sip_id(self.caller_number)
118
119 @property
120 def caller_name(self):
121 return self.data.cid_name
122
123 @property
124 def caller_number(self):
125 return self.data.cid_num
126
127 @lazy_property
128 def callee(self):
129 return self.backend.accounts.get_by_sip_id(self.callee_number)
66862195 130
9f05796c
MT
131 @property
132 def callee_name(self):
133 return self.data.callee_name
134
135 @property
136 def callee_number(self):
137 return self.data.callee_num
138
139 @property
140 def called_number(self):
141 return self.data.dest
142
143 @property
144 def application(self):
145 return self.data.application
66862195 146
9f05796c
MT
147 @property
148 def application_data(self):
149 return self.data.application_data
66862195 150
9f05796c
MT
151 @property
152 def duration(self):
153 return time.time() - self.data.created_epoch
66862195 154
9f05796c
MT
155 @property
156 def codec(self):
157 # We always assume a symmetric codec
158 s = [
e3dfabc1 159 self.data.write_codec,
9f05796c
MT
160 ]
161
e3dfabc1
MT
162 if self.data.write_rate:
163 s.append("%.0f kHz" % (int(self.data.write_rate) / 1000.0))
164
9f05796c
MT
165 if self.data.write_bit_rate == "0":
166 s.append("VBR")
167 else:
168 s.append("%.0f kBit/s" % (int(self.data.write_bit_rate) / 1000.0))
66862195 169
9f05796c
MT
170 return " ".join(s)
171
fe55357f
MT
172 def is_secure(self):
173 if self.data.secure:
174 return True
175
176 return False
177
9f05796c
MT
178 @property
179 def secure(self):
fe55357f
MT
180 try:
181 transport_protocol, key_negotiation, cipher_suite = self.data.secure.split(":")
182 except:
183 return
184
185 return "%s: %s" % (key_negotiation.upper(), cipher_suite.replace("_", "-"))
9f05796c
MT
186
187
525c01f7
MT
188class CDR(object):
189 def __init__(self, freeswitch, data):
190 self.freeswitch = freeswitch
191 self.data = data
192
193 @property
194 def backend(self):
195 return self.freeswitch.backend
196
197 @property
198 def direction(self):
199 if self.data.bleg_uuid:
200 return "inbound"
201
202 return "outbound"
203
204 @lazy_property
205 def caller(self):
206 return self.backend.accounts.get_by_phone_number(self.data.caller_id_number)
207
208 @property
209 def caller_number(self):
210 return self.data.caller_id_number
211
212 @lazy_property
213 def callee(self):
214 return self.backend.accounts.get_by_phone_number(self.data.destination_number)
215
216 @property
217 def callee_number(self):
218 return self.data.destination_number
219
220 @property
221 def time_start(self):
222 return self.data.start_stamp
223
224 @property
225 def time_answered(self):
226 return self.data.answer_stamp
227
228 @property
229 def duration(self):
230 return self.data.duration
231
232 @property
233 def codec(self):
234 return self.data.write_codec
235
236 @property
237 def user_agent(self):
c2c06884 238 return self.data.user_agent.replace("_", " ")
525c01f7 239
354445ed
MT
240 @property
241 def size(self):
242 return sum((self.data.rtp_audio_in_raw_bytes or 0, self.data.rtp_audio_out_raw_bytes or 0))
243
244 @property
245 def mos(self):
246 return self.data.rtp_audio_in_mos
247
525c01f7 248
9f05796c
MT
249class Talk(Object):
250 def init(self):
251 # Connect to FreeSWITCH
252 self.freeswitch = Freeswitch(self.backend)
66862195 253
66862195
MT
254 # Conferences
255
256 @property
257 def conferences(self):
258 conferences = []
259
260 for no in range(1, 10):
261 conference = Conference(self.backend, no)
262 conferences.append(conference)
263
264 return conferences
265
266 def get_conference(self, id):
267 for c in self.conferences:
268 if not c.sip_id == id:
269 continue
270
271 return c
272
273
274class Conference(Object):
275 def __init__(self, backend, no):
276 Object.__init__(self, backend)
277 self.no = no
278
279 def __cmp__(self, other):
280 return cmp(self.no, other.no)
281
282 @property
283 def name(self):
284 return "IPFire Conference Room %s" % self.no
285
286 @property
287 def sip_id(self):
288 return "%s" % (9000 + self.no)
289
290 @property
291 def sip_url(self):
292 return "%s@ipfire.org" % self.sip_id
293
294 @property
295 def participants(self):
296 if not hasattr(self, "_participants"):
297 self._participants = self.backend.talk.get_ongoing_calls(sip_id=self.sip_id)
298
299 return self._participants