]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/talk.py
10 from .misc
import Object
11 from .decorators
import *
13 class Freeswitch(Object
):
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"),
23 return database
.Connection(**credentials
)
25 def get_sip_registrations(self
, sip_uri
):
26 logging
.debug("Fetching SIP registrations for %s" % sip_uri
)
28 user
, delim
, domain
= sip_uri
.partition("@")
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
)
35 yield SIPRegistration(self
, data
=row
)
37 def get_sip_channels(self
, account
):
38 res
= self
.db
.query("SELECT * FROM channels \
39 WHERE (direction = %s AND cid_num = %s) OR \
40 (direction = %s AND callee_num = %s) ORDER BY created_epoch",
41 "inbound", account
.sip_id
, "outbound", account
.sip_id
)
46 c
= Channel(self
, data
=row
)
52 class SIPRegistration(object):
53 def __init__(self
, freeswitch
, data
):
54 self
.freeswitch
= freeswitch
59 m
= re
.match(r
"Registered\(([A-Z]+)(\-NAT)?\)", self
.data
.status
)
66 return ipaddress
.ip_address(self
.data
.network_ip
)
69 def network_port(self
):
70 return self
.data
.network_port
74 return self
.data
.user_agent
76 def is_reachable(self
):
77 return self
.data
.ping_status
== "Reachable"
81 if self
.is_reachable() and self
.data
.ping_time
:
82 return self
.data
.ping_time
/ 1000.0
85 class Channel(object):
86 def __init__(self
, freeswitch
, data
):
87 self
.freeswitch
= freeswitch
92 return self
.freeswitch
.backend
100 return self
.data
.direction
104 return self
.backend
.accounts
.get_by_sip_id(self
.caller_number
)
107 def caller_name(self
):
108 return self
.data
.cid_name
111 def caller_number(self
):
112 return self
.data
.cid_num
116 return self
.backend
.accounts
.get_by_sip_id(self
.callee_number
)
119 def callee_name(self
):
120 return self
.data
.callee_name
123 def callee_number(self
):
124 return self
.data
.callee_num
127 def called_number(self
):
128 return self
.data
.dest
131 def application(self
):
132 return self
.data
.application
135 def application_data(self
):
136 return self
.data
.application_data
140 return time
.time() - self
.data
.created_epoch
144 # We always assume a symmetric codec
146 "%s @ %s kHz" % (self
.data
.write_codec
, int(self
.data
.write_rate
) / 1000.0),
149 if self
.data
.write_bit_rate
== "0":
152 s
.append("%.0f kBit/s" % (int(self
.data
.write_bit_rate
) / 1000.0))
158 return self
.data
.secure
163 # Connect to FreeSWITCH
164 self
.freeswitch
= Freeswitch(self
.backend
)
168 for account
in self
.backend
.accounts
:
169 if not account
.is_talk_enabled():
174 def search(self
, query
):
177 for account
in self
.backend
.accounts
.search(query
):
178 if not account
.is_talk_enabled():
181 accounts
.append(account
)
185 def get_lines(self
, account
=None):
188 if account
and not account
.is_talk_enabled():
192 res
= self
.db
.query("SELECT contact AS location, expires, user_agent, socket \
193 FROM location WHERE domain = %s AND username = %s ORDER BY expires DESC",
194 "ipfire.org", account
.sip_id
)
196 res
= self
.db
.query("SELECT username, domain, contact AS location, \
197 expires, user_agent, socket FROM location ORDER BY username, expires DESC")
202 row
.account
= account
205 row
.account
= accounts_cache
[row
.username
]
207 row
.account
= accounts_cache
[row
.username
] = \
208 self
.accounts
.get_by_sip_id(row
.username
)
212 # Check if TLS is used
213 row
.tls_enabled
= row
.socket
.startswith("tls:")
215 # Cut off everything after ;
216 row
.location
, sep
, rest
= row
.location
.partition(";")
222 def _process_sip_uri(self
, sip_uri
):
223 sip_uri
, delimiter
, rest
= sip_uri
.partition(";")
225 m
= re
.match(r
"^sip:([0-9]{4})@ipfire\.org", sip_uri
)
229 # Remove trailing default port
230 if sip_uri
.endswith(":5060"):
231 sip_uri
= sip_uri
.replace(":5060", "")
235 def _process_cdr(self
, entries
, replace_sip_uris
=False):
241 row
["caller"] = self
._process
_sip
_uri
(row
.caller
)
244 row
["caller_account"] = accounts_cache
[row
.caller
]
246 row
["caller_account"] = accounts_cache
[row
.caller
] = \
247 self
.accounts
.get_by_sip_id(row
.caller
)
250 row
["called"] = self
._process
_sip
_uri
(row
.called
)
253 row
["called_account"] = accounts_cache
[row
.called
]
255 row
["called_account"] = accounts_cache
[row
.called
] = \
256 self
.accounts
.get_by_sip_id(row
.called
)
258 if not row
.called_account
:
259 row
["called_conference"] = self
.get_conference(row
.called
)
261 row
["called_conference"] = None
264 row
["time"] = datetime
.datetime
.fromutctimestamp(row
.time
)
272 def get_call_log(self
, account
, limit
=25):
274 res
= self
.db
.query("SELECT * FROM cdr WHERE (caller = %s OR called = %s) \
275 ORDER BY time DESC LIMIT %s", account
.sip_id
, account
.sip_id
, limit
)
277 res
= self
.db
.query("SELECT * FROM cdr ORDER BY time DESC LIMIT %s", limit
)
279 return self
._process
_cdr
(res
)
281 def get_channels(self
, account
=None):
283 for c
in a
.list_channels():
284 if account
and not account
.sip_id
in (c
.caller
, c
.callee
):
289 return sorted(channels
)
291 def get_channel(self
, channel_id
, account
=None):
292 channels
= self
.get_channels(account
=account
)
294 for channel
in channels
:
295 if channel
.id == channel_id
:
298 def get_ongoing_calls(self
, account
=None, sip_id
=None):
299 if account
and sip_id
is None:
300 sip_id
= account
.sip_id
302 # If the given account does not have a SIP ID,
303 # we not need to search for any active sessions
308 sip_id
= "sip:%s@%%" % sip_id
310 res
= self
.db
.query("SELECT from_uri AS caller, \
311 to_uri AS called, start_time AS time FROM dialog \
312 WHERE from_uri LIKE %s OR to_uri LIKE %s ORDER BY time",
315 res
= self
.db
.query("SELECT from_uri AS caller, to_uri AS called, \
316 start_time AS time FROM dialog ORDER BY time")
318 return self
._process
_cdr
(res
, replace_sip_uris
=True)
323 def conferences(self
):
326 for no
in range(1, 10):
327 conference
= Conference(self
.backend
, no
)
328 conferences
.append(conference
)
332 def get_conference(self
, id):
333 for c
in self
.conferences
:
334 if not c
.sip_id
== id:
340 class Conference(Object
):
341 def __init__(self
, backend
, no
):
342 Object
.__init
__(self
, backend
)
345 def __cmp__(self
, other
):
346 return cmp(self
.no
, other
.no
)
350 return "IPFire Conference Room %s" % self
.no
354 return "%s" % (9000 + self
.no
)
358 return "%s@ipfire.org" % self
.sip_id
361 def participants(self
):
362 if not hasattr(self
, "_participants"):
363 self
._participants
= self
.backend
.talk
.get_ongoing_calls(sip_id
=self
.sip_id
)
365 return self
._participants