mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-09 11:28:25 +00:00
Compare commits
6 Commits
18.26.0-rc
...
18.14.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb67c6b99 | ||
|
|
0f6b195fb2 | ||
|
|
bcd06ec179 | ||
|
|
28234b6b26 | ||
|
|
5dc6b85e5e | ||
|
|
5b0748cc3f |
1
.lastclean
Normal file
1
.lastclean
Normal file
@@ -0,0 +1 @@
|
||||
40
|
||||
28
CHANGES
28
CHANGES
@@ -16,6 +16,34 @@
|
||||
--- Functionality changes from Asterisk 18.13.0 to Asterisk 18.14.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
res_geolocation
|
||||
------------------
|
||||
* * Added processing for the 'confidence' element.
|
||||
* Added documentation to some APIs.
|
||||
* removed a lot of complex code related to the very-off-nominal
|
||||
case of needing to process multiple location info sources.
|
||||
* Create a new 'ast_geoloc_eprofile_to_pidf' API that just takes
|
||||
one eprofile instead of a datastore of multiples.
|
||||
* Plugged a huge leak in XML processing that arose from
|
||||
insufficient documentation by the libxml/libxslt authors.
|
||||
* Refactored stylesheets to be more efficient.
|
||||
* Renamed 'profile_action' to 'profile_precedence' to better
|
||||
reflect it's purpose.
|
||||
* Added the config option for 'allow_routing_use' which
|
||||
sets the value of the 'Geolocation-Routing' header.
|
||||
* Removed the GeolocProfileCreate and GeolocProfileDelete
|
||||
dialplan apps.
|
||||
* Changed the GEOLOC_PROFILE dialplan function as follows:
|
||||
* Removed the 'profile' argument.
|
||||
* Automatically create a profile if it doesn't exist.
|
||||
* Delete a profile if 'inheritable' is set to no.
|
||||
* Fixed various bugs and leaks
|
||||
* Updated Asterisk WiKi documentation.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 18.13.0 to Asterisk 18.14.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
chan_dahdi
|
||||
------------------
|
||||
* A POLARITY function is now available that allows
|
||||
|
||||
187
asterisk-18.14.0-summary.html
Normal file
187
asterisk-18.14.0-summary.html
Normal file
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-18.14.0</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-18.14.0</h3><h3 align="center">Date: 2022-08-18</h3><h3 align="center"><asteriskteam@digium.com></h3><hr><h2 align="center">Table of Contents</h2><ol>
|
||||
<li><a href="#summary">Summary</a></li>
|
||||
<li><a href="#contributors">Contributors</a></li>
|
||||
<li><a href="#closed_issues">Closed Issues</a></li>
|
||||
<li><a href="#commits">Other Changes</a></li>
|
||||
<li><a href="#diffstat">Diffstat</a></li>
|
||||
</ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version are strongly encouraged to review the UPGRADE.txt document as well as the CHANGES document for information about upgrading to this release series.</p><p>The data in this summary reflects changes that have been made since the previous release, asterisk-18.13.0.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were affected by commits that went into this release.</p><table width="100%" border="0">
|
||||
<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
|
||||
<tr valign="top"><td width="33%">16 Naveen Albert <asterisk@phreaknet.org><br/>6 George Joseph <gjoseph@digium.com><br/>4 Asterisk Development Team <asteriskteam@digium.com><br/>2 Boris P. Korzun <drtr0jan@yandex.ru><br/>1 Morvai Szabolcs<br/>1 Michael Neuhauser <mike@firmix.at><br/>1 Kevin Harwell <kharwell@sangoma.com><br/>1 Sam Banks <sam.banks.nz@gmail.com><br/>1 Sean Bright <sean@seanbright.com><br/>1 Trevor Peirce <trev@acrovoice.ca><br/>1 Joshua C. Colp <jcolp@sangoma.com><br/>1 Jose Lopes <jose.lopes@nfon.com><br/>1 Mike Bradeen <mbradeen@sangoma.com><br/>1 Stanislav Abramenkov <stas.abramenkov@gmail.com><br/>1 Sergey V. Lobanov <sergey@lobanov.in><br/></td><td width="33%"><td width="33%">15 N A <mail@interlinked.x10host.com><br/>4 George Joseph <gjoseph@digium.com><br/>2 Kevin Harwell <default.enum@gmail.com><br/>2 Boris P. Korzun <drtr0jan@yandex.ru><br/>1 Sergey V. Lobanov <sergey@lobanov.in><br/>1 Michael Neuhauser<br/>1 Sam Banks <sam.banks.nz@gmail.com><br/>1 José Lopes <josemslopes@gmail.com><br/>1 Sean Bright<br/>1 Michael Neuhauser <mike@firmix.at><br/>1 Joshua C. Colp <jcolp@digium.com><br/>1 Dmitry Melekhov <dm@belkam.com><br/>1 Morvai Szabolcs <smorvai@arenim.com><br/>1 Stanislav Abramenkov <stas.abramenkov@gmail.com><br/>1 Trevor Peirce <trev@digitalcon.ca><br/></td></tr>
|
||||
</table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Improvement</h3><h4>Category: General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30089">ASTERISK-30089</a>: general: fix typos<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0fe1a581e5978c444f67c9fbba6aab7ee1fa0d3e">[0fe1a581e5]</a> Naveen Albert -- general: Fix various typos.</li>
|
||||
</ul><br><h4>Category: Resources/res_geolocation</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30127">ASTERISK-30127</a>: Create core Geolocation capability for Asterisk<br/>Reported by: George Joseph<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f4913553848e906fd6dbaa9e8b514b739fb6311c">[f491355384]</a> George Joseph -- Geolocation: Core Capability Preview</li>
|
||||
</ul><br><h4>Category: Resources/res_pjsip_geolocation</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30128">ASTERISK-30128</a>: Create PJSIP interface module for Geolocation<br/>Reported by: George Joseph<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cdbd973ecdc49ff178b43b34180d005c21d06cbf">[cdbd973ecd]</a> George Joseph -- Geolocation: chan_pjsip Capability Preview</li>
|
||||
</ul><br><h4>Category: pjproject/pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30050">ASTERISK-30050</a>: Upgrade Asterisk to bundled pjproject 2.12.1<br/>Reported by: Stanislav Abramenkov<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2d500a090f44b4f145e018d2ff31ae821aace61e">[2d500a090f]</a> Stanislav Abramenkov -- pjsip: Upgrade bundled version to pjproject 2.12.1</li>
|
||||
</ul><br><h3>Bug</h3><h4>Category: Applications/app_confbridge</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29907">ASTERISK-29907</a>: res_pjsip, app_confbridge: Video call through ConfBridge with normal endpoints causes infinite loop/crash<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a4266030cea52f43193e96286ec249d2f1b6e02c">[a4266030ce]</a> Naveen Albert -- app_confbridge: Always set minimum video update interval.</li>
|
||||
</ul><br><h4>Category: Applications/app_dial</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29989">ASTERISK-29989</a>: app_dial, chan_dahdi: DIALSTATUS is inconsistent for busy<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8ce1b7db3c37f6992cce6b08420a8217afe3f2a6">[8ce1b7db3c]</a> Naveen Albert -- app_dial: Fix dial status regression.</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30115">ASTERISK-30115</a>: app_dial: Allow hook flashes to propogate on outbound dials<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0a636927168f45d4ff321baf1e4c807d128f34d8">[0a63692716]</a> Naveen Albert -- app_dial: Propagate outbound hook flashes.</li>
|
||||
</ul><br><h4>Category: CEL/cel_odbc</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30096">ASTERISK-30096</a>: cel_odbc: Column type 9 (field 'cdr:cel:eventtime') is unsupported at this time<br/>Reported by: Morvai Szabolcs<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=182fee79eb6708d6145cef6511f593cad04e4491">[182fee79eb]</a> Morvai Szabolcs -- cel_odbc & res_config_odbc: Add support for SQL_DATETIME field type</li>
|
||||
</ul><br><h4>Category: Channels/chan_dahdi</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29991">ASTERISK-29991</a>: chan_dahdi, callerid: Caller ID does not honor presentation<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8fddef679cd9a6269ae2fc2314af41a4c9e35062">[8fddef679c]</a> Naveen Albert -- chan_dahdi: Fix buggy and missing Caller ID parameters</li>
|
||||
</ul><br><h4>Category: Channels/chan_iax2</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30083">ASTERISK-30083</a>: chan_iax2: Optional dependency on openssl/res_crypto is now mandatory<br/>Reported by: Dmitry Melekhov<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1d3d6e49db1912ce8f39e538bf0bd9201227432f">[1d3d6e49db]</a> Naveen Albert -- chan_iax2: Allow compiling without OpenSSL.</li>
|
||||
</ul><br><h4>Category: Configs/Samples</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30126">ASTERISK-30126</a>: Spelling mistake in configs/samples/queues.conf.sample<br/>Reported by: Sam Banks<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=56c6d76a455cd7c15787ab41cc403bf7b7d4fc41">[56c6d76a45]</a> Sam Banks -- queues.conf.sample: Correction of typo</li>
|
||||
</ul><br><h4>Category: Core/BuildSystem</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30029">ASTERISK-30029</a>: build: Git security vulnerability fix is sad with our accessing git as root during "make install"<br/>Reported by: Joshua C. Colp<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7a82919256e661a4e8456e1d42d17e8567249036">[7a82919256]</a> Mike Bradeen -- Makefile: Avoid git-make user conflict</li>
|
||||
</ul><br><h4>Category: Core/CallerID</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29991">ASTERISK-29991</a>: chan_dahdi, callerid: Caller ID does not honor presentation<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8fddef679cd9a6269ae2fc2314af41a4c9e35062">[8fddef679c]</a> Naveen Albert -- chan_dahdi: Fix buggy and missing Caller ID parameters</li>
|
||||
</ul><br><h4>Category: Core/ManagerInterface</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30137">ASTERISK-30137</a>: manager: Global disabled event filtered is incomplete<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4580ac7ded4ef617fc3687bee5278d07c3f93b2c">[4580ac7ded]</a> Naveen Albert -- manager: Fix incomplete filtering of AMI events.</li>
|
||||
</ul><br><h4>Category: Features</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30123">ASTERISK-30123</a>: features: Update automixmon documentation to reflect reality<br/>Reported by: Trevor Peirce<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=dbace3334da1631e2d8d4e499ce409d48cff1aa2">[dbace3334d]</a> Trevor Peirce -- features: Update documentation for automon and automixmon</li>
|
||||
</ul><br><h4>Category: General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29905">ASTERISK-29905</a>: OSX: bininstall launchd issue on cross-platfrom build<br/>Reported by: Sergey V. Lobanov<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=133ecb346c36857c5e8ecc61dc4b70e51ff2a1a0">[133ecb346c]</a> Sergey V. Lobanov -- build: fix bininstall launchd issue on cross-platform build</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30001">ASTERISK-30001</a>: db: Removing nonexistent entries shows "Database entry removed"<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c9955d5fcdeb879edb24e1b165f730738b46c0e5">[c9955d5fcd]</a> Naveen Albert -- db: Notify user if deleted DB entry didn't exist.</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29822">ASTERISK-29822</a>: cli: Typing \? freezes the CLI permanently with remote console<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=57d66966a159a6e5af246a5266566c8300018a09">[57d66966a1]</a> Naveen Albert -- cli: Fix CLI blocking forever on terminating backslash</li>
|
||||
</ul><br><h4>Category: PBX/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29966">ASTERISK-29966</a>: pbx_variables: ast_str_strlen can be wrong<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a2799554d25d74eeb5dfb8bc8e52887fb27637fb">[a2799554d2]</a> Naveen Albert -- pbx_functions.c: Manually update ast_str strlen.</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30075">ASTERISK-30075</a>: say: Abort if channel hangs up during playback<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=93644fca5959e2c296dc9755c525da9f13eabc7e">[93644fca59]</a> Naveen Albert -- say: Abort play loop if caller hangs up.</li>
|
||||
</ul><br><h4>Category: PBX/pbx_lua</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30117">ASTERISK-30117</a>: pbx_lua: Remove compiler warnings<br/>Reported by: Boris P. Korzun<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d6ff560f20ca974a455b26f0060e0abd62a73eb6">[d6ff560f20]</a> Boris P. Korzun -- pbx_lua: Remove compiler warnings</li>
|
||||
</ul><br><h4>Category: Resources/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30101">ASTERISK-30101</a>: res_prometheus: Optional load res_pjsip_outbound_registration.so<br/>Reported by: Boris P. Korzun<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=22be2a28578954701ad658d777d2067b94981108">[22be2a2857]</a> Boris P. Korzun -- res_prometheus: Optional load res_pjsip_outbound_registration.so</li>
|
||||
</ul><br><h4>Category: Resources/res_calendar_icalendar</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30106">ASTERISK-30106</a>: res_calendar_icalendar: Microsoft online ICS calendars no longer work<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=53d921a19959018eaac1f98c59c6811d2a316294">[53d921a199]</a> Naveen Albert -- res_calendar_icalendar: Send user agent in request.</li>
|
||||
</ul><br><h4>Category: Resources/res_geolocation</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30167">ASTERISK-30167</a>: res_geolocation: Refactor for issues found by users<br/>Reported by: George Joseph<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=28234b6b26e72be3800357324054f04295ab4111">[28234b6b26]</a> George Joseph -- res_geolocation: Address user issues, remove complexity, plug leaks</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30138">ASTERISK-30138</a>: Compile failure in res_geolocation/geoloc_eprofile.c when optimization is enabled<br/>Reported by: George Joseph<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fcc3e7fac61b9e4b37b9f6710e0bfb3074b28242">[fcc3e7fac6]</a> George Joseph -- geoloc_eprofile.c: Fix setting of loc_src in set_loc_src()</li>
|
||||
</ul><br><h4>Category: Resources/res_http_websocket</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30099">ASTERISK-30099</a>: test_aeap_transport: transport_connect_fail sporadically causes failure<br/>Reported by: Kevin Harwell<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=512c711716a05d80acc9b1068f0ed537d18992bc">[512c711716]</a> Joshua C. Colp -- websocket / aeap: Handle poll() interruptions better.</li>
|
||||
</ul><br><h4>Category: Resources/res_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30109">ASTERISK-30109</a>: res_pjsip: no contact-status AMI event on register of prune-on-boot contact that uses the same URI as before Asterisk restart<br/>Reported by: Michael Neuhauser<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=75226a4b02027bf63ec222edec76a037c92703fb">[75226a4b02]</a> Michael Neuhauser -- res_pjsip: delay contact pruning on Asterisk start</li>
|
||||
</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30072">ASTERISK-30072</a>: res_pjsip: allow TLS verification of wildcard cert-bearing servers<br/>Reported by: Kevin Harwell<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0ddbf6bc453276d7d9affa84908465c3b204b49c">[0ddbf6bc45]</a> Kevin Harwell -- res_pjsip: allow TLS verification of wildcard cert-bearing servers</li>
|
||||
</ul><br><h4>Category: Tests/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30099">ASTERISK-30099</a>: test_aeap_transport: transport_connect_fail sporadically causes failure<br/>Reported by: Kevin Harwell<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=512c711716a05d80acc9b1068f0ed537d18992bc">[512c711716]</a> Joshua C. Colp -- websocket / aeap: Handle poll() interruptions better.</li>
|
||||
</ul><br><h3>New Feature</h3><h4>Category: Channels/chan_dahdi</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30000">ASTERISK-30000</a>: chan_dahdi: Add POLARITY function<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a78a82016d94881bfc38c33acd54b487020af029">[a78a82016d]</a> Naveen Albert -- chan_dahdi: Add POLARITY function.</li>
|
||||
</ul><br><h4>Category: Channels/chan_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29999">ASTERISK-29999</a>: pjsip: Get information from 200 OK INVITE reply headers<br/>Reported by: José Lopes<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b29a0e08a39abaa8539255738a55632d54a75dd8">[b29a0e08a3]</a> Jose Lopes -- res_pjsip_header_funcs: Add functions PJSIP_RESPONSE_HEADER and PJSIP_RESPONSE_HEADERS</li>
|
||||
</ul><br><h4>Category: Core/AstDB</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30136">ASTERISK-30136</a>: db: Add AMI action to retrieve all keys beginning with a prefix<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7bdab4e20695c37a9be22119624396391e21df05">[7bdab4e206]</a> Naveen Albert -- db: Add AMI action to retrieve DB keys at prefix.</li>
|
||||
</ul><br><h4>Category: PBX/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30061">ASTERISK-30061</a>: pbx: Add pbx helper application<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6720caa29ceeeeefd1c1640de0faa4394ff3e8b4">[6720caa29c]</a> Naveen Albert -- pbx: Add helper function to execute applications.</li>
|
||||
</ul><br><h4>Category: Resources/res_clioriginate</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30062">ASTERISK-30062</a>: cli: Add CLI command to execute a dialplan app<br/>Reported by: N A<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4adbdfde06bd3cdd8d737eea5abb8a740576cb1f">[4adbdfde06]</a> Naveen Albert -- res_cliexec: Add dialplan exec CLI command.</li>
|
||||
</ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
|
||||
<tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0f6b195fb2519e590a46d41930a44662926a7d7c">0f6b195fb2</a></td><td>Asterisk Development Team</td><td>Update for 18.14.0-rc2</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bcd06ec17999d74baf09c09a6fc731ab47ac7c54">bcd06ec179</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 18.14.0</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5dc6b85e5e860b93df4517b09817cb02ec06d69b">5dc6b85e5e</a></td><td>George Joseph</td><td>Geolocation: Wiki Documentation</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5b0748cc3f6ff8144efce572d2a8837dcb1a36e5">5b0748cc3f</a></td><td>Asterisk Development Team</td><td>Update for 18.14.0-rc1</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=57c4dc1721ee7f5c62772f04c1711f51da6cd1ee">57c4dc1721</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 18.14.0</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=35ebaed94d90fd86b7074f2cc48051be6d1efa2d">35ebaed94d</a></td><td>Sean Bright</td><td>pbx.c: Simplify ast_context memory management.</td></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1ed15e18156ab5e78769a3ba5defdcac7b546c2c">1ed15e1815</a></td><td>George Joseph</td><td>Geolocation: Base Asterisk Prereqs</td></tr>
|
||||
</table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>asterisk-18.13.0-summary.html | 149 -
|
||||
asterisk-18.13.0-summary.txt | 395 ---
|
||||
b/.version | 2
|
||||
b/CHANGES | 77
|
||||
b/ChangeLog | 665 +++++
|
||||
b/Makefile | 28
|
||||
b/Makefile.rules | 15
|
||||
b/apps/app_confbridge.c | 6
|
||||
b/apps/app_dial.c | 15
|
||||
b/apps/app_disa.c | 6
|
||||
b/apps/app_playback.c | 4
|
||||
b/asterisk-18.14.0-rc2-summary.html | 37
|
||||
b/asterisk-18.14.0-rc2-summary.txt | 122
|
||||
b/build_tools/make_version | 7
|
||||
b/cel/cel_odbc.c | 1
|
||||
b/channels/chan_dahdi.c | 131 +
|
||||
b/channels/chan_iax2.c | 4
|
||||
b/channels/iax2/include/iax2.h | 2
|
||||
b/channels/sig_analog.c | 27
|
||||
b/channels/sig_analog.h | 2
|
||||
b/configs/samples/geolocation.conf.sample | 274 ++
|
||||
b/configs/samples/iax.conf.sample | 2
|
||||
b/configs/samples/pjsip.conf.sample | 20
|
||||
b/configs/samples/queues.conf.sample | 2
|
||||
b/contrib/ast-db-manage/config/versions/58e440314c2a_allow_wildcard_certs.py | 29
|
||||
b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py | 22
|
||||
b/contrib/realtime/mysql/mysql_config.sql | 14
|
||||
b/contrib/realtime/postgresql/postgresql_config.sql | 14
|
||||
b/funcs/func_logic.c | 4
|
||||
b/include/asterisk/astdb.h | 11
|
||||
b/include/asterisk/callerid.h | 51
|
||||
b/include/asterisk/config.h | 20
|
||||
b/include/asterisk/pbx.h | 39
|
||||
b/include/asterisk/res_geolocation.h | 397 +++
|
||||
b/include/asterisk/res_pjsip.h | 26
|
||||
b/include/asterisk/strings.h | 18
|
||||
b/include/asterisk/test.h | 2
|
||||
b/include/asterisk/xml.h | 24
|
||||
b/main/asterisk.c | 23
|
||||
b/main/bridge.c | 2
|
||||
b/main/bridge_channel.c | 18
|
||||
b/main/callerid.c | 98
|
||||
b/main/channel.c | 2
|
||||
b/main/config.c | 28
|
||||
b/main/datastore.c | 4
|
||||
b/main/db.c | 124
|
||||
b/main/dial.c | 10
|
||||
b/main/features.c | 7
|
||||
b/main/features_config.c | 26
|
||||
b/main/manager.c | 23
|
||||
b/main/pbx.c | 97
|
||||
b/main/pbx_app.c | 25
|
||||
b/main/pbx_builtins.c | 9
|
||||
b/main/pbx_functions.c | 1
|
||||
b/main/pbx_variables.c | 127 -
|
||||
b/main/say.c | 12
|
||||
b/main/utils.c | 61
|
||||
b/main/xml.c | 35
|
||||
b/makeopts.in | 2
|
||||
b/pbx/pbx_lua.c | 17
|
||||
b/res/Makefile | 5
|
||||
b/res/res_aeap/transport_websocket.c | 7
|
||||
b/res/res_calendar_icalendar.c | 1
|
||||
b/res/res_cliexec.c | 160 +
|
||||
b/res/res_config_odbc.c | 1
|
||||
b/res/res_geolocation.c | 125
|
||||
b/res/res_geolocation.exports.in | 6
|
||||
b/res/res_geolocation/eprofile_to_pidf.xslt | 232 +
|
||||
b/res/res_geolocation/geoloc_civicaddr.c | 151 +
|
||||
b/res/res_geolocation/geoloc_common.c | 36
|
||||
b/res/res_geolocation/geoloc_config.c | 650 +++++
|
||||
b/res/res_geolocation/geoloc_datastore.c | 325 ++
|
||||
b/res/res_geolocation/geoloc_dialplan.c | 280 ++
|
||||
b/res/res_geolocation/geoloc_doc.xml | 258 ++
|
||||
b/res/res_geolocation/geoloc_eprofile.c | 1257 ++++++++++
|
||||
b/res/res_geolocation/geoloc_gml.c | 367 ++
|
||||
b/res/res_geolocation/geoloc_private.h | 158 +
|
||||
b/res/res_geolocation/pidf_lo_test.xml | 33
|
||||
b/res/res_geolocation/pidf_to_eprofile.xslt | 213 +
|
||||
b/res/res_geolocation/wiki/AsteriskImplementation.md | 183 +
|
||||
b/res/res_geolocation/wiki/CivicAddress.md | 167 +
|
||||
b/res/res_geolocation/wiki/GML.md | 60
|
||||
b/res/res_geolocation/wiki/Geolocation.md | 74
|
||||
b/res/res_geolocation/wiki/ReferenceInformation.md | 33
|
||||
b/res/res_geolocation/wiki/URI.md | 86
|
||||
b/res/res_http_websocket.c | 20
|
||||
b/res/res_mutestream.c | 2
|
||||
b/res/res_pjsip.c | 27
|
||||
b/res/res_pjsip/config_transport.c | 31
|
||||
b/res/res_pjsip/pjsip_config.xml | 30
|
||||
b/res/res_pjsip/pjsip_configuration.c | 41
|
||||
b/res/res_pjsip/pjsip_transport_events.c | 122
|
||||
b/res/res_pjsip_geolocation.c | 658 +++++
|
||||
b/res/res_pjsip_header_funcs.c | 254 +-
|
||||
b/res/res_prometheus.c | 12
|
||||
b/res/res_stasis_snoop.c | 8
|
||||
b/res/res_tonedetect.c | 2
|
||||
b/tests/test_aeap_transport.c | 17
|
||||
b/tests/test_config.c | 4
|
||||
b/tests/test_strings.c | 124
|
||||
100 files changed, 8827 insertions(+), 808 deletions(-)</pre><br></html>
|
||||
455
asterisk-18.14.0-summary.txt
Normal file
455
asterisk-18.14.0-summary.txt
Normal file
@@ -0,0 +1,455 @@
|
||||
Release Summary
|
||||
|
||||
asterisk-18.14.0
|
||||
|
||||
Date: 2022-08-18
|
||||
|
||||
<asteriskteam@digium.com>
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Summary
|
||||
2. Contributors
|
||||
3. Closed Issues
|
||||
4. Other Changes
|
||||
5. Diffstat
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Summary
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This release is a point release of an existing major version. The changes
|
||||
included were made to address problems that have been identified in this
|
||||
release series, or are minor, backwards compatible new features or
|
||||
improvements. Users should be able to safely upgrade to this version if
|
||||
this release series is already in use. Users considering upgrading from a
|
||||
previous version are strongly encouraged to review the UPGRADE.txt
|
||||
document as well as the CHANGES document for information about upgrading
|
||||
to this release series.
|
||||
|
||||
The data in this summary reflects changes that have been made since the
|
||||
previous release, asterisk-18.13.0.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Contributors
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This table lists the people who have submitted code, those that have
|
||||
tested patches, as well as those that reported issues on the issue tracker
|
||||
that were resolved in this release. For coders, the number is how many of
|
||||
their patches (of any size) were committed into this release. For testers,
|
||||
the number is the number of times their name was listed as assisting with
|
||||
testing a patch. Finally, for reporters, the number is the number of
|
||||
issues that they reported that were affected by commits that went into
|
||||
this release.
|
||||
|
||||
Coders Testers Reporters
|
||||
16 Naveen Albert 15 N A
|
||||
6 George Joseph 4 George Joseph
|
||||
4 Asterisk Development Team 2 Kevin Harwell
|
||||
2 Boris P. Korzun 2 Boris P. Korzun
|
||||
1 Morvai Szabolcs 1 Sergey V. Lobanov
|
||||
1 Michael Neuhauser 1 Michael Neuhauser
|
||||
1 Kevin Harwell 1 Sam Banks
|
||||
1 Sam Banks 1 José Lopes
|
||||
1 Sean Bright 1 Sean Bright
|
||||
1 Trevor Peirce 1 Michael Neuhauser
|
||||
1 Joshua C. Colp 1 Joshua C. Colp
|
||||
1 Jose Lopes 1 Dmitry Melekhov
|
||||
1 Mike Bradeen 1 Morvai Szabolcs
|
||||
1 Stanislav Abramenkov 1 Stanislav Abramenkov
|
||||
1 Sergey V. Lobanov 1 Trevor Peirce
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Closed Issues
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all issues from the issue tracker that were closed by
|
||||
changes that went into this release.
|
||||
|
||||
Improvement
|
||||
|
||||
Category: General
|
||||
|
||||
ASTERISK-30089: general: fix typos
|
||||
Reported by: N A
|
||||
* [0fe1a581e5] Naveen Albert -- general: Fix various typos.
|
||||
|
||||
Category: Resources/res_geolocation
|
||||
|
||||
ASTERISK-30127: Create core Geolocation capability for Asterisk
|
||||
Reported by: George Joseph
|
||||
* [f491355384] George Joseph -- Geolocation: Core Capability Preview
|
||||
|
||||
Category: Resources/res_pjsip_geolocation
|
||||
|
||||
ASTERISK-30128: Create PJSIP interface module for Geolocation
|
||||
Reported by: George Joseph
|
||||
* [cdbd973ecd] George Joseph -- Geolocation: chan_pjsip Capability
|
||||
Preview
|
||||
|
||||
Category: pjproject/pjsip
|
||||
|
||||
ASTERISK-30050: Upgrade Asterisk to bundled pjproject 2.12.1
|
||||
Reported by: Stanislav Abramenkov
|
||||
* [2d500a090f] Stanislav Abramenkov -- pjsip: Upgrade bundled version to
|
||||
pjproject 2.12.1
|
||||
|
||||
Bug
|
||||
|
||||
Category: Applications/app_confbridge
|
||||
|
||||
ASTERISK-29907: res_pjsip, app_confbridge: Video call through ConfBridge
|
||||
with normal endpoints causes infinite loop/crash
|
||||
Reported by: N A
|
||||
* [a4266030ce] Naveen Albert -- app_confbridge: Always set minimum video
|
||||
update interval.
|
||||
|
||||
Category: Applications/app_dial
|
||||
|
||||
ASTERISK-29989: app_dial, chan_dahdi: DIALSTATUS is inconsistent for busy
|
||||
Reported by: N A
|
||||
* [8ce1b7db3c] Naveen Albert -- app_dial: Fix dial status regression.
|
||||
ASTERISK-30115: app_dial: Allow hook flashes to propogate on outbound
|
||||
dials
|
||||
Reported by: N A
|
||||
* [0a63692716] Naveen Albert -- app_dial: Propagate outbound hook
|
||||
flashes.
|
||||
|
||||
Category: CEL/cel_odbc
|
||||
|
||||
ASTERISK-30096: cel_odbc: Column type 9 (field 'cdr:cel:eventtime') is
|
||||
unsupported at this time
|
||||
Reported by: Morvai Szabolcs
|
||||
* [182fee79eb] Morvai Szabolcs -- cel_odbc & res_config_odbc: Add
|
||||
support for SQL_DATETIME field type
|
||||
|
||||
Category: Channels/chan_dahdi
|
||||
|
||||
ASTERISK-29991: chan_dahdi, callerid: Caller ID does not honor
|
||||
presentation
|
||||
Reported by: N A
|
||||
* [8fddef679c] Naveen Albert -- chan_dahdi: Fix buggy and missing Caller
|
||||
ID parameters
|
||||
|
||||
Category: Channels/chan_iax2
|
||||
|
||||
ASTERISK-30083: chan_iax2: Optional dependency on openssl/res_crypto is
|
||||
now mandatory
|
||||
Reported by: Dmitry Melekhov
|
||||
* [1d3d6e49db] Naveen Albert -- chan_iax2: Allow compiling without
|
||||
OpenSSL.
|
||||
|
||||
Category: Configs/Samples
|
||||
|
||||
ASTERISK-30126: Spelling mistake in configs/samples/queues.conf.sample
|
||||
Reported by: Sam Banks
|
||||
* [56c6d76a45] Sam Banks -- queues.conf.sample: Correction of typo
|
||||
|
||||
Category: Core/BuildSystem
|
||||
|
||||
ASTERISK-30029: build: Git security vulnerability fix is sad with our
|
||||
accessing git as root during "make install"
|
||||
Reported by: Joshua C. Colp
|
||||
* [7a82919256] Mike Bradeen -- Makefile: Avoid git-make user conflict
|
||||
|
||||
Category: Core/CallerID
|
||||
|
||||
ASTERISK-29991: chan_dahdi, callerid: Caller ID does not honor
|
||||
presentation
|
||||
Reported by: N A
|
||||
* [8fddef679c] Naveen Albert -- chan_dahdi: Fix buggy and missing Caller
|
||||
ID parameters
|
||||
|
||||
Category: Core/ManagerInterface
|
||||
|
||||
ASTERISK-30137: manager: Global disabled event filtered is incomplete
|
||||
Reported by: N A
|
||||
* [4580ac7ded] Naveen Albert -- manager: Fix incomplete filtering of AMI
|
||||
events.
|
||||
|
||||
Category: Features
|
||||
|
||||
ASTERISK-30123: features: Update automixmon documentation to reflect
|
||||
reality
|
||||
Reported by: Trevor Peirce
|
||||
* [dbace3334d] Trevor Peirce -- features: Update documentation for
|
||||
automon and automixmon
|
||||
|
||||
Category: General
|
||||
|
||||
ASTERISK-29905: OSX: bininstall launchd issue on cross-platfrom build
|
||||
Reported by: Sergey V. Lobanov
|
||||
* [133ecb346c] Sergey V. Lobanov -- build: fix bininstall launchd issue
|
||||
on cross-platform build
|
||||
ASTERISK-30001: db: Removing nonexistent entries shows "Database entry
|
||||
removed"
|
||||
Reported by: N A
|
||||
* [c9955d5fcd] Naveen Albert -- db: Notify user if deleted DB entry
|
||||
didn't exist.
|
||||
ASTERISK-29822: cli: Typing \? freezes the CLI permanently with remote
|
||||
console
|
||||
Reported by: N A
|
||||
* [57d66966a1] Naveen Albert -- cli: Fix CLI blocking forever on
|
||||
terminating backslash
|
||||
|
||||
Category: PBX/General
|
||||
|
||||
ASTERISK-29966: pbx_variables: ast_str_strlen can be wrong
|
||||
Reported by: N A
|
||||
* [a2799554d2] Naveen Albert -- pbx_functions.c: Manually update ast_str
|
||||
strlen.
|
||||
ASTERISK-30075: say: Abort if channel hangs up during playback
|
||||
Reported by: N A
|
||||
* [93644fca59] Naveen Albert -- say: Abort play loop if caller hangs up.
|
||||
|
||||
Category: PBX/pbx_lua
|
||||
|
||||
ASTERISK-30117: pbx_lua: Remove compiler warnings
|
||||
Reported by: Boris P. Korzun
|
||||
* [d6ff560f20] Boris P. Korzun -- pbx_lua: Remove compiler warnings
|
||||
|
||||
Category: Resources/General
|
||||
|
||||
ASTERISK-30101: res_prometheus: Optional load
|
||||
res_pjsip_outbound_registration.so
|
||||
Reported by: Boris P. Korzun
|
||||
* [22be2a2857] Boris P. Korzun -- res_prometheus: Optional load
|
||||
res_pjsip_outbound_registration.so
|
||||
|
||||
Category: Resources/res_calendar_icalendar
|
||||
|
||||
ASTERISK-30106: res_calendar_icalendar: Microsoft online ICS calendars no
|
||||
longer work
|
||||
Reported by: N A
|
||||
* [53d921a199] Naveen Albert -- res_calendar_icalendar: Send user agent
|
||||
in request.
|
||||
|
||||
Category: Resources/res_geolocation
|
||||
|
||||
ASTERISK-30167: res_geolocation: Refactor for issues found by users
|
||||
Reported by: George Joseph
|
||||
* [28234b6b26] George Joseph -- res_geolocation: Address user issues,
|
||||
remove complexity, plug leaks
|
||||
ASTERISK-30138: Compile failure in res_geolocation/geoloc_eprofile.c when
|
||||
optimization is enabled
|
||||
Reported by: George Joseph
|
||||
* [fcc3e7fac6] George Joseph -- geoloc_eprofile.c: Fix setting of
|
||||
loc_src in set_loc_src()
|
||||
|
||||
Category: Resources/res_http_websocket
|
||||
|
||||
ASTERISK-30099: test_aeap_transport: transport_connect_fail sporadically
|
||||
causes failure
|
||||
Reported by: Kevin Harwell
|
||||
* [512c711716] Joshua C. Colp -- websocket / aeap: Handle poll()
|
||||
interruptions better.
|
||||
|
||||
Category: Resources/res_pjsip
|
||||
|
||||
ASTERISK-30109: res_pjsip: no contact-status AMI event on register of
|
||||
prune-on-boot contact that uses the same URI as before Asterisk restart
|
||||
Reported by: Michael Neuhauser
|
||||
* [75226a4b02] Michael Neuhauser -- res_pjsip: delay contact pruning on
|
||||
Asterisk start
|
||||
ASTERISK-30072: res_pjsip: allow TLS verification of wildcard cert-bearing
|
||||
servers
|
||||
Reported by: Kevin Harwell
|
||||
* [0ddbf6bc45] Kevin Harwell -- res_pjsip: allow TLS verification of
|
||||
wildcard cert-bearing servers
|
||||
|
||||
Category: Tests/General
|
||||
|
||||
ASTERISK-30099: test_aeap_transport: transport_connect_fail sporadically
|
||||
causes failure
|
||||
Reported by: Kevin Harwell
|
||||
* [512c711716] Joshua C. Colp -- websocket / aeap: Handle poll()
|
||||
interruptions better.
|
||||
|
||||
New Feature
|
||||
|
||||
Category: Channels/chan_dahdi
|
||||
|
||||
ASTERISK-30000: chan_dahdi: Add POLARITY function
|
||||
Reported by: N A
|
||||
* [a78a82016d] Naveen Albert -- chan_dahdi: Add POLARITY function.
|
||||
|
||||
Category: Channels/chan_pjsip
|
||||
|
||||
ASTERISK-29999: pjsip: Get information from 200 OK INVITE reply headers
|
||||
Reported by: José Lopes
|
||||
* [b29a0e08a3] Jose Lopes -- res_pjsip_header_funcs: Add functions
|
||||
PJSIP_RESPONSE_HEADER and PJSIP_RESPONSE_HEADERS
|
||||
|
||||
Category: Core/AstDB
|
||||
|
||||
ASTERISK-30136: db: Add AMI action to retrieve all keys beginning with a
|
||||
prefix
|
||||
Reported by: N A
|
||||
* [7bdab4e206] Naveen Albert -- db: Add AMI action to retrieve DB keys
|
||||
at prefix.
|
||||
|
||||
Category: PBX/General
|
||||
|
||||
ASTERISK-30061: pbx: Add pbx helper application
|
||||
Reported by: N A
|
||||
* [6720caa29c] Naveen Albert -- pbx: Add helper function to execute
|
||||
applications.
|
||||
|
||||
Category: Resources/res_clioriginate
|
||||
|
||||
ASTERISK-30062: cli: Add CLI command to execute a dialplan app
|
||||
Reported by: N A
|
||||
* [4adbdfde06] Naveen Albert -- res_cliexec: Add dialplan exec CLI
|
||||
command.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Commits Not Associated with an Issue
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all changes that went into this release that did not
|
||||
reference a JIRA issue.
|
||||
|
||||
+------------------------------------------------------------------------+
|
||||
| Revision | Author | Summary |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 0f6b195fb2 | Asterisk Development | Update for 18.14.0-rc2 |
|
||||
| | Team | |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| bcd06ec179 | Asterisk Development | Update CHANGES and UPGRADE.txt for |
|
||||
| | Team | 18.14.0 |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 5dc6b85e5e | George Joseph | Geolocation: Wiki Documentation |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 5b0748cc3f | Asterisk Development | Update for 18.14.0-rc1 |
|
||||
| | Team | |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 57c4dc1721 | Asterisk Development | Update CHANGES and UPGRADE.txt for |
|
||||
| | Team | 18.14.0 |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 35ebaed94d | Sean Bright | pbx.c: Simplify ast_context memory |
|
||||
| | | management. |
|
||||
|------------+----------------------+------------------------------------|
|
||||
| 1ed15e1815 | George Joseph | Geolocation: Base Asterisk Prereqs |
|
||||
+------------------------------------------------------------------------+
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Diffstat Results
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a summary of the changes to the source code that went into this
|
||||
release that was generated using the diffstat utility.
|
||||
|
||||
asterisk-18.13.0-summary.html | 149 -
|
||||
asterisk-18.13.0-summary.txt | 395 ---
|
||||
b/.version | 2
|
||||
b/CHANGES | 77
|
||||
b/ChangeLog | 665 +++++
|
||||
b/Makefile | 28
|
||||
b/Makefile.rules | 15
|
||||
b/apps/app_confbridge.c | 6
|
||||
b/apps/app_dial.c | 15
|
||||
b/apps/app_disa.c | 6
|
||||
b/apps/app_playback.c | 4
|
||||
b/asterisk-18.14.0-rc2-summary.html | 37
|
||||
b/asterisk-18.14.0-rc2-summary.txt | 122
|
||||
b/build_tools/make_version | 7
|
||||
b/cel/cel_odbc.c | 1
|
||||
b/channels/chan_dahdi.c | 131 +
|
||||
b/channels/chan_iax2.c | 4
|
||||
b/channels/iax2/include/iax2.h | 2
|
||||
b/channels/sig_analog.c | 27
|
||||
b/channels/sig_analog.h | 2
|
||||
b/configs/samples/geolocation.conf.sample | 274 ++
|
||||
b/configs/samples/iax.conf.sample | 2
|
||||
b/configs/samples/pjsip.conf.sample | 20
|
||||
b/configs/samples/queues.conf.sample | 2
|
||||
b/contrib/ast-db-manage/config/versions/58e440314c2a_allow_wildcard_certs.py | 29
|
||||
b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py | 22
|
||||
b/contrib/realtime/mysql/mysql_config.sql | 14
|
||||
b/contrib/realtime/postgresql/postgresql_config.sql | 14
|
||||
b/funcs/func_logic.c | 4
|
||||
b/include/asterisk/astdb.h | 11
|
||||
b/include/asterisk/callerid.h | 51
|
||||
b/include/asterisk/config.h | 20
|
||||
b/include/asterisk/pbx.h | 39
|
||||
b/include/asterisk/res_geolocation.h | 397 +++
|
||||
b/include/asterisk/res_pjsip.h | 26
|
||||
b/include/asterisk/strings.h | 18
|
||||
b/include/asterisk/test.h | 2
|
||||
b/include/asterisk/xml.h | 24
|
||||
b/main/asterisk.c | 23
|
||||
b/main/bridge.c | 2
|
||||
b/main/bridge_channel.c | 18
|
||||
b/main/callerid.c | 98
|
||||
b/main/channel.c | 2
|
||||
b/main/config.c | 28
|
||||
b/main/datastore.c | 4
|
||||
b/main/db.c | 124
|
||||
b/main/dial.c | 10
|
||||
b/main/features.c | 7
|
||||
b/main/features_config.c | 26
|
||||
b/main/manager.c | 23
|
||||
b/main/pbx.c | 97
|
||||
b/main/pbx_app.c | 25
|
||||
b/main/pbx_builtins.c | 9
|
||||
b/main/pbx_functions.c | 1
|
||||
b/main/pbx_variables.c | 127 -
|
||||
b/main/say.c | 12
|
||||
b/main/utils.c | 61
|
||||
b/main/xml.c | 35
|
||||
b/makeopts.in | 2
|
||||
b/pbx/pbx_lua.c | 17
|
||||
b/res/Makefile | 5
|
||||
b/res/res_aeap/transport_websocket.c | 7
|
||||
b/res/res_calendar_icalendar.c | 1
|
||||
b/res/res_cliexec.c | 160 +
|
||||
b/res/res_config_odbc.c | 1
|
||||
b/res/res_geolocation.c | 125
|
||||
b/res/res_geolocation.exports.in | 6
|
||||
b/res/res_geolocation/eprofile_to_pidf.xslt | 232 +
|
||||
b/res/res_geolocation/geoloc_civicaddr.c | 151 +
|
||||
b/res/res_geolocation/geoloc_common.c | 36
|
||||
b/res/res_geolocation/geoloc_config.c | 650 +++++
|
||||
b/res/res_geolocation/geoloc_datastore.c | 325 ++
|
||||
b/res/res_geolocation/geoloc_dialplan.c | 280 ++
|
||||
b/res/res_geolocation/geoloc_doc.xml | 258 ++
|
||||
b/res/res_geolocation/geoloc_eprofile.c | 1257 ++++++++++
|
||||
b/res/res_geolocation/geoloc_gml.c | 367 ++
|
||||
b/res/res_geolocation/geoloc_private.h | 158 +
|
||||
b/res/res_geolocation/pidf_lo_test.xml | 33
|
||||
b/res/res_geolocation/pidf_to_eprofile.xslt | 213 +
|
||||
b/res/res_geolocation/wiki/AsteriskImplementation.md | 183 +
|
||||
b/res/res_geolocation/wiki/CivicAddress.md | 167 +
|
||||
b/res/res_geolocation/wiki/GML.md | 60
|
||||
b/res/res_geolocation/wiki/Geolocation.md | 74
|
||||
b/res/res_geolocation/wiki/ReferenceInformation.md | 33
|
||||
b/res/res_geolocation/wiki/URI.md | 86
|
||||
b/res/res_http_websocket.c | 20
|
||||
b/res/res_mutestream.c | 2
|
||||
b/res/res_pjsip.c | 27
|
||||
b/res/res_pjsip/config_transport.c | 31
|
||||
b/res/res_pjsip/pjsip_config.xml | 30
|
||||
b/res/res_pjsip/pjsip_configuration.c | 41
|
||||
b/res/res_pjsip/pjsip_transport_events.c | 122
|
||||
b/res/res_pjsip_geolocation.c | 658 +++++
|
||||
b/res/res_pjsip_header_funcs.c | 254 +-
|
||||
b/res/res_prometheus.c | 12
|
||||
b/res/res_stasis_snoop.c | 8
|
||||
b/res/res_tonedetect.c | 2
|
||||
b/tests/test_aeap_transport.c | 17
|
||||
b/tests/test_config.c | 4
|
||||
b/tests/test_strings.c | 124
|
||||
100 files changed, 8827 insertions(+), 808 deletions(-)
|
||||
@@ -134,14 +134,24 @@ allowed. See RFC8787.
|
||||
Example:
|
||||
location_source = sip1.myserver.net
|
||||
|
||||
-- confidence (optional) -----------------------------------------
|
||||
The confidence in the location specified.
|
||||
confidence = pdf=[ unknown | normal | rectangular ], value=<percent_confident>
|
||||
|
||||
Please see RFC7459 for the exact description of this parameter.
|
||||
|
||||
Example:
|
||||
confidence = pdf=normal, value=75
|
||||
|
||||
|
||||
-- Location Example ---------------------------------------------------
|
||||
|
||||
[mylocation]
|
||||
type = location
|
||||
format = civicAddress
|
||||
location_info = country=US
|
||||
location_info = A1="New York", A3="New York", A4=Manhattan
|
||||
location_info = HNO=1633, PRD=W, RD=46th, STS=Street
|
||||
location_info = A1="New York", A3="New York", A4=Manhattan
|
||||
location_info = HNO=1633, PRD=W, RD=46th, STS=Street
|
||||
location_info = PC=10222
|
||||
method = Manual
|
||||
location_source = sip1.myserver.net
|
||||
@@ -160,9 +170,9 @@ location_source = sip1.myserver.net
|
||||
Defines the object type.
|
||||
type = profile
|
||||
|
||||
-- profile_action (optional) ------------------------------------------
|
||||
-- profile_precedence (optional) ------------------------------------------
|
||||
Sets how to reconcile incoming and configured profiles.
|
||||
profile_action = < prefer_incoming | prefer_config | discard_incoming
|
||||
profile_precedence = < prefer_incoming | prefer_config | discard_incoming
|
||||
| discard_config >
|
||||
|
||||
On an incoming call leg, "incoming" is the location description
|
||||
@@ -188,7 +198,7 @@ discard_config: Discard any configured location description. If
|
||||
discard_incoming is the default.
|
||||
|
||||
Example:
|
||||
profile_action = prefer_config
|
||||
profile_precedence = prefer_config
|
||||
|
||||
-- pidf_element (optional) --------------------------------------------
|
||||
PIDF-LO element in which to place the location description.
|
||||
@@ -207,10 +217,10 @@ Per [RFC5491], "device" is preferred and therefore the default.
|
||||
Example:
|
||||
pidf_element = tuple
|
||||
|
||||
-- geolocation_routing (optional) -------------------------------------
|
||||
-- allow_routing_use (optional) -------------------------------------
|
||||
Sets whether the "Geolocation-Routing" header is added to outgoing
|
||||
requests.
|
||||
geolocation_routing = < yes | no >
|
||||
allow_routing_use = < yes | no >
|
||||
|
||||
Set to "yes" to indicate that servers later in the path
|
||||
can use the location information for routing purposes. Set to "no"
|
||||
@@ -218,7 +228,7 @@ if they should not. If this value isn't specified, no
|
||||
"Geolocation-Routing" header will be added.
|
||||
|
||||
Example:
|
||||
geolocation_routing = yes
|
||||
allow_routing_use = yes
|
||||
|
||||
-- location_reference (optional) --------------------------------------
|
||||
The name of an existing Location object.
|
||||
|
||||
41
contrib/realtime/mysql/mysql_cdr.sql
Normal file
41
contrib/realtime/mysql/mysql_cdr.sql
Normal file
@@ -0,0 +1,41 @@
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> 210693f3123d
|
||||
|
||||
CREATE TABLE cdr (
|
||||
accountcode VARCHAR(20),
|
||||
src VARCHAR(80),
|
||||
dst VARCHAR(80),
|
||||
dcontext VARCHAR(80),
|
||||
clid VARCHAR(80),
|
||||
channel VARCHAR(80),
|
||||
dstchannel VARCHAR(80),
|
||||
lastapp VARCHAR(80),
|
||||
lastdata VARCHAR(80),
|
||||
start DATETIME,
|
||||
answer DATETIME,
|
||||
end DATETIME,
|
||||
duration INTEGER,
|
||||
billsec INTEGER,
|
||||
disposition VARCHAR(45),
|
||||
amaflags VARCHAR(45),
|
||||
userfield VARCHAR(256),
|
||||
uniqueid VARCHAR(150),
|
||||
linkedid VARCHAR(150),
|
||||
peeraccount VARCHAR(20),
|
||||
sequence INTEGER
|
||||
);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
|
||||
|
||||
-- Running upgrade 210693f3123d -> 54cde9847798
|
||||
|
||||
ALTER TABLE cdr MODIFY accountcode VARCHAR(80) NULL;
|
||||
|
||||
ALTER TABLE cdr MODIFY peeraccount VARCHAR(80) NULL;
|
||||
|
||||
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';
|
||||
|
||||
1362
contrib/realtime/mysql/mysql_config.sql
Normal file
1362
contrib/realtime/mysql/mysql_config.sql
Normal file
File diff suppressed because it is too large
Load Diff
35
contrib/realtime/mysql/mysql_voicemail.sql
Normal file
35
contrib/realtime/mysql/mysql_voicemail.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> a2e9769475e
|
||||
|
||||
CREATE TABLE voicemail_messages (
|
||||
dir VARCHAR(255) NOT NULL,
|
||||
msgnum INTEGER NOT NULL,
|
||||
context VARCHAR(80),
|
||||
macrocontext VARCHAR(80),
|
||||
callerid VARCHAR(80),
|
||||
origtime INTEGER,
|
||||
duration INTEGER,
|
||||
recording BLOB,
|
||||
flag VARCHAR(30),
|
||||
category VARCHAR(30),
|
||||
mailboxuser VARCHAR(30),
|
||||
mailboxcontext VARCHAR(30),
|
||||
msg_id VARCHAR(40)
|
||||
);
|
||||
|
||||
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
|
||||
|
||||
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
|
||||
|
||||
-- Running upgrade a2e9769475e -> 39428242f7f5
|
||||
|
||||
ALTER TABLE voicemail_messages MODIFY recording BLOB(4294967295) NULL;
|
||||
|
||||
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';
|
||||
|
||||
45
contrib/realtime/postgresql/postgresql_cdr.sql
Normal file
45
contrib/realtime/postgresql/postgresql_cdr.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> 210693f3123d
|
||||
|
||||
CREATE TABLE cdr (
|
||||
accountcode VARCHAR(20),
|
||||
src VARCHAR(80),
|
||||
dst VARCHAR(80),
|
||||
dcontext VARCHAR(80),
|
||||
clid VARCHAR(80),
|
||||
channel VARCHAR(80),
|
||||
dstchannel VARCHAR(80),
|
||||
lastapp VARCHAR(80),
|
||||
lastdata VARCHAR(80),
|
||||
start TIMESTAMP WITHOUT TIME ZONE,
|
||||
answer TIMESTAMP WITHOUT TIME ZONE,
|
||||
"end" TIMESTAMP WITHOUT TIME ZONE,
|
||||
duration INTEGER,
|
||||
billsec INTEGER,
|
||||
disposition VARCHAR(45),
|
||||
amaflags VARCHAR(45),
|
||||
userfield VARCHAR(256),
|
||||
uniqueid VARCHAR(150),
|
||||
linkedid VARCHAR(150),
|
||||
peeraccount VARCHAR(20),
|
||||
sequence INTEGER
|
||||
);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
|
||||
|
||||
-- Running upgrade 210693f3123d -> 54cde9847798
|
||||
|
||||
ALTER TABLE cdr ALTER COLUMN accountcode TYPE VARCHAR(80);
|
||||
|
||||
ALTER TABLE cdr ALTER COLUMN peeraccount TYPE VARCHAR(80);
|
||||
|
||||
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';
|
||||
|
||||
COMMIT;
|
||||
|
||||
1474
contrib/realtime/postgresql/postgresql_config.sql
Normal file
1474
contrib/realtime/postgresql/postgresql_config.sql
Normal file
File diff suppressed because it is too large
Load Diff
39
contrib/realtime/postgresql/postgresql_voicemail.sql
Normal file
39
contrib/realtime/postgresql/postgresql_voicemail.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> a2e9769475e
|
||||
|
||||
CREATE TABLE voicemail_messages (
|
||||
dir VARCHAR(255) NOT NULL,
|
||||
msgnum INTEGER NOT NULL,
|
||||
context VARCHAR(80),
|
||||
macrocontext VARCHAR(80),
|
||||
callerid VARCHAR(80),
|
||||
origtime INTEGER,
|
||||
duration INTEGER,
|
||||
recording BYTEA,
|
||||
flag VARCHAR(30),
|
||||
category VARCHAR(30),
|
||||
mailboxuser VARCHAR(30),
|
||||
mailboxcontext VARCHAR(30),
|
||||
msg_id VARCHAR(40)
|
||||
);
|
||||
|
||||
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
|
||||
|
||||
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
|
||||
|
||||
-- Running upgrade a2e9769475e -> 39428242f7f5
|
||||
|
||||
ALTER TABLE voicemail_messages ALTER COLUMN recording TYPE BYTEA;
|
||||
|
||||
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
enum ast_geoloc_pidf_element {
|
||||
AST_PIDF_ELEMENT_NONE = 0,
|
||||
AST_PIDF_ELEMENT_TUPLE,
|
||||
AST_PIDF_ELEMENT_DEVICE,
|
||||
AST_PIDF_ELEMENT_TUPLE,
|
||||
AST_PIDF_ELEMENT_PERSON,
|
||||
AST_PIDF_ELEMENT_LAST,
|
||||
};
|
||||
@@ -43,13 +43,22 @@ enum ast_geoloc_format {
|
||||
AST_GEOLOC_FORMAT_LAST,
|
||||
};
|
||||
|
||||
enum ast_geoloc_action {
|
||||
AST_GEOLOC_ACT_PREFER_INCOMING = 0,
|
||||
AST_GEOLOC_ACT_PREFER_CONFIG,
|
||||
AST_GEOLOC_ACT_DISCARD_INCOMING,
|
||||
AST_GEOLOC_ACT_DISCARD_CONFIG,
|
||||
enum ast_geoloc_precedence {
|
||||
AST_GEOLOC_PRECED_PREFER_INCOMING = 0,
|
||||
AST_GEOLOC_PRECED_PREFER_CONFIG,
|
||||
AST_GEOLOC_PRECED_DISCARD_INCOMING,
|
||||
AST_GEOLOC_PRECED_DISCARD_CONFIG,
|
||||
};
|
||||
|
||||
#define CONFIG_STR_TO_ENUM_DECL(_stem) int ast_geoloc_ ## _stem ## _str_to_enum(const char *str);
|
||||
CONFIG_STR_TO_ENUM_DECL(pidf_element)
|
||||
CONFIG_STR_TO_ENUM_DECL(format);
|
||||
CONFIG_STR_TO_ENUM_DECL(precedence);
|
||||
#define GEOLOC_ENUM_TO_NAME_DECL(_stem) const char * ast_geoloc_ ## _stem ## _to_name(int ix);
|
||||
GEOLOC_ENUM_TO_NAME_DECL(pidf_element)
|
||||
GEOLOC_ENUM_TO_NAME_DECL(format);
|
||||
GEOLOC_ENUM_TO_NAME_DECL(precedence);
|
||||
|
||||
struct ast_geoloc_location {
|
||||
SORCERY_OBJECT(details);
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
@@ -58,6 +67,7 @@ struct ast_geoloc_location {
|
||||
);
|
||||
enum ast_geoloc_format format;
|
||||
struct ast_variable *location_info;
|
||||
struct ast_variable *confidence;
|
||||
};
|
||||
|
||||
struct ast_geoloc_profile {
|
||||
@@ -67,8 +77,8 @@ struct ast_geoloc_profile {
|
||||
AST_STRING_FIELD(notes);
|
||||
);
|
||||
enum ast_geoloc_pidf_element pidf_element;
|
||||
enum ast_geoloc_action action;
|
||||
int geolocation_routing;
|
||||
enum ast_geoloc_precedence precedence;
|
||||
int allow_routing_use;
|
||||
struct ast_variable *location_refinement;
|
||||
struct ast_variable *location_variables;
|
||||
struct ast_variable *usage_rules;
|
||||
@@ -83,14 +93,15 @@ struct ast_geoloc_eprofile {
|
||||
AST_STRING_FIELD(notes);
|
||||
);
|
||||
enum ast_geoloc_pidf_element pidf_element;
|
||||
enum ast_geoloc_action action;
|
||||
int geolocation_routing;
|
||||
enum ast_geoloc_precedence precedence;
|
||||
int allow_routing_use;
|
||||
enum ast_geoloc_format format;
|
||||
struct ast_variable *location_info;
|
||||
struct ast_variable *location_refinement;
|
||||
struct ast_variable *location_variables;
|
||||
struct ast_variable *effective_location;
|
||||
struct ast_variable *usage_rules;
|
||||
struct ast_variable *confidence;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -331,12 +342,45 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
|
||||
struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,
|
||||
const char *reference_string);
|
||||
|
||||
/*!
|
||||
* \brief Convert a URI eprofile to a URI string
|
||||
*
|
||||
* \param eprofile Effective profile to convert
|
||||
* \param chan Channel to use to resolve variables
|
||||
* \param buf Pointer to ast_str pointer to use for work
|
||||
* \param ref_string An identifying string to use in error messages.
|
||||
*
|
||||
* \return String representation of URI allocated from buf or NULL on failure
|
||||
*/
|
||||
const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,
|
||||
struct ast_channel *chan, struct ast_str **buf, const char *ref_string);
|
||||
|
||||
/*!
|
||||
* \brief Convert a datastore containing eprofiles to a PIDF-LO document
|
||||
*
|
||||
* \param ds Datastore containing effective profiles to convert
|
||||
* \param chan Channel to use to resolve variables
|
||||
* \param buf Pointer to ast_str pointer to use for work
|
||||
* \param ref_string An identifying string to use in error messages.
|
||||
*
|
||||
* \return String representation PIDF-LO allocated from buf or NULL on failure.
|
||||
*/
|
||||
const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
|
||||
struct ast_channel *chan, struct ast_str **buf, const char * ref_string);
|
||||
|
||||
/*!
|
||||
* \brief Convert a single eprofile to a PIDF-LO document
|
||||
*
|
||||
* \param eprofile Effective profile to convert
|
||||
* \param chan Channel to use to resolve variables
|
||||
* \param buf Pointer to ast_str pointer to use for work
|
||||
* \param ref_string An identifying string to use in error messages.
|
||||
*
|
||||
* \return String representation PIDF-LO allocated from buf or NULL on failure.
|
||||
*/
|
||||
const char *ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile,
|
||||
struct ast_channel *chan, struct ast_str **buf, const char * ref_string);
|
||||
|
||||
/*!
|
||||
* \brief Refresh the effective profile with any changed info.
|
||||
*
|
||||
|
||||
@@ -163,6 +163,7 @@ void ast_xml_free_text(const char *text);
|
||||
* \param attrname Attribute name.
|
||||
* \retval NULL on error
|
||||
* \return The attribute value on success.
|
||||
* \note The result must be freed with ast_xml_free_attr().
|
||||
*/
|
||||
const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname);
|
||||
|
||||
|
||||
30
main/xml.c
30
main/xml.c
@@ -544,35 +544,45 @@ struct ast_xml_doc *ast_xslt_apply(struct ast_xslt_doc *axslt, struct ast_xml_do
|
||||
{
|
||||
xsltStylesheet *xslt = (xsltStylesheet *)axslt;
|
||||
xmlDoc *xml = (xmlDoc *)axml;
|
||||
xmlDoc *res;
|
||||
xsltTransformContextPtr ctxt;
|
||||
xmlNs *ns;
|
||||
xmlDoc *res;
|
||||
int options = XSLT_PARSE_OPTIONS;
|
||||
|
||||
/*
|
||||
* Normally we could just call xsltApplyStylesheet() without creating
|
||||
* our own transform context but we need to pass parameters to it
|
||||
* that have namespace prefixes and that's not supported. Instead
|
||||
* we have to create a transform context, iterate over the namespace
|
||||
* declarations in the stylesheet (not the incoming xml document),
|
||||
* and add them to the transform context's xpath context.
|
||||
* our own transform context but passing parameters to it that have
|
||||
* namespace prefixes isn't supported. Instead we have to create a
|
||||
* transform context, iterate over the namespace declarations in the
|
||||
* stylesheet (not the incoming xml document), add them to the
|
||||
* transform context's xpath context, and call xsltApplyStylesheetUser.
|
||||
*
|
||||
* Since this is a bit involved and libxslt apparently doesn't completely
|
||||
* clean up after itself in this situation, we'll only do that dance
|
||||
* if there are parameters passed in. Otherwise we just call the simpler
|
||||
* xsltApplyStylesheet.
|
||||
*
|
||||
* The alternative would be to pass the parameters with namespaces
|
||||
* as text strings but that's not intuitive and results in much
|
||||
* slower performance than adding the namespaces here.
|
||||
*/
|
||||
|
||||
if (!params) {
|
||||
res = xsltApplyStylesheet(xslt, xml, params);
|
||||
return (struct ast_xml_doc *)res;
|
||||
}
|
||||
|
||||
ctxt = xsltNewTransformContext(xslt, xml);
|
||||
xsltSetCtxtParseOptions(ctxt, options);
|
||||
|
||||
for (ns = xslt->doc->children->nsDef; ns; ns = ns->next) {
|
||||
if (xmlXPathRegisterNs(ctxt->xpathCtxt, ns->prefix, ns->href) != 0) {
|
||||
xmlXPathFreeContext(ctxt->xpathCtxt);
|
||||
xsltFreeTransformContext(ctxt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
res = xsltApplyStylesheetUser(xslt, xml, params, NULL, NULL, ctxt);
|
||||
xmlXPathFreeContext(ctxt->xpathCtxt);
|
||||
ctxt->xpathCtxt = NULL;
|
||||
xsltFreeTransformContext(ctxt);
|
||||
|
||||
return (struct ast_xml_doc *)res;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
|
||||
xmlns:gs="http://www.opengis.net/pidflo/1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:con="urn:ietf:params:xml:ns:geopriv:conf"
|
||||
xmlns:date="http://exslt.org/dates-and-times">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
@@ -20,12 +21,16 @@
|
||||
<!-- xslt will take care of adding all of the namespace declarations
|
||||
from the list above -->
|
||||
<presence xmlns="urn:ietf:params:xml:ns:pidf" entity="{@entity}">
|
||||
<xsl:apply-templates select="./device|tuple|person"/>
|
||||
<xsl:apply-templates/>
|
||||
</presence>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="device">
|
||||
<dm:device>
|
||||
<xsl:template match="person|device">
|
||||
<xsl:element name="dm:{local-name(.)}">
|
||||
<xsl:if test="@id">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
|
||||
<gp:geopriv>
|
||||
<xsl:apply-templates select="./location-info"/>
|
||||
<xsl:apply-templates select="./usage-rules"/>
|
||||
@@ -42,7 +47,7 @@
|
||||
<xsl:value-of select="./deviceID"/>
|
||||
</dm:deviceID>
|
||||
</xsl:if>
|
||||
</dm:device>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="tuple">
|
||||
@@ -63,21 +68,6 @@
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="person">
|
||||
<dm:person>
|
||||
<gp:geopriv>
|
||||
<xsl:apply-templates select="./location-info"/>
|
||||
<xsl:apply-templates select="./usage-rules"/>
|
||||
<xsl:apply-templates select="./method"/>
|
||||
<xsl:apply-templates select="./note-well"/>
|
||||
</gp:geopriv>
|
||||
<xsl:if test="./timestamp">
|
||||
<dm:timestamp>
|
||||
<xsl:value-of select="./timestamp"/>
|
||||
</dm:timestamp>
|
||||
</xsl:if>
|
||||
</dm:person>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="location-info">
|
||||
<gp:location-info>
|
||||
@@ -233,5 +223,10 @@
|
||||
<xsl:template match="pos"><xsl:call-template name="name-value" /></xsl:template>
|
||||
<xsl:template match="posList"><xsl:call-template name="name-value" /></xsl:template>
|
||||
|
||||
<xsl:template match="confidence">
|
||||
<con:confidence pdf="{@pdf}">
|
||||
<xsl:value-of select="."/>
|
||||
</con:confidence>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
@@ -26,8 +26,8 @@ static struct ast_sorcery *geoloc_sorcery;
|
||||
|
||||
static const char *pidf_element_names[] = {
|
||||
"<none>",
|
||||
"tuple",
|
||||
"device",
|
||||
"tuple",
|
||||
"person"
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ static const char *format_names[] = {
|
||||
"URI",
|
||||
};
|
||||
|
||||
static const char * action_names[] = {
|
||||
static const char * precedence_names[] = {
|
||||
"prefer_incoming",
|
||||
"prefer_config",
|
||||
"discard_incoming",
|
||||
@@ -47,12 +47,14 @@ static const char * action_names[] = {
|
||||
|
||||
CONFIG_ENUM(location, format)
|
||||
CONFIG_VAR_LIST(location, location_info)
|
||||
CONFIG_VAR_LIST(location, confidence)
|
||||
|
||||
static void geoloc_location_destructor(void *obj) {
|
||||
struct ast_geoloc_location *location = obj;
|
||||
|
||||
ast_string_field_free_memory(location);
|
||||
ast_variables_destroy(location->location_info);
|
||||
ast_variables_destroy(location->confidence);
|
||||
}
|
||||
|
||||
static void *geoloc_location_alloc(const char *name)
|
||||
@@ -67,7 +69,7 @@ static void *geoloc_location_alloc(const char *name)
|
||||
|
||||
|
||||
CONFIG_ENUM(profile, pidf_element)
|
||||
CONFIG_ENUM(profile, action)
|
||||
CONFIG_ENUM(profile, precedence)
|
||||
CONFIG_VAR_LIST(profile, location_refinement)
|
||||
CONFIG_VAR_LIST(profile, location_variables)
|
||||
CONFIG_VAR_LIST(profile, usage_rules)
|
||||
@@ -308,7 +310,7 @@ static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struc
|
||||
int using_regex = 0;
|
||||
char *result = CLI_SUCCESS;
|
||||
int ret = 0;
|
||||
char *action;
|
||||
char *precedence;
|
||||
int count = 0;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -365,13 +367,13 @@ static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struc
|
||||
for (; (profile = ao2_iterator_next(&iter)); ao2_ref(profile, -1)) {
|
||||
ao2_lock(profile);
|
||||
|
||||
action_to_str(profile, NULL, &action);
|
||||
precedence_to_str(profile, NULL, &precedence);
|
||||
ast_cli(a->fd, "%-46.46s %-16s %-s\n",
|
||||
ast_sorcery_object_get_id(profile),
|
||||
action,
|
||||
precedence,
|
||||
profile->location_reference);
|
||||
ao2_unlock(profile);
|
||||
ast_free(action);
|
||||
ast_free(precedence);
|
||||
count++;
|
||||
}
|
||||
ao2_iterator_destroy(&iter);
|
||||
@@ -460,11 +462,11 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
|
||||
variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL);
|
||||
usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL);
|
||||
|
||||
action_to_str(eprofile, NULL, &action);
|
||||
precedence_to_str(eprofile, NULL, &action);
|
||||
|
||||
ast_cli(a->fd,
|
||||
"id: %-s\n"
|
||||
"profile_action: %-s\n"
|
||||
"profile_disposition: %-s\n"
|
||||
"pidf_element: %-s\n"
|
||||
"location_reference: %-s\n"
|
||||
"Location_format: %-s\n"
|
||||
@@ -472,6 +474,7 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
|
||||
"location_method: %-s\n"
|
||||
"location_refinement: %-s\n"
|
||||
"location_variables: %-s\n"
|
||||
"allow_routing_use: %-s\n"
|
||||
"effective_location: %-s\n"
|
||||
"usage_rules: %-s\n"
|
||||
"notes: %-s\n",
|
||||
@@ -484,6 +487,7 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
|
||||
S_OR(eprofile->method, "<none>"),
|
||||
S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"),
|
||||
S_COR(variables_str, ast_str_buffer(variables_str), "<none>"),
|
||||
S_COR(eprofile->precedence, "yes", "no"),
|
||||
S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"),
|
||||
S_COR(usage_rules_str, ast_str_buffer(usage_rules_str), "<none>"),
|
||||
S_OR(eprofile->notes, "<none>")
|
||||
@@ -597,6 +601,8 @@ int geoloc_config_load(void)
|
||||
format_handler, format_to_str, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location_info", NULL,
|
||||
location_info_handler, location_info_to_str, location_info_dup, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "confidence", NULL,
|
||||
confidence_handler, confidence_to_str, confidence_dup, 0, 0);
|
||||
ast_sorcery_object_field_register(geoloc_sorcery, "location", "location_source", "", OPT_STRINGFIELD_T,
|
||||
0, STRFLDSET(struct ast_geoloc_location, location_source));
|
||||
ast_sorcery_object_field_register(geoloc_sorcery, "location", "method", "", OPT_STRINGFIELD_T,
|
||||
@@ -616,8 +622,8 @@ int geoloc_config_load(void)
|
||||
pidf_element_names[AST_PIDF_ELEMENT_DEVICE], pidf_element_handler, pidf_element_to_str, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_reference", "", OPT_STRINGFIELD_T,
|
||||
0, STRFLDSET(struct ast_geoloc_profile, location_reference));
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "profile_action", "discard_incoming",
|
||||
action_handler, action_to_str, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "profile_precedence", "discard_incoming",
|
||||
precedence_handler, precedence_to_str, NULL, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "usage_rules", NULL,
|
||||
usage_rules_handler, usage_rules_to_str, usage_rules_dup, 0, 0);
|
||||
ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info_refinement", NULL,
|
||||
@@ -626,6 +632,9 @@ int geoloc_config_load(void)
|
||||
location_variables_handler, location_variables_to_str, location_variables_dup, 0, 0);
|
||||
ast_sorcery_object_field_register(geoloc_sorcery, "profile", "notes", "", OPT_STRINGFIELD_T,
|
||||
0, STRFLDSET(struct ast_geoloc_profile, notes));
|
||||
ast_sorcery_object_field_register(geoloc_sorcery, "profile", "allow_routing_use",
|
||||
"no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, allow_routing_use));
|
||||
|
||||
|
||||
ast_sorcery_load(geoloc_sorcery);
|
||||
|
||||
|
||||
@@ -41,84 +41,63 @@ static int geoloc_profile_read(struct ast_channel *chan,
|
||||
const char *cmd, char *data, struct ast_str **buf, ssize_t len)
|
||||
{
|
||||
char *parsed_data = ast_strdupa(data);
|
||||
int index = -1;
|
||||
struct ast_datastore *ds;
|
||||
struct ast_geoloc_eprofile *eprofile = NULL;
|
||||
int profile_count = 0;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(field);
|
||||
AST_APP_ARG(index);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parsed_data)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);
|
||||
return -1;
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parsed_data);
|
||||
|
||||
if (ast_strlen_zero(args.field)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without a field to query\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args.index)) {
|
||||
if (sscanf(args.index, "%30d", &index) != 1) {
|
||||
ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);
|
||||
return -1;
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_find(chan);
|
||||
if (!ds) {
|
||||
ast_log(LOG_NOTICE, "%s: There are no geoloc profiles on this channel\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
profile_count = ast_geoloc_datastore_size(ds);
|
||||
|
||||
if (index < 0) {
|
||||
if (ast_strings_equal(args.field, "count")) {
|
||||
ast_str_append(buf, len, "%d", profile_count);
|
||||
} else if (ast_strings_equal(args.field, "inheritable")) {
|
||||
ast_str_append(buf, len, "%d", ds->inheritance ? 1 : 0);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", cmd);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (index >= profile_count) {
|
||||
ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eprofile = ast_geoloc_datastore_get_eprofile(ds, index);
|
||||
eprofile = ast_geoloc_datastore_get_eprofile(ds, 0);
|
||||
if (!eprofile) {
|
||||
ast_log(LOG_ERROR, "%s: Internal Error. Profile at index %d couldn't be retrieved.\n", cmd, index);
|
||||
return -1;
|
||||
ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", cmd);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_strings_equal(args.field, "id")) {
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "0");
|
||||
if (ast_strings_equal(args.field, "inheritable")) {
|
||||
ast_str_append(buf, len, "%s", ds->inheritance ? "true" : "false");
|
||||
} else if (ast_strings_equal(args.field, "id")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->id);
|
||||
} else if (ast_strings_equal(args.field, "location_reference")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->location_reference);
|
||||
} else if (ast_strings_equal(args.field, "method")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->method);
|
||||
} else if (ast_strings_equal(args.field, "geolocation_routing")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->geolocation_routing ? "yes" : "no");
|
||||
} else if (ast_strings_equal(args.field, "profile_action")) {
|
||||
ast_str_append(buf, len, "%s", geoloc_action_to_name(eprofile->action));
|
||||
} else if (ast_strings_equal(args.field, "allow_routing_use")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->allow_routing_use ? "yes" : "no");
|
||||
} else if (ast_strings_equal(args.field, "profile_precedence")) {
|
||||
ast_str_append(buf, len, "%s", ast_geoloc_precedence_to_name(eprofile->precedence));
|
||||
} else if (ast_strings_equal(args.field, "format")) {
|
||||
ast_str_append(buf, len, "%s", geoloc_format_to_name(eprofile->format));
|
||||
ast_str_append(buf, len, "%s", ast_geoloc_format_to_name(eprofile->format));
|
||||
} else if (ast_strings_equal(args.field, "pidf_element")) {
|
||||
ast_str_append(buf, len, "%s", geoloc_pidf_element_to_name(eprofile->pidf_element));
|
||||
ast_str_append(buf, len, "%s", ast_geoloc_pidf_element_to_name(eprofile->pidf_element));
|
||||
} else if (ast_strings_equal(args.field, "location_source")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->location_source);
|
||||
} else if (ast_strings_equal(args.field, "notes")) {
|
||||
ast_str_append(buf, len, "%s", eprofile->notes);
|
||||
} else if (ast_strings_equal(args.field, "location_info")) {
|
||||
varlist_to_str(eprofile->location_info, buf, len);
|
||||
} else if (ast_strings_equal(args.field, "location_info_refinement")) {
|
||||
@@ -129,41 +108,37 @@ static int geoloc_profile_read(struct ast_channel *chan,
|
||||
varlist_to_str(eprofile->effective_location, buf, len);
|
||||
} else if (ast_strings_equal(args.field, "usage_rules")) {
|
||||
varlist_to_str(eprofile->usage_rules, buf, len);
|
||||
} else if (ast_strings_equal(args.field, "confidence")) {
|
||||
varlist_to_str(eprofile->confidence, buf, len);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
|
||||
return -1;
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3");
|
||||
}
|
||||
|
||||
ao2_ref(eprofile, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_ENUM_VALUE(_cmd, _ep, _field, _value) \
|
||||
#define TEST_ENUM_VALUE(_chan_name, _ep, _field, _value) \
|
||||
({ \
|
||||
enum ast_geoloc_ ## _field v; \
|
||||
if (!_ep) { \
|
||||
ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \
|
||||
return -1; \
|
||||
} \
|
||||
v = geoloc_ ## _field ## _str_to_enum(_value); \
|
||||
v = ast_geoloc_ ## _field ## _str_to_enum(_value); \
|
||||
if (v == AST_GEOLOC_INVALID_VALUE) { \
|
||||
ast_log(LOG_ERROR, "%s: %s '%s' is invalid\n", _cmd, #_field, value); \
|
||||
return -1; \
|
||||
ast_log(LOG_ERROR, "%s: %s '%s' is invalid\n", _chan_name, #_field, value); \
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3"); \
|
||||
return 0; \
|
||||
} \
|
||||
_ep->_field = v; \
|
||||
})
|
||||
|
||||
#define TEST_VARLIST(_cmd, _ep, _field, _value) \
|
||||
#define TEST_VARLIST(_chan_name, _ep, _field, _value) \
|
||||
({ \
|
||||
struct ast_variable *_list; \
|
||||
if (!_ep) { \
|
||||
ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \
|
||||
return -1; \
|
||||
} \
|
||||
_list = ast_variable_list_from_quoted_string(_value, ",", "=", "\"" ); \
|
||||
if (!_list) { \
|
||||
ast_log(LOG_ERROR, "%s: %s '%s' is malformed or contains invalid values", _cmd, #_field, _value); \
|
||||
return -1; \
|
||||
ast_log(LOG_ERROR, "%s: %s '%s' is malformed or contains invalid values", _chan_name, #_field, _value); \
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3"); \
|
||||
return 0; \
|
||||
} \
|
||||
ast_variables_destroy(_ep->_field); \
|
||||
_ep->_field = _list; \
|
||||
@@ -173,105 +148,106 @@ static int geoloc_profile_write(struct ast_channel *chan, const char *cmd, char
|
||||
const char *value)
|
||||
{
|
||||
char *parsed_data = ast_strdupa(data);
|
||||
struct ast_datastore *ds;
|
||||
const char *chan_name = ast_channel_name(chan);
|
||||
struct ast_datastore *ds; /* Reminder: datastores aren't ao2 objects */
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
|
||||
int profile_count = 0;
|
||||
int index = -1;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(field);
|
||||
AST_APP_ARG(index);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parsed_data)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);
|
||||
return -1;
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", chan_name);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parsed_data);
|
||||
|
||||
if (ast_strlen_zero(args.field)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without a field to set\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args.index)) {
|
||||
if (sscanf(args.index, "%30d", &index) != 1) {
|
||||
ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);
|
||||
return -1;
|
||||
}
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without a field to set\n", chan_name);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_find(chan);
|
||||
if (!ds) {
|
||||
ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", cmd);
|
||||
return -1;
|
||||
ds = ast_geoloc_datastore_create(ast_channel_name(chan));
|
||||
if (!ds) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to create geolocation datastore\n", chan_name);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");
|
||||
return 0;
|
||||
}
|
||||
ast_channel_datastore_add(chan, ds);
|
||||
}
|
||||
|
||||
profile_count = ast_geoloc_datastore_size(ds);
|
||||
|
||||
if (index >= 0 && index < profile_count) {
|
||||
eprofile = ast_geoloc_datastore_get_eprofile(ds, index);
|
||||
eprofile = ast_geoloc_datastore_get_eprofile(ds, 0);
|
||||
if (!eprofile) {
|
||||
int rc;
|
||||
eprofile = ast_geoloc_eprofile_alloc(chan_name);
|
||||
if (!eprofile) {
|
||||
ast_log(LOG_ERROR, "%s: Internal Error. Profile at index %d couldn't be retrieved.\n", cmd, index);
|
||||
return -1;
|
||||
ast_log(LOG_ERROR, "%s: Could not allocate eprofile\n", chan_name);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");
|
||||
return 0;
|
||||
}
|
||||
} else if (index >= profile_count) {
|
||||
ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);
|
||||
return -1;
|
||||
} else {
|
||||
if (ast_strings_equal(args.field, "inheritable")) {
|
||||
ast_geoloc_datastore_set_inheritance(ds, ast_true(value));
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "%s: Field '%s' is not valid or requires a profile index\n", cmd, args.field);
|
||||
return -1;
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
ast_log(LOG_ERROR, "%s: Could not add eprofile to datastore\n", chan_name);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_strings_equal(args.field, "location_reference")) {
|
||||
if (ast_strings_equal(args.field, "inheritable")) {
|
||||
ast_geoloc_datastore_set_inheritance(ds, ast_true(value));
|
||||
} else if (ast_strings_equal(args.field, "location_reference")) {
|
||||
struct ast_geoloc_location *loc = ast_geoloc_get_location(value);
|
||||
ao2_cleanup(loc);
|
||||
if (!loc) {
|
||||
ast_log(LOG_ERROR, "%s: Location reference '%s' doesn't exist\n", cmd, value);
|
||||
return -1;
|
||||
ast_log(LOG_ERROR, "%s: Location reference '%s' doesn't exist\n", chan_name, value);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3");
|
||||
return 0;
|
||||
}
|
||||
ast_string_field_set(eprofile, location_reference, value);
|
||||
} else if (ast_strings_equal(args.field, "method")) {
|
||||
ast_string_field_set(eprofile, method, value);
|
||||
|
||||
} else if (ast_strings_equal(args.field, "geolocation_routing")) {
|
||||
eprofile->geolocation_routing = ast_true(value);
|
||||
} else if (ast_strings_equal(args.field, "allow_routing_use")) {
|
||||
eprofile->allow_routing_use = ast_true(value);
|
||||
|
||||
} else if (ast_strings_equal(args.field, "profile_action")) {
|
||||
TEST_ENUM_VALUE(cmd, eprofile, action, value);
|
||||
} else if (ast_strings_equal(args.field, "profile_precedence")) {
|
||||
TEST_ENUM_VALUE(chan_name, eprofile, precedence, value);
|
||||
|
||||
} else if (ast_strings_equal(args.field, "format")) {
|
||||
TEST_ENUM_VALUE(cmd, eprofile, format, value);
|
||||
TEST_ENUM_VALUE(chan_name, eprofile, format, value);
|
||||
|
||||
} else if (ast_strings_equal(args.field, "pidf_element")) {
|
||||
TEST_ENUM_VALUE(cmd, eprofile, pidf_element, value);
|
||||
TEST_ENUM_VALUE(chan_name, eprofile, pidf_element, value);
|
||||
|
||||
} else if (ast_strings_equal(args.field, "location_info")) {
|
||||
TEST_VARLIST(cmd, eprofile, location_info, value);
|
||||
TEST_VARLIST(chan_name, eprofile, location_info, value);
|
||||
} else if (ast_strings_equal(args.field, "location_source")) {
|
||||
ast_string_field_set(eprofile, location_source, value);
|
||||
} else if (ast_strings_equal(args.field, "location_info_refinement")) {
|
||||
TEST_VARLIST(cmd, eprofile, location_refinement, value);
|
||||
TEST_VARLIST(chan_name, eprofile, location_refinement, value);
|
||||
} else if (ast_strings_equal(args.field, "location_variables")) {
|
||||
TEST_VARLIST(cmd, eprofile, location_variables, value);
|
||||
TEST_VARLIST(chan_name, eprofile, location_variables, value);
|
||||
} else if (ast_strings_equal(args.field, "effective_location")) {
|
||||
TEST_VARLIST(cmd, eprofile, effective_location, value);
|
||||
TEST_VARLIST(chan_name, eprofile, effective_location, value);
|
||||
} else if (ast_strings_equal(args.field, "usage_rules")) {
|
||||
TEST_VARLIST(cmd, eprofile, usage_rules, value);
|
||||
TEST_VARLIST(chan_name, eprofile, usage_rules, value);
|
||||
} else if (ast_strings_equal(args.field, "confidence")) {
|
||||
TEST_VARLIST(chan_name, eprofile, confidence, value);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
|
||||
return -1;
|
||||
ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", chan_name, args.field);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_geoloc_eprofile_refresh_location(eprofile);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -281,155 +257,8 @@ static struct ast_custom_function geoloc_function = {
|
||||
.write = geoloc_profile_write,
|
||||
};
|
||||
|
||||
#define profile_create "GeolocProfileCreate"
|
||||
|
||||
static int geoloc_eprofile_create(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *parsed_data = ast_strdupa(data);
|
||||
struct ast_datastore *ds;
|
||||
struct ast_geoloc_eprofile * eprofile;
|
||||
int profile_count = 0;
|
||||
int index = -1;
|
||||
int rc = 0;
|
||||
struct ast_str *new_size;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(id);
|
||||
AST_APP_ARG(index);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parsed_data)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", profile_create);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parsed_data);
|
||||
|
||||
if (ast_strlen_zero(args.id)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without an id field\n", profile_create);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args.index)) {
|
||||
if (sscanf(args.index, "%30d", &index) != 1) {
|
||||
ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", profile_create, args.index);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
index = -1;
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_find(chan);
|
||||
if (!ds) {
|
||||
ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", profile_create);
|
||||
return -1;
|
||||
}
|
||||
|
||||
profile_count = ast_geoloc_datastore_size(ds);
|
||||
if (index < -1 || index >= profile_count) {
|
||||
ast_log(LOG_ERROR, "%s: Invalid insert_before index '%d'. It must be 0 to insert at the beginning of the list or -1 to append to the end of the list\n", profile_create, index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eprofile = ast_geoloc_eprofile_alloc(args.id);
|
||||
if (!eprofile) {
|
||||
ast_log(LOG_ERROR, "%s: Could not allocate eprofile '%s'\n", profile_create, args.id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_find(chan);
|
||||
if (!ds) {
|
||||
ds = ast_geoloc_datastore_create_from_eprofile(eprofile);
|
||||
if (!ds) {
|
||||
ao2_ref(eprofile, -1);
|
||||
ast_log(LOG_ERROR, "%s: Could not create datastore for eprofile '%s'\n", profile_create, args.id);
|
||||
return -1;
|
||||
}
|
||||
rc = 1;
|
||||
ast_channel_datastore_add(chan, ds);
|
||||
} else if (index < 0) {
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
ao2_ref(eprofile, -1);
|
||||
ast_log(LOG_ERROR, "%s: Could not add eprofile '%s' to datastore\n", profile_create, args.id);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
rc = ast_geoloc_datastore_insert_eprofile(ds, eprofile, index);
|
||||
if (rc <= 0) {
|
||||
ao2_ref(eprofile, -1);
|
||||
ast_log(LOG_ERROR, "%s: Could not insert eprofile '%s' to datastore\n", profile_create, args.id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
new_size = ast_str_alloca(16);
|
||||
ast_str_append(&new_size, 0, "%d", rc);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOC_PROFILE_COUNT", ast_str_buffer(new_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define profile_delete "GeolocProfileDelete"
|
||||
|
||||
static int geoloc_eprofile_delete(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *parsed_data = ast_strdupa(data);
|
||||
struct ast_datastore *ds;
|
||||
int profile_count = 0;
|
||||
int index = -1;
|
||||
struct ast_str *new_size;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(index);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parsed_data)) {
|
||||
ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", profile_delete);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parsed_data);
|
||||
|
||||
if (!ast_strlen_zero(args.index)) {
|
||||
if (sscanf(args.index, "%30d", &index) != 1) {
|
||||
ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", profile_delete, args.index);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "%s: A profile_index is required\n", profile_delete);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_find(chan);
|
||||
if (!ds) {
|
||||
ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", profile_delete);
|
||||
return -1;
|
||||
}
|
||||
|
||||
profile_count = ast_geoloc_datastore_size(ds);
|
||||
if (index < -1 || index >= profile_count) {
|
||||
ast_log(LOG_ERROR, "%s: Invalid profile_index '%d'. It must be between 0 and %d\n",
|
||||
profile_create, index, profile_count - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_geoloc_datastore_delete_eprofile(ds, index);
|
||||
profile_count = ast_geoloc_datastore_size(ds);
|
||||
|
||||
new_size = ast_str_alloca(16);
|
||||
ast_str_append(&new_size, 0, "%d", profile_count);
|
||||
pbx_builtin_setvar_helper(chan, "GEOLOC_PROFILE_COUNT", ast_str_buffer(new_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int geoloc_dialplan_unload(void)
|
||||
{
|
||||
ast_unregister_application(profile_delete);
|
||||
ast_unregister_application(profile_create);
|
||||
ast_custom_function_unregister(&geoloc_function);
|
||||
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
@@ -440,12 +269,6 @@ int geoloc_dialplan_load(void)
|
||||
int res = 0;
|
||||
|
||||
res = ast_custom_function_register(&geoloc_function);
|
||||
if (res == 0) {
|
||||
res = ast_register_application_xml(profile_create, geoloc_eprofile_create);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = ast_register_application_xml(profile_delete, geoloc_eprofile_delete);
|
||||
}
|
||||
|
||||
return res == 0 ? AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,34 @@
|
||||
</enumlist>
|
||||
</description>
|
||||
</configOption>
|
||||
<configOption name="confidence" default="">
|
||||
<synopsis>Level of confidence</synopsis>
|
||||
<description>
|
||||
<para>This is a rarely used field in the specification that would
|
||||
indicate the confidence in the location specified. See RFC7459
|
||||
for exact details.
|
||||
</para>
|
||||
<para>
|
||||
Sub-parameters:
|
||||
</para>
|
||||
<enumlist>
|
||||
<enum name="pdf">
|
||||
<para>One of:</para>
|
||||
<enumlist>
|
||||
<enum name="unknown"/>
|
||||
<enum name="normal"/>
|
||||
<enum name="rectangular"/>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="value">
|
||||
<para>A percentage indicating the confidence.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="link">https://www.rfc-editor.org/rfc/rfc7459</ref>
|
||||
</see-also>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="profile">
|
||||
<synopsis>Profile</synopsis>
|
||||
@@ -144,7 +172,11 @@
|
||||
any recipients.</para>
|
||||
</description>
|
||||
</configOption>
|
||||
<configOption name="profile_action" default="discard_incoming">
|
||||
<configOption name="allow_routing_use">
|
||||
<synopsis>Sets the value of the Geolocation-Routing header.</synopsis>
|
||||
</configOption>
|
||||
|
||||
<configOption name="profile_precedence" default="discard_incoming">
|
||||
<synopsis>Determine which profile on a channel should be used</synopsis>
|
||||
<description>
|
||||
<enumlist>
|
||||
@@ -180,56 +212,47 @@
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="field" required="true">
|
||||
<para>The profile field to operate on.</para>
|
||||
</parameter>
|
||||
<parameter name="profile_index" required="false">
|
||||
<para>The index of the profile to operate on. Not required for the special fields.</para>
|
||||
<para>The profile field to operate on. The following fields from the
|
||||
Location and Profile objects are supported.</para>
|
||||
<enumlist>
|
||||
<enum name="id"/>
|
||||
<enum name="location_reference"/>
|
||||
<enum name="method"/>
|
||||
<enum name="allow_routing_use"/>
|
||||
<enum name="profile_precedence"/>
|
||||
<enum name="format"/>
|
||||
<enum name="pidf_element"/>
|
||||
<enum name="location_source"/>
|
||||
<enum name="notes"/>
|
||||
<enum name="location_info"/>
|
||||
<enum name="location_info_refinement"/>
|
||||
<enum name="location_variables"/>
|
||||
<enum name="effective_location"/>
|
||||
<enum name="usage_rules"/>
|
||||
<enum name="confidence"/>
|
||||
</enumlist>
|
||||
<para>Additionally, the <literal>inheritable</literal> field may be
|
||||
set to <literal>true</literal> or <literal>false</literal> to control
|
||||
whether the profile will be passed to the outgoing channel.
|
||||
</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description><para>
|
||||
When used to set a field on a profile, if the profile doesn't already exist, a new
|
||||
one will be created automatically.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>${GEOLOCPROFILESTATUS}</literal> channel variable will be set with
|
||||
a return code indicating the result of the operation. Possible values are:
|
||||
</para>
|
||||
<enumlist>
|
||||
<enum name="0"><para>Success</para></enum>
|
||||
<enum name="-1"><para>No or not enough parameters were supplied</para></enum>
|
||||
<enum name="-2"><para>There was an internal error finding or creating a profile</para></enum>
|
||||
<enum name="-3"><para>There was an issue specific to the field specified
|
||||
(value not valid or field name not found)</para></enum>
|
||||
</enumlist>
|
||||
</description>
|
||||
</function>
|
||||
<application name="GeolocProfileCreate" language="en_US">
|
||||
<synopsis>
|
||||
Create a new, empty Geolocation Profile on a channel
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="id" required="true"><para>
|
||||
The id of the new profile.
|
||||
</para></parameter>
|
||||
<parameter name="profile_index" required="false"><para>
|
||||
The position at which to insert the new eprofile.
|
||||
Existing profiles will be moved forward to make room.
|
||||
Leave empty to append to the end of the list.
|
||||
</para></parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This application adds a new, empty Geolocation Profile to a channel.</para>
|
||||
<para>The following variable is set:</para>
|
||||
<variablelist>
|
||||
<variable name="GEOLOC_PROFILE_COUNT">
|
||||
<para>The number of profiles on the channel after the new one is created</para>
|
||||
</variable>
|
||||
</variablelist>
|
||||
</description>
|
||||
</application>
|
||||
<application name="GeolocProfileDelete" language="en_US">
|
||||
<synopsis>
|
||||
Delete a Geolocation Profile from a channel
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="profile_index" required="true"><para>
|
||||
The position of the profile to be deleted
|
||||
Existing profiles will be moved back.
|
||||
</para></parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This application deletes a Geolocation Profile from a channel.</para>
|
||||
<para>The following variable is set:</para>
|
||||
<variablelist>
|
||||
<variable name="GEOLOC_PROFILE_COUNT">
|
||||
<para>The number of profiles left on the channel after the delete.</para>
|
||||
</variable>
|
||||
</variablelist>
|
||||
</description>
|
||||
</application>
|
||||
</docs>
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ static void geoloc_eprofile_destructor(void *obj)
|
||||
ast_variables_destroy(eprofile->location_variables);
|
||||
ast_variables_destroy(eprofile->effective_location);
|
||||
ast_variables_destroy(eprofile->usage_rules);
|
||||
ast_variables_destroy(eprofile->confidence);
|
||||
}
|
||||
|
||||
struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)
|
||||
@@ -79,8 +80,12 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)
|
||||
int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
|
||||
{
|
||||
struct ast_geoloc_location *loc = NULL;
|
||||
struct ast_variable *temp_locinfo = NULL;
|
||||
struct ast_variable *temp_effloc = NULL;
|
||||
RAII_VAR(struct ast_variable *, temp_locinfo, NULL, ast_variables_destroy);
|
||||
RAII_VAR(struct ast_variable *, temp_effloc, NULL, ast_variables_destroy);
|
||||
RAII_VAR(struct ast_variable *, temp_confidence, NULL, ast_variables_destroy);
|
||||
const char *method = NULL;
|
||||
const char *location_source = NULL;
|
||||
enum ast_geoloc_format format;
|
||||
struct ast_variable *var;
|
||||
int rc = 0;
|
||||
|
||||
@@ -96,20 +101,32 @@ int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
|
||||
return -1;
|
||||
}
|
||||
|
||||
eprofile->format = loc->format;
|
||||
format = loc->format;
|
||||
method = loc->method;
|
||||
location_source = loc->location_source;
|
||||
rc = DUP_VARS(temp_locinfo, loc->location_info);
|
||||
ast_string_field_set(eprofile, method, loc->method);
|
||||
if (rc == 0) {
|
||||
rc = DUP_VARS(temp_confidence, loc->confidence);
|
||||
}
|
||||
ao2_ref(loc, -1);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
temp_locinfo = eprofile->location_info;
|
||||
format = eprofile->format;
|
||||
method = eprofile->method;
|
||||
location_source = eprofile->location_source;
|
||||
rc = DUP_VARS(temp_locinfo, eprofile->location_info);
|
||||
if (rc == 0) {
|
||||
rc = DUP_VARS(temp_confidence, eprofile->confidence);
|
||||
}
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = DUP_VARS(temp_effloc, temp_locinfo);
|
||||
if (rc != 0) {
|
||||
ast_variables_destroy(temp_locinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -117,8 +134,6 @@ int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
|
||||
for (var = eprofile->location_refinement; var; var = var->next) {
|
||||
struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");
|
||||
if (!newvar) {
|
||||
ast_variables_destroy(temp_locinfo);
|
||||
ast_variables_destroy(temp_effloc);
|
||||
return -1;
|
||||
}
|
||||
if (ast_variable_list_replace(&temp_effloc, newvar)) {
|
||||
@@ -127,10 +142,16 @@ int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
|
||||
}
|
||||
}
|
||||
|
||||
eprofile->format = format;
|
||||
ast_string_field_set(eprofile, method, method);
|
||||
ast_string_field_set(eprofile, location_source, location_source);
|
||||
|
||||
ast_variables_destroy(eprofile->location_info);
|
||||
eprofile->location_info = temp_locinfo;
|
||||
temp_locinfo = NULL;
|
||||
ast_variables_destroy(eprofile->effective_location);
|
||||
eprofile->effective_location = temp_effloc;
|
||||
temp_effloc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -153,7 +174,7 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_g
|
||||
}
|
||||
|
||||
ao2_lock(profile);
|
||||
eprofile->geolocation_routing = profile->geolocation_routing;
|
||||
eprofile->allow_routing_use = profile->allow_routing_use;
|
||||
eprofile->pidf_element = profile->pidf_element;
|
||||
|
||||
rc = ast_string_field_set(eprofile, location_reference, profile->location_reference);
|
||||
@@ -175,7 +196,7 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_g
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eprofile->action = profile->action;
|
||||
eprofile->precedence = profile->precedence;
|
||||
ao2_unlock(profile);
|
||||
|
||||
if (ast_geoloc_eprofile_refresh_location(eprofile) != 0) {
|
||||
@@ -301,20 +322,20 @@ static struct ast_variable *geoloc_eprofile_resolve_varlist(struct ast_variable
|
||||
|
||||
|
||||
const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,
|
||||
struct ast_channel *chan, struct ast_str **buf, const char *ref_string)
|
||||
struct ast_channel *chan, struct ast_str **buf, const char *ref_str)
|
||||
{
|
||||
const char *uri = NULL;
|
||||
struct ast_variable *resolved = NULL;
|
||||
char *result;
|
||||
int we_created_buf = 0;
|
||||
|
||||
if (!eprofile || !buf) {
|
||||
if (!eprofile || !buf || !chan) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eprofile->format != AST_GEOLOC_FORMAT_URI) {
|
||||
ast_log(LOG_ERROR, "%s: '%s' is not a URI profile. It's '%s'\n",
|
||||
ref_string, eprofile->id, geoloc_format_to_name(eprofile->format));
|
||||
ref_str, eprofile->id, ast_geoloc_format_to_name(eprofile->format));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -330,7 +351,7 @@ const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,
|
||||
|
||||
if (ast_strlen_zero(result)) {
|
||||
ast_log(LOG_ERROR, "%s: '%s' is a URI profile but had no, or an empty, 'URI' entry in location_info\n",
|
||||
ref_string, eprofile->id);
|
||||
ref_str, eprofile->id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -353,14 +374,14 @@ const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,
|
||||
return ast_str_buffer(*buf);
|
||||
}
|
||||
|
||||
static struct ast_variable *var_list_from_node(struct ast_xml_node *node, const char *reference_string)
|
||||
static struct ast_variable *var_list_from_node(struct ast_xml_node *node,
|
||||
const char *ref_str)
|
||||
{
|
||||
struct ast_variable *list = NULL;
|
||||
struct ast_xml_node *container;
|
||||
struct ast_xml_node *child;
|
||||
struct ast_variable *var;
|
||||
RAII_VAR(struct ast_str *, buf, NULL, ast_free);
|
||||
SCOPE_ENTER(3, "%s\n", reference_string);
|
||||
SCOPE_ENTER(3, "%s\n", ref_str);
|
||||
|
||||
container = ast_xml_node_get_children(node);
|
||||
for (child = container; child; child = ast_xml_node_get_next(child)) {
|
||||
@@ -370,168 +391,296 @@ static struct ast_variable *var_list_from_node(struct ast_xml_node *node, const
|
||||
|
||||
if (uom) {
|
||||
/* '20 radians\0' */
|
||||
char *newval = ast_malloc(strlen(value) + 1 + strlen(uom) + 1);
|
||||
char newval[strlen(value) + 1 + strlen(uom) + 1];
|
||||
sprintf(newval, "%s %s", value, uom);
|
||||
var = ast_variable_new(name, newval, "");
|
||||
ast_free(newval);
|
||||
} else {
|
||||
var = ast_variable_new(name, value, "");
|
||||
}
|
||||
|
||||
ast_xml_free_text(value);
|
||||
ast_xml_free_attr(uom);
|
||||
|
||||
if (!var) {
|
||||
ast_variables_destroy(list);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
}
|
||||
|
||||
ast_variable_list_join(list, ", ", "=", "\"", &buf);
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
struct ast_str *buf = NULL;
|
||||
ast_variable_list_join(list, ", ", "=", "\"", &buf);
|
||||
ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
|
||||
ast_free(buf);
|
||||
}
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(list, "%s: Done. %s\n", reference_string, ast_str_buffer(buf));
|
||||
SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
|
||||
}
|
||||
|
||||
static struct ast_variable *var_list_from_loc_info(struct ast_xml_node *locinfo,
|
||||
enum ast_geoloc_format format, const char *reference_string)
|
||||
enum ast_geoloc_format format, const char *ref_str)
|
||||
{
|
||||
struct ast_variable *list = NULL;
|
||||
struct ast_xml_node *container;
|
||||
struct ast_variable *var;
|
||||
RAII_VAR(struct ast_str *, buf, NULL, ast_free);
|
||||
SCOPE_ENTER(3, "%s\n", reference_string);
|
||||
struct ast_variable *var = NULL;
|
||||
const char *attr;
|
||||
SCOPE_ENTER(3, "%s\n", ref_str);
|
||||
|
||||
container = ast_xml_node_get_children(locinfo);
|
||||
if (format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {
|
||||
var = ast_variable_new("lang", ast_xml_get_attribute(container, "lang"), "");
|
||||
if (!var) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);
|
||||
attr = ast_xml_get_attribute(container, "lang");
|
||||
if (attr) {
|
||||
var = ast_variable_new("lang", attr, "");
|
||||
ast_xml_free_attr(attr);
|
||||
if (!var) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
} else {
|
||||
var = ast_variable_new("shape", ast_xml_node_get_name(container), "");
|
||||
if (!var) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
var = ast_variable_new("crs", ast_xml_get_attribute(container, "srsName"), "");
|
||||
|
||||
attr = ast_xml_get_attribute(container, "srsName");
|
||||
var = ast_variable_new("crs", attr, "");
|
||||
ast_xml_free_attr(attr);
|
||||
if (!var) {
|
||||
ast_variables_destroy(list);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
}
|
||||
|
||||
ast_variable_list_append(&list, var_list_from_node(container, reference_string));
|
||||
ast_variable_list_append(&list, var_list_from_node(container, ref_str));
|
||||
|
||||
ast_variable_list_join(list, ", ", "=", "\"", &buf);
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
struct ast_str *buf = NULL;
|
||||
ast_variable_list_join(list, ", ", "=", "\"", &buf);
|
||||
ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
|
||||
ast_free(buf);
|
||||
}
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(list, "%s: Done. %s\n", reference_string, ast_str_buffer(buf));
|
||||
SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
|
||||
}
|
||||
|
||||
static struct ast_variable *var_list_from_confidence(struct ast_xml_node *confidence,
|
||||
const char *ref_str)
|
||||
{
|
||||
struct ast_variable *list = NULL;
|
||||
struct ast_variable *var;
|
||||
const char *pdf;
|
||||
const char *value;
|
||||
SCOPE_ENTER(3, "%s\n", ref_str);
|
||||
|
||||
if (!confidence) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: No confidence\n", ref_str);
|
||||
}
|
||||
|
||||
pdf = ast_xml_get_attribute(confidence, "pdf");
|
||||
var = ast_variable_new("pdf", S_OR(pdf, "unknown"), "");
|
||||
ast_xml_free_attr(pdf);
|
||||
if (!var) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
|
||||
value = ast_xml_get_text(confidence);
|
||||
var = ast_variable_new("value", S_OR(value, "95"), "");
|
||||
ast_xml_free_text(value);
|
||||
if (!var) {
|
||||
ast_variables_destroy(list);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
ast_variable_list_append(&list, var);
|
||||
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
struct ast_str *buf = NULL;
|
||||
ast_variable_list_join(list, ", ", "=", "\"", &buf);
|
||||
ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
|
||||
ast_free(buf);
|
||||
}
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
|
||||
}
|
||||
|
||||
static struct ast_geoloc_eprofile *geoloc_eprofile_create_from_xslt_result(
|
||||
struct ast_xml_doc *result_doc,
|
||||
const char *reference_string)
|
||||
struct ast_xml_doc *result_doc, const char *ref_str)
|
||||
{
|
||||
struct ast_geoloc_eprofile *eprofile;
|
||||
/*
|
||||
* None of the ast_xml_nodes needs to be freed
|
||||
* because they're just pointers into result_doc.
|
||||
*/
|
||||
struct ast_xml_node *presence = NULL;
|
||||
struct ast_xml_node *pidf_element = NULL;
|
||||
struct ast_xml_node *location_info = NULL;
|
||||
struct ast_xml_node *confidence = NULL;
|
||||
struct ast_xml_node *usage_rules = NULL;
|
||||
struct ast_xml_node *method = NULL;
|
||||
struct ast_xml_node *note_well = NULL;
|
||||
char *doc_str;
|
||||
int doc_len;
|
||||
const char *id;
|
||||
const char *format_str;
|
||||
/*
|
||||
* Like nodes, names of nodes are just
|
||||
* pointers into result_doc and don't need to be freed.
|
||||
*/
|
||||
const char *pidf_element_str;
|
||||
const char *method_str;
|
||||
const char *note_well_str;
|
||||
SCOPE_ENTER(3, "%s\n", reference_string);
|
||||
/*
|
||||
* Attributes and element text however are allocated on the fly
|
||||
* so they DO need to be freed after use.
|
||||
*/
|
||||
const char *id = NULL;
|
||||
const char *format_str = NULL;
|
||||
const char *method_str = NULL;
|
||||
const char *note_well_str = NULL;
|
||||
|
||||
ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
|
||||
ast_trace(5, "xslt result doc:\n%s\n", doc_str);
|
||||
ast_xml_free_text(doc_str);
|
||||
SCOPE_ENTER(3, "%s\n", ref_str);
|
||||
|
||||
if (!result_doc) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: result_doc was NULL", ref_str);
|
||||
}
|
||||
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
char *doc_str = NULL;
|
||||
int doc_len = 0;
|
||||
|
||||
ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
|
||||
ast_trace(5, "xslt result doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
|
||||
ast_xml_free_text(doc_str);
|
||||
}
|
||||
|
||||
presence = ast_xml_get_root(result_doc);
|
||||
pidf_element = ast_xml_node_get_children(presence);
|
||||
location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
|
||||
usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);
|
||||
method = ast_xml_find_child_element(pidf_element, "method", NULL, NULL);
|
||||
note_well = ast_xml_find_child_element(pidf_element, "note-well", NULL, NULL);
|
||||
if (!presence) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find 'presence' root element\n",
|
||||
ref_str);
|
||||
}
|
||||
|
||||
pidf_element = ast_xml_node_get_children(presence);
|
||||
if (!pidf_element) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a device, tuple or person element\n",
|
||||
ref_str);
|
||||
}
|
||||
|
||||
id = ast_xml_get_attribute(pidf_element, "id");
|
||||
if (ast_strlen_zero(id)) {
|
||||
ast_xml_free_attr(id);
|
||||
id = ast_xml_get_attribute(presence, "entity");
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(id)) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Unable to find 'id' attribute\n", ref_str);
|
||||
}
|
||||
|
||||
id = S_OR(ast_xml_get_attribute(pidf_element, "id"), ast_xml_get_attribute(presence, "entity"));
|
||||
eprofile = ast_geoloc_eprofile_alloc(id);
|
||||
ast_xml_free_attr(id);
|
||||
if (!eprofile) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
|
||||
}
|
||||
|
||||
location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
|
||||
if (!location_info) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a location-info element\n",
|
||||
ref_str);
|
||||
}
|
||||
|
||||
format_str = ast_xml_get_attribute(location_info, "format");
|
||||
if (ast_strlen_zero(format_str)) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Unable to find 'format' attribute\n", ref_str);
|
||||
}
|
||||
|
||||
eprofile->format = AST_GEOLOC_FORMAT_NONE;
|
||||
if (strcasecmp(format_str, "gml") == 0) {
|
||||
eprofile->format = AST_GEOLOC_FORMAT_GML;
|
||||
} else if (strcasecmp(format_str, "civicAddress") == 0) {
|
||||
eprofile->format = AST_GEOLOC_FORMAT_CIVIC_ADDRESS;
|
||||
} else {
|
||||
ao2_ref(eprofile, -1);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unknown format '%s'\n", reference_string, format_str);
|
||||
}
|
||||
|
||||
pidf_element_str = ast_xml_node_get_name(pidf_element);
|
||||
eprofile->pidf_element = geoloc_pidf_element_str_to_enum(pidf_element_str);
|
||||
if (eprofile->format == AST_GEOLOC_FORMAT_NONE) {
|
||||
char *dup_format_str = ast_strdupa(format_str);
|
||||
ast_xml_free_attr(format_str);
|
||||
ao2_ref(eprofile, -1);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unknown format '%s'\n", ref_str, dup_format_str);
|
||||
}
|
||||
ast_xml_free_attr(format_str);
|
||||
|
||||
eprofile->location_info = var_list_from_loc_info(location_info, eprofile->format, reference_string);
|
||||
pidf_element_str = ast_xml_node_get_name(pidf_element);
|
||||
eprofile->pidf_element = ast_geoloc_pidf_element_str_to_enum(pidf_element_str);
|
||||
|
||||
eprofile->location_info = var_list_from_loc_info(location_info, eprofile->format, ref_str);
|
||||
if (!eprofile->location_info) {
|
||||
ao2_ref(eprofile, -1);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR,
|
||||
"%s: Unable to create location variables\n", reference_string);
|
||||
"%s: Unable to create location variables\n", ref_str);
|
||||
}
|
||||
|
||||
eprofile->usage_rules = var_list_from_node(usage_rules, reference_string);
|
||||
/*
|
||||
* The function calls that follow are all NULL tolerant
|
||||
* so no need for explicit error checking.
|
||||
*/
|
||||
usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);
|
||||
eprofile->usage_rules = var_list_from_node(usage_rules, ref_str);
|
||||
confidence = ast_xml_find_child_element(location_info, "confidence", NULL, NULL);
|
||||
eprofile->confidence = var_list_from_confidence(confidence, ref_str);
|
||||
|
||||
method = ast_xml_find_child_element(pidf_element, "method", NULL, NULL);
|
||||
method_str = ast_xml_get_text(method);
|
||||
ast_string_field_set(eprofile, method, method_str);
|
||||
ast_xml_free_text(method_str);
|
||||
|
||||
note_well = ast_xml_find_child_element(pidf_element, "note-well", NULL, NULL);
|
||||
note_well_str = ast_xml_get_text(note_well);
|
||||
ast_string_field_set(eprofile, notes, note_well_str);
|
||||
ast_xml_free_text(note_well_str);
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", reference_string);
|
||||
SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);
|
||||
}
|
||||
|
||||
static int is_pidf_lo(struct ast_xml_doc *result_doc)
|
||||
{
|
||||
struct ast_xml_node *presence;
|
||||
struct ast_xml_node *pidf_element;
|
||||
struct ast_xml_node *location_info;
|
||||
const char *pidf_element_name;
|
||||
|
||||
if (!result_doc) {
|
||||
return 0;
|
||||
}
|
||||
presence = ast_xml_get_root(result_doc);
|
||||
if (!presence || !ast_strings_equal("presence", ast_xml_node_get_name(presence))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pidf_element = ast_xml_node_get_children(presence);
|
||||
if (!pidf_element) {
|
||||
return 0;
|
||||
}
|
||||
pidf_element_name = ast_xml_node_get_name(pidf_element);
|
||||
if (!ast_strings_equal(pidf_element_name, "device") &&
|
||||
!ast_strings_equal(pidf_element_name, "tuple") &&
|
||||
!ast_strings_equal(pidf_element_name, "person")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
|
||||
if (!location_info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
|
||||
struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *ref_str)
|
||||
{
|
||||
RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
|
||||
struct ast_geoloc_eprofile *eprofile;
|
||||
/*
|
||||
* The namespace prefixes used here (dm, def, gp, etc) don't have to match
|
||||
* the ones used in the received PIDF-LO document but they MUST match the
|
||||
* ones in the embedded pidf_to_eprofile stylesheet.
|
||||
*
|
||||
* RFC5491 Rule 8 states that...
|
||||
* Where a PIDF document contains more than one <geopriv>
|
||||
* element, the priority of interpretation is given to the first
|
||||
* <device> element in the document containing a location. If no
|
||||
* <device> element containing a location is present in the document,
|
||||
* then priority is given to the first <tuple> element containing a
|
||||
* location. Locations contained in <person> tuples SHOULD only be
|
||||
* used as a last resort.
|
||||
*
|
||||
* Reminder: xpath arrays are 1-based not 0-based.
|
||||
*/
|
||||
const char *find_device[] = { "path", "/def:presence/dm:device[.//gp:location-info][1]", NULL};
|
||||
const char *find_tuple[] = { "path", "/def:presence/def:tuple[.//gp:location-info][1]", NULL};
|
||||
const char *find_person[] = { "path", "/def:presence/dm:person[.//gp:location-info][1]", NULL};
|
||||
struct ast_xml_doc *result_doc = NULL;
|
||||
struct ast_geoloc_eprofile *eprofile = NULL;
|
||||
|
||||
SCOPE_ENTER(3, "%s\n", ref_str);
|
||||
|
||||
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_device);
|
||||
if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {
|
||||
ast_xml_close(result_doc);
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_tuple);
|
||||
}
|
||||
if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {
|
||||
ast_xml_close(result_doc);
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_person);
|
||||
}
|
||||
if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, NULL);
|
||||
if (!is_pidf_lo(result_doc)) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Not a PIDF-LO. Skipping.\n", ref_str);
|
||||
}
|
||||
|
||||
@@ -546,17 +695,27 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
|
||||
* </presence>
|
||||
*
|
||||
* Regardless of whether the pidf-element was tuple, device or person and whether
|
||||
* the format is gml or civicAddress, the presence, pidf-element, location-info,
|
||||
* usage-rules and method elements should be there although usage-rules and method
|
||||
* may be empty.
|
||||
* the format is gml or civicAddress, the presence, pidf-element and location-info
|
||||
* elements should be there.
|
||||
*
|
||||
* The contents of the location-info and usage-rules elements can be passed directly to
|
||||
* ast_variable_list_from_string().
|
||||
* The confidence, usage-rules and note-well elements are optional.
|
||||
*/
|
||||
|
||||
eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
char *doc_str = NULL;
|
||||
int doc_len = 0;
|
||||
|
||||
if (geoloc_uri) {
|
||||
ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
|
||||
ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
|
||||
ast_xml_free_text(doc_str);
|
||||
doc_str = NULL;
|
||||
doc_len = 0;
|
||||
}
|
||||
|
||||
eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);
|
||||
ast_xml_close(result_doc);
|
||||
|
||||
if (eprofile && geoloc_uri) {
|
||||
set_loc_src(eprofile, geoloc_uri, ref_str);
|
||||
}
|
||||
|
||||
@@ -586,6 +745,7 @@ static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_
|
||||
RAII_VAR(struct ast_xml_node *, pidf_node, NULL, ast_xml_free_node);
|
||||
struct ast_xml_node *rtn_pidf_node;
|
||||
struct ast_xml_node *loc_node;
|
||||
struct ast_xml_node *confidence_node;
|
||||
struct ast_xml_node *info_node;
|
||||
struct ast_xml_node *rules_node;
|
||||
struct ast_xml_node *method_node;
|
||||
@@ -613,7 +773,7 @@ static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'location-info' XML node\n",
|
||||
ref_string);
|
||||
}
|
||||
rc = ast_xml_set_attribute(loc_node, "format", geoloc_format_to_name(eprofile->format));
|
||||
rc = ast_xml_set_attribute(loc_node, "format", ast_geoloc_format_to_name(eprofile->format));
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'format' XML attribute\n", ref_string);
|
||||
}
|
||||
@@ -625,14 +785,33 @@ static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_
|
||||
} else {
|
||||
info_node = geoloc_gml_list_to_xml(resolved_location, ref_string);
|
||||
}
|
||||
ast_variables_destroy(resolved_location);
|
||||
|
||||
if (!info_node) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML from '%s' list\n",
|
||||
ref_string, geoloc_format_to_name(eprofile->format));
|
||||
ref_string, ast_geoloc_format_to_name(eprofile->format));
|
||||
}
|
||||
if (!ast_xml_add_child(loc_node, info_node)) {
|
||||
ast_xml_free_node(info_node);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable add '%s' node to XML document\n",
|
||||
ref_string, geoloc_format_to_name(eprofile->format));
|
||||
ref_string, ast_geoloc_format_to_name(eprofile->format));
|
||||
}
|
||||
|
||||
if (eprofile->confidence) {
|
||||
const char *value = S_OR(ast_variable_find_in_list(eprofile->confidence, "value"), "95");
|
||||
const char *pdf = S_OR(ast_variable_find_in_list(eprofile->confidence, "pdf"), "unknown");
|
||||
|
||||
confidence_node = ast_xml_new_child(loc_node, "confidence");
|
||||
if (!confidence_node) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'confidence' XML node\n",
|
||||
ref_string);
|
||||
}
|
||||
rc = ast_xml_set_attribute(confidence_node, "pdf", pdf);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'pdf' attribute on 'confidence' element\n", ref_string);
|
||||
}
|
||||
|
||||
ast_xml_set_text(confidence_node, value);
|
||||
}
|
||||
|
||||
rules_node = ast_xml_new_child(pidf_node, "usage-rules");
|
||||
@@ -646,6 +825,7 @@ static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_
|
||||
struct ast_xml_node *ur = ast_xml_new_child(rules_node, var->name);
|
||||
ast_xml_set_text(ur, var->value);
|
||||
}
|
||||
ast_variables_destroy(resolved_usage);
|
||||
|
||||
if (!ast_strlen_zero(eprofile->method)) {
|
||||
method_node = ast_xml_new_child(pidf_node, "method");
|
||||
@@ -699,8 +879,8 @@ const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
|
||||
struct ast_geoloc_eprofile *eprofile;
|
||||
int eprofile_count = 0;
|
||||
int i;
|
||||
RAII_VAR(char *, doc_str, NULL, ast_xml_free_text);
|
||||
int doc_len;
|
||||
char *doc_str = NULL;
|
||||
int doc_len = 0;
|
||||
int rc = 0;
|
||||
SCOPE_ENTER(3, "%s\n", ref_string);
|
||||
|
||||
@@ -726,20 +906,28 @@ const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
|
||||
struct ast_xml_node *new_loc = NULL;
|
||||
struct ast_xml_node *new_loc_child = NULL;
|
||||
struct ast_xml_node *new_loc_child_dup = NULL;
|
||||
const char *entity = NULL;
|
||||
int has_no_entity = 0;
|
||||
eprofile = ast_geoloc_datastore_get_eprofile(ds, i);
|
||||
if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(ast_xml_get_attribute(root_node, "entity"))) {
|
||||
entity = ast_xml_get_attribute(root_node, "entity");
|
||||
has_no_entity = ast_strlen_zero(entity);
|
||||
ast_xml_free_attr(entity);
|
||||
if (has_no_entity) {
|
||||
rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
|
||||
}
|
||||
}
|
||||
|
||||
temp_node = geoloc_eprofile_to_intermediate(geoloc_pidf_element_to_name(eprofile->pidf_element),
|
||||
temp_node = geoloc_eprofile_to_intermediate(ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
|
||||
eprofile, chan, ref_string);
|
||||
if (!temp_node) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node\n", ref_string);
|
||||
}
|
||||
|
||||
if (!pidfs[eprofile->pidf_element]) {
|
||||
pidfs[eprofile->pidf_element] = temp_node;
|
||||
@@ -756,18 +944,18 @@ const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
|
||||
ast_xml_free_node(temp_node);
|
||||
}
|
||||
|
||||
ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
|
||||
if (doc_len == 0 || !doc_str) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump intermediate doc to string\n",
|
||||
ref_string);
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
|
||||
ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
|
||||
ast_xml_free_text(doc_str);
|
||||
doc_str = NULL;
|
||||
doc_len = 0;
|
||||
}
|
||||
|
||||
ast_trace(5, "Intermediate doc:\n%s\n", doc_str);
|
||||
|
||||
pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL);
|
||||
if (!pidf_doc) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc:\n%s\n",
|
||||
ref_string, doc_str);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate docs\n",
|
||||
ref_string);
|
||||
}
|
||||
|
||||
ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
|
||||
@@ -777,6 +965,93 @@ const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
|
||||
}
|
||||
|
||||
rc = ast_str_set(buf, 0, "%s", doc_str);
|
||||
ast_xml_free_text(doc_str);
|
||||
if (rc <= 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
|
||||
ref_string, rc);
|
||||
}
|
||||
|
||||
ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);
|
||||
}
|
||||
|
||||
const char *ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile,
|
||||
struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
|
||||
{
|
||||
RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);
|
||||
RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);
|
||||
struct ast_xml_node *root_node;
|
||||
char *doc_str = NULL;
|
||||
int doc_len;
|
||||
int rc = 0;
|
||||
struct ast_xml_node *temp_node = NULL;
|
||||
const char *entity = NULL;
|
||||
int has_no_entity = 0;
|
||||
|
||||
SCOPE_ENTER(3, "%s\n", ref_string);
|
||||
|
||||
if (!eprofile || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: One of eprofile, chan or buf was NULL\n",
|
||||
ref_string);
|
||||
}
|
||||
|
||||
if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: eprofile '%s' was a URI format\n",
|
||||
ref_string, eprofile->id);
|
||||
}
|
||||
|
||||
intermediate = ast_xml_new();
|
||||
if (!intermediate) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);
|
||||
}
|
||||
root_node = ast_xml_new_node("presence");
|
||||
if (!root_node) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);
|
||||
}
|
||||
ast_xml_set_root(intermediate, root_node);
|
||||
|
||||
entity = ast_xml_get_attribute(root_node, "entity");
|
||||
has_no_entity = ast_strlen_zero(entity);
|
||||
ast_xml_free_attr(entity);
|
||||
if (has_no_entity) {
|
||||
rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
|
||||
}
|
||||
}
|
||||
|
||||
temp_node = geoloc_eprofile_to_intermediate(
|
||||
ast_geoloc_pidf_element_to_name(eprofile->pidf_element), eprofile, chan, ref_string);
|
||||
if (!temp_node) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node for eprofile '%s'\n",
|
||||
ref_string, eprofile->id);
|
||||
}
|
||||
|
||||
ast_xml_add_child(root_node, temp_node);
|
||||
|
||||
if (TRACE_ATLEAST(5)) {
|
||||
ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
|
||||
ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
|
||||
ast_xml_free_text(doc_str);
|
||||
doc_str = NULL;
|
||||
doc_len = 0;
|
||||
}
|
||||
|
||||
pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL);
|
||||
if (!pidf_doc) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n",
|
||||
ref_string);
|
||||
}
|
||||
|
||||
ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
|
||||
if (doc_len == 0 || !doc_str) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",
|
||||
ref_string);
|
||||
}
|
||||
|
||||
rc = ast_str_set(buf, 0, "%s", doc_str);
|
||||
ast_xml_free_text(doc_str);
|
||||
if (rc <= 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
|
||||
ref_string, rc);
|
||||
@@ -899,10 +1174,9 @@ static enum ast_test_result_state validate_eprofile(struct ast_test *test,
|
||||
RAII_VAR(struct ast_str *, str, NULL, ast_free);
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
|
||||
const char *search[] = { "path", path, NULL };
|
||||
|
||||
if (!ast_strlen_zero(path)) {
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, (const char **)search);
|
||||
result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, NULL);
|
||||
ast_test_validate(test, (result_doc && ast_xml_node_get_children((struct ast_xml_node *)result_doc)));
|
||||
|
||||
eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, "test_create_from_xslt");
|
||||
@@ -912,8 +1186,8 @@ static enum ast_test_result_state validate_eprofile(struct ast_test *test,
|
||||
|
||||
ast_test_validate(test, eprofile != NULL);
|
||||
ast_test_status_update(test, "ID: '%s' pidf_element: '%s' format: '%s' method: '%s'\n", eprofile->id,
|
||||
geoloc_pidf_element_to_name(eprofile->pidf_element),
|
||||
geoloc_format_to_name(eprofile->format),
|
||||
ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
|
||||
ast_geoloc_format_to_name(eprofile->format),
|
||||
eprofile->method);
|
||||
|
||||
ast_test_validate(test, ast_strings_equal(eprofile->id, id));
|
||||
@@ -959,34 +1233,15 @@ AST_TEST_DEFINE(test_create_from_pidf)
|
||||
|
||||
res = validate_eprofile(test, pidf_xmldoc,
|
||||
NULL,
|
||||
"arcband-2d",
|
||||
AST_PIDF_ELEMENT_DEVICE,
|
||||
"point-2d",
|
||||
AST_PIDF_ELEMENT_TUPLE,
|
||||
AST_GEOLOC_FORMAT_GML,
|
||||
"TA-NMR",
|
||||
"shape=ArcBand,crs=2d,pos=-43.5723 153.21760,innerRadius=3594,"
|
||||
"outerRadius=4148,startAngle=20 radians,openingAngle=20 radians",
|
||||
"retransmission-allowed='yes',ruleset-preference='https:/www/more.com',"
|
||||
"retention-expires='2007-06-22T20:57:29Z'"
|
||||
"Manual",
|
||||
"shape=Point,crs=2d,pos=-34.410649 150.87651",
|
||||
"retransmission-allowed='no',retention-expiry='2010-11-14T20:00:00Z'"
|
||||
);
|
||||
ast_test_validate(test, res == AST_TEST_PASS);
|
||||
|
||||
|
||||
res = validate_eprofile(test, pidf_xmldoc,
|
||||
"/def:presence/dm:device[.//ca:civicAddress][1]",
|
||||
"pres:alice@asterisk.org",
|
||||
AST_PIDF_ELEMENT_DEVICE,
|
||||
AST_GEOLOC_FORMAT_CIVIC_ADDRESS,
|
||||
"GPS",
|
||||
"lang=en-AU,country=AU,A1=NSW,A3=Wollongong,A4=North Wollongong,"
|
||||
"RD=Flinders,STS=Street,RDBR=Campbell Street,LMK=Gilligan's Island,"
|
||||
"LOC=Corner,NAM=Video Rental Store,PC=2500,ROOM=Westerns and Classics,"
|
||||
"PLC=store,POBOX=Private Box 15",
|
||||
"retransmission-allowed='yes',ruleset-preference='https:/www/more.com',"
|
||||
"retention-expires='2007-06-22T20:57:29Z'"
|
||||
);
|
||||
ast_test_validate(test, res == AST_TEST_PASS);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,11 @@ struct ast_xml_node *geoloc_gml_list_to_xml(const struct ast_variable *resolved_
|
||||
|
||||
SCOPE_ENTER(3, "%s", ref_string);
|
||||
|
||||
if (!resolved_location) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: resolved_location was NULL\n",
|
||||
ref_string);
|
||||
}
|
||||
|
||||
shape = ast_variable_find_in_list(resolved_location, "shape");
|
||||
if (ast_strlen_zero(shape)) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: There's no 'shape' parameter\n",
|
||||
|
||||
@@ -25,18 +25,8 @@
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/res_geolocation.h"
|
||||
|
||||
#define CONFIG_STR_TO_ENUM_DECL(_stem) int geoloc_ ## _stem ## _str_to_enum(const char *str);
|
||||
CONFIG_STR_TO_ENUM_DECL(pidf_element)
|
||||
CONFIG_STR_TO_ENUM_DECL(format);
|
||||
CONFIG_STR_TO_ENUM_DECL(action);
|
||||
#define GEOLOC_ENUM_TO_NAME_DECL(_stem) const char * geoloc_ ## _stem ## _to_name(int ix);
|
||||
GEOLOC_ENUM_TO_NAME_DECL(pidf_element)
|
||||
GEOLOC_ENUM_TO_NAME_DECL(format);
|
||||
GEOLOC_ENUM_TO_NAME_DECL(action);
|
||||
|
||||
|
||||
#define CONFIG_STR_TO_ENUM(_stem) \
|
||||
int geoloc_ ## _stem ## _str_to_enum(const char *str) \
|
||||
int ast_geoloc_ ## _stem ## _str_to_enum(const char *str) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_LEN(_stem ## _names); i++) { \
|
||||
@@ -51,7 +41,7 @@ int geoloc_ ## _stem ## _str_to_enum(const char *str) \
|
||||
static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \
|
||||
{ \
|
||||
struct ast_geoloc_ ## _object *_thisobject = obj; \
|
||||
int enumval = geoloc_ ## _stem ## _str_to_enum(var->value); \
|
||||
int enumval = ast_geoloc_ ## _stem ## _str_to_enum(var->value); \
|
||||
if (enumval == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
@@ -61,7 +51,7 @@ static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *
|
||||
|
||||
|
||||
#define GEOLOC_ENUM_TO_NAME(_stem) \
|
||||
const char * geoloc_ ## _stem ## _to_name(int ix) \
|
||||
const char * ast_geoloc_ ## _stem ## _to_name(int ix) \
|
||||
{ \
|
||||
if (!ARRAY_IN_BOUNDS(ix, _stem ## _names)) { \
|
||||
return "none"; \
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"
|
||||
xmlns:gml="http://www.opengis.net/gml"
|
||||
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
|
||||
xmlns:con="urn:ietf:params:xml:ns:geopriv:conf"
|
||||
xmlns:gs="http://www.opengis.net/pidflo/1.0">
|
||||
<tuple id="point-2d">
|
||||
<status>
|
||||
@@ -14,299 +15,19 @@
|
||||
<gml:Point srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:pos>-34.410649 150.87651</gml:pos>
|
||||
</gml:Point>
|
||||
<con:confidence pdf="normal">66</con:confidence>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>Manual</gp:method>
|
||||
<gp:note-well>
|
||||
this is a test
|
||||
of the emergency broadcast system
|
||||
</gp:note-well>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<dm:person id="point-3d">
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gml:Point srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:pos>-34.410649 150.87651 1800</gml:pos>
|
||||
</gml:Point>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>802.11</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp>
|
||||
</dm:person>
|
||||
<tuple id="circle-2d">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Circle srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:pos>-34.410649 150.87651</gml:pos>
|
||||
<gs:radius uom="urn:ogc:def:uom:EPSG::9001">30</gs:radius>
|
||||
</gs:Circle>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>802.11</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<tuple id="circle-3d">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Circle srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:pos>-34.410649 150.87651 1800</gml:pos>
|
||||
<gs:radius uom="urn:ogc:def:uom:EPSG::9001">30</gs:radius>
|
||||
</gs:Circle>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>802.11</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<dm:person id="polygon-2d">
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gml:Polygon srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:exterior>
|
||||
<gml:LinearRing>
|
||||
<gml:pos>43.311 -73.422</gml:pos>
|
||||
<gml:pos>43.111 -73.322</gml:pos>
|
||||
<gml:pos>43.111 -73.222</gml:pos>
|
||||
<gml:pos>43.311 -73.122</gml:pos>
|
||||
<gml:pos>43.411 -73.222</gml:pos>
|
||||
<gml:pos>43.411 -73.322</gml:pos>
|
||||
<gml:pos>43.311 -73.422</gml:pos>
|
||||
</gml:LinearRing>
|
||||
</gml:exterior>
|
||||
</gml:Polygon>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>802.11</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp>
|
||||
</dm:person>
|
||||
<dm:person id="polygon-3d">
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gml:Polygon srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:exterior>
|
||||
<gml:LinearRing>
|
||||
<gml:pos>43.311 -73.422 1800</gml:pos>
|
||||
<gml:pos>43.111 -73.322 1800</gml:pos>
|
||||
<gml:pos>43.111 -73.222 1800</gml:pos>
|
||||
<gml:pos>43.311 -73.122 1800</gml:pos>
|
||||
<gml:pos>43.411 -73.222 1800</gml:pos>
|
||||
<gml:pos>43.411 -73.322 1800</gml:pos>
|
||||
<gml:pos>43.311 -73.422 1800</gml:pos>
|
||||
</gml:LinearRing>
|
||||
</gml:exterior>
|
||||
</gml:Polygon>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>802.11</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp>
|
||||
</dm:person>
|
||||
<tuple id="polygon-poslist-2d">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gml:Polygon srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:exterior>
|
||||
<gml:LinearRing>
|
||||
<gml:posList>
|
||||
43.311 -73.422 43.111 -73.322
|
||||
43.111 -73.222 43.311 -73.122
|
||||
43.411 -73.222 43.411 -73.322
|
||||
43.311 -73.422
|
||||
</gml:posList>
|
||||
</gml:LinearRing>
|
||||
</gml:exterior>
|
||||
</gml:Polygon>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>Wiremap</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<tuple id="polygon-poslist-3d">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gml:Polygon srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:exterior>
|
||||
<gml:LinearRing>
|
||||
<gml:posList>
|
||||
43.311 -73.422 1800 43.111 -73.322 1800
|
||||
43.111 -73.222 1800 43.311 -73.122 1800
|
||||
43.411 -73.222 1800 43.411 -73.322 1800
|
||||
43.311 -73.422 1800
|
||||
</gml:posList>
|
||||
</gml:LinearRing>
|
||||
</gml:exterior>
|
||||
</gml:Polygon>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>Wiremap</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<tuple id="ellipse-2d">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Ellipse srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:pos>42.5463 -73.2512</gml:pos>
|
||||
<gs:semiMajorAxis uom="urn:ogc:def:uom:EPSG::9001">1275</gs:semiMajorAxis>
|
||||
<gs:semiMinorAxis uom="urn:ogc:def:uom:EPSG::9001">670</gs:semiMinorAxis>
|
||||
<gs:orientation uom="urn:ogc:def:uom:EPSG::9102">43.2</gs:orientation>
|
||||
</gs:Ellipse>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules/>
|
||||
<gp:method>Device-Assisted_A-GPS</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<dm:device id="arcband-2d">
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:ArcBand srsName="urn:ogc:def:crs:EPSG::4326">
|
||||
<gml:pos>-43.5723 153.21760</gml:pos>
|
||||
<gs:innerRadius uom="urn:ogc:def:uom:EPSG::9001">3594</gs:innerRadius>
|
||||
<gs:outerRadius uom="urn:ogc:def:uom:EPSG::9001">4148</gs:outerRadius>
|
||||
<gs:startAngle uom="urn:ogc:def:uom:EPSG::9102">20</gs:startAngle>
|
||||
<gs:openingAngle uom="urn:ogc:def:uom:EPSG::9102">20</gs:openingAngle>
|
||||
</gs:ArcBand>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gp:retransmission-allowed>yes</gp:retransmission-allowed>
|
||||
<gp:ruleset-preference>https:/www/more.com</gp:ruleset-preference>
|
||||
<gp:retention-expires>2007-06-22T20:57:29Z</gp:retention-expires>
|
||||
</gp:usage-rules>
|
||||
<gp:method>TA-NMR</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:deviceID>mac:1234567890ab</dm:deviceID>
|
||||
<dm:timestamp>2007-06-22T20:57:29Z</dm:timestamp>
|
||||
</dm:device>
|
||||
<tuple id="sphere">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Sphere srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:pos>42.5463 -73.2512 26.3</gml:pos>
|
||||
<gs:radius uom="urn:ogc:def:uom:EPSG::9001">850.24</gs:radius>
|
||||
</gs:Sphere>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gbp:retransmission-allowed>no</gbp:retransmission-allowed>
|
||||
<gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry>
|
||||
</gp:usage-rules>
|
||||
<gp:method>Device-Based_A-GPS</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
</tuple>
|
||||
<tuple id="ellipsoid">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Ellipsoid srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gml:pos>42.5463 -73.2512 26.3</gml:pos>
|
||||
<gs:semiMajorAxis uom="urn:ogc:def:uom:EPSG::9001">7.7156</gs:semiMajorAxis>
|
||||
<gs:semiMinorAxis uom="urn:ogc:def:uom:EPSG::9001">3.31</gs:semiMinorAxis>
|
||||
<gs:verticalAxis uom="urn:ogc:def:uom:EPSG::9001">28.7</gs:verticalAxis>
|
||||
<gs:orientation uom="urn:ogc:def:uom:EPSG::9102">90</gs:orientation>
|
||||
</gs:Ellipsoid>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules/>
|
||||
<gp:method>Hybrid_A-GPS</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<tuple id="prism">
|
||||
<status>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<gs:Prism srsName="urn:ogc:def:crs:EPSG::4979">
|
||||
<gs:base>
|
||||
<gml:Polygon>
|
||||
<gml:exterior>
|
||||
<gml:LinearRing>
|
||||
<gml:posList>
|
||||
42.556844 -73.248157 36.6 <!--A -->
|
||||
42.656844 -73.248157 36.6 <!--B -->
|
||||
42.656844 -73.348157 36.6 <!--C -->
|
||||
42.556844 -73.348157 36.6 <!--D -->
|
||||
42.556844 -73.248157 36.6 <!--A -->
|
||||
</gml:posList>
|
||||
</gml:LinearRing>
|
||||
</gml:exterior>
|
||||
</gml:Polygon>
|
||||
</gs:base>
|
||||
<gs:height uom="urn:ogc:def:uom:EPSG::9001">2.4</gs:height>
|
||||
</gs:Prism>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules/>
|
||||
<gp:method>Wiremap</gp:method>
|
||||
</gp:geopriv>
|
||||
</status>
|
||||
<timestamp>2007-06-22T20:57:29Z</timestamp>
|
||||
</tuple>
|
||||
<dm:device>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<ca:civicAddress xml:lang="en-AU">
|
||||
<ca:country>AU</ca:country>
|
||||
<ca:A1>NSW</ca:A1>
|
||||
<ca:A3>Wollongong</ca:A3>
|
||||
<ca:A4>North Wollongong</ca:A4>
|
||||
<ca:RD>Flinders</ca:RD>
|
||||
<ca:STS>Street</ca:STS>
|
||||
<ca:RDBR>Campbell Street</ca:RDBR>
|
||||
<ca:LMK>Gilligan's Island</ca:LMK>
|
||||
<ca:LOC>Corner</ca:LOC>
|
||||
<ca:NAM> Video Rental Store </ca:NAM>
|
||||
<ca:PC>2500</ca:PC>
|
||||
<ca:ROOM> Westerns and Classics </ca:ROOM>
|
||||
<ca:PLC>store</ca:PLC>
|
||||
<ca:POBOX>Private Box 15</ca:POBOX>
|
||||
</ca:civicAddress>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
<gp:retransmission-allowed>yes</gp:retransmission-allowed>
|
||||
<gp:ruleset-preference>https:/www/more.com</gp:ruleset-preference>
|
||||
<gp:retention-expires>2007-06-22T20:57:29Z</gp:retention-expires>
|
||||
</gp:usage-rules>
|
||||
<gp:method>GPS</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:deviceID>mac:1234567890ab</dm:deviceID>
|
||||
<dm:timestamp>2007-06-22T20:57:29Z</dm:timestamp>
|
||||
</dm:device>
|
||||
</presence>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:gml="http://www.opengis.net/gml"
|
||||
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
|
||||
xmlns:gs="http://www.opengis.net/pidflo/1.0"
|
||||
xmlns:con="urn:ietf:params:xml:ns:geopriv:conf"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
|
||||
@@ -41,34 +42,47 @@
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
<xsl:strip-space elements="*"/>
|
||||
<xsl:param name="path"/>
|
||||
|
||||
<!--
|
||||
Even though the "presence", "tuple", and "status" elements won't have namespaces in the
|
||||
incoming PIDF document, we have to use the pseudo-namespace "def" here because of namespace
|
||||
processing quirks in libxml2 and libxslt.
|
||||
|
||||
We don't use namespace prefixes in the output document at all.
|
||||
processing quirks in libxml2 and libxslt. We don't use namespace prefixes in the output
|
||||
document at all.
|
||||
-->
|
||||
<xsl:template match="/def:presence">
|
||||
<xsl:element name="presence">
|
||||
<xsl:attribute name="entity"><xsl:value-of select="@entity"/></xsl:attribute>
|
||||
<xsl:apply-templates select="$path"/>
|
||||
<!--
|
||||
We only want devices, tuples and persons (in that order) that
|
||||
have location-info elements.
|
||||
-->
|
||||
<xsl:apply-templates select="dm:device[./gp:geopriv/gp:location-info]"/>
|
||||
<xsl:apply-templates select="def:tuple[./def:status/gp:geopriv/gp:location-info]"/>
|
||||
<xsl:apply-templates select="dm:person[.//gp:geopriv/gp:location-info]"/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dm:device">
|
||||
<xsl:element name="device">
|
||||
<xsl:template name="geopriv">
|
||||
<xsl:apply-templates select=".//gp:geopriv/gp:location-info"/>
|
||||
<xsl:apply-templates select=".//gp:geopriv/gp:usage-rules"/>
|
||||
<xsl:apply-templates select=".//gp:geopriv/gp:method"/>
|
||||
<xsl:apply-templates select=".//gp:geopriv/gp:note-well"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="def:tuple">
|
||||
<xsl:element name="tuple">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
|
||||
<xsl:apply-templates select=".//gp:location-info"/>
|
||||
<xsl:apply-templates select=".//gp:usage-rules"/>
|
||||
<xsl:apply-templates select=".//gp:method"/>
|
||||
<xsl:apply-templates select=".//gp:note-well"/>
|
||||
<xsl:if test="./dm:timestamp">
|
||||
<timestamp>
|
||||
<xsl:value-of select="./dm:timestamp"/>
|
||||
</timestamp>
|
||||
</xsl:if>
|
||||
<xsl:call-template name="geopriv"/>
|
||||
<xsl:apply-templates select="./def:timestamp"/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dm:device|dm:person">
|
||||
<xsl:element name="{local-name(.)}">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
|
||||
<xsl:call-template name="geopriv"/>
|
||||
<xsl:apply-templates select="./dm:timestamp"/>
|
||||
<!-- deviceID should only apply to devices -->
|
||||
<xsl:if test="./dm:deviceID">
|
||||
<deviceID>
|
||||
<xsl:value-of select="./dm:deviceID"/>
|
||||
@@ -77,63 +91,69 @@
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="def:tuple">
|
||||
<xsl:element name="tuple">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
|
||||
<xsl:apply-templates select=".//gp:location-info"/>
|
||||
<xsl:apply-templates select=".//gp:usage-rules"/>
|
||||
<xsl:apply-templates select=".//gp:method"/>
|
||||
<xsl:apply-templates select=".//gp:note-well"/>
|
||||
<xsl:if test="./timestamp">
|
||||
<timestamp>
|
||||
<xsl:value-of select="./timestamp"/>
|
||||
</timestamp>
|
||||
</xsl:if>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dm:person">
|
||||
<xsl:element name="person">
|
||||
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
|
||||
<xsl:apply-templates select=".//gp:location-info"/>
|
||||
<xsl:apply-templates select=".//gp:usage-rules"/>
|
||||
<xsl:apply-templates select=".//gp:method"/>
|
||||
<xsl:apply-templates select=".//gp:note-well"/>
|
||||
<xsl:if test="./dm:timestamp">
|
||||
<timestamp>
|
||||
<xsl:value-of select="./dm:timestamp"/>
|
||||
</timestamp>
|
||||
</xsl:if>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gp:location-info/gml:*">
|
||||
<xsl:template match="gp:geopriv/gp:location-info">
|
||||
<xsl:element name="location-info">
|
||||
<xsl:attribute name="format">gml</xsl:attribute>
|
||||
<xsl:call-template name="shape" />
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gp:location-info/gs:*">
|
||||
<xsl:element name="location-info">
|
||||
<xsl:attribute name="format">gml</xsl:attribute>
|
||||
<xsl:call-template name="shape" />
|
||||
<xsl:choose>
|
||||
<xsl:when test="ca:civicAddress">
|
||||
<xsl:attribute name="format">civicAddress</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="gml:*">
|
||||
<xsl:attribute name="format">gml</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="gs:*">
|
||||
<xsl:attribute name="format">gml</xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
<xsl:apply-templates/> <!-- Down we go! -->
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Civic Address -->
|
||||
<xsl:template match="gp:location-info/ca:civicAddress">
|
||||
<xsl:element name="location-info">
|
||||
<xsl:attribute name="format">civicAddress</xsl:attribute>
|
||||
<xsl:call-template name="civicAddress" />
|
||||
<xsl:element name="civicAddress">
|
||||
<xsl:attribute name="lang"><xsl:value-of select="@xml:lang"/></xsl:attribute>
|
||||
<!-- The for-each seems to be slightly faster than applying another template -->
|
||||
<xsl:for-each select="./*">
|
||||
<xsl:call-template name="name-value" />
|
||||
</xsl:for-each>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!--
|
||||
All of the "following-sibling" things just stick a comma after the value if there's another
|
||||
element after it. The result should be...
|
||||
<!-- End of Civic Address. Back up to location-info. -->
|
||||
|
||||
name1="value1", name2="value2"
|
||||
-->
|
||||
<!-- The GML shapes: gml:Point, gs:Circle, etc. -->
|
||||
<xsl:template match="gp:location-info/gml:*|gp:location-info/gs:*">
|
||||
<xsl:element name="{local-name(.)}">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4326'">
|
||||
<xsl:attribute name="srsName">2d</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4979'">
|
||||
<xsl:attribute name="srsName">3d</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="srsName">unknown</xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:apply-templates /> <!-- Down we go! -->
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!-- The supported GML attributes -->
|
||||
<xsl:template match="gs:orientation"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gs:radius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:height"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:semiMajorAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:semiMinorAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:verticalAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:innerRadius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:outerRadius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:startAngle"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gs:openingAngle"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gml:pos"><xsl:call-template name="name-value" /></xsl:template>
|
||||
<xsl:template match="gml:posList"><xsl:call-template name="name-value" /></xsl:template>
|
||||
|
||||
<!-- The GML attribute types -->
|
||||
<xsl:template name="name-value">
|
||||
<xsl:element name="{local-name(.)}">
|
||||
<xsl:value-of select="normalize-space(.)"/>
|
||||
@@ -154,58 +174,39 @@
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gs:orientation"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gs:radius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:height"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:semiMajorAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:semiMinorAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:verticalAxis"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:innerRadius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:outerRadius"><xsl:call-template name="length" /></xsl:template>
|
||||
<xsl:template match="gs:startAngle"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gs:openingAngle"><xsl:call-template name="angle" /></xsl:template>
|
||||
<xsl:template match="gml:pos"><xsl:call-template name="name-value" /></xsl:template>
|
||||
<xsl:template match="gml:posList"><xsl:call-template name="name-value" /></xsl:template>
|
||||
<!-- End of GML. Back up to location-info -->
|
||||
|
||||
<xsl:template name="shape">
|
||||
<xsl:template match="gp:location-info/con:confidence">
|
||||
<xsl:element name="{local-name(.)}">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4326'">
|
||||
<xsl:attribute name="srsName">2d</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4979'">
|
||||
<xsl:attribute name="srsName">3d</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="srsName">unknown</xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:apply-templates />
|
||||
<xsl:attribute name="pdf"><xsl:value-of select="@pdf"/></xsl:attribute>
|
||||
<xsl:value-of select="normalize-space(.)" />
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ca:civicAddress/*"><xsl:call-template name="name-value" /></xsl:template>
|
||||
<xsl:template name="civicAddress">
|
||||
<xsl:element name="{local-name(.)}">
|
||||
<xsl:attribute name="lang"><xsl:value-of select="@xml:lang"/></xsl:attribute>
|
||||
<xsl:apply-templates select="./*"/>
|
||||
<!-- End of location-info. Back up to geopriv -->
|
||||
|
||||
<xsl:template match="gp:geopriv/gp:usage-rules">
|
||||
<xsl:element name="usage-rules">
|
||||
<xsl:for-each select="./*">
|
||||
<xsl:call-template name="name-value" />
|
||||
</xsl:for-each>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gp:usage-rules/*">
|
||||
<xsl:template match="gp:geopriv/gp:method">
|
||||
<xsl:call-template name="name-value" />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gp:usage-rules">
|
||||
<xsl:element name="usage-rules">
|
||||
<xsl:apply-templates />
|
||||
<xsl:template match="gp:geopriv/gp:note-well">
|
||||
<xsl:element name="note-well">
|
||||
<xsl:value-of select="." />
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="gp:method">
|
||||
<xsl:element name="method">
|
||||
<xsl:value-of select="normalize-space(.)" />
|
||||
</xsl:element>
|
||||
<!-- End of geopriv. Back up to device/tuple/person -->
|
||||
|
||||
<xsl:template match="def:timestamp|dm:timestamp">
|
||||
<xsl:call-template name="name-value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
183
res/res_geolocation/wiki/AsteriskImplementation.md
Normal file
183
res/res_geolocation/wiki/AsteriskImplementation.md
Normal file
@@ -0,0 +1,183 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
h1. Introduction
|
||||
|
||||
The Geolocation capabilities are implemented in Asterisk with the res_geolocation and res_pjsip_geolocation modules and the geolocation.conf configuration file. There are also dialplan functions which allow you to manipulate location information as it's passed through the dialplan.
|
||||
|
||||
h1. Location Information Flow
|
||||
|
||||
Location information can be supplied to Asterisk from several sources during the call flow...
|
||||
* Sent by a caller in a SIP INVITE message.
|
||||
* Provided by a geolocation profile attached to the caller's endpoint.
|
||||
* Provided by the dialplan via the Geolocation apps and functions.
|
||||
* Provided by a geolocation profile attached to the callee's endpoint.
|
||||
|
||||
These sources aren't mutually exclusive and may, in fact, provide conflicting information or present the same information in multiple formats. Given that, there's no way for Asterisk to merge information nor is there a way for Asterisk to automatically determine which source should take precedence. However, you can use the geolocation profiles and the dialplan functions to tell Asterisk what to do with the location information received from the previous step in the call flow.
|
||||
|
||||
h1. Core Configuration
|
||||
The bulk of the geolocation support is implemented in the res_geolocation module and configured in the geolocation.conf file. The file contains two main objects, Location and Profile.
|
||||
|
||||
h2. Common Behavior
|
||||
|
||||
h3. Sub-parameters
|
||||
Some of the parameters in each object are actually lists of comma-separated name-value "sub-parameters". For example, the {{location_info}} parameter in the Location object contains a list of sub-parameters that are specific to the location type.
|
||||
{code}
|
||||
location_info = shape=Circle, pos="39.12345 -105.98766", radius=100
|
||||
{code}
|
||||
Spaces around the equals signs and commas are ignored so you must double quote sub-parameter values with spaces or commas in them.
|
||||
|
||||
For readability, parameters that use sub-parameters can be split over more than one line. For example:
|
||||
{code}
|
||||
location_info = country=US,A1="New York"
|
||||
location_info = house_number=1633,PRD=W,street=46th
|
||||
{code}
|
||||
would be equivalent to:
|
||||
{code}
|
||||
location_info = country=US,A1="New York",house_number=1633,PRD=W,street=46th
|
||||
{code}
|
||||
|
||||
h3. Variable substitution
|
||||
Some of the parameters can contain references to channel variables and dialplan functions. For example, you might have a URI location object that contains a reference to the {{EXTEN}} channel variable:
|
||||
{code}
|
||||
location_info = URI=http://some.example.com?key=${EXTEN}
|
||||
{code}
|
||||
When a call is processed that uses this location object, {{$\{EXTEN\}}} would be replaced with the channel's extension and would result in a URI such as {{http://some.example.com?key=1000}}. You'd set up your web server to return a location document based on the value of "key".
|
||||
|
||||
You can also use dialplan functions such as {{CURL}} and {{ODBC_SQL}} to supply values just as you would in extensions.conf.
|
||||
|
||||
h2. Location
|
||||
The Location object defines a discrete location or defines a template that can be used to define a discrete location on a per-call basis.
|
||||
||Parameter||Required?||Uses Channel\\Variables?||Uses Sub\\Parameters?||Usage||
|
||||
|type|yes|no|no|Must be "location"|
|
||||
|format|yes|no|no|"civicAddress", "GML" or "URI" to indicate how the location is expressed.|
|
||||
|method|no|no|no|If provided, it MUST be one of "GPS", "A-GPS", "Manual", "DHCP", "Triangulation", "Cell", "802.11"|
|
||||
|location_source|no|no|no|If provided, it MUST be a fully qualified domain name. IP addresses are specifically not allowed.
|
||||
See [RFC8787|Geolocation Reference Information#rfc8787] for the exact definition of this parameter.|
|
||||
|location_info|yes|yes|yes|The sub-parameters of location_info are dependent on the location's format:
|
||||
* URI: A single {{URI}} sub-parameter with the URI.
|
||||
Example: {{location_info = URI=http://some.example.com}}
|
||||
See the [URI] page for more info.
|
||||
* civicAddress: A set of sub-parameters that describe the location.
|
||||
Example:
|
||||
{code}
|
||||
location_info = country=US,A1="New York",A3="New York"
|
||||
location_info = house_number=1633,PRD=W,street=46th
|
||||
location_info = street_suffix = Street,postal_code=10222
|
||||
{code}
|
||||
See the [Civic Address] page for more info.
|
||||
* GML: A set of sub-parameters that describe the location.
|
||||
Example: {{location_info = shape=Circle, pos="39.12345 -105.98766", radius=100}}
|
||||
See the [GML] page for more info.|
|
||||
|confidence|no|no|yes|This is a rarely used field in the specification that would indicate the confidence in the location specified. See [RFC7459|https://www.rfc-editor.org/rfc/rfc7459] for exact details.
|
||||
Sub-parameters:
|
||||
* {{pdf}}: One of: "unknown", "normal", "rectangular".
|
||||
* {{value}}: A percentage indicating the confidence.
|
||||
|
|
||||
|
||||
|
||||
h2. Profile
|
||||
The Profile object defines how a location is used and is referenced by channel drivers.
|
||||
|
||||
||Parameter||Required?||Uses Channel\\Variables?||Uses Sub\\Parameters?||Usage||
|
||||
|type|yes|no|no|Must be "profile"|
|
||||
|location_reference|no|no|no|Specifies the id of a Location object to use.|
|
||||
|pidf_element|no|no|no|For Civic Address and GML location formats, this parameter specifies the PIDF element that will carry the location description on outgoing SIP requests. Must be one of "tuple", "device" or "person". The default is "device".|
|
||||
|allow_routing_use|no|no|no|This value controls the value of the {{Geolocation-Routing}} header sent on SIP requests, Must be "yes" or "no". The default is "no".
|
||||
See [RFC6442|Geolocation Reference Information#rfc6442] for more information.|
|
||||
|profile_precedence|no|no|no|Specifies which of the available profiles (configured or incoming) takes precedence.\\
|
||||
NOTE: On an incoming call leg/channel, the "incoming" profile is the one received by the channel driver from the calling party in the SIP INVITE and the "configured" profile is the one attached to the calling party's pjsip endpoint. On an outgoing call segment/channel, the "incoming" profile is the one received by the channel driver from the Asterisk core/dialplan and the "configured" profile one is the one attached to the called party's pjsip endpoint.
|
||||
* {{prefer_incoming}}: Use the incoming profile if it exists and has location information, otherwise use the configured profile if it has location information. If neither profile has location information, nothing is sent.
|
||||
* {{force_incoming}}: Discard any configured profile and use the incoming profile if it exists and it has location information. If the incoming profile doesn't exist or has no location information, nothing is sent.
|
||||
* {{prefer_config}}: Use the configured profile if it exists and has location information, otherwise use the incoming profile if it exists and has location information. If neither profile has location information, nothing is sent.
|
||||
* {{force_config}}: Discard any incoming profile and use the configured profile if it exists and it has location information. If the configured profile doesn't exist or has no location information, nothing is sent.
|
||||
|
|
||||
|usage_rules|no|yes|yes|For Civic Address and GML location formats, this parameter specifies the contents of the {{usage-rules}} PIDF-LO element.\\
|
||||
* {{retransmission-allowed}}: Must be "yes" or "no". The default is "no".\\
|
||||
* {{retention-expires}}: An ISO-format timestamp after which the recipient MUST discard and location information associated with this request. The default is 24 hours after the request was sent. You can use dialplan functions to create a timestamp yourself if needed. For example, to set the timestamp to 1 hour after the request is sent, use:
|
||||
{{retention-expires="$\{STRFTIME($[$\{EPOCH\}+3600],UTC,%FT%TZ)\}"}}\\
|
||||
See [RFC4119|Geolocation Reference Information#rfc4119] for the exact definition of this parameter.
|
||||
|
|
||||
|location_info_refinement|no|yes|yes|This parameter can be used to refine referenced location by adding these sub-parameters to the {{location_info}} parameter of the referenced location object. For example, you could have Civic Address referenced object describe a building, then have this profile refine it by adding floor, room, etc. Another profile could then also reference the same location object and refine it by adding a different floor, room, etc.
|
||||
|location_variables|no|yes|yes|Any parameter than can use channel variables can also use the arbitrary variables defined in this parameter. For example {{location_variables = MYVAR1=something, MYVAR2="something else"}} would allow you to use {{$\{MYVAR1\}}} and {{$\{MYVAR2\}}} in any other parameter that can accept channel variables|
|
||||
|notes|no|no|no|The specifications allow a free-form "note-well" element to be added to the location description. Any text entered here will be present on all outgoing Civic Address and GML requests.|
|
||||
|
||||
h1. chan_pjsip Configuration
|
||||
Two new parameters have been added to pjsip endpoints:
|
||||
||Parameter||Usage||
|
||||
|geoloc_incoming_call_profile|Should be set to the name of a geolocation profile to use for calls coming into Asterisk from this remote endpoint. If not set, no geolocation processing will occur and any location descriptions present on the incoming request will be silently dropped.|
|
||||
|geoloc_outgoing_call_profile|Should be set to the name of a geolocation profile to use for calls Asterisk sends to this remote endpoint. If not set, no geolocation processing will occur and any location descriptions coming from the associated incoming channel or the dialplan will be silently dropped and not conveyed to the endpoint.|
|
||||
|
||||
h1. Dialplan Applications and Functions
|
||||
Two new dialplan applications and one dialplan function have been added to allow a dialplan author to manipulate geolocation information.
|
||||
|
||||
h2. GeolocProfileCreate
|
||||
This application creates a new Geolocation profile on the channel in addition to any others that may already exist. It tasks a profile name and an index as its arguments. Callers must use the {{GEOLOC_PROFILE}} function to set its actual location description.
|
||||
|
||||
h2. GeolocProfileDelete
|
||||
This application deletes the existing Geolocation profile at the specified index from the channel's list of profiles.
|
||||
|
||||
h2. GEOLOC_PROFILE
|
||||
This function can get or set any of the fields in a specific profile. The available fields are those in _both_ the Location and Profile configuration objects.
|
||||
|
||||
h1. Example Call Flows
|
||||
|
||||
h2. Simple Example 1
|
||||
Alice and Bob work in the same building so in geolocation.conf, we can define a location that describes the building and profiles for Bob and Alice that add floor and room. We're assuming here that Bob's and Alice's phones don't send any location information themselves.
|
||||
{code}
|
||||
[building1]
|
||||
type = location
|
||||
format = civicAddress
|
||||
location_info = country=US, A1="New York", A3="New York",
|
||||
location_info = HNO=1633, PRD=W, RD=46th, STS=Street, PC=10222
|
||||
method = Manual
|
||||
|
||||
[alice]
|
||||
type = profile
|
||||
location_reference = building1
|
||||
location_refinement = FLR=4, ROOM=4B20
|
||||
|
||||
[bob]
|
||||
type = profile
|
||||
location_reference = building1
|
||||
location_refinement = FLR=32, ROOM=32A6
|
||||
{code}
|
||||
|
||||
In pjsip.conf, we can now associate those profiles to endpoints.
|
||||
{code}
|
||||
[bob]
|
||||
type = endpoint
|
||||
geoloc_incoming_call_profile = bob
|
||||
|
||||
[alice]
|
||||
type = endpoint
|
||||
geoloc_incoming_call_profile = alice
|
||||
{code}
|
||||
You'll notice that neither bob nor alice set {{geoloc_outgoing_call_profile}} because we never want to send location information _to_ them.
|
||||
|
||||
Now when Alice makes a call, Asterisk will construct an effective profile (including any defaults and variable substitutions) that looks like this...
|
||||
{code}
|
||||
format = civicAddress
|
||||
location_info = country=US, A1="New York", A3="New York",
|
||||
location_info = HNO=1633, RD=46th, STS=Street, PC=10222, FLR=4, ROOM=4B20
|
||||
method = Manual
|
||||
usage_rules = retransmission-allowed=no
|
||||
usage_rules = retention-expires="${STRFTIME($[${EPOCH}+86400],UTC,%FT%TZ)}"
|
||||
allow_routing = no
|
||||
pidf_element = device
|
||||
{code}
|
||||
|
||||
Bob's effective profile would be exactly the same except for {{FLR}} and {{ROOM}}
|
||||
|
||||
This effective profile will then be forwarded to the dialplan. The dialplan application can then use GEOLOC_PROFILE to make changes before the effective profile is forwarded to the outgoing channel. It can also use GeolocProfileDelete to just delete the effective profile and pass nothing.
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
167
res/res_geolocation/wiki/CivicAddress.md
Normal file
167
res/res_geolocation/wiki/CivicAddress.md
Normal file
@@ -0,0 +1,167 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
h1. Introduction
|
||||
For static locations, using Civic Address location descriptions would be the easiest method. As stated earlier though, you and your partners must agree on which description formats are acceptable.
|
||||
|
||||
The following tables list the IANA registered element names that are currently accepted. The complete list of codes is defined in:
|
||||
[https://www.iana.org/assignments/civic-address-types-registry/civic-address-types-registry.xhtml]
|
||||
|
||||
These codes were originally defined in [RFC4119|Geolocation Reference Information#rfc4119] and [RFC4776|Geolocation Reference Information#rfc4776]
|
||||
|| Label || Description || Example |
|
||||
| country | The country is identified by the two-letter ISO 3166 code.|US|
|
||||
| A1 | national subdivisions (state, region, province, prefecture)|New York|
|
||||
| A2 | county, parish, gun (JP), district (IN)|King's County|
|
||||
| A3 | city, township, shi (JP)|New York|
|
||||
| A4 | city division, borough, city, district, ward, chou (JP)|Manhattan|
|
||||
| A5 | neighborhood, block | Morningside Heights |
|
||||
| A6 | street\\NOTE: This code has been deprecated in favor of {{RD}}, defined below. | Broadway |
|
||||
| PRD | Leading street direction| N, W |
|
||||
| POD | Trailing street direction| SW |
|
||||
| STS | Street suffix | Avenue, Platz, Street|
|
||||
| HNO | House number, numeric part only|123|
|
||||
| HNS | House number suffix | A, 1/2 |
|
||||
| LMK | Landmark or vanity address|Low Library |
|
||||
| LOC | Additional location information\\NOTE: {{ROOM}} was added below.| Room 543 |
|
||||
| FLR | Floor | 5 |
|
||||
| NAM | Name (residence, business or office occupant)|Joe's Barbershop |
|
||||
| PC | Postal code | 10027-0401 |
|
||||
|
||||
These codes were added in [RFC5139|Geolocation Reference Information#rfc5139]
|
||||
|
||||
|| Label || Description || Example |
|
||||
| BLD | Building (structure) | Hope Theatre |
|
||||
| UNIT | Unit (apartment, suite) | 12a |
|
||||
| ROOM | Room | 450F |
|
||||
| PLC | Place-type | office |
|
||||
| PCN | Postal community name | Leonia |
|
||||
| POBOX | Post office box (P.O. box) | U40 |
|
||||
| ADDCODE | Additional Code | 13203000003 |
|
||||
| SEAT | Seat (desk, cubicle, workstation) | WS 181 |
|
||||
| RD | Primary road or street | Broadway |
|
||||
| RDSEC | Road section | 14 |
|
||||
| RDBR | Road branch | Lane 7 |
|
||||
| RDSUBBR | Road sub-branch | Alley 8 |
|
||||
| PRM | Road pre-modifier | Old |
|
||||
| POM | Road post-modifier | Service |
|
||||
|
||||
These codes were added in [RFC6848|Geolocation Reference Information#rfc6848]
|
||||
|
||||
|| Label || Description || Example |
|
||||
|PN|Post number that is attributed to a lamp post or utility pole.|21344567|
|
||||
|MP|Milepost: a marker indicating distance to or from a place (often a town)
|
||||
May actually be expressed in "miles" or "kilometers".|237.4|
|
||||
|STP|Street Type Prefix.|Boulevard|
|
||||
|HNP|House Number Prefix.|Z|
|
||||
|
||||
h1. Example Configurations
|
||||
|
||||
h2. Simple Example 1
|
||||
In geolocation.conf, we can define a location that describes a building and profiles for Bob and Alice that add floor and room. We're assuming here that Bob's and Alice's phones don't send any location information themselves.
|
||||
{code}
|
||||
[building1]
|
||||
type = location
|
||||
format = civicAddress
|
||||
location_info = country=US, A1="New York", A3="New York",
|
||||
location_info = HNO=1633, PRD=W, RD=46th, STS=Street, PC=10222
|
||||
method = Manual
|
||||
|
||||
[alice]
|
||||
type = profile
|
||||
location_reference = building1
|
||||
location_refinement = FLR=4, ROOM=4B20
|
||||
|
||||
[bob]
|
||||
type = profile
|
||||
location_reference = building1
|
||||
location_refinement = FLR=32, ROOM=32A6
|
||||
{code}
|
||||
|
||||
h1. PIDF-LO XML Examples
|
||||
|
||||
Here's what Alice's PIDF-LO would look like:
|
||||
{code}
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<presence entity="pres:alice@example.com"
|
||||
xmlns="urn:ietf:params:xml:ns:pidf"
|
||||
xmlns:ca="urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"
|
||||
xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"
|
||||
xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"
|
||||
xmlns:gml="http://www.opengis.net/gml"
|
||||
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
|
||||
xmlns:gs="http://www.opengis.net/pidflo/1.0">
|
||||
<dm:device>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<ca:civicAddress xml:lang="en-AU">
|
||||
<ca:country>US</ca:country>
|
||||
<ca:A1>New York</ca:A1>
|
||||
<ca:A3>New York</ca:A3>
|
||||
<ca:HNO>1633</ca:HNO>
|
||||
<ca:PRD>W</ca:PRD>
|
||||
<ca:RD>46th</ca:RD>
|
||||
<ca:STS>Street</ca:STS>
|
||||
<ca:PC>10222</ca:PC>
|
||||
<ca:FLR>4</ca:FLR>
|
||||
<ca:ROOM>4B20</ca:ROOM>
|
||||
</ca:civicAddress>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
</gp:usage-rules>
|
||||
<gp:method>manual</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:deviceID>mac:1234567890ab</dm:deviceID>
|
||||
<dm:timestamp>2022-04-22T20:57:29Z</dm:timestamp>
|
||||
</dm:device>
|
||||
</presence>
|
||||
{code}
|
||||
|
||||
Here's what Bob's PIDF-LO would look like:
|
||||
{code}
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<presence entity="pres:bob@example.com"
|
||||
xmlns="urn:ietf:params:xml:ns:pidf"
|
||||
xmlns:ca="urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"
|
||||
xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"
|
||||
xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"
|
||||
xmlns:gml="http://www.opengis.net/gml"
|
||||
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
|
||||
xmlns:gs="http://www.opengis.net/pidflo/1.0">
|
||||
<dm:device>
|
||||
<gp:geopriv>
|
||||
<gp:location-info>
|
||||
<ca:civicAddress xml:lang="en-AU">
|
||||
<ca:country>US</ca:country>
|
||||
<ca:A1>New York</ca:A1>
|
||||
<ca:A3>New York</ca:A3>
|
||||
<ca:HNO>1633</ca:HNO>
|
||||
<ca:PRD>W</ca:PRD>
|
||||
<ca:RD>46th</ca:RD>
|
||||
<ca:STS>Street</ca:STS>
|
||||
<ca:PC>10222</ca:PC>
|
||||
<ca:FLR>32</ca:FLR>
|
||||
<ca:ROOM>32A6</ca:ROOM>
|
||||
</ca:civicAddress>
|
||||
</gp:location-info>
|
||||
<gp:usage-rules>
|
||||
</gp:usage-rules>
|
||||
<gp:method>manual</gp:method>
|
||||
</gp:geopriv>
|
||||
<dm:deviceID>mac:1234567890ab</dm:deviceID>
|
||||
<dm:timestamp>2022-04-22T20:57:29Z</dm:timestamp>
|
||||
</dm:device>
|
||||
</presence>
|
||||
{code}
|
||||
|
||||
Note that the only civicAddress difference between the two are the {{FLR}} and {{ROOM}}.
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
60
res/res_geolocation/wiki/GML.md
Normal file
60
res/res_geolocation/wiki/GML.md
Normal file
@@ -0,0 +1,60 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
h1. Introduction
|
||||
All compliant participants are required to support GML as the description language but it's really only suitable for mobile devices. As stated earlier though, you and your partners must agree on which description formats are acceptable.
|
||||
|
||||
The language itself is fairly simple. There are 8 shapes that can be used to describe a location and they share a common set of attributes described below. Determining the actual values for those attributes though can be quite complex and is not covered here.
|
||||
|
||||
h2. References:
|
||||
* [Open Geospatial Consortium Geography Markup Language|gml]
|
||||
* [GML 3.1.1 PIDF-LO Shape Application Schema|geoshape]
|
||||
* [Universal Geographical Area Description (GAD)|gad] (for background)
|
||||
|
||||
h2. Coordinate Reference Systems
|
||||
The coordinate reference system (crs) for a shape specifies whether the points that define a shape express a two dimensional or three dimensional point in space. It does NOT specify whether the shape itself is 2D or 3D. For instance, a Point is a one dimensional "shape" but it can be specified with just a latitude and longitude (2d) or latitude, longitude and altitude (3d). The `crs` is specified for each shape with the `crs` attribute whose value can be either `2d` or `3d`.
|
||||
|
||||
h2. Units of Measure
|
||||
h3. Position
|
||||
Positions are always specified in decimal degrees latitude and longitude. A 3d position adds the altitude in meters. `pos` and `posList` are the two attributes that specify position.
|
||||
h3. Distance
|
||||
Distance is _always_ specified in meters. `height`, `radius` and the altitude component of `pos` are some of the distance attributes.
|
||||
|
||||
*A special note about altitude:* As of the date of this writing (May 2022) we couldn't find any mention in the RFCs concerning the altitude reference. Is it above:
|
||||
# Ground Level (AGL)
|
||||
# Mean Sea Level (MSL)
|
||||
# A Geoid reference (which one?)
|
||||
|
||||
h3. Angle
|
||||
Angle may be specified in either degrees or radians by specifying the `degrees` or `radians` suffix to the angle value. The default it `degrees` if no suffix is provided. `orientation`, `startAngle` and `openingAngle` are some of the angle attributes.
|
||||
|
||||
h2. Shapes
|
||||
h3. Point
|
||||
A Point isn't really a "shape" because it's a one dimensional construct but we'll ignore that. It's simply a point in space specified with either two or three dimensions.
|
||||
|
||||
|
||||
|
||||
|| Shape || Attributes || Description ||
|
||||
| Point | pos or pos3d | A single point |
|
||||
| Circle | pos or pos3d, radius | A two dimensional circle around a point |
|
||||
| Sphere | pos3d, radius | A 3 dimensional sphere around a point |
|
||||
|
||||
|| Attribute || Description || Units || Example ||
|
||||
| pos | A two dimensional point | Decimal degrees | pos="39.12345 -105.98766" |
|
||||
| pos3d | A three dimensional point | Decimal degrees + altitude in meters | pos="39.12345 -105.98766 1690" |
|
||||
| radius | Distance | Meters | radius="20" |
|
||||
| height | Distance | Meters | height="45" |
|
||||
| orientation | Angle | Degrees (default) or Radians | orientation="90", orientation="25 radians" |
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
|
||||
|
||||
74
res/res_geolocation/wiki/Geolocation.md
Normal file
74
res/res_geolocation/wiki/Geolocation.md
Normal file
@@ -0,0 +1,74 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
{warning:title=Please Read!}
|
||||
Before you go off on a geolocation configuration spree, you'll need to understand a few things about Geolocation itself.
|
||||
* It's not a single specification.
|
||||
While a good part of the implementation is covered in RFCs, some of it is documented in the Geography Markup Language Specification, the 3GPP Technical Specifications, national organizations like the FCC and National Emergency Number Association in the US, and probably your interfacing carriers. The last is the most important as you don't want emergency calls dropped or routed to incorrect emergency service centers because of a configuration incompatibility.
|
||||
|
||||
* It's been around a while.
|
||||
The first references I could find date back to 2002. Since then there have been innumerable changes including IETF drafts that expired 15 years ago that are still being returned by Google searches.
|
||||
|
||||
With that in mind, please do your own research and coordinate closely with your partners to validate your configuration.
|
||||
{warning}
|
||||
|
||||
h1. Introduction
|
||||
|
||||
As it applies to Asterisk, Geolocation is the process of...
|
||||
* A channel driver accepting location information in an incoming SIP INVITE, either by reference or by value, then using a geolocation profile to determine the disposition of that information and/or possibly add or delete information.
|
||||
* Passing the resulting information (if any) to the dialplan which can also determine the disposition of that information and/or possibly add or delete information.
|
||||
* Passing the information from the dialplan to the outgoing channel driver which can also use a geolocation profile to determine the disposition of that information and/or possibly add or delete information.
|
||||
* Finally sending the information to another party, either by reference or by value.
|
||||
|
||||
|
||||
h1. What's a "location"?
|
||||
|
||||
h2. Describing a Location
|
||||
There are currently two ways to describe a location.
|
||||
|
||||
h3. Geography Markup Language (GML)
|
||||
GML allows you to express a location in terms of shapes, coordinates, lengths, angles, etc. For example, a Point with a latitude, longitude and altitude, or a Sphere with a latitude, longitude, altitude and radius. Other shapes include, Circle, Polygon, Ellipse, Ellipsoid, and Prism. See [GeoShape|Geolocation Reference Information#geoshape].
|
||||
|
||||
GML would most often be used by mobile systems where the originator's location is determined dynamically such as base station, sector antenna, distance, etc. According to [RFC4119|Geolocation Reference Information#rfc4119] GML is considered to be the "baseline" format and MUST be supported by all implementations. The _level_ of support is not well defined however. For instance, a specific implementation may only support a subset of shapes.
|
||||
|
||||
h3. Civic Address
|
||||
For fixed locations, Civic Address is probably the most used location description method. It's described with terms like Country, State/Province, City, Neighborhood, Street, House Number, Floor, Room, etc. Oddly enough, support for Civic Address is NOT required by [RFC4119|Geolocation Reference Information#rfc4119].
|
||||
|
||||
Both methods are expressed in XML but which location description method you use is entirely between you and your partners.
|
||||
|
||||
h3. Encapsulation
|
||||
The IETF chose the "Presence Information Data Format" (PIDF) as the wrapper document for location information which can be placed in {{<tuple>}}, {{<device>}}, or {{<person>}} sub-elements. BTW, this is the same PIDF used to convey SIP subscription information but Asterisk is only supporting PIDF-LO in INVITE requests at this time.
|
||||
|
||||
The specification allows multiple locations in each element, multiple elements in a single PIDF-LO document, _and_ multiple PIDF-LO documents in a single request. Dealing with multiple locations however is such an extraordinarily complex process that it's not support by Asterisk at this time. Please read the reference information for the applicable rules. [RFC5491|Geolocation Reference Information#rfc5491] is a good starting point.
|
||||
|
||||
h2. Conveying a Location via SIP
|
||||
There are currently two ways to convey a location description regardless of which description method you use. Both use the {{Geolocation}} SIP message header to indicate where to get the location description document.
|
||||
|
||||
h3. By Reference
|
||||
This one's simple. The "reference" is actually URI that the recipient can access that will return an XML document containing the description. "http" and "https" are the most common URI schemes but there are others. See [RFC6442|Geolocation Reference Information#rfc6442] above. An example {{Geolocation}} header might look like: {{Geolocation: <https://geoloc.example.com?location=some_location_reference>}}.
|
||||
|
||||
With this method, you are entirely responsible for retrieving location descriptions from URIs you receive and for serving location descriptions for URIs you send. Asterisk does not attempt to retrieve any information from those URIs.
|
||||
|
||||
When sending information to an upstream carrier, it's possible they may give _you_ special URIs to place in Geolocation headers you send them.
|
||||
|
||||
h3. By Value
|
||||
This method involves sending or receiving a PIDF-LO document attached to a SIP message. For details on how this works generally, See [RFC6442|Geolocation Reference Information#rfc6442] and [RFC5491|Geolocation Reference Information#rfc5491]. An example {{Geolocation}} header might look like: {{Geolocation: <cid:gyytfr@your.pbx.com>}}. The {{cid}} scheme indicates that the recipient should look in the SIP message body (or bodies since there could also be an SDP for example) for the location document.
|
||||
|
||||
h3. Multiple URIs
|
||||
The {{Geolocation}} header can contain multiple URIs and they can be a mix of "by-reference" and "by-value". As mentioned above though, the process of dealing with multiple location references is pretty complex and should be avoided.
|
||||
|
||||
h3. Geolocation-Routing
|
||||
[RFC6442|Geolocation Reference Information#rfc6442] also defines the {{Geolocation-Routing}} header which indicates to a recipient that the location information may or may not be used for call routing purposes. If set to "no" (the default if absent), the recipient MUST NOT use the location information for routing purposes. If set to "yes", the recipient MAY use the location information for routing purposes and may also reset the value to "no" to prevent downstream systems from using the location information for routing.
|
||||
|
||||
Some carriers ignore this header altogether.
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
33
res/res_geolocation/wiki/ReferenceInformation.md
Normal file
33
res/res_geolocation/wiki/ReferenceInformation.md
Normal file
@@ -0,0 +1,33 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
|
||||
There is no single document that has the complete, current specification so please follow and read any "updated by" references in these documents.
|
||||
|
||||
|| RFC || Title ||
|
||||
|[RFC3693|https://www.rfc-editor.org/rfc/rfc3693]|Geopriv Requirements|
|
||||
|[RFC4119|https://www.rfc-editor.org/rfc/rfc4119]|A Presence-based GEOPRIV Location Object Format|
|
||||
|[RFC5139|https://www.rfc-editor.org/rfc/rfc5139]|Revised Civic Location Format for\\Presence Information Data Format Location Object (PIDF-LO)|
|
||||
|{anchor:rfc5491} [RFC5491|https://www.rfc-editor.org/rfc/rfc5491]|GEOPRIV Presence Information Data Format\\Location Object (PIDF-LO) Usage Clarification, Considerations, and Recommendations|
|
||||
|[RFC5808|https://www.rfc-editor.org/rfc/rfc5808]|Requirements for a Location-by-Reference Mechanism|
|
||||
|[RFC6280|https://www.rfc-editor.org/rfc/rfc6280]|An Architecture for Location and Location\\Privacy in Internet Applications|
|
||||
|{anchor:rfc6442} [RFC6442|https://www.rfc-editor.org/rfc/rfc6442]|Location Conveyance for the Session Initiation Protocol|
|
||||
|[RFC6848|https://www.rfc-editor.org/rfc/rfc6848]|Specifying Civic Address Extensions in the\\Presence Information Data Format Location Object (PIDF-LO)|
|
||||
|[RFC7459|https://www.rfc-editor.org/rfc/rfc7459]|Representation of Uncertainty and Confidence\\in the Presence Information Data Format Location Object (PIDF-LO)|
|
||||
|[RFC8787|https://www.rfc-editor.org/rfc/rfc8787]|Location Source Parameter for the SIP Geolocation Header Field|
|
||||
|{anchor:gml} [OGC GML|https://www.ogc.org/standards/gml]|Open Geospatial Consortium Geography Markup Language|
|
||||
|{anchor:geoshape} [GeoShape|https://portal.ogc.org/files/?artifact_id=21630#:~:text=This%20GML%203.1.,uses%20the%20separately%20specified%20geoshape]|GML 3.1.1 PIDF-LO Shape Application Schema\\for use by the Internet Engineering Task Force (IETF)|
|
||||
|{anchor:gad} [3GPP TS 23.032|https://www.3gpp.org/ftp/Specs/archive/23_series/23.032/]|3GPP Technical Specification: Universal Geographical Area Description (GAD)\\Use version [23.032-h20|https://www.3gpp.org/ftp/Specs/archive/23_series/23.032/23032-h20.zip]\\This document is NOT specific to Geopriv so use with caution|
|
||||
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
|
||||
86
res/res_geolocation/wiki/URI.md
Normal file
86
res/res_geolocation/wiki/URI.md
Normal file
@@ -0,0 +1,86 @@
|
||||
{section:border=false}
|
||||
{column:width=70%}
|
||||
|
||||
h1. Introduction
|
||||
|
||||
As mentioned in other pages, Geolocation descriptions can be passed "by-value" using a GML or Civic Address XML document, or "by-reference" using a URI. This page discusses the latter.
|
||||
|
||||
h1. Concepts
|
||||
|
||||
h2. Outgoing Calls
|
||||
Passing location descriptions using URIs is fairly simple from an Asterisk perspective. It does however, require the implementer to establish and maintain infrastructure to handle the serving of those URIs. Given the critical nature of the information, setting up such infrastructure is not trivial and is beyond the scope of Asterisk and this documentation.
|
||||
|
||||
h2. Incoming calls
|
||||
On incoming calls, Asterisk will make any "pass-by-reference" URIs available to the dialplan via the {{GEOLOC_PROFILE}} function but will NOT attempt to retrieve any documents from that URI. It's the dialplan author's responsibility to retrieve, interpret and process such documents.
|
||||
|
||||
h1. Example 1
|
||||
|
||||
Let's say that every extension in your organization has a public DID associated with it, you have a database that cross references DIDs and office locations, and you have a web server that can be queried with a "GET" request and an "DID" query parameter ({{https://my.company.com/location_query?DID=<did>}}) to get the DID's location. When someone in your organization dials 911, you want a link sent in the outgoing SIP INVITE that the recipient can call to get the caller's location.
|
||||
|
||||
In geolocation.conf, you'd create Location and Profile objects as follows:
|
||||
{code}
|
||||
[did-xref]
|
||||
type = location
|
||||
format = URI
|
||||
location = URI='https://my.company.com/location_query?DID=${CALLERID(num)}'
|
||||
|
||||
[employees-outbound]
|
||||
type = profile
|
||||
location_reference = did-xref
|
||||
{code}
|
||||
|
||||
In pjsip.conf, you'd add a {{geoloc_outgoing_call_profile}} parameter to your _outgoing_ endpoint definition:
|
||||
{code}
|
||||
[my-provider]
|
||||
type = endpoint
|
||||
...
|
||||
geoloc_outgoing_call_profile = employees-outbound
|
||||
{code}
|
||||
|
||||
Now let's say that Bob has DID {{12125551212}} assigned to him and he makes an outgoing call which is routed to "my-provider". Asterisk would automatically add the following header to the INVITE:
|
||||
{code}
|
||||
Geolocation: <https://my.company.com/location_query?DID=12125551212>
|
||||
{code}
|
||||
The recipient could then make a simply query using that URI and get Bob's location in whatever format was agreed upon with you and them.
|
||||
|
||||
Of course, this is a _very_ simple example that would add the Geolocation header to _all_ calls made via "my-provider". If you only routed emergency calls to "my-provider" this would work fine but you probably don't want to leak location information on non-emergency calls.
|
||||
|
||||
h1. Example 2
|
||||
|
||||
In this example, we'll use the dialplan apps and functions to decide if we want to send location information to the recipient or not. In fact, we're not going to use geolocation.conf at all.
|
||||
|
||||
In extensions.conf:
|
||||
|
||||
{code}
|
||||
; The pre dial handler adds a new profile with a URI location to
|
||||
; the outgoing channel when 911 is dialed and does nothing if another number is dialed.
|
||||
[pre-dial-handler]
|
||||
exten = 911,1,NoOp(Entering PDH for Outgoing Channel)
|
||||
same = n,GeolocProfileCreate(geoloc.example@myserver.com)
|
||||
same = n,Set(GEOLOC_PROFILE(format,0)=URI)
|
||||
same = n,Set(GEOLOC_PROFILE(location_info,0)=URI=https://my.company.com/location_query?DID=${CALLERID(num)})
|
||||
same = n,Return(0)
|
||||
exten = _X.,1,Return(0)
|
||||
|
||||
[default]
|
||||
exten = _X.,1,NoOp(Outgoing call)
|
||||
; 'b' will run the pre-dial-handler on the outgoing channel.
|
||||
same = n,Dial(PJSIP/${EXTEN},5,b(pre-dial-handler))
|
||||
|
||||
{code}
|
||||
|
||||
{column}
|
||||
{column:width=30%}
|
||||
Table of Contents:
|
||||
{toc}
|
||||
|
||||
|
||||
Geolocation:
|
||||
{pagetree:root=Geolocation|expandCollapseAll=true}
|
||||
{column}
|
||||
{section}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "asterisk/res_pjsip_session.h"
|
||||
|
||||
static pj_str_t GEOLOCATION_HDR;
|
||||
static pj_str_t GEOLOCATION_ROUTING_HDR;
|
||||
|
||||
static int find_pidf(const char *session_name, struct pjsip_rx_data *rdata, char *geoloc_uri,
|
||||
char **pidf_body, unsigned int *pidf_len)
|
||||
@@ -94,6 +95,42 @@ static int find_pidf(const char *session_name, struct pjsip_rx_data *rdata, char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_eprofile_to_channel(struct ast_sip_session *session,
|
||||
struct ast_geoloc_eprofile *eprofile, struct ast_str * buf)
|
||||
{
|
||||
const char *session_name = (session ? ast_sip_session_get_name(session) : "NULL_SESSION");
|
||||
struct ast_datastore *ds = NULL;
|
||||
int rc = 0;
|
||||
SCOPE_ENTER(4, "%s\n", session_name);
|
||||
|
||||
ds = ast_geoloc_datastore_create(session_name);
|
||||
if (!ds) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING,
|
||||
"%s: Couldn't allocate a geoloc datastore\n", session_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* We want the datastore to pass through the dialplan and the core
|
||||
* so we need to turn inheritance on.
|
||||
*/
|
||||
ast_geoloc_datastore_set_inheritance(ds, 1);
|
||||
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
ast_datastore_free(ds);
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING,
|
||||
"%s: Couldn't add eprofile '%s' to datastore\n", session_name,
|
||||
eprofile->id);
|
||||
}
|
||||
|
||||
ast_channel_lock(session->channel);
|
||||
ast_channel_datastore_add(session->channel, ds);
|
||||
ast_channel_unlock(session->channel);
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: eprofile: '%s' EffectiveLoc: %s\n",
|
||||
session_name, eprofile->id, ast_str_buffer(
|
||||
ast_variable_list_join(eprofile->effective_location, ",", "=", NULL, &buf)));
|
||||
}
|
||||
|
||||
static int handle_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
|
||||
{
|
||||
@@ -101,14 +138,16 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
||||
struct ast_sip_endpoint *endpoint = (session ? session->endpoint : NULL);
|
||||
struct ast_channel *channel = (session ? session->channel : NULL);
|
||||
RAII_VAR(struct ast_geoloc_profile *, config_profile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, config_eprofile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_datastore *, ds, NULL, ast_datastore_free);
|
||||
size_t eprofile_count = 0;
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, incoming_eprofile, NULL, ao2_cleanup);
|
||||
char *geoloc_hdr_value = NULL;
|
||||
char *geoloc_routing_hdr_value = NULL;
|
||||
char *geoloc_uri = NULL;
|
||||
int rc = 0;
|
||||
RAII_VAR(struct ast_str *, buf, ast_str_create(1024), ast_free);
|
||||
pjsip_generic_string_hdr *geoloc_hdr = NULL;
|
||||
pjsip_generic_string_hdr *geoloc_routing_hdr = NULL;
|
||||
SCOPE_ENTER(3, "%s\n", session_name);
|
||||
|
||||
if (!session) {
|
||||
@@ -130,7 +169,13 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
||||
session_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need geoloc_hdr or geoloc_routing_hdr for a while but we get it now
|
||||
* for trace purposes.
|
||||
*/
|
||||
geoloc_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &GEOLOCATION_HDR, NULL);
|
||||
geoloc_routing_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
|
||||
&GEOLOCATION_ROUTING_HDR, NULL);
|
||||
|
||||
if (!geoloc_hdr) {
|
||||
ast_trace(4, "%s: Message has no Geolocation header\n", session_name);
|
||||
@@ -143,11 +188,11 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
||||
if (geoloc_hdr) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"
|
||||
PJSTR_PRINTF_SPEC "' but endpoint has no geoloc_incoming_call_profile. "
|
||||
"Geolocation info discarded.\n", session_name,
|
||||
"Done.\n", session_name,
|
||||
PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
|
||||
} else {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Endpoint has no geoloc_incoming_call_profile. "
|
||||
"Skipping.\n", session_name);
|
||||
"Done.\n", session_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,252 +201,177 @@ static int handle_incoming_request(struct ast_sip_session *session, struct pjsip
|
||||
if (geoloc_hdr) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"
|
||||
PJSTR_PRINTF_SPEC "' but endpoint's geoloc_incoming_call_profile doesn't exist. "
|
||||
"Geolocation info discarded.\n", session_name,
|
||||
"Done.\n", session_name,
|
||||
PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
|
||||
} else {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has no Geolocation header and endpoint has "
|
||||
" an invalid geoloc_incoming_call_profile. Nothing to do..\n", session_name);
|
||||
" an invalid geoloc_incoming_call_profile. Done.\n", session_name);
|
||||
}
|
||||
}
|
||||
|
||||
ds = ast_geoloc_datastore_create(session_name);
|
||||
if (!ds) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
|
||||
"%s: Couldn't allocate a geoloc datastore\n", session_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* We want the datastore to pass through the dialplan and the core
|
||||
* so we need to turn inheritance on.
|
||||
*/
|
||||
ast_geoloc_datastore_set_inheritance(ds, 1);
|
||||
|
||||
switch (config_profile->action) {
|
||||
case AST_GEOLOC_ACT_DISCARD_INCOMING:
|
||||
if (geoloc_hdr) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'discard_incoming' so "
|
||||
"discarding Geolocation: " PJSTR_PRINTF_SPEC "\n", session_name,
|
||||
ast_sorcery_object_get_id(config_profile),
|
||||
PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
|
||||
} else {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'discard_incoming' but there was no Geolocation header"
|
||||
"so there's nothing to discard\n",
|
||||
session_name, ast_sorcery_object_get_id(config_profile));
|
||||
}
|
||||
|
||||
eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
|
||||
if (!eprofile) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from "
|
||||
if (config_profile->precedence != AST_GEOLOC_PRECED_DISCARD_CONFIG) {
|
||||
config_eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
|
||||
if (!config_eprofile) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to create config_eprofile from "
|
||||
"profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
}
|
||||
|
||||
if (!eprofile->effective_location) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Configured profile has no effective location. Skipping."
|
||||
"profile '%s'\n", session_name, ast_sorcery_object_get_id(eprofile));
|
||||
}
|
||||
if (config_eprofile && config_eprofile->effective_location) {
|
||||
ast_trace(4, "%s: config eprofile '%s' has effective location\n",
|
||||
session_name, config_eprofile->id);
|
||||
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
|
||||
"%s: Couldn't add eprofile '%s' to datastore\n", session_name,
|
||||
eprofile->id);
|
||||
}
|
||||
if (!geoloc_hdr || config_profile->precedence == AST_GEOLOC_PRECED_DISCARD_INCOMING ||
|
||||
config_profile->precedence == AST_GEOLOC_PRECED_PREFER_CONFIG) {
|
||||
|
||||
ast_channel_lock(channel);
|
||||
ast_channel_datastore_add(channel, ds);
|
||||
ast_channel_unlock(channel);
|
||||
/* We gave the datastore to the channel so don't let RAII_VAR clean it up. */
|
||||
ds = NULL;
|
||||
ast_trace(4, "%s: config eprofile '%s' is being used\n",
|
||||
session_name, config_eprofile->id);
|
||||
|
||||
ast_trace(4, "ep: '%s' EffectiveLoc: %s\n", eprofile->id, ast_str_buffer(
|
||||
ast_variable_list_join(eprofile->effective_location, ",", "=", NULL, &buf)));
|
||||
ast_str_reset(buf);
|
||||
/*
|
||||
* If we have an effective location and there's no geolocation header,
|
||||
* or the action is either DISCARD_INCOMING or PREFER_CONFIG,
|
||||
* we don't need to even look for a Geolocation header so just add the
|
||||
* config eprofile to the channel and exit.
|
||||
*/
|
||||
|
||||
/* We discarded the Geolocation header so there's no need to go on. */
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with 1 eprofile from config\n",
|
||||
session_name);
|
||||
rc = add_eprofile_to_channel(session, config_eprofile, buf);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
|
||||
"%s: Couldn't add config eprofile '%s' to datastore. Fail.\n", session_name,
|
||||
config_eprofile->id);
|
||||
}
|
||||
|
||||
case AST_GEOLOC_ACT_DISCARD_CONFIG:
|
||||
if (geoloc_hdr) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'discard_config' so "
|
||||
"discarding config profile\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
/* We process the Geolocation header down below. */
|
||||
} else {
|
||||
/* Discarded the config and there's no Geolocation header so we're done. */
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Profile '%s' location_disposition is 'discard_config' but "
|
||||
"there was no Geolocation header so there's nothing left to process\n",
|
||||
session_name, ast_sorcery_object_get_id(config_profile));
|
||||
}
|
||||
break;
|
||||
|
||||
case AST_GEOLOC_ACT_PREFER_CONFIG:
|
||||
eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
|
||||
if (!eprofile) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from "
|
||||
"profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
}
|
||||
|
||||
if (!eprofile->effective_location) {
|
||||
if (geoloc_hdr) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'prefer_config' but the configured"
|
||||
"eprofile has no location information. Falling back to Geolocation: "
|
||||
PJSTR_PRINTF_SPEC "\n", session_name, ast_sorcery_object_get_id(config_profile),
|
||||
PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
|
||||
/* We process the Geolocation header down below. */
|
||||
} else {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Configured profile '%s' has no effective location"
|
||||
" and there was no Geolocation header. Skipping.\n",
|
||||
session_name, ast_sorcery_object_get_id(eprofile));
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with eprofile from config. Done.\n",
|
||||
session_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
|
||||
"%s: Couldn't add eprofile '%s' to datastore\n", session_name,
|
||||
eprofile->id);
|
||||
}
|
||||
|
||||
ast_channel_lock(channel);
|
||||
ast_channel_datastore_add(channel, ds);
|
||||
ast_channel_unlock(channel);
|
||||
/* We gave the datastore to the channel so don't let RAII_VAR clean it up. */
|
||||
ds = NULL;
|
||||
|
||||
if (geoloc_hdr) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'prefer_config' so "
|
||||
"discarding Geolocation: " PJSTR_PRINTF_SPEC "\n",
|
||||
session_name, ast_sorcery_object_get_id(config_profile), PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
|
||||
}
|
||||
|
||||
ast_trace(4, "ep: '%s' EffectiveLoc: %s\n", eprofile->id, ast_str_buffer(
|
||||
ast_variable_list_join(eprofile->effective_location, ",", "=", NULL, &buf)));
|
||||
ast_str_reset(buf);
|
||||
|
||||
/* We discarded the Geolocation header so there's no need to go on. */
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with 1 eprofile from config\n",
|
||||
session_name);
|
||||
|
||||
case AST_GEOLOC_ACT_PREFER_INCOMING:
|
||||
if (geoloc_hdr) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'replace' so "
|
||||
"we don't need to do anything with the configured profile", session_name,
|
||||
ast_sorcery_object_get_id(config_profile));
|
||||
} else {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE,
|
||||
"%s: Profile '%s' location_disposition is 'replace' but there's "
|
||||
"no Geolocation header and therefore no location info to replace"
|
||||
"it with\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
/*
|
||||
* If the config eprofile has no effective location, just get rid
|
||||
* of it.
|
||||
*/
|
||||
ast_trace(4, "%s: Either config_eprofile didn't exist or it had no effective location\n",
|
||||
session_name);
|
||||
|
||||
ao2_cleanup(config_eprofile);
|
||||
config_eprofile = NULL;
|
||||
if (config_profile->precedence == AST_GEOLOC_PRECED_DISCARD_INCOMING) {
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: DISCARD_INCOMING set and no config eprofile. Done.\n",
|
||||
session_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geoloc_hdr_value = ast_alloca(geoloc_hdr->hvalue.slen + 1);
|
||||
ast_copy_pj_str(geoloc_hdr_value, &geoloc_hdr->hvalue, geoloc_hdr->hvalue.slen + 1);
|
||||
|
||||
/*
|
||||
* From RFC-6442:
|
||||
* Geolocation-header = "Geolocation" HCOLON locationValue
|
||||
* *( COMMA locationValue )
|
||||
* locationValue = LAQUOT locationURI RAQUOT
|
||||
* *(SEMI geoloc-param)
|
||||
* locationURI = sip-URI / sips-URI / pres-URI
|
||||
* / http-URI / https-URI
|
||||
* / cid-url ; (from RFC 2392)
|
||||
* / absoluteURI ; (from RFC 3261)
|
||||
* At this point, if we have a config_eprofile, then the action was
|
||||
* PREFER_INCOMING so we're going to keep it as a backup if we can't
|
||||
* get a profile from the incoming message.
|
||||
*/
|
||||
while((geoloc_uri = ast_strsep(&geoloc_hdr_value, ',', AST_STRSEP_TRIM))) {
|
||||
/* geoloc_uri should now be <scheme:location>[;loc-src=fqdn] */
|
||||
char *pidf_body = NULL;
|
||||
unsigned int pidf_len = 0;
|
||||
struct ast_xml_doc *incoming_doc = NULL;
|
||||
struct ast_geoloc_eprofile *eprofile = NULL;
|
||||
int rc = 0;
|
||||
|
||||
ast_trace(4, "Processing URI '%s'\n", geoloc_uri);
|
||||
if (geoloc_hdr && config_profile->precedence != AST_GEOLOC_PRECED_DISCARD_INCOMING) {
|
||||
|
||||
if (geoloc_uri[0] != '<' || strchr(geoloc_uri, '>') == NULL) {
|
||||
ast_log(LOG_WARNING, "%s: Geolocation header has bad URI '%s'. Skipping\n", session_name,
|
||||
geoloc_uri);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If the URI isn't "cid" then we're just going to pass it through.
|
||||
* From RFC-6442:
|
||||
* Geolocation-header = "Geolocation" HCOLON locationValue
|
||||
* *( COMMA locationValue )
|
||||
* locationValue = LAQUOT locationURI RAQUOT
|
||||
* *(SEMI geoloc-param)
|
||||
* locationURI = sip-URI / sips-URI / pres-URI
|
||||
* / http-URI / https-URI
|
||||
* / cid-url ; (from RFC 2392)
|
||||
* / absoluteURI ; (from RFC 3261)
|
||||
*/
|
||||
if (!ast_begins_with(geoloc_uri, "<cid:")) {
|
||||
|
||||
geoloc_hdr_value = ast_alloca(geoloc_hdr->hvalue.slen + 1);
|
||||
ast_copy_pj_str(geoloc_hdr_value, &geoloc_hdr->hvalue, geoloc_hdr->hvalue.slen + 1);
|
||||
|
||||
/*
|
||||
* We're going to scan the header value for URIs until we find
|
||||
* one that processes successfully or we run out of URIs.
|
||||
* I.E. The first good one wins.
|
||||
*/
|
||||
while (geoloc_hdr_value && !incoming_eprofile) {
|
||||
char *pidf_body = NULL;
|
||||
unsigned int pidf_len = 0;
|
||||
struct ast_xml_doc *incoming_doc = NULL;
|
||||
int rc = 0;
|
||||
|
||||
/* We're only going to consider the first URI in the header for now */
|
||||
geoloc_uri = ast_strsep(&geoloc_hdr_value, ',', AST_STRSEP_TRIM);
|
||||
if (ast_strlen_zero(geoloc_uri) || geoloc_uri[0] != '<' || strchr(geoloc_uri, '>') == NULL) {
|
||||
ast_log(LOG_WARNING, "%s: Geolocation header has no or bad URI '%s'. Skipping\n", session_name,
|
||||
S_OR(geoloc_uri, "<empty>"));
|
||||
continue;
|
||||
}
|
||||
|
||||
ast_trace(4, "Processing URI '%s'\n", geoloc_uri);
|
||||
|
||||
eprofile = ast_geoloc_eprofile_create_from_uri(geoloc_uri, session_name);
|
||||
if (!eprofile) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to create effective profile for URI '%s'. Skipping\n",
|
||||
session_name, geoloc_uri);
|
||||
continue;
|
||||
if (!ast_begins_with(geoloc_uri, "<cid:")) {
|
||||
ast_trace(4, "Processing URI '%s'\n", geoloc_uri);
|
||||
|
||||
incoming_eprofile = ast_geoloc_eprofile_create_from_uri(geoloc_uri, session_name);
|
||||
if (!incoming_eprofile) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to create effective profile for URI '%s'. Skipping\n",
|
||||
session_name, geoloc_uri);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
ast_trace(4, "Processing PIDF-LO '%s'\n", geoloc_uri);
|
||||
|
||||
rc = find_pidf(session_name, rdata, geoloc_uri, &pidf_body, &pidf_len);
|
||||
if (rc != 0 || !pidf_body || pidf_len == 0) {
|
||||
continue;
|
||||
}
|
||||
ast_trace(5, "Processing PIDF-LO "PJSTR_PRINTF_SPEC "\n", (int)pidf_len, pidf_body);
|
||||
|
||||
incoming_doc = ast_xml_read_memory(pidf_body, pidf_len);
|
||||
if (!incoming_doc) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to parse pidf document for URI '%s'\n",
|
||||
session_name, geoloc_uri);
|
||||
continue;
|
||||
}
|
||||
|
||||
incoming_eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, geoloc_uri, session_name);
|
||||
ast_xml_close(incoming_doc);
|
||||
|
||||
if (!incoming_eprofile) {
|
||||
ast_log(LOG_WARNING,
|
||||
"%s: Couldn't create incoming_eprofile from pidf\n", session_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_trace(4, "Processing PIDF-LO '%s'\n", geoloc_uri);
|
||||
|
||||
rc = find_pidf(session_name, rdata, geoloc_uri, &pidf_body, &pidf_len);
|
||||
if (rc != 0 || !pidf_body || pidf_len == 0) {
|
||||
continue;
|
||||
}
|
||||
ast_trace(5, "Processing PIDF-LO "PJSTR_PRINTF_SPEC "\n", (int)pidf_len, pidf_body);
|
||||
|
||||
incoming_doc = ast_xml_read_memory(pidf_body, pidf_len);
|
||||
if (!incoming_doc) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to parse pidf document for URI '%s'\n",
|
||||
session_name, geoloc_uri);
|
||||
continue;
|
||||
}
|
||||
|
||||
eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, geoloc_uri, session_name);
|
||||
}
|
||||
eprofile->action = config_profile->action;
|
||||
|
||||
ast_trace(4, "Processing URI '%s'. Adding to datastore\n", geoloc_uri);
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
ao2_ref(eprofile, -1);
|
||||
if (rc <= 0) {
|
||||
ast_log(LOG_WARNING, "%s: Unable to add effective profile for URI '%s' to datastore. Skipping\n",
|
||||
session_name, geoloc_uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (config_profile->action == AST_GEOLOC_ACT_PREFER_CONFIG) {
|
||||
ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "
|
||||
"adding to datastore first", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
|
||||
eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
|
||||
if (!eprofile) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from"
|
||||
" profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
if (!incoming_eprofile) {
|
||||
/* Use the config_eprofile as a backup if there was one */
|
||||
incoming_eprofile = config_eprofile;
|
||||
} else {
|
||||
ao2_cleanup(config_eprofile);
|
||||
config_eprofile = NULL;
|
||||
if (geoloc_routing_hdr) {
|
||||
geoloc_routing_hdr_value = ast_alloca(geoloc_routing_hdr->hvalue.slen + 1);
|
||||
ast_copy_pj_str(geoloc_routing_hdr_value, &geoloc_routing_hdr->hvalue,
|
||||
geoloc_routing_hdr->hvalue.slen + 1);
|
||||
incoming_eprofile->allow_routing_use = ast_true(geoloc_routing_hdr_value);
|
||||
}
|
||||
}
|
||||
|
||||
rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
|
||||
if (rc <= 0) {
|
||||
if (incoming_eprofile) {
|
||||
rc = add_eprofile_to_channel(session, incoming_eprofile, buf);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
|
||||
"%s: Couldn't add eprofile '%s' to datastore\n", session_name,
|
||||
eprofile->id);
|
||||
"%s: Couldn't add eprofile '%s' to channel. Fail.\n", session_name,
|
||||
incoming_eprofile->id);
|
||||
}
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: Added eprofile '%s' to channel. Done.\n",
|
||||
session_name, incoming_eprofile->id);
|
||||
}
|
||||
|
||||
eprofile_count = ast_geoloc_datastore_size(ds);
|
||||
if (eprofile_count == 0) {
|
||||
SCOPE_EXIT_RTN_VALUE(0,
|
||||
"%s: Unable to add any effective profiles. Not adding datastore to channel.\n",
|
||||
session_name);
|
||||
}
|
||||
|
||||
ast_channel_lock(channel);
|
||||
ast_channel_datastore_add(channel, ds);
|
||||
ast_channel_unlock(channel);
|
||||
ds = NULL;
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with %" PRIu64 " eprofiles\n",
|
||||
session_name, eprofile_count);
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: No eprofiles to add to channel. Done.\n", session_name);
|
||||
}
|
||||
|
||||
static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *channel,
|
||||
struct ast_vector_string *uris, int pidf_index, struct pjsip_tx_data *tdata, const char *session_name)
|
||||
static const char *add_eprofile_to_tdata(struct ast_geoloc_eprofile *eprofile, struct ast_channel *channel,
|
||||
struct pjsip_tx_data *tdata, struct ast_str **buf, const char *session_name)
|
||||
{
|
||||
static const pj_str_t from_name = { "From", 4};
|
||||
static const pj_str_t cid_name = { "Content-ID", 10 };
|
||||
@@ -417,9 +387,8 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
char id[6];
|
||||
size_t alloc_size;
|
||||
RAII_VAR(char *, base_cid, NULL, ast_free);
|
||||
const char *final;
|
||||
const char *final_doc;
|
||||
int rc = 0;
|
||||
RAII_VAR(struct ast_str *, buf, ast_str_create(1024), ast_free);
|
||||
SCOPE_ENTER(3, "%s\n", session_name);
|
||||
|
||||
/*
|
||||
@@ -427,8 +396,13 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
* in it, skips over the ones not needing PIDF processing and combines the
|
||||
* rest into one document.
|
||||
*/
|
||||
final = ast_geoloc_eprofiles_to_pidf(tempds, channel, &buf, session_name);
|
||||
ast_trace(5, "Final pidf: \n%s\n", final);
|
||||
final_doc = ast_geoloc_eprofile_to_pidf(eprofile, channel, buf, session_name);
|
||||
ast_trace(5, "Final pidf: \n%s\n", final_doc);
|
||||
|
||||
if (!final_doc) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create pidf document from"
|
||||
" eprofile '%s'\n\n", session_name, eprofile->id);
|
||||
}
|
||||
|
||||
/*
|
||||
* There _should_ be an SDP already attached to the tdata at this point
|
||||
@@ -450,7 +424,7 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
|
||||
rc = pjsip_create_multipart_sdp_body(tdata->pool, tdata_sdp_info->sdp, &multipart_body);
|
||||
if (rc != PJ_SUCCESS) {
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_ERROR, "%s: Unable to create sdp multipart body\n",
|
||||
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create sdp multipart body\n",
|
||||
session_name);
|
||||
}
|
||||
} else {
|
||||
@@ -458,7 +432,7 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
}
|
||||
|
||||
pidf_part = pjsip_multipart_create_part(tdata->pool);
|
||||
pj_cstr(&pidf_body_text, final);
|
||||
pj_cstr(&pidf_body_text, final_doc);
|
||||
pidf_part->body = pjsip_msg_body_create(tdata->pool, &pjsip_media_type_application_pidf_xml.type,
|
||||
&pjsip_media_type_application_pidf_xml.subtype, &pidf_body_text);
|
||||
|
||||
@@ -471,10 +445,8 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
ast_generate_random_string(id, sizeof(id)),
|
||||
(int) pj_strlen(&sip_uri->host), pj_strbuf(&sip_uri->host));
|
||||
|
||||
ast_str_set(&buf, 0, "cid:%s", base_cid);
|
||||
ast_trace(4, "cid: '%s' uri: '%s' pidf_index: %d\n", base_cid, ast_str_buffer(buf), pidf_index);
|
||||
|
||||
AST_VECTOR_INSERT_AT(uris, pidf_index, ast_strdup(ast_str_buffer(buf)));
|
||||
ast_str_set(buf, 0, "cid:%s", base_cid);
|
||||
ast_trace(4, "cid: '%s' uri: '%s'\n", base_cid, ast_str_buffer(*buf));
|
||||
|
||||
cid_value.ptr = pj_pool_alloc(tdata->pool, alloc_size);
|
||||
cid_value.slen = sprintf(cid_value.ptr, "<%s>", base_cid);
|
||||
@@ -485,7 +457,7 @@ static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *c
|
||||
|
||||
tdata->msg->body = multipart_body;
|
||||
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s: PIDF-LO added with cid '%s'\n", session_name, base_cid);
|
||||
SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: PIDF-LO added with cid '%s'\n", session_name, base_cid);
|
||||
}
|
||||
|
||||
static void handle_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
|
||||
@@ -495,18 +467,15 @@ static void handle_outgoing_request(struct ast_sip_session *session, struct pjsi
|
||||
struct ast_channel *channel = session->channel;
|
||||
RAII_VAR(struct ast_geoloc_profile *, config_profile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, config_eprofile, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_geoloc_eprofile *, incoming_eprofile, NULL, ao2_cleanup);
|
||||
struct ast_geoloc_eprofile *final_eprofile = NULL;
|
||||
RAII_VAR(struct ast_str *, buf, ast_str_create(1024), ast_free);
|
||||
RAII_VAR(struct ast_datastore *, tempds, NULL, ast_datastore_free);
|
||||
struct ast_datastore *ds = NULL; /* The channel cleans up ds */
|
||||
struct ast_vector_string uris;
|
||||
pjsip_msg_body *orig_body;
|
||||
pjsip_generic_string_hdr *geoloc_hdr;
|
||||
int i;
|
||||
pjsip_msg_body *orig_body = NULL;
|
||||
pjsip_generic_string_hdr *geoloc_hdr = NULL;
|
||||
int eprofile_count = 0;
|
||||
int pidf_index = -1;
|
||||
int geoloc_routing = 0;
|
||||
int rc = 0;
|
||||
const char *final;
|
||||
const char *uri;
|
||||
SCOPE_ENTER(3, "%s\n", session_name);
|
||||
|
||||
if (!buf) {
|
||||
@@ -541,136 +510,111 @@ static void handle_outgoing_request(struct ast_sip_session *session, struct pjsi
|
||||
"profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
|
||||
}
|
||||
|
||||
if (config_profile->action != AST_GEOLOC_ACT_PREFER_INCOMING) {
|
||||
ds = ast_geoloc_datastore_find(channel);
|
||||
if (!ds) {
|
||||
ast_trace(4, "%s: There was no geoloc datastore\n", session_name);
|
||||
} else {
|
||||
eprofile_count = ast_geoloc_datastore_size(ds);
|
||||
ast_trace(4, "%s: There are %d geoloc profiles on this channel\n", session_name,
|
||||
eprofile_count);
|
||||
}
|
||||
if (!config_eprofile->effective_location) {
|
||||
/*
|
||||
* If there's no effective location on the eprofile
|
||||
* we don't need to keep it.
|
||||
*/
|
||||
ast_trace(4, "%s: There was no effective location for config profile '%s'\n",
|
||||
session_name, ast_sorcery_object_get_id(config_profile));
|
||||
ao2_ref(config_eprofile, -1);
|
||||
config_eprofile = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want to alter the datastore that may (or may not) be on
|
||||
* the channel so we're going to create a temporary one to hold the
|
||||
* config eprofile plus any in the channel datastore. Technically
|
||||
* we could just use a vector but the datastore already has the logic
|
||||
* to release all the eprofile references and the datastore itself.
|
||||
*/
|
||||
tempds = ast_geoloc_datastore_create("temp");
|
||||
ds = ast_geoloc_datastore_find(channel);
|
||||
if (!ds) {
|
||||
ast_trace(4, "%s: There are no geoloc profiles on this channel\n", session_name);
|
||||
ast_geoloc_datastore_add_eprofile(tempds, config_eprofile);
|
||||
ast_trace(4, "%s: There was no geoloc datastore on the channel\n", session_name);
|
||||
} else {
|
||||
if (config_profile->action == AST_GEOLOC_ACT_PREFER_CONFIG) {
|
||||
ast_trace(4, "%s: prepending config_eprofile\n", session_name);
|
||||
ast_geoloc_datastore_add_eprofile(tempds, config_eprofile);
|
||||
}
|
||||
for (i = 0; i < eprofile_count; i++) {
|
||||
struct ast_geoloc_eprofile *ep = ast_geoloc_datastore_get_eprofile(ds, i);
|
||||
ast_trace(4, "%s: adding eprofile '%s' from channel\n", session_name, ep->id);
|
||||
ast_geoloc_datastore_add_eprofile(tempds, ep);
|
||||
}
|
||||
if (config_profile->action == AST_GEOLOC_ACT_PREFER_INCOMING) {
|
||||
ast_trace(4, "%s: appending config_eprofile\n", session_name);
|
||||
ast_geoloc_datastore_add_eprofile(tempds, config_eprofile);
|
||||
}
|
||||
eprofile_count = ast_geoloc_datastore_size(ds);
|
||||
ast_trace(4, "%s: There are %d geoloc profiles on this channel\n", session_name,
|
||||
eprofile_count);
|
||||
/*
|
||||
* There'd better be a max of 1 at this time. In the future
|
||||
* we may allow more than 1.
|
||||
*/
|
||||
incoming_eprofile = ast_geoloc_datastore_get_eprofile(ds, 0);
|
||||
}
|
||||
|
||||
eprofile_count = ast_geoloc_datastore_size(tempds);
|
||||
if (eprofile_count == 0) {
|
||||
SCOPE_EXIT_RTN("%s: There are no profiles left to send\n", session_name);
|
||||
}
|
||||
ast_trace(4, "%s: There are now %d geoloc profiles to be sent\n", session_name,
|
||||
eprofile_count);
|
||||
ast_trace(4, "%s: Profile precedence: %s\n\n", session_name,
|
||||
ast_geoloc_precedence_to_name(config_profile->precedence));
|
||||
|
||||
/*
|
||||
* This vector is going to accumulate all of the URIs that
|
||||
* will need to go on the Geolocation header.
|
||||
*/
|
||||
rc = AST_VECTOR_INIT(&uris, 2);
|
||||
if (rc != 0) {
|
||||
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to allocate memory for vector\n", session_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* It's possible that we have a list of eprofiles that have both "pass-by-reference (external URI)"
|
||||
* and "pass by value (to go in PIDF)" eprofiles. The ones that just need a URI added to the
|
||||
* Geolocation header get added to the "uris" vector in this loop. The ones that result in a
|
||||
* PIDF though, need to be combined into a single PIDF-LO document so we're just going to
|
||||
* save the first one's index so we can insert the "cid" header in the right place, then
|
||||
* we'll send the whole list off to add_pidf_to_tdata() so they can be combined into a
|
||||
* single document.
|
||||
*/
|
||||
|
||||
for (i = 0; i < eprofile_count; i++) {
|
||||
struct ast_geoloc_eprofile *ep = ast_geoloc_datastore_get_eprofile(tempds, i);
|
||||
ast_geoloc_eprofile_refresh_location(ep);
|
||||
|
||||
ast_trace(4, "ep: '%s' EffectiveLoc: %s\n", ep->id, ast_str_buffer(
|
||||
ast_variable_list_join(ep->effective_location, ",", "=", NULL, &buf)));
|
||||
ast_str_reset(buf);
|
||||
|
||||
if (ep->format == AST_GEOLOC_FORMAT_URI) {
|
||||
final = ast_geoloc_eprofile_to_uri(ep, channel, &buf, session_name);
|
||||
ast_trace(4, "URI: %s\n", final);
|
||||
AST_VECTOR_APPEND(&uris, ast_strdup(final));
|
||||
ast_str_reset(buf);
|
||||
switch (config_profile->precedence) {
|
||||
case AST_GEOLOC_PRECED_DISCARD_INCOMING:
|
||||
final_eprofile = config_eprofile;
|
||||
ao2_cleanup(incoming_eprofile);
|
||||
incoming_eprofile = NULL;
|
||||
break;
|
||||
case AST_GEOLOC_PRECED_PREFER_INCOMING:
|
||||
if (incoming_eprofile) {
|
||||
final_eprofile = incoming_eprofile;
|
||||
ao2_cleanup(config_eprofile);
|
||||
config_eprofile = NULL;
|
||||
} else {
|
||||
/*
|
||||
* If there are GML or civicAddress eprofiles, we need to save the position
|
||||
* of the first one in relation to any URI ones so we can insert the "cid"
|
||||
* uri for it in the original position.
|
||||
*/
|
||||
if (pidf_index < 0) {
|
||||
pidf_index = i;
|
||||
}
|
||||
final_eprofile = config_eprofile;
|
||||
}
|
||||
/* The LAST eprofile determines routing */
|
||||
geoloc_routing = ep->geolocation_routing;
|
||||
ao2_ref(ep, -1);
|
||||
break;
|
||||
case AST_GEOLOC_PRECED_DISCARD_CONFIG:
|
||||
final_eprofile = incoming_eprofile;
|
||||
ao2_cleanup(config_eprofile);
|
||||
config_eprofile = NULL;
|
||||
break;
|
||||
case AST_GEOLOC_PRECED_PREFER_CONFIG:
|
||||
if (config_eprofile) {
|
||||
final_eprofile = config_eprofile;
|
||||
ao2_cleanup(incoming_eprofile);
|
||||
incoming_eprofile = NULL;
|
||||
} else {
|
||||
final_eprofile = incoming_eprofile;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found at least one eprofile needing PIDF processing, we'll
|
||||
* send the entire list off to add_pidf_to_tdata(). We're going to save
|
||||
* the pointer to the original tdata body in case we need to revert
|
||||
* if we can't add the headers.
|
||||
*/
|
||||
orig_body = tdata->msg->body;
|
||||
if (pidf_index >= 0) {
|
||||
rc = add_pidf_to_tdata(tempds, channel, &uris, pidf_index, tdata, session_name);
|
||||
if (!final_eprofile) {
|
||||
SCOPE_EXIT_RTN("%s: No eprofiles to send. Done.\n",
|
||||
session_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we have all the URIs in the vector, we'll string them together
|
||||
* to create the data for the Geolocation header.
|
||||
*/
|
||||
ast_geoloc_eprofile_refresh_location(final_eprofile);
|
||||
if (final_eprofile->format == AST_GEOLOC_FORMAT_URI) {
|
||||
uri = ast_geoloc_eprofile_to_uri(final_eprofile, channel, &buf, session_name);
|
||||
if (!uri) {
|
||||
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to create URI from eprofile '%s'\n",
|
||||
session_name, final_eprofile->id);
|
||||
}
|
||||
} else {
|
||||
orig_body = tdata->msg->body;
|
||||
uri = add_eprofile_to_tdata(final_eprofile, channel, tdata, &buf, session_name);
|
||||
if (!uri) {
|
||||
tdata->msg->body = orig_body;
|
||||
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to add eprofile '%s' to tdata\n",
|
||||
session_name, final_eprofile->id);
|
||||
}
|
||||
}
|
||||
|
||||
uri = ast_strdupa(ast_str_buffer(buf));
|
||||
ast_str_reset(buf);
|
||||
for (i = 0; i < AST_VECTOR_SIZE(&uris); i++) {
|
||||
char *uri = AST_VECTOR_GET(&uris, i);
|
||||
ast_trace(4, "ix: %d of %d LocRef: %s\n", i, (int)AST_VECTOR_SIZE(&uris), uri);
|
||||
ast_str_append(&buf, 0, "%s<%s>", (i > 0 ? "," : ""), uri);
|
||||
}
|
||||
ast_str_set(&buf, 0, "<%s>", uri);
|
||||
uri = ast_strdupa(ast_str_buffer(buf));
|
||||
|
||||
AST_VECTOR_RESET(&uris, ast_free);
|
||||
AST_VECTOR_FREE(&uris);
|
||||
ast_trace(4, "%s: Using URI '%s'\n", session_name, uri);
|
||||
|
||||
/* It's almost impossible for add header to fail but you never know */
|
||||
geoloc_hdr = ast_sip_add_header2(tdata, "Geolocation", ast_str_buffer(buf));
|
||||
geoloc_hdr = ast_sip_add_header2(tdata, "Geolocation", uri);
|
||||
if (geoloc_hdr == NULL) {
|
||||
tdata->msg->body = orig_body;
|
||||
if (orig_body) {
|
||||
tdata->msg->body = orig_body;
|
||||
}
|
||||
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to add Geolocation header\n", session_name);
|
||||
}
|
||||
rc = ast_sip_add_header(tdata, "Geolocation-Routing", geoloc_routing ? "yes" : "no");
|
||||
rc = ast_sip_add_header(tdata, "Geolocation-Routing", final_eprofile->allow_routing_use ? "yes" : "no");
|
||||
if (rc != 0) {
|
||||
tdata->msg->body = orig_body;
|
||||
if (orig_body) {
|
||||
tdata->msg->body = orig_body;
|
||||
}
|
||||
pj_list_erase(geoloc_hdr);
|
||||
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to add Geolocation-Routing header\n", session_name);
|
||||
}
|
||||
SCOPE_EXIT_RTN("%s: Geolocation: %s\n", session_name, ast_str_buffer(buf));
|
||||
SCOPE_EXIT_RTN("%s: Geolocation: %s\n", session_name, uri);
|
||||
}
|
||||
|
||||
static struct ast_sip_session_supplement geolocation_supplement = {
|
||||
@@ -697,6 +641,7 @@ static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
GEOLOCATION_HDR = pj_str("Geolocation");
|
||||
GEOLOCATION_ROUTING_HDR = pj_str("Geolocation-Routing");
|
||||
|
||||
ast_sip_session_register_supplement(&geolocation_supplement);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user