if "sipRoutingObject" in self.classes:
return self._get_first_attribute("sipRoutingAddress")
- def sip_is_online(self):
- assert self.sip_id
-
- if not hasattr(self, "_is_online"):
- self._is_online = self.backend.talk.user_is_online(self.sip_id)
-
- return self._is_online
-
@lazy_property
def sip_registrations(self):
sip_registrations = []
return accounts
- def get_lines(self, account=None):
- accounts_cache = {}
-
- if account and not account.is_talk_enabled():
- return []
-
- if account:
- res = self.db.query("SELECT contact AS location, expires, user_agent, socket \
- FROM location WHERE domain = %s AND username = %s ORDER BY expires DESC",
- "ipfire.org", account.sip_id)
- else:
- res = self.db.query("SELECT username, domain, contact AS location, \
- expires, user_agent, socket FROM location ORDER BY username, expires DESC")
-
- result = []
- for row in res:
- if account:
- row.account = account
- elif row.username:
- try:
- row.account = accounts_cache[row.username]
- except KeyError:
- row.account = accounts_cache[row.username] = \
- self.accounts.get_by_sip_id(row.username)
- else:
- row.account = None
-
- # Check if TLS is used
- row.tls_enabled = row.socket.startswith("tls:")
-
- # Cut off everything after ;
- row.location, sep, rest = row.location.partition(";")
-
- result.append(row)
-
- return result
-
- def _process_sip_uri(self, sip_uri):
- sip_uri, delimiter, rest = sip_uri.partition(";")
-
- m = re.match(r"^sip:([0-9]{4})@ipfire\.org", sip_uri)
- if m:
- return m.group(1)
-
- # Remove trailing default port
- if sip_uri.endswith(":5060"):
- sip_uri = sip_uri.replace(":5060", "")
-
- return sip_uri
-
- def _process_cdr(self, entries, replace_sip_uris=False):
- accounts_cache = {}
-
- result = []
- for row in entries:
- if replace_sip_uris:
- row["caller"] = self._process_sip_uri(row.caller)
-
- try:
- row["caller_account"] = accounts_cache[row.caller]
- except KeyError:
- row["caller_account"] = accounts_cache[row.caller] = \
- self.accounts.get_by_sip_id(row.caller)
-
- if replace_sip_uris:
- row["called"] = self._process_sip_uri(row.called)
-
- try:
- row["called_account"] = accounts_cache[row.called]
- except KeyError:
- row["called_account"] = accounts_cache[row.called] = \
- self.accounts.get_by_sip_id(row.called)
-
- if not row.called_account:
- row["called_conference"] = self.get_conference(row.called)
- else:
- row["called_conference"] = None
-
- try:
- row["time"] = datetime.datetime.fromutctimestamp(row.time)
- except:
- pass
-
- result.append(row)
-
- return result
-
- def get_call_log(self, account, limit=25):
- if account:
- res = self.db.query("SELECT * FROM cdr WHERE (caller = %s OR called = %s) \
- ORDER BY time DESC LIMIT %s", account.sip_id, account.sip_id, limit)
- else:
- res = self.db.query("SELECT * FROM cdr ORDER BY time DESC LIMIT %s", limit)
-
- return self._process_cdr(res)
-
- def get_channels(self, account=None):
- channels = []
- for c in a.list_channels():
- if account and not account.sip_id in (c.caller, c.callee):
- continue
-
- channels.append(c)
-
- return sorted(channels)
-
- def get_channel(self, channel_id, account=None):
- channels = self.get_channels(account=account)
-
- for channel in channels:
- if channel.id == channel_id:
- return channel
-
- def get_ongoing_calls(self, account=None, sip_id=None):
- if account and sip_id is None:
- sip_id = account.sip_id
-
- # If the given account does not have a SIP ID,
- # we not need to search for any active sessions
- if sip_id is None:
- return []
-
- if sip_id:
- sip_id = "sip:%s@%%" % sip_id
-
- res = self.db.query("SELECT from_uri AS caller, \
- to_uri AS called, start_time AS time FROM dialog \
- WHERE from_uri LIKE %s OR to_uri LIKE %s ORDER BY time",
- sip_id, sip_id)
- else:
- res = self.db.query("SELECT from_uri AS caller, to_uri AS called, \
- start_time AS time FROM dialog ORDER BY time")
-
- return self._process_cdr(res, replace_sip_uris=True)
-
# Conferences
@property
+++ /dev/null
-{% extends "../base.html" %}
-
-{% block title %}{{ _("Conferences") }}{% end block %}
-
-{% block body %}
- <div class="page-header">
- <h3>{{ _("Conferences") }}</h3>
- </div>
-
- {% for conf in conferences %}
- <div class="well well-sm">
- <div class="btn-group pull-right">
- <a class="btn btn-default" href="/call/{{ conf.sip_id }}">
- <span class="glyphicon glyphicon-earphone"></span> {{ conf.sip_id }}
- </a>
- <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
- <span class="caret"></span>
- <span class="sr-only">{{ _("Toggle Dropdown") }}</span>
- </button>
- <ul class="dropdown-menu" role="menu">
- <li role="presentation" class="dropdown-header">{{ _("Invite participant") }}</li>
- {% for p in [p for p in conf.invitees if not current_user == p] %}
- <li>
- <a href="/conferences/{{ conf.sip_id }}/invite/{{ p.sip_id }}">
- <img src="{{ p.avatar_url(13) }}" alt="{{ p.name }}"> {{ p.name }}
- </a>
- </li>
- {% end %}
- </ul>
- </div>
-
- <h4>
- {{ _("IPFire Conference Room %s") % conf.no }}
- </h4>
-
- {% if conf.participants %}
- <hr>
-
- <ul class="list-unstyled">
- {% for p in conf.participants %}
- <li>
- {% if p.caller_account %}
- <img src="{{ p.caller_account.avatar_url(32) }}" alt="{{ p.caller_account.name }}" class="img-thumbnail">
- <a href="/phonebook/{{ p.caller_account.uid }}">{{ p.caller_account.name }}</a>
- {% else %}
- {{ p.caller }}
- {% end %}
- {{ _("joined %s") % locale.format_date(p.time, relative=True) }}
- </li>
- {% end %}
- </ul>
- {% end %}
- </div>
- {% end %}
-{% end block %}
+++ /dev/null
-{% extends "../base.html" %}
-
-{% block title %}{{ _("Hangup Channel") }}{% end block %}
-
-{% block body %}
- <form action="" method="POST">
- {% raw xsrf_form_html() %}
-
- <div class="row">
- <div class="col-md-4 col-md-offset-4">
- <div class="well well-sm ac">
- <h4>{{ _("Hangup Channel") }}</h4>
-
- <p>
- {{ _("You are about to hangup this channel") }}
- </p>
-
- <hr>
-
- <p>
- {% module TalkContact(channel.caller, name=channel.caller_name) %}
- </p>
-
- <p>
- <i class="glyphicon glyphicon-arrow-right text-success"></i>
- </p>
-
- <p>
- {% module TalkContact(channel.callee, application=channel.application) %}
- </p>
-
- <br>
-
- <input class="btn btn-danger btn-block" type="submit" value="{{ _("Hangup Channel") }}">
- </div>
- </div>
- </div>
- </form>
-{% end block %}
+++ /dev/null
-{% extends "../base.html" %}
-
-{% block title %}{{ _("Diagnosis") }}{% end block %}
-
-{% block body %}
- <div class="page-header">
- <h2>{{ _("Diagnosis") }}</h2>
- </div>
-
- {% module TalkOngoingCalls() %}
-
- {% module TalkLines(show_account=True) %}
-{% end block %}
+++ /dev/null
-{% extends "../base.html" %}
-
-{% block title %}{{ account.name }}{% end block %}
-
-{% block body %}
-<div class="container">
- <section class="features-content col-12">
- <h2 class="display-2 text-center">{{ account.name }}</h2>
-
- <div class="row mb-6">
- <div class="col-3">
- <img src="{{ account.avatar_url(243) }}" alt="{{ account.name }}" class="img-thumbnail">
- </div>
- <div class="col">
- {% if account.sip_id %}
- <h4>{{ _("Voice over IP") }}</h4>
-
- <ul class="list-unstyled">
- <li>
- <h4>
- {% if account.uses_sip_forwarding() %}
- <i class="fa fa-phone" aria-hidden="true"></i>
- <a href="/call/{{ account.sip_id }}">{{ account.sip_id }}</a>
- {% elif account.sip_is_online() %}
- <i class="fa fa-phone" aria-hidden="true"></i>
- <span class="text-success" title="{{ _("online") }}"></span>
- <a href="/call/{{ account.sip_id }}">{{ account.sip_id }}</a>
- {% else %}
- <i class="fa fa-phone" aria-hidden="true"></i>
- <span class="text-danger" title="{{ _("offline") }}"></span>
- {{ account.sip_id }}
- {% end %}
- {{ account.sip_id }}
- </h4>
- </li>
-
- <li>
- <small>
- <a href="sip:{{ account.sip_url }}">{{ account.sip_url }}</a>
- </small>
- </li>
-
- {% if account.sip_password and (current_user == account or current_user.is_admin()) %}
- <li>
- <small>
- {{ _("Password") }}: {{ account.sip_password }}
- </small>
- </li>
- {% end %}
- </ul>
- {% end %}
-
- {% if account.sip_id and account.email %}
- <hr>
- {% end %}
-
- {% if account.email %}
- <ul class="list-unstyled">
- <li>
- <i class="fa fa-envelope" aria-hidden="true"></i>
- <span class="glyphicon glyphicon-envelope" title="{{ _("Email") }}"></span>
- <a href="mailto:{{ account.email }}">{{ account.email }}</a>
- </li>
- <li>
- <span class="glyphicon glyphicon-comment" title="{{ _("XMPP") }}"></span>
- <a href="xmpp:{{ account.email }}">{{ account.email }}</a>
- </li>
- </ul>
- {% end %}
- </div>
-
- <div class="col">
- <h4>{{ _("Postal Address") }}</h4>
- <address>
- <strong>{{ account.name }}</strong><br>
- <a href="https://nominatim.openstreetmap.org/search?q={{ ", ".join(account.address.splitlines()) }}" target="_blank">
- {% for line in account.address.splitlines() %}
- {{ line }}<br>
- {% end %}
- </a>
- </address>
-
- {% if account.telephone_numbers %}
- <h4>{{ _("Telephone") }}</h4>
-
- <ul class="list-unstyled">
- {% for number in account.telephone_numbers %}
- <li>
- {% if number in account.mobile_telephone_numbers %}
- <span class="fa fa-mobile" title="{{ _("Mobile phone") }}"></span>
- {% elif number in account.home_telephone_numbers %}
- <span class="fa fa-home" title="{{ _("Home telephone") }}"></span>
- {% else %}
- <span class="fa fa-phone"></span>
- {% end %}
- <a href="tel:{{ number }}">{{ number }}</a>
- </li>
- {% end %}
- </ul>
- {% end %}
- </div>
-
- </div>
- <div class="row">
- <div class="col">
- {% if current_user.is_admin() and account.uses_sip_forwarding() %}
- <div class="alert alert-info" role="alert">
- {{ _("All calls are forwarded to:") }}
- <a href="sip:{{ account.sip_routing_url }}">{{ account.sip_routing_url }}</a>
- </div>
- {% end %}
-
- {% if current_user == account or current_user.is_admin() %}
- {% module TalkLines(account) %}
- {% module TalkOngoingCalls(account) %}
- {% module TalkCallLog(account) %}
- {% end %}
- </div>
- </div>
- </section>
-</div>
-{% end block %}
+++ /dev/null
-{% extends "../base.html" %}
-
-{% block title %}{{ _("Phonebook") }}{% end block %}
-
-{% block body %}
-
-<div class="container">
- <section class="features-content col-12">
- <h2 class="display-2 text-center">{{ _("Phonebook") }}</h2>
-
- <div class="row">
- <div class="col-12">
- <table class="table table-sm table-striped">
- <thead>
- <tr>
- <th scope="col">Name</th>
- <th scope="col">eMail</th>
- <th scope="col">Phone</th>
- <th scope="col">Avatar</th>
- </tr>
- </thead>
- <tbody>
- {% for e in phonebook %}
- <tr>
- <td><a href="/phonebook/{{ e.uid }}">{{ e.name }}</a></td>
- <td>
- <i class="fa fa-envelope" aria-hidden="true"></i> <a href="mailto:{{ e.email }}">{{ e.email }}</a></td>
- <td>
- {% if e.sip_id %}
- <i class="fa fa-phone" aria-hidden="true"></i>
- {% if e.uses_sip_forwarding() %}
- {{ e.sip_id }}
- {% elif e.sip_is_online() %}
- <a href="/call/{{ e.sip_id }}">{{ e.sip_id }}</a>
- {% else %}
- {{ e.sip_id }}
- {% end %}
- {% end %}
- </td>
- <td><a href="/phonebook/{{ e.uid }}"><img src="{{ e.avatar_url(64) }}" alt="{{ e.name }}"></a></td>
- </tr>
- {% end %}
- </tbody>
- </table>
- </div>
- </div>
- </section>
-</div>
-{% end block %}